@open-multi-agent/core 1.4.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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +373 -0
  3. package/dist/agent/agent.d.ts +153 -0
  4. package/dist/agent/agent.d.ts.map +1 -0
  5. package/dist/agent/agent.js +559 -0
  6. package/dist/agent/agent.js.map +1 -0
  7. package/dist/agent/loop-detector.d.ts +39 -0
  8. package/dist/agent/loop-detector.d.ts.map +1 -0
  9. package/dist/agent/loop-detector.js +122 -0
  10. package/dist/agent/loop-detector.js.map +1 -0
  11. package/dist/agent/pool.d.ts +158 -0
  12. package/dist/agent/pool.d.ts.map +1 -0
  13. package/dist/agent/pool.js +320 -0
  14. package/dist/agent/pool.js.map +1 -0
  15. package/dist/agent/runner.d.ts +242 -0
  16. package/dist/agent/runner.d.ts.map +1 -0
  17. package/dist/agent/runner.js +943 -0
  18. package/dist/agent/runner.js.map +1 -0
  19. package/dist/agent/structured-output.d.ts +33 -0
  20. package/dist/agent/structured-output.d.ts.map +1 -0
  21. package/dist/agent/structured-output.js +116 -0
  22. package/dist/agent/structured-output.js.map +1 -0
  23. package/dist/cli/oma.d.ts +30 -0
  24. package/dist/cli/oma.d.ts.map +1 -0
  25. package/dist/cli/oma.js +433 -0
  26. package/dist/cli/oma.js.map +1 -0
  27. package/dist/dashboard/layout-tasks.d.ts +23 -0
  28. package/dist/dashboard/layout-tasks.d.ts.map +1 -0
  29. package/dist/dashboard/layout-tasks.js +79 -0
  30. package/dist/dashboard/layout-tasks.js.map +1 -0
  31. package/dist/dashboard/render-team-run-dashboard.d.ts +11 -0
  32. package/dist/dashboard/render-team-run-dashboard.d.ts.map +1 -0
  33. package/dist/dashboard/render-team-run-dashboard.js +456 -0
  34. package/dist/dashboard/render-team-run-dashboard.js.map +1 -0
  35. package/dist/errors.d.ts +14 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +20 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/index.d.ts +79 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +92 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/llm/adapter.d.ts +54 -0
  44. package/dist/llm/adapter.d.ts.map +1 -0
  45. package/dist/llm/adapter.js +101 -0
  46. package/dist/llm/adapter.js.map +1 -0
  47. package/dist/llm/anthropic.d.ts +57 -0
  48. package/dist/llm/anthropic.d.ts.map +1 -0
  49. package/dist/llm/anthropic.js +432 -0
  50. package/dist/llm/anthropic.js.map +1 -0
  51. package/dist/llm/azure-openai.d.ts +74 -0
  52. package/dist/llm/azure-openai.d.ts.map +1 -0
  53. package/dist/llm/azure-openai.js +267 -0
  54. package/dist/llm/azure-openai.js.map +1 -0
  55. package/dist/llm/bedrock.d.ts +41 -0
  56. package/dist/llm/bedrock.d.ts.map +1 -0
  57. package/dist/llm/bedrock.js +345 -0
  58. package/dist/llm/bedrock.js.map +1 -0
  59. package/dist/llm/copilot.d.ts +92 -0
  60. package/dist/llm/copilot.d.ts.map +1 -0
  61. package/dist/llm/copilot.js +433 -0
  62. package/dist/llm/copilot.js.map +1 -0
  63. package/dist/llm/deepseek.d.ts +21 -0
  64. package/dist/llm/deepseek.d.ts.map +1 -0
  65. package/dist/llm/deepseek.js +24 -0
  66. package/dist/llm/deepseek.js.map +1 -0
  67. package/dist/llm/gemini.d.ts +65 -0
  68. package/dist/llm/gemini.d.ts.map +1 -0
  69. package/dist/llm/gemini.js +427 -0
  70. package/dist/llm/gemini.js.map +1 -0
  71. package/dist/llm/grok.d.ts +21 -0
  72. package/dist/llm/grok.d.ts.map +1 -0
  73. package/dist/llm/grok.js +24 -0
  74. package/dist/llm/grok.js.map +1 -0
  75. package/dist/llm/minimax.d.ts +21 -0
  76. package/dist/llm/minimax.d.ts.map +1 -0
  77. package/dist/llm/minimax.js +24 -0
  78. package/dist/llm/minimax.js.map +1 -0
  79. package/dist/llm/openai-common.d.ts +65 -0
  80. package/dist/llm/openai-common.d.ts.map +1 -0
  81. package/dist/llm/openai-common.js +286 -0
  82. package/dist/llm/openai-common.js.map +1 -0
  83. package/dist/llm/openai.d.ts +63 -0
  84. package/dist/llm/openai.d.ts.map +1 -0
  85. package/dist/llm/openai.js +256 -0
  86. package/dist/llm/openai.js.map +1 -0
  87. package/dist/llm/qiniu.d.ts +21 -0
  88. package/dist/llm/qiniu.d.ts.map +1 -0
  89. package/dist/llm/qiniu.js +24 -0
  90. package/dist/llm/qiniu.js.map +1 -0
  91. package/dist/mcp.d.ts +3 -0
  92. package/dist/mcp.d.ts.map +1 -0
  93. package/dist/mcp.js +2 -0
  94. package/dist/mcp.js.map +1 -0
  95. package/dist/memory/shared.d.ts +162 -0
  96. package/dist/memory/shared.d.ts.map +1 -0
  97. package/dist/memory/shared.js +294 -0
  98. package/dist/memory/shared.js.map +1 -0
  99. package/dist/memory/store.d.ts +72 -0
  100. package/dist/memory/store.d.ts.map +1 -0
  101. package/dist/memory/store.js +121 -0
  102. package/dist/memory/store.js.map +1 -0
  103. package/dist/orchestrator/orchestrator.d.ts +245 -0
  104. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  105. package/dist/orchestrator/orchestrator.js +1400 -0
  106. package/dist/orchestrator/orchestrator.js.map +1 -0
  107. package/dist/orchestrator/scheduler.d.ts +112 -0
  108. package/dist/orchestrator/scheduler.d.ts.map +1 -0
  109. package/dist/orchestrator/scheduler.js +256 -0
  110. package/dist/orchestrator/scheduler.js.map +1 -0
  111. package/dist/task/queue.d.ts +191 -0
  112. package/dist/task/queue.d.ts.map +1 -0
  113. package/dist/task/queue.js +408 -0
  114. package/dist/task/queue.js.map +1 -0
  115. package/dist/task/task.d.ts +90 -0
  116. package/dist/task/task.d.ts.map +1 -0
  117. package/dist/task/task.js +206 -0
  118. package/dist/task/task.js.map +1 -0
  119. package/dist/team/messaging.d.ts +106 -0
  120. package/dist/team/messaging.d.ts.map +1 -0
  121. package/dist/team/messaging.js +183 -0
  122. package/dist/team/messaging.js.map +1 -0
  123. package/dist/team/team.d.ts +141 -0
  124. package/dist/team/team.d.ts.map +1 -0
  125. package/dist/team/team.js +293 -0
  126. package/dist/team/team.js.map +1 -0
  127. package/dist/tool/built-in/bash.d.ts +12 -0
  128. package/dist/tool/built-in/bash.d.ts.map +1 -0
  129. package/dist/tool/built-in/bash.js +133 -0
  130. package/dist/tool/built-in/bash.js.map +1 -0
  131. package/dist/tool/built-in/delegate.d.ts +29 -0
  132. package/dist/tool/built-in/delegate.d.ts.map +1 -0
  133. package/dist/tool/built-in/delegate.js +92 -0
  134. package/dist/tool/built-in/delegate.js.map +1 -0
  135. package/dist/tool/built-in/file-edit.d.ts +14 -0
  136. package/dist/tool/built-in/file-edit.d.ts.map +1 -0
  137. package/dist/tool/built-in/file-edit.js +130 -0
  138. package/dist/tool/built-in/file-edit.js.map +1 -0
  139. package/dist/tool/built-in/file-read.d.ts +12 -0
  140. package/dist/tool/built-in/file-read.d.ts.map +1 -0
  141. package/dist/tool/built-in/file-read.js +82 -0
  142. package/dist/tool/built-in/file-read.js.map +1 -0
  143. package/dist/tool/built-in/file-write.d.ts +11 -0
  144. package/dist/tool/built-in/file-write.d.ts.map +1 -0
  145. package/dist/tool/built-in/file-write.js +70 -0
  146. package/dist/tool/built-in/file-write.js.map +1 -0
  147. package/dist/tool/built-in/fs-walk.d.ts +23 -0
  148. package/dist/tool/built-in/fs-walk.d.ts.map +1 -0
  149. package/dist/tool/built-in/fs-walk.js +78 -0
  150. package/dist/tool/built-in/fs-walk.js.map +1 -0
  151. package/dist/tool/built-in/glob.d.ts +12 -0
  152. package/dist/tool/built-in/glob.d.ts.map +1 -0
  153. package/dist/tool/built-in/glob.js +82 -0
  154. package/dist/tool/built-in/glob.js.map +1 -0
  155. package/dist/tool/built-in/grep.d.ts +15 -0
  156. package/dist/tool/built-in/grep.d.ts.map +1 -0
  157. package/dist/tool/built-in/grep.js +218 -0
  158. package/dist/tool/built-in/grep.js.map +1 -0
  159. package/dist/tool/built-in/index.d.ts +48 -0
  160. package/dist/tool/built-in/index.d.ts.map +1 -0
  161. package/dist/tool/built-in/index.js +56 -0
  162. package/dist/tool/built-in/index.js.map +1 -0
  163. package/dist/tool/executor.d.ts +100 -0
  164. package/dist/tool/executor.d.ts.map +1 -0
  165. package/dist/tool/executor.js +184 -0
  166. package/dist/tool/executor.js.map +1 -0
  167. package/dist/tool/framework.d.ts +167 -0
  168. package/dist/tool/framework.d.ts.map +1 -0
  169. package/dist/tool/framework.js +402 -0
  170. package/dist/tool/framework.js.map +1 -0
  171. package/dist/tool/mcp.d.ts +31 -0
  172. package/dist/tool/mcp.d.ts.map +1 -0
  173. package/dist/tool/mcp.js +175 -0
  174. package/dist/tool/mcp.js.map +1 -0
  175. package/dist/tool/text-tool-extractor.d.ts +32 -0
  176. package/dist/tool/text-tool-extractor.d.ts.map +1 -0
  177. package/dist/tool/text-tool-extractor.js +195 -0
  178. package/dist/tool/text-tool-extractor.js.map +1 -0
  179. package/dist/types.d.ts +916 -0
  180. package/dist/types.d.ts.map +1 -0
  181. package/dist/types.js +8 -0
  182. package/dist/types.js.map +1 -0
  183. package/dist/utils/keywords.d.ts +18 -0
  184. package/dist/utils/keywords.d.ts.map +1 -0
  185. package/dist/utils/keywords.js +32 -0
  186. package/dist/utils/keywords.js.map +1 -0
  187. package/dist/utils/semaphore.d.ts +49 -0
  188. package/dist/utils/semaphore.d.ts.map +1 -0
  189. package/dist/utils/semaphore.js +89 -0
  190. package/dist/utils/semaphore.js.map +1 -0
  191. package/dist/utils/tokens.d.ts +7 -0
  192. package/dist/utils/tokens.d.ts.map +1 -0
  193. package/dist/utils/tokens.js +30 -0
  194. package/dist/utils/tokens.js.map +1 -0
  195. package/dist/utils/trace.d.ts +12 -0
  196. package/dist/utils/trace.d.ts.map +1 -0
  197. package/dist/utils/trace.js +30 -0
  198. package/dist/utils/trace.js.map +1 -0
  199. package/docs/DECISIONS.md +49 -0
  200. package/docs/cli.md +265 -0
  201. package/docs/context-management.md +24 -0
  202. package/docs/featured-partner.md +28 -0
  203. package/docs/observability.md +56 -0
  204. package/docs/providers.md +78 -0
  205. package/docs/shared-memory.md +27 -0
  206. package/docs/tool-configuration.md +152 -0
  207. package/package.json +96 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * @fileoverview Azure OpenAI adapter implementing {@link LLMAdapter}.
