@jackchen_me/open-multi-agent 0.1.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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/agent/agent.d.ts +121 -0
  4. package/dist/agent/agent.d.ts.map +1 -0
  5. package/dist/agent/agent.js +294 -0
  6. package/dist/agent/agent.js.map +1 -0
  7. package/dist/agent/pool.d.ts +128 -0
  8. package/dist/agent/pool.d.ts.map +1 -0
  9. package/dist/agent/pool.js +236 -0
  10. package/dist/agent/pool.js.map +1 -0
  11. package/dist/agent/runner.d.ts +120 -0
  12. package/dist/agent/runner.d.ts.map +1 -0
  13. package/dist/agent/runner.js +274 -0
  14. package/dist/agent/runner.js.map +1 -0
  15. package/dist/index.d.ts +73 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +87 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/llm/adapter.d.ts +38 -0
  20. package/dist/llm/adapter.d.ts.map +1 -0
  21. package/dist/llm/adapter.js +46 -0
  22. package/dist/llm/adapter.js.map +1 -0
  23. package/dist/llm/anthropic.d.ts +56 -0
  24. package/dist/llm/anthropic.d.ts.map +1 -0
  25. package/dist/llm/anthropic.js +307 -0
  26. package/dist/llm/anthropic.js.map +1 -0
  27. package/dist/llm/openai.d.ts +62 -0
  28. package/dist/llm/openai.d.ts.map +1 -0
  29. package/dist/llm/openai.js +424 -0
  30. package/dist/llm/openai.js.map +1 -0
  31. package/dist/memory/shared.d.ts +86 -0
  32. package/dist/memory/shared.d.ts.map +1 -0
  33. package/dist/memory/shared.js +155 -0
  34. package/dist/memory/shared.js.map +1 -0
  35. package/dist/memory/store.d.ts +64 -0
  36. package/dist/memory/store.d.ts.map +1 -0
  37. package/dist/memory/store.js +103 -0
  38. package/dist/memory/store.js.map +1 -0
  39. package/dist/orchestrator/orchestrator.d.ts +173 -0
  40. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  41. package/dist/orchestrator/orchestrator.js +698 -0
  42. package/dist/orchestrator/orchestrator.js.map +1 -0
  43. package/dist/orchestrator/scheduler.d.ts +112 -0
  44. package/dist/orchestrator/scheduler.d.ts.map +1 -0
  45. package/dist/orchestrator/scheduler.js +282 -0
  46. package/dist/orchestrator/scheduler.js.map +1 -0
  47. package/dist/task/queue.d.ts +160 -0
  48. package/dist/task/queue.d.ts.map +1 -0
  49. package/dist/task/queue.js +337 -0
  50. package/dist/task/queue.js.map +1 -0
  51. package/dist/task/task.d.ts +86 -0
  52. package/dist/task/task.d.ts.map +1 -0
  53. package/dist/task/task.js +201 -0
  54. package/dist/task/task.js.map +1 -0
  55. package/dist/team/messaging.d.ts +106 -0
  56. package/dist/team/messaging.d.ts.map +1 -0
  57. package/dist/team/messaging.js +182 -0
  58. package/dist/team/messaging.js.map +1 -0
  59. package/dist/team/team.d.ts +141 -0
  60. package/dist/team/team.d.ts.map +1 -0
  61. package/dist/team/team.js +282 -0
  62. package/dist/team/team.js.map +1 -0
  63. package/dist/tool/built-in/bash.d.ts +12 -0
  64. package/dist/tool/built-in/bash.d.ts.map +1 -0
  65. package/dist/tool/built-in/bash.js +133 -0
  66. package/dist/tool/built-in/bash.js.map +1 -0
  67. package/dist/tool/built-in/file-edit.d.ts +14 -0
  68. package/dist/tool/built-in/file-edit.d.ts.map +1 -0
  69. package/dist/tool/built-in/file-edit.js +130 -0
  70. package/dist/tool/built-in/file-edit.js.map +1 -0
  71. package/dist/tool/built-in/file-read.d.ts +12 -0
  72. package/dist/tool/built-in/file-read.d.ts.map +1 -0
  73. package/dist/tool/built-in/file-read.js +82 -0
  74. package/dist/tool/built-in/file-read.js.map +1 -0
  75. package/dist/tool/built-in/file-write.d.ts +11 -0
  76. package/dist/tool/built-in/file-write.d.ts.map +1 -0
  77. package/dist/tool/built-in/file-write.js +70 -0
  78. package/dist/tool/built-in/file-write.js.map +1 -0
  79. package/dist/tool/built-in/grep.d.ts +15 -0
  80. package/dist/tool/built-in/grep.d.ts.map +1 -0
  81. package/dist/tool/built-in/grep.js +287 -0
  82. package/dist/tool/built-in/grep.js.map +1 -0
  83. package/dist/tool/built-in/index.d.ts +36 -0
  84. package/dist/tool/built-in/index.d.ts.map +1 -0
  85. package/dist/tool/built-in/index.js +45 -0
  86. package/dist/tool/built-in/index.js.map +1 -0
  87. package/dist/tool/executor.d.ts +71 -0
  88. package/dist/tool/executor.d.ts.map +1 -0
  89. package/dist/tool/executor.js +116 -0
  90. package/dist/tool/executor.js.map +1 -0
  91. package/dist/tool/framework.d.ts +143 -0
  92. package/dist/tool/framework.d.ts.map +1 -0
  93. package/dist/tool/framework.js +371 -0
  94. package/dist/tool/framework.js.map +1 -0
  95. package/dist/types.d.ts +285 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +8 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/utils/semaphore.d.ts +47 -0
  100. package/dist/utils/semaphore.d.ts.map +1 -0
  101. package/dist/utils/semaphore.js +85 -0
  102. package/dist/utils/semaphore.js.map +1 -0
  103. package/examples/01-single-agent.ts +131 -0
  104. package/examples/02-team-collaboration.ts +167 -0
  105. package/examples/03-task-pipeline.ts +201 -0
  106. package/examples/04-multi-model-team.ts +261 -0
  107. package/package.json +49 -0
  108. package/src/agent/agent.ts +364 -0
  109. package/src/agent/pool.ts +278 -0
  110. package/src/agent/runner.ts +413 -0
  111. package/src/index.ts +166 -0
  112. package/src/llm/adapter.ts +74 -0
  113. package/src/llm/anthropic.ts +388 -0
  114. package/src/llm/openai.ts +522 -0
  115. package/src/memory/shared.ts +181 -0
  116. package/src/memory/store.ts +124 -0
  117. package/src/orchestrator/orchestrator.ts +851 -0
  118. package/src/orchestrator/scheduler.ts +352 -0
  119. package/src/task/queue.ts +394 -0
  120. package/src/task/task.ts +232 -0
  121. package/src/team/messaging.ts +230 -0
  122. package/src/team/team.ts +334 -0
  123. package/src/tool/built-in/bash.ts +187 -0
  124. package/src/tool/built-in/file-edit.ts +154 -0
  125. package/src/tool/built-in/file-read.ts +105 -0
  126. package/src/tool/built-in/file-write.ts +81 -0
  127. package/src/tool/built-in/grep.ts +362 -0
  128. package/src/tool/built-in/index.ts +50 -0
  129. package/src/tool/executor.ts +178 -0
  130. package/src/tool/framework.ts +557 -0
  131. package/src/types.ts +362 -0
  132. package/src/utils/semaphore.ts +89 -0
  133. package/tsconfig.json +25 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @fileoverview LLM adapter factory.
