Skip to content
Merged
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
22 changes: 21 additions & 1 deletion src/runner/templates/agents/cloudflare/vercel/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"displayName": "Vercel AI SDK (Cloudflare)",
"type": "agentic",
"platform": "cloudflare",
"streamingMode": "both",
"dependencies": [
{
"package": "ai",
Expand All @@ -11,8 +12,27 @@
{
"package": "@ai-sdk/openai",
"version": "latest"
},
{
"package": "@ai-sdk/anthropic",
"version": "latest"
}
],
"versions": ["6.0.116"],
"sentryVersions": ["latest"]
"sentryVersions": ["latest"],
"options": {
"agentStyle": ["function", "class"],
"provider": [
"openai",
{
"value": "anthropic",
"overrides": {
"modelOverrides": {
"request": "claude-haiku-4-5",
"response": "claude-haiku-4-5*"
}
}
}
]
}
}
124 changes: 120 additions & 4 deletions src/runner/templates/agents/cloudflare/vercel/template.njk
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,33 @@
{% endblock %}

{% block imports %}
{% if agentStyle == "class" %}
import { ToolLoopAgent, tool, jsonSchema, stepCountIs } from "ai";
{% elif isStreaming %}
import { streamText, tool, jsonSchema, stepCountIs } from "ai";
{% else %}
import { generateText, tool, jsonSchema, stepCountIs } from "ai";
{% endif %}
{% if provider == "anthropic" %}
import { createAnthropic } from "@ai-sdk/anthropic";
{% else %}
import { createOpenAI } from "@ai-sdk/openai";
{% endif %}
{% endblock %}

{% block dynamic_imports %}
{% if provider == "anthropic" %}
const anthropic = createAnthropic({ apiKey: env.ANTHROPIC_API_KEY });
{% else %}
const openai = createOpenAI({ apiKey: env.OPENAI_API_KEY });
{% endif %}
{% endblock %}

{# Helper macro for model reference #}
{% macro modelRef(input) %}
{% if provider == "anthropic" %}anthropic({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}){% else %}openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}){% endif %}
{% endmacro %}

{% block test %}
{% if agent and agent.tools and agent.tools.length > 0 %}
const tools = {
Expand Down Expand Up @@ -70,10 +89,106 @@ import { createOpenAI } from "@ai-sdk/openai";
// Request {{ loop.index }}{% if loop.length > 1 %} of {{ loop.length }}{% endif %}

try {
{% if agentStyle == "class" %}
// ToolLoopAgent class-based approach
const agent = new ToolLoopAgent({
model: {{ modelRef(input) | trim }},
{% if agent and agent.tools and agent.tools.length > 0 %}
tools,
{% endif %}
{% if system_content %}
instructions: "{{ system_content }}",
{% endif %}
stopWhen: stepCountIs(10),
experimental_telemetry: {
isEnabled: true,
functionId: "{{ agent.name if agent else 'assistant' }}",
recordInputs: true,
recordOutputs: true,
},
});

{% if isStreaming %}
{% if user_content is iterable and user_content is not string %}
const { textStream } = await agent.stream({
messages: [
{
role: "user",
content: {{ renderVercelContent(user_content) }},
},
],
});
{% else %}
const { textStream } = await agent.stream({
prompt: "{{ user_content }}",
});
{% endif %}
const chunks = [];
for await (const chunk of textStream) {
chunks.push(chunk);
}
console.log("Response:", chunks.join(""));
{% else %}
{% if user_content is iterable and user_content is not string %}
const { text } = await agent.generate({
messages: [
{
role: "user",
content: {{ renderVercelContent(user_content) }},
},
],
});
{% else %}
const { text } = await agent.generate({
prompt: "{{ user_content }}",
});
{% endif %}
console.log("Response:", text);
{% endif %}
{% else %}
// Function-based approach
{% if isStreaming %}
{% if user_content is iterable and user_content is not string %}
const { textStream } = streamText({
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
messages: [
{
role: "user",
content: {{ renderVercelContent(user_content) }},
},
],
{% if agent and agent.tools and agent.tools.length > 0 %}
tools,
stopWhen: stepCountIs(10),
{% endif %}
experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },
});
{% else %}
const { textStream } = streamText({
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
prompt: "{{ user_content }}",
{% if agent and agent.tools and agent.tools.length > 0 %}
tools,
stopWhen: stepCountIs(10),
{% endif %}
experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },
});
{% endif %}
const chunks = [];
for await (const chunk of textStream) {
chunks.push(chunk);
}
console.log("Response:", chunks.join(""));
{% else %}
{% if user_content is iterable and user_content is not string %}
// Multimodal content - use messages array
const { text } = await generateText({
model: openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}),
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
Expand All @@ -90,9 +205,8 @@ import { createOpenAI } from "@ai-sdk/openai";
experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },
});
{% else %}
// Simple text prompt
const { text } = await generateText({
model: openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}),
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
Expand All @@ -105,6 +219,8 @@ import { createOpenAI } from "@ai-sdk/openai";
});
{% endif %}
console.log("Response:", text);
{% endif %}
{% endif %}
} catch (error) {
Sentry.captureException(error);
console.error("Error:", error.message);
Expand Down
21 changes: 20 additions & 1 deletion src/runner/templates/agents/nextjs/vercel/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
"package": "@ai-sdk/openai",
"version": "latest"
},
{
"package": "@ai-sdk/anthropic",
"version": "latest"
},
{
"package": "@sentry/nextjs",
"version": "sentry"
Expand All @@ -23,5 +27,20 @@
}
],
"versions": ["6.0.116"],
"sentryVersions": ["latest"]
"sentryVersions": ["latest"],
"options": {
"agentStyle": ["function", "class"],
"provider": [
"openai",
{
"value": "anthropic",
"overrides": {
"modelOverrides": {
"request": "claude-haiku-4-5",
"response": "claude-haiku-4-5*"
}
}
}
]
}
}
85 changes: 81 additions & 4 deletions src/runner/templates/agents/nextjs/vercel/template.njk
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,24 @@
{% endmacro %}

