{"_id":"@drew-foxall/a2a-ai-sdk-adapter","_rev":"3-edf5180e9a2eeaac609e82a8cf66ea07","name":"@drew-foxall/a2a-ai-sdk-adapter","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.1":{"name":"@drew-foxall/a2a-ai-sdk-adapter","version":"1.0.1","keywords":["a2a","agent","ai-sdk","adapter","vercel-ai-sdk","hono","typescript","agent-to-agent","multi-agent","llm"],"author":{"name":"Drew Foxall"},"license":"Apache-2.0","_id":"@drew-foxall/a2a-ai-sdk-adapter@1.0.1","maintainers":[{"name":"drew-foxall","email":"drew@foxalltogether.com"}],"homepage":"https://github.com/drew-foxall/a2a-js-sdk-examples/tree/main/packages/a2a-ai-sdk-adapter#readme","bugs":{"url":"https://github.com/drew-foxall/a2a-js-sdk-examples/issues"},"dist":{"shasum":"5a5d0a14324a761c30baf4e8e28e822c44c26707","tarball":"https://registry.npmjs.org/@drew-foxall/a2a-ai-sdk-adapter/-/a2a-ai-sdk-adapter-1.0.1.tgz","fileCount":9,"integrity":"sha512-3RTyUnvDKfi/Uqbe/dH/0z5ryEL0yo9CCZLXspBkW6Jv40b+WcofEI8RsFowjsDGHSUvvKeW+1S93bB6Bgnq1g==","signatures":[{"sig":"MEUCIGKHmSxKL8MNUqrm9bxxH9O4eFq9xMYyPM6HlElWWS4qAiEAzpwdMEDhGs8fT5yJzZpH/3NkwolgZSc487a8m7VDPGc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82646},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"5410f6ca82f49ddf642ced65863d46d6c537b18c","scripts":{"test":"vitest run","build":"tsc","watch":"tsc --watch","test:ui":"vitest --ui","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm build"},"_npmUser":{"name":"drew-foxall","email":"drew@foxalltogether.com"},"repository":{"url":"git+https://github.com/drew-foxall/a2a-js-sdk-examples.git","type":"git","directory":"packages/a2a-ai-sdk-adapter"},"_npmVersion":"10.9.2","description":"Unified adapter bridging Vercel AI SDK ToolLoopAgent with A2A protocol","directories":{},"_nodeVersion":"22.16.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.11.1","devDependencies":{"ai":"6.0.0-beta.99","zod":"^3.25.0","uuid":"^11.1.0","vitest":"^3.0.0","@vitest/ui":"^3.0.0","typescript":"^5.8.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0","@drew-foxall/a2a-js-sdk":"^0.3.5","@total-typescript/tsconfig":"1.0.4"},"peerDependencies":{"ai":"^6.0.0","uuid":"^11.0.0","@drew-foxall/a2a-js-sdk":"^0.3.5"},"_npmOperationalInternal":{"tmp":"tmp/a2a-ai-sdk-adapter_1.0.1_1764002533126_0.9138662147867471","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@drew-foxall/a2a-ai-sdk-adapter","version":"1.0.2","keywords":["a2a","agent","ai-sdk","adapter","vercel-ai-sdk","hono","typescript","agent-to-agent","multi-agent","llm"],"author":{"name":"Drew Foxall"},"license":"Apache-2.0","_id":"@drew-foxall/a2a-ai-sdk-adapter@1.0.2","maintainers":[{"name":"drew-foxall","email":"drew@foxalltogether.com"}],"homepage":"https://github.com/drew-foxall/a2a-js-sdk-examples/tree/main/packages/a2a-ai-sdk-adapter#readme","bugs":{"url":"https://github.com/drew-foxall/a2a-js-sdk-examples/issues"},"dist":{"shasum":"d9d783d54342d20a2c8f26fc20244dcfe3dfcfad","tarball":"https://registry.npmjs.org/@drew-foxall/a2a-ai-sdk-adapter/-/a2a-ai-sdk-adapter-1.0.2.tgz","fileCount":9,"integrity":"sha512-Q1qpP4Qr9ZSmWgua3GtRldctYScg7vJU3gn1PqdRr7Ll2sI9nV5D8dwgRHMsaoNFFL1fXDgqiJsVdJMubGveDg==","signatures":[{"sig":"MEUCIQCsRgxdJMvyKopqJXRtRTLQRVdmFGaZjBuVOmgQiBfVFgIgCZWF4QjfWN4A905va2FpDfkqXBKhRrSPtDOGw749XHs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82644},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"5410f6ca82f49ddf642ced65863d46d6c537b18c","scripts":{"test":"vitest run","build":"tsc","watch":"tsc --watch","test:ui":"vitest --ui","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm build"},"_npmUser":{"name":"drew-foxall","email":"drew@foxalltogether.com"},"repository":{"url":"git+https://github.com/drew-foxall/a2a-js-sdk-examples.git","type":"git","directory":"packages/a2a-ai-sdk-adapter"},"_npmVersion":"10.9.2","description":"Unified adapter bridging Vercel AI SDK ToolLoopAgent with A2A protocol","directories":{},"_nodeVersion":"22.16.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.11.1","devDependencies":{"ai":"6.0.0-beta.99","zod":"^3.25.0","uuid":"^11.1.0","vitest":"^3.0.0","@vitest/ui":"^3.0.0","typescript":"^5.8.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0","@drew-foxall/a2a-js-sdk":"^0.3.5","@total-typescript/tsconfig":"1.0.4"},"peerDependencies":{"ai":"^6.0.0","uuid":"^11.0.0","@drew-foxall/a2a-js-sdk":"^0.3.5"},"_npmOperationalInternal":{"tmp":"tmp/a2a-ai-sdk-adapter_1.0.2_1764002735977_0.23020051371991257","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@drew-foxall/a2a-ai-sdk-adapter","version":"1.1.0","description":"Unified adapter bridging Vercel AI SDK ToolLoopAgent with A2A protocol","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./durable":{"types":"./dist/durable-adapter.d.ts","import":"./dist/durable-adapter.js"}},"scripts":{"build":"tsc","watch":"tsc --watch","test":"vitest run","test:watch":"vitest","test:ui":"vitest --ui","typecheck":"tsc --noEmit","lint":"biome check .","lint:fix":"biome check --write .","format":"biome format .","format:write":"biome format --write .","prepublishOnly":"pnpm build"},"keywords":["a2a","agent","ai-sdk","adapter","vercel-ai-sdk","hono","typescript","agent-to-agent","multi-agent","llm"],"author":{"name":"Drew Foxall"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/drew-foxall/a2a-js-sdk-examples.git","directory":"packages/a2a-ai-sdk-adapter"},"bugs":{"url":"https://github.com/drew-foxall/a2a-js-sdk-examples/issues"},"homepage":"https://github.com/drew-foxall/a2a-js-sdk-examples/tree/main/packages/a2a-ai-sdk-adapter#readme","peerDependencies":{"@drew-foxall/a2a-js-sdk":"^0.4.2","ai":"^6.0.0","uuid":">=11.0.0","workflow":"4.0.1-beta.32","zod":">=4.0.0"},"peerDependenciesMeta":{"workflow":{"optional":true},"zod":{"optional":true}},"devDependencies":{"@biomejs/biome":"2.3.10","@drew-foxall/a2a-js-sdk":"^0.4.2","@total-typescript/tsconfig":"1.0.4","@types/node":"^24.10.1","@types/uuid":"^11.0.0","@vitest/ui":"^4.0.14","ai":"6.0.3","typescript":"^5.9.3","uuid":"^13.0.0","vitest":"^4.0.14","workflow":"4.0.1-beta.32","zod":"4.3.4"},"packageManager":"pnpm@10.23.0","engines":{"node":"24.x","pnpm":">=10.0.0"},"gitHead":"c836b031af950892a6f6158ed6f563a947199c64","_id":"@drew-foxall/a2a-ai-sdk-adapter@1.1.0","_nodeVersion":"22.16.0","_npmVersion":"11.6.4","dist":{"integrity":"sha512-QLRuY0yUD+qGtwVkkiQokqyJX5EJmE1RSYFAguqlWV7cp75XCjMYE5k3Dai4rWzZv/UPTr2X1lWpc+fRsbhanA==","shasum":"95802fd3725e250b4c6597e51b75f86363d9c322","tarball":"https://registry.npmjs.org/@drew-foxall/a2a-ai-sdk-adapter/-/a2a-ai-sdk-adapter-1.1.0.tgz","fileCount":16,"unpackedSize":153326,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDbuU/W541u4TqUltKbN5hPCx/T730S9vhMoMN1GdcvkgIhAI5BdZV/r/5682k/V31xZ7qEh7mK5N594Q8j7E6YETOA"}]},"_npmUser":{"name":"drew-foxall","email":"drew@foxalltogether.com"},"directories":{},"maintainers":[{"name":"drew-foxall","email":"drew@foxalltogether.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/a2a-ai-sdk-adapter_1.1.0_1767554373546_0.858670042518457"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-24T16:42:13.065Z","modified":"2026-01-04T19:19:33.901Z","1.0.1":"2025-11-24T16:42:13.327Z","1.0.2":"2025-11-24T16:45:36.187Z","1.1.0":"2026-01-04T19:19:33.704Z"},"bugs":{"url":"https://github.com/drew-foxall/a2a-js-sdk-examples/issues"},"author":{"name":"Drew Foxall"},"license":"Apache-2.0","homepage":"https://github.com/drew-foxall/a2a-js-sdk-examples/tree/main/packages/a2a-ai-sdk-adapter#readme","keywords":["a2a","agent","ai-sdk","adapter","vercel-ai-sdk","hono","typescript","agent-to-agent","multi-agent","llm"],"repository":{"type":"git","url":"git+https://github.com/drew-foxall/a2a-js-sdk-examples.git","directory":"packages/a2a-ai-sdk-adapter"},"description":"Unified adapter bridging Vercel AI SDK ToolLoopAgent with A2A protocol","maintainers":[{"name":"drew-foxall","email":"drew@foxalltogether.com"}],"readme":"# @drew-foxall/a2a-ai-sdk-adapter\n\n[![npm version](https://img.shields.io/npm/v/@drew-foxall/a2a-ai-sdk-adapter)](https://www.npmjs.com/package/@drew-foxall/a2a-ai-sdk-adapter)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.8-blue)](https://www.typescriptlang.org/)\n\n**Unified adapter bridging Vercel AI SDK's ToolLoopAgent with the A2A (Agent-to-Agent) protocol.**\n\nThis package provides a robust and type-safe way to expose AI SDK agents as A2A-compliant services, supporting both simple (awaited) and streaming interactions, along with flexible artifact generation and logging.\n\n**Two Adapters Available:**\n- **`A2AAdapter`** - For standard `ToolLoopAgent` agents (non-durable)\n- **`DurableA2AAdapter`** - For durable workflows using Workflow DevKit (import from `@drew-foxall/a2a-ai-sdk-adapter/durable`)\n\n---\n\n## 📦 Installation\n\n```bash\nnpm install @drew-foxall/a2a-ai-sdk-adapter\n# or\npnpm add @drew-foxall/a2a-ai-sdk-adapter\n# or\nyarn add @drew-foxall/a2a-ai-sdk-adapter\n```\n\n**Peer Dependencies**:\n- `ai` ^6.0.0 (Vercel AI SDK)\n- `@drew-foxall/a2a-js-sdk` ^0.3.5\n- `uuid` ^11.0.0\n\n---\n\n## 🚀 Quick Start\n\n```typescript\nimport { ToolLoopAgent } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { A2AAdapter } from \"@drew-foxall/a2a-ai-sdk-adapter\";\nimport { A2AHonoApp } from \"@drew-foxall/a2a-js-sdk/server/hono\";\nimport { serve } from \"@hono/node-server\";\n\n// 1. Create your AI SDK agent\nconst agent = new ToolLoopAgent({\n  model: openai(\"gpt-4o\"),\n  instructions: \"You are a helpful assistant\",\n  tools: {},\n});\n\n// 2. Wrap with A2A adapter\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\", // or \"generate\"\n});\n\n// 3. Create A2A server\nconst app = new A2AHonoApp({\n  card: {\n    name: \"My Agent\",\n    description: \"A helpful AI agent\",\n    url: \"http://localhost:3000\",\n    version: \"1.0.0\",\n    protocolVersion: \"0.3.0\",\n    capabilities: {\n      streaming: true,\n    },\n    defaultInputModes: [\"text/plain\"],\n    defaultOutputModes: [\"text/plain\"],\n    skills: [],\n  },\n  executor,\n});\n\n// 4. Start server\nserve({ fetch: app.fetch, port: 3000 });\n```\n\n---\n\n## 📖 API Documentation\n\n### `A2AAdapter<TTools extends ToolSet>`\n\nThe main adapter class that bridges AI SDK agents with the A2A protocol.\n\n#### Constructor\n\n```typescript\nconstructor(agent: ToolLoopAgent<never, TTools, never>, config: A2AAdapterConfig)\n```\n\n**Parameters**:\n- `agent`: A configured `ToolLoopAgent` from Vercel AI SDK\n- `config`: Configuration object (see below)\n\n#### Configuration Options (`A2AAdapterConfig`)\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `mode` | `'stream' \\| 'generate'` | **Yes** | Execution mode (see [Mode Selection](#mode-selection)) |\n| `selectResponseType` | `(ctx) => 'message' \\| 'task' \\| Promise<'message' \\| 'task'>` | No | **Agent-owned routing step** to choose A2A `Message` vs `Task` per request (defaults to `task`) |\n| `systemPrompt` | `string` | No | System prompt for the agent (default: generic A2A prompt) |\n| `maxSteps` | `number` | No | Max tool call iterations (default: 5) |\n| `includeHistory` | `boolean` | No | Include conversation history (default: false) |\n| `logger` | `A2ALogger` | No | Custom logger (default: `ConsoleLogger`) |\n| `parseArtifacts` | `(text: string, context: ArtifactGenerationContext) => ParsedArtifacts \\| ParsedArtifact[]` | No | Parse artifacts from text (stream mode only) |\n| `generateArtifacts` | `(context: ArtifactGenerationContext) => Promise<Artifact[]>` | No | Generate artifacts asynchronously |\n| `parseTaskState` | `(text: string) => TaskState` | No | Custom task state parser (default: \"completed\") |\n\n---\n\n## 🧭 Dynamic Response Type (A2A `Message` vs `Task`)\n\nA2A allows an agent to respond with either a stateless **`Message`** (immediate) or a stateful **`Task`** (lifecycle + streaming/progress). See “Agent Response: Task or Message” in the A2A core concepts doc ([A2A key concepts](https://raw.githubusercontent.com/a2aproject/A2A/main/docs/topics/key-concepts.md)).\n\n### Why this must be decided “up front”\n\nIf the server starts emitting task lifecycle events (or starts SSE streaming), it has already committed to a **Task** response shape. Therefore the adapter needs a *routing decision* before it publishes any task events.\n\n### Recommended pattern: agent-owned routing (AI SDK “Routing”)\n\nUse `selectResponseType` as a small *routing/classification step* owned by your agentic system (not “the user telling the agent what to do”):\n\n```ts\nimport { A2AAdapter } from \"@drew-foxall/a2a-ai-sdk-adapter\";\n\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\", // default execution mode for Task responses\n\n  // Agent-owned routing step (AI SDK \"Routing\" pattern)\n  selectResponseType: async ({ userMessage, existingTask }) => {\n    // Continuations should stay in Task mode\n    if (existingTask) return \"task\";\n\n    // Do a cheap classification step (e.g. generateObject / small model)\n    const { responseType } = await classifyRequest(userMessage);\n    return responseType; // \"message\" | \"task\"\n  },\n});\n```\n\nNotes:\n- If you always want stateless behavior (e.g. “Hello World”), return `\"message\"`.\n- If you want full lifecycle + streaming/progress/cancellation, return `\"task\"`.\n\n### Utilities to reduce boilerplate\n\nThe adapter exports small helpers you can use when implementing routing:\n\n```ts\nimport {\n  extractTextFromA2AMessage,\n  createLLMResponseTypeRouter,\n  preferTaskForContinuations,\n} from \"@drew-foxall/a2a-ai-sdk-adapter\";\n\nconst selectResponseType = preferTaskForContinuations(async ({ userMessage }) => {\n  const text = extractTextFromA2AMessage(userMessage);\n  // ... your agent-owned routing/classification logic ...\n  return text ? \"message\" : \"task\";\n});\n```\n\nIf you want a ready-made LLM router (AI SDK `generateObject`), you can use:\n\n```ts\nimport { createLLMResponseTypeRouter } from \"@drew-foxall/a2a-ai-sdk-adapter\";\nimport { z } from \"zod\";\n\nconst selectResponseType = createLLMResponseTypeRouter({\n  model: routingModel, // choose a small/cheap model\n  // Optional: omit schema to use the adapter’s default schema (requires zod installed)\n  schema: z.object({\n    responseType: z.enum([\"message\", \"task\"]),\n    reasoning: z.string().optional(),\n  }),\n});\n```\n\n## 🎯 Mode Selection\n\n### Stream Mode (`mode: 'stream'`)\n\n**Best for**: Long-form content, code generation, chat interfaces\n\n**Capabilities**:\n- ✅ Real-time text streaming\n- ✅ Incremental artifact parsing (via `parseArtifacts`)\n- ✅ Post-completion artifacts (via `generateArtifacts`)\n\n**Example**:\n```typescript\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\",\n  parseArtifacts: (text) => {\n    // Extract code blocks in real-time\n    const codeBlocks = extractCodeBlocks(text);\n    return codeBlocks.map(block => ({\n      content: block.code,\n      mimeType: \"application/octet-stream\",\n      title: `${block.language} code`,\n    }));\n  },\n});\n```\n\n---\n\n### Generate Mode (`mode: 'generate'`)\n\n**Best for**: Quick responses, API-style interactions, simple agents\n\n**Capabilities**:\n- ✅ Single awaited response\n- ✅ Post-completion artifacts (via `generateArtifacts`)\n\n**Example**:\n```typescript\nconst executor = new A2AAdapter(agent, {\n  mode: \"generate\",\n  generateArtifacts: async (ctx) => {\n    // Generate a chart after response is complete\n    const chart = await generateChart(ctx.responseText);\n    return [{\n      content: chart.toString(\"base64\"),\n      mimeType: \"image/png\",\n      title: \"Analytics Chart\",\n    }];\n  },\n});\n```\n\n---\n\n## 📊 Artifacts\n\nArtifacts are supplementary data (images, code, files) attached to agent responses.\n\n### Real-Time Artifact Parsing (Stream Mode Only)\n\n```typescript\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\",\n  parseArtifacts: (text, context) => {\n    // Called for each text chunk\n    const artifacts: ParsedArtifact[] = [];\n    \n    // Extract code blocks\n    const codeMatches = text.matchAll(/```(\\w+)\\n([\\s\\S]+?)```/g);\n    for (const match of codeMatches) {\n      artifacts.push({\n        content: match[2],\n        mimeType: \"application/octet-stream\",\n        title: `${match[1]} code`,\n      });\n    }\n    \n    return artifacts;\n  },\n});\n```\n\n### Post-Completion Artifact Generation\n\n```typescript\nconst executor = new A2AAdapter(agent, {\n  mode: \"generate\", // or \"stream\"\n  generateArtifacts: async (context) => {\n    // Called after response is complete\n    const { responseText, messages, task } = context;\n    \n    // Generate a PNG chart\n    const canvas = createCanvas(800, 600);\n    const ctx = canvas.getContext(\"2d\");\n    // ... draw chart ...\n    \n    return [{\n      content: canvas.toBuffer(\"image/png\").toString(\"base64\"),\n      mimeType: \"image/png\",\n      title: \"Sales Chart\",\n    }];\n  },\n});\n```\n\n---\n\n## 🔧 Logging\n\n### Built-in Loggers\n\n```typescript\nimport { ConsoleLogger, NoOpLogger } from \"@drew-foxall/a2a-ai-sdk-adapter\";\n\n// Console logging (default)\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\",\n  logger: new ConsoleLogger(),\n});\n\n// No logging\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\",\n  logger: new NoOpLogger(),\n});\n```\n\n### Custom Logger\n\n```typescript\nimport { A2ALogger } from \"@drew-foxall/a2a-ai-sdk-adapter\";\n\nclass CustomLogger implements A2ALogger {\n  debug(message: string, meta?: Record<string, unknown>): void {\n    // Your implementation\n  }\n\n  info(message: string, meta?: Record<string, unknown>): void {\n    // Your implementation\n  }\n\n  warn(message: string, meta?: Record<string, unknown>): void {\n    // Your implementation\n  }\n\n  error(message: string, meta?: Record<string, unknown>): void {\n    // Your implementation\n  }\n}\n\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\",\n  logger: new CustomLogger(),\n});\n```\n\n---\n\n## 🔄 Conversation History\n\nEnable multi-turn conversations by including message history:\n\n```typescript\nconst executor = new A2AAdapter(agent, {\n  mode: \"generate\",\n  includeHistory: true, // ← Include previous messages\n});\n```\n\n**Example** (Movie Recommendation Agent):\n```typescript\n// Turn 1: User: \"I want to watch a movie\"\n// Agent: \"What genre do you prefer?\"\n\n// Turn 2: User: \"Sci-fi\"\n// Agent: (has context from Turn 1) \"I recommend Interstellar...\"\n```\n\n---\n\n## 🎭 Custom Task States\n\nBy default, all tasks complete with `state: \"completed\"`. Override for custom workflows:\n\n```typescript\nconst executor = new A2AAdapter(agent, {\n  mode: \"generate\",\n  parseTaskState: (responseText) => {\n    if (responseText.includes(\"NEED_MORE_INFO\")) {\n      return \"input-required\";\n    }\n    if (responseText.includes(\"ERROR\")) {\n      return \"failed\";\n    }\n    return \"completed\";\n  },\n  includeHistory: true, // Usually needed with custom states\n});\n```\n\n**Valid States**: `\"submitted\" | \"working\" | \"completed\" | \"failed\" | \"canceled\" | \"input-required\"`\n\n---\n\n## 🛠️ Advanced Usage\n\n### Multiple Tool Usage\n\n```typescript\nimport { z } from \"zod\";\n\nconst agent = new ToolLoopAgent({\n  model: openai(\"gpt-4o\"),\n  instructions: \"You are a weather assistant\",\n  tools: {\n    getWeather: {\n      description: \"Get current weather for a location\",\n      parameters: z.object({\n        location: z.string().describe(\"City name\"),\n      }),\n      execute: async ({ location }) => {\n        const response = await fetch(`https://wttr.in/${location}?format=j1`);\n        return await response.json();\n      },\n    },\n    getForecast: {\n      description: \"Get 7-day forecast\",\n      parameters: z.object({\n        location: z.string(),\n      }),\n      execute: async ({ location }) => {\n        // ... fetch forecast ...\n      },\n    },\n  },\n});\n\nconst executor = new A2AAdapter(agent, {\n  mode: \"stream\",\n  maxSteps: 10, // Allow multiple tool calls\n});\n```\n\n---\n\n### Multi-Provider Support\n\nWorks with all AI SDK providers:\n\n```typescript\nimport { openai } from \"@ai-sdk/openai\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\nimport { google } from \"@ai-sdk/google\";\n\n// OpenAI\nconst executor1 = new A2AAdapter(\n  new ToolLoopAgent({ model: openai(\"gpt-4o\"), ... }),\n  { mode: \"stream\" }\n);\n\n// Anthropic\nconst executor2 = new A2AAdapter(\n  new ToolLoopAgent({ model: anthropic(\"claude-3-5-sonnet-20241022\"), ... }),\n  { mode: \"stream\" }\n);\n\n// Google\nconst executor3 = new A2AAdapter(\n  new ToolLoopAgent({ model: google(\"gemini-1.5-pro\"), ... }),\n  { mode: \"stream\" }\n);\n```\n\n---\n\n## 🧪 Testing\n\n### Unit Tests with Vitest\n\n```typescript\nimport { describe, it, expect } from \"vitest\";\nimport { ToolLoopAgent } from \"ai\";\nimport { MockLanguageModelV3 } from \"ai/test\";\nimport { A2AAdapter } from \"@drew-foxall/a2a-ai-sdk-adapter\";\n\ndescribe(\"My Agent\", () => {\n  it(\"should respond correctly\", () => {\n    const agent = new ToolLoopAgent({\n      model: new MockLanguageModelV3({\n        doGenerate: async () => ({\n          finishReason: \"stop\",\n          usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 },\n          content: [{ type: \"text\", text: \"Hello, world!\" }],\n          warnings: [],\n        }),\n      }),\n      instructions: \"Test agent\",\n      tools: {},\n    });\n\n    const adapter = new A2AAdapter(agent, {\n      mode: \"generate\",\n    });\n\n    expect(adapter).toBeDefined();\n  });\n});\n```\n\n**See**: [Official AI SDK Testing Guide](https://ai-sdk.dev/docs/ai-sdk-core/testing)\n\n---\n\n## 📚 Examples\n\nFor complete working examples of agents built with this adapter, see the [a2a-js-sdk-examples repository](https://github.com/drew-foxall/a2a-js-sdk-examples).\n\nExamples include:\n- **Hello World** - Simplest possible agent\n- **Dice Agent** - Tool usage example\n- **GitHub Agent** - External API integration\n- **Analytics Agent** - PNG chart generation with artifacts\n- **Currency Agent** - Real-time data fetching\n- **Movie Agent** - Multi-turn conversations\n- **Coder** - Streaming code generation\n- **Content Editor** - Text processing\n- **Travel Planner** - Multi-agent orchestration\n- **Weather & Airbnb Agents** - MCP integration\n\n---\n\n## 🔗 Resources\n\n- **[GitHub Repository](https://github.com/drew-foxall/a2a-js-sdk-examples)** - Source code and examples\n- **[AI SDK Documentation](https://ai-sdk.dev/)** - Vercel AI SDK docs\n- **[A2A Protocol](https://a2a-protocol.org/)** - Agent2Agent protocol specification\n- **[@drew-foxall/a2a-js-sdk](https://github.com/drew-foxall/a2a-js-sdk)** - A2A JavaScript SDK with Hono support\n\n---\n\n## 🤝 Contributing\n\nContributions welcome! Please see the [GitHub repository](https://github.com/drew-foxall/a2a-js-sdk-examples) for contribution guidelines.\n\n---\n\n## 📄 License\n\nApache 2.0 - See [LICENSE](LICENSE) for details\n\n---\n\n## 🙏 Acknowledgments\n\n- **[Vercel AI SDK](https://ai-sdk.dev/)** - Foundation for agent logic\n- **[A2A Project](https://a2a-protocol.org/)** - Agent2Agent protocol\n- **[@drew-foxall/a2a-js-sdk](https://github.com/drew-foxall/a2a-js-sdk)** - A2A JavaScript SDK\n\n---\n\n---\n\n## 🔄 Durable Workflows (DurableA2AAdapter)\n\nFor agents that need durability (automatic retry, result caching, observability), use `DurableA2AAdapter`:\n\n```typescript\nimport { DurableA2AAdapter } from \"@drew-foxall/a2a-ai-sdk-adapter/durable\";\nimport { diceAgentWorkflow } from \"a2a-agents\";\n\n// Wrap a durable workflow for A2A protocol\nconst executor = new DurableA2AAdapter(diceAgentWorkflow, {\n});\n\n// For workflows with additional arguments:\nconst imageExecutor = new DurableA2AAdapter(imageGeneratorWorkflow, {\n  workflowArgs: [env.OPENAI_API_KEY], // Additional args after messages\n});\n```\n\n### How Durability Works\n\nThe durability stack consists of three layers working together:\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│                        DurableA2AAdapter                            │\n│  Bridges A2A protocol with Workflow DevKit via start()              │\n└─────────────────────────────────┬───────────────────────────────────┘\n                                  │ calls start()\n                                  ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│                    Workflow DevKit Runtime                          │\n│  - start() creates run in World, queues workflow execution          │\n│  - \"use workflow\" and \"use step\" directives (SWC transform)         │\n│  - getWritable() for streaming output                               │\n└─────────────────────────────────┬───────────────────────────────────┘\n                                  │ persists to\n                                  ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│                         World (Persistence)                         │\n│  - @drew-foxall/upstash-workflow-world (Cloudflare Workers)         │\n│  - @workflow/world-vercel (Vercel)                                  │\n│  - @workflow/world-local (local dev)                                │\n└─────────────────────────────────┬───────────────────────────────────┘\n                                  │ uses\n                                  ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│                      @drew-foxall/workflow-ai                       │\n│  - DurableAgent: AI SDK integration with \"use step\" internally      │\n│  - Must run inside a workflow context                               │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n**Key Insight:** Calling a workflow function directly does NOT provide durability. The workflow MUST be invoked via `start()` from `workflow/api`, which triggers the World's persistence mechanisms.\n\n### DurableA2AAdapter Configuration\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `workflowArgs` | `TArgs` | No | Additional arguments to pass to the workflow (after messages) |\n| `includeHistory` | `boolean` | No | Include conversation history (default: false) |\n| `parseTaskState` | `(text: string) => TaskState` | No | Custom task state parser |\n| `generateArtifacts` | `(context) => Promise<Artifact[]>` | No | Generate artifacts after completion |\n| `debug` | `boolean` | No | Enable debug logging (default: false) |\n| `logger` | `Logger` | No | Custom logger implementation |\n\n### When to Use DurableA2AAdapter\n\n| Use DurableA2AAdapter When | Use A2AAdapter When |\n|---------------------------|---------------------|\n| Operations take >30 seconds | Quick responses |\n| Expensive API calls (avoid duplicates) | Cheap/free operations |\n| Multi-step coordination | Single operation |\n| Need observability traces | Simple debugging |\n| Operations must survive restarts | Stateless operations |\n\n---\n\n**Built with 🤖 by Drew Foxall**\n","readmeFilename":"README.md"}