Skip to content
Draft
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
2 changes: 1 addition & 1 deletion js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
},
"dependencies": {
"@ai-sdk/provider": "^1.1.3",
"@apm-js-collab/code-transformer": "^0.8.2",
"@apm-js-collab/code-transformer": "^0.9.0",
"@next/env": "^14.2.3",
"@vercel/functions": "^1.0.2",
"ajv": "^8.17.1",
Expand Down
114 changes: 114 additions & 0 deletions js/src/auto-instrumentations/configs/google-adk.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { describe, it, expect } from "vitest";
import { googleADKConfigs } from "./google-adk";

describe("Google ADK Instrumentation Configs", () => {
it("should have valid configs", () => {
expect(googleADKConfigs).toBeDefined();
expect(Array.isArray(googleADKConfigs)).toBe(true);
expect(googleADKConfigs).toHaveLength(4);
});

it("should have runner.runAsync config", () => {
const config = googleADKConfigs.find(
(c) => c.channelName === "runner.runAsync",
);

expect(config).toBeDefined();
expect(config?.module.name).toBe("@google/adk");
expect(config?.module.versionRange).toBe(">=0.1.0");
expect(config?.module.filePath).toBe("dist/esm/index.js");
expect((config?.functionQuery as any).className).toBe("Runner");
expect((config?.functionQuery as any).methodName).toBe("runAsync");
expect((config?.functionQuery as any).kind).toBe("Async");
expect((config?.functionQuery as any).isExportAlias).toBe(true);
});

it("should have agent.runAsync config", () => {
const config = googleADKConfigs.find(
(c) => c.channelName === "agent.runAsync",
);

expect(config).toBeDefined();
expect(config?.module.name).toBe("@google/adk");
expect(config?.module.versionRange).toBe(">=0.1.0");
expect(config?.module.filePath).toBe("dist/esm/index.js");
expect((config?.functionQuery as any).className).toBe("BaseAgent");
expect((config?.functionQuery as any).methodName).toBe("runAsync");
expect((config?.functionQuery as any).kind).toBe("Async");
expect((config?.functionQuery as any).isExportAlias).toBe(true);
});

it("should have llm.callLlmAsync config", () => {
const config = googleADKConfigs.find(
(c) => c.channelName === "llm.callLlmAsync",
);

expect(config).toBeDefined();
expect(config?.module.name).toBe("@google/adk");
expect(config?.module.versionRange).toBe(">=0.1.0");
expect(config?.module.filePath).toBe("dist/esm/index.js");
expect((config?.functionQuery as any).className).toBe("LlmAgent");
expect((config?.functionQuery as any).methodName).toBe("callLlmAsync");
expect((config?.functionQuery as any).kind).toBe("Async");
expect((config?.functionQuery as any).isExportAlias).toBe(true);
});

it("should have mcpTool.runAsync config", () => {
const config = googleADKConfigs.find(
(c) => c.channelName === "mcpTool.runAsync",
);

expect(config).toBeDefined();
expect(config?.module.name).toBe("@google/adk");
expect(config?.module.versionRange).toBe(">=0.1.0");
expect(config?.module.filePath).toBe("dist/esm/index.js");
expect((config?.functionQuery as any).className).toBe("MCPTool");
expect((config?.functionQuery as any).methodName).toBe("runAsync");
expect((config?.functionQuery as any).kind).toBe("Async");
expect((config?.functionQuery as any).isExportAlias).toBe(true);
});

it("should NOT include braintrust: or orchestrion: prefix (code-transformer adds orchestrion:google-adk: prefix)", () => {
for (const config of googleADKConfigs) {
expect(config.channelName).not.toContain("braintrust:");
expect(config.channelName).not.toContain("orchestrion:");
}
});

it("should target @google/adk package for all configs", () => {
for (const config of googleADKConfigs) {
expect(config.module.name).toBe("@google/adk");
}
});

it("should have valid version ranges", () => {
for (const config of googleADKConfigs) {
expect(config.module.versionRange).toMatch(/^>=\d+\.\d+\.\d+$/);
}
});

it("should have valid function kinds", () => {
const validKinds = ["Async", "Sync", "Callback"];
for (const config of googleADKConfigs) {
expect(validKinds).toContain((config.functionQuery as any).kind);
}
});

it("should use Async kind for all methods", () => {
for (const config of googleADKConfigs) {
expect((config.functionQuery as any).kind).toBe("Async");
}
});

it("should use isExportAlias for all configs", () => {
for (const config of googleADKConfigs) {
expect((config.functionQuery as any).isExportAlias).toBe(true);
}
});

it("should target dist/esm/index.js for all configs", () => {
for (const config of googleADKConfigs) {
expect(config.module.filePath).toBe("dist/esm/index.js");
}
});
});
78 changes: 78 additions & 0 deletions js/src/auto-instrumentations/configs/google-adk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { InstrumentationConfig } from "@apm-js-collab/code-transformer";

/**
* Instrumentation configurations for the Google ADK (Agent Development Kit).
*
* These configs define which functions to instrument and what channel
* to emit events on. They are used by orchestrion-js to perform AST
* transformation at build-time or load-time.
*
* NOTE: Channel names should NOT include the braintrust: prefix. The code-transformer
* will prepend "orchestrion:google-adk:" to these names, resulting in final channel names like:
* "orchestrion:google-adk:runner.runAsync"
*/
export const googleADKConfigs: InstrumentationConfig[] = [
// Runner.runAsync - Top-level orchestration entry point
{
channelName: "runner.runAsync",
module: {
name: "@google/adk",
versionRange: ">=0.1.0",
filePath: "dist/esm/index.js",
},
functionQuery: {
className: "Runner",
methodName: "runAsync",
kind: "Async",
isExportAlias: true,
},
},

// BaseAgent.runAsync - Agent execution
{
channelName: "agent.runAsync",
module: {
name: "@google/adk",
versionRange: ">=0.1.0",
filePath: "dist/esm/index.js",
},
functionQuery: {
className: "BaseAgent",
methodName: "runAsync",
kind: "Async",
isExportAlias: true,
},
},

// LlmAgent.callLlmAsync - Actual LLM call
{
channelName: "llm.callLlmAsync",
module: {
name: "@google/adk",
versionRange: ">=0.1.0",
filePath: "dist/esm/index.js",
},
functionQuery: {
className: "LlmAgent",
methodName: "callLlmAsync",
kind: "Async",
isExportAlias: true,
},
},

// MCPTool.runAsync - MCP tool calls
{
channelName: "mcpTool.runAsync",
module: {
name: "@google/adk",
versionRange: ">=0.1.0",
filePath: "dist/esm/index.js",
},
functionQuery: {
className: "MCPTool",
methodName: "runAsync",
kind: "Async",
isExportAlias: true,
},
},
];
2 changes: 2 additions & 0 deletions js/src/auto-instrumentations/hook.mts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { anthropicConfigs } from "./configs/anthropic.js";
import { aiSDKConfigs } from "./configs/ai-sdk.js";
import { claudeAgentSDKConfigs } from "./configs/claude-agent-sdk.js";
import { googleGenAIConfigs } from "./configs/google-genai.js";
import { googleADKConfigs } from "./configs/google-adk.js";
import { ModulePatch } from "./loader/cjs-patch.js";

// Combine all instrumentation configs
Expand All @@ -28,6 +29,7 @@ const allConfigs = [
...aiSDKConfigs,
...claudeAgentSDKConfigs,
...googleGenAIConfigs,
...googleADKConfigs,
];

// 1. Register ESM loader for ESM modules
Expand Down
1 change: 1 addition & 0 deletions js/src/auto-instrumentations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export { anthropicConfigs } from "./configs/anthropic";
export { aiSDKConfigs } from "./configs/ai-sdk";
export { claudeAgentSDKConfigs } from "./configs/claude-agent-sdk";
export { googleGenAIConfigs } from "./configs/google-genai";
export { googleADKConfigs } from "./configs/google-adk";

// Re-export orchestrion configuration types
// Note: ModuleMetadata and FunctionQuery are properties of InstrumentationConfig,
Expand Down
15 changes: 15 additions & 0 deletions js/src/instrumentation/braintrust-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AnthropicPlugin } from "./plugins/anthropic-plugin";
import { AISDKPlugin } from "./plugins/ai-sdk-plugin";
import { ClaudeAgentSDKPlugin } from "./plugins/claude-agent-sdk-plugin";
import { GoogleGenAIPlugin } from "./plugins/google-genai-plugin";
import { GoogleADKPlugin } from "./plugins/google-adk-plugin";