{% block dynamic_imports %}
{% if agentStyle == "class" %}
const { ToolLoopAgent, tool, jsonSchema, stepCountIs } = await import("ai");
{% else %}
const { generateText, streamText, tool, jsonSchema, stepCountIs } = await import("ai");
{% endif %}
{% if provider == "anthropic" %}
const { anthropic } = await import("@ai-sdk/anthropic");
{% else %}
const { openai } = await import("@ai-sdk/openai");
{% endif %}
console.log('Vercel AI SDK initialized (auto-instrumentation enabled)');
{% endblock %}

{# Helper macro for model reference #}
{% macro modelRef(input) %}
{% if provider == "anthropic" %}anthropic({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}){% else %}openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}){% endif %}
{% endmacro %}

{% block test %}
{% if agent and agent.tools and agent.tools.length > 0 %}
const tools = {
Expand Down Expand Up @@ -58,13 +71,76 @@ console.log('Vercel AI SDK initialized (auto-instrumentation enabled)');
// Request {{ loop.index }}{% if loop.length > 1 %} of {{ loop.length }}{% endif %}

try {
{% if agentStyle == "class" %}
// ToolLoopAgent class-based approach
const agent = new ToolLoopAgent({
model: {{ modelRef(input) | trim }},
{% if agent and agent.tools and agent.tools.length > 0 %}
tools,
{% endif %}
{% if system_content %}
instructions: "{{ system_content }}",
{% endif %}
stopWhen: stepCountIs(10),
experimental_telemetry: {
isEnabled: true,
functionId: "{{ agent.name if agent else 'assistant' }}",
recordInputs: true,
recordOutputs: true,
},
});

{% if isStreaming %}
console.log('Starting streaming request {{ loop.index }}...');

{% if user_content is iterable and user_content is not string %}
const { textStream } = await agent.stream({
messages: [
{
role: "user",
content: {{ renderVercelContent(user_content) }},
},
],
});
{% else %}
const { textStream } = await agent.stream({
prompt: "{{ user_content }}",
});
Comment thread
cursor[bot] marked this conversation as resolved.
{% endif %}

const chunks = [];
for await (const chunk of textStream) {
chunks.push(chunk);
}
console.log("Response {{ loop.index }}:", chunks.join(""));
{% else %}
console.log('Starting blocking request {{ loop.index }}...');

{% if user_content is iterable and user_content is not string %}
const { text } = await agent.generate({
messages: [
{
role: "user",
content: {{ renderVercelContent(user_content) }},
},
],
});
{% else %}
const { text } = await agent.generate({
prompt: "{{ user_content }}",
});
{% endif %}
console.log("Response {{ loop.index }}:", text);
{% endif %}
{% else %}
// Function-based approach
{% if isStreaming %}
console.log('Starting streaming request {{ loop.index }}...');

{% if user_content is iterable and user_content is not string %}
// Multimodal content - use messages array
const { textStream } = streamText({
model: openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}),
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
Expand All @@ -87,7 +163,7 @@ console.log('Vercel AI SDK initialized (auto-instrumentation enabled)');
{% else %}
// Simple text prompt
const { textStream } = streamText({
model: openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}),
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
Expand Down Expand Up @@ -115,7 +191,7 @@ console.log('Vercel AI SDK initialized (auto-instrumentation enabled)');
{% if user_content is iterable and user_content is not string %}
// Multimodal content - use messages array
const { text } = await generateText({
model: openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}),
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
Expand All @@ -138,7 +214,7 @@ console.log('Vercel AI SDK initialized (auto-instrumentation enabled)');
{% else %}
// Simple text prompt
const { text } = await generateText({
model: openai({% if causeAPIError %}"invalid-model"{% else %}"{{ input.model }}"{% endif %}),
model: {{ modelRef(input) | trim }},
{% if system_content %}
system: "{{ system_content }}",
{% endif %}
Expand All @@ -155,6 +231,7 @@ console.log('Vercel AI SDK initialized (auto-instrumentation enabled)');
});
{% endif %}
console.log("Response {{ loop.index }}:", text);
{% endif %}
{% endif %}
} catch (error) {
Sentry.captureException(error);
Expand Down
Loading
Loading