Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/app/components/builder-tabs/builder-tabs.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,55 @@
</mat-form-field>
}

@if (agentConfig.isRoot) {
<div class="logging-checkbox-row">
<mat-checkbox
[ngModel]="!!agentConfig.logging?.enabled"
(ngModelChange)="onTelemetryChange($event)"
style="margin-bottom: 0;"
>
Enable logging to BigQuery
</mat-checkbox>
<mat-icon
class="logging-help-icon"
matTooltip="Log agent interactions to Google BigQuery for analysis."
matTooltipPosition="above"
>help_outline</mat-icon>
</div>

@if (agentConfig.logging?.enabled) {
<div class="analytics-config-section">
<div class="logging-section-title">
Logging to BigQuery
</div>
<p class="analytics-hint">
<strong>Agent Analytics (powered by BigQuery):</strong> Please provide the dataset and table information to store interaction data. If the Table ID is left empty, the default table 'agent_events_v2' will be used. If the target table already exists, it will be used for logging (ensure you have table write permissions); otherwise, it will be created automatically (requires dataset write permissions).
<a href="https://google.github.io/adk-docs/integrations/bigquery-agent-analytics/" target="_blank" class="learn-more-link">Learn more</a>
</p>
<div class="form-row">
<mat-form-field style="width: 100%;">
<mat-label>Project ID *</mat-label>
<input matInput [(ngModel)]="agentConfig.logging!.project_id" required/>
</mat-form-field>
<mat-form-field style="width: 100%;">
<mat-label>Dataset ID *</mat-label>
<input matInput [(ngModel)]="agentConfig.logging!.dataset_id" required/>
</mat-form-field>
</div>
<div class="form-row">
<mat-form-field style="width: 100%;">
<mat-label>Table ID (optional)</mat-label>
<input matInput [(ngModel)]="agentConfig.logging!.table_id" placeholder="agent_events_v2"/>
</mat-form-field>
<mat-form-field style="width: 100%;">
<mat-label>Dataset Location *</mat-label>
<input matInput [(ngModel)]="agentConfig.logging!.dataset_location" required/>
</mat-form-field>
</div>
</div>
}
}

@if (agentConfig.agent_class === 'LoopAgent') {
<mat-form-field>
<mat-label>Max Iteration</mat-label>
Expand Down
50 changes: 50 additions & 0 deletions src/app/components/builder-tabs/builder-tabs.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,56 @@
margin-bottom: 8px;
}

.analytics-hint {
margin: 0 0 16px 0;
font-size: 13px;
line-height: 1.5;
color: var(--builder-text-secondary-color);

.learn-more-link {
color: var(--builder-text-link-color);
text-decoration: none;
display: inline-block;
margin-top: 4px;
font-weight: 500;

&:hover {
text-decoration: underline;
}
}
}

.logging-checkbox-row {
display: flex;
align-items: center;
gap: 4px;
margin-top: 16px;
margin-bottom: 8px;

.logging-help-icon {
font-size: 16px;
width: 16px;
height: 16px;
color: #c4c7c5;
cursor: help;
}
}

.analytics-config-section {
margin-top: 8px;
padding: 16px;
border: 1px solid var(--builder-border-color);
border-radius: 8px;
background-color: var(--mat-sys-surface-container-low);

.logging-section-title {
font-weight: 500;
margin-bottom: 12px;
font-size: 14px;
color: var(--mat-sys-on-surface);
}
}

.tool-code-section {
margin-top: 16px;

Expand Down
24 changes: 24 additions & 0 deletions src/app/components/builder-tabs/builder-tabs.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,19 @@ export class BuilderTabsComponent {
}
}

onTelemetryChange(enabled: boolean) {
if (this.agentConfig) {
if (!this.agentConfig.logging) {
this.agentConfig.logging = {
enabled: enabled,
dataset_location: 'US'
};
} else {
this.agentConfig.logging.enabled = enabled;
}
}
}