export interface BraintrustPluginConfig {
integrations?: {
Expand All @@ -13,6 +14,7 @@ export interface BraintrustPluginConfig {
aisdk?: boolean;
google?: boolean;
googleGenAI?: boolean;
googleADK?: boolean;
claudeAgentSDK?: boolean;
};
}
Expand All @@ -26,6 +28,7 @@ export interface BraintrustPluginConfig {
* - Claude Agent SDK (agent interactions)
* - Vercel AI SDK (generateText, streamText, etc.)
* - Google GenAI SDK
* - Google ADK (Agent Development Kit)
*
* The plugin is automatically enabled when the Braintrust library is loaded.
* Individual integrations can be disabled via configuration.
Expand All @@ -37,6 +40,7 @@ export class BraintrustPlugin extends BasePlugin {
private aiSDKPlugin: AISDKPlugin | null = null;
private claudeAgentSDKPlugin: ClaudeAgentSDKPlugin | null = null;
private googleGenAIPlugin: GoogleGenAIPlugin | null = null;
private googleADKPlugin: GoogleADKPlugin | null = null;

constructor(config: BraintrustPluginConfig = {}) {
super();
Expand Down Expand Up @@ -77,6 +81,12 @@ export class BraintrustPlugin extends BasePlugin {
this.googleGenAIPlugin = new GoogleGenAIPlugin();
this.googleGenAIPlugin.enable();
}

// Enable Google ADK integration (default: true)
if (integrations.googleADK !== false) {
this.googleADKPlugin = new GoogleADKPlugin();
this.googleADKPlugin.enable();
}
}

protected onDisable(): void {
Expand Down Expand Up @@ -104,6 +114,11 @@ export class BraintrustPlugin extends BasePlugin {
this.googleGenAIPlugin.disable();
this.googleGenAIPlugin = null;
}

if (this.googleADKPlugin) {
this.googleADKPlugin.disable();
this.googleADKPlugin = null;
}
}
}

Expand Down
Loading
Loading