Skip to content

Commit 193a4d8

Browse files
committed
chore(ai): update default gemini model to 2.5-flash and lock gateway to v1beta
1 parent 0ab77ec commit 193a4d8

82 files changed

Lines changed: 16754 additions & 1028 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/ai/agent-ai.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Agent, OpenAIProvider, Runner, type ModelProvider } from "@openai/agents";
2-
import { getAiGatewayUrl as resolveAiGatewayUrl } from "./utils/ai-gateway";
2+
import { getAiGatewayUrlForOpenAI } from "@/ai/utils/ai-gateway";
33

44
export type SupportedProvider =
55
| "worker-ai"
@@ -80,14 +80,14 @@ export async function getAiGatewayUrl(
8080
provider: SupportedProvider,
8181
): Promise<string> {
8282
const gatewayProvider = PROVIDER_TO_GATEWAY[provider];
83-
return resolveAiGatewayUrl(env, gatewayProvider);
83+
return getAiGatewayUrlForOpenAI(env, gatewayProvider);
8484
}
8585

8686
export async function getAiBaseUrl(
8787
env: Env,
8888
provider: SupportedProvider,
8989
): Promise<string> {
90-
return getAiGatewayUrl(env, provider);
90+
return getAiGatewayUrlForOpenAI(env, provider);
9191
}
9292

9393
export async function createRunner(

backend/src/ai/agents/BaseAgent.ts

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
import { Agent as OpenAIAgent } from "@openai/agents";
21
import { Agent as CFAgent } from "agents";
32
import {
4-
createGatewayClient,
53
createRunner,
64
resolveDefaultAiModel,
75
resolveDefaultAiProvider,
86
type SupportedProvider,
97
} from "@/ai/agent-sdk";
108
import { Logger } from "@/lib/logger";
11-
import { z } from "zod";
9+
import type { z } from "zod"; // ✅ Use type import to avoid runtime evaluation
1210

1311
export class BaseAgent<State = any> extends CFAgent<Env, State> {
1412
private _logger?: Logger;
@@ -41,22 +39,22 @@ export class BaseAgent<State = any> extends CFAgent<Env, State> {
4139
}): Promise<string> {
4240
const provider = this.resolveProvider(input.provider);
4341
const model = this.resolveModel(provider, input.model);
42+
43+
// ✅ Dynamically import the heavy SDK only when executed
44+
const { Agent: OpenAIAgent } = await import("@openai/agents");
45+
4446
const runner = await createRunner(this.env, provider, model);
45-
const client = await createGatewayClient(this.env, model);
47+
48+
// ⚠️ Note: Removed unused createGatewayClient
49+
4650
const agent = new OpenAIAgent({
4751
name: input.name,
4852
model,
4953
instructions: input.instructions,
50-
mcpServers: {
51-
"cloudflare": {
52-
transport: {
53-
type: "stdio",
54-
command: "npx",
55-
args: ["@cloudflare/mcp-server-cloudflare", "--mcp-endpoint", (this.env as any).MCP_API_URL || "https://docs.mcp.cloudflare.com/mcp"]
56-
}
57-
}
58-
} as any // Cast to any to avoid strict type issues with the specific Agent SDK version
54+
// ⚠️ Removed local 'stdio'/'npx' MCP config as it will crash a CF Worker.
55+
// If MCP is required, you must use an SSE/HTTP transport or inject it as a standard tool.
5956
});
57+
6058
const result = await runner.run(agent, input.prompt);
6159
return String(result.finalOutput ?? "");
6260
}
@@ -71,24 +69,18 @@ export class BaseAgent<State = any> extends CFAgent<Env, State> {
7169
}): Promise<T> {
7270
const provider = this.resolveProvider(input.provider);
7371
const model = this.resolveModel(provider, input.model);
72+
73+
// ✅ Dynamically import the heavy SDK only when executed
74+
const { Agent: OpenAIAgent } = await import("@openai/agents");
75+
7476
const runner = await createRunner(this.env, provider, model);
75-
const client = await createGatewayClient(this.env, model);
7677

77-
// We must pass the schema to the agent configuration
7878
const agent = new OpenAIAgent({
7979
name: input.name,
8080
model,
8181
instructions: input.instructions,
82-
outputType: input.schema as any, // Cast to any to avoid strict type issues with specific SDK versions
83-
mcpServers: {
84-
"cloudflare": {
85-
transport: {
86-
type: "stdio",
87-
command: "npx",
88-
args: ["@cloudflare/mcp-server-cloudflare", "--mcp-endpoint", (this.env as any).MCP_API_URL || "https://docs.mcp.cloudflare.com/mcp"]
89-
}
90-
}
91-
} as any
82+
outputType: input.schema as any,
83+
// ⚠️ Removed local 'stdio'/'npx' MCP config
9284
});
9385

9486
try {
@@ -99,5 +91,4 @@ export class BaseAgent<State = any> extends CFAgent<Env, State> {
9991
throw error;
10092
}
10193
}
102-
}
103-
94+
}