3
+ *
4
+ * Azure OpenAI uses regional deployment endpoints and API versioning that differ
5
+ * from standard OpenAI:
6
+ *
7
+ * - Endpoint: `https://{resource-name}.openai.azure.com`
8
+ * - API version: Query parameter (e.g., `?api-version=2024-10-21`)
9
+ * - Model/Deployment: Users deploy models with custom names; the `model` field
10
+ * in agent config should contain the Azure deployment name, not the underlying
11
+ * model name (e.g., `model: 'my-gpt4-deployment'`)
12
+ *
13
+ * The OpenAI SDK provides an `AzureOpenAI` client class that handles these
14
+ * Azure-specific requirements. This adapter uses that client while reusing all
15
+ * message conversion logic from `openai-common.ts`.
16
+ *
17
+ * Environment variable resolution order:
18
+ * 1. Constructor arguments
19
+ * 2. `AZURE_OPENAI_API_KEY` environment variable
20
+ * 3. `AZURE_OPENAI_ENDPOINT` environment variable
21
+ * 4. `AZURE_OPENAI_API_VERSION` environment variable (defaults to '2024-10-21')
22
+ * 5. `AZURE_OPENAI_DEPLOYMENT` as an optional fallback when `model` is blank
23
+ *
24
+ * Note: Azure introduced a next-generation v1 API (August 2025) that uses the standard
25
+ * OpenAI() client with baseURL set to `{endpoint}/openai/v1/` and requires no api-version.
26
+ * That path is not yet supported by this adapter. To use it, pass `provider: 'openai'`
27
+ * with `baseURL: 'https://{resource}.openai.azure.com/openai/v1/'` in your agent config.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { AzureOpenAIAdapter } from './azure-openai.js'
32
+ *
33
+ * const adapter = new AzureOpenAIAdapter()
34
+ * const response = await adapter.chat(messages, {
35
+ * model: 'my-gpt4-deployment', // Azure deployment name, not 'gpt-4'
36
+ * maxTokens: 1024,
37
+ * })
38
+ * ```
39
+ */
40
+ import { AzureOpenAI } from 'openai';
41
+ import { toOpenAITool, fromOpenAICompletion, normalizeFinishReason, buildOpenAIMessageList, } from './openai-common.js';
42
+ import { extractToolCallsFromText } from '../tool/text-tool-extractor.js';
43
+ // ---------------------------------------------------------------------------
44
+ // Adapter implementation
45
+ // ---------------------------------------------------------------------------
46
+ const DEFAULT_AZURE_OPENAI_API_VERSION = '2024-10-21';
47
+ function resolveAzureDeploymentName(model) {
48
+ const explicitModel = model.trim();
49
+ if (explicitModel.length > 0)
50
+ return explicitModel;
51
+ const fallbackDeployment = process.env['AZURE_OPENAI_DEPLOYMENT']?.trim();
52
+ if (fallbackDeployment !== undefined && fallbackDeployment.length > 0) {
53
+ return fallbackDeployment;
54
+ }
55
+ throw new Error('Azure OpenAI deployment is required. Set agent model to your deployment name, or set AZURE_OPENAI_DEPLOYMENT.');
56
+ }
57
+ /**
58
+ * LLM adapter backed by Azure OpenAI Chat Completions API.
59
+ *
60
+ * Thread-safe — a single instance may be shared across concurrent agent runs.
61
+ */
62
+ export class AzureOpenAIAdapter {
63
+ name = 'azure-openai';
64
+ #client;
65
+ /**
66
+ * @param apiKey - Azure OpenAI API key (falls back to AZURE_OPENAI_API_KEY env var)
67
+ * @param endpoint - Azure endpoint URL (falls back to AZURE_OPENAI_ENDPOINT env var)
68
+ * @param apiVersion - API version string (falls back to AZURE_OPENAI_API_VERSION, defaults to '2024-10-21')
69
+ */
70
+ constructor(apiKey, endpoint, apiVersion) {
71
+ this.#client = new AzureOpenAI({
72
+ apiKey: apiKey ?? process.env['AZURE_OPENAI_API_KEY'],
73
+ endpoint: endpoint ?? process.env['AZURE_OPENAI_ENDPOINT'],
74
+ apiVersion: apiVersion ?? process.env['AZURE_OPENAI_API_VERSION'] ?? DEFAULT_AZURE_OPENAI_API_VERSION,
75
+ });
76
+ }
77
+ // -------------------------------------------------------------------------
78
+ // chat()
79
+ // -------------------------------------------------------------------------
80
+ /**
81
+ * Send a synchronous (non-streaming) chat request and return the complete
82
+ * {@link LLMResponse}.
83
+ *
84
+ * Throws an `AzureOpenAI.APIError` on non-2xx responses. Callers should catch and
85
+ * handle these (e.g. rate limits, context length exceeded, deployment not found).
86
+ */
87
+ async chat(messages, options) {
88
+ const deploymentName = resolveAzureDeploymentName(options.model);
89
+ const openAIMessages = buildOpenAIMessageList(messages, options.systemPrompt);
90
+ const completion = await this.#client.chat.completions.create({
91
+ // Sampling params first so extraBody can override them. Structural
92
+ // fields (model/messages/tools/stream) come after extraBody so users
93
+ // cannot accidentally clobber them via extraBody.
94
+ // `top_k` / `min_p` deliberately omitted — vLLM-only, not accepted
95
+ // by Azure OpenAI's hosted endpoint.
96
+ max_tokens: options.maxTokens,
97
+ temperature: options.temperature,
98
+ frequency_penalty: options.frequencyPenalty,
99
+ presence_penalty: options.presencePenalty,
100
+ top_p: options.topP,
101
+ parallel_tool_calls: options.parallelToolCalls,
102
+ reasoning_effort: options.thinking?.effort,
103
+ ...options.extraBody,
104
+ model: deploymentName,
105
+ messages: openAIMessages,
106
+ tools: options.tools ? options.tools.map(toOpenAITool) : undefined,
107
+ stream: false,
108
+ }, {
109
+ signal: options.abortSignal,
110
+ });
111
+ const toolNames = options.tools?.map(t => t.name);
112
+ return fromOpenAICompletion(completion, toolNames);
113
+ }
114
+ // -------------------------------------------------------------------------
115
+ // stream()
116
+ // -------------------------------------------------------------------------
117
+ /**
118
+ * Send a streaming chat request and yield {@link StreamEvent}s incrementally.
119
+ *
120
+ * Sequence guarantees match {@link OpenAIAdapter.stream}:
121
+ * - Zero or more `text` events
122
+ * - Zero or more `tool_use` events (emitted once per tool call, after
123
+ * arguments have been fully assembled)
124
+ * - Exactly one terminal event: `done` or `error`
125
+ */
126
+ async *stream(messages, options) {
127
+ const deploymentName = resolveAzureDeploymentName(options.model);
128
+ const openAIMessages = buildOpenAIMessageList(messages, options.systemPrompt);
129
+ // We request usage in the final chunk so we can include it in the `done` event.
130
+ const streamResponse = await this.#client.chat.completions.create({
131
+ // See chat() above for the field-ordering rationale and the
132
+ // `top_k` / `min_p` exclusion.
133
+ max_tokens: options.maxTokens,
134
+ temperature: options.temperature,
135
+ frequency_penalty: options.frequencyPenalty,
136
+ presence_penalty: options.presencePenalty,
137
+ top_p: options.topP,
138
+ parallel_tool_calls: options.parallelToolCalls,
139
+ reasoning_effort: options.thinking?.effort,
140
+ ...options.extraBody,
141
+ model: deploymentName,
142
+ messages: openAIMessages,
143
+ tools: options.tools ? options.tools.map(toOpenAITool) : undefined,
144
+ stream: true,
145
+ stream_options: { include_usage: true },
146
+ }, {
147
+ signal: options.abortSignal,
148
+ });
149
+ // Accumulate state across chunks.
150
+ let completionId = '';
151
+ let completionModel = '';
152
+ let finalFinishReason = 'stop';
153
+ let inputTokens = 0;
154
+ let outputTokens = 0;
155
+ // tool_calls are streamed piecemeal; key = tool call index
156
+ const toolCallBuffers = new Map();
157
+ // Full text accumulator for the `done` response.
158
+ let fullText = '';
159
+ try {
160
+ for await (const chunk of streamResponse) {
161
+ completionId = chunk.id;
162
+ completionModel = chunk.model;
163
+ // Usage is only populated in the final chunk when stream_options.include_usage is set.
164
+ if (chunk.usage !== null && chunk.usage !== undefined) {
165
+ inputTokens = chunk.usage.prompt_tokens;
166
+ outputTokens = chunk.usage.completion_tokens;
167
+ }
168
+ const choice = chunk.choices[0];
169
+ if (choice === undefined)
170
+ continue;
171
+ const delta = choice.delta;
172
+ // --- text delta ---
173
+ if (delta.content !== null && delta.content !== undefined) {
174
+ fullText += delta.content;
175
+ const textEvent = { type: 'text', data: delta.content };
176
+ yield textEvent;
177
+ }
178
+ // --- tool call delta ---
179
+ for (const toolCallDelta of delta.tool_calls ?? []) {
180
+ const idx = toolCallDelta.index;
181
+ if (!toolCallBuffers.has(idx)) {
182
+ toolCallBuffers.set(idx, {
183
+ id: toolCallDelta.id ?? '',
184
+ name: toolCallDelta.function?.name ?? '',
185
+ argsJson: '',
186
+ });
187
+ }
188
+ const buf = toolCallBuffers.get(idx);
189
+ // buf is guaranteed to exist: we just set it above.
190
+ if (buf !== undefined) {
191
+ if (toolCallDelta.id)
192
+ buf.id = toolCallDelta.id;
193
+ if (toolCallDelta.function?.name)
194
+ buf.name = toolCallDelta.function.name;
195
+ if (toolCallDelta.function?.arguments) {
196
+ buf.argsJson += toolCallDelta.function.arguments;
197
+ }
198
+ }
199
+ }
200
+ if (choice.finish_reason !== null && choice.finish_reason !== undefined) {
201
+ finalFinishReason = choice.finish_reason;
202
+ }
203
+ }
204
+ // Emit accumulated tool_use events after the stream ends.
205
+ const finalToolUseBlocks = [];
206
+ for (const buf of toolCallBuffers.values()) {
207
+ let parsedInput = {};
208
+ try {
209
+ const parsed = JSON.parse(buf.argsJson);
210
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
211
+ parsedInput = parsed;
212
+ }
213
+ }
214
+ catch {
215
+ // Malformed JSON — surface as empty object.
216
+ }
217
+ const toolUseBlock = {
218
+ type: 'tool_use',
219
+ id: buf.id,
220
+ name: buf.name,
221
+ input: parsedInput,
222
+ };
223
+ finalToolUseBlocks.push(toolUseBlock);
224
+ const toolUseEvent = { type: 'tool_use', data: toolUseBlock };
225
+ yield toolUseEvent;
226
+ }
227
+ // Build the complete content array for the done response.
228
+ const doneContent = [];
229
+ if (fullText.length > 0) {
230
+ const textBlock = { type: 'text', text: fullText };
231
+ doneContent.push(textBlock);
232
+ }
233
+ doneContent.push(...finalToolUseBlocks);
234
+ // Fallback: extract tool calls from text when streaming produced no
235
+ // native tool_calls (same logic as fromOpenAICompletion).
236
+ if (finalToolUseBlocks.length === 0 && fullText.length > 0 && options.tools) {
237
+ const toolNames = options.tools.map(t => t.name);
238
+ const extracted = extractToolCallsFromText(fullText, toolNames);
239
+ if (extracted.length > 0) {
240
+ doneContent.push(...extracted);
241
+ for (const block of extracted) {
242
+ yield { type: 'tool_use', data: block };
243
+ }
244
+ }
245
+ }
246
+ const hasToolUseBlocks = doneContent.some(b => b.type === 'tool_use');
247
+ const resolvedStopReason = hasToolUseBlocks && finalFinishReason === 'stop'
248
+ ? 'tool_use'
249
+ : normalizeFinishReason(finalFinishReason);
250
+ const finalResponse = {
251
+ id: completionId,
252
+ content: doneContent,
253
+ model: completionModel,
254
+ stop_reason: resolvedStopReason,
255
+ usage: { input_tokens: inputTokens, output_tokens: outputTokens },
256
+ };
257
+ const doneEvent = { type: 'done', data: finalResponse };
258
+ yield doneEvent;
259
+ }
260
+ catch (err) {
261
+ const error = err instanceof Error ? err : new Error(String(err));
262
+ const errorEvent = { type: 'error', data: error };
263
+ yield errorEvent;
264
+ }
265
+ }
266
+ }
267
+ //# sourceMappingURL=azure-openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure-openai.js","sourceRoot":"","sources":["../../src/llm/azure-openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @fileoverview AWS Bedrock LLM adapter implementing {@link LLMAdapter}.
3
+ *
4
+ * Uses the Converse / ConverseStream APIs from `@aws-sdk/client-bedrock-runtime`
5
+ * (the unified Anthropic-shaped schema) so the same adapter works across Claude,
6
+ * Llama, Mistral, Cohere, and Titan model families without per-model shims.
7
+ *
8
+ * Region resolution order:
9
+ * 1. `region` constructor argument
10
+ * 2. `AWS_REGION` environment variable
11
+ * 3. `'us-east-1'` (hard fallback)
12
+ *
13
+ * AWS credentials are resolved via the SDK default provider chain:
14
+ * env vars → shared config file → EC2/ECS/Lambda IAM role.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { BedrockAdapter } from './bedrock.js'
19
+ *
20
+ * const adapter = new BedrockAdapter('us-east-1')
21
+ * const response = await adapter.chat(messages, {
22
+ * model: 'anthropic.claude-3-5-haiku-20241022-v1:0',
23
+ * maxTokens: 1024,
24
+ * })
25
+ * ```
26
+ */
27
+ import type { ContentBlock, ImageBlock, LLMAdapter, LLMChatOptions, LLMMessage, LLMResponse, LLMStreamOptions, LLMToolDef, StreamEvent, TextBlock, ToolResultBlock, ToolUseBlock } from '../types.js';
28
+ /**
29
+ * LLM adapter backed by AWS Bedrock Converse / ConverseStream APIs.
30
+ *
31
+ * Thread-safe — a single instance may be shared across concurrent agent runs.
32
+ */
33
+ export declare class BedrockAdapter implements LLMAdapter {
34
+ #private;
35
+ readonly name = "bedrock";
36
+ constructor(region?: string);
37
+ chat(messages: LLMMessage[], options: LLMChatOptions): Promise<LLMResponse>;
38
+ stream(messages: LLMMessage[], options: LLMStreamOptions): AsyncIterable<StreamEvent>;
39
+ }
40
+ export type { ContentBlock, ImageBlock, LLMAdapter, LLMChatOptions, LLMMessage, LLMResponse, LLMStreamOptions, LLMToolDef, StreamEvent, TextBlock, ToolResultBlock, ToolUseBlock };
41
+ //# sourceMappingURL=bedrock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bedrock.d.ts","sourceRoot":"","sources":["../../src/llm/bedrock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAeH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EAEV,WAAW,EACX,SAAS,EACT,eAAe,EACf,YAAY,EACb,MAAM,aAAa,CAAA;AA2JpB;;;;GAIG;AACH,qBAAa,cAAe,YAAW,UAAU;;IAC/C,QAAQ,CAAC,IAAI,aAAY;gBAIb,MAAM,CAAC,EAAE,MAAM;IASrB,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IA4C1E,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAAC,WAAW,CAAC;CAkI7F;AAED,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,345 @@
1
+ /**
2
+ * @fileoverview AWS Bedrock LLM adapter implementing {@link LLMAdapter}.
3
+ *
4
+ * Uses the Converse / ConverseStream APIs from `@aws-sdk/client-bedrock-runtime`
5
+ * (the unified Anthropic-shaped schema) so the same adapter works across Claude,
6
+ * Llama, Mistral, Cohere, and Titan model families without per-model shims.
7
+ *
8
+ * Region resolution order:
9
+ * 1. `region` constructor argument
10
+ * 2. `AWS_REGION` environment variable
11
+ * 3. `'us-east-1'` (hard fallback)
12
+ *
13
+ * AWS credentials are resolved via the SDK default provider chain:
14
+ * env vars → shared config file → EC2/ECS/Lambda IAM role.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { BedrockAdapter } from './bedrock.js'
19
+ *
20
+ * const adapter = new BedrockAdapter('us-east-1')
21
+ * const response = await adapter.chat(messages, {
22
+ * model: 'anthropic.claude-3-5-haiku-20241022-v1:0',
23
+ * maxTokens: 1024,
24
+ * })
25
+ * ```
26
+ */
27
+ import { BedrockRuntimeClient, ConverseCommand, ConverseStreamCommand, } from '@aws-sdk/client-bedrock-runtime';
28
+ // ---------------------------------------------------------------------------
29
+ // Internal helpers
30
+ // ---------------------------------------------------------------------------
31
+ const MEDIA_TYPE_TO_FORMAT = {
32
+ 'image/jpeg': 'jpeg',
33
+ 'image/png': 'png',
34
+ 'image/gif': 'gif',
35
+ 'image/webp': 'webp',
36
+ };
37
+ function base64ToUint8Array(b64) {
38
+ return Buffer.from(b64, 'base64');
39
+ }
40
+ /**
41
+ * Convert a single framework {@link ContentBlock} into a Bedrock
42
+ * {@link BedrockContentBlock} for the messages array.
43
+ *
44
+ * Reasoning blocks are dropped on input — see the `case 'reasoning'` arm below
45
+ * for the round-trip limitation that forces this.
46
+ */
47
+ function toBedrockContentBlock(block) {
48
+ switch (block.type) {
49
+ case 'text':
50
+ return { text: block.text };
51
+ case 'tool_use':
52
+ // DocumentType is not publicly exported from the SDK; cast the whole block.
53
+ return {
54
+ toolUse: { toolUseId: block.id, name: block.name, input: block.input },
55
+ };
56
+ case 'tool_result': {
57
+ const rawContent = block.content;
58
+ const textContent = typeof rawContent === 'string' ? rawContent : JSON.stringify(rawContent);
59
+ return {
60
+ toolResult: {
61
+ toolUseId: block.tool_use_id,
62
+ content: [{ text: textContent }],
63
+ status: block.is_error ? 'error' : 'success',
64
+ },
65
+ };
66
+ }
67
+ case 'image': {
68
+ const format = MEDIA_TYPE_TO_FORMAT[block.source.media_type] ?? 'png';
69
+ return {
70
+ image: {
71
+ format,
72
+ source: { bytes: base64ToUint8Array(block.source.data) },
73
+ },
74
+ };
75
+ }
76
+ case 'reasoning':
77
+ // Bedrock requires the original reasoning text plus its `signature`
78
+ // (and `redactedData` for redacted blocks) to be echoed back unchanged
79
+ // when continuing a multi-turn tool-use conversation with extended
80
+ // thinking. The IR now carries these fields on {@link ReasoningBlock}
81
+ // (added in #200), but wiring them through Bedrock's
82
+ // `reasoningContent.reasoningText.signature` shape has been deferred
83
+ // to a follow-up PR — until then, we drop reasoning on input.
84
+ return null;
85
+ default: {
86
+ const _exhaustive = block;
87
+ throw new Error(`Unhandled content block type: ${JSON.stringify(_exhaustive)}`);
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Convert framework messages into Bedrock `Message[]`.
93
+ *
94
+ * System prompt is passed separately via `options.systemPrompt` and handled
95
+ * in `chat()`/`stream()` — it never appears as a message role in the framework.
96
+ * Reasoning blocks are silently dropped on input — see {@link toBedrockContentBlock}
97
+ * for why; multi-turn tool-use flows with extended thinking are tracked as
98
+ * a follow-up to #200's phase-1 IR additions.
99
+ */
100
+ function toBedrockMessages(messages) {
101
+ const bedrockMessages = [];
102
+ for (const msg of messages) {
103
+ const content = [];
104
+ for (const block of msg.content) {
105
+ const converted = toBedrockContentBlock(block);
106
+ if (converted !== null)
107
+ content.push(converted);
108
+ }
109
+ if (content.length > 0) {
110
+ bedrockMessages.push({ role: msg.role, content });
111
+ }
112
+ }
113
+ return bedrockMessages;
114
+ }
115
+ function toBedrockTools(tools) {
116
+ // Tool is a discriminated union with a required $unknown variant; cast to satisfy it.
117
+ const bedrockTools = tools.map((t) => ({
118
+ toolSpec: {
119
+ name: t.name,
120
+ description: t.description,
121
+ inputSchema: { json: t.inputSchema },
122
+ },
123
+ }));
124
+ return { tools: bedrockTools };
125
+ }
126
+ /**
127
+ * Convert a Bedrock response {@link BedrockContentBlock} into a framework
128
+ * {@link ContentBlock}.
129
+ *
130
+ * `toolUse.input` arrives as a parsed object in chat() responses.
131
+ */
132
+ function fromBedrockContentBlock(block) {
133
+ if (block.text !== undefined) {
134
+ const text = { type: 'text', text: block.text };
135
+ return text;
136
+ }
137
+ if (block.toolUse !== undefined) {
138
+ const toolUse = {
139
+ type: 'tool_use',
140
+ id: block.toolUse.toolUseId ?? '',
141
+ name: block.toolUse.name ?? '',
142
+ input: block.toolUse.input ?? {},
143
+ };
144
+ return toolUse;
145
+ }
146
+ if (block.reasoningContent !== undefined) {
147
+ const r = block.reasoningContent;
148
+ const reasoning = {
149
+ type: 'reasoning',
150
+ text: r.reasoningText?.text ?? '',
151
+ };
152
+ return reasoning;
153
+ }
154
+ return null;
155
+ }
156
+ function buildInferenceConfig(options) {
157
+ const cfg = {};
158
+ if (options.maxTokens !== undefined)
159
+ cfg.maxTokens = options.maxTokens ?? 4096;
160
+ if (options.temperature !== undefined)
161
+ cfg.temperature = options.temperature;
162
+ if (options.topP !== undefined)
163
+ cfg.topP = options.topP;
164
+ return Object.keys(cfg).length > 0 ? cfg : undefined;
165
+ }
166
+ // ---------------------------------------------------------------------------
167
+ // Adapter implementation
168
+ // ---------------------------------------------------------------------------
169
+ /**
170
+ * LLM adapter backed by AWS Bedrock Converse / ConverseStream APIs.
171
+ *
172
+ * Thread-safe — a single instance may be shared across concurrent agent runs.
173
+ */
174
+ export class BedrockAdapter {
175
+ name = 'bedrock';
176
+ #client;
177
+ constructor(region) {
178
+ const resolvedRegion = region ?? process.env['AWS_REGION'] ?? 'us-east-1';
179
+ this.#client = new BedrockRuntimeClient({ region: resolvedRegion });
180
+ }
181
+ // -------------------------------------------------------------------------
182
+ // chat()
183
+ // -------------------------------------------------------------------------
184
+ async chat(messages, options) {
185
+ const bedrockMessages = toBedrockMessages(messages);
186
+ const system = options.systemPrompt ? [{ text: options.systemPrompt }] : undefined;
187
+ const input = {
188
+ modelId: options.model,
189
+ messages: bedrockMessages,
190
+ system,
191
+ toolConfig: options.tools ? toBedrockTools(options.tools) : undefined,
192
+ inferenceConfig: buildInferenceConfig(options) ?? { maxTokens: 4096 },
193
+ };
194
+ if (options.topK !== undefined || options.extraBody) {
195
+ input.additionalModelRequestFields = {
196
+ ...(options.topK !== undefined ? { top_k: options.topK } : {}),
197
+ ...options.extraBody,
198
+ };
199
+ }
200
+ const response = await this.#client.send(new ConverseCommand(input), {
201
+ abortSignal: options.abortSignal,
202
+ });
203
+ const rawContent = response.output?.message?.content ?? [];
204
+ const content = rawContent
205
+ .map(fromBedrockContentBlock)
206
+ .filter((b) => b !== null);
207
+ return {
208
+ id: response.$metadata.requestId ?? '',
209
+ content,
210
+ model: options.model,
211
+ stop_reason: response.stopReason ?? 'end_turn',
212
+ usage: {
213
+ input_tokens: response.usage?.inputTokens ?? 0,
214
+ output_tokens: response.usage?.outputTokens ?? 0,
215
+ },
216
+ };
217
+ }
218
+ // -------------------------------------------------------------------------
219
+ // stream()
220
+ // -------------------------------------------------------------------------
221
+ async *stream(messages, options) {
222
+ const bedrockMessages = toBedrockMessages(messages);
223
+ const system = options.systemPrompt ? [{ text: options.systemPrompt }] : undefined;
224
+ const input = {
225
+ modelId: options.model,
226
+ messages: bedrockMessages,
227
+ system,
228
+ toolConfig: options.tools ? toBedrockTools(options.tools) : undefined,
229
+ inferenceConfig: buildInferenceConfig(options) ?? { maxTokens: 4096 },
230
+ };
231
+ if (options.topK !== undefined || options.extraBody) {
232
+ input.additionalModelRequestFields = {
233
+ ...(options.topK !== undefined ? { top_k: options.topK } : {}),
234
+ ...options.extraBody,
235
+ };
236
+ }
237
+ // Accumulate tool-use input JSON deltas; keyed by content block index.
238
+ const toolBuffers = new Map();
239
+ // Accumulate reasoning text deltas; keyed by content block index. Each
240
+ // index becomes one ReasoningBlock in the final `done` payload, matching
241
+ // what `chat()` produces for the same response shape.
242
+ const reasoningBuffers = new Map();
243
+ // Accumulated content blocks for the done event.
244
+ const accumulatedContent = [];
245
+ let stopReason = 'end_turn';
246
+ let inputTokens = 0;
247
+ let outputTokens = 0;
248
+ const requestId = '';
249
+ try {
250
+ const response = await this.#client.send(new ConverseStreamCommand(input), {
251
+ abortSignal: options.abortSignal,
252
+ });
253
+ for await (const event of response.stream ?? []) {
254
+ if (event.contentBlockStart?.start?.toolUse) {
255
+ const { toolUseId, name } = event.contentBlockStart.start.toolUse;
256
+ const index = event.contentBlockStart.contentBlockIndex ?? 0;
257
+ toolBuffers.set(index, { toolUseId: toolUseId ?? '', name: name ?? '', json: '' });
258
+ }
259
+ if (event.contentBlockDelta?.delta) {
260
+ const delta = event.contentBlockDelta.delta;
261
+ const index = event.contentBlockDelta.contentBlockIndex ?? 0;
262
+ if (delta.text !== undefined) {
263
+ const textEvent = { type: 'text', data: delta.text };
264
+ yield textEvent;
265
+ accumulatedContent.push({ type: 'text', text: delta.text });
266
+ }
267
+ else if (delta.toolUse?.input !== undefined) {
268
+ const buf = toolBuffers.get(index);
269
+ if (buf)
270
+ buf.json += delta.toolUse.input;
271
+ }
272
+ else if (delta.reasoningContent?.text !== undefined) {
273
+ const text = delta.reasoningContent.text;
274
+ const reasoningEvent = { type: 'reasoning', data: text };
275
+ yield reasoningEvent;
276
+ const buf = reasoningBuffers.get(index) ?? { text: '' };
277
+ buf.text += text;
278
+ reasoningBuffers.set(index, buf);
279
+ }
280
+ }
281
+ if (event.contentBlockStop !== undefined) {
282
+ const index = event.contentBlockStop.contentBlockIndex ?? 0;
283
+ const reasoningBuf = reasoningBuffers.get(index);
284
+ if (reasoningBuf) {
285
+ const reasoningBlock = { type: 'reasoning', text: reasoningBuf.text };
286
+ accumulatedContent.push(reasoningBlock);
287
+ reasoningBuffers.delete(index);
288
+ }
289
+ const buf = toolBuffers.get(index);
290
+ if (buf) {
291
+ let parsedInput = {};
292
+ try {
293
+ const parsed = JSON.parse(buf.json || '{}');
294
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
295
+ parsedInput = parsed;
296
+ }
297
+ }
298
+ catch {
299
+ // malformed JSON → empty object
300
+ }
301
+ const toolUseBlock = {
302
+ type: 'tool_use',
303
+ id: buf.toolUseId,
304
+ name: buf.name,
305
+ input: parsedInput,
306
+ };
307
+ accumulatedContent.push(toolUseBlock);
308
+ const toolUseEvent = { type: 'tool_use', data: toolUseBlock };
309
+ yield toolUseEvent;
310
+ toolBuffers.delete(index);
311
+ }
312
+ }
313
+ if (event.messageStop) {
314
+ stopReason = event.messageStop.stopReason ?? 'end_turn';
315
+ }
316
+ if (event.metadata?.usage) {
317
+ inputTokens = event.metadata.usage.inputTokens ?? 0;
318
+ outputTokens = event.metadata.usage.outputTokens ?? 0;
319
+ }
320
+ }
321
+ // Safety net: if Bedrock ever omits a contentBlockStop for a reasoning
322
+ // block, flush whatever we buffered so the done payload still matches
323
+ // what chat() would have returned for the same response.
324
+ for (const [, buf] of reasoningBuffers) {
325
+ accumulatedContent.push({ type: 'reasoning', text: buf.text });
326
+ }
327
+ reasoningBuffers.clear();
328
+ const finalResponse = {
329
+ id: requestId,
330
+ content: accumulatedContent,
331
+ model: options.model,
332
+ stop_reason: stopReason,
333
+ usage: { input_tokens: inputTokens, output_tokens: outputTokens },
334
+ };
335
+ const doneEvent = { type: 'done', data: finalResponse };
336
+ yield doneEvent;
337
+ }
338
+ catch (err) {
339
+ const error = err instanceof Error ? err : new Error(String(err));
340
+ const errorEvent = { type: 'error', data: error };
341
+ yield errorEvent;
342
+ }
343
+ }
344
+ }
345
+ //# sourceMappingURL=bedrock.js.map