From 7cd2d7e2f706abf464c2436076c30567e96a01f3 Mon Sep 17 00:00:00 2001 From: Kris Braun Date: Sun, 19 Oct 2025 12:09:18 -0400 Subject: [PATCH 1/3] AI model selection based on preferences --- .changeset/fiery-times-create.md | 5 ++ sdk/src/tools/ai.ts | 131 +++++++++++++++++++++++++------ 2 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 .changeset/fiery-times-create.md diff --git a/.changeset/fiery-times-create.md b/.changeset/fiery-times-create.md new file mode 100644 index 0000000..aace8ee --- /dev/null +++ b/.changeset/fiery-times-create.md @@ -0,0 +1,5 @@ +--- +"@plotday/sdk": minor +--- + +Changed: BREAKING: Use ModelPreferences instead of an explicit AIModel in AI.prompt(). This supports BYOK and user preferences. diff --git a/sdk/src/tools/ai.ts b/sdk/src/tools/ai.ts index f50b03b..7261027 100644 --- a/sdk/src/tools/ai.ts +++ b/sdk/src/tools/ai.ts @@ -1,6 +1,6 @@ import type { Static, TSchema } from "typebox"; -import { ITool, type Tools } from ".."; +import { ITool } from ".."; /** * Built-in tool for prompting Large Language Models (LLMs). @@ -43,7 +43,7 @@ import { ITool, type Tools } from ".."; * }); * * const response = await this.ai.prompt({ - * model: AIModel.GPT_4O_MINI, + * model: { speed: "fast", cost: "medium" }, * system: "Classify emails into categories: work, personal, spam, or promotional.", * prompt: `Categorize this email: ${emailContent}`, * outputSchema: schema @@ -54,7 +54,7 @@ import { ITool, type Tools } from ".."; * * async generateResponse(emailContent: string) { * const response = await this.ai.prompt({ - * model: AIModel.GPT_4O_MINI, + * model: AIModel.GPT_5_MINI, * system: "Generate professional email responses that are helpful and concise.", * prompt: `Write a response to: ${emailContent}` * }); @@ -76,16 +76,23 @@ export abstract class AI extends ITool { * * @example * ```typescript - * // Simple text generation + * // Simple text generation with specific model * const response = await ai.prompt({ - * model: AIModel.GPT_4O_MINI, + * model: AIModel.GPT_5_MINI, * prompt: "Explain quantum computing in simple terms" * }); * console.log(response.text); * + * // Using model preferences for automatic selection + * const response = await ai.prompt({ + * model: { speed: "fast", cost: "low" }, + * prompt: "Summarize this text..." + * }); + * console.log(response.text); + * * // With system instructions * const response = await ai.prompt({ - * model: AIModel.CLAUDE_35_SONNET, + * model: { speed: "capable", cost: "high" }, * system: "You are a helpful physics tutor.", * prompt: "Explain quantum entanglement" * }); @@ -93,7 +100,7 @@ export abstract class AI extends ITool { * * // Multi-turn conversation * const response = await ai.prompt({ - * model: AIModel.CLAUDE_35_SONNET, + * model: AIModel.CLAUDE_SONNET_45, * messages: [ * { role: "user", content: "What is 2+2?" }, * { role: "assistant", content: "2+2 equals 4." }, @@ -134,10 +141,66 @@ export abstract class AI extends ITool { * ``` */ abstract prompt( - _request: AIRequest, + _request: AIRequest ): Promise>; } +/** + * Model preferences for selecting an AI model based on performance and cost requirements. + * This allows Plot to match those preferences with user preferences (such as preferred or + * disallowed providers), as well as availability of newer and better models. + * + * @example + * ```typescript + * // Fast and cheap - uses Workers AI models like Llama 3.2 1B + * const response = await ai.prompt({ + * model: { speed: "fast", cost: "low" }, + * prompt: "Summarize this in one sentence: ..." + * }); + * + * // Balanced performance - uses GPT-5 Mini or Gemini 2.5 Flash + * const response = await ai.prompt({ + * model: { speed: "balanced", cost: "medium" }, + * prompt: "Analyze this data..." + * }); + * + * // Most capable - uses Claude Sonnet 4.5 or Opus 4.1 + * const response = await ai.prompt({ + * model: { speed: "capable", cost: "high" }, + * prompt: "Solve this complex reasoning problem..." + * }); + * + * // Request a specific model with a hint + * const response = await ai.prompt({ + * model: { speed: "balanced", cost: "medium", hint: AIModel.CLAUDE_SONNET_45 }, + * prompt: "..." + * }); + * ``` + */ +export type ModelPreferences = { + /** + * Desired speed tier: + * - "fast": Optimized for low latency and quick responses + * - "balanced": Good balance of speed and capability + * - "capable": Maximum reasoning and problem-solving ability + */ + speed: "fast" | "balanced" | "capable"; + + /** + * Desired cost tier: + * - "low": Minimal cost, often using Workers AI models (free/very cheap) + * - "medium": Moderate pricing for good performance + * - "high": Premium pricing for best-in-class models + */ + cost: "low" | "medium" | "high"; + + /** + * Optional hint to suggest a specific model. The system will use this + * model if possible, but may override it based on user preferences. + */ + hint?: AIModel; +}; + /** * Supported AI models available through Cloudflare AI Gateway and Workers AI. * @@ -145,27 +208,38 @@ export abstract class AI extends ITool { * - **OpenAI**: Latest GPT models via AI Gateway * - **Anthropic**: Claude models via AI Gateway (prefix with "anthropic/") * - **Google**: Gemini models via AI Gateway (prefix with "google-ai-studio/") - * - **Workers AI**: Models running on Cloudflare's network + * - **Workers AI**: Models running on Cloudflare's network (free/low cost) */ export enum AIModel { - // OpenAI models + // OpenAI models - Latest GPT and reasoning models + GPT_5 = "openai/gpt-5", + GPT_5_PRO = "openai/gpt-5-pro", + GPT_5_MINI = "openai/gpt-5-mini", + GPT_5_NANO = "openai/gpt-5-nano", GPT_4O = "openai/gpt-4o", GPT_4O_MINI = "openai/gpt-4o-mini", - GPT_4_TURBO = "openai/gpt-4-turbo", - GPT_35_TURBO = "openai/gpt-3.5-turbo", + O3 = "openai/o3", + O3_MINI = "openai/o3-mini", - // Anthropic models - CLAUDE_SONNET_4_5 = "anthropic/claude-sonnet-4-5", - CLAUDE_35_SONNET = "anthropic/claude-3-5-sonnet", - CLAUDE_3_OPUS = "anthropic/claude-3-opus", + // Anthropic models - Claude 4.x and 3.7 series + CLAUDE_SONNET_45 = "anthropic/claude-sonnet-4-5", + CLAUDE_HAIKU_45 = "anthropic/claude-haiku-4-5", + CLAUDE_OPUS_41 = "anthropic/claude-opus-4-1", + CLAUDE_37_SONNET = "anthropic/claude-3-7-sonnet-latest", - // Google models + // Google models - Gemini 2.x series + GEMINI_25_PRO = "google/gemini-2.5-pro", GEMINI_25_FLASH = "google/gemini-2.5-flash", + GEMINI_25_FLASH_LITE = "google/gemini-2.5-flash-lite", + GEMINI_20_FLASH = "google/gemini-2.0-flash", + GEMINI_20_FLASH_LITE = "google/gemini-2.0-flash-lite", - // Cloudflare Workers AI models + // Cloudflare Workers AI models - Free/low-cost models running on Cloudflare's network + LLAMA_4_SCOUT_17B = "meta/llama-4-scout-17b-16e-instruct", LLAMA_33_70B = "meta/llama-3.3-70b-instruct-fp8-fast", - LLAMA_31_8B = "meta/llama-3.1-8b-instruct-fast", - MISTRAL_7B = "meta/mistral-7b-instruct-v0.2", + LLAMA_31_8B = "meta/llama-3.1-8b-instruct-fp8", + LLAMA_32_1B = "meta/llama-3.2-1b-instruct", + DEEPSEEK_R1_32B = "deepseek-ai/deepseek-r1-distill-qwen-32b", } /** @@ -173,12 +247,21 @@ export enum AIModel { */ export interface AIRequest< TOOLS extends AIToolSet, - SCHEMA extends TSchema = never, + SCHEMA extends TSchema = never > { /** * The AI model to use for generation. + * Can be either a specific model from the AIModel enum or preferences (speed/cost tiers). + * + * @example + * // Using a specific model + * model: AIModel.GPT_5_MINI + * + * @example + * // Using preferences + * model: { speed: "fast", cost: "low" } */ - model: AIModel; + model: AIModel | ModelPreferences; /** * System instructions to guide the model's behavior. @@ -240,7 +323,7 @@ export interface AIRequest< */ export interface AIResponse< TOOLS extends AIToolSet, - SCHEMA extends TSchema = never, + SCHEMA extends TSchema = never > { /** * The generated text. @@ -656,7 +739,7 @@ export type AITool = { */ execute?: ( args: inferParameters, - options: ToolExecutionOptions, + options: ToolExecutionOptions ) => PromiseLike; } & ( | { From 59ae64145c535dd75d9b2a9a503ff7627c8ba953 Mon Sep 17 00:00:00 2001 From: Kris Braun Date: Sun, 19 Oct 2025 14:35:29 -0400 Subject: [PATCH 2/3] Reference sdk types in AGENTS rather than duplicating --- agents/chat/src/index.ts | 25 ++++--- sdk/cli/templates/AGENTS.template.md | 106 +++------------------------ sdk/package.json | 4 + sdk/src/agents-guide.ts | 100 +++---------------------- sdk/src/index.ts | 1 + sdk/src/sdk-docs.ts | 106 +++++++++++++++++++++++++++ sdk/src/tools/ai.ts | 38 ++++++---- 7 files changed, 171 insertions(+), 209 deletions(-) create mode 100644 sdk/src/sdk-docs.ts diff --git a/agents/chat/src/index.ts b/agents/chat/src/index.ts index 61c4a06..feae107 100644 --- a/agents/chat/src/index.ts +++ b/agents/chat/src/index.ts @@ -1,21 +1,22 @@ +import { Type } from "typebox"; + import { type Activity, ActivityType, Agent, AuthorType, Tag, - Tools, + type Tools, } from "@plotday/sdk"; -import { AI, AIModel, type AIMessage } from "@plotday/sdk/tools/ai"; +import { AI, type AIMessage } from "@plotday/sdk/tools/ai"; import { Plot } from "@plotday/sdk/tools/plot"; -import { Type } from "typebox"; export default class extends Agent { private ai: AI; private plot: Plot; constructor(protected tools: Tools) { - super(); + super(tools); this.ai = tools.get(AI); this.plot = tools.get(Plot); } @@ -26,7 +27,7 @@ export default class extends Agent { previous: Activity; tagsAdded: Record; tagsRemoved: Record; - }, + } ) { if (changes) return; @@ -35,7 +36,7 @@ export default class extends Agent { if ( activity.note?.includes("@chat") || previousActivities.some((activity: any) => - activity.note.includes("@chat"), + activity.note.includes("@chat") ) ) { // Add Thinking tag to indicate processing has started @@ -63,7 +64,7 @@ You can also create tasks, but should only do so when the user explicitly asks y ? "assistant" : "user", content: (prevActivity.note ?? prevActivity.title)!, - }) satisfies AIMessage, + } satisfies AIMessage) ), ]; @@ -81,7 +82,7 @@ You can also create tasks, but should only do so when the user explicitly asks y Type.String({ description: "Optional detailed description of the action item. Can include markdown. Only add when important details are needed beyond the title.", - }), + }) ), title: Type.String({ description: @@ -90,13 +91,13 @@ You can also create tasks, but should only do so when the user explicitly asks y }), { description: "Tasks to create in response to the user's request.", - }, - ), + } + ) ), }); const response = await this.ai.prompt({ - model: AIModel.LLAMA_33_70B, + model: { speed: "balanced", cost: "low" }, messages, outputSchema: schema, }); @@ -117,7 +118,7 @@ You can also create tasks, but should only do so when the user explicitly asks y priority: activity.priority, type: ActivityType.Task, start: new Date(), - }), + }) ) ?? []), ]); diff --git a/sdk/cli/templates/AGENTS.template.md b/sdk/cli/templates/AGENTS.template.md index 5c41aad..5c7eeac 100644 --- a/sdk/cli/templates/AGENTS.template.md +++ b/sdk/cli/templates/AGENTS.template.md @@ -20,12 +20,7 @@ Plot agents are TypeScript classes that extend the `Agent` base class. Agents in ## Agent Structure Pattern ```typescript -import { - type Activity, - Agent, - type Priority, - type Tools, -} from "@plotday/sdk"; +import { type Activity, Agent, type Priority, type Tools } from "@plotday/sdk"; import { Plot } from "@plotday/sdk/tools/plot"; export default class MyAgent extends Agent { @@ -66,99 +61,22 @@ All `tools.get()` calls must occur in the constructor as they are used for depen ### Built-in Tools (Always Available) -#### Plot Tool +For complete API documentation of built-in tools including all methods, types, and detailed examples, see the TypeScript definitions in your installed package at `node_modules/@plotday/sdk/src/tools/*.ts`. Each tool file contains comprehensive JSDoc documentation. -Core functionality for managing activities: +**Quick reference - Available tools:** -```typescript -import { Plot } from "@plotday/sdk/tools/plot"; - -// Create activity -await this.plot.createActivity({ - type: ActivityType.Task, - title: "Task title", - start: new Date(), - end: null, - links: [], // Optional activity links - parent: { id: "parent-activity-id" }, // Optional parent -}); - -// Update activity -await this.plot.updateActivity(activityId, { - title: "New title", - completed: true, -}); - -// Delete activity -await this.plot.deleteActivity(activityId); - -// Add contacts -await this.plot.addContacts(contacts); -``` - -#### Store Tool - -Persistent key-value storage (available directly via `this`): - -```typescript -// Set value (no import needed) -await this.set("key", value); - -// Get value -const value = await this.get("key"); - -// Clear value -await this.clear("key"); - -// Clear all values -await this.clearAll(); -``` +- `@plotday/sdk/tools/plot` - Core data layer (create/update activities, priorities, contacts) +- `@plotday/sdk/tools/ai` - LLM integration (text generation, structured output, reasoning) + - Use ModelPreferences to specify `speed` (fast/balanced/capable) and `cost` (low/medium/high) +- `@plotday/sdk/tools/store` - Persistent key-value storage (also via `this.set()`, `this.get()`) +- `@plotday/sdk/tools/run` - Queue batched work (also via `this.run()`) +- `@plotday/sdk/tools/callback` - Persistent function references (also via `this.callback()`) +- `@plotday/sdk/tools/auth` - OAuth2 authentication flows +- `@plotday/sdk/tools/webhook` - HTTP webhook management +- `@plotday/sdk/tools/agent` - Manage other agents **Critical**: Never use instance variables for state. They are lost after function execution. Always use Store methods. -#### Run Tool - -Queue separate chunks of work (available directly via `this`): - -```typescript -// Create callback and queue execution (no import needed) -const callback = await this.callback("functionName", { context: "data" }); -await this.run(callback); - -// The function must exist on the agent class -async functionName(args: any, context: { context: string }) { - // Process batch and queue next if needed - if (hasMore) { - const nextCallback = await this.callback("functionName", { context: "next" }); - await this.run(nextCallback); - } -} -``` - -#### Callback Tool - -Create persistent function references (for webhooks, auth callbacks - available directly via `this`): - -```typescript -// Create callback (no import needed) -const token = await this.callback("onAuthComplete", { - provider: "google", -}); - -// Pass token to external service or store it -await this.set("webhook_token", token); - -// When callback is invoked, your function is called -async onAuthComplete(authResult: any, context?: any) { - // Handle callback - const provider = context?.provider; -} - -// Clean up -await this.deleteCallback(token); -await this.deleteAllCallbacks(); // Delete all for this agent -``` - ### External Tools (Add to package.json) Add tool dependencies to `package.json`: diff --git a/sdk/package.json b/sdk/package.json index 1fbd818..f391987 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -66,6 +66,10 @@ "types": "./dist/agents-guide.d.ts", "default": "./dist/agents-guide.js" }, + "./sdk-docs": { + "types": "./dist/sdk-docs.d.ts", + "default": "./dist/sdk-docs.js" + }, "./tsconfig.base.json": "./tsconfig.base.json" }, "files": [ diff --git a/sdk/src/agents-guide.ts b/sdk/src/agents-guide.ts index 789d4ef..7df6860 100644 --- a/sdk/src/agents-guide.ts +++ b/sdk/src/agents-guide.ts @@ -80,99 +80,23 @@ Assign tool instances to class properties for use in other methods. ### Built-in Tools (Always Available) -#### Plot Tool +The following tools are always available to agents. For complete API documentation including all methods, parameters, return types, and detailed examples, refer to the TypeScript definitions which are provided with full JSDoc when generating agents. -Core functionality for managing activities: +**Available Built-in Tools:** +- **Plot** (\`@plotday/sdk/tools/plot\`): Core data layer - create/update activities, priorities, contacts +- **AI** (\`@plotday/sdk/tools/ai\`): LLM access for text generation, structured output, reasoning + - Use ModelPreferences to specify \`speed\` (fast/balanced/capable) and \`cost\` (low/medium/high) +- **Store** (\`@plotday/sdk/tools/store\`): Persistent key-value storage (also available via \`this.set()\`, \`this.get()\`) +- **Run** (\`@plotday/sdk/tools/run\`): Queue batched work (also available via \`this.run()\`) +- **Callback** (\`@plotday/sdk/tools/callback\`): Persistent function references (also available via \`this.callback()\`) +- **Auth** (\`@plotday/sdk/tools/auth\`): OAuth2 authentication flows +- **Webhook** (\`@plotday/sdk/tools/webhook\`): HTTP webhook management +- **AgentManager** (\`@plotday/sdk/tools/agent\`): Manage other agents -\`\`\`typescript -import { Plot } from "@plotday/sdk/tools/plot"; - -// Create activity -await this.plot.createActivity({ - type: ActivityType.Task, - title: "Task title", - start: new Date(), - end: null, - links: [], // Optional activity links - parent: { id: "parent-activity-id" }, // Optional parent -}); - -// Update activity -await this.plot.updateActivity(activityId, { - title: "New title", - completed: true, -}); - -// Delete activity -await this.plot.deleteActivity(activityId); - -// Add contacts -await this.plot.addContacts(contacts); -\`\`\` - -#### Store Tool - -Persistent key-value storage (available directly via \`this\`): - -\`\`\`typescript -// Set value (no import needed) -await this.set("key", value); - -// Get value -const value = await this.get("key"); - -// Clear value -await this.clear("key"); - -// Clear all values -await this.clearAll(); -\`\`\` +See the SDK type definitions for full API documentation with usage examples. **Critical**: Never use instance variables for state. They are lost after function execution. Always use Store methods. -#### Run Tool - -Queue separate chunks of work (available directly via \`this\`): - -\`\`\`typescript -// Create callback and queue execution (no import needed) -const callback = await this.callback("functionName", { context: "data" }); -await this.run(callback); - -// The function must exist on the agent class -async functionName(args: any, context: { context: string }) { - // Process batch and queue next if needed - if (hasMore) { - const nextCallback = await this.callback("functionName", { context: "next" }); - await this.run(nextCallback); - } -} -\`\`\` - -#### Callback Tool - -Create persistent function references (for webhooks, auth callbacks - available directly via \`this\`): - -\`\`\`typescript -// Create callback (no import needed) -const token = await this.callback("onAuthComplete", { - provider: "google", -}); - -// Pass token to external service or store it -await this.set("webhook_token", token); - -// When callback is invoked, your function is called -async onAuthComplete(authResult: any, context?: any) { - // Handle callback - const provider = context?.provider; -} - -// Clean up -await this.deleteCallback(token); -await this.deleteAllCallbacks(); // Delete all for this agent -\`\`\` - ### External Tools (Add to package.json) Add tool dependencies to \`package.json\`: diff --git a/sdk/src/index.ts b/sdk/src/index.ts index f565b86..215616c 100644 --- a/sdk/src/index.ts +++ b/sdk/src/index.ts @@ -2,3 +2,4 @@ export * from "./agent"; export * from "./plot"; export * from "./tag"; export * from "./tools"; +export { getSDKDocumentation } from "./sdk-docs"; diff --git a/sdk/src/sdk-docs.ts b/sdk/src/sdk-docs.ts new file mode 100644 index 0000000..ba5814d --- /dev/null +++ b/sdk/src/sdk-docs.ts @@ -0,0 +1,106 @@ +import * as fs from "fs"; +import * as path from "path"; +import { fileURLToPath } from "url"; + +/** + * Gets complete SDK type definitions with import paths for LLM context. + * + * This function reads all SDK type definition files and formats them with + * their corresponding import paths. Used by agent generators to provide + * complete type information to LLMs. + * + * @returns Formatted string containing all SDK type definitions with import paths + */ +export function getSDKDocumentation(): string { + // Get the directory of this file + const __filename = fileURLToPath(import.meta.url); + const sdkRoot = path.dirname(__filename); + const packageRoot = path.dirname(sdkRoot); + + // Read package.json to get exports dynamically + const packageJsonPath = path.join(packageRoot, "package.json"); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")); + + // Build typeFiles from package.json exports + // Exclude non-type exports like tsconfig.base.json + const typeFiles: Array<{ file: string; importPath: string }> = []; + const exports = packageJson.exports || {}; + + for (const [exportPath, exportValue] of Object.entries(exports)) { + // Skip non-type exports + if ( + exportPath === "./tsconfig.base.json" || + exportPath === "./agents-guide" || + exportPath === "./sdk-docs" + ) { + continue; + } + + // Get the types field from the export + const typesPath = + typeof exportValue === "object" && exportValue !== null + ? (exportValue as any).types + : null; + + if (!typesPath || typeof typesPath !== "string") { + continue; + } + + // Convert dist/*.d.ts to src/*.ts + const sourceFile = typesPath + .replace(/^\.\/dist\//, "") + .replace(/\.d\.ts$/, ".ts"); + + // Build import path + const importPath = + exportPath === "." ? "@plotday/sdk" : `@plotday/sdk${exportPath.slice(1)}`; + + typeFiles.push({ file: sourceFile, importPath }); + } + + // Sort to ensure consistent ordering: + // 1. Root exports (@plotday/sdk) first + // 2. Then by directory depth and alphabetically + typeFiles.sort((a, b) => { + const aDepth = a.file.split("/").length; + const bDepth = b.file.split("/").length; + + // Root exports first + if (a.importPath === "@plotday/sdk" && b.importPath !== "@plotday/sdk") + return -1; + if (b.importPath === "@plotday/sdk" && a.importPath !== "@plotday/sdk") + return 1; + + // Then by depth + if (aDepth !== bDepth) return aDepth - bDepth; + + // Then alphabetically + return a.file.localeCompare(b.file); + }); + + let documentation = "# Plot SDK Type Definitions\n\n"; + documentation += + "Complete type definitions with JSDoc documentation for all Plot SDK types.\n"; + documentation += + "These are the source files - use the import paths shown to import types in your agent code.\n\n"; + + for (const { file, importPath } of typeFiles) { + const filePath = path.join(sdkRoot, file); + + // Skip if file doesn't exist (graceful degradation) + if (!fs.existsSync(filePath)) { + console.warn(`Warning: SDK file not found: ${filePath}`); + continue; + } + + const content = fs.readFileSync(filePath, "utf-8"); + + documentation += `## ${importPath}\n\n`; + documentation += "```typescript\n"; + documentation += `// Import from: ${importPath}\n\n`; + documentation += content; + documentation += "\n```\n\n"; + } + + return documentation; +} diff --git a/sdk/src/tools/ai.ts b/sdk/src/tools/ai.ts index 7261027..63aa06b 100644 --- a/sdk/src/tools/ai.ts +++ b/sdk/src/tools/ai.ts @@ -54,7 +54,7 @@ import { ITool } from ".."; * * async generateResponse(emailContent: string) { * const response = await this.ai.prompt({ - * model: AIModel.GPT_5_MINI, + * model: { speed: "fast", cost: "medium" }, * system: "Generate professional email responses that are helpful and concise.", * prompt: `Write a response to: ${emailContent}` * }); @@ -76,21 +76,21 @@ export abstract class AI extends ITool { * * @example * ```typescript - * // Simple text generation with specific model + * // Simple text generation * const response = await ai.prompt({ - * model: AIModel.GPT_5_MINI, + * model: { speed: "fast", cost: "medium" }, * prompt: "Explain quantum computing in simple terms" * }); * console.log(response.text); * - * // Using model preferences for automatic selection + * // Fast and cheap for simple tasks * const response = await ai.prompt({ * model: { speed: "fast", cost: "low" }, * prompt: "Summarize this text..." * }); * console.log(response.text); * - * // With system instructions + * // With system instructions for complex reasoning * const response = await ai.prompt({ * model: { speed: "capable", cost: "high" }, * system: "You are a helpful physics tutor.", @@ -100,7 +100,7 @@ export abstract class AI extends ITool { * * // Multi-turn conversation * const response = await ai.prompt({ - * model: AIModel.CLAUDE_SONNET_45, + * model: { speed: "balanced", cost: "medium" }, * messages: [ * { role: "user", content: "What is 2+2?" }, * { role: "assistant", content: "2+2 equals 4." }, @@ -111,7 +111,7 @@ export abstract class AI extends ITool { * * // Structured output with Typebox schema * const response = await ai.prompt({ - * model: AIModel.GPT_4O, + * model: { speed: "fast", cost: "medium" }, * prompt: "Extract information: John is 30 years old", * outputSchema: Type.Object({ * name: Type.String(), @@ -122,7 +122,7 @@ export abstract class AI extends ITool { * * // Tool calling * const response = await ai.prompt({ - * model: AIModel.GPT_4O_MINI, + * model: { speed: "balanced", cost: "medium" }, * prompt: "What's the weather in San Francisco?", * tools: { * getWeather: { @@ -250,18 +250,26 @@ export interface AIRequest< SCHEMA extends TSchema = never > { /** - * The AI model to use for generation. - * Can be either a specific model from the AIModel enum or preferences (speed/cost tiers). + * Model selection preferences based on desired speed and cost characteristics. + * Plot will automatically select the best available model matching these preferences. * * @example - * // Using a specific model - * model: AIModel.GPT_5_MINI + * // Fast and cheap - good for simple tasks + * model: { speed: "fast", cost: "low" } * * @example - * // Using preferences - * model: { speed: "fast", cost: "low" } + * // Balanced performance - general purpose + * model: { speed: "balanced", cost: "medium" } + * + * @example + * // Maximum capability - complex reasoning + * model: { speed: "capable", cost: "high" } + * + * @example + * // With a specific model hint + * model: { speed: "balanced", cost: "medium", hint: "anthropic/claude-sonnet-4-5" } */ - model: AIModel | ModelPreferences; + model: ModelPreferences; /** * System instructions to guide the model's behavior. From 1aed07be429d271523fb79188b61597822aeb587 Mon Sep 17 00:00:00 2001 From: Kris Braun Date: Sun, 19 Oct 2025 15:34:12 -0400 Subject: [PATCH 3/3] Update generate API path --- sdk/cli/commands/generate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cli/commands/generate.ts b/sdk/cli/commands/generate.ts index ebc8c2b..6ae8276 100644 --- a/sdk/cli/commands/generate.ts +++ b/sdk/cli/commands/generate.ts @@ -170,7 +170,7 @@ export async function generateCommand(options: GenerateOptions) { try { out.progress("Generating agent from spec..."); - const response = await fetch(`${options.apiUrl}/v1/agent/${agentId}/generate`, { + const response = await fetch(`${options.apiUrl}/v1/agent/generate`, { method: "POST", headers: { "Content-Type": "application/json",