3
+ *
4
+ * Re-exports the {@link LLMAdapter} interface and provides a
5
+ * {@link createAdapter} factory that returns the correct concrete
6
+ * implementation based on the requested provider.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { createAdapter } from './adapter.js'
11
+ *
12
+ * const anthropic = createAdapter('anthropic')
13
+ * const openai = createAdapter('openai', process.env.OPENAI_API_KEY)
14
+ * ```
15
+ */
16
+ /**
17
+ * Instantiate the appropriate {@link LLMAdapter} for the given provider.
18
+ *
19
+ * API keys fall back to the standard environment variables
20
+ * (`ANTHROPIC_API_KEY` / `OPENAI_API_KEY`) when not supplied explicitly.
21
+ *
22
+ * Adapters are imported lazily so that projects using only one provider
23
+ * are not forced to install the SDK for the other.
24
+ *
25
+ * @param provider - Which LLM provider to target.
26
+ * @param apiKey - Optional API key override; falls back to env var.
27
+ * @throws {Error} When the provider string is not recognised.
28
+ */
29
+ export async function createAdapter(provider, apiKey) {
30
+ switch (provider) {
31
+ case 'anthropic': {
32
+ const { AnthropicAdapter } = await import('./anthropic.js');
33
+ return new AnthropicAdapter(apiKey);
34
+ }
35
+ case 'openai': {
36
+ const { OpenAIAdapter } = await import('./openai.js');
37
+ return new OpenAIAdapter(apiKey);
38
+ }
39
+ default: {
40
+ // The `never` cast here makes TypeScript enforce exhaustiveness.
41
+ const _exhaustive = provider;
42
+ throw new Error(`Unsupported LLM provider: ${String(_exhaustive)}`);
43
+ }
44
+ }
45
+ }
46
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/llm/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA2BH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAA2B,EAC3B,MAAe;IAEf,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;YAC3D,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAA;QACrC,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;YACrD,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAA;QAClC,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,iEAAiE;YACjE,MAAM,WAAW,GAAU,QAAQ,CAAA;YACnC,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview Anthropic Claude adapter implementing {@link LLMAdapter}.
3
+ *
4
+ * Converts between the framework's internal {@link ContentBlock} types and the
5
+ * Anthropic SDK's wire format, handling tool definitions, system prompts, and
6
+ * both batch and streaming response paths.
7
+ *
8
+ * API key resolution order:
9
+ * 1. `apiKey` constructor argument
10
+ * 2. `ANTHROPIC_API_KEY` environment variable
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { AnthropicAdapter } from './anthropic.js'
15
+ *
16
+ * const adapter = new AnthropicAdapter()
17
+ * const response = await adapter.chat(messages, {
18
+ * model: 'claude-opus-4-6',
19
+ * maxTokens: 1024,
20
+ * })
21
+ * ```
22
+ */
23
+ import type { ContentBlock, ImageBlock, LLMAdapter, LLMChatOptions, LLMMessage, LLMResponse, LLMStreamOptions, LLMToolDef, StreamEvent, TextBlock, ToolResultBlock, ToolUseBlock } from '../types.js';
24
+ /**
25
+ * LLM adapter backed by the Anthropic Claude API.
26
+ *
27
+ * Thread-safe — a single instance may be shared across concurrent agent runs.
28
+ * The underlying SDK client is stateless across requests.
29
+ */
30
+ export declare class AnthropicAdapter implements LLMAdapter {
31
+ #private;
32
+ readonly name = "anthropic";
33
+ constructor(apiKey?: string);
34
+ /**
35
+ * Send a synchronous (non-streaming) chat request and return the complete
36
+ * {@link LLMResponse}.
37
+ *
38
+ * Throws an `Anthropic.APIError` on non-2xx responses. Callers should catch
39
+ * and handle these (e.g. rate limits, context window exceeded).
40
+ */
41
+ chat(messages: LLMMessage[], options: LLMChatOptions): Promise<LLMResponse>;
42
+ /**
43
+ * Send a streaming chat request and yield {@link StreamEvent}s as they
44
+ * arrive from the API.
45
+ *
46
+ * Sequence guarantees:
47
+ * - Zero or more `text` events containing incremental deltas
48
+ * - Zero or more `tool_use` events when the model calls a tool (emitted once
49
+ * per tool use, after input JSON has been fully assembled)
50
+ * - Exactly one terminal event: `done` (with the complete {@link LLMResponse}
51
+ * as `data`) or `error` (with an `Error` as `data`)
52
+ */
53
+ stream(messages: LLMMessage[], options: LLMStreamOptions): AsyncIterable<StreamEvent>;
54
+ }
55
+ export type { ContentBlock, ImageBlock, LLMAdapter, LLMChatOptions, LLMMessage, LLMResponse, LLMStreamOptions, LLMToolDef, StreamEvent, TextBlock, ToolResultBlock, ToolUseBlock, };
56
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/llm/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAaH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,YAAY,EACb,MAAM,aAAa,CAAA;AAqIpB;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,UAAU;;IACjD,QAAQ,CAAC,IAAI,eAAc;gBAIf,MAAM,CAAC,EAAE,MAAM;IAU3B;;;;;;OAMG;IACG,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAmCjF;;;;;;;;;;OAUG;IACI,MAAM,CACX,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,EAAE,gBAAgB,GACxB,aAAa,CAAC,WAAW,CAAC;CAkH9B;AAGD,YAAY,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,YAAY,GACb,CAAA"}
@@ -0,0 +1,307 @@
1
+ /**
2
+ * @fileoverview Anthropic Claude adapter implementing {@link LLMAdapter}.
3
+ *
4
+ * Converts between the framework's internal {@link ContentBlock} types and the
5
+ * Anthropic SDK's wire format, handling tool definitions, system prompts, and
6
+ * both batch and streaming response paths.
7
+ *
8
+ * API key resolution order:
9
+ * 1. `apiKey` constructor argument
10
+ * 2. `ANTHROPIC_API_KEY` environment variable
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { AnthropicAdapter } from './anthropic.js'
15
+ *
16
+ * const adapter = new AnthropicAdapter()
17
+ * const response = await adapter.chat(messages, {
18
+ * model: 'claude-opus-4-6',
19
+ * maxTokens: 1024,
20
+ * })
21
+ * ```
22
+ */
23
+ import Anthropic from '@anthropic-ai/sdk';
24
+ // ---------------------------------------------------------------------------
25
+ // Internal helpers
26
+ // ---------------------------------------------------------------------------
27
+ /**
28
+ * Convert a single framework {@link ContentBlock} into an Anthropic
29
+ * {@link ContentBlockParam} suitable for the `messages` array.
30
+ *
31
+ * `tool_result` blocks are only valid inside `user`-role messages, which is
32
+ * handled by {@link toAnthropicMessages} based on role context.
33
+ */
34
+ function toAnthropicContentBlockParam(block) {
35
+ switch (block.type) {
36
+ case 'text': {
37
+ const param = { type: 'text', text: block.text };
38
+ return param;
39
+ }
40
+ case 'tool_use': {
41
+ const param = {
42
+ type: 'tool_use',
43
+ id: block.id,
44
+ name: block.name,
45
+ input: block.input,
46
+ };
47
+ return param;
48
+ }
49
+ case 'tool_result': {
50
+ const param = {
51
+ type: 'tool_result',
52
+ tool_use_id: block.tool_use_id,
53
+ content: block.content,
54
+ is_error: block.is_error,
55
+ };
56
+ return param;
57
+ }
58
+ case 'image': {
59
+ // Anthropic only accepts a subset of MIME types; we pass them through
60
+ // trusting the caller to supply a valid media_type value.
61
+ const param = {
62
+ type: 'image',
63
+ source: {
64
+ type: 'base64',
65
+ media_type: block.source.media_type,
66
+ data: block.source.data,
67
+ },
68
+ };
69
+ return param;
70
+ }
71
+ default: {
72
+ // Exhaustiveness guard — TypeScript will flag this at compile time if a
73
+ // new variant is added to ContentBlock without updating this switch.
74
+ const _exhaustive = block;
75
+ throw new Error(`Unhandled content block type: ${JSON.stringify(_exhaustive)}`);
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Convert framework messages into Anthropic's `MessageParam[]` format.
81
+ *
82
+ * The Anthropic API requires strict user/assistant alternation. We do not
83
+ * enforce that here — the caller is responsible for producing a valid
84
+ * conversation history.
85
+ */
86
+ function toAnthropicMessages(messages) {
87
+ return messages.map((msg) => ({
88
+ role: msg.role,
89
+ content: msg.content.map(toAnthropicContentBlockParam),
90
+ }));
91
+ }
92
+ /**
93
+ * Convert framework {@link LLMToolDef}s into Anthropic's `Tool` objects.
94
+ *
95
+ * The `inputSchema` on {@link LLMToolDef} is already a plain JSON Schema
96
+ * object, so we just need to reshape the wrapper.
97
+ */
98
+ function toAnthropicTools(tools) {
99
+ return tools.map((t) => ({
100
+ name: t.name,
101
+ description: t.description,
102
+ input_schema: {
103
+ type: 'object',
104
+ ...t.inputSchema,
105
+ },
106
+ }));
107
+ }
108
+ /**
109
+ * Convert an Anthropic SDK `ContentBlock` into a framework {@link ContentBlock}.
110
+ *
111
+ * We only map the subset of SDK types that the framework exposes. Unknown
112
+ * variants (thinking, server_tool_use, etc.) are converted to a text block
113
+ * carrying a stringified representation so data is never silently dropped.
114
+ */
115
+ function fromAnthropicContentBlock(block) {
116
+ switch (block.type) {
117
+ case 'text': {
118
+ const text = { type: 'text', text: block.text };
119
+ return text;
120
+ }
121
+ case 'tool_use': {
122
+ const toolUse = {
123
+ type: 'tool_use',
124
+ id: block.id,
125
+ name: block.name,
126
+ input: block.input,
127
+ };
128
+ return toolUse;
129
+ }
130
+ default: {
131
+ // Graceful degradation for SDK types we don't model (thinking, etc.).
132
+ const fallback = {
133
+ type: 'text',
134
+ text: `[unsupported block type: ${block.type}]`,
135
+ };
136
+ return fallback;
137
+ }
138
+ }
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Adapter implementation
142
+ // ---------------------------------------------------------------------------
143
+ /**
144
+ * LLM adapter backed by the Anthropic Claude API.
145
+ *
146
+ * Thread-safe — a single instance may be shared across concurrent agent runs.
147
+ * The underlying SDK client is stateless across requests.
148
+ */
149
+ export class AnthropicAdapter {
150
+ name = 'anthropic';
151
+ #client;
152
+ constructor(apiKey) {
153
+ this.#client = new Anthropic({
154
+ apiKey: apiKey ?? process.env['ANTHROPIC_API_KEY'],
155
+ });
156
+ }
157
+ // -------------------------------------------------------------------------
158
+ // chat()
159
+ // -------------------------------------------------------------------------
160
+ /**
161
+ * Send a synchronous (non-streaming) chat request and return the complete
162
+ * {@link LLMResponse}.
163
+ *
164
+ * Throws an `Anthropic.APIError` on non-2xx responses. Callers should catch
165
+ * and handle these (e.g. rate limits, context window exceeded).
166
+ */
167
+ async chat(messages, options) {
168
+ const anthropicMessages = toAnthropicMessages(messages);
169
+ const response = await this.#client.messages.create({
170
+ model: options.model,
171
+ max_tokens: options.maxTokens ?? 4096,
172
+ messages: anthropicMessages,
173
+ system: options.systemPrompt,
174
+ tools: options.tools ? toAnthropicTools(options.tools) : undefined,
175
+ temperature: options.temperature,
176
+ }, {
177
+ signal: options.abortSignal,
178
+ });
179
+ const content = response.content.map(fromAnthropicContentBlock);
180
+ return {
181
+ id: response.id,
182
+ content,
183
+ model: response.model,
184
+ stop_reason: response.stop_reason ?? 'end_turn',
185
+ usage: {
186
+ input_tokens: response.usage.input_tokens,
187
+ output_tokens: response.usage.output_tokens,
188
+ },
189
+ };
190
+ }
191
+ // -------------------------------------------------------------------------
192
+ // stream()
193
+ // -------------------------------------------------------------------------
194
+ /**
195
+ * Send a streaming chat request and yield {@link StreamEvent}s as they
196
+ * arrive from the API.
197
+ *
198
+ * Sequence guarantees:
199
+ * - Zero or more `text` events containing incremental deltas
200
+ * - Zero or more `tool_use` events when the model calls a tool (emitted once
201
+ * per tool use, after input JSON has been fully assembled)
202
+ * - Exactly one terminal event: `done` (with the complete {@link LLMResponse}
203
+ * as `data`) or `error` (with an `Error` as `data`)
204
+ */
205
+ async *stream(messages, options) {
206
+ const anthropicMessages = toAnthropicMessages(messages);
207
+ // MessageStream gives us typed events and handles SSE reconnect internally.
208
+ const stream = this.#client.messages.stream({
209
+ model: options.model,
210
+ max_tokens: options.maxTokens ?? 4096,
211
+ messages: anthropicMessages,
212
+ system: options.systemPrompt,
213
+ tools: options.tools ? toAnthropicTools(options.tools) : undefined,
214
+ temperature: options.temperature,
215
+ }, {
216
+ signal: options.abortSignal,
217
+ });
218
+ // Accumulate tool-use input JSON as it streams in.
219
+ // key = content block index, value = partially assembled input JSON string
220
+ const toolInputBuffers = new Map();
221
+ try {
222
+ for await (const event of stream) {
223
+ switch (event.type) {
224
+ case 'content_block_start': {
225
+ const block = event.content_block;
226
+ if (block.type === 'tool_use') {
227
+ toolInputBuffers.set(event.index, {
228
+ id: block.id,
229
+ name: block.name,
230
+ json: '',
231
+ });
232
+ }
233
+ break;
234
+ }
235
+ case 'content_block_delta': {
236
+ const delta = event.delta;
237
+ if (delta.type === 'text_delta') {
238
+ const textEvent = { type: 'text', data: delta.text };
239
+ yield textEvent;
240
+ }
241
+ else if (delta.type === 'input_json_delta') {
242
+ const buf = toolInputBuffers.get(event.index);
243
+ if (buf !== undefined) {
244
+ buf.json += delta.partial_json;
245
+ }
246
+ }
247
+ break;
248
+ }
249
+ case 'content_block_stop': {
250
+ const buf = toolInputBuffers.get(event.index);
251
+ if (buf !== undefined) {
252
+ // Parse the accumulated JSON and emit a tool_use event.
253
+ let parsedInput = {};
254
+ try {
255
+ const parsed = JSON.parse(buf.json);
256
+ if (parsed !== null &&
257
+ typeof parsed === 'object' &&
258
+ !Array.isArray(parsed)) {
259
+ parsedInput = parsed;
260
+ }
261
+ }
262
+ catch {
263
+ // Malformed JSON from the model — surface as an empty object
264
+ // rather than crashing the stream.
265
+ }
266
+ const toolUseBlock = {
267
+ type: 'tool_use',
268
+ id: buf.id,
269
+ name: buf.name,
270
+ input: parsedInput,
271
+ };
272
+ const toolUseEvent = { type: 'tool_use', data: toolUseBlock };
273
+ yield toolUseEvent;
274
+ toolInputBuffers.delete(event.index);
275
+ }
276
+ break;
277
+ }
278
+ // message_start, message_delta, message_stop — we handle the final
279
+ // response via stream.finalMessage() below rather than piecemeal.
280
+ default:
281
+ break;
282
+ }
283
+ }
284
+ // Await the fully assembled final message (token counts, stop_reason, etc.)
285
+ const finalMessage = await stream.finalMessage();
286
+ const content = finalMessage.content.map(fromAnthropicContentBlock);
287
+ const finalResponse = {
288
+ id: finalMessage.id,
289
+ content,
290
+ model: finalMessage.model,
291
+ stop_reason: finalMessage.stop_reason ?? 'end_turn',
292
+ usage: {
293
+ input_tokens: finalMessage.usage.input_tokens,
294
+ output_tokens: finalMessage.usage.output_tokens,
295
+ },
296
+ };
297
+ const doneEvent = { type: 'done', data: finalResponse };
298
+ yield doneEvent;
299
+ }
300
+ catch (err) {
301
+ const error = err instanceof Error ? err : new Error(String(err));
302
+ const errorEvent = { type: 'error', data: error };
303
+ yield errorEvent;
304
+ }
305
+ }
306
+ }
307
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/llm/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview OpenAI adapter implementing {@link LLMAdapter}.
3
+ *
4
+ * Converts between the framework's internal {@link ContentBlock} types and the
5
+ * OpenAI Chat Completions wire format. Key mapping decisions:
6
+ *
7
+ * - Framework `tool_use` blocks in assistant messages → OpenAI `tool_calls`
8
+ * - Framework `tool_result` blocks in user messages → OpenAI `tool` role messages
9
+ * - Framework `image` blocks in user messages → OpenAI image content parts
10
+ * - System prompt in {@link LLMChatOptions} → prepended `system` message
11
+ *
12
+ * Because OpenAI and Anthropic use fundamentally different role-based structures
13
+ * for tool calling (Anthropic embeds tool results in user-role content arrays;
14
+ * OpenAI uses a dedicated `tool` role), the conversion necessarily splits
15
+ * `tool_result` blocks out into separate top-level messages.
16
+ *
17
+ * API key resolution order:
18
+ * 1. `apiKey` constructor argument
19
+ * 2. `OPENAI_API_KEY` environment variable
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { OpenAIAdapter } from './openai.js'
24
+ *
25
+ * const adapter = new OpenAIAdapter()
26
+ * const response = await adapter.chat(messages, {
27
+ * model: 'gpt-5.4',
28
+ * maxTokens: 1024,
29
+ * })
30
+ * ```
31
+ */
32
+ import type { ContentBlock, LLMAdapter, LLMChatOptions, LLMMessage, LLMResponse, LLMStreamOptions, LLMToolDef, StreamEvent } from '../types.js';
33
+ /**
34
+ * LLM adapter backed by the OpenAI Chat Completions API.
35
+ *
36
+ * Thread-safe — a single instance may be shared across concurrent agent runs.
37
+ */
38
+ export declare class OpenAIAdapter implements LLMAdapter {
39
+ #private;
40
+ readonly name = "openai";
41
+ constructor(apiKey?: string);
42
+ /**
43
+ * Send a synchronous (non-streaming) chat request and return the complete
44
+ * {@link LLMResponse}.
45
+ *
46
+ * Throws an `OpenAI.APIError` on non-2xx responses. Callers should catch and
47
+ * handle these (e.g. rate limits, context length exceeded).
48
+ */
49
+ chat(messages: LLMMessage[], options: LLMChatOptions): Promise<LLMResponse>;
50
+ /**
51
+ * Send a streaming chat request and yield {@link StreamEvent}s incrementally.
52
+ *
53
+ * Sequence guarantees match {@link AnthropicAdapter.stream}:
54
+ * - Zero or more `text` events
55
+ * - Zero or more `tool_use` events (emitted once per tool call, after
56
+ * arguments have been fully assembled)
57
+ * - Exactly one terminal event: `done` or `error`
58
+ */
59
+ stream(messages: LLMMessage[], options: LLMStreamOptions): AsyncIterable<StreamEvent>;
60
+ }
61
+ export type { ContentBlock, LLMAdapter, LLMChatOptions, LLMMessage, LLMResponse, LLMStreamOptions, LLMToolDef, StreamEvent, };
62
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/llm/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAcH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EAGZ,MAAM,aAAa,CAAA;AAwOpB;;;;GAIG;AACH,qBAAa,aAAc,YAAW,UAAU;;IAC9C,QAAQ,CAAC,IAAI,YAAW;gBAIZ,MAAM,CAAC,EAAE,MAAM;IAU3B;;;;;;OAMG;IACG,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAwBjF;;;;;;;;OAQG;IACI,MAAM,CACX,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,EAAE,gBAAgB,GACxB,aAAa,CAAC,WAAW,CAAC;CAsI9B;AA4BD,YAAY,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,GACZ,CAAA"}