@directive-run/ai 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +26 -31
  2. package/dist/anthropic.cjs +1 -1
  3. package/dist/anthropic.cjs.map +1 -1
  4. package/dist/anthropic.d.cts +5 -9
  5. package/dist/anthropic.d.ts +5 -9
  6. package/dist/anthropic.js +1 -1
  7. package/dist/anthropic.js.map +1 -1
  8. package/dist/gemini.cjs +3 -0
  9. package/dist/gemini.cjs.map +1 -0
  10. package/dist/gemini.d.cts +93 -0
  11. package/dist/gemini.d.ts +93 -0
  12. package/dist/gemini.js +3 -0
  13. package/dist/gemini.js.map +1 -0
  14. package/dist/index.cjs +117 -45
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +1376 -2106
  17. package/dist/index.d.ts +1376 -2106
  18. package/dist/index.js +117 -45
  19. package/dist/index.js.map +1 -1
  20. package/dist/multi-agent-orchestrator-CxL8ycw_.d.cts +2290 -0
  21. package/dist/multi-agent-orchestrator-uMp8bLfV.d.ts +2290 -0
  22. package/dist/ollama.cjs.map +1 -1
  23. package/dist/ollama.d.cts +3 -2
  24. package/dist/ollama.d.ts +3 -2
  25. package/dist/ollama.js.map +1 -1
  26. package/dist/openai.cjs +2 -2
  27. package/dist/openai.cjs.map +1 -1
  28. package/dist/openai.d.cts +4 -8
  29. package/dist/openai.d.ts +4 -8
  30. package/dist/openai.js +2 -2
  31. package/dist/openai.js.map +1 -1
  32. package/dist/semantic-cache-F0psCRuz.d.cts +271 -0
  33. package/dist/semantic-cache-F0psCRuz.d.ts +271 -0
  34. package/dist/testing.cjs +42 -7
  35. package/dist/testing.cjs.map +1 -1
  36. package/dist/testing.d.cts +365 -5
  37. package/dist/testing.d.ts +365 -5
  38. package/dist/testing.js +42 -7
  39. package/dist/testing.js.map +1 -1
  40. package/dist/types-Co4BzMiH.d.cts +1373 -0
  41. package/dist/types-Co4BzMiH.d.ts +1373 -0
  42. package/package.json +7 -2
  43. package/dist/types-Bbar7yKz.d.cts +0 -304
  44. package/dist/types-Bbar7yKz.d.ts +0 -304
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  AI agent orchestration with guardrails, cost tracking, and multi-agent coordination. Built on [Directive](https://www.npmjs.com/package/@directive-run/core)'s constraint-driven runtime.
9
9
 
10
- - **No SDK dependencies** – pure `fetch` adapters for OpenAI, Anthropic, and Ollama
10
+ - **No SDK dependencies** – pure `fetch` adapters for OpenAI, Anthropic, Ollama, and Gemini
11
11
  - **Guardrails** – input, output, and tool call validation with retry support
12
12
  - **Multi-agent orchestration** – parallel, sequential, and supervisor patterns
13
13
  - **Cost tracking** – per-call token usage with pricing constants for every provider
@@ -25,24 +25,22 @@ Provider adapters are subpath exports – no extra packages needed.
25
25
  ## Quick Start
26
26
 
27
27
  ```typescript
28
- import { createAgentStack } from "@directive-run/ai";
28
+ import { createAgentOrchestrator } from "@directive-run/ai";
29
29
  import { createOpenAIRunner } from "@directive-run/ai/openai";
30
30
 
31
31
  const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });
32
32
 
33
- const stack = createAgentStack({
33
+ const orchestrator = createAgentOrchestrator({
34
34
  runner,
35
- agents: {
36
- assistant: {
37
- agent: { name: "assistant", instructions: "You are a helpful assistant." },
38
- },
39
- },
40
35
  guardrails: {
41
36
  input: [async (data) => ({ passed: data.input.length < 10000 })],
42
37
  },
43
38
  });
44
39
 
45
- const result = await stack.run("assistant", "Hello!");
40
+ const result = await orchestrator.run(
41
+ { name: "assistant", instructions: "You are a helpful assistant." },
42
+ "Hello!",
43
+ );
46
44
  console.log(result.output);
47
45
  ```
48
46
 
@@ -50,15 +48,15 @@ console.log(result.output);
50
48
 
51
49
  Adapters are thin wrappers around each provider's HTTP API. No SDK dependencies &ndash; pure `fetch`.
52
50
 
53
- | | OpenAI | Anthropic | Ollama |
54
- |---|--------|-----------|--------|
55
- | Import | `@directive-run/ai/openai` | `@directive-run/ai/anthropic` | `@directive-run/ai/ollama` |
56
- | Default model | `gpt-4o` | `claude-sonnet-4-5-20250929` | `llama3` |
57
- | API key required | Yes | Yes | No |
58
- | Streaming runner | `createOpenAIStreamingRunner` | `createAnthropicStreamingRunner` | &ndash; |
59
- | Embedder | `createOpenAIEmbedder` | &ndash; | &ndash; |
60
- | Pricing constants | `OPENAI_PRICING` | `ANTHROPIC_PRICING` | &ndash; |
61
- | Compatible APIs | Azure, Together, any OpenAI-compatible | &ndash; | &ndash; |
51
+ | | OpenAI | Anthropic | Ollama | Gemini |
52
+ |---|--------|-----------|--------|--------|
53
+ | Import | `@directive-run/ai/openai` | `@directive-run/ai/anthropic` | `@directive-run/ai/ollama` | `@directive-run/ai/gemini` |
54
+ | Default model | `gpt-4o` | `claude-sonnet-4-5-20250929` | `llama3` | `gemini-2.0-flash` |
55
+ | API key required | Yes | Yes | No | Yes |
56
+ | Streaming runner | `createOpenAIStreamingRunner` | `createAnthropicStreamingRunner` | &ndash; | `createGeminiStreamingRunner` |
57
+ | Embedder | `createOpenAIEmbedder` | &ndash; | &ndash; | &ndash; |
58
+ | Pricing constants | `OPENAI_PRICING` | `ANTHROPIC_PRICING` | &ndash; | `GEMINI_PRICING` |
59
+ | Compatible APIs | Azure, Together, any OpenAI-compatible | &ndash; | &ndash; | &ndash; |
62
60
 
63
61
  ## Cost Tracking
64
62
 
@@ -101,7 +99,7 @@ const runner = createAnthropicRunner({
101
99
  Coordinate multiple agents with built-in execution patterns:
102
100
 
103
101
  ```typescript
104
- import { createAgentStack, parallel } from "@directive-run/ai";
102
+ import { createMultiAgentOrchestrator, parallel } from "@directive-run/ai";
105
103
  import { createOpenAIRunner } from "@directive-run/ai/openai";
106
104
 
107
105
  const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });
@@ -109,7 +107,7 @@ const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });
109
107
  const researchAgent = { name: "researcher", instructions: "Research the topic thoroughly." };
110
108
  const writerAgent = { name: "writer", instructions: "Write a clear summary." };
111
109
 
112
- const stack = createAgentStack({
110
+ const orchestrator = createMultiAgentOrchestrator({
113
111
  runner,
114
112
  agents: {
115
113
  researcher: { agent: researchAgent, maxConcurrent: 3 },
@@ -124,7 +122,7 @@ const stack = createAgentStack({
124
122
  });
125
123
 
126
124
  // Run the pattern
127
- const result = await stack.runPattern("researchAndWrite", "Quantum computing basics");
125
+ const result = await orchestrator.runPattern("researchAndWrite", "Quantum computing basics");
128
126
  ```
129
127
 
130
128
  ## Subpath Exports
@@ -136,13 +134,14 @@ const result = await stack.runPattern("researchAndWrite", "Quantum computing bas
136
134
  | `@directive-run/ai/openai` | OpenAI / Azure / Together adapter |
137
135
  | `@directive-run/ai/anthropic` | Anthropic Claude adapter |
138
136
  | `@directive-run/ai/ollama` | Local Ollama inference adapter |
137
+ | `@directive-run/ai/gemini` | Google Gemini adapter |
139
138
 
140
139
  ## Testing
141
140
 
142
141
  Mock runners for unit testing without real LLM calls:
143
142
 
144
143
  ```typescript
145
- import { createAgentStack } from "@directive-run/ai";
144
+ import { createAgentOrchestrator } from "@directive-run/ai";
146
145
  import { createMockAgentRunner } from "@directive-run/ai/testing";
147
146
 
148
147
  const mock = createMockAgentRunner({
@@ -151,16 +150,12 @@ const mock = createMockAgentRunner({
151
150
  },
152
151
  });
153
152
 
154
- const stack = createAgentStack({
155
- runner: mock.run,
156
- agents: {
157
- assistant: {
158
- agent: { name: "assistant", instructions: "You are a helpful assistant." },
159
- },
160
- },
161
- });
153
+ const orchestrator = createAgentOrchestrator({ runner: mock.run });
162
154
 
163
- const result = await stack.run("assistant", "Hello!");
155
+ const result = await orchestrator.run(
156
+ { name: "assistant", instructions: "You are a helpful assistant." },
157
+ "Hello!",
158
+ );
164
159
  // result.output === "This is a mock response."
165
160
  ```
166
161
 
@@ -1,3 +1,3 @@
1
- 'use strict';var E=new Set(["http:","https:"]);function x(u){try{let o=new URL(u);if(!E.has(o.protocol))throw new Error(`[Directive] Invalid baseURL protocol "${o.protocol}" \u2013 only http: and https: are allowed`)}catch(o){throw o instanceof Error&&o.message.startsWith("[Directive]")?o:new Error(`[Directive] Invalid baseURL "${u}" \u2013 must be a valid URL (e.g. "https://api.openai.com/v1")`)}}function S(u){let{fetch:o=globalThis.fetch,buildRequest:T,parseResponse:y,parseOutput:m,hooks:g}=u,c=m??(e=>{try{return JSON.parse(e)}catch{return e}});return async(e,s,r)=>{let t=Date.now();g?.onBeforeCall?.({agent:e,input:s,timestamp:t});let i=[{role:"user",content:s}];try{let{url:d,init:l}=T(e,s,i),h=r?.signal?{...l,signal:r.signal}:l,p=await o(d,h);if(!p.ok){let b=await p.text().catch(()=>"");throw new Error(`[Directive] AgentRunner request failed: ${p.status} ${p.statusText}${b?` \u2013 ${b.slice(0,300)}`:""}`)}let a=await y(p,i),R={inputTokens:a.inputTokens??0,outputTokens:a.outputTokens??0},w={role:"assistant",content:a.text},A=[...i,w];r?.onMessage?.(w);let k=Date.now()-t;return g?.onAfterCall?.({agent:e,input:s,output:a.text,totalTokens:a.totalTokens,tokenUsage:R,durationMs:k,timestamp:Date.now()}),{output:c(a.text),messages:A,toolCalls:[],totalTokens:a.totalTokens,tokenUsage:R}}catch(d){let l=Date.now()-t;throw d instanceof Error&&g?.onError?.({agent:e,input:s,error:d,durationMs:l,timestamp:Date.now()}),d}}}var C={"claude-sonnet-4-5-20250929":{input:3,output:15},"claude-haiku-3-5-20241022":{input:.8,output:4},"claude-opus-4-20250514":{input:15,output:75}};function L(u){let{apiKey:o,model:T="claude-sonnet-4-5-20250929",maxTokens:y=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,timeoutMs:f,hooks:c}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicRunner: apiKey is empty. API calls will fail."),S({fetch:g,hooks:c,buildRequest:(e,s,r)=>({url:`${m}/messages`,init:{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:e.model??T,max_tokens:y,system:e.instructions??"",messages:r.map(t=>({role:t.role,content:t.content}))}),...f!=null?{signal:AbortSignal.timeout(f)}:{}}}),parseResponse:async e=>{let s=await e.json(),r=s.content?.[0]?.text??"",t=s.usage?.input_tokens??0,i=s.usage?.output_tokens??0;return {text:r,totalTokens:t+i,inputTokens:t,outputTokens:i}}})}function U(u){let{apiKey:o,model:T="claude-sonnet-4-5-20250929",maxTokens:y=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,hooks:f}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail."),async(c,e,s)=>{let r=Date.now();f?.onBeforeCall?.({agent:c,input:e,timestamp:r});try{let t=await g(`${m}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:c.model??T,max_tokens:y,system:c.instructions??"",messages:[{role:"user",content:e}],stream:!0}),signal:s.signal});if(!t.ok){let k=await t.text().catch(()=>"");throw new Error(`[Directive] Anthropic streaming error ${t.status}${k?` \u2013 ${k.slice(0,200)}`:""}`)}let i=t.body?.getReader();if(!i)throw new Error("[Directive] No response body");let d=new TextDecoder,l="",h="",p=0,a=0;try{for(;;){let{done:k,value:b}=await i.read();if(k)break;l+=d.decode(b,{stream:!0});let v=l.split(`
1
+ 'use strict';var E=new Set(["http:","https:"]);function x(u){try{let o=new URL(u);if(!E.has(o.protocol))throw new Error(`[Directive] Invalid baseURL protocol "${o.protocol}" \u2013 only http: and https: are allowed`)}catch(o){throw o instanceof Error&&o.message.startsWith("[Directive]")?o:new Error(`[Directive] Invalid baseURL "${u}" \u2013 must be a valid URL (e.g. "https://api.openai.com/v1")`)}}function S(u){let{fetch:o=globalThis.fetch,buildRequest:y,parseResponse:T,parseOutput:m,hooks:g}=u,c=m??(e=>{try{return JSON.parse(e)}catch{return e}});return async(e,s,r)=>{let t=Date.now();g?.onBeforeCall?.({agent:e,input:s,timestamp:t});let i=[{role:"user",content:s}];try{let{url:d,init:l}=y(e,s,i),h=r?.signal?{...l,signal:r.signal}:l,p=await o(d,h);if(!p.ok){let b=await p.text().catch(()=>"");throw new Error(`[Directive] AgentRunner request failed: ${p.status} ${p.statusText}${b?` \u2013 ${b.slice(0,300)}`:""}`)}let a=await T(p,i),R={inputTokens:a.inputTokens??0,outputTokens:a.outputTokens??0},w={role:"assistant",content:a.text},A=[...i,w];r?.onMessage?.(w);let k=Date.now()-t;return g?.onAfterCall?.({agent:e,input:s,output:a.text,totalTokens:a.totalTokens,tokenUsage:R,durationMs:k,timestamp:Date.now()}),{output:c(a.text),messages:A,toolCalls:[],totalTokens:a.totalTokens,tokenUsage:R}}catch(d){let l=Date.now()-t;throw d instanceof Error&&g?.onError?.({agent:e,input:s,error:d,durationMs:l,timestamp:Date.now()}),d}}}var C={"claude-sonnet-4-5-20250929":{input:3,output:15},"claude-haiku-3-5-20241022":{input:.8,output:4},"claude-opus-4-20250514":{input:15,output:75}};function L(u){let{apiKey:o,model:y="claude-sonnet-4-5-20250929",maxTokens:T=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,timeoutMs:f,hooks:c}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicRunner: apiKey is empty. API calls will fail."),S({fetch:g,hooks:c,buildRequest:(e,s,r)=>({url:`${m}/messages`,init:{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:e.model??y,max_tokens:T,system:e.instructions??"",messages:r.map(t=>({role:t.role,content:t.content}))}),...f!=null?{signal:AbortSignal.timeout(f)}:{}}}),parseResponse:async e=>{let s=await e.json(),r=s.content?.[0]?.text??"",t=s.usage?.input_tokens??0,i=s.usage?.output_tokens??0;return {text:r,totalTokens:t+i,inputTokens:t,outputTokens:i}}})}function U(u){let{apiKey:o,model:y="claude-sonnet-4-5-20250929",maxTokens:T=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,hooks:f}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail."),async(c,e,s)=>{let r=Date.now();f?.onBeforeCall?.({agent:c,input:e,timestamp:r});try{let t=await g(`${m}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:c.model??y,max_tokens:T,system:c.instructions??"",messages:[{role:"user",content:e}],stream:!0}),signal:s.signal});if(!t.ok){let k=await t.text().catch(()=>"");throw new Error(`[Directive] Anthropic streaming error ${t.status}${k?` \u2013 ${k.slice(0,200)}`:""}`)}let i=t.body?.getReader();if(!i)throw new Error("[Directive] No response body");let d=new TextDecoder,l="",h="",p=0,a=0;try{for(;;){let{done:k,value:b}=await i.read();if(k)break;l+=d.decode(b,{stream:!0});let v=l.split(`
2
2
  `);l=v.pop()??"";for(let D of v){if(!D.startsWith("data: "))continue;let O=D.slice(6).trim();try{let n=JSON.parse(O);if(n.type==="error")throw new Error(`[Directive] Anthropic stream error: ${n.error?.message??JSON.stringify(n.error)}`);n.type==="content_block_delta"&&n.delta?.type==="text_delta"&&(h+=n.delta.text,s.onToken?.(n.delta.text)),n.type==="message_delta"&&n.usage&&(a=n.usage.output_tokens??0),n.type==="message_start"&&n.message?.usage&&(p=n.message.usage.input_tokens??0);}catch(n){if(n instanceof SyntaxError)typeof process<"u"&&process.env?.NODE_ENV==="development"&&console.warn("[Directive] Malformed SSE event from Anthropic:",O);else throw n}}}}finally{i.cancel().catch(()=>{});}let R={role:"assistant",content:h};s.onMessage?.(R);let w={inputTokens:p,outputTokens:a},A=p+a;return f?.onAfterCall?.({agent:c,input:e,output:h,totalTokens:A,tokenUsage:w,durationMs:Date.now()-r,timestamp:Date.now()}),{output:h,messages:[{role:"user",content:e},R],toolCalls:[],totalTokens:A,tokenUsage:w}}catch(t){throw t instanceof Error&&f?.onError?.({agent:c,input:e,error:t,durationMs:Date.now()-r,timestamp:Date.now()}),t}}}exports.ANTHROPIC_PRICING=C;exports.createAnthropicRunner=L;exports.createAnthropicStreamingRunner=U;//# sourceMappingURL=anthropic.cjs.map
3
3
  //# sourceMappingURL=anthropic.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/helpers.ts","../src/adapters/anthropic.ts"],"names":["ALLOWED_PROTOCOLS","validateBaseURL","baseURL","url","err","createRunner","options","fetchFn","buildRequest","parseResponse","parseOutput","hooks","parse","text","agent","input","runOptions","startTime","messages","init","fetchInit","response","errBody","parsed","tokenUsage","assistantMessage","allMessages","durationMs","ANTHROPIC_PRICING","createAnthropicRunner","apiKey","model","maxTokens","timeoutMs","_input","m","res","data","inputTokens","outputTokens","createAnthropicStreamingRunner","callbacks","reader","decoder","buf","fullText","done","value","lines","line","event","parseErr","assistantMsg","totalTokens"],"mappings":"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","file":"anthropic.cjs","sourcesContent":["/**\n * Helper functions for AI adapter — createRunner, estimateCost, state queries, validation.\n */\n\nimport type {\n AdapterHooks,\n AgentLike,\n AgentRunner,\n RunResult,\n RunOptions,\n Message,\n TokenUsage,\n AgentState,\n ApprovalState,\n} from \"./types.js\";\n\n// ============================================================================\n// State Query Helpers\n// ============================================================================\n\n/** Check if agent is currently running. */\nexport function isAgentRunning(state: AgentState): boolean {\n return state.status === \"running\";\n}\n\n/** Check if there are pending approvals. */\nexport function hasPendingApprovals(state: ApprovalState): boolean {\n return state.pending.length > 0;\n}\n\n// ============================================================================\n// Cost Estimation\n// ============================================================================\n\n/**\n * Get total cost estimate based on token usage.\n *\n * @param tokenUsage - Total token count\n * @param ratePerMillionTokens - Cost per million tokens (required, no default to avoid stale pricing)\n * @returns Estimated cost in dollars\n */\nexport function estimateCost(\n tokenUsage: number,\n ratePerMillionTokens: number\n): number {\n return (tokenUsage / 1_000_000) * ratePerMillionTokens;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\"]);\n\n/**\n * Validate that a baseURL uses http or https.\n * Throws immediately at adapter creation time (not at call time) to catch config errors early.\n */\nexport function validateBaseURL(baseURL: string): void {\n try {\n const url = new URL(baseURL);\n if (!ALLOWED_PROTOCOLS.has(url.protocol)) {\n throw new Error(\n `[Directive] Invalid baseURL protocol \"${url.protocol}\" – only http: and https: are allowed`,\n );\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"[Directive]\")) {\n throw err;\n }\n\n throw new Error(\n `[Directive] Invalid baseURL \"${baseURL}\" – must be a valid URL (e.g. \"https://api.openai.com/v1\")`,\n );\n }\n}\n\n// ============================================================================\n// createRunner Helper\n// ============================================================================\n\n/** Parsed response from an LLM provider */\nexport interface ParsedResponse {\n text: string;\n totalTokens: number;\n /** Input token count, when available from the provider */\n inputTokens?: number;\n /** Output token count, when available from the provider */\n outputTokens?: number;\n}\n\n/** Options for creating an AgentRunner from buildRequest/parseResponse */\nexport interface CreateRunnerOptions {\n fetch?: typeof globalThis.fetch;\n buildRequest: (\n agent: AgentLike,\n input: string,\n messages: Message[]\n ) => { url: string; init: RequestInit };\n parseResponse: (\n response: Response,\n messages: Message[]\n ) => Promise<ParsedResponse>;\n parseOutput?: <T>(text: string) => T;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner from buildRequest/parseResponse helpers.\n * Reduces ~50 lines of fetch boilerplate to ~20 lines of configuration.\n *\n * Supports lifecycle hooks for observability:\n * - `onBeforeCall` fires before each API request\n * - `onAfterCall` fires after a successful response (includes token breakdown)\n * - `onError` fires when the request fails\n *\n * @example\n * ```typescript\n * const runClaude = createRunner({\n * buildRequest: (agent, input) => ({\n * url: \"/api/claude\",\n * init: {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * model: agent.model ?? \"claude-haiku-4-5-20251001\",\n * system: agent.instructions ?? \"\",\n * messages: [{ role: \"user\", content: input }],\n * }),\n * },\n * }),\n * parseResponse: async (res) => {\n * const data = await res.json();\n * const inputTokens = data.usage?.input_tokens ?? 0;\n * const outputTokens = data.usage?.output_tokens ?? 0;\n * return {\n * text: data.content?.[0]?.text ?? \"\",\n * totalTokens: inputTokens + outputTokens,\n * inputTokens,\n * outputTokens,\n * };\n * },\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`LLM call: ${durationMs}ms, ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * ```\n */\nexport function createRunner(options: CreateRunnerOptions): AgentRunner {\n const {\n fetch: fetchFn = globalThis.fetch,\n buildRequest,\n parseResponse,\n parseOutput,\n hooks,\n } = options;\n\n const defaultParseOutput = <T>(text: string): T => {\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n };\n\n const parse = parseOutput ?? defaultParseOutput;\n\n return async <T = unknown>(\n agent: AgentLike,\n input: string,\n runOptions?: RunOptions\n ): Promise<RunResult<T>> => {\n const startTime = Date.now();\n hooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n const messages: Message[] = [{ role: \"user\", content: input }];\n\n try {\n const { url, init } = buildRequest(agent, input, messages);\n\n const fetchInit: RequestInit = runOptions?.signal\n ? { ...init, signal: runOptions.signal }\n : init;\n\n const response = await fetchFn(url, fetchInit);\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] AgentRunner request failed: ${response.status} ${response.statusText}${errBody ? ` – ${errBody.slice(0, 300)}` : \"\"}`,\n );\n }\n\n const parsed = await parseResponse(response, messages);\n const tokenUsage: TokenUsage = {\n inputTokens: parsed.inputTokens ?? 0,\n outputTokens: parsed.outputTokens ?? 0,\n };\n\n const assistantMessage: Message = { role: \"assistant\", content: parsed.text };\n const allMessages: Message[] = [...messages, assistantMessage];\n\n runOptions?.onMessage?.(assistantMessage);\n\n const durationMs = Date.now() - startTime;\n hooks?.onAfterCall?.({\n agent,\n input,\n output: parsed.text,\n totalTokens: parsed.totalTokens,\n tokenUsage,\n durationMs,\n timestamp: Date.now(),\n });\n\n return {\n output: parse<T>(parsed.text),\n messages: allMessages,\n toolCalls: [],\n totalTokens: parsed.totalTokens,\n tokenUsage,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n if (err instanceof Error) {\n hooks?.onError?.({\n agent,\n input,\n error: err,\n durationMs,\n timestamp: Date.now(),\n });\n }\n\n throw err;\n }\n };\n}\n","/**\n * @directive-run/ai/anthropic\n *\n * Anthropic adapter for Directive AI. Provides runners for the\n * Anthropic Messages API, including streaming support.\n *\n * @example\n * ```typescript\n * import { createAnthropicRunner, createAnthropicStreamingRunner } from '@directive-run/ai/anthropic';\n *\n * const runner = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../helpers.js\";\nimport type { AdapterHooks, AgentRunner, Message, TokenUsage } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../stack.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Anthropic model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { ANTHROPIC_PRICING } from '@directive-run/ai/anthropic';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://anthropic.com/pricing\n */\nexport const ANTHROPIC_PRICING: Record<string, { input: number; output: number }> = {\n\t\"claude-sonnet-4-5-20250929\": { input: 3, output: 15 },\n\t\"claude-haiku-3-5-20241022\": { input: 0.8, output: 4 },\n\t\"claude-opus-4-20250514\": { input: 15, output: 75 },\n};\n\n// ============================================================================\n// Anthropic Runner\n// ============================================================================\n\n/** Options for createAnthropicRunner */\nexport interface AnthropicRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** @default undefined */\n\ttimeoutMs?: number;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner for the Anthropic Messages API.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const runner = createAnthropicRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`${durationMs}ms – ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * const stack = createAgentStack({ runner, agents: { ... } });\n * ```\n */\nexport function createAnthropicRunner(\n\toptions: AnthropicRunnerOptions,\n): AgentRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\ttimeoutMs,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn createRunner({\n\t\tfetch: fetchFn,\n\t\thooks,\n\t\tbuildRequest: (agent, _input, messages) => ({\n\t\t\turl: `${baseURL}/messages`,\n\t\t\tinit: {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: messages.map((m) => ({\n\t\t\t\t\t\trole: m.role,\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t})),\n\t\t\t\t}),\n\t\t\t\t...(timeoutMs != null ? { signal: AbortSignal.timeout(timeoutMs) } : {}),\n\t\t\t},\n\t\t}),\n\t\tparseResponse: async (res) => {\n\t\t\tconst data = await res.json();\n\t\t\tconst text = data.content?.[0]?.text ?? \"\";\n\t\t\tconst inputTokens = data.usage?.input_tokens ?? 0;\n\t\t\tconst outputTokens = data.usage?.output_tokens ?? 0;\n\n\t\t\treturn {\n\t\t\t\ttext,\n\t\t\t\ttotalTokens: inputTokens + outputTokens,\n\t\t\t\tinputTokens,\n\t\t\t\toutputTokens,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Anthropic Streaming Runner\n// ============================================================================\n\n/** Options for createAnthropicStreamingRunner */\nexport interface AnthropicStreamingRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create a StreamingCallbackRunner for the Anthropic Messages API with\n * server-sent events. Can be used standalone or paired with `createAnthropicRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createAnthropicStreamingRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * });\n * const stack = createAgentStack({\n * runner: createAnthropicRunner({ apiKey }),\n * streaming: { runner: streamingRunner },\n * agents: { ... },\n * });\n * ```\n */\nexport function createAnthropicStreamingRunner(\n\toptions: AnthropicStreamingRunnerOptions,\n): StreamingCallbackRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn async (agent, input, callbacks) => {\n\t\tconst startTime = Date.now();\n\t\thooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n\t\ttry {\n\t\t\tconst response = await fetchFn(`${baseURL}/messages`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: [{ role: \"user\", content: input }],\n\t\t\t\t\tstream: true,\n\t\t\t\t}),\n\t\t\t\tsignal: callbacks.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errBody = await response.text().catch(() => \"\");\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[Directive] Anthropic streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tthrow new Error(\"[Directive] No response body\");\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buf = \"\";\n\t\t\tlet fullText = \"\";\n\t\t\tlet inputTokens = 0;\n\t\t\tlet outputTokens = 0;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tbuf += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buf.split(\"\\n\");\n\t\t\t\t\tbuf = lines.pop() ?? \"\";\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.startsWith(\"data: \")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(data);\n\t\t\t\t\t\t\tif (event.type === \"error\") {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`[Directive] Anthropic stream error: ${event.error?.message ?? JSON.stringify(event.error)}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tevent.type === \"content_block_delta\" &&\n\t\t\t\t\t\t\t\tevent.delta?.type === \"text_delta\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tfullText += event.delta.text;\n\t\t\t\t\t\t\t\tcallbacks.onToken?.(event.delta.text);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_delta\" && event.usage) {\n\t\t\t\t\t\t\t\toutputTokens = event.usage.output_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_start\" && event.message?.usage) {\n\t\t\t\t\t\t\t\tinputTokens = event.message.usage.input_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (parseErr) {\n\t\t\t\t\t\t\tif (parseErr instanceof SyntaxError) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\ttypeof process !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\tprocess.env?.NODE_ENV === \"development\"\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t\t\"[Directive] Malformed SSE event from Anthropic:\",\n\t\t\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow parseErr;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.cancel().catch(() => {});\n\t\t\t}\n\n\t\t\tconst assistantMsg: Message = { role: \"assistant\", content: fullText };\n\t\t\tcallbacks.onMessage?.(assistantMsg);\n\n\t\t\tconst tokenUsage: TokenUsage = { inputTokens, outputTokens };\n\t\t\tconst totalTokens = inputTokens + outputTokens;\n\n\t\t\thooks?.onAfterCall?.({\n\t\t\t\tagent,\n\t\t\t\tinput,\n\t\t\t\toutput: fullText,\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\toutput: fullText,\n\t\t\t\tmessages: [{ role: \"user\" as const, content: input }, assistantMsg],\n\t\t\t\ttoolCalls: [],\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\thooks?.onError?.({\n\t\t\t\t\tagent,\n\t\t\t\t\tinput,\n\t\t\t\t\terror: err,\n\t\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t}\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../src/agent-utils.ts","../src/adapters/anthropic.ts"],"names":["ALLOWED_PROTOCOLS","validateBaseURL","baseURL","url","err","createRunner","options","fetchFn","buildRequest","parseResponse","parseOutput","hooks","parse","text","agent","input","runOptions","startTime","messages","init","fetchInit","response","errBody","parsed","tokenUsage","assistantMessage","allMessages","durationMs","ANTHROPIC_PRICING","createAnthropicRunner","apiKey","model","maxTokens","timeoutMs","_input","m","res","data","inputTokens","outputTokens","createAnthropicStreamingRunner","callbacks","reader","decoder","buf","fullText","done","value","lines","line","event","parseErr","assistantMsg","totalTokens"],"mappings":"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","file":"anthropic.cjs","sourcesContent":["/**\n * Agent utilities — createRunner, estimateCost, state queries, URL validation.\n */\n\nimport type {\n AdapterHooks,\n AgentLike,\n AgentRunner,\n RunResult,\n RunOptions,\n Message,\n TokenUsage,\n AgentState,\n ApprovalState,\n} from \"./types.js\";\n\n// ============================================================================\n// State Query Helpers\n// ============================================================================\n\n/** Check if agent is currently running. */\nexport function isAgentRunning(state: AgentState): boolean {\n return state.status === \"running\";\n}\n\n/** Check if there are pending approvals. */\nexport function hasPendingApprovals(state: ApprovalState): boolean {\n return state.pending.length > 0;\n}\n\n// ============================================================================\n// Cost Estimation\n// ============================================================================\n\n/**\n * Get total cost estimate based on token usage.\n *\n * @param tokenUsage - Total token count\n * @param ratePerMillionTokens - Cost per million tokens (required, no default to avoid stale pricing)\n * @returns Estimated cost in dollars\n */\nexport function estimateCost(\n tokenUsage: number,\n ratePerMillionTokens: number\n): number {\n return (tokenUsage / 1_000_000) * ratePerMillionTokens;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\"]);\n\n/**\n * Validate that a baseURL uses http or https.\n * Throws immediately at adapter creation time (not at call time) to catch config errors early.\n */\nexport function validateBaseURL(baseURL: string): void {\n try {\n const url = new URL(baseURL);\n if (!ALLOWED_PROTOCOLS.has(url.protocol)) {\n throw new Error(\n `[Directive] Invalid baseURL protocol \"${url.protocol}\" – only http: and https: are allowed`,\n );\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"[Directive]\")) {\n throw err;\n }\n\n throw new Error(\n `[Directive] Invalid baseURL \"${baseURL}\" – must be a valid URL (e.g. \"https://api.openai.com/v1\")`,\n );\n }\n}\n\n// ============================================================================\n// createRunner Helper\n// ============================================================================\n\n/** Parsed response from an LLM provider */\nexport interface ParsedResponse {\n text: string;\n totalTokens: number;\n /** Input token count, when available from the provider */\n inputTokens?: number;\n /** Output token count, when available from the provider */\n outputTokens?: number;\n}\n\n/** Options for creating an AgentRunner from buildRequest/parseResponse */\nexport interface CreateRunnerOptions {\n fetch?: typeof globalThis.fetch;\n buildRequest: (\n agent: AgentLike,\n input: string,\n messages: Message[]\n ) => { url: string; init: RequestInit };\n parseResponse: (\n response: Response,\n messages: Message[]\n ) => Promise<ParsedResponse>;\n parseOutput?: <T>(text: string) => T;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner from buildRequest/parseResponse helpers.\n * Reduces ~50 lines of fetch boilerplate to ~20 lines of configuration.\n *\n * Supports lifecycle hooks for observability:\n * - `onBeforeCall` fires before each API request\n * - `onAfterCall` fires after a successful response (includes token breakdown)\n * - `onError` fires when the request fails\n *\n * @example\n * ```typescript\n * const runClaude = createRunner({\n * buildRequest: (agent, input) => ({\n * url: \"/api/claude\",\n * init: {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * model: agent.model ?? \"claude-haiku-4-5-20251001\",\n * system: agent.instructions ?? \"\",\n * messages: [{ role: \"user\", content: input }],\n * }),\n * },\n * }),\n * parseResponse: async (res) => {\n * const data = await res.json();\n * const inputTokens = data.usage?.input_tokens ?? 0;\n * const outputTokens = data.usage?.output_tokens ?? 0;\n * return {\n * text: data.content?.[0]?.text ?? \"\",\n * totalTokens: inputTokens + outputTokens,\n * inputTokens,\n * outputTokens,\n * };\n * },\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`LLM call: ${durationMs}ms, ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * ```\n */\nexport function createRunner(options: CreateRunnerOptions): AgentRunner {\n const {\n fetch: fetchFn = globalThis.fetch,\n buildRequest,\n parseResponse,\n parseOutput,\n hooks,\n } = options;\n\n const defaultParseOutput = <T>(text: string): T => {\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n };\n\n const parse = parseOutput ?? defaultParseOutput;\n\n return async <T = unknown>(\n agent: AgentLike,\n input: string,\n runOptions?: RunOptions\n ): Promise<RunResult<T>> => {\n const startTime = Date.now();\n hooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n const messages: Message[] = [{ role: \"user\", content: input }];\n\n try {\n const { url, init } = buildRequest(agent, input, messages);\n\n const fetchInit: RequestInit = runOptions?.signal\n ? { ...init, signal: runOptions.signal }\n : init;\n\n const response = await fetchFn(url, fetchInit);\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] AgentRunner request failed: ${response.status} ${response.statusText}${errBody ? ` – ${errBody.slice(0, 300)}` : \"\"}`,\n );\n }\n\n const parsed = await parseResponse(response, messages);\n const tokenUsage: TokenUsage = {\n inputTokens: parsed.inputTokens ?? 0,\n outputTokens: parsed.outputTokens ?? 0,\n };\n\n const assistantMessage: Message = { role: \"assistant\", content: parsed.text };\n const allMessages: Message[] = [...messages, assistantMessage];\n\n runOptions?.onMessage?.(assistantMessage);\n\n const durationMs = Date.now() - startTime;\n hooks?.onAfterCall?.({\n agent,\n input,\n output: parsed.text,\n totalTokens: parsed.totalTokens,\n tokenUsage,\n durationMs,\n timestamp: Date.now(),\n });\n\n return {\n output: parse<T>(parsed.text),\n messages: allMessages,\n toolCalls: [],\n totalTokens: parsed.totalTokens,\n tokenUsage,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n if (err instanceof Error) {\n hooks?.onError?.({\n agent,\n input,\n error: err,\n durationMs,\n timestamp: Date.now(),\n });\n }\n\n throw err;\n }\n };\n}\n","/**\n * @directive-run/ai/anthropic\n *\n * Anthropic adapter for Directive AI. Provides runners for the\n * Anthropic Messages API, including streaming support.\n *\n * @example\n * ```typescript\n * import { createAnthropicRunner, createAnthropicStreamingRunner } from '@directive-run/ai/anthropic';\n *\n * const runner = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { AdapterHooks, AgentRunner, Message, TokenUsage } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Anthropic model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { ANTHROPIC_PRICING } from '@directive-run/ai/anthropic';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://anthropic.com/pricing\n */\nexport const ANTHROPIC_PRICING: Record<string, { input: number; output: number }> = {\n\t\"claude-sonnet-4-5-20250929\": { input: 3, output: 15 },\n\t\"claude-haiku-3-5-20241022\": { input: 0.8, output: 4 },\n\t\"claude-opus-4-20250514\": { input: 15, output: 75 },\n};\n\n// ============================================================================\n// Anthropic Runner\n// ============================================================================\n\n/** Options for createAnthropicRunner */\nexport interface AnthropicRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** @default undefined */\n\ttimeoutMs?: number;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner for the Anthropic Messages API.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const runner = createAnthropicRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`${durationMs}ms – ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createAnthropicRunner(\n\toptions: AnthropicRunnerOptions,\n): AgentRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\ttimeoutMs,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn createRunner({\n\t\tfetch: fetchFn,\n\t\thooks,\n\t\tbuildRequest: (agent, _input, messages) => ({\n\t\t\turl: `${baseURL}/messages`,\n\t\t\tinit: {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: messages.map((m) => ({\n\t\t\t\t\t\trole: m.role,\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t})),\n\t\t\t\t}),\n\t\t\t\t...(timeoutMs != null ? { signal: AbortSignal.timeout(timeoutMs) } : {}),\n\t\t\t},\n\t\t}),\n\t\tparseResponse: async (res) => {\n\t\t\tconst data = await res.json();\n\t\t\tconst text = data.content?.[0]?.text ?? \"\";\n\t\t\tconst inputTokens = data.usage?.input_tokens ?? 0;\n\t\t\tconst outputTokens = data.usage?.output_tokens ?? 0;\n\n\t\t\treturn {\n\t\t\t\ttext,\n\t\t\t\ttotalTokens: inputTokens + outputTokens,\n\t\t\t\tinputTokens,\n\t\t\t\toutputTokens,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Anthropic Streaming Runner\n// ============================================================================\n\n/** Options for createAnthropicStreamingRunner */\nexport interface AnthropicStreamingRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create a StreamingCallbackRunner for the Anthropic Messages API with\n * server-sent events. Can be used standalone or paired with `createAnthropicRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createAnthropicStreamingRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createAnthropicStreamingRunner(\n\toptions: AnthropicStreamingRunnerOptions,\n): StreamingCallbackRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn async (agent, input, callbacks) => {\n\t\tconst startTime = Date.now();\n\t\thooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n\t\ttry {\n\t\t\tconst response = await fetchFn(`${baseURL}/messages`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: [{ role: \"user\", content: input }],\n\t\t\t\t\tstream: true,\n\t\t\t\t}),\n\t\t\t\tsignal: callbacks.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errBody = await response.text().catch(() => \"\");\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[Directive] Anthropic streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tthrow new Error(\"[Directive] No response body\");\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buf = \"\";\n\t\t\tlet fullText = \"\";\n\t\t\tlet inputTokens = 0;\n\t\t\tlet outputTokens = 0;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tbuf += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buf.split(\"\\n\");\n\t\t\t\t\tbuf = lines.pop() ?? \"\";\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.startsWith(\"data: \")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(data);\n\t\t\t\t\t\t\tif (event.type === \"error\") {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`[Directive] Anthropic stream error: ${event.error?.message ?? JSON.stringify(event.error)}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tevent.type === \"content_block_delta\" &&\n\t\t\t\t\t\t\t\tevent.delta?.type === \"text_delta\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tfullText += event.delta.text;\n\t\t\t\t\t\t\t\tcallbacks.onToken?.(event.delta.text);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_delta\" && event.usage) {\n\t\t\t\t\t\t\t\toutputTokens = event.usage.output_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_start\" && event.message?.usage) {\n\t\t\t\t\t\t\t\tinputTokens = event.message.usage.input_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (parseErr) {\n\t\t\t\t\t\t\tif (parseErr instanceof SyntaxError) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\ttypeof process !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\tprocess.env?.NODE_ENV === \"development\"\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t\t\"[Directive] Malformed SSE event from Anthropic:\",\n\t\t\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow parseErr;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.cancel().catch(() => {});\n\t\t\t}\n\n\t\t\tconst assistantMsg: Message = { role: \"assistant\", content: fullText };\n\t\t\tcallbacks.onMessage?.(assistantMsg);\n\n\t\t\tconst tokenUsage: TokenUsage = { inputTokens, outputTokens };\n\t\t\tconst totalTokens = inputTokens + outputTokens;\n\n\t\t\thooks?.onAfterCall?.({\n\t\t\t\tagent,\n\t\t\t\tinput,\n\t\t\t\toutput: fullText,\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\toutput: fullText,\n\t\t\t\tmessages: [{ role: \"user\" as const, content: input }, assistantMsg],\n\t\t\t\ttoolCalls: [],\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\thooks?.onError?.({\n\t\t\t\t\tagent,\n\t\t\t\t\tinput,\n\t\t\t\t\terror: err,\n\t\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t}\n\t};\n}\n"]}
@@ -1,7 +1,5 @@
1
- import { f as AdapterHooks, c as AgentRunner } from './types-Bbar7yKz.cjs';
2
- import { StreamingCallbackRunner } from './index.cjs';
1
+ import { a as AdapterHooks, b as AgentRunner, aX as StreamingCallbackRunner } from './types-Co4BzMiH.cjs';
3
2
  import '@directive-run/core';
4
- import '@directive-run/core/plugins';
5
3
 
6
4
  /**
7
5
  * @directive-run/ai/anthropic
@@ -65,7 +63,8 @@ interface AnthropicRunnerOptions {
65
63
  * },
66
64
  * },
67
65
  * });
68
- * const stack = createAgentStack({ runner, agents: { ... } });
66
+ * const orchestrator = createAgentOrchestrator({ runner });
67
+ * const result = await orchestrator.run(agent, input);
69
68
  * ```
70
69
  */
71
70
  declare function createAnthropicRunner(options: AnthropicRunnerOptions): AgentRunner;
@@ -91,11 +90,8 @@ interface AnthropicStreamingRunnerOptions {
91
90
  * const streamingRunner = createAnthropicStreamingRunner({
92
91
  * apiKey: process.env.ANTHROPIC_API_KEY!,
93
92
  * });
94
- * const stack = createAgentStack({
95
- * runner: createAnthropicRunner({ apiKey }),
96
- * streaming: { runner: streamingRunner },
97
- * agents: { ... },
98
- * });
93
+ * const streamRunner = createStreamingRunner(streamingRunner);
94
+ * const { stream, result } = streamRunner(agent, input);
99
95
  * ```
100
96
  */
101
97
  declare function createAnthropicStreamingRunner(options: AnthropicStreamingRunnerOptions): StreamingCallbackRunner;
@@ -1,7 +1,5 @@
1
- import { f as AdapterHooks, c as AgentRunner } from './types-Bbar7yKz.js';
2
- import { StreamingCallbackRunner } from './index.js';
1
+ import { a as AdapterHooks, b as AgentRunner, aX as StreamingCallbackRunner } from './types-Co4BzMiH.js';
3
2
  import '@directive-run/core';
4
- import '@directive-run/core/plugins';
5
3
 
6
4
  /**
7
5
  * @directive-run/ai/anthropic
@@ -65,7 +63,8 @@ interface AnthropicRunnerOptions {
65
63
  * },
66
64
  * },
67
65
  * });
68
- * const stack = createAgentStack({ runner, agents: { ... } });
66
+ * const orchestrator = createAgentOrchestrator({ runner });
67
+ * const result = await orchestrator.run(agent, input);
69
68
  * ```
70
69
  */
71
70
  declare function createAnthropicRunner(options: AnthropicRunnerOptions): AgentRunner;
@@ -91,11 +90,8 @@ interface AnthropicStreamingRunnerOptions {
91
90
  * const streamingRunner = createAnthropicStreamingRunner({
92
91
  * apiKey: process.env.ANTHROPIC_API_KEY!,
93
92
  * });
94
- * const stack = createAgentStack({
95
- * runner: createAnthropicRunner({ apiKey }),
96
- * streaming: { runner: streamingRunner },
97
- * agents: { ... },
98
- * });
93
+ * const streamRunner = createStreamingRunner(streamingRunner);
94
+ * const { stream, result } = streamRunner(agent, input);
99
95
  * ```
100
96
  */
101
97
  declare function createAnthropicStreamingRunner(options: AnthropicStreamingRunnerOptions): StreamingCallbackRunner;
package/dist/anthropic.js CHANGED
@@ -1,3 +1,3 @@
1
- var E=new Set(["http:","https:"]);function x(u){try{let o=new URL(u);if(!E.has(o.protocol))throw new Error(`[Directive] Invalid baseURL protocol "${o.protocol}" \u2013 only http: and https: are allowed`)}catch(o){throw o instanceof Error&&o.message.startsWith("[Directive]")?o:new Error(`[Directive] Invalid baseURL "${u}" \u2013 must be a valid URL (e.g. "https://api.openai.com/v1")`)}}function S(u){let{fetch:o=globalThis.fetch,buildRequest:T,parseResponse:y,parseOutput:m,hooks:g}=u,c=m??(e=>{try{return JSON.parse(e)}catch{return e}});return async(e,s,r)=>{let t=Date.now();g?.onBeforeCall?.({agent:e,input:s,timestamp:t});let i=[{role:"user",content:s}];try{let{url:d,init:l}=T(e,s,i),h=r?.signal?{...l,signal:r.signal}:l,p=await o(d,h);if(!p.ok){let b=await p.text().catch(()=>"");throw new Error(`[Directive] AgentRunner request failed: ${p.status} ${p.statusText}${b?` \u2013 ${b.slice(0,300)}`:""}`)}let a=await y(p,i),R={inputTokens:a.inputTokens??0,outputTokens:a.outputTokens??0},w={role:"assistant",content:a.text},A=[...i,w];r?.onMessage?.(w);let k=Date.now()-t;return g?.onAfterCall?.({agent:e,input:s,output:a.text,totalTokens:a.totalTokens,tokenUsage:R,durationMs:k,timestamp:Date.now()}),{output:c(a.text),messages:A,toolCalls:[],totalTokens:a.totalTokens,tokenUsage:R}}catch(d){let l=Date.now()-t;throw d instanceof Error&&g?.onError?.({agent:e,input:s,error:d,durationMs:l,timestamp:Date.now()}),d}}}var C={"claude-sonnet-4-5-20250929":{input:3,output:15},"claude-haiku-3-5-20241022":{input:.8,output:4},"claude-opus-4-20250514":{input:15,output:75}};function L(u){let{apiKey:o,model:T="claude-sonnet-4-5-20250929",maxTokens:y=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,timeoutMs:f,hooks:c}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicRunner: apiKey is empty. API calls will fail."),S({fetch:g,hooks:c,buildRequest:(e,s,r)=>({url:`${m}/messages`,init:{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:e.model??T,max_tokens:y,system:e.instructions??"",messages:r.map(t=>({role:t.role,content:t.content}))}),...f!=null?{signal:AbortSignal.timeout(f)}:{}}}),parseResponse:async e=>{let s=await e.json(),r=s.content?.[0]?.text??"",t=s.usage?.input_tokens??0,i=s.usage?.output_tokens??0;return {text:r,totalTokens:t+i,inputTokens:t,outputTokens:i}}})}function U(u){let{apiKey:o,model:T="claude-sonnet-4-5-20250929",maxTokens:y=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,hooks:f}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail."),async(c,e,s)=>{let r=Date.now();f?.onBeforeCall?.({agent:c,input:e,timestamp:r});try{let t=await g(`${m}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:c.model??T,max_tokens:y,system:c.instructions??"",messages:[{role:"user",content:e}],stream:!0}),signal:s.signal});if(!t.ok){let k=await t.text().catch(()=>"");throw new Error(`[Directive] Anthropic streaming error ${t.status}${k?` \u2013 ${k.slice(0,200)}`:""}`)}let i=t.body?.getReader();if(!i)throw new Error("[Directive] No response body");let d=new TextDecoder,l="",h="",p=0,a=0;try{for(;;){let{done:k,value:b}=await i.read();if(k)break;l+=d.decode(b,{stream:!0});let v=l.split(`
1
+ var E=new Set(["http:","https:"]);function x(u){try{let o=new URL(u);if(!E.has(o.protocol))throw new Error(`[Directive] Invalid baseURL protocol "${o.protocol}" \u2013 only http: and https: are allowed`)}catch(o){throw o instanceof Error&&o.message.startsWith("[Directive]")?o:new Error(`[Directive] Invalid baseURL "${u}" \u2013 must be a valid URL (e.g. "https://api.openai.com/v1")`)}}function S(u){let{fetch:o=globalThis.fetch,buildRequest:y,parseResponse:T,parseOutput:m,hooks:g}=u,c=m??(e=>{try{return JSON.parse(e)}catch{return e}});return async(e,s,r)=>{let t=Date.now();g?.onBeforeCall?.({agent:e,input:s,timestamp:t});let i=[{role:"user",content:s}];try{let{url:d,init:l}=y(e,s,i),h=r?.signal?{...l,signal:r.signal}:l,p=await o(d,h);if(!p.ok){let b=await p.text().catch(()=>"");throw new Error(`[Directive] AgentRunner request failed: ${p.status} ${p.statusText}${b?` \u2013 ${b.slice(0,300)}`:""}`)}let a=await T(p,i),R={inputTokens:a.inputTokens??0,outputTokens:a.outputTokens??0},w={role:"assistant",content:a.text},A=[...i,w];r?.onMessage?.(w);let k=Date.now()-t;return g?.onAfterCall?.({agent:e,input:s,output:a.text,totalTokens:a.totalTokens,tokenUsage:R,durationMs:k,timestamp:Date.now()}),{output:c(a.text),messages:A,toolCalls:[],totalTokens:a.totalTokens,tokenUsage:R}}catch(d){let l=Date.now()-t;throw d instanceof Error&&g?.onError?.({agent:e,input:s,error:d,durationMs:l,timestamp:Date.now()}),d}}}var C={"claude-sonnet-4-5-20250929":{input:3,output:15},"claude-haiku-3-5-20241022":{input:.8,output:4},"claude-opus-4-20250514":{input:15,output:75}};function L(u){let{apiKey:o,model:y="claude-sonnet-4-5-20250929",maxTokens:T=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,timeoutMs:f,hooks:c}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicRunner: apiKey is empty. API calls will fail."),S({fetch:g,hooks:c,buildRequest:(e,s,r)=>({url:`${m}/messages`,init:{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:e.model??y,max_tokens:T,system:e.instructions??"",messages:r.map(t=>({role:t.role,content:t.content}))}),...f!=null?{signal:AbortSignal.timeout(f)}:{}}}),parseResponse:async e=>{let s=await e.json(),r=s.content?.[0]?.text??"",t=s.usage?.input_tokens??0,i=s.usage?.output_tokens??0;return {text:r,totalTokens:t+i,inputTokens:t,outputTokens:i}}})}function U(u){let{apiKey:o,model:y="claude-sonnet-4-5-20250929",maxTokens:T=4096,baseURL:m="https://api.anthropic.com/v1",fetch:g=globalThis.fetch,hooks:f}=u;return x(m),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!o&&console.warn("[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail."),async(c,e,s)=>{let r=Date.now();f?.onBeforeCall?.({agent:c,input:e,timestamp:r});try{let t=await g(`${m}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:c.model??y,max_tokens:T,system:c.instructions??"",messages:[{role:"user",content:e}],stream:!0}),signal:s.signal});if(!t.ok){let k=await t.text().catch(()=>"");throw new Error(`[Directive] Anthropic streaming error ${t.status}${k?` \u2013 ${k.slice(0,200)}`:""}`)}let i=t.body?.getReader();if(!i)throw new Error("[Directive] No response body");let d=new TextDecoder,l="",h="",p=0,a=0;try{for(;;){let{done:k,value:b}=await i.read();if(k)break;l+=d.decode(b,{stream:!0});let v=l.split(`
2
2
  `);l=v.pop()??"";for(let D of v){if(!D.startsWith("data: "))continue;let O=D.slice(6).trim();try{let n=JSON.parse(O);if(n.type==="error")throw new Error(`[Directive] Anthropic stream error: ${n.error?.message??JSON.stringify(n.error)}`);n.type==="content_block_delta"&&n.delta?.type==="text_delta"&&(h+=n.delta.text,s.onToken?.(n.delta.text)),n.type==="message_delta"&&n.usage&&(a=n.usage.output_tokens??0),n.type==="message_start"&&n.message?.usage&&(p=n.message.usage.input_tokens??0);}catch(n){if(n instanceof SyntaxError)typeof process<"u"&&process.env?.NODE_ENV==="development"&&console.warn("[Directive] Malformed SSE event from Anthropic:",O);else throw n}}}}finally{i.cancel().catch(()=>{});}let R={role:"assistant",content:h};s.onMessage?.(R);let w={inputTokens:p,outputTokens:a},A=p+a;return f?.onAfterCall?.({agent:c,input:e,output:h,totalTokens:A,tokenUsage:w,durationMs:Date.now()-r,timestamp:Date.now()}),{output:h,messages:[{role:"user",content:e},R],toolCalls:[],totalTokens:A,tokenUsage:w}}catch(t){throw t instanceof Error&&f?.onError?.({agent:c,input:e,error:t,durationMs:Date.now()-r,timestamp:Date.now()}),t}}}export{C as ANTHROPIC_PRICING,L as createAnthropicRunner,U as createAnthropicStreamingRunner};//# sourceMappingURL=anthropic.js.map
3
3
  //# sourceMappingURL=anthropic.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/helpers.ts","../src/adapters/anthropic.ts"],"names":["ALLOWED_PROTOCOLS","validateBaseURL","baseURL","url","err","createRunner","options","fetchFn","buildRequest","parseResponse","parseOutput","hooks","parse","text","agent","input","runOptions","startTime","messages","init","fetchInit","response","errBody","parsed","tokenUsage","assistantMessage","allMessages","durationMs","ANTHROPIC_PRICING","createAnthropicRunner","apiKey","model","maxTokens","timeoutMs","_input","m","res","data","inputTokens","outputTokens","createAnthropicStreamingRunner","callbacks","reader","decoder","buf","fullText","done","value","lines","line","event","parseErr","assistantMsg","totalTokens"],"mappings":"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","file":"anthropic.js","sourcesContent":["/**\n * Helper functions for AI adapter — createRunner, estimateCost, state queries, validation.\n */\n\nimport type {\n AdapterHooks,\n AgentLike,\n AgentRunner,\n RunResult,\n RunOptions,\n Message,\n TokenUsage,\n AgentState,\n ApprovalState,\n} from \"./types.js\";\n\n// ============================================================================\n// State Query Helpers\n// ============================================================================\n\n/** Check if agent is currently running. */\nexport function isAgentRunning(state: AgentState): boolean {\n return state.status === \"running\";\n}\n\n/** Check if there are pending approvals. */\nexport function hasPendingApprovals(state: ApprovalState): boolean {\n return state.pending.length > 0;\n}\n\n// ============================================================================\n// Cost Estimation\n// ============================================================================\n\n/**\n * Get total cost estimate based on token usage.\n *\n * @param tokenUsage - Total token count\n * @param ratePerMillionTokens - Cost per million tokens (required, no default to avoid stale pricing)\n * @returns Estimated cost in dollars\n */\nexport function estimateCost(\n tokenUsage: number,\n ratePerMillionTokens: number\n): number {\n return (tokenUsage / 1_000_000) * ratePerMillionTokens;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\"]);\n\n/**\n * Validate that a baseURL uses http or https.\n * Throws immediately at adapter creation time (not at call time) to catch config errors early.\n */\nexport function validateBaseURL(baseURL: string): void {\n try {\n const url = new URL(baseURL);\n if (!ALLOWED_PROTOCOLS.has(url.protocol)) {\n throw new Error(\n `[Directive] Invalid baseURL protocol \"${url.protocol}\" – only http: and https: are allowed`,\n );\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"[Directive]\")) {\n throw err;\n }\n\n throw new Error(\n `[Directive] Invalid baseURL \"${baseURL}\" – must be a valid URL (e.g. \"https://api.openai.com/v1\")`,\n );\n }\n}\n\n// ============================================================================\n// createRunner Helper\n// ============================================================================\n\n/** Parsed response from an LLM provider */\nexport interface ParsedResponse {\n text: string;\n totalTokens: number;\n /** Input token count, when available from the provider */\n inputTokens?: number;\n /** Output token count, when available from the provider */\n outputTokens?: number;\n}\n\n/** Options for creating an AgentRunner from buildRequest/parseResponse */\nexport interface CreateRunnerOptions {\n fetch?: typeof globalThis.fetch;\n buildRequest: (\n agent: AgentLike,\n input: string,\n messages: Message[]\n ) => { url: string; init: RequestInit };\n parseResponse: (\n response: Response,\n messages: Message[]\n ) => Promise<ParsedResponse>;\n parseOutput?: <T>(text: string) => T;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner from buildRequest/parseResponse helpers.\n * Reduces ~50 lines of fetch boilerplate to ~20 lines of configuration.\n *\n * Supports lifecycle hooks for observability:\n * - `onBeforeCall` fires before each API request\n * - `onAfterCall` fires after a successful response (includes token breakdown)\n * - `onError` fires when the request fails\n *\n * @example\n * ```typescript\n * const runClaude = createRunner({\n * buildRequest: (agent, input) => ({\n * url: \"/api/claude\",\n * init: {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * model: agent.model ?? \"claude-haiku-4-5-20251001\",\n * system: agent.instructions ?? \"\",\n * messages: [{ role: \"user\", content: input }],\n * }),\n * },\n * }),\n * parseResponse: async (res) => {\n * const data = await res.json();\n * const inputTokens = data.usage?.input_tokens ?? 0;\n * const outputTokens = data.usage?.output_tokens ?? 0;\n * return {\n * text: data.content?.[0]?.text ?? \"\",\n * totalTokens: inputTokens + outputTokens,\n * inputTokens,\n * outputTokens,\n * };\n * },\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`LLM call: ${durationMs}ms, ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * ```\n */\nexport function createRunner(options: CreateRunnerOptions): AgentRunner {\n const {\n fetch: fetchFn = globalThis.fetch,\n buildRequest,\n parseResponse,\n parseOutput,\n hooks,\n } = options;\n\n const defaultParseOutput = <T>(text: string): T => {\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n };\n\n const parse = parseOutput ?? defaultParseOutput;\n\n return async <T = unknown>(\n agent: AgentLike,\n input: string,\n runOptions?: RunOptions\n ): Promise<RunResult<T>> => {\n const startTime = Date.now();\n hooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n const messages: Message[] = [{ role: \"user\", content: input }];\n\n try {\n const { url, init } = buildRequest(agent, input, messages);\n\n const fetchInit: RequestInit = runOptions?.signal\n ? { ...init, signal: runOptions.signal }\n : init;\n\n const response = await fetchFn(url, fetchInit);\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] AgentRunner request failed: ${response.status} ${response.statusText}${errBody ? ` – ${errBody.slice(0, 300)}` : \"\"}`,\n );\n }\n\n const parsed = await parseResponse(response, messages);\n const tokenUsage: TokenUsage = {\n inputTokens: parsed.inputTokens ?? 0,\n outputTokens: parsed.outputTokens ?? 0,\n };\n\n const assistantMessage: Message = { role: \"assistant\", content: parsed.text };\n const allMessages: Message[] = [...messages, assistantMessage];\n\n runOptions?.onMessage?.(assistantMessage);\n\n const durationMs = Date.now() - startTime;\n hooks?.onAfterCall?.({\n agent,\n input,\n output: parsed.text,\n totalTokens: parsed.totalTokens,\n tokenUsage,\n durationMs,\n timestamp: Date.now(),\n });\n\n return {\n output: parse<T>(parsed.text),\n messages: allMessages,\n toolCalls: [],\n totalTokens: parsed.totalTokens,\n tokenUsage,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n if (err instanceof Error) {\n hooks?.onError?.({\n agent,\n input,\n error: err,\n durationMs,\n timestamp: Date.now(),\n });\n }\n\n throw err;\n }\n };\n}\n","/**\n * @directive-run/ai/anthropic\n *\n * Anthropic adapter for Directive AI. Provides runners for the\n * Anthropic Messages API, including streaming support.\n *\n * @example\n * ```typescript\n * import { createAnthropicRunner, createAnthropicStreamingRunner } from '@directive-run/ai/anthropic';\n *\n * const runner = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../helpers.js\";\nimport type { AdapterHooks, AgentRunner, Message, TokenUsage } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../stack.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Anthropic model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { ANTHROPIC_PRICING } from '@directive-run/ai/anthropic';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://anthropic.com/pricing\n */\nexport const ANTHROPIC_PRICING: Record<string, { input: number; output: number }> = {\n\t\"claude-sonnet-4-5-20250929\": { input: 3, output: 15 },\n\t\"claude-haiku-3-5-20241022\": { input: 0.8, output: 4 },\n\t\"claude-opus-4-20250514\": { input: 15, output: 75 },\n};\n\n// ============================================================================\n// Anthropic Runner\n// ============================================================================\n\n/** Options for createAnthropicRunner */\nexport interface AnthropicRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** @default undefined */\n\ttimeoutMs?: number;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner for the Anthropic Messages API.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const runner = createAnthropicRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`${durationMs}ms – ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * const stack = createAgentStack({ runner, agents: { ... } });\n * ```\n */\nexport function createAnthropicRunner(\n\toptions: AnthropicRunnerOptions,\n): AgentRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\ttimeoutMs,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn createRunner({\n\t\tfetch: fetchFn,\n\t\thooks,\n\t\tbuildRequest: (agent, _input, messages) => ({\n\t\t\turl: `${baseURL}/messages`,\n\t\t\tinit: {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: messages.map((m) => ({\n\t\t\t\t\t\trole: m.role,\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t})),\n\t\t\t\t}),\n\t\t\t\t...(timeoutMs != null ? { signal: AbortSignal.timeout(timeoutMs) } : {}),\n\t\t\t},\n\t\t}),\n\t\tparseResponse: async (res) => {\n\t\t\tconst data = await res.json();\n\t\t\tconst text = data.content?.[0]?.text ?? \"\";\n\t\t\tconst inputTokens = data.usage?.input_tokens ?? 0;\n\t\t\tconst outputTokens = data.usage?.output_tokens ?? 0;\n\n\t\t\treturn {\n\t\t\t\ttext,\n\t\t\t\ttotalTokens: inputTokens + outputTokens,\n\t\t\t\tinputTokens,\n\t\t\t\toutputTokens,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Anthropic Streaming Runner\n// ============================================================================\n\n/** Options for createAnthropicStreamingRunner */\nexport interface AnthropicStreamingRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create a StreamingCallbackRunner for the Anthropic Messages API with\n * server-sent events. Can be used standalone or paired with `createAnthropicRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createAnthropicStreamingRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * });\n * const stack = createAgentStack({\n * runner: createAnthropicRunner({ apiKey }),\n * streaming: { runner: streamingRunner },\n * agents: { ... },\n * });\n * ```\n */\nexport function createAnthropicStreamingRunner(\n\toptions: AnthropicStreamingRunnerOptions,\n): StreamingCallbackRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn async (agent, input, callbacks) => {\n\t\tconst startTime = Date.now();\n\t\thooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n\t\ttry {\n\t\t\tconst response = await fetchFn(`${baseURL}/messages`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: [{ role: \"user\", content: input }],\n\t\t\t\t\tstream: true,\n\t\t\t\t}),\n\t\t\t\tsignal: callbacks.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errBody = await response.text().catch(() => \"\");\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[Directive] Anthropic streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tthrow new Error(\"[Directive] No response body\");\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buf = \"\";\n\t\t\tlet fullText = \"\";\n\t\t\tlet inputTokens = 0;\n\t\t\tlet outputTokens = 0;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tbuf += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buf.split(\"\\n\");\n\t\t\t\t\tbuf = lines.pop() ?? \"\";\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.startsWith(\"data: \")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(data);\n\t\t\t\t\t\t\tif (event.type === \"error\") {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`[Directive] Anthropic stream error: ${event.error?.message ?? JSON.stringify(event.error)}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tevent.type === \"content_block_delta\" &&\n\t\t\t\t\t\t\t\tevent.delta?.type === \"text_delta\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tfullText += event.delta.text;\n\t\t\t\t\t\t\t\tcallbacks.onToken?.(event.delta.text);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_delta\" && event.usage) {\n\t\t\t\t\t\t\t\toutputTokens = event.usage.output_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_start\" && event.message?.usage) {\n\t\t\t\t\t\t\t\tinputTokens = event.message.usage.input_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (parseErr) {\n\t\t\t\t\t\t\tif (parseErr instanceof SyntaxError) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\ttypeof process !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\tprocess.env?.NODE_ENV === \"development\"\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t\t\"[Directive] Malformed SSE event from Anthropic:\",\n\t\t\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow parseErr;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.cancel().catch(() => {});\n\t\t\t}\n\n\t\t\tconst assistantMsg: Message = { role: \"assistant\", content: fullText };\n\t\t\tcallbacks.onMessage?.(assistantMsg);\n\n\t\t\tconst tokenUsage: TokenUsage = { inputTokens, outputTokens };\n\t\t\tconst totalTokens = inputTokens + outputTokens;\n\n\t\t\thooks?.onAfterCall?.({\n\t\t\t\tagent,\n\t\t\t\tinput,\n\t\t\t\toutput: fullText,\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\toutput: fullText,\n\t\t\t\tmessages: [{ role: \"user\" as const, content: input }, assistantMsg],\n\t\t\t\ttoolCalls: [],\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\thooks?.onError?.({\n\t\t\t\t\tagent,\n\t\t\t\t\tinput,\n\t\t\t\t\terror: err,\n\t\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t}\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../src/agent-utils.ts","../src/adapters/anthropic.ts"],"names":["ALLOWED_PROTOCOLS","validateBaseURL","baseURL","url","err","createRunner","options","fetchFn","buildRequest","parseResponse","parseOutput","hooks","parse","text","agent","input","runOptions","startTime","messages","init","fetchInit","response","errBody","parsed","tokenUsage","assistantMessage","allMessages","durationMs","ANTHROPIC_PRICING","createAnthropicRunner","apiKey","model","maxTokens","timeoutMs","_input","m","res","data","inputTokens","outputTokens","createAnthropicStreamingRunner","callbacks","reader","decoder","buf","fullText","done","value","lines","line","event","parseErr","assistantMsg","totalTokens"],"mappings":"AAoDA,IAAMA,EAAoB,IAAI,GAAA,CAAI,CAAC,OAAA,CAAS,QAAQ,CAAC,CAAA,CAM9C,SAASC,CAAAA,CAAgBC,EAAuB,CACrD,GAAI,CACF,IAAMC,CAAAA,CAAM,IAAI,GAAA,CAAID,CAAO,CAAA,CAC3B,GAAI,CAACF,CAAAA,CAAkB,GAAA,CAAIG,EAAI,QAAQ,CAAA,CACrC,MAAM,IAAI,KAAA,CACR,CAAA,sCAAA,EAAyCA,CAAAA,CAAI,QAAQ,CAAA,0CAAA,CACvD,CAEJ,OAASC,CAAAA,CAAK,CACZ,MAAIA,CAAAA,YAAe,KAAA,EAASA,CAAAA,CAAI,OAAA,CAAQ,WAAW,aAAa,CAAA,CACxDA,EAGF,IAAI,KAAA,CACR,gCAAgCF,CAAO,CAAA,+DAAA,CACzC,CACF,CACF,CA4EO,SAASG,CAAAA,CAAaC,EAA2C,CACtE,GAAM,CACJ,KAAA,CAAOC,CAAAA,CAAU,UAAA,CAAW,KAAA,CAC5B,aAAAC,CAAAA,CACA,aAAA,CAAAC,EACA,WAAA,CAAAC,CAAAA,CACA,MAAAC,CACF,CAAA,CAAIL,CAAAA,CAUEM,CAAAA,CAAQF,IARiBG,CAAAA,EAAoB,CACjD,GAAI,CACF,OAAO,KAAK,KAAA,CAAMA,CAAI,CACxB,CAAA,KAAQ,CACN,OAAOA,CACT,CACF,CAAA,CAAA,CAIA,aACEC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,GAC0B,CAC1B,IAAMC,CAAAA,CAAY,IAAA,CAAK,KAAI,CAC3BN,CAAAA,EAAO,eAAe,CAAE,KAAA,CAAAG,CAAAA,CAAO,KAAA,CAAAC,EAAO,SAAA,CAAWE,CAAU,CAAC,CAAA,CAE5D,IAAMC,EAAsB,CAAC,CAAE,IAAA,CAAM,MAAA,CAAQ,QAASH,CAAM,CAAC,EAE7D,GAAI,CACF,GAAM,CAAE,GAAA,CAAAZ,CAAAA,CAAK,IAAA,CAAAgB,CAAK,CAAA,CAAIX,CAAAA,CAAaM,EAAOC,CAAAA,CAAOG,CAAQ,EAEnDE,CAAAA,CAAyBJ,CAAAA,EAAY,MAAA,CACvC,CAAE,GAAGG,CAAAA,CAAM,MAAA,CAAQH,EAAW,MAAO,CAAA,CACrCG,EAEEE,CAAAA,CAAW,MAAMd,CAAAA,CAAQJ,CAAAA,CAAKiB,CAAS,CAAA,CAE7C,GAAI,CAACC,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMC,CAAAA,CAAU,MAAMD,CAAAA,CAAS,MAAK,CAAE,KAAA,CAAM,IAAM,EAAE,CAAA,CAEpD,MAAM,IAAI,KAAA,CACR,CAAA,wCAAA,EAA2CA,CAAAA,CAAS,MAAM,CAAA,CAAA,EAAIA,CAAAA,CAAS,UAAU,CAAA,EAAGC,CAAAA,CAAU,WAAMA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,GAAG,CAAC,CAAA,CAAA,CAAK,EAAE,EAClI,CACF,CAEA,IAAMC,CAAAA,CAAS,MAAMd,CAAAA,CAAcY,CAAAA,CAAUH,CAAQ,CAAA,CAC/CM,CAAAA,CAAyB,CAC7B,WAAA,CAAaD,CAAAA,CAAO,aAAe,CAAA,CACnC,YAAA,CAAcA,CAAAA,CAAO,YAAA,EAAgB,CACvC,CAAA,CAEME,CAAAA,CAA4B,CAAE,IAAA,CAAM,WAAA,CAAa,QAASF,CAAAA,CAAO,IAAK,CAAA,CACtEG,CAAAA,CAAyB,CAAC,GAAGR,CAAAA,CAAUO,CAAgB,CAAA,CAE7DT,CAAAA,EAAY,YAAYS,CAAgB,CAAA,CAExC,IAAME,CAAAA,CAAa,KAAK,GAAA,EAAI,CAAIV,EAChC,OAAAN,CAAAA,EAAO,cAAc,CACnB,KAAA,CAAAG,CAAAA,CACA,KAAA,CAAAC,EACA,MAAA,CAAQQ,CAAAA,CAAO,KACf,WAAA,CAAaA,CAAAA,CAAO,YACpB,UAAA,CAAAC,CAAAA,CACA,UAAA,CAAAG,CAAAA,CACA,UAAW,IAAA,CAAK,GAAA,EAClB,CAAC,CAAA,CAEM,CACL,MAAA,CAAQf,CAAAA,CAASW,CAAAA,CAAO,IAAI,EAC5B,QAAA,CAAUG,CAAAA,CACV,UAAW,EAAC,CACZ,YAAaH,CAAAA,CAAO,WAAA,CACpB,UAAA,CAAAC,CACF,CACF,CAAA,MAASpB,CAAAA,CAAK,CACZ,IAAMuB,CAAAA,CAAa,KAAK,GAAA,EAAI,CAAIV,CAAAA,CAChC,MAAIb,aAAe,KAAA,EACjBO,CAAAA,EAAO,UAAU,CACf,KAAA,CAAAG,EACA,KAAA,CAAAC,CAAAA,CACA,KAAA,CAAOX,CAAAA,CACP,WAAAuB,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAClB,CAAC,CAAA,CAGGvB,CACR,CACF,CACF,CC3MO,IAAMwB,CAAAA,CAAuE,CACnF,4BAAA,CAA8B,CAAE,MAAO,CAAA,CAAG,MAAA,CAAQ,EAAG,CAAA,CACrD,4BAA6B,CAAE,KAAA,CAAO,GAAK,MAAA,CAAQ,CAAE,EACrD,wBAAA,CAA0B,CAAE,KAAA,CAAO,EAAA,CAAI,OAAQ,EAAG,CACnD,EAuCO,SAASC,CAAAA,CACfvB,EACc,CACd,GAAM,CACL,MAAA,CAAAwB,EACA,KAAA,CAAAC,CAAAA,CAAQ,6BACR,SAAA,CAAAC,CAAAA,CAAY,KACZ,OAAA,CAAA9B,CAAAA,CAAU,8BAAA,CACV,KAAA,CAAOK,EAAU,UAAA,CAAW,KAAA,CAC5B,SAAA,CAAA0B,CAAAA,CACA,MAAAtB,CACD,CAAA,CAAIL,CAAAA,CAEJ,OAAAL,EAAgBC,CAAO,CAAA,CAEnB,OAAO,OAAA,CAAY,GAAA,EAAe,QAAQ,GAAA,EAAK,QAAA,GAAa,YAAA,EAAgB,CAAC4B,GAChF,OAAA,CAAQ,IAAA,CAAK,0EAA0E,CAAA,CAGjFzB,CAAAA,CAAa,CACnB,KAAA,CAAOE,CAAAA,CACP,KAAA,CAAAI,CAAAA,CACA,aAAc,CAACG,CAAAA,CAAOoB,EAAQhB,CAAAA,IAAc,CAC3C,IAAK,CAAA,EAAGhB,CAAO,CAAA,SAAA,CAAA,CACf,IAAA,CAAM,CACL,MAAA,CAAQ,MAAA,CACR,QAAS,CACR,cAAA,CAAgB,mBAChB,WAAA,CAAa4B,CAAAA,CACb,mBAAA,CAAqB,YACtB,EACA,IAAA,CAAM,IAAA,CAAK,UAAU,CACpB,KAAA,CAAOhB,EAAM,KAAA,EAASiB,CAAAA,CACtB,UAAA,CAAYC,CAAAA,CACZ,OAAQlB,CAAAA,CAAM,YAAA,EAAgB,GAC9B,QAAA,CAAUI,CAAAA,CAAS,IAAKiB,CAAAA,GAAO,CAC9B,IAAA,CAAMA,CAAAA,CAAE,KACR,OAAA,CAASA,CAAAA,CAAE,OACZ,CAAA,CAAE,CACH,CAAC,CAAA,CACD,GAAIF,CAAAA,EAAa,IAAA,CAAO,CAAE,MAAA,CAAQ,WAAA,CAAY,QAAQA,CAAS,CAAE,EAAI,EACtE,CACD,CAAA,CAAA,CACA,cAAe,MAAOG,CAAAA,EAAQ,CAC7B,IAAMC,CAAAA,CAAO,MAAMD,CAAAA,CAAI,IAAA,EAAK,CACtBvB,CAAAA,CAAOwB,EAAK,OAAA,GAAU,CAAC,GAAG,IAAA,EAAQ,EAAA,CAClCC,EAAcD,CAAAA,CAAK,KAAA,EAAO,YAAA,EAAgB,CAAA,CAC1CE,EAAeF,CAAAA,CAAK,KAAA,EAAO,eAAiB,CAAA,CAElD,OAAO,CACN,IAAA,CAAAxB,CAAAA,CACA,WAAA,CAAayB,CAAAA,CAAcC,EAC3B,WAAA,CAAAD,CAAAA,CACA,aAAAC,CACD,CACD,CACD,CAAC,CACF,CAiCO,SAASC,EACflC,CAAAA,CAC0B,CAC1B,GAAM,CACL,MAAA,CAAAwB,EACA,KAAA,CAAAC,CAAAA,CAAQ,4BAAA,CACR,SAAA,CAAAC,EAAY,IAAA,CACZ,OAAA,CAAA9B,EAAU,8BAAA,CACV,KAAA,CAAOK,EAAU,UAAA,CAAW,KAAA,CAC5B,KAAA,CAAAI,CACD,EAAIL,CAAAA,CAEJ,OAAAL,EAAgBC,CAAO,CAAA,CAEnB,OAAO,OAAA,CAAY,GAAA,EAAe,OAAA,CAAQ,GAAA,EAAK,WAAa,YAAA,EAAgB,CAAC4B,GAChF,OAAA,CAAQ,IAAA,CAAK,mFAAmF,CAAA,CAG1F,MAAOhB,CAAAA,CAAOC,CAAAA,CAAO0B,IAAc,CACzC,IAAMxB,EAAY,IAAA,CAAK,GAAA,GACvBN,CAAAA,EAAO,YAAA,GAAe,CAAE,KAAA,CAAAG,EAAO,KAAA,CAAAC,CAAAA,CAAO,UAAWE,CAAU,CAAC,EAE5D,GAAI,CACH,IAAMI,CAAAA,CAAW,MAAMd,CAAAA,CAAQ,CAAA,EAAGL,CAAO,CAAA,SAAA,CAAA,CAAa,CACrD,OAAQ,MAAA,CACR,OAAA,CAAS,CACR,cAAA,CAAgB,mBAChB,WAAA,CAAa4B,CAAAA,CACb,oBAAqB,YACtB,CAAA,CACA,KAAM,IAAA,CAAK,SAAA,CAAU,CACpB,KAAA,CAAOhB,EAAM,KAAA,EAASiB,CAAAA,CACtB,WAAYC,CAAAA,CACZ,MAAA,CAAQlB,EAAM,YAAA,EAAgB,EAAA,CAC9B,QAAA,CAAU,CAAC,CAAE,IAAA,CAAM,MAAA,CAAQ,QAASC,CAAM,CAAC,EAC3C,MAAA,CAAQ,CAAA,CACT,CAAC,CAAA,CACD,OAAQ0B,CAAAA,CAAU,MACnB,CAAC,CAAA,CAED,GAAI,CAACpB,CAAAA,CAAS,EAAA,CAAI,CACjB,IAAMC,EAAU,MAAMD,CAAAA,CAAS,MAAK,CAAE,KAAA,CAAM,IAAM,EAAE,CAAA,CAEpD,MAAM,IAAI,MACT,CAAA,sCAAA,EAAyCA,CAAAA,CAAS,MAAM,CAAA,EAAGC,CAAAA,CAAU,WAAMA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,GAAG,CAAC,CAAA,CAAA,CAAK,EAAE,EACxG,CACD,CAEA,IAAMoB,CAAAA,CAASrB,CAAAA,CAAS,IAAA,EAAM,SAAA,GAC9B,GAAI,CAACqB,EACJ,MAAM,IAAI,MAAM,8BAA8B,CAAA,CAG/C,IAAMC,CAAAA,CAAU,IAAI,WAAA,CAChBC,CAAAA,CAAM,GACNC,CAAAA,CAAW,EAAA,CACXP,EAAc,CAAA,CACdC,CAAAA,CAAe,CAAA,CAEnB,GAAI,CACH,OAAa,CACZ,GAAM,CAAE,IAAA,CAAAO,EAAM,KAAA,CAAAC,CAAM,CAAA,CAAI,MAAML,EAAO,IAAA,EAAK,CAC1C,GAAII,CAAAA,CACH,MAGDF,GAAOD,CAAAA,CAAQ,MAAA,CAAOI,CAAAA,CAAO,CAAE,OAAQ,CAAA,CAAK,CAAC,EAC7C,IAAMC,CAAAA,CAAQJ,EAAI,KAAA,CAAM;AAAA,CAAI,CAAA,CAC5BA,CAAAA,CAAMI,CAAAA,CAAM,GAAA,EAAI,EAAK,GAErB,IAAA,IAAWC,CAAAA,IAAQD,CAAAA,CAAO,CACzB,GAAI,CAACC,EAAK,UAAA,CAAW,QAAQ,CAAA,CAC5B,SAED,IAAMZ,CAAAA,CAAOY,EAAK,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,EAAK,CAEhC,GAAI,CACH,IAAMC,CAAAA,CAAQ,IAAA,CAAK,KAAA,CAAMb,CAAI,CAAA,CAC7B,GAAIa,CAAAA,CAAM,IAAA,GAAS,OAAA,CAClB,MAAM,IAAI,KAAA,CACT,uCAAuCA,CAAAA,CAAM,KAAA,EAAO,OAAA,EAAW,IAAA,CAAK,SAAA,CAAUA,CAAAA,CAAM,KAAK,CAAC,CAAA,CAC3F,CAAA,CAGAA,CAAAA,CAAM,IAAA,GAAS,qBAAA,EACfA,EAAM,KAAA,EAAO,IAAA,GAAS,YAAA,GAEtBL,CAAAA,EAAYK,CAAAA,CAAM,KAAA,CAAM,KACxBT,CAAAA,CAAU,OAAA,GAAUS,CAAAA,CAAM,KAAA,CAAM,IAAI,CAAA,CAAA,CAEjCA,EAAM,IAAA,GAAS,eAAA,EAAmBA,CAAAA,CAAM,KAAA,GAC3CX,CAAAA,CAAeW,CAAAA,CAAM,MAAM,aAAA,EAAiB,CAAA,CAAA,CAEzCA,CAAAA,CAAM,IAAA,GAAS,eAAA,EAAmBA,CAAAA,CAAM,SAAS,KAAA,GACpDZ,CAAAA,CAAcY,CAAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,YAAA,EAAgB,GAEpD,CAAA,MAASC,CAAAA,CAAU,CAClB,GAAIA,CAAAA,YAAoB,WAAA,CAEtB,OAAO,OAAA,CAAY,GAAA,EACnB,OAAA,CAAQ,GAAA,EAAK,QAAA,GAAa,aAAA,EAE1B,QAAQ,IAAA,CACP,iDAAA,CACAd,CACD,CAAA,CAAA,KAGD,MAAMc,CAER,CACD,CACD,CACD,CAAA,OAAE,CACDT,CAAAA,CAAO,MAAA,GAAS,KAAA,CAAM,IAAM,CAAC,CAAC,EAC/B,CAEA,IAAMU,CAAAA,CAAwB,CAAE,IAAA,CAAM,WAAA,CAAa,OAAA,CAASP,CAAS,EACrEJ,CAAAA,CAAU,SAAA,GAAYW,CAAY,CAAA,CAElC,IAAM5B,CAAAA,CAAyB,CAAE,WAAA,CAAAc,CAAAA,CAAa,YAAA,CAAAC,CAAa,CAAA,CACrDc,CAAAA,CAAcf,EAAcC,CAAAA,CAElC,OAAA5B,CAAAA,EAAO,WAAA,GAAc,CACpB,KAAA,CAAAG,EACA,KAAA,CAAAC,CAAAA,CACA,MAAA,CAAQ8B,CAAAA,CACR,WAAA,CAAAQ,CAAAA,CACA,WAAA7B,CAAAA,CACA,UAAA,CAAY,IAAA,CAAK,GAAA,EAAI,CAAIP,CAAAA,CACzB,UAAW,IAAA,CAAK,GAAA,EACjB,CAAC,CAAA,CAEM,CACN,OAAQ4B,CAAAA,CACR,QAAA,CAAU,CAAC,CAAE,IAAA,CAAM,MAAA,CAAiB,QAAS9B,CAAM,CAAA,CAAGqC,CAAY,CAAA,CAClE,SAAA,CAAW,GACX,WAAA,CAAAC,CAAAA,CACA,UAAA,CAAA7B,CACD,CACD,CAAA,MAASpB,EAAK,CACb,MAAIA,CAAAA,YAAe,KAAA,EAClBO,CAAAA,EAAO,OAAA,GAAU,CAChB,KAAA,CAAAG,CAAAA,CACA,KAAA,CAAAC,CAAAA,CACA,KAAA,CAAOX,CAAAA,CACP,WAAY,IAAA,CAAK,GAAA,EAAI,CAAIa,CAAAA,CACzB,SAAA,CAAW,IAAA,CAAK,GAAA,EACjB,CAAC,CAAA,CAGIb,CACP,CACD,CACD","file":"anthropic.js","sourcesContent":["/**\n * Agent utilities — createRunner, estimateCost, state queries, URL validation.\n */\n\nimport type {\n AdapterHooks,\n AgentLike,\n AgentRunner,\n RunResult,\n RunOptions,\n Message,\n TokenUsage,\n AgentState,\n ApprovalState,\n} from \"./types.js\";\n\n// ============================================================================\n// State Query Helpers\n// ============================================================================\n\n/** Check if agent is currently running. */\nexport function isAgentRunning(state: AgentState): boolean {\n return state.status === \"running\";\n}\n\n/** Check if there are pending approvals. */\nexport function hasPendingApprovals(state: ApprovalState): boolean {\n return state.pending.length > 0;\n}\n\n// ============================================================================\n// Cost Estimation\n// ============================================================================\n\n/**\n * Get total cost estimate based on token usage.\n *\n * @param tokenUsage - Total token count\n * @param ratePerMillionTokens - Cost per million tokens (required, no default to avoid stale pricing)\n * @returns Estimated cost in dollars\n */\nexport function estimateCost(\n tokenUsage: number,\n ratePerMillionTokens: number\n): number {\n return (tokenUsage / 1_000_000) * ratePerMillionTokens;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\"]);\n\n/**\n * Validate that a baseURL uses http or https.\n * Throws immediately at adapter creation time (not at call time) to catch config errors early.\n */\nexport function validateBaseURL(baseURL: string): void {\n try {\n const url = new URL(baseURL);\n if (!ALLOWED_PROTOCOLS.has(url.protocol)) {\n throw new Error(\n `[Directive] Invalid baseURL protocol \"${url.protocol}\" – only http: and https: are allowed`,\n );\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"[Directive]\")) {\n throw err;\n }\n\n throw new Error(\n `[Directive] Invalid baseURL \"${baseURL}\" – must be a valid URL (e.g. \"https://api.openai.com/v1\")`,\n );\n }\n}\n\n// ============================================================================\n// createRunner Helper\n// ============================================================================\n\n/** Parsed response from an LLM provider */\nexport interface ParsedResponse {\n text: string;\n totalTokens: number;\n /** Input token count, when available from the provider */\n inputTokens?: number;\n /** Output token count, when available from the provider */\n outputTokens?: number;\n}\n\n/** Options for creating an AgentRunner from buildRequest/parseResponse */\nexport interface CreateRunnerOptions {\n fetch?: typeof globalThis.fetch;\n buildRequest: (\n agent: AgentLike,\n input: string,\n messages: Message[]\n ) => { url: string; init: RequestInit };\n parseResponse: (\n response: Response,\n messages: Message[]\n ) => Promise<ParsedResponse>;\n parseOutput?: <T>(text: string) => T;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner from buildRequest/parseResponse helpers.\n * Reduces ~50 lines of fetch boilerplate to ~20 lines of configuration.\n *\n * Supports lifecycle hooks for observability:\n * - `onBeforeCall` fires before each API request\n * - `onAfterCall` fires after a successful response (includes token breakdown)\n * - `onError` fires when the request fails\n *\n * @example\n * ```typescript\n * const runClaude = createRunner({\n * buildRequest: (agent, input) => ({\n * url: \"/api/claude\",\n * init: {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * model: agent.model ?? \"claude-haiku-4-5-20251001\",\n * system: agent.instructions ?? \"\",\n * messages: [{ role: \"user\", content: input }],\n * }),\n * },\n * }),\n * parseResponse: async (res) => {\n * const data = await res.json();\n * const inputTokens = data.usage?.input_tokens ?? 0;\n * const outputTokens = data.usage?.output_tokens ?? 0;\n * return {\n * text: data.content?.[0]?.text ?? \"\",\n * totalTokens: inputTokens + outputTokens,\n * inputTokens,\n * outputTokens,\n * };\n * },\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`LLM call: ${durationMs}ms, ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * ```\n */\nexport function createRunner(options: CreateRunnerOptions): AgentRunner {\n const {\n fetch: fetchFn = globalThis.fetch,\n buildRequest,\n parseResponse,\n parseOutput,\n hooks,\n } = options;\n\n const defaultParseOutput = <T>(text: string): T => {\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n };\n\n const parse = parseOutput ?? defaultParseOutput;\n\n return async <T = unknown>(\n agent: AgentLike,\n input: string,\n runOptions?: RunOptions\n ): Promise<RunResult<T>> => {\n const startTime = Date.now();\n hooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n const messages: Message[] = [{ role: \"user\", content: input }];\n\n try {\n const { url, init } = buildRequest(agent, input, messages);\n\n const fetchInit: RequestInit = runOptions?.signal\n ? { ...init, signal: runOptions.signal }\n : init;\n\n const response = await fetchFn(url, fetchInit);\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] AgentRunner request failed: ${response.status} ${response.statusText}${errBody ? ` – ${errBody.slice(0, 300)}` : \"\"}`,\n );\n }\n\n const parsed = await parseResponse(response, messages);\n const tokenUsage: TokenUsage = {\n inputTokens: parsed.inputTokens ?? 0,\n outputTokens: parsed.outputTokens ?? 0,\n };\n\n const assistantMessage: Message = { role: \"assistant\", content: parsed.text };\n const allMessages: Message[] = [...messages, assistantMessage];\n\n runOptions?.onMessage?.(assistantMessage);\n\n const durationMs = Date.now() - startTime;\n hooks?.onAfterCall?.({\n agent,\n input,\n output: parsed.text,\n totalTokens: parsed.totalTokens,\n tokenUsage,\n durationMs,\n timestamp: Date.now(),\n });\n\n return {\n output: parse<T>(parsed.text),\n messages: allMessages,\n toolCalls: [],\n totalTokens: parsed.totalTokens,\n tokenUsage,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n if (err instanceof Error) {\n hooks?.onError?.({\n agent,\n input,\n error: err,\n durationMs,\n timestamp: Date.now(),\n });\n }\n\n throw err;\n }\n };\n}\n","/**\n * @directive-run/ai/anthropic\n *\n * Anthropic adapter for Directive AI. Provides runners for the\n * Anthropic Messages API, including streaming support.\n *\n * @example\n * ```typescript\n * import { createAnthropicRunner, createAnthropicStreamingRunner } from '@directive-run/ai/anthropic';\n *\n * const runner = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { AdapterHooks, AgentRunner, Message, TokenUsage } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Anthropic model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { ANTHROPIC_PRICING } from '@directive-run/ai/anthropic';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, ANTHROPIC_PRICING[\"claude-sonnet-4-5-20250929\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://anthropic.com/pricing\n */\nexport const ANTHROPIC_PRICING: Record<string, { input: number; output: number }> = {\n\t\"claude-sonnet-4-5-20250929\": { input: 3, output: 15 },\n\t\"claude-haiku-3-5-20241022\": { input: 0.8, output: 4 },\n\t\"claude-opus-4-20250514\": { input: 15, output: 75 },\n};\n\n// ============================================================================\n// Anthropic Runner\n// ============================================================================\n\n/** Options for createAnthropicRunner */\nexport interface AnthropicRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** @default undefined */\n\ttimeoutMs?: number;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner for the Anthropic Messages API.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const runner = createAnthropicRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`${durationMs}ms – ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createAnthropicRunner(\n\toptions: AnthropicRunnerOptions,\n): AgentRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\ttimeoutMs,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn createRunner({\n\t\tfetch: fetchFn,\n\t\thooks,\n\t\tbuildRequest: (agent, _input, messages) => ({\n\t\t\turl: `${baseURL}/messages`,\n\t\t\tinit: {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: messages.map((m) => ({\n\t\t\t\t\t\trole: m.role,\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t})),\n\t\t\t\t}),\n\t\t\t\t...(timeoutMs != null ? { signal: AbortSignal.timeout(timeoutMs) } : {}),\n\t\t\t},\n\t\t}),\n\t\tparseResponse: async (res) => {\n\t\t\tconst data = await res.json();\n\t\t\tconst text = data.content?.[0]?.text ?? \"\";\n\t\t\tconst inputTokens = data.usage?.input_tokens ?? 0;\n\t\t\tconst outputTokens = data.usage?.output_tokens ?? 0;\n\n\t\t\treturn {\n\t\t\t\ttext,\n\t\t\t\ttotalTokens: inputTokens + outputTokens,\n\t\t\t\tinputTokens,\n\t\t\t\toutputTokens,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Anthropic Streaming Runner\n// ============================================================================\n\n/** Options for createAnthropicStreamingRunner */\nexport interface AnthropicStreamingRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\t/** @default 4096 */\n\tmaxTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create a StreamingCallbackRunner for the Anthropic Messages API with\n * server-sent events. Can be used standalone or paired with `createAnthropicRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createAnthropicStreamingRunner({\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createAnthropicStreamingRunner(\n\toptions: AnthropicStreamingRunnerOptions,\n): StreamingCallbackRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"claude-sonnet-4-5-20250929\",\n\t\tmaxTokens = 4096,\n\t\tbaseURL = \"https://api.anthropic.com/v1\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createAnthropicStreamingRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn async (agent, input, callbacks) => {\n\t\tconst startTime = Date.now();\n\t\thooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n\t\ttry {\n\t\t\tconst response = await fetchFn(`${baseURL}/messages`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-api-key\": apiKey,\n\t\t\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: agent.model ?? model,\n\t\t\t\t\tmax_tokens: maxTokens,\n\t\t\t\t\tsystem: agent.instructions ?? \"\",\n\t\t\t\t\tmessages: [{ role: \"user\", content: input }],\n\t\t\t\t\tstream: true,\n\t\t\t\t}),\n\t\t\t\tsignal: callbacks.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errBody = await response.text().catch(() => \"\");\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[Directive] Anthropic streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tthrow new Error(\"[Directive] No response body\");\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buf = \"\";\n\t\t\tlet fullText = \"\";\n\t\t\tlet inputTokens = 0;\n\t\t\tlet outputTokens = 0;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tbuf += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buf.split(\"\\n\");\n\t\t\t\t\tbuf = lines.pop() ?? \"\";\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.startsWith(\"data: \")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(data);\n\t\t\t\t\t\t\tif (event.type === \"error\") {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`[Directive] Anthropic stream error: ${event.error?.message ?? JSON.stringify(event.error)}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tevent.type === \"content_block_delta\" &&\n\t\t\t\t\t\t\t\tevent.delta?.type === \"text_delta\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tfullText += event.delta.text;\n\t\t\t\t\t\t\t\tcallbacks.onToken?.(event.delta.text);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_delta\" && event.usage) {\n\t\t\t\t\t\t\t\toutputTokens = event.usage.output_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"message_start\" && event.message?.usage) {\n\t\t\t\t\t\t\t\tinputTokens = event.message.usage.input_tokens ?? 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (parseErr) {\n\t\t\t\t\t\t\tif (parseErr instanceof SyntaxError) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\ttypeof process !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\tprocess.env?.NODE_ENV === \"development\"\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t\t\"[Directive] Malformed SSE event from Anthropic:\",\n\t\t\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow parseErr;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.cancel().catch(() => {});\n\t\t\t}\n\n\t\t\tconst assistantMsg: Message = { role: \"assistant\", content: fullText };\n\t\t\tcallbacks.onMessage?.(assistantMsg);\n\n\t\t\tconst tokenUsage: TokenUsage = { inputTokens, outputTokens };\n\t\t\tconst totalTokens = inputTokens + outputTokens;\n\n\t\t\thooks?.onAfterCall?.({\n\t\t\t\tagent,\n\t\t\t\tinput,\n\t\t\t\toutput: fullText,\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\toutput: fullText,\n\t\t\t\tmessages: [{ role: \"user\" as const, content: input }, assistantMsg],\n\t\t\t\ttoolCalls: [],\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\thooks?.onError?.({\n\t\t\t\t\tagent,\n\t\t\t\t\tinput,\n\t\t\t\t\terror: err,\n\t\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t}\n\t};\n}\n"]}
@@ -0,0 +1,3 @@
1
+ 'use strict';var E=new Set(["http:","https:"]);function M(c){try{let n=new URL(c);if(!E.has(n.protocol))throw new Error(`[Directive] Invalid baseURL protocol "${n.protocol}" \u2013 only http: and https: are allowed`)}catch(n){throw n instanceof Error&&n.message.startsWith("[Directive]")?n:new Error(`[Directive] Invalid baseURL "${c}" \u2013 must be a valid URL (e.g. "https://api.openai.com/v1")`)}}function C(c){let{fetch:n=globalThis.fetch,buildRequest:R,parseResponse:l,parseOutput:g,hooks:m}=c,a=g??(e=>{try{return JSON.parse(e)}catch{return e}});return async(e,o,r)=>{let t=Date.now();m?.onBeforeCall?.({agent:e,input:o,timestamp:t});let i=[{role:"user",content:o}];try{let{url:d,init:p}=R(e,o,i),T=r?.signal?{...p,signal:r.signal}:p,u=await n(d,T);if(!u.ok){let x=await u.text().catch(()=>"");throw new Error(`[Directive] AgentRunner request failed: ${u.status} ${u.statusText}${x?` \u2013 ${x.slice(0,300)}`:""}`)}let s=await l(u,i),y={inputTokens:s.inputTokens??0,outputTokens:s.outputTokens??0},w={role:"assistant",content:s.text},b=[...i,w];r?.onMessage?.(w);let k=Date.now()-t;return m?.onAfterCall?.({agent:e,input:o,output:s.text,totalTokens:s.totalTokens,tokenUsage:y,durationMs:k,timestamp:Date.now()}),{output:a(s.text),messages:b,toolCalls:[],totalTokens:s.totalTokens,tokenUsage:y}}catch(d){let p=Date.now()-t;throw d instanceof Error&&m?.onError?.({agent:e,input:o,error:d,durationMs:p,timestamp:Date.now()}),d}}}var U={"gemini-2.5-pro":{input:1.25,output:10},"gemini-2.5-flash":{input:.15,output:.6},"gemini-2.0-flash":{input:.1,output:.4},"gemini-2.0-flash-lite":{input:.025,output:.1}};function N(c){let{apiKey:n,model:R="gemini-2.0-flash",maxOutputTokens:l,baseURL:g="https://generativelanguage.googleapis.com/v1beta",fetch:m=globalThis.fetch,timeoutMs:f,hooks:a}=c;return M(g),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!n&&console.warn("[Directive] createGeminiRunner: apiKey is empty. API calls will fail."),C({fetch:m,hooks:a,buildRequest:(e,o,r)=>({url:`${g}/models/${e.model??R}:generateContent`,init:{method:"POST",headers:{"Content-Type":"application/json","x-goog-api-key":n},body:JSON.stringify({...e.instructions?{systemInstruction:{parts:[{text:e.instructions}]}}:{},contents:r.map(t=>({role:t.role==="assistant"?"model":"user",parts:[{text:t.content}]})),...l!=null?{generationConfig:{maxOutputTokens:l}}:{}}),...f!=null?{signal:AbortSignal.timeout(f)}:{}}}),parseResponse:async e=>{let o=await e.json(),r=o.candidates?.[0]?.content?.parts?.[0]?.text??"",t=o.usageMetadata?.promptTokenCount??0,i=o.usageMetadata?.candidatesTokenCount??0;return {text:r,totalTokens:t+i,inputTokens:t,outputTokens:i}}})}function G(c){let{apiKey:n,model:R="gemini-2.0-flash",maxOutputTokens:l,baseURL:g="https://generativelanguage.googleapis.com/v1beta",fetch:m=globalThis.fetch,hooks:f}=c;return M(g),typeof process<"u"&&process.env?.NODE_ENV!=="production"&&!n&&console.warn("[Directive] createGeminiStreamingRunner: apiKey is empty. API calls will fail."),async(a,e,o)=>{let r=Date.now();f?.onBeforeCall?.({agent:a,input:e,timestamp:r});try{let t=await m(`${g}/models/${a.model??R}:streamGenerateContent?alt=sse`,{method:"POST",headers:{"Content-Type":"application/json","x-goog-api-key":n},body:JSON.stringify({...a.instructions?{systemInstruction:{parts:[{text:a.instructions}]}}:{},contents:[{role:"user",parts:[{text:e}]}],...l!=null?{generationConfig:{maxOutputTokens:l}}:{}}),signal:o.signal});if(!t.ok){let k=await t.text().catch(()=>"");throw new Error(`[Directive] Gemini streaming error ${t.status}${k?` \u2013 ${k.slice(0,200)}`:""}`)}let i=t.body?.getReader();if(!i)throw new Error("[Directive] No response body");let d=new TextDecoder,p="",T="",u=0,s=0;try{for(;;){let{done:k,value:x}=await i.read();if(k)break;p+=d.decode(x,{stream:!0});let A=p.split(`
2
+ `);p=A.pop()??"";for(let D of A){if(!D.startsWith("data: "))continue;let v=D.slice(6).trim();if(v!=="[DONE]")try{let h=JSON.parse(v),O=h.candidates?.[0]?.content?.parts?.[0]?.text;O&&(T+=O,o.onToken?.(O)),h.usageMetadata&&(u=h.usageMetadata.promptTokenCount??u,s=h.usageMetadata.candidatesTokenCount??s);}catch(h){if(h instanceof SyntaxError)typeof process<"u"&&process.env?.NODE_ENV==="development"&&console.warn("[Directive] Malformed SSE event from Gemini:",v);else throw h}}}}finally{i.cancel().catch(()=>{});}let y={role:"assistant",content:T};o.onMessage?.(y);let w={inputTokens:u,outputTokens:s},b=u+s;return f?.onAfterCall?.({agent:a,input:e,output:T,totalTokens:b,tokenUsage:w,durationMs:Date.now()-r,timestamp:Date.now()}),{output:T,messages:[{role:"user",content:e},y],toolCalls:[],totalTokens:b,tokenUsage:w}}catch(t){throw t instanceof Error&&f?.onError?.({agent:a,input:e,error:t,durationMs:Date.now()-r,timestamp:Date.now()}),t}}}exports.GEMINI_PRICING=U;exports.createGeminiRunner=N;exports.createGeminiStreamingRunner=G;//# sourceMappingURL=gemini.cjs.map
3
+ //# sourceMappingURL=gemini.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agent-utils.ts","../src/adapters/gemini.ts"],"names":["ALLOWED_PROTOCOLS","validateBaseURL","baseURL","url","err","createRunner","options","fetchFn","buildRequest","parseResponse","parseOutput","hooks","parse","text","agent","input","runOptions","startTime","messages","init","fetchInit","response","errBody","parsed","tokenUsage","assistantMessage","allMessages","durationMs","GEMINI_PRICING","createGeminiRunner","apiKey","model","maxOutputTokens","timeoutMs","_input","m","res","data","inputTokens","outputTokens","createGeminiStreamingRunner","callbacks","reader","decoder","buf","fullText","done","value","lines","line","event","parseErr","assistantMsg","totalTokens"],"mappings":"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","file":"gemini.cjs","sourcesContent":["/**\n * Agent utilities — createRunner, estimateCost, state queries, URL validation.\n */\n\nimport type {\n AdapterHooks,\n AgentLike,\n AgentRunner,\n RunResult,\n RunOptions,\n Message,\n TokenUsage,\n AgentState,\n ApprovalState,\n} from \"./types.js\";\n\n// ============================================================================\n// State Query Helpers\n// ============================================================================\n\n/** Check if agent is currently running. */\nexport function isAgentRunning(state: AgentState): boolean {\n return state.status === \"running\";\n}\n\n/** Check if there are pending approvals. */\nexport function hasPendingApprovals(state: ApprovalState): boolean {\n return state.pending.length > 0;\n}\n\n// ============================================================================\n// Cost Estimation\n// ============================================================================\n\n/**\n * Get total cost estimate based on token usage.\n *\n * @param tokenUsage - Total token count\n * @param ratePerMillionTokens - Cost per million tokens (required, no default to avoid stale pricing)\n * @returns Estimated cost in dollars\n */\nexport function estimateCost(\n tokenUsage: number,\n ratePerMillionTokens: number\n): number {\n return (tokenUsage / 1_000_000) * ratePerMillionTokens;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\"]);\n\n/**\n * Validate that a baseURL uses http or https.\n * Throws immediately at adapter creation time (not at call time) to catch config errors early.\n */\nexport function validateBaseURL(baseURL: string): void {\n try {\n const url = new URL(baseURL);\n if (!ALLOWED_PROTOCOLS.has(url.protocol)) {\n throw new Error(\n `[Directive] Invalid baseURL protocol \"${url.protocol}\" – only http: and https: are allowed`,\n );\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"[Directive]\")) {\n throw err;\n }\n\n throw new Error(\n `[Directive] Invalid baseURL \"${baseURL}\" – must be a valid URL (e.g. \"https://api.openai.com/v1\")`,\n );\n }\n}\n\n// ============================================================================\n// createRunner Helper\n// ============================================================================\n\n/** Parsed response from an LLM provider */\nexport interface ParsedResponse {\n text: string;\n totalTokens: number;\n /** Input token count, when available from the provider */\n inputTokens?: number;\n /** Output token count, when available from the provider */\n outputTokens?: number;\n}\n\n/** Options for creating an AgentRunner from buildRequest/parseResponse */\nexport interface CreateRunnerOptions {\n fetch?: typeof globalThis.fetch;\n buildRequest: (\n agent: AgentLike,\n input: string,\n messages: Message[]\n ) => { url: string; init: RequestInit };\n parseResponse: (\n response: Response,\n messages: Message[]\n ) => Promise<ParsedResponse>;\n parseOutput?: <T>(text: string) => T;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner from buildRequest/parseResponse helpers.\n * Reduces ~50 lines of fetch boilerplate to ~20 lines of configuration.\n *\n * Supports lifecycle hooks for observability:\n * - `onBeforeCall` fires before each API request\n * - `onAfterCall` fires after a successful response (includes token breakdown)\n * - `onError` fires when the request fails\n *\n * @example\n * ```typescript\n * const runClaude = createRunner({\n * buildRequest: (agent, input) => ({\n * url: \"/api/claude\",\n * init: {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * model: agent.model ?? \"claude-haiku-4-5-20251001\",\n * system: agent.instructions ?? \"\",\n * messages: [{ role: \"user\", content: input }],\n * }),\n * },\n * }),\n * parseResponse: async (res) => {\n * const data = await res.json();\n * const inputTokens = data.usage?.input_tokens ?? 0;\n * const outputTokens = data.usage?.output_tokens ?? 0;\n * return {\n * text: data.content?.[0]?.text ?? \"\",\n * totalTokens: inputTokens + outputTokens,\n * inputTokens,\n * outputTokens,\n * };\n * },\n * hooks: {\n * onAfterCall: ({ durationMs, tokenUsage }) => {\n * console.log(`LLM call: ${durationMs}ms, ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);\n * },\n * },\n * });\n * ```\n */\nexport function createRunner(options: CreateRunnerOptions): AgentRunner {\n const {\n fetch: fetchFn = globalThis.fetch,\n buildRequest,\n parseResponse,\n parseOutput,\n hooks,\n } = options;\n\n const defaultParseOutput = <T>(text: string): T => {\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as unknown as T;\n }\n };\n\n const parse = parseOutput ?? defaultParseOutput;\n\n return async <T = unknown>(\n agent: AgentLike,\n input: string,\n runOptions?: RunOptions\n ): Promise<RunResult<T>> => {\n const startTime = Date.now();\n hooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n const messages: Message[] = [{ role: \"user\", content: input }];\n\n try {\n const { url, init } = buildRequest(agent, input, messages);\n\n const fetchInit: RequestInit = runOptions?.signal\n ? { ...init, signal: runOptions.signal }\n : init;\n\n const response = await fetchFn(url, fetchInit);\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] AgentRunner request failed: ${response.status} ${response.statusText}${errBody ? ` – ${errBody.slice(0, 300)}` : \"\"}`,\n );\n }\n\n const parsed = await parseResponse(response, messages);\n const tokenUsage: TokenUsage = {\n inputTokens: parsed.inputTokens ?? 0,\n outputTokens: parsed.outputTokens ?? 0,\n };\n\n const assistantMessage: Message = { role: \"assistant\", content: parsed.text };\n const allMessages: Message[] = [...messages, assistantMessage];\n\n runOptions?.onMessage?.(assistantMessage);\n\n const durationMs = Date.now() - startTime;\n hooks?.onAfterCall?.({\n agent,\n input,\n output: parsed.text,\n totalTokens: parsed.totalTokens,\n tokenUsage,\n durationMs,\n timestamp: Date.now(),\n });\n\n return {\n output: parse<T>(parsed.text),\n messages: allMessages,\n toolCalls: [],\n totalTokens: parsed.totalTokens,\n tokenUsage,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n if (err instanceof Error) {\n hooks?.onError?.({\n agent,\n input,\n error: err,\n durationMs,\n timestamp: Date.now(),\n });\n }\n\n throw err;\n }\n };\n}\n","/**\n * @directive-run/ai/gemini\n *\n * Google Gemini adapter for Directive AI. Provides runners for the\n * Gemini generateContent API, including streaming support.\n *\n * @example\n * ```typescript\n * import { createGeminiRunner, createGeminiStreamingRunner } from '@directive-run/ai/gemini';\n *\n * const runner = createGeminiRunner({ apiKey: process.env.GEMINI_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { AdapterHooks, AgentRunner, Message, TokenUsage } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Gemini model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { GEMINI_PRICING } from '@directive-run/ai/gemini';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, GEMINI_PRICING[\"gemini-2.0-flash\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, GEMINI_PRICING[\"gemini-2.0-flash\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://ai.google.dev/pricing\n */\nexport const GEMINI_PRICING: Record<string, { input: number; output: number }> = {\n\t\"gemini-2.5-pro\": { input: 1.25, output: 10 },\n\t\"gemini-2.5-flash\": { input: 0.15, output: 0.6 },\n\t\"gemini-2.0-flash\": { input: 0.1, output: 0.4 },\n\t\"gemini-2.0-flash-lite\": { input: 0.025, output: 0.1 },\n};\n\n// ============================================================================\n// Gemini Runner\n// ============================================================================\n\n/** Options for createGeminiRunner */\nexport interface GeminiRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\tmaxOutputTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** @default undefined */\n\ttimeoutMs?: number;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create an AgentRunner for the Google Gemini generateContent API.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const runner = createGeminiRunner({\n * apiKey: process.env.GEMINI_API_KEY!,\n * model: 'gemini-2.0-flash',\n * });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createGeminiRunner(options: GeminiRunnerOptions): AgentRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"gemini-2.0-flash\",\n\t\tmaxOutputTokens,\n\t\tbaseURL = \"https://generativelanguage.googleapis.com/v1beta\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\ttimeoutMs,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createGeminiRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn createRunner({\n\t\tfetch: fetchFn,\n\t\thooks,\n\t\tbuildRequest: (agent, _input, messages) => ({\n\t\t\turl: `${baseURL}/models/${agent.model ?? model}:generateContent`,\n\t\t\tinit: {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"x-goog-api-key\": apiKey,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t...(agent.instructions\n\t\t\t\t\t\t? { systemInstruction: { parts: [{ text: agent.instructions }] } }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\tcontents: messages.map((m) => ({\n\t\t\t\t\t\trole: m.role === \"assistant\" ? \"model\" : \"user\",\n\t\t\t\t\t\tparts: [{ text: m.content }],\n\t\t\t\t\t})),\n\t\t\t\t\t...(maxOutputTokens != null\n\t\t\t\t\t\t? { generationConfig: { maxOutputTokens } }\n\t\t\t\t\t\t: {}),\n\t\t\t\t}),\n\t\t\t\t...(timeoutMs != null ? { signal: AbortSignal.timeout(timeoutMs) } : {}),\n\t\t\t},\n\t\t}),\n\t\tparseResponse: async (res) => {\n\t\t\tconst data = await res.json();\n\t\t\tconst text = data.candidates?.[0]?.content?.parts?.[0]?.text ?? \"\";\n\t\t\tconst inputTokens = data.usageMetadata?.promptTokenCount ?? 0;\n\t\t\tconst outputTokens = data.usageMetadata?.candidatesTokenCount ?? 0;\n\n\t\t\treturn {\n\t\t\t\ttext,\n\t\t\t\ttotalTokens: inputTokens + outputTokens,\n\t\t\t\tinputTokens,\n\t\t\t\toutputTokens,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Gemini Streaming Runner\n// ============================================================================\n\n/** Options for createGeminiStreamingRunner */\nexport interface GeminiStreamingRunnerOptions {\n\tapiKey: string;\n\tmodel?: string;\n\tmaxOutputTokens?: number;\n\tbaseURL?: string;\n\tfetch?: typeof globalThis.fetch;\n\t/** Lifecycle hooks for tracing, logging, and metrics */\n\thooks?: AdapterHooks;\n}\n\n/**\n * Create a StreamingCallbackRunner for the Gemini streamGenerateContent API\n * with server-sent events. Can be used standalone or paired with `createGeminiRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createGeminiStreamingRunner({\n * apiKey: process.env.GEMINI_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createGeminiStreamingRunner(\n\toptions: GeminiStreamingRunnerOptions,\n): StreamingCallbackRunner {\n\tconst {\n\t\tapiKey,\n\t\tmodel = \"gemini-2.0-flash\",\n\t\tmaxOutputTokens,\n\t\tbaseURL = \"https://generativelanguage.googleapis.com/v1beta\",\n\t\tfetch: fetchFn = globalThis.fetch,\n\t\thooks,\n\t} = options;\n\n\tvalidateBaseURL(baseURL);\n\n\tif (typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\" && !apiKey) {\n\t\tconsole.warn(\"[Directive] createGeminiStreamingRunner: apiKey is empty. API calls will fail.\");\n\t}\n\n\treturn async (agent, input, callbacks) => {\n\t\tconst startTime = Date.now();\n\t\thooks?.onBeforeCall?.({ agent, input, timestamp: startTime });\n\n\t\ttry {\n\t\t\tconst response = await fetchFn(\n\t\t\t\t`${baseURL}/models/${agent.model ?? model}:streamGenerateContent?alt=sse`,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t\"x-goog-api-key\": apiKey,\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\t...(agent.instructions\n\t\t\t\t\t\t\t? { systemInstruction: { parts: [{ text: agent.instructions }] } }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\tcontents: [{ role: \"user\", parts: [{ text: input }] }],\n\t\t\t\t\t\t...(maxOutputTokens != null\n\t\t\t\t\t\t\t? { generationConfig: { maxOutputTokens } }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}),\n\t\t\t\t\tsignal: callbacks.signal,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errBody = await response.text().catch(() => \"\");\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[Directive] Gemini streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tthrow new Error(\"[Directive] No response body\");\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buf = \"\";\n\t\t\tlet fullText = \"\";\n\t\t\tlet inputTokens = 0;\n\t\t\tlet outputTokens = 0;\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tbuf += decoder.decode(value, { stream: true });\n\t\t\t\t\tconst lines = buf.split(\"\\n\");\n\t\t\t\t\tbuf = lines.pop() ?? \"\";\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (!line.startsWith(\"data: \")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data === \"[DONE]\") {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(data);\n\n\t\t\t\t\t\t\t// Extract text from candidates\n\t\t\t\t\t\t\tconst text = event.candidates?.[0]?.content?.parts?.[0]?.text;\n\t\t\t\t\t\t\tif (text) {\n\t\t\t\t\t\t\t\tfullText += text;\n\t\t\t\t\t\t\t\tcallbacks.onToken?.(text);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Extract usage metadata from any chunk that has it\n\t\t\t\t\t\t\tif (event.usageMetadata) {\n\t\t\t\t\t\t\t\tinputTokens = event.usageMetadata.promptTokenCount ?? inputTokens;\n\t\t\t\t\t\t\t\toutputTokens = event.usageMetadata.candidatesTokenCount ?? outputTokens;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (parseErr) {\n\t\t\t\t\t\t\tif (parseErr instanceof SyntaxError) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\ttypeof process !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\tprocess.env?.NODE_ENV === \"development\"\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t\t\"[Directive] Malformed SSE event from Gemini:\",\n\t\t\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow parseErr;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.cancel().catch(() => {});\n\t\t\t}\n\n\t\t\tconst assistantMsg: Message = { role: \"assistant\", content: fullText };\n\t\t\tcallbacks.onMessage?.(assistantMsg);\n\n\t\t\tconst tokenUsage: TokenUsage = { inputTokens, outputTokens };\n\t\t\tconst totalTokens = inputTokens + outputTokens;\n\n\t\t\thooks?.onAfterCall?.({\n\t\t\t\tagent,\n\t\t\t\tinput,\n\t\t\t\toutput: fullText,\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\toutput: fullText,\n\t\t\t\tmessages: [{ role: \"user\" as const, content: input }, assistantMsg],\n\t\t\t\ttoolCalls: [],\n\t\t\t\ttotalTokens,\n\t\t\t\ttokenUsage,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\thooks?.onError?.({\n\t\t\t\t\tagent,\n\t\t\t\t\tinput,\n\t\t\t\t\terror: err,\n\t\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t}\n\t};\n}\n"]}