backend/src/ai/agents/Gemini.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,16 @@ export class GeminiAgent extends CFAgent<Env, any> {
2121
this.doId = state.id.toString();
2222
}
2323

24-
@callable({ streaming: true })
25-
async chat(stream: any, prompt: string) {
24+
@callable()
25+
async chat(prompt: string, history?: any[]) {
2626
// 1. Construct the Cloudflare AI Gateway OpenAI-Compatible URL
27-
// CLOUDFLARE_ACCOUNT_ID is a secret, so .get() is likely correct if typed as such
2827
const accountId = await this.env.CLOUDFLARE_ACCOUNT_ID.get();
29-
// AI_GATEWAY_NAME is a var (string), so no .get()
3028
const gateway = this.env.AI_GATEWAY_NAME;
31-
// CLOUDFLARE_API_TOKEN is a secret
32-
// Note: If CLOUDFLARE_API_TOKEN is not in Env, check wrangler.jsonc. It is there.
33-
// If it's a string in Env, .get() will fail. If it's a Secret, .get() is needed.
34-
// Based on usage of WORKER_API_KEY.get(), we assume secrets use .get().
3529
const apiKey = await this.env.CLOUDFLARE_API_TOKEN.get();
3630

3731
const baseURL = await this.env.AI.gateway(gateway).getUrl('worker-ai');
3832

3933
// 2. Hijack the global process environment to reroute ADK's underlying fetcher
40-
// We pass the CF API Token as the "OpenAI" key, and the AI Gateway as the Base URL.
4134
(globalThis as any).process = {
4235
env: {
4336
OPENAI_API_KEY: apiKey,
@@ -51,7 +44,6 @@ export class GeminiAgent extends CFAgent<Env, any> {
5144
// 3. Initialize ADK with the Cloudflare Workers AI Model
5245
const agent = new LlmAgent({
5346
name: "cf_gateway_agent",
54-
// The exact model requested, routed to Cloudflare Edge GPUs
5547
model: "@cf/openai/gpt-oss-120b",
5648
instruction: "You are an elite autonomous agent powered by Cloudflare Workers AI and Google ADK. Provide structured, highly accurate responses.",
5749
});
@@ -61,19 +53,18 @@ export class GeminiAgent extends CFAgent<Env, any> {
6153

6254
const eventStream = runner.runAsync({
6355
userId: "user",
64-
sessionId: this.doId, // Use captured Durable Object ID
56+
sessionId: this.doId,
6557
newMessage: { role: "user", parts: [{ text: prompt }] },
6658
});
6759

6860
let fullResponse = "";
6961

70-
// 5. Stream the chunks directly back to the assistant-ui frontend
62+
// 5. Accumulate the full response
7163
for await (const event of eventStream) {
7264
if (event.content?.parts) {
7365
for (const part of event.content.parts) {
7466
if (part.text) {
7567
fullResponse += part.text;
76-
await stream.write(part.text);
7768
}
7869
}
7970
}
@@ -89,9 +80,11 @@ export class GeminiAgent extends CFAgent<Env, any> {
8980
status: "idle"
9081
});
9182

83+
return { response: fullResponse };
84+
9285
} catch (error: any) {
9386
this.setState({ ...this.state, status: "error" });
94-
await stream.write(`\n\n[Agent Error]: ${error.message}`);
87+
return { response: `[Agent Error]: ${error.message}` };
9588
}
9689
}
9790
}

backend/src/ai/agents/Planner.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { callable } from "agents";
2-
import { Agent as OpenAIAgent } from "@openai/agents";
2+
import type { Agent } from "@openai/agents";
33
import { z } from "zod";
44
import { resolveDefaultAiModel, resolveDefaultAiProvider, createGatewayClient } from "@/ai/agent-sdk";
55
import { BaseAgent, BaseAgentState } from "@/ai/agent-sdk";
@@ -58,6 +58,7 @@ export class PlannerAgent extends BaseAgent<Env, BaseAgentState> {
5858
this.logger.info("Generating plan", { goalLength: goal.length, provider, model });
5959

6060
const client = await createGatewayClient(this.env, model);
61+
const { Agent: OpenAIAgent } = await import("@openai/agents");
6162
const planner = new OpenAIAgent({
6263
name: "PlannerAgent",
6364
model,

backend/src/ai/agents/Research.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { callable } from "agents";
88
import { BaseAgent, BaseAgentState } from "@/ai/agent-sdk";
99
import { Logger } from "@logging";
10-
import { Agent } from "@openai/agents";
10+
import type { Agent } from "@openai/agents";
1111
import { getAgentModelName } from "@/ai/utils/model-config";
1212
import { getOctokit } from "@services/octokit/core";
1313
import { z } from "zod";
@@ -117,8 +117,9 @@ export class ResearchAgent extends BaseAgent<Env, ResearchState> {
117117
}
118118
};
119119

120+
const { Agent: OpenAIAgent } = await import("@openai/agents");
120121
// Initialize agent WITH tools
121-
this.agent = new Agent({
122+
this.agent = new OpenAIAgent({
122123
name: "ResearchAgent",
123124
model: getAgentModelName('ResearchAgent'), // Cost-optimized: gpt-4o
124125
instructions: `You are a senior research analyst specializing in GitHub repository analysis.

backend/src/ai/agents/SoftwareEngineer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Agent as OpenAIAgent } from "@openai/agents";
1+
import type { Agent } from "@openai/agents";
22
import { z } from "zod";
33
import {
44
createRunner,
@@ -36,6 +36,7 @@ export class CodeGeneratorAgent {
3636
resolveDefaultAiModel(this.env, provider);
3737
const runner = await createRunner(this.env, provider, model);
3838

39+
const { Agent: OpenAIAgent } = await import("@openai/agents");
3940
const agent = new OpenAIAgent({
4041
name: "CodeGeneratorAgent",
4142
model,

backend/src/ai/agents/base/patterns/evaluator-optimizer.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Agent, run, type AgentInputItem, withTrace } from "@openai/agents";
1+
import type { AgentInputItem } from "@openai/agents";
22
import { Agent as CFAgent, callable } from "agents";
33
import { z } from "zod";
44

@@ -26,21 +26,23 @@ export class EvaluatorOptimizerAgent extends CFAgent<Env, EvaluatorState> {
2626
status: "idle"
2727
};
2828

29-
// 1. Generator Agent (The "Writer")
30-
generator = new Agent({
31-
name: "Generator",
32-
instructions: "You are a helpful assistant. Improve your previous response based on feedback if provided."
33-
});
34-
35-
// 2. Evaluator Agent (The "Judge")
36-
evaluator = new Agent({
37-
name: "Evaluator",
38-
instructions: "Evaluate the content for accuracy and clarity. Provide constructive feedback.",
39-
outputType: EvaluationSchema
40-
});
41-
4229
@callable()
4330
async execute(input: string) {
31+
const { Agent, run, withTrace } = await import("@openai/agents");
32+
33+
// 1. Generator Agent (The "Writer")
34+
const generator = new Agent({
35+
name: "Generator",
36+
instructions: "You are a helpful assistant. Improve your previous response based on feedback if provided."
37+
});
38+
39+
// 2. Evaluator Agent (The "Judge")
40+
const evaluator = new Agent({
41+
name: "Evaluator",
42+
instructions: "Evaluate the content for accuracy and clarity. Provide constructive feedback.",
43+
outputType: EvaluationSchema
44+
});
45+
4446
await withTrace("Evaluator-Optimizer Loop", async () => {
4547
let currentInput: AgentInputItem[] = [{ role: "user", content: input }];
4648
let attempts = 0;
@@ -51,14 +53,14 @@ export class EvaluatorOptimizerAgent extends CFAgent<Env, EvaluatorState> {
5153
while (attempts < MAX_ATTEMPTS) {
5254
// --- Generate ---
5355
console.log(`[Optimizer] Iteration ${attempts + 1}: Generating...`);
54-
const genResult = await run(this.generator, currentInput);
56+
const genResult = await run(generator, currentInput);
5557
const content = genResult.finalOutput;
5658

5759
if (!content) throw new Error("No content generated");
5860

5961
// --- Evaluate ---
6062
console.log(`[Optimizer] Iteration ${attempts + 1}: Evaluating...`);
61-
const evalResult = await run(this.evaluator, [
63+
const evalResult = await run(evaluator, [
6264
{ role: "user", content: `Original Request: ${input}\nGenerated Content: ${content}` }
6365
]);
6466

backend/src/ai/agents/base/patterns/orchestrator-workers.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Agent, run, withTrace } from "@openai/agents";
1+
// Dynamic imports used instead of static
22
import { Agent as CFAgent, callable } from "agents";
33
import { z } from "zod";
44

@@ -22,30 +22,32 @@ type OrchestratorState = {
2222
export class OrchestratorAgent extends CFAgent<Env, OrchestratorState> {
2323
initialState: OrchestratorState = { results: {} };
2424

25-
// 1. Planner Agent
26-
planner = new Agent({
27-
name: "Planner",
28-
instructions: "Break the user request into smaller, distinct tasks.",
29-
outputType: PlanSchema
30-
});
25+
@callable()
26+
async processRequest(objective: string) {
27+
const { Agent, run, withTrace } = await import("@openai/agents");
28+
29+
// 1. Planner Agent
30+
const planner = new Agent({
31+
name: "Planner",
32+
instructions: "Break the user request into smaller, distinct tasks.",
33+
outputType: PlanSchema
34+
});
3135

32-
// 2. Worker Agents
33-
researcher = new Agent({
34-
name: "Researcher",
35-
instructions: "You are a research assistant. Find information and summarize."
36-
});
36+
// 2. Worker Agents
37+
const researcher = new Agent({
38+
name: "Researcher",
39+
instructions: "You are a research assistant. Find information and summarize."
40+
});
3741

38-
coder = new Agent({
39-
name: "Coder",
40-
instructions: "You are a software engineer. Write code snippets based on instructions."
41-
});
42+
const coder = new Agent({
43+
name: "Coder",
44+
instructions: "You are a software engineer. Write code snippets based on instructions."
45+
});
4246

43-
@callable()
44-
async processRequest(objective: string) {
4547
return await withTrace("Orchestrator Workflow", async () => {
4648

4749
// Step 1: Create Plan
48-
const planResult = await run(this.planner, objective);
50+
const planResult = await run(planner, objective);
4951
const plan = planResult.finalOutput;
5052

5153
if (!plan) return "Failed to generate plan";
@@ -59,8 +61,8 @@ export class OrchestratorAgent extends CFAgent<Env, OrchestratorState> {
5961
console.log(`[Orchestrator] Executing task: ${task.id}`);
6062

6163
let workerAgent;
62-
if (task.workerType === "researcher") workerAgent = this.researcher;
63-
else workerAgent = this.coder;
64+
if (task.workerType === "researcher") workerAgent = researcher;
65+
else workerAgent = coder;
6466

6567
// Run worker with context
6668
const result = await run(workerAgent, [

0 commit comments

Comments
 (0)