createAgentTool() {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
width: '750px',
Expand All @@ -734,6 +747,17 @@ export class BuilderTabsComponent {
}

saveChanges() {
if (this.agentConfig?.isRoot && this.agentConfig?.logging?.enabled) {
if (!this.agentConfig.logging.project_id?.trim() ||
!this.agentConfig.logging.dataset_id?.trim() ||
!this.agentConfig.logging.dataset_location?.trim()) {
this.snackBar.open("Project ID, Dataset ID, and Dataset Location are required when Agent Analytics is enabled.", "OK", {
duration: 3000
});
return;
}
}

const rootAgent = this.agentBuilderService.getRootNode();

if (!rootAgent) {
Expand Down
37 changes: 30 additions & 7 deletions src/app/components/canvas/canvas.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import { MatIcon } from '@angular/material/icon';
import { MatTooltip } from '@angular/material/tooltip';
import { MatMenu, MatMenuItem, MatMenuTrigger } from "@angular/material/menu";
import * as YAML from 'yaml';
import { firstValueFrom, Observable } from "rxjs";
import { take, filter } from "rxjs/operators";
import { firstValueFrom, Observable, forkJoin, of } from "rxjs";
import { take, filter, catchError } from "rxjs/operators";
import { YamlUtils } from "../../../utils/yaml-utils";
import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.component";
import { AddToolDialogComponent } from "../add-tool-dialog/add-tool-dialog.component";
Expand Down Expand Up @@ -1377,11 +1377,22 @@ export class CanvasComponent implements AfterViewInit, OnInit, OnChanges {
return toolsMap.get(nodeName) ?? [];
}

loadFromYaml(yamlContent: string, appName: string) {
loadFromYaml(yamlContent: string, appName: string, pluginsContent?: string) {
try {
// Parse the YAML content
const yamlData = YAML.parse(yamlContent);

if (pluginsContent) {
try {
const pluginsData = YAML.parse(pluginsContent);
if (pluginsData && pluginsData.bigquery_agent_analytics) {
yamlData.logging = pluginsData.bigquery_agent_analytics;
}
} catch (e) {
// It's fine if plugins.yaml is not valid YAML or doesn't exist
}
}

this.agentBuilderService.clear();
this.nodePositions.clear();
this.agentToolBoards.set(new Map());
Expand All @@ -1402,6 +1413,13 @@ export class CanvasComponent implements AfterViewInit, OnInit, OnChanges {
sub_agents: yamlData.sub_agents || [],
tools: this.parseToolsFromYaml(yamlData.tools || []),
callbacks: this.parseCallbacksFromYaml(yamlData),
logging: yamlData.logging ? {
enabled: true,
project_id: yamlData.logging.project_id,
dataset_id: yamlData.logging.dataset_id,
table_id: yamlData.logging.table_id,
dataset_location: yamlData.logging.dataset_location,
} : undefined
};

// Add to agent builder service
Expand Down Expand Up @@ -2040,10 +2058,15 @@ export class CanvasComponent implements AfterViewInit, OnInit, OnChanges {

reloadCanvasFromYaml(): void {
if (this.appNameInput) {
this.agentService.getAgentBuilderTmp(this.appNameInput).subscribe({
next: (yamlContent: string) => {
if (yamlContent) {
this.loadFromYaml(yamlContent, this.appNameInput);
const rootYaml$ = this.agentService.getAgentBuilderTmp(this.appNameInput);
const pluginsYaml$ = this.agentService.getSubAgentBuilder(this.appNameInput, 'plugins.yaml').pipe(
catchError(() => of(''))
);

forkJoin([rootYaml$, pluginsYaml$]).subscribe({
next: ([rootContent, pluginsContent]) => {
if (rootContent) {
this.loadFromYaml(rootContent, this.appNameInput, pluginsContent);
}
},
error: (error) => {
Expand Down
15 changes: 10 additions & 5 deletions src/app/components/chat/chat.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {MatTooltip} from '@angular/material/tooltip';
import {SafeHtml} from '@angular/platform-browser';
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
import {NgxJsonViewerModule} from 'ngx-json-viewer';
import {BehaviorSubject, combineLatest, Observable, of} from 'rxjs';
import {BehaviorSubject, combineLatest, forkJoin, Observable, of} from 'rxjs';
import {catchError, distinctUntilChanged, filter, first, map, shareReplay, switchMap, take, tap} from 'rxjs/operators';

import {URLUtil} from '../../../utils/url-util';
Expand Down Expand Up @@ -1927,10 +1927,15 @@ export class ChatComponent implements OnInit, AfterViewInit, OnDestroy {


private loadExistingAgentConfiguration() {
this.agentService.getAgentBuilderTmp(this.appName).subscribe({
next: (yamlContent: string) => {
if (yamlContent) {
this.canvasComponent()?.loadFromYaml(yamlContent, this.appName);
const rootYaml$ = this.agentService.getAgentBuilderTmp(this.appName);
const pluginsYaml$ = this.agentService.getSubAgentBuilder(this.appName, 'plugins.yaml').pipe(
catchError(() => of(''))
);

forkJoin([rootYaml$, pluginsYaml$]).subscribe({
next: ([rootContent, pluginsContent]) => {
if (rootContent) {
this.canvasComponent()?.loadFromYaml(rootContent, this.appName, pluginsContent);
}
},
error: (error: any) => {
Expand Down
10 changes: 10 additions & 0 deletions src/app/core/models/AgentBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ export interface AgentNode {
config_path?: string;
isAgentTool?: boolean;
skip_summarization?: boolean;
logging?: LoggingConfig;
}

export interface LoggingConfig {
enabled?: boolean;
project_id?: string;
dataset_id?: string;
table_id?: string;
dataset_location?: string;
}

export interface ToolNode {
Expand All @@ -56,6 +65,7 @@ export interface YamlConfig {
sub_agents: any;
tools?: any[];
callbacks?: any[];
logging?: LoggingConfig;
}

export interface DiagramNode {
Expand Down
17 changes: 17 additions & 0 deletions src/utils/yaml-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ export class YamlUtils {
tools: YamlUtils.buildToolsConfig(agentNode.tools, allTabAgents)
}

if (agentNode.isRoot && agentNode.logging?.enabled) {
const logging = agentNode.logging!;
const pluginsConfig = {
bigquery_agent_analytics: {
project_id: logging.project_id,
dataset_id: logging.dataset_id,
table_id: logging.table_id,
dataset_location: logging.dataset_location
}
};
const pluginsYamlString = YAML.stringify(pluginsConfig);
const pluginsBlob = new Blob([pluginsYamlString], { type: 'application/x-yaml' });
const pluginsFileName = `${appName}/plugins.yaml`;
const pluginsFile = new File([pluginsBlob], pluginsFileName, { type: 'application/x-yaml' });
formData.append('files', pluginsFile);
}

if (!agentNode.description || agentNode.description.trim() === '') {
delete yamlConfig.description;
}
Expand Down