@directive-run/ai 0.1.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jason Comes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # @directive-run/ai
2
+
3
+ AI agent orchestration, guardrails, and multi-agent coordination for Directive. Use Directive constraints to add safety guardrails, approval workflows, and state persistence to any LLM agent framework.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @directive-run/core @directive-run/ai
9
+ ```
10
+
11
+ Provider adapters are included as subpath exports – no extra packages needed.
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { createAgentStack } from "@directive-run/ai";
17
+ import { createOpenAIRunner } from "@directive-run/ai/openai";
18
+
19
+ const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });
20
+
21
+ const stack = createAgentStack({
22
+ runner,
23
+ agents: {
24
+ assistant: { instructions: "You are a helpful assistant." },
25
+ },
26
+ guardrails: {
27
+ input: [async (data) => ({ passed: data.input.length < 10000 })],
28
+ },
29
+ });
30
+
31
+ const result = await stack.run("assistant", "Hello!");
32
+ console.log(result.output);
33
+ ```
34
+
35
+ ## Why Directive Adapters?
36
+
37
+ Directive adapters are intentionally thin &ndash; they map `createRunner()` config to each provider's HTTP API. This gives you:
38
+
39
+ - **No SDK dependencies** &ndash; pure `fetch`, no `openai` or `@anthropic-ai/sdk` to install
40
+ - **Uniform interface** &ndash; swap providers by changing one import, not your entire codebase
41
+ - **Built-in observability** &ndash; lifecycle hooks (`onBeforeCall`, `onAfterCall`, `onError`) on every adapter
42
+ - **Cost tracking** &ndash; `tokenUsage` breakdown (input/output) and pricing constants for every provider
43
+ - **Tree-shakeable** &ndash; each adapter is a separate entry point; unused adapters never enter your bundle
44
+
45
+ ## Key Features
46
+
47
+ - Guardrails (input, output, tool call) with retry support
48
+ - Approval workflows for tool calls
49
+ - Multi-agent orchestration (parallel, sequential, supervisor patterns)
50
+ - Agent memory (sliding window, token-based, hybrid strategies)
51
+ - Streaming with backpressure and streaming guardrails
52
+ - Semantic caching and RAG enrichment
53
+ - Circuit breakers and observability
54
+ - Per-call cost tracking with `tokenUsage` and pricing constants
55
+ - Adapter lifecycle hooks for tracing, logging, and metrics
56
+
57
+ ## Subpath Exports
58
+
59
+ | Import | Purpose |
60
+ |--------|---------|
61
+ | `@directive-run/ai` | Orchestrator, guardrails, multi-agent, streaming |
62
+ | `@directive-run/ai/testing` | Mock runners, test helpers |
63
+ | `@directive-run/ai/openai` | OpenAI, Azure, Together adapter |
64
+ | `@directive-run/ai/anthropic` | Anthropic Claude adapter |
65
+ | `@directive-run/ai/ollama` | Local Ollama inference adapter |
66
+
67
+ ## Provider Comparison
68
+
69
+ | | OpenAI | Anthropic | Ollama |
70
+ |---|--------|-----------|--------|
71
+ | Import | `@directive-run/ai/openai` | `@directive-run/ai/anthropic` | `@directive-run/ai/ollama` |
72
+ | Default model | `gpt-4o` | `claude-sonnet-4-5-20250929` | `llama3` |
73
+ | API key required | Yes | Yes | No |
74
+ | Streaming runner | `createOpenAIStreamingRunner` | `createAnthropicStreamingRunner` | &ndash; |
75
+ | Embedder | `createOpenAIEmbedder` | &ndash; | &ndash; |
76
+ | Pricing constants | `OPENAI_PRICING` | `ANTHROPIC_PRICING` | &ndash; |
77
+ | Compatible APIs | Azure, Together, any OpenAI-compatible | &ndash; | &ndash; |
78
+
79
+ ## Cost Tracking
80
+
81
+ Every adapter returns `tokenUsage` with input/output breakdown:
82
+
83
+ ```typescript
84
+ import { estimateCost } from '@directive-run/ai';
85
+ import { createOpenAIRunner, OPENAI_PRICING } from '@directive-run/ai/openai';
86
+
87
+ const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });
88
+ const result = await runner(agent, 'Hello');
89
+
90
+ const { inputTokens, outputTokens } = result.tokenUsage!;
91
+ const cost =
92
+ estimateCost(inputTokens, OPENAI_PRICING['gpt-4o'].input) +
93
+ estimateCost(outputTokens, OPENAI_PRICING['gpt-4o'].output);
94
+ ```
95
+
96
+ ## Lifecycle Hooks
97
+
98
+ Attach hooks to any adapter for observability:
99
+
100
+ ```typescript
101
+ import { createAnthropicRunner } from '@directive-run/ai/anthropic';
102
+
103
+ const runner = createAnthropicRunner({
104
+ apiKey: process.env.ANTHROPIC_API_KEY!,
105
+ hooks: {
106
+ onBeforeCall: ({ agent, input }) => console.log(`→ ${agent.name}`),
107
+ onAfterCall: ({ durationMs, tokenUsage }) => {
108
+ metrics.track('llm_call', { durationMs, ...tokenUsage });
109
+ },
110
+ onError: ({ error }) => Sentry.captureException(error),
111
+ },
112
+ });
113
+ ```
114
+
115
+ ## Testing
116
+
117
+ The `@directive-run/ai/testing` subpath provides mock runners and test helpers for unit testing agent stacks without making real LLM calls:
118
+
119
+ ```typescript
120
+ import { createAgentStack } from "@directive-run/ai";
121
+ import { createMockRunner, createMockStreamingRunner } from "@directive-run/ai/testing";
122
+
123
+ const mockRunner = createMockRunner({
124
+ responses: {
125
+ assistant: "This is a mock response.",
126
+ },
127
+ });
128
+
129
+ const stack = createAgentStack({
130
+ runner: mockRunner,
131
+ agents: {
132
+ assistant: { instructions: "You are a helpful assistant." },
133
+ },
134
+ });
135
+
136
+ const result = await stack.run("assistant", "Hello!");
137
+ // result.output === "This is a mock response."
138
+ ```
139
+
140
+ Use `createMockStreamingRunner` to test streaming code paths with controlled chunk delivery.
141
+
142
+ ## License
143
+
144
+ MIT
145
+
146
+ [Full documentation](https://directive.run/docs)
@@ -0,0 +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(`
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
+ //# sourceMappingURL=anthropic.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,103 @@
1
+ import { f as AdapterHooks, c as AgentRunner } from './types-BKCdgKC-.cjs';
2
+ import { StreamingCallbackRunner } from './index.cjs';
3
+ import '@directive-run/core';
4
+ import '@directive-run/core/plugins';
5
+
6
+ /**
7
+ * @directive-run/ai/anthropic
8
+ *
9
+ * Anthropic adapter for Directive AI. Provides runners for the
10
+ * Anthropic Messages API, including streaming support.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { createAnthropicRunner, createAnthropicStreamingRunner } from '@directive-run/ai/anthropic';
15
+ *
16
+ * const runner = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY! });
17
+ * ```
18
+ */
19
+
20
+ /**
21
+ * Anthropic model pricing (USD per million tokens).
22
+ *
23
+ * Use with `estimateCost()` for per-call cost tracking:
24
+ * ```typescript
25
+ * import { estimateCost } from '@directive-run/ai';
26
+ * import { ANTHROPIC_PRICING } from '@directive-run/ai/anthropic';
27
+ *
28
+ * const cost =
29
+ * estimateCost(result.tokenUsage!.inputTokens, ANTHROPIC_PRICING["claude-sonnet-4-5-20250929"].input) +
30
+ * estimateCost(result.tokenUsage!.outputTokens, ANTHROPIC_PRICING["claude-sonnet-4-5-20250929"].output);
31
+ * ```
32
+ *
33
+ * **Note:** Pricing changes over time. These values are provided as a convenience
34
+ * and may not reflect the latest rates. Always verify at https://anthropic.com/pricing
35
+ */
36
+ declare const ANTHROPIC_PRICING: Record<string, {
37
+ input: number;
38
+ output: number;
39
+ }>;
40
+ /** Options for createAnthropicRunner */
41
+ interface AnthropicRunnerOptions {
42
+ apiKey: string;
43
+ model?: string;
44
+ /** @default 4096 */
45
+ maxTokens?: number;
46
+ baseURL?: string;
47
+ fetch?: typeof globalThis.fetch;
48
+ /** @default undefined */
49
+ timeoutMs?: number;
50
+ /** Lifecycle hooks for tracing, logging, and metrics */
51
+ hooks?: AdapterHooks;
52
+ }
53
+ /**
54
+ * Create an AgentRunner for the Anthropic Messages API.
55
+ *
56
+ * Returns `tokenUsage` with input/output breakdown for cost tracking.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const runner = createAnthropicRunner({
61
+ * apiKey: process.env.ANTHROPIC_API_KEY!,
62
+ * hooks: {
63
+ * onAfterCall: ({ durationMs, tokenUsage }) => {
64
+ * console.log(`${durationMs}ms – ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);
65
+ * },
66
+ * },
67
+ * });
68
+ * const stack = createAgentStack({ runner, agents: { ... } });
69
+ * ```
70
+ */
71
+ declare function createAnthropicRunner(options: AnthropicRunnerOptions): AgentRunner;
72
+ /** Options for createAnthropicStreamingRunner */
73
+ interface AnthropicStreamingRunnerOptions {
74
+ apiKey: string;
75
+ model?: string;
76
+ /** @default 4096 */
77
+ maxTokens?: number;
78
+ baseURL?: string;
79
+ fetch?: typeof globalThis.fetch;
80
+ /** Lifecycle hooks for tracing, logging, and metrics */
81
+ hooks?: AdapterHooks;
82
+ }
83
+ /**
84
+ * Create a StreamingCallbackRunner for the Anthropic Messages API with
85
+ * server-sent events. Can be used standalone or paired with `createAnthropicRunner`.
86
+ *
87
+ * Returns `tokenUsage` with input/output breakdown for cost tracking.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const streamingRunner = createAnthropicStreamingRunner({
92
+ * apiKey: process.env.ANTHROPIC_API_KEY!,
93
+ * });
94
+ * const stack = createAgentStack({
95
+ * runner: createAnthropicRunner({ apiKey }),
96
+ * streaming: { runner: streamingRunner },
97
+ * agents: { ... },
98
+ * });
99
+ * ```
100
+ */
101
+ declare function createAnthropicStreamingRunner(options: AnthropicStreamingRunnerOptions): StreamingCallbackRunner;
102
+
103
+ export { ANTHROPIC_PRICING, type AnthropicRunnerOptions, type AnthropicStreamingRunnerOptions, createAnthropicRunner, createAnthropicStreamingRunner };
@@ -0,0 +1,103 @@
1
+ import { f as AdapterHooks, c as AgentRunner } from './types-BKCdgKC-.js';
2
+ import { StreamingCallbackRunner } from './index.js';
3
+ import '@directive-run/core';
4
+ import '@directive-run/core/plugins';
5
+
6
+ /**
7
+ * @directive-run/ai/anthropic
8
+ *
9
+ * Anthropic adapter for Directive AI. Provides runners for the
10
+ * Anthropic Messages API, including streaming support.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { createAnthropicRunner, createAnthropicStreamingRunner } from '@directive-run/ai/anthropic';
15
+ *
16
+ * const runner = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY! });
17
+ * ```
18
+ */
19
+
20
+ /**
21
+ * Anthropic model pricing (USD per million tokens).
22
+ *
23
+ * Use with `estimateCost()` for per-call cost tracking:
24
+ * ```typescript
25
+ * import { estimateCost } from '@directive-run/ai';
26
+ * import { ANTHROPIC_PRICING } from '@directive-run/ai/anthropic';
27
+ *
28
+ * const cost =
29
+ * estimateCost(result.tokenUsage!.inputTokens, ANTHROPIC_PRICING["claude-sonnet-4-5-20250929"].input) +
30
+ * estimateCost(result.tokenUsage!.outputTokens, ANTHROPIC_PRICING["claude-sonnet-4-5-20250929"].output);
31
+ * ```
32
+ *
33
+ * **Note:** Pricing changes over time. These values are provided as a convenience
34
+ * and may not reflect the latest rates. Always verify at https://anthropic.com/pricing
35
+ */
36
+ declare const ANTHROPIC_PRICING: Record<string, {
37
+ input: number;
38
+ output: number;
39
+ }>;
40
+ /** Options for createAnthropicRunner */
41
+ interface AnthropicRunnerOptions {
42
+ apiKey: string;
43
+ model?: string;
44
+ /** @default 4096 */
45
+ maxTokens?: number;
46
+ baseURL?: string;
47
+ fetch?: typeof globalThis.fetch;
48
+ /** @default undefined */
49
+ timeoutMs?: number;
50
+ /** Lifecycle hooks for tracing, logging, and metrics */
51
+ hooks?: AdapterHooks;
52
+ }
53
+ /**
54
+ * Create an AgentRunner for the Anthropic Messages API.
55
+ *
56
+ * Returns `tokenUsage` with input/output breakdown for cost tracking.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const runner = createAnthropicRunner({
61
+ * apiKey: process.env.ANTHROPIC_API_KEY!,
62
+ * hooks: {
63
+ * onAfterCall: ({ durationMs, tokenUsage }) => {
64
+ * console.log(`${durationMs}ms – ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);
65
+ * },
66
+ * },
67
+ * });
68
+ * const stack = createAgentStack({ runner, agents: { ... } });
69
+ * ```
70
+ */
71
+ declare function createAnthropicRunner(options: AnthropicRunnerOptions): AgentRunner;
72
+ /** Options for createAnthropicStreamingRunner */
73
+ interface AnthropicStreamingRunnerOptions {
74
+ apiKey: string;
75
+ model?: string;
76
+ /** @default 4096 */
77
+ maxTokens?: number;
78
+ baseURL?: string;
79
+ fetch?: typeof globalThis.fetch;
80
+ /** Lifecycle hooks for tracing, logging, and metrics */
81
+ hooks?: AdapterHooks;
82
+ }
83
+ /**
84
+ * Create a StreamingCallbackRunner for the Anthropic Messages API with
85
+ * server-sent events. Can be used standalone or paired with `createAnthropicRunner`.
86
+ *
87
+ * Returns `tokenUsage` with input/output breakdown for cost tracking.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const streamingRunner = createAnthropicStreamingRunner({
92
+ * apiKey: process.env.ANTHROPIC_API_KEY!,
93
+ * });
94
+ * const stack = createAgentStack({
95
+ * runner: createAnthropicRunner({ apiKey }),
96
+ * streaming: { runner: streamingRunner },
97
+ * agents: { ... },
98
+ * });
99
+ * ```
100
+ */
101
+ declare function createAnthropicStreamingRunner(options: AnthropicStreamingRunnerOptions): StreamingCallbackRunner;
102
+
103
+ export { ANTHROPIC_PRICING, type AnthropicRunnerOptions, type AnthropicStreamingRunnerOptions, createAnthropicRunner, createAnthropicStreamingRunner };
@@ -0,0 +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(`
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
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +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"]}