From ff5f0320c20024b22f56900ca81de82e410742cc Mon Sep 17 00:00:00 2001 From: Hisku Date: Mon, 26 Jan 2026 10:16:00 +0000 Subject: [PATCH 01/22] feat: initialize StackOne TypeScript agent with essential configuration and example --- apps/stackone-typescript-agent/.env.example | 7 + apps/stackone-typescript-agent/package.json | 23 ++ apps/stackone-typescript-agent/src/agent.ts | 400 +++++++++++++++++++ apps/stackone-typescript-agent/tsconfig.json | 17 + 4 files changed, 447 insertions(+) create mode 100644 apps/stackone-typescript-agent/.env.example create mode 100644 apps/stackone-typescript-agent/package.json create mode 100644 apps/stackone-typescript-agent/src/agent.ts create mode 100644 apps/stackone-typescript-agent/tsconfig.json diff --git a/apps/stackone-typescript-agent/.env.example b/apps/stackone-typescript-agent/.env.example new file mode 100644 index 0000000..8212113 --- /dev/null +++ b/apps/stackone-typescript-agent/.env.example @@ -0,0 +1,7 @@ +STACKONE_API_KEY=you_stackone_api_key + +# For linked accounts (get from StackOne Dashboard after linking) +STACKONE_ACCOUNT_ID=you_stackone_account_id + +# For AI providers +ANTHROPIC_API_KEY=your_anthropic_api_key # For Claude-based agents \ No newline at end of file diff --git a/apps/stackone-typescript-agent/package.json b/apps/stackone-typescript-agent/package.json new file mode 100644 index 0000000..2547408 --- /dev/null +++ b/apps/stackone-typescript-agent/package.json @@ -0,0 +1,23 @@ +{ + "name": "stackone-typescript-agent", + "version": "1.0.0", + "description": "StackOne AI Agent Example using Vercel AI SDK with dynamic MCP tools", + "type": "module", + "scripts": { + "agent": "tsx src/agent.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@ai-sdk/anthropic": "^1.0.0", + "@ai-sdk/openai": "^1.0.0", + "ai": "^4.0.0", + "dotenv": "^16.4.0", + "zod": "^3.23.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.19.0", + "typescript": "^5.6.0" + } + } + \ No newline at end of file diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts new file mode 100644 index 0000000..295c5ff --- /dev/null +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -0,0 +1,400 @@ +/** + * StackOne AI Agent Example - Using Vercel AI SDK + * + * This agent dynamically creates tools from StackOne's MCP endpoint, + * allowing Claude to call them directly (not via meta-tool). + */ + +import "dotenv/config"; +import { anthropic } from "@ai-sdk/anthropic"; +import { generateText, CoreMessage, CoreTool } from "ai"; +import { z } from "zod"; +import * as readline from "readline"; + +// StackOne MCP configuration +const STACKONE_API_KEY = process.env.STACKONE_API_KEY || ""; +const MCP_ENDPOINT = "https://api.stackone.com/mcp"; + +// Tool and account mappings +const toolToAccount = new Map(); + +// Conversation history +const conversationHistory: CoreMessage[] = []; +const MAX_HISTORY_TURNS = 10; +const MAX_TOOL_RESULT_LENGTH = 24000; + +interface LinkedAccount { + id: string; + provider: string; + status: string; +} + +interface McpTool { + name: string; + description?: string; + inputSchema?: { + type?: string; + properties?: Record; + required?: string[]; + }; +} + +/** + * Fetch all linked accounts from StackOne + */ +async function getLinkedAccounts(): Promise { + const response = await fetch("https://api.stackone.com/accounts", { + headers: { + Authorization: `Basic ${Buffer.from(STACKONE_API_KEY + ":").toString("base64")}`, + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch accounts: ${response.status}`); + } + + return response.json(); +} + +/** + * Make an MCP request to StackOne + */ +async function mcpRequest( + method: string, + params: Record = {}, + accountId: string +): Promise { + const response = await fetch(MCP_ENDPOINT, { + method: "POST", + headers: { + Authorization: `Basic ${Buffer.from(STACKONE_API_KEY + ":").toString("base64")}`, + "x-account-id": accountId, + "Content-Type": "application/json", + Accept: "application/json, text/event-stream", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: `req-${method}-${Date.now()}`, + method, + params, + }), + }); + + if (!response.ok) { + throw new Error(`MCP request failed: ${response.status}`); + } + + return response.json(); +} + +/** + * Call a StackOne tool via MCP + */ +async function callTool(toolName: string, args: Record): Promise { + const accountId = toolToAccount.get(toolName); + if (!accountId) { + throw new Error(`Unknown tool: ${toolName}`); + } + + const result = (await mcpRequest( + "tools/call", + { name: toolName, arguments: args }, + accountId + )) as { result?: unknown }; + + return result.result || result; +} + +/** + * Convert MCP tools to Vercel AI SDK tools + */ +function createVercelTool(mcpTool: McpTool): CoreTool { + const toolName = mcpTool.name; + + return { + description: mcpTool.description || `Call the ${toolName} tool`, + parameters: z.record(z.unknown()).describe("Arguments for the tool"), + execute: async (args: Record) => { + console.log(`šŸ”§ Calling: ${toolName}`); + + try { + const result = await callTool(toolName, args); + const resultStr = JSON.stringify(result, null, 2); + + // Truncate large results + if (resultStr.length > MAX_TOOL_RESULT_LENGTH) { + console.log(` ⚠ Truncated (${resultStr.length} chars)`); + return { + success: true, + data: resultStr.slice(0, MAX_TOOL_RESULT_LENGTH), + truncated: true, + note: "Result truncated. Request more specific data if needed.", + }; + } + + return { success: true, data: result }; + } catch (error) { + console.log(` āŒ Error: ${error}`); + return { success: false, error: String(error) }; + } + }, + }; +} + +interface FetchToolsResult { + tools: Record; + providerCounts: Record; +} + +/** + * Fetch tools from all linked accounts and create Vercel tools + */ +async function fetchAndCreateTools(): Promise { + console.log("Fetching linked accounts..."); + const accounts = await getLinkedAccounts(); + + const tools: Record = {}; + const providerCounts: Record = {}; + + for (const account of accounts) { + if (account.status !== "active") { + console.log(` Skipping ${account.provider} (status: ${account.status})`); + continue; + } + + console.log(`Fetching tools from ${account.provider}...`); + + try { + const result = (await mcpRequest("tools/list", {}, account.id)) as { + result?: { tools?: McpTool[] }; + }; + const mcpTools = result.result?.tools || []; + + for (const mcpTool of mcpTools) { + toolToAccount.set(mcpTool.name, account.id); + tools[mcpTool.name] = createVercelTool(mcpTool); + } + + providerCounts[account.provider] = mcpTools.length; + console.log(` Found ${mcpTools.length} tools`); + } catch (error) { + console.warn(` Warning: Could not fetch from ${account.provider}: ${error}`); + } + } + + const total = Object.keys(tools).length; + console.log(`\nTotal: ${total} tools from ${Object.keys(providerCounts).length} providers`); + + return { tools, providerCounts }; +} + +/** + * Build system prompt dynamically based on available providers + */ +function buildSystemPrompt(providerCounts: Record): string { + const providers = Object.entries(providerCounts); + + // Build capabilities list from actual providers + const capabilities = providers + .map(([provider, count]) => `- **${provider}**: ${count} tools available`) + .join('\n'); + + // Base prompt + let prompt = `You are a helpful assistant with access to StackOne's unified API tools. +You can directly call tools for the user's connected services. + +Connected providers: +${capabilities} + +Tool names follow the pattern: provider_action (e.g., gmail_list_messages, drive_list_files). +Use tool names and descriptions to understand their capabilities. +You have conversation history - you can reference previous results. +Always complete multi-step tasks fully.`; + + // Add provider-specific tips only if those providers are connected + const providerNames = providers.map(([name]) => name.toLowerCase()); + + if (providerNames.some(p => p.includes('gmail'))) { + prompt += ` + +Gmail tips: +- Reading attachments: Use gmail_get_message first, then gmail_get_attachment with the attachmentId +- Sending emails: Use gmail_send_message (requires RFC 2822 format) or create a draft first`; + } + + if (providerNames.some(p => p.includes('drive'))) { + prompt += ` + +Google Drive tips: +- Most tools use nested parameters: { "query": {...} } or { "path": { "id": "..." } }`; + } + + return prompt; +} + +/** + * Run the agent with conversation history + */ +async function runAgent( + userMessage: string, + tools: Record, + systemPrompt: string +): Promise { + console.log(`\nšŸ“ User: ${userMessage}\n`); + + // Add to history + conversationHistory.push({ role: "user", content: userMessage }); + + try { + const { text, toolCalls } = await generateText({ + model: anthropic("claude-sonnet-4-20250514"), + system: systemPrompt, + messages: conversationHistory, + tools, + maxSteps: 15, // Allow more steps for multi-tool workflows + }); + + // Log tool summary + if (toolCalls && toolCalls.length > 0) { + const toolNames = toolCalls.map((t) => t.toolName); + const uniqueTools = [...new Set(toolNames)]; + console.log(`\nšŸ“Š Tools used: ${uniqueTools.join(", ")} (${toolCalls.length} calls)`); + } + + // Add response to history + conversationHistory.push({ role: "assistant", content: text }); + + // Trim history if needed + while (conversationHistory.length > MAX_HISTORY_TURNS * 2) { + conversationHistory.shift(); + } + + console.log(`\nšŸ¤– Assistant: ${text}\n`); + return text; + } catch (error) { + console.error("Agent error:", error); + throw error; + } +} + +/** + * Interactive CLI mode + */ +async function interactiveMode( + tools: Record, + providerCounts: Record, + systemPrompt: string +): Promise { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + console.log("\n╔══════════════════════════════════════════════════════════╗"); + console.log("ā•‘ StackOne AI Agent (TypeScript) ā•‘"); + console.log("╠══════════════════════════════════════════════════════════╣"); + console.log("ā•‘ Direct tool access - no meta-tool overhead! ā•‘"); + console.log("ā•‘ Commands: 'quit' to exit, '/clear' to reset history ā•‘"); + console.log("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n"); + + // Show provider summary from actual data + const summary = Object.entries(providerCounts) + .map(([provider, count]) => `${count} ${provider}`) + .join(", "); + console.log(`Tools: ${summary}\n`); + + // Show dynamic examples based on connected providers + const providerNames = Object.keys(providerCounts).map(p => p.toLowerCase()); + console.log("Examples:"); + if (providerNames.some(p => p.includes('gmail'))) { + console.log(" • List my recent emails"); + console.log(" • Read my last email and reply saying I'll get back to them"); + } + if (providerNames.some(p => p.includes('ashby'))) { + console.log(" • Show open jobs in Ashby"); + } + if (providerNames.some(p => p.includes('drive'))) { + console.log(" • List files in my Drive"); + } + if (providerNames.some(p => p.includes('slack'))) { + console.log(" • Send a message to #general channel"); + } + if (providerNames.some(p => p.includes('salesforce') || p.includes('hubspot'))) { + console.log(" • List my recent contacts"); + } + // Fallback generic example if no specific providers matched + if (!providerNames.some(p => ['gmail', 'ashby', 'drive', 'slack', 'salesforce', 'hubspot'].some(known => p.includes(known)))) { + console.log(" • List available data"); + console.log(" • Show me what you can do"); + } + console.log(""); + + const askQuestion = (): void => { + rl.question("You: ", async (input) => { + const trimmed = input.trim(); + + if (["quit", "exit", "q"].includes(trimmed.toLowerCase())) { + console.log("Goodbye!"); + rl.close(); + return; + } + + if (trimmed.toLowerCase() === "/clear") { + conversationHistory.length = 0; + console.log("History cleared.\n"); + askQuestion(); + return; + } + + if (!trimmed) { + askQuestion(); + return; + } + + try { + await runAgent(trimmed, tools, systemPrompt); + } catch (error) { + console.error("Error:", error); + } + + askQuestion(); + }); + }; + + askQuestion(); +} + +/** + * Main entry point + */ +async function main(): Promise { + if (!STACKONE_API_KEY) { + console.error("Error: STACKONE_API_KEY not set"); + process.exit(1); + } + + if (!process.env.ANTHROPIC_API_KEY) { + console.error("Error: ANTHROPIC_API_KEY not set"); + process.exit(1); + } + + // Fetch and create tools + const result = await fetchAndCreateTools().catch((error): never => { + console.error("Failed to fetch tools:", error); + return process.exit(1); + }); + + const { tools, providerCounts } = result; + + if (Object.keys(tools).length === 0) { + console.error("No tools available. Check your StackOne configuration."); + process.exit(1); + } + + // Build system prompt based on actual connected providers + const systemPrompt = buildSystemPrompt(providerCounts); + + await interactiveMode(tools, providerCounts, systemPrompt); +} + +main().catch(console.error); diff --git a/apps/stackone-typescript-agent/tsconfig.json b/apps/stackone-typescript-agent/tsconfig.json new file mode 100644 index 0000000..f2fe0bf --- /dev/null +++ b/apps/stackone-typescript-agent/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] + } + \ No newline at end of file From e6ee8a2a12133526da0bab515d4fe15bf5b4cbd7 Mon Sep 17 00:00:00 2001 From: Hiskias Date: Mon, 26 Jan 2026 10:34:02 +0000 Subject: [PATCH 02/22] Update apps/stackone-typescript-agent/package.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/stackone-typescript-agent/package.json b/apps/stackone-typescript-agent/package.json index 2547408..044418f 100644 --- a/apps/stackone-typescript-agent/package.json +++ b/apps/stackone-typescript-agent/package.json @@ -9,7 +9,6 @@ }, "dependencies": { "@ai-sdk/anthropic": "^1.0.0", - "@ai-sdk/openai": "^1.0.0", "ai": "^4.0.0", "dotenv": "^16.4.0", "zod": "^3.23.0" From 54aec9b1ce58afda8acc1bb2b604e449e4a7b9e7 Mon Sep 17 00:00:00 2001 From: Hiskias Date: Mon, 26 Jan 2026 10:34:22 +0000 Subject: [PATCH 03/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 295c5ff..f7e55e3 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -102,7 +102,7 @@ async function callTool(toolName: string, args: Record): Promis accountId )) as { result?: unknown }; - return result.result || result; + return result.result ?? result; } /** From 99baf8797b02625768bf32cb9165d2167b455eec Mon Sep 17 00:00:00 2001 From: Hiskias Date: Mon, 26 Jan 2026 10:35:03 +0000 Subject: [PATCH 04/22] Update apps/stackone-typescript-agent/.env.example Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/.env.example | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/stackone-typescript-agent/.env.example b/apps/stackone-typescript-agent/.env.example index 8212113..68fd37e 100644 --- a/apps/stackone-typescript-agent/.env.example +++ b/apps/stackone-typescript-agent/.env.example @@ -1,7 +1,3 @@ -STACKONE_API_KEY=you_stackone_api_key - -# For linked accounts (get from StackOne Dashboard after linking) -STACKONE_ACCOUNT_ID=you_stackone_account_id - +STACKONE_API_KEY=your_stackone_api_key # For AI providers ANTHROPIC_API_KEY=your_anthropic_api_key # For Claude-based agents \ No newline at end of file From a59f67257786c8416e8873714bb6faee7b72d873 Mon Sep 17 00:00:00 2001 From: Hisku Date: Mon, 26 Jan 2026 10:58:10 +0000 Subject: [PATCH 05/22] feat: enhance JSON Schema handling in McpTool --- apps/stackone-typescript-agent/src/agent.ts | 126 +++++++++++++++++++- 1 file changed, 120 insertions(+), 6 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index f7e55e3..707cfb7 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -29,14 +29,125 @@ interface LinkedAccount { status: string; } +/** + * JSON Schema type definition for MCP tool parameters + */ +interface JsonSchema { + type?: string | string[]; + properties?: Record; + required?: string[]; + items?: JsonSchema; + enum?: (string | number | boolean | null)[]; + description?: string; + default?: unknown; + // Additional JSON Schema fields we might encounter + oneOf?: JsonSchema[]; + anyOf?: JsonSchema[]; + allOf?: JsonSchema[]; + $ref?: string; +} + interface McpTool { name: string; description?: string; - inputSchema?: { - type?: string; - properties?: Record; - required?: string[]; - }; + inputSchema?: JsonSchema; +} + +/** + * Convert JSON Schema to Zod schema + * Handles common types and falls back to z.unknown() for unsupported cases + */ +function jsonSchemaToZod(schema: JsonSchema | undefined): z.ZodTypeAny { + if (!schema) { + return z.record(z.unknown()); + } + + // Handle enum first (can appear with or without type) + if (schema.enum && schema.enum.length > 0) { + const enumValues = schema.enum.filter((v): v is string => typeof v === "string"); + if (enumValues.length > 0 && enumValues.length === schema.enum.length) { + const zodEnum = z.enum(enumValues as [string, ...string[]]); + return schema.description ? zodEnum.describe(schema.description) : zodEnum; + } + // For mixed enums, use union of literals + const literals = schema.enum.map((v) => z.literal(v as string | number | boolean)); + const zodUnion = z.union(literals as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]); + return schema.description ? zodUnion.describe(schema.description) : zodUnion; + } + + // Handle type-based conversion + const type = Array.isArray(schema.type) ? schema.type[0] : schema.type; + + switch (type) { + case "string": { + const zodString = z.string(); + return schema.description ? zodString.describe(schema.description) : zodString; + } + + case "number": + case "integer": { + const zodNumber = z.number(); + return schema.description ? zodNumber.describe(schema.description) : zodNumber; + } + + case "boolean": { + const zodBoolean = z.boolean(); + return schema.description ? zodBoolean.describe(schema.description) : zodBoolean; + } + + case "null": { + const zodNull = z.null(); + return schema.description ? zodNull.describe(schema.description) : zodNull; + } + + case "array": { + const itemSchema = jsonSchemaToZod(schema.items); + const zodArray = z.array(itemSchema); + return schema.description ? zodArray.describe(schema.description) : zodArray; + } + + case "object": { + return jsonSchemaObjectToZod(schema); + } + + default: { + // Fallback: if properties exist, treat as object + if (schema.properties) { + return jsonSchemaObjectToZod(schema); + } + // Unknown type - use permissive schema + const zodUnknown = z.record(z.unknown()); + return schema.description ? zodUnknown.describe(schema.description) : zodUnknown; + } + } +} + +/** + * Convert JSON Schema object type to Zod object schema + */ +function jsonSchemaObjectToZod(schema: JsonSchema): z.ZodTypeAny { + if (!schema.properties) { + const zodRecord = z.record(z.unknown()); + return schema.description ? zodRecord.describe(schema.description) : zodRecord; + } + + const required = new Set(schema.required || []); + const shape: Record = {}; + + for (const [key, propSchema] of Object.entries(schema.properties)) { + let zodProp = jsonSchemaToZod(propSchema); + + // Make non-required fields optional + if (!required.has(key)) { + zodProp = zodProp.optional(); + } + + shape[key] = zodProp; + } + + // Use passthrough to allow additional properties (common in MCP tools) + const zodObject = z.object(shape).passthrough(); + return schema.description ? zodObject.describe(schema.description) : zodObject; } /** @@ -111,9 +222,12 @@ async function callTool(toolName: string, args: Record): Promis function createVercelTool(mcpTool: McpTool): CoreTool { const toolName = mcpTool.name; + // Convert JSON Schema to Zod, or use permissive fallback + const parameters = jsonSchemaToZod(mcpTool.inputSchema); + return { description: mcpTool.description || `Call the ${toolName} tool`, - parameters: z.record(z.unknown()).describe("Arguments for the tool"), + parameters, execute: async (args: Record) => { console.log(`šŸ”§ Calling: ${toolName}`); From f8eb7d3cb2cee2343340d4b00d7d755c0ad462eb Mon Sep 17 00:00:00 2001 From: Hisku Date: Mon, 26 Jan 2026 11:14:14 +0000 Subject: [PATCH 06/22] chore: update .gitignore to include lock files for package management --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 96fab4f..6782484 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,8 @@ yarn-error.log* # Misc .DS_Store *.pem + +# Lock files +package-lock.json +pnpm-lock.yaml +yarn.lock \ No newline at end of file From f69867a1b9eaed7645547e5c01502f7c2829cc6d Mon Sep 17 00:00:00 2001 From: Hiskias Date: Mon, 26 Jan 2026 11:18:18 +0000 Subject: [PATCH 07/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 707cfb7..32d85a2 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -289,7 +289,8 @@ async function fetchAndCreateTools(): Promise { tools[mcpTool.name] = createVercelTool(mcpTool); } - providerCounts[account.provider] = mcpTools.length; + providerCounts[account.provider] = + (providerCounts[account.provider] || 0) + mcpTools.length; console.log(` Found ${mcpTools.length} tools`); } catch (error) { console.warn(` Warning: Could not fetch from ${account.provider}: ${error}`); From 74340431f72d4b8e67782a75e707a070ae58d81f Mon Sep 17 00:00:00 2001 From: Hisku Date: Mon, 26 Jan 2026 11:20:06 +0000 Subject: [PATCH 08/22] fix: update Accept header in mcpRequest to remove text/event-stream --- apps/stackone-typescript-agent/src/agent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 32d85a2..9fd566a 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -181,7 +181,7 @@ async function mcpRequest( Authorization: `Basic ${Buffer.from(STACKONE_API_KEY + ":").toString("base64")}`, "x-account-id": accountId, "Content-Type": "application/json", - Accept: "application/json, text/event-stream", + Accept: "application/json", }, body: JSON.stringify({ jsonrpc: "2.0", From 88db30b7c52793699119d169d89a039ad4dfcf5b Mon Sep 17 00:00:00 2001 From: Hiskias Date: Mon, 26 Jan 2026 11:20:51 +0000 Subject: [PATCH 09/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 9fd566a..9ae13ed 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -285,8 +285,10 @@ async function fetchAndCreateTools(): Promise { const mcpTools = result.result?.tools || []; for (const mcpTool of mcpTools) { - toolToAccount.set(mcpTool.name, account.id); - tools[mcpTool.name] = createVercelTool(mcpTool); + // Namespace tool names by provider and account to avoid collisions across accounts. + const toolKey = `${account.provider}:${account.id}:${mcpTool.name}`; + toolToAccount.set(toolKey, account.id); + tools[toolKey] = createVercelTool(mcpTool); } providerCounts[account.provider] = From feaaa86594b44c8c453c0224480fe7dc262139e0 Mon Sep 17 00:00:00 2001 From: Hiskias Date: Mon, 26 Jan 2026 11:22:18 +0000 Subject: [PATCH 10/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 9ae13ed..c9a1bce 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -69,8 +69,10 @@ function jsonSchemaToZod(schema: JsonSchema | undefined): z.ZodTypeAny { const zodEnum = z.enum(enumValues as [string, ...string[]]); return schema.description ? zodEnum.describe(schema.description) : zodEnum; } - // For mixed enums, use union of literals - const literals = schema.enum.map((v) => z.literal(v as string | number | boolean)); + // For mixed enums, use union of literals (including null entries) + const literals = schema.enum.map((v) => + v === null ? z.literal(null) : z.literal(v as string | number | boolean), + ); const zodUnion = z.union(literals as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]); return schema.description ? zodUnion.describe(schema.description) : zodUnion; } From faa3f1cc3dfae54649faf3563d7954551925b2ef Mon Sep 17 00:00:00 2001 From: Hisku Date: Mon, 26 Jan 2026 11:26:15 +0000 Subject: [PATCH 11/22] chore: update package.json to set private flag and rename typecheck script --- apps/stackone-typescript-agent/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/stackone-typescript-agent/package.json b/apps/stackone-typescript-agent/package.json index 044418f..5bec605 100644 --- a/apps/stackone-typescript-agent/package.json +++ b/apps/stackone-typescript-agent/package.json @@ -1,11 +1,12 @@ { "name": "stackone-typescript-agent", "version": "1.0.0", + "private": true, "description": "StackOne AI Agent Example using Vercel AI SDK with dynamic MCP tools", "type": "module", "scripts": { "agent": "tsx src/agent.ts", - "typecheck": "tsc --noEmit" + "check-types": "tsc --noEmit" }, "dependencies": { "@ai-sdk/anthropic": "^1.0.0", From fa587dca9a83ce1a1b19a3cc30d11ff716667a52 Mon Sep 17 00:00:00 2001 From: Hisku Date: Mon, 26 Jan 2026 11:37:12 +0000 Subject: [PATCH 12/22] chore: update .gitignore to maintain .pem file exclusion and add package-lock.json for stackone-typescript-agent --- .gitignore | 7 +- .../package-lock.json | 872 ++++++++++++++++++ 2 files changed, 873 insertions(+), 6 deletions(-) create mode 100644 apps/stackone-typescript-agent/package-lock.json diff --git a/.gitignore b/.gitignore index 6782484..00f9b61 100644 --- a/.gitignore +++ b/.gitignore @@ -35,9 +35,4 @@ yarn-error.log* # Misc .DS_Store -*.pem - -# Lock files -package-lock.json -pnpm-lock.yaml -yarn.lock \ No newline at end of file +*.pem \ No newline at end of file diff --git a/apps/stackone-typescript-agent/package-lock.json b/apps/stackone-typescript-agent/package-lock.json new file mode 100644 index 0000000..a54bb04 --- /dev/null +++ b/apps/stackone-typescript-agent/package-lock.json @@ -0,0 +1,872 @@ +{ + "name": "stackone-typescript-agent", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "stackone-typescript-agent", + "version": "1.0.0", + "dependencies": { + "@ai-sdk/anthropic": "^1.0.0", + "ai": "^4.0.0", + "dotenv": "^16.4.0", + "zod": "^3.23.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.19.0", + "typescript": "^5.6.0" + } + }, + "node_modules/@ai-sdk/anthropic": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-1.2.12.tgz", + "integrity": "sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@ai-sdk/react": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.2.12.tgz", + "integrity": "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider-utils": "2.2.8", + "@ai-sdk/ui-utils": "1.2.11", + "swr": "^2.2.5", + "throttleit": "2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/ui-utils": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz", + "integrity": "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@types/diff-match-patch": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", + "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", + "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/ai": { + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/ai/-/ai-4.3.19.tgz", + "integrity": "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "@ai-sdk/provider-utils": "2.2.8", + "@ai-sdk/react": "1.2.12", + "@ai-sdk/ui-utils": "1.2.11", + "@opentelemetry/api": "1.9.0", + "jsondiffpatch": "0.6.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/jsondiffpatch": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz", + "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", + "license": "MIT", + "dependencies": { + "@types/diff-match-patch": "^1.0.36", + "chalk": "^5.3.0", + "diff-match-patch": "^1.0.5" + }, + "bin": { + "jsondiffpatch": "bin/jsondiffpatch.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" + }, + "node_modules/swr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.8.tgz", + "integrity": "sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + } + } +} From f1f8f5b45c01c21e9540b4e265bdf3b3a44c9053 Mon Sep 17 00:00:00 2001 From: Hiskias Date: Thu, 29 Jan 2026 14:07:22 +0000 Subject: [PATCH 13/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index c9a1bce..110be1d 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -73,6 +73,12 @@ function jsonSchemaToZod(schema: JsonSchema | undefined): z.ZodTypeAny { const literals = schema.enum.map((v) => v === null ? z.literal(null) : z.literal(v as string | number | boolean), ); + if (literals.length === 1) { + const singleLiteral = literals[0]; + return schema.description + ? singleLiteral.describe(schema.description) + : singleLiteral; + } const zodUnion = z.union(literals as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]); return schema.description ? zodUnion.describe(schema.description) : zodUnion; } From 99a6f6aae087723ee4eb52181e2d6ac3e90e2dac Mon Sep 17 00:00:00 2001 From: Hisku Date: Thu, 29 Jan 2026 14:56:59 +0000 Subject: [PATCH 14/22] Refactor tool management in agent.ts --- apps/stackone-typescript-agent/src/agent.ts | 122 +++++++++++++++----- 1 file changed, 92 insertions(+), 30 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 110be1d..709db82 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -15,9 +15,6 @@ import * as readline from "readline"; const STACKONE_API_KEY = process.env.STACKONE_API_KEY || ""; const MCP_ENDPOINT = "https://api.stackone.com/mcp"; -// Tool and account mappings -const toolToAccount = new Map(); - // Conversation history const conversationHistory: CoreMessage[] = []; const MAX_HISTORY_TURNS = 10; @@ -29,6 +26,20 @@ interface LinkedAccount { status: string; } +/** + * Key under which a tool is exposed to the model (and used for registry/API). + * Format: "provider_accountId_toolName" (underscores only, API-safe per Anthropic ^[a-zA-Z0-9_-]{1,128}$). + */ +type ToolKey = string; + +/** + * Build the tool key for a given account and MCP tool. + * Uses underscores so the same key is valid for registry, tools object, and model API. + */ +function buildToolKey(provider: string, accountId: string, toolName: string): ToolKey { + return `${provider}_${accountId}_${toolName}`; +} + /** * JSON Schema type definition for MCP tool parameters */ @@ -189,7 +200,7 @@ async function mcpRequest( Authorization: `Basic ${Buffer.from(STACKONE_API_KEY + ":").toString("base64")}`, "x-account-id": accountId, "Content-Type": "application/json", - Accept: "application/json", + Accept: "application/json, text/event-stream", }, body: JSON.stringify({ jsonrpc: "2.0", @@ -206,41 +217,72 @@ async function mcpRequest( return response.json(); } +/** Single tool entry in the registry (accountId + raw MCP tool name). */ +interface ToolRegistryEntry { + accountId: string; + rawName: string; +} + /** - * Call a StackOne tool via MCP + * Registry of tools exposed to the model. Encapsulates lookup by ToolKey + * and MCP invocation (accountId + raw tool name). */ -async function callTool(toolName: string, args: Record): Promise { - const accountId = toolToAccount.get(toolName); - if (!accountId) { - throw new Error(`Unknown tool: ${toolName}`); - } +interface ToolRegistry { + register(toolKey: ToolKey, accountId: string, rawName: string): void; + getAccountId(toolKey: ToolKey): string | undefined; + getRawName(toolKey: ToolKey): string | undefined; + callTool(toolKey: ToolKey, args: Record): Promise; +} - const result = (await mcpRequest( - "tools/call", - { name: toolName, arguments: args }, - accountId - )) as { result?: unknown }; +function createToolRegistry(): ToolRegistry { + const entries = new Map(); + + return { + register(toolKey, accountId, rawName) { + entries.set(toolKey, { accountId, rawName }); + }, - return result.result ?? result; + getAccountId(toolKey) { + return entries.get(toolKey)?.accountId; + }, + + getRawName(toolKey) { + return entries.get(toolKey)?.rawName ?? toolKey; + }, + + async callTool(toolKey, args) { + const entry = entries.get(toolKey); + if (!entry) { + throw new Error(`Unknown tool: ${toolKey}`); + } + const result = (await mcpRequest( + "tools/call", + { name: entry.rawName, arguments: args }, + entry.accountId + )) as { result?: unknown }; + return result.result ?? result; + }, + }; } /** * Convert MCP tools to Vercel AI SDK tools + * @param mcpTool - The underlying MCP tool definition + * @param toolKey - Single key for registry, tools object, and API (format: provider_accountId_toolName) + * @param registry - Registry used to invoke the tool (lookup + MCP call) */ -function createVercelTool(mcpTool: McpTool): CoreTool { - const toolName = mcpTool.name; - +function createVercelTool(mcpTool: McpTool, toolKey: ToolKey, registry: ToolRegistry): CoreTool { // Convert JSON Schema to Zod, or use permissive fallback const parameters = jsonSchemaToZod(mcpTool.inputSchema); return { - description: mcpTool.description || `Call the ${toolName} tool`, + description: mcpTool.description || `Call the ${toolKey} tool`, parameters, execute: async (args: Record) => { - console.log(`šŸ”§ Calling: ${toolName}`); + console.log(`šŸ”§ Calling: ${toolKey}`); try { - const result = await callTool(toolName, args); + const result = await registry.callTool(toolKey, args); const resultStr = JSON.stringify(result, null, 2); // Truncate large results @@ -268,6 +310,21 @@ interface FetchToolsResult { providerCounts: Record; } +/** + * Register a single MCP tool in the registry and tools record. + * Tool key uses underscores only (API-safe); same key used everywhere. + */ +function registerTool( + account: LinkedAccount, + mcpTool: McpTool, + registry: ToolRegistry, + tools: Record +): void { + const toolKey = buildToolKey(account.provider, account.id, mcpTool.name); + registry.register(toolKey, account.id, mcpTool.name); + tools[toolKey] = createVercelTool(mcpTool, toolKey, registry); +} + /** * Fetch tools from all linked accounts and create Vercel tools */ @@ -275,6 +332,7 @@ async function fetchAndCreateTools(): Promise { console.log("Fetching linked accounts..."); const accounts = await getLinkedAccounts(); + const registry = createToolRegistry(); const tools: Record = {}; const providerCounts: Record = {}; @@ -293,10 +351,7 @@ async function fetchAndCreateTools(): Promise { const mcpTools = result.result?.tools || []; for (const mcpTool of mcpTools) { - // Namespace tool names by provider and account to avoid collisions across accounts. - const toolKey = `${account.provider}:${account.id}:${mcpTool.name}`; - toolToAccount.set(toolKey, account.id); - tools[toolKey] = createVercelTool(mcpTool); + registerTool(account, mcpTool, registry, tools); } providerCounts[account.provider] = @@ -331,7 +386,7 @@ You can directly call tools for the user's connected services. Connected providers: ${capabilities} -Tool names follow the pattern: provider_action (e.g., gmail_list_messages, drive_list_files). +Tool names follow the pattern: provider_accountId_action (e.g., gmail_abc123_gmail_list_messages, googledrive_xyz789_drive_list_files). Use the exact tool names listed in your available tools. Use tool names and descriptions to understand their capabilities. You have conversation history - you can reference previous results. Always complete multi-step tasks fully.`; @@ -371,7 +426,7 @@ async function runAgent( conversationHistory.push({ role: "user", content: userMessage }); try { - const { text, toolCalls } = await generateText({ + const { text, toolCalls, messages: responseMessages } = await generateText({ model: anthropic("claude-sonnet-4-20250514"), system: systemPrompt, messages: conversationHistory, @@ -386,8 +441,15 @@ async function runAgent( console.log(`\nšŸ“Š Tools used: ${uniqueTools.join(", ")} (${toolCalls.length} calls)`); } - // Add response to history - conversationHistory.push({ role: "assistant", content: text }); + // Persist full response (assistant + tool calls + tool results) so follow-ups can reference prior results + if (responseMessages && responseMessages.length > 0) { + for (const msg of responseMessages) { + conversationHistory.push(msg as CoreMessage); + } + } else { + // Fallback: SDK may not return messages in some versions + conversationHistory.push({ role: "assistant", content: text }); + } // Trim history if needed while (conversationHistory.length > MAX_HISTORY_TURNS * 2) { From 6e3b4431e3384df470359cab1cae5079ccbb31f0 Mon Sep 17 00:00:00 2001 From: Hiskias Date: Thu, 29 Jan 2026 15:08:14 +0000 Subject: [PATCH 15/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 709db82..aa2704d 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -28,13 +28,15 @@ interface LinkedAccount { /** * Key under which a tool is exposed to the model (and used for registry/API). - * Format: "provider_accountId_toolName" (underscores only, API-safe per Anthropic ^[a-zA-Z0-9_-]{1,128}$). + * Format: "provider_accountId_toolName", using underscores as separators. + * Intended to be compatible with Anthropic tool name requirements (^[a-zA-Z0-9_-]{1,128}$), + * assuming the provider, accountId, and toolName components themselves are valid. */ type ToolKey = string; /** - * Build the tool key for a given account and MCP tool. - * Uses underscores so the same key is valid for registry, tools object, and model API. + * Build the tool key for a given account and MCP tool by joining components with underscores. + * Does not modify or sanitize the individual components. */ function buildToolKey(provider: string, accountId: string, toolName: string): ToolKey { return `${provider}_${accountId}_${toolName}`; From 49d8322a501ce830fc64794b5ebb96234a683983 Mon Sep 17 00:00:00 2001 From: Hisku Date: Wed, 4 Feb 2026 15:35:44 +0000 Subject: [PATCH 16/22] Improve StackOne TypeScript Agent configuration and dependencies --- apps/stackone-typescript-agent/.env.example | 11 +- .../package-lock.json | 1696 +++++++++++++++-- apps/stackone-typescript-agent/package.json | 27 +- apps/stackone-typescript-agent/src/agent.ts | 628 ++---- 4 files changed, 1695 insertions(+), 667 deletions(-) diff --git a/apps/stackone-typescript-agent/.env.example b/apps/stackone-typescript-agent/.env.example index 68fd37e..de139d1 100644 --- a/apps/stackone-typescript-agent/.env.example +++ b/apps/stackone-typescript-agent/.env.example @@ -1,3 +1,10 @@ STACKONE_API_KEY=your_stackone_api_key -# For AI providers -ANTHROPIC_API_KEY=your_anthropic_api_key # For Claude-based agents \ No newline at end of file +STACKONE_ACCOUNT_ID=your_stackone_account_id + +# Optional: filter which tools to load (default: "*" loads all) +# STACKONE_TOOL_FILTER=documents_* + +# Optional: model to use (default: claude-sonnet-4-20250514) +# MODEL=claude-sonnet-4-20250514 + +ANTHROPIC_API_KEY=your_anthropic_api_key diff --git a/apps/stackone-typescript-agent/package-lock.json b/apps/stackone-typescript-agent/package-lock.json index a54bb04..ffde978 100644 --- a/apps/stackone-typescript-agent/package-lock.json +++ b/apps/stackone-typescript-agent/package-lock.json @@ -8,10 +8,11 @@ "name": "stackone-typescript-agent", "version": "1.0.0", "dependencies": { - "@ai-sdk/anthropic": "^1.0.0", - "ai": "^4.0.0", + "@ai-sdk/anthropic": "^3.0.36", + "@stackone/ai": "^2.3.0", + "ai": "^6.0.69", "dotenv": "^16.4.0", - "zod": "^3.23.0" + "zod": "^3.25.0" }, "devDependencies": { "@types/node": "^22.0.0", @@ -20,89 +21,65 @@ } }, "node_modules/@ai-sdk/anthropic": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-1.2.12.tgz", - "integrity": "sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ==", + "version": "3.0.36", + "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.36.tgz", + "integrity": "sha512-GHQccfwC0j1JltN9M47RSlBpOyHoUam0mvbYMf8zpE0UD1tzIX5sDw2m/8nRlrTz6wGuKfaDxmoC3XH7uhTrXg==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8" + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.0.0" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/provider": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", - "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", - "license": "Apache-2.0", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ai-sdk/provider-utils": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", - "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "node_modules/@ai-sdk/gateway": { + "version": "3.0.32", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.32.tgz", + "integrity": "sha512-7clZRr07P9rpur39t1RrbIe7x8jmwnwUWI8tZs+BvAfX3NFgdSVGGIaT7bTz2pb08jmLXzTSDbrOTqAQ7uBkBQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "nanoid": "^3.3.8", - "secure-json-parse": "^2.7.0" + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13", + "@vercel/oidc": "3.1.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.23.8" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/react": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.2.12.tgz", - "integrity": "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==", + "node_modules/@ai-sdk/provider": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.7.tgz", + "integrity": "sha512-VkPLrutM6VdA924/mG8OS+5frbVTcu6e046D2bgDo00tehBANR1QBJ/mPcZ9tXMFOsVcm6SQArOregxePzTFPw==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider-utils": "2.2.8", - "@ai-sdk/ui-utils": "1.2.11", - "swr": "^2.2.5", - "throttleit": "2.1.0" + "json-schema": "^0.4.0" }, "engines": { "node": ">=18" - }, - "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } } }, - "node_modules/@ai-sdk/ui-utils": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz", - "integrity": "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==", + "node_modules/@ai-sdk/provider-utils": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.13.tgz", + "integrity": "sha512-HHG72BN4d+OWTcq2NwTxOm/2qvk1duYsnhCDtsbYwn/h/4zeqURu1S0+Cn0nY2Ysq9a9HGKvrYuMn9bgFhR2Og==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8", - "zod-to-json-schema": "^3.24.1" + "@ai-sdk/provider": "3.0.7", + "@standard-schema/spec": "^1.1.0", + "eventsource-parser": "^3.0.6" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.23.8" + "zod": "^3.25.76 || ^4.1.8" } }, "node_modules/@esbuild/aix-ppc64": { @@ -547,6 +524,57 @@ "node": ">=18" } }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz", + "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, "node_modules/@opentelemetry/api": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", @@ -556,74 +584,396 @@ "node": ">=8.0.0" } }, - "node_modules/@types/diff-match-patch": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", - "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", + "node_modules/@orama/orama": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/@orama/orama/-/orama-3.1.18.tgz", + "integrity": "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20.0.0" + } + }, + "node_modules/@stackone/ai": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stackone/ai/-/ai-2.3.0.tgz", + "integrity": "sha512-ftxLiOKE3durZta74eKa7JhF/bvyHCy+lvlATXMaTAe9qr3jct859ZNjUdRCBfwFtYGUFUD/mGjI1KnSnfh/1A==", + "license": "Apache-2.0", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.24.3", + "@orama/orama": "^3.1.11", + "defu": "^6.1.4" + }, + "engines": { + "node": ">=20.19.6" + }, + "peerDependencies": { + "@anthropic-ai/claude-agent-sdk": "^0.2.12", + "@anthropic-ai/sdk": "^0.71.2", + "ai": ">=5.0.108 <7.0.0", + "openai": "^6.2.0", + "zod": ">=3.25.0 <5" + }, + "peerDependenciesMeta": { + "@anthropic-ai/claude-agent-sdk": { + "optional": true + }, + "@anthropic-ai/sdk": { + "optional": true + }, + "ai": { + "optional": true + }, + "openai": { + "optional": true + } + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "license": "MIT" }, "node_modules/@types/node": { "version": "22.19.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@vercel/oidc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", + "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "optional": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ai": { - "version": "4.3.19", - "resolved": "https://registry.npmjs.org/ai/-/ai-4.3.19.tgz", - "integrity": "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==", + "version": "6.0.69", + "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.69.tgz", + "integrity": "sha512-zIURMSnNroaVvu47Bm3XhC2y3LRsm8jmkwBgupxF+N7q/s6MpIiv04w1ltlnWqC8+T2PT2rN+f0sUhF+vArkwg==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8", - "@ai-sdk/react": "1.2.12", - "@ai-sdk/ui-utils": "1.2.11", - "@opentelemetry/api": "1.9.0", - "jsondiffpatch": "0.6.0" + "@ai-sdk/gateway": "3.0.32", + "@ai-sdk/provider": "3.0.7", + "@ai-sdk/provider-utils": "4.0.13", + "@opentelemetry/api": "1.9.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "zod": "^3.23.8" + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" }, "peerDependenciesMeta": { - "react": { + "ajv": { "optional": true } } }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT", + "optional": true + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/diff-match-patch": { + "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/dotenv": { "version": "16.6.1", @@ -637,6 +987,81 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "optional": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -679,81 +1104,764 @@ "@esbuild/win32-x64": "0.27.2" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 0.6" } }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", - "dev": true, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT", + "optional": true + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, "funding": { "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "optional": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.11.7", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", + "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "license": "(AFL-2.1 OR BSD-3-Clause)" }, - "node_modules/jsondiffpatch": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz", - "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", - "dependencies": { - "@types/diff-match-patch": "^1.0.36", - "chalk": "^5.3.0", - "diff-match-patch": "^1.0.5" + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" }, - "bin": { - "jsondiffpatch": "bin/jsondiffpatch.js" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mime-db": "1.52.0" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/ai" + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" } ], "license": "MIT", + "optional": true, + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, "bin": { - "nanoid": "bin/nanoid.cjs" + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "license": "MIT", + "optional": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT", + "optional": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -768,37 +1876,222 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/secure-json-parse": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", - "license": "BSD-3-Clause" + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, - "node_modules/swr": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.8.tgz", - "integrity": "sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==", + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "dequal": "^2.0.3", - "use-sync-external-store": "^1.6.0" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, - "peerDependencies": { - "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/throttleit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", - "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, "engines": { "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "optional": true + }, "node_modules/tsx": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", @@ -819,6 +2112,45 @@ "fsevents": "~2.3.3" } }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -837,18 +2169,76 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/apps/stackone-typescript-agent/package.json b/apps/stackone-typescript-agent/package.json index 5bec605..e22551c 100644 --- a/apps/stackone-typescript-agent/package.json +++ b/apps/stackone-typescript-agent/package.json @@ -2,22 +2,25 @@ "name": "stackone-typescript-agent", "version": "1.0.0", "private": true, - "description": "StackOne AI Agent Example using Vercel AI SDK with dynamic MCP tools", + "description": "StackOne AI Agent Example using Vercel AI SDK and StackOne Toolset SDK (@stackone/ai)", "type": "module", "scripts": { - "agent": "tsx src/agent.ts", - "check-types": "tsc --noEmit" + "agent": "tsx src/agent.ts", + "check-types": "tsc --noEmit" + }, + "overrides": { + "openai": "^4.52.0" }, "dependencies": { - "@ai-sdk/anthropic": "^1.0.0", - "ai": "^4.0.0", - "dotenv": "^16.4.0", - "zod": "^3.23.0" + "@ai-sdk/anthropic": "^3.0.36", + "@stackone/ai": "^2.3.0", + "ai": "^6.0.69", + "dotenv": "^16.4.0", + "zod": "^3.25.0" }, "devDependencies": { - "@types/node": "^22.0.0", - "tsx": "^4.19.0", - "typescript": "^5.6.0" + "@types/node": "^22.0.0", + "tsx": "^4.19.0", + "typescript": "^5.6.0" } - } - \ No newline at end of file +} diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index aa2704d..020b2b4 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -1,536 +1,160 @@ /** - * StackOne AI Agent Example - Using Vercel AI SDK - * - * This agent dynamically creates tools from StackOne's MCP endpoint, - * allowing Claude to call them directly (not via meta-tool). + * StackOne AI Agent - Vercel AI SDK + StackOne Toolset SDK */ import "dotenv/config"; import { anthropic } from "@ai-sdk/anthropic"; -import { generateText, CoreMessage, CoreTool } from "ai"; -import { z } from "zod"; +import { generateText, ToolSet, ModelMessage, stepCountIs } from "ai"; +import { StackOneToolSet } from "@stackone/ai"; import * as readline from "readline"; -// StackOne MCP configuration -const STACKONE_API_KEY = process.env.STACKONE_API_KEY || ""; -const MCP_ENDPOINT = "https://api.stackone.com/mcp"; - -// Conversation history -const conversationHistory: CoreMessage[] = []; +const STACKONE_ACCOUNT_ID = process.env.STACKONE_ACCOUNT_ID ?? ""; +const STACKONE_BASE_URL = process.env.STACKONE_BASE_URL ?? "https://api.stackone.com"; +const TOOL_FILTER = process.env.STACKONE_TOOL_FILTER ?? "*"; +const MODEL = process.env.MODEL ?? "claude-sonnet-4-20250514"; const MAX_HISTORY_TURNS = 10; -const MAX_TOOL_RESULT_LENGTH = 24000; - -interface LinkedAccount { - id: string; - provider: string; - status: string; -} - -/** - * Key under which a tool is exposed to the model (and used for registry/API). - * Format: "provider_accountId_toolName", using underscores as separators. - * Intended to be compatible with Anthropic tool name requirements (^[a-zA-Z0-9_-]{1,128}$), - * assuming the provider, accountId, and toolName components themselves are valid. - */ -type ToolKey = string; - -/** - * Build the tool key for a given account and MCP tool by joining components with underscores. - * Does not modify or sanitize the individual components. - */ -function buildToolKey(provider: string, accountId: string, toolName: string): ToolKey { - return `${provider}_${accountId}_${toolName}`; -} -/** - * JSON Schema type definition for MCP tool parameters - */ -interface JsonSchema { - type?: string | string[]; - properties?: Record; - required?: string[]; - items?: JsonSchema; - enum?: (string | number | boolean | null)[]; - description?: string; - default?: unknown; - // Additional JSON Schema fields we might encounter - oneOf?: JsonSchema[]; - anyOf?: JsonSchema[]; - allOf?: JsonSchema[]; - $ref?: string; -} - -interface McpTool { - name: string; - description?: string; - inputSchema?: JsonSchema; -} - -/** - * Convert JSON Schema to Zod schema - * Handles common types and falls back to z.unknown() for unsupported cases - */ -function jsonSchemaToZod(schema: JsonSchema | undefined): z.ZodTypeAny { - if (!schema) { - return z.record(z.unknown()); - } +const conversationHistory: ModelMessage[] = []; - // Handle enum first (can appear with or without type) - if (schema.enum && schema.enum.length > 0) { - const enumValues = schema.enum.filter((v): v is string => typeof v === "string"); - if (enumValues.length > 0 && enumValues.length === schema.enum.length) { - const zodEnum = z.enum(enumValues as [string, ...string[]]); - return schema.description ? zodEnum.describe(schema.description) : zodEnum; - } - // For mixed enums, use union of literals (including null entries) - const literals = schema.enum.map((v) => - v === null ? z.literal(null) : z.literal(v as string | number | boolean), - ); - if (literals.length === 1) { - const singleLiteral = literals[0]; - return schema.description - ? singleLiteral.describe(schema.description) - : singleLiteral; - } - const zodUnion = z.union(literals as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]); - return schema.description ? zodUnion.describe(schema.description) : zodUnion; - } - - // Handle type-based conversion - const type = Array.isArray(schema.type) ? schema.type[0] : schema.type; - - switch (type) { - case "string": { - const zodString = z.string(); - return schema.description ? zodString.describe(schema.description) : zodString; - } - - case "number": - case "integer": { - const zodNumber = z.number(); - return schema.description ? zodNumber.describe(schema.description) : zodNumber; - } - - case "boolean": { - const zodBoolean = z.boolean(); - return schema.description ? zodBoolean.describe(schema.description) : zodBoolean; - } - - case "null": { - const zodNull = z.null(); - return schema.description ? zodNull.describe(schema.description) : zodNull; - } - - case "array": { - const itemSchema = jsonSchemaToZod(schema.items); - const zodArray = z.array(itemSchema); - return schema.description ? zodArray.describe(schema.description) : zodArray; - } - - case "object": { - return jsonSchemaObjectToZod(schema); - } +const SYSTEM_PROMPT = `You are a helpful assistant with access to StackOne tools. +Use the available tools to help the user with their requests. +You have conversation history - you can reference previous results. +Always complete multi-step tasks fully.`; - default: { - // Fallback: if properties exist, treat as object - if (schema.properties) { - return jsonSchemaObjectToZod(schema); +// ANSI color codes +const colors = { + reset: "\x1b[0m", + bright: "\x1b[1m", + dim: "\x1b[2m", + cyan: "\x1b[36m", + green: "\x1b[32m", + yellow: "\x1b[33m", + magenta: "\x1b[35m", +}; + +function trimHistory(messages: ModelMessage[], maxTurns: number): void { + if (messages.length <= 0 || maxTurns <= 0) return; + let userCount = 0; + let startIndex = 0; + for (let i = messages.length - 1; i >= 0; i--) { + if (messages[i].role === "user") { + userCount++; + if (userCount >= maxTurns) { + startIndex = i; + break; } - // Unknown type - use permissive schema - const zodUnknown = z.record(z.unknown()); - return schema.description ? zodUnknown.describe(schema.description) : zodUnknown; } } -} - -/** - * Convert JSON Schema object type to Zod object schema - */ -function jsonSchemaObjectToZod(schema: JsonSchema): z.ZodTypeAny { - if (!schema.properties) { - const zodRecord = z.record(z.unknown()); - return schema.description ? zodRecord.describe(schema.description) : zodRecord; - } - - const required = new Set(schema.required || []); - const shape: Record = {}; - - for (const [key, propSchema] of Object.entries(schema.properties)) { - let zodProp = jsonSchemaToZod(propSchema); - - // Make non-required fields optional - if (!required.has(key)) { - zodProp = zodProp.optional(); - } - - shape[key] = zodProp; + if (startIndex > 0) { + messages.splice(0, startIndex); } - - // Use passthrough to allow additional properties (common in MCP tools) - const zodObject = z.object(shape).passthrough(); - return schema.description ? zodObject.describe(schema.description) : zodObject; } -/** - * Fetch all linked accounts from StackOne - */ -async function getLinkedAccounts(): Promise { - const response = await fetch("https://api.stackone.com/accounts", { - headers: { - Authorization: `Basic ${Buffer.from(STACKONE_API_KEY + ":").toString("base64")}`, - }, +async function loadTools(): Promise { + const toolset = new StackOneToolSet({ + baseUrl: STACKONE_BASE_URL, + accountId: STACKONE_ACCOUNT_ID, }); - if (!response.ok) { - throw new Error(`Failed to fetch accounts: ${response.status}`); - } - - return response.json(); + const actions = TOOL_FILTER !== "*" ? [TOOL_FILTER] : undefined; + const tools = await toolset.fetchTools({ actions }); + return tools.toAISDK() as unknown as ToolSet; } -/** - * Make an MCP request to StackOne - */ -async function mcpRequest( - method: string, - params: Record = {}, - accountId: string -): Promise { - const response = await fetch(MCP_ENDPOINT, { - method: "POST", - headers: { - Authorization: `Basic ${Buffer.from(STACKONE_API_KEY + ":").toString("base64")}`, - "x-account-id": accountId, - "Content-Type": "application/json", - Accept: "application/json, text/event-stream", - }, - body: JSON.stringify({ - jsonrpc: "2.0", - id: `req-${method}-${Date.now()}`, - method, - params, - }), +async function runAgent(userMessage: string, tools: ToolSet): Promise { + const result = await generateText({ + model: anthropic(MODEL) as Parameters[0]["model"], + system: SYSTEM_PROMPT, + messages: [...conversationHistory, { role: "user" as const, content: userMessage }], + tools, + stopWhen: stepCountIs(15), }); - if (!response.ok) { - throw new Error(`MCP request failed: ${response.status}`); - } - - return response.json(); -} - -/** Single tool entry in the registry (accountId + raw MCP tool name). */ -interface ToolRegistryEntry { - accountId: string; - rawName: string; -} - -/** - * Registry of tools exposed to the model. Encapsulates lookup by ToolKey - * and MCP invocation (accountId + raw tool name). - */ -interface ToolRegistry { - register(toolKey: ToolKey, accountId: string, rawName: string): void; - getAccountId(toolKey: ToolKey): string | undefined; - getRawName(toolKey: ToolKey): string | undefined; - callTool(toolKey: ToolKey, args: Record): Promise; -} - -function createToolRegistry(): ToolRegistry { - const entries = new Map(); - - return { - register(toolKey, accountId, rawName) { - entries.set(toolKey, { accountId, rawName }); - }, - - getAccountId(toolKey) { - return entries.get(toolKey)?.accountId; - }, - - getRawName(toolKey) { - return entries.get(toolKey)?.rawName ?? toolKey; - }, - - async callTool(toolKey, args) { - const entry = entries.get(toolKey); - if (!entry) { - throw new Error(`Unknown tool: ${toolKey}`); - } - const result = (await mcpRequest( - "tools/call", - { name: entry.rawName, arguments: args }, - entry.accountId - )) as { result?: unknown }; - return result.result ?? result; - }, - }; -} - -/** - * Convert MCP tools to Vercel AI SDK tools - * @param mcpTool - The underlying MCP tool definition - * @param toolKey - Single key for registry, tools object, and API (format: provider_accountId_toolName) - * @param registry - Registry used to invoke the tool (lookup + MCP call) - */ -function createVercelTool(mcpTool: McpTool, toolKey: ToolKey, registry: ToolRegistry): CoreTool { - // Convert JSON Schema to Zod, or use permissive fallback - const parameters = jsonSchemaToZod(mcpTool.inputSchema); - - return { - description: mcpTool.description || `Call the ${toolKey} tool`, - parameters, - execute: async (args: Record) => { - console.log(`šŸ”§ Calling: ${toolKey}`); - - try { - const result = await registry.callTool(toolKey, args); - const resultStr = JSON.stringify(result, null, 2); - - // Truncate large results - if (resultStr.length > MAX_TOOL_RESULT_LENGTH) { - console.log(` ⚠ Truncated (${resultStr.length} chars)`); - return { - success: true, - data: resultStr.slice(0, MAX_TOOL_RESULT_LENGTH), - truncated: true, - note: "Result truncated. Request more specific data if needed.", - }; - } - - return { success: true, data: result }; - } catch (error) { - console.log(` āŒ Error: ${error}`); - return { success: false, error: String(error) }; - } - }, - }; -} + const { text, response } = result; + const responseMessages = response?.messages; -interface FetchToolsResult { - tools: Record; - providerCounts: Record; -} - -/** - * Register a single MCP tool in the registry and tools record. - * Tool key uses underscores only (API-safe); same key used everywhere. - */ -function registerTool( - account: LinkedAccount, - mcpTool: McpTool, - registry: ToolRegistry, - tools: Record -): void { - const toolKey = buildToolKey(account.provider, account.id, mcpTool.name); - registry.register(toolKey, account.id, mcpTool.name); - tools[toolKey] = createVercelTool(mcpTool, toolKey, registry); -} - -/** - * Fetch tools from all linked accounts and create Vercel tools - */ -async function fetchAndCreateTools(): Promise { - console.log("Fetching linked accounts..."); - const accounts = await getLinkedAccounts(); - - const registry = createToolRegistry(); - const tools: Record = {}; - const providerCounts: Record = {}; - - for (const account of accounts) { - if (account.status !== "active") { - console.log(` Skipping ${account.provider} (status: ${account.status})`); - continue; - } - - console.log(`Fetching tools from ${account.provider}...`); - - try { - const result = (await mcpRequest("tools/list", {}, account.id)) as { - result?: { tools?: McpTool[] }; - }; - const mcpTools = result.result?.tools || []; - - for (const mcpTool of mcpTools) { - registerTool(account, mcpTool, registry, tools); - } - - providerCounts[account.provider] = - (providerCounts[account.provider] || 0) + mcpTools.length; - console.log(` Found ${mcpTools.length} tools`); - } catch (error) { - console.warn(` Warning: Could not fetch from ${account.provider}: ${error}`); + conversationHistory.push({ role: "user", content: userMessage }); + if (responseMessages && responseMessages.length > 0) { + for (const msg of responseMessages) { + conversationHistory.push(msg as ModelMessage); } + } else { + conversationHistory.push({ role: "assistant", content: text }); } - const total = Object.keys(tools).length; - console.log(`\nTotal: ${total} tools from ${Object.keys(providerCounts).length} providers`); - - return { tools, providerCounts }; + trimHistory(conversationHistory, MAX_HISTORY_TURNS); + return text; } -/** - * Build system prompt dynamically based on available providers - */ -function buildSystemPrompt(providerCounts: Record): string { - const providers = Object.entries(providerCounts); - - // Build capabilities list from actual providers - const capabilities = providers - .map(([provider, count]) => `- **${provider}**: ${count} tools available`) - .join('\n'); - - // Base prompt - let prompt = `You are a helpful assistant with access to StackOne's unified API tools. -You can directly call tools for the user's connected services. - -Connected providers: -${capabilities} - -Tool names follow the pattern: provider_accountId_action (e.g., gmail_abc123_gmail_list_messages, googledrive_xyz789_drive_list_files). Use the exact tool names listed in your available tools. -Use tool names and descriptions to understand their capabilities. -You have conversation history - you can reference previous results. -Always complete multi-step tasks fully.`; - - // Add provider-specific tips only if those providers are connected - const providerNames = providers.map(([name]) => name.toLowerCase()); +function printBanner(toolCount: number): void { + const { cyan, bright, reset, dim, yellow } = colors; - if (providerNames.some(p => p.includes('gmail'))) { - prompt += ` + console.log(` +${cyan}${bright} ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” + │ │ + │ ${yellow}ā—†${cyan} StackOne AI Agent │ + │ │ + ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜${reset} -Gmail tips: -- Reading attachments: Use gmail_get_message first, then gmail_get_attachment with the attachmentId -- Sending emails: Use gmail_send_message (requires RFC 2822 format) or create a draft first`; - } +${dim} Powered by Vercel AI SDK + StackOne Toolset${reset} +${dim} Model: ${reset}${MODEL} +${dim} Tools: ${reset}${toolCount} loaded - if (providerNames.some(p => p.includes('drive'))) { - prompt += ` +${bright} Commands${reset} +${dim} ────────────────────────────────────────${reset} + ${yellow}quit${reset}, ${yellow}exit${reset}, ${yellow}q${reset} Exit the agent + ${yellow}/clear${reset} Clear conversation history -Google Drive tips: -- Most tools use nested parameters: { "query": {...} } or { "path": { "id": "..." } }`; - } - - return prompt; +${cyan} ────────────────────────────────────────${reset} +`); } -/** - * Run the agent with conversation history - */ -async function runAgent( - userMessage: string, - tools: Record, - systemPrompt: string -): Promise { - console.log(`\nšŸ“ User: ${userMessage}\n`); - - // Add to history - conversationHistory.push({ role: "user", content: userMessage }); - - try { - const { text, toolCalls, messages: responseMessages } = await generateText({ - model: anthropic("claude-sonnet-4-20250514"), - system: systemPrompt, - messages: conversationHistory, - tools, - maxSteps: 15, // Allow more steps for multi-tool workflows - }); - - // Log tool summary - if (toolCalls && toolCalls.length > 0) { - const toolNames = toolCalls.map((t) => t.toolName); - const uniqueTools = [...new Set(toolNames)]; - console.log(`\nšŸ“Š Tools used: ${uniqueTools.join(", ")} (${toolCalls.length} calls)`); - } - - // Persist full response (assistant + tool calls + tool results) so follow-ups can reference prior results - if (responseMessages && responseMessages.length > 0) { - for (const msg of responseMessages) { - conversationHistory.push(msg as CoreMessage); - } - } else { - // Fallback: SDK may not return messages in some versions - conversationHistory.push({ role: "assistant", content: text }); - } - - // Trim history if needed - while (conversationHistory.length > MAX_HISTORY_TURNS * 2) { - conversationHistory.shift(); - } - - console.log(`\nšŸ¤– Assistant: ${text}\n`); - return text; - } catch (error) { - console.error("Agent error:", error); - throw error; - } -} - -/** - * Interactive CLI mode - */ -async function interactiveMode( - tools: Record, - providerCounts: Record, - systemPrompt: string -): Promise { +async function interactiveMode(tools: ToolSet): Promise { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); - console.log("\n╔══════════════════════════════════════════════════════════╗"); - console.log("ā•‘ StackOne AI Agent (TypeScript) ā•‘"); - console.log("╠══════════════════════════════════════════════════════════╣"); - console.log("ā•‘ Direct tool access - no meta-tool overhead! ā•‘"); - console.log("ā•‘ Commands: 'quit' to exit, '/clear' to reset history ā•‘"); - console.log("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n"); - - // Show provider summary from actual data - const summary = Object.entries(providerCounts) - .map(([provider, count]) => `${count} ${provider}`) - .join(", "); - console.log(`Tools: ${summary}\n`); - - // Show dynamic examples based on connected providers - const providerNames = Object.keys(providerCounts).map(p => p.toLowerCase()); - console.log("Examples:"); - if (providerNames.some(p => p.includes('gmail'))) { - console.log(" • List my recent emails"); - console.log(" • Read my last email and reply saying I'll get back to them"); - } - if (providerNames.some(p => p.includes('ashby'))) { - console.log(" • Show open jobs in Ashby"); - } - if (providerNames.some(p => p.includes('drive'))) { - console.log(" • List files in my Drive"); - } - if (providerNames.some(p => p.includes('slack'))) { - console.log(" • Send a message to #general channel"); - } - if (providerNames.some(p => p.includes('salesforce') || p.includes('hubspot'))) { - console.log(" • List my recent contacts"); + const isInteractive = process.stdin.isTTY; + const { green, magenta, reset, bright, dim, yellow } = colors; + + if (isInteractive) { + printBanner(Object.keys(tools).length); } - // Fallback generic example if no specific providers matched - if (!providerNames.some(p => ['gmail', 'ashby', 'drive', 'slack', 'salesforce', 'hubspot'].some(known => p.includes(known)))) { - console.log(" • List available data"); - console.log(" • Show me what you can do"); + + if (!isInteractive) { + const lines: string[] = []; + for await (const line of rl) { + lines.push(line); + } + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed && !["quit", "exit", "q"].includes(trimmed.toLowerCase())) { + try { + const response = await runAgent(trimmed, tools); + console.log(response); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`Error: ${message}`); + } + } + } + return; } - console.log(""); const askQuestion = (): void => { - rl.question("You: ", async (input) => { + rl.question(`${green}${bright} You ${reset}${dim}>${reset} `, async (input) => { const trimmed = input.trim(); if (["quit", "exit", "q"].includes(trimmed.toLowerCase())) { - console.log("Goodbye!"); + console.log(`\n${dim} Goodbye!${reset}\n`); rl.close(); return; } if (trimmed.toLowerCase() === "/clear") { conversationHistory.length = 0; - console.log("History cleared.\n"); + console.log(`${dim} History cleared.${reset}\n`); askQuestion(); return; } @@ -541,49 +165,53 @@ async function interactiveMode( } try { - await runAgent(trimmed, tools, systemPrompt); + console.log(); + const response = await runAgent(trimmed, tools); + console.log(`${magenta}${bright} Assistant ${reset}${dim}>${reset} ${response}\n`); } catch (error) { - console.error("Error:", error); + const message = error instanceof Error ? error.message : String(error); + console.error(`${yellow} Error: ${message}${reset}\n`); } askQuestion(); }); }; + rl.on("close", () => { + console.log(`\n${dim} Goodbye!${reset}\n`); + process.exit(0); + }); + askQuestion(); } -/** - * Main entry point - */ async function main(): Promise { - if (!STACKONE_API_KEY) { - console.error("Error: STACKONE_API_KEY not set"); + const { yellow, reset, dim } = colors; + + if (!process.env.STACKONE_API_KEY) { + console.error(`${yellow}Error:${reset} STACKONE_API_KEY not set`); process.exit(1); } - if (!process.env.ANTHROPIC_API_KEY) { - console.error("Error: ANTHROPIC_API_KEY not set"); + if (!STACKONE_ACCOUNT_ID) { + console.error(`${yellow}Error:${reset} STACKONE_ACCOUNT_ID not set`); process.exit(1); } - // Fetch and create tools - const result = await fetchAndCreateTools().catch((error): never => { - console.error("Failed to fetch tools:", error); - return process.exit(1); - }); + if (!process.env.ANTHROPIC_API_KEY) { + console.error(`${yellow}Error:${reset} ANTHROPIC_API_KEY not set`); + process.exit(1); + } - const { tools, providerCounts } = result; + console.log(`\n${dim} Loading tools...${reset}`); + const tools = await loadTools(); if (Object.keys(tools).length === 0) { - console.error("No tools available. Check your StackOne configuration."); + console.error(`${yellow}Error:${reset} No tools available. Check STACKONE_ACCOUNT_ID and STACKONE_TOOL_FILTER.`); process.exit(1); } - // Build system prompt based on actual connected providers - const systemPrompt = buildSystemPrompt(providerCounts); - - await interactiveMode(tools, providerCounts, systemPrompt); + await interactiveMode(tools); } main().catch(console.error); From 18e11abcf994904796c43a37d26bc9cb0fb92f4f Mon Sep 17 00:00:00 2001 From: Hisku Date: Wed, 4 Feb 2026 15:36:08 +0000 Subject: [PATCH 17/22] Update .env.example to clarify tool filter options for StackOne TypeScript Agent --- apps/stackone-typescript-agent/.env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/stackone-typescript-agent/.env.example b/apps/stackone-typescript-agent/.env.example index de139d1..aed6f9b 100644 --- a/apps/stackone-typescript-agent/.env.example +++ b/apps/stackone-typescript-agent/.env.example @@ -1,8 +1,8 @@ STACKONE_API_KEY=your_stackone_api_key STACKONE_ACCOUNT_ID=your_stackone_account_id -# Optional: filter which tools to load (default: "*" loads all) -# STACKONE_TOOL_FILTER=documents_* +# Optional: filter tools by action pattern (default: "*" loads all) +# STACKONE_TOOL_FILTER=googledrive_* # Optional: model to use (default: claude-sonnet-4-20250514) # MODEL=claude-sonnet-4-20250514 From 241248b2af9be23fb387aa1727b952f65f5f8452 Mon Sep 17 00:00:00 2001 From: Hisku Date: Wed, 4 Feb 2026 16:01:08 +0000 Subject: [PATCH 18/22] Refactor agent.ts to improve error handling and conversation history management. Introduced a new formatError function for better error messages and updated conversationHistory type to enhance type safety. --- apps/stackone-typescript-agent/src/agent.ts | 46 ++++++++++++--------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 020b2b4..e98cbe7 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -4,7 +4,7 @@ import "dotenv/config"; import { anthropic } from "@ai-sdk/anthropic"; -import { generateText, ToolSet, ModelMessage, stepCountIs } from "ai"; +import { generateText, stepCountIs, type ToolSet } from "ai"; import { StackOneToolSet } from "@stackone/ai"; import * as readline from "readline"; @@ -14,7 +14,8 @@ const TOOL_FILTER = process.env.STACKONE_TOOL_FILTER ?? "*"; const MODEL = process.env.MODEL ?? "claude-sonnet-4-20250514"; const MAX_HISTORY_TURNS = 10; -const conversationHistory: ModelMessage[] = []; +type Message = { role: "user" | "assistant"; content: string }; +const conversationHistory: Message[] = []; const SYSTEM_PROMPT = `You are a helpful assistant with access to StackOne tools. Use the available tools to help the user with their requests. @@ -32,7 +33,24 @@ const colors = { magenta: "\x1b[35m", }; -function trimHistory(messages: ModelMessage[], maxTurns: number): void { +function formatError(error: unknown): string { + const message = error instanceof Error ? error.message : String(error); + if (message.includes("401") || message.includes("Unauthorized")) { + return "Authentication failed. Check your API keys."; + } + if (message.includes("rate") || message.includes("429")) { + return "Rate limited. Please wait a moment and try again."; + } + if (message.includes("timeout") || message.includes("ETIMEDOUT")) { + return "Request timed out. Please try again."; + } + if (message.includes("network") || message.includes("ENOTFOUND")) { + return "Network error. Check your internet connection."; + } + return message; +} + +function trimHistory(messages: Message[], maxTurns: number): void { if (messages.length <= 0 || maxTurns <= 0) return; let userCount = 0; let startIndex = 0; @@ -58,30 +76,22 @@ async function loadTools(): Promise { const actions = TOOL_FILTER !== "*" ? [TOOL_FILTER] : undefined; const tools = await toolset.fetchTools({ actions }); + // Type assertion needed due to SDK schema type variance return tools.toAISDK() as unknown as ToolSet; } async function runAgent(userMessage: string, tools: ToolSet): Promise { const result = await generateText({ - model: anthropic(MODEL) as Parameters[0]["model"], + model: anthropic(MODEL), system: SYSTEM_PROMPT, messages: [...conversationHistory, { role: "user" as const, content: userMessage }], tools, stopWhen: stepCountIs(15), }); - const { text, response } = result; - const responseMessages = response?.messages; - + const { text } = result; conversationHistory.push({ role: "user", content: userMessage }); - if (responseMessages && responseMessages.length > 0) { - for (const msg of responseMessages) { - conversationHistory.push(msg as ModelMessage); - } - } else { - conversationHistory.push({ role: "assistant", content: text }); - } - + conversationHistory.push({ role: "assistant", content: text }); trimHistory(conversationHistory, MAX_HISTORY_TURNS); return text; } @@ -134,8 +144,7 @@ async function interactiveMode(tools: ToolSet): Promise { const response = await runAgent(trimmed, tools); console.log(response); } catch (error) { - const message = error instanceof Error ? error.message : String(error); - console.error(`Error: ${message}`); + console.error(`Error: ${formatError(error)}`); } } } @@ -169,8 +178,7 @@ async function interactiveMode(tools: ToolSet): Promise { const response = await runAgent(trimmed, tools); console.log(`${magenta}${bright} Assistant ${reset}${dim}>${reset} ${response}\n`); } catch (error) { - const message = error instanceof Error ? error.message : String(error); - console.error(`${yellow} Error: ${message}${reset}\n`); + console.error(`${yellow} Error: ${formatError(error)}${reset}\n`); } askQuestion(); From 198ba085d53dba1be3653ce96919eac1063b5583 Mon Sep 17 00:00:00 2001 From: Hisku Date: Thu, 5 Feb 2026 09:58:49 +0000 Subject: [PATCH 19/22] Improve .env.example with additional comments --- apps/stackone-typescript-agent/.env.example | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/stackone-typescript-agent/.env.example b/apps/stackone-typescript-agent/.env.example index aed6f9b..1fc47f8 100644 --- a/apps/stackone-typescript-agent/.env.example +++ b/apps/stackone-typescript-agent/.env.example @@ -1,8 +1,13 @@ STACKONE_API_KEY=your_stackone_api_key STACKONE_ACCOUNT_ID=your_stackone_account_id -# Optional: filter tools by action pattern (default: "*" loads all) -# STACKONE_TOOL_FILTER=googledrive_* +# Optional: override StackOne base URL (default: https://api.stackone.com) +# STACKONE_BASE_URL=https://api.stackone.com + +# Optional: filter tools by action key pattern (default: "*" loads all) +# Examples: only messaging (Gmail), or only list/get operations +# STACKONE_TOOL_FILTER=messaging_* +# STACKONE_TOOL_FILTER=*_list_* # Optional: model to use (default: claude-sonnet-4-20250514) # MODEL=claude-sonnet-4-20250514 From 336b0bc0bd8b0f7b1767858dbd0d19479971b249 Mon Sep 17 00:00:00 2001 From: Hisku Date: Thu, 5 Feb 2026 10:20:05 +0000 Subject: [PATCH 20/22] Add Node.js engine requirement to package.json for StackOne TypeScript Agent --- apps/stackone-typescript-agent/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/stackone-typescript-agent/package.json b/apps/stackone-typescript-agent/package.json index e22551c..67ee342 100644 --- a/apps/stackone-typescript-agent/package.json +++ b/apps/stackone-typescript-agent/package.json @@ -4,6 +4,9 @@ "private": true, "description": "StackOne AI Agent Example using Vercel AI SDK and StackOne Toolset SDK (@stackone/ai)", "type": "module", + "engines": { + "node": ">=20.19.6" + }, "scripts": { "agent": "tsx src/agent.ts", "check-types": "tsc --noEmit" From b7dcee1838a07f05c038130b03c77253fb05d967 Mon Sep 17 00:00:00 2001 From: Hiskias Date: Thu, 5 Feb 2026 10:20:55 +0000 Subject: [PATCH 21/22] Update apps/stackone-typescript-agent/src/agent.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/stackone-typescript-agent/src/agent.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index e98cbe7..9282c4b 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -222,4 +222,7 @@ async function main(): Promise { await interactiveMode(tools); } -main().catch(console.error); +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); From b525059df1237cbd1bdb865d5d498396103b6d61 Mon Sep 17 00:00:00 2001 From: Hisku Date: Thu, 5 Feb 2026 10:24:02 +0000 Subject: [PATCH 22/22] Refactor interactiveMode function in agent.ts --- apps/stackone-typescript-agent/src/agent.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/stackone-typescript-agent/src/agent.ts b/apps/stackone-typescript-agent/src/agent.ts index 9282c4b..3485eef 100644 --- a/apps/stackone-typescript-agent/src/agent.ts +++ b/apps/stackone-typescript-agent/src/agent.ts @@ -133,11 +133,7 @@ async function interactiveMode(tools: ToolSet): Promise { } if (!isInteractive) { - const lines: string[] = []; for await (const line of rl) { - lines.push(line); - } - for (const line of lines) { const trimmed = line.trim(); if (trimmed && !["quit", "exit", "q"].includes(trimmed.toLowerCase())) { try { @@ -148,6 +144,7 @@ async function interactiveMode(tools: ToolSet): Promise { } } } + rl.close(); return; }