@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.
- package/LICENSE +21 -0
- package/README.md +280 -0
- package/dist/agent/agent.d.ts +121 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +294 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/pool.d.ts +128 -0
- package/dist/agent/pool.d.ts.map +1 -0
- package/dist/agent/pool.js +236 -0
- package/dist/agent/pool.js.map +1 -0
- package/dist/agent/runner.d.ts +120 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +274 -0
- package/dist/agent/runner.js.map +1 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/adapter.d.ts +38 -0
- package/dist/llm/adapter.d.ts.map +1 -0
- package/dist/llm/adapter.js +46 -0
- package/dist/llm/adapter.js.map +1 -0
- package/dist/llm/anthropic.d.ts +56 -0
- package/dist/llm/anthropic.d.ts.map +1 -0
- package/dist/llm/anthropic.js +307 -0
- package/dist/llm/anthropic.js.map +1 -0
- package/dist/llm/openai.d.ts +62 -0
- package/dist/llm/openai.d.ts.map +1 -0
- package/dist/llm/openai.js +424 -0
- package/dist/llm/openai.js.map +1 -0
- package/dist/memory/shared.d.ts +86 -0
- package/dist/memory/shared.d.ts.map +1 -0
- package/dist/memory/shared.js +155 -0
- package/dist/memory/shared.js.map +1 -0
- package/dist/memory/store.d.ts +64 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +103 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/orchestrator/orchestrator.d.ts +173 -0
- package/dist/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator.js +698 -0
- package/dist/orchestrator/orchestrator.js.map +1 -0
- package/dist/orchestrator/scheduler.d.ts +112 -0
- package/dist/orchestrator/scheduler.d.ts.map +1 -0
- package/dist/orchestrator/scheduler.js +282 -0
- package/dist/orchestrator/scheduler.js.map +1 -0
- package/dist/task/queue.d.ts +160 -0
- package/dist/task/queue.d.ts.map +1 -0
- package/dist/task/queue.js +337 -0
- package/dist/task/queue.js.map +1 -0
- package/dist/task/task.d.ts +86 -0
- package/dist/task/task.d.ts.map +1 -0
- package/dist/task/task.js +201 -0
- package/dist/task/task.js.map +1 -0
- package/dist/team/messaging.d.ts +106 -0
- package/dist/team/messaging.d.ts.map +1 -0
- package/dist/team/messaging.js +182 -0
- package/dist/team/messaging.js.map +1 -0
- package/dist/team/team.d.ts +141 -0
- package/dist/team/team.d.ts.map +1 -0
- package/dist/team/team.js +282 -0
- package/dist/team/team.js.map +1 -0
- package/dist/tool/built-in/bash.d.ts +12 -0
- package/dist/tool/built-in/bash.d.ts.map +1 -0
- package/dist/tool/built-in/bash.js +133 -0
- package/dist/tool/built-in/bash.js.map +1 -0
- package/dist/tool/built-in/file-edit.d.ts +14 -0
- package/dist/tool/built-in/file-edit.d.ts.map +1 -0
- package/dist/tool/built-in/file-edit.js +130 -0
- package/dist/tool/built-in/file-edit.js.map +1 -0
- package/dist/tool/built-in/file-read.d.ts +12 -0
- package/dist/tool/built-in/file-read.d.ts.map +1 -0
- package/dist/tool/built-in/file-read.js +82 -0
- package/dist/tool/built-in/file-read.js.map +1 -0
- package/dist/tool/built-in/file-write.d.ts +11 -0
- package/dist/tool/built-in/file-write.d.ts.map +1 -0
- package/dist/tool/built-in/file-write.js +70 -0
- package/dist/tool/built-in/file-write.js.map +1 -0
- package/dist/tool/built-in/grep.d.ts +15 -0
- package/dist/tool/built-in/grep.d.ts.map +1 -0
- package/dist/tool/built-in/grep.js +287 -0
- package/dist/tool/built-in/grep.js.map +1 -0
- package/dist/tool/built-in/index.d.ts +36 -0
- package/dist/tool/built-in/index.d.ts.map +1 -0
- package/dist/tool/built-in/index.js +45 -0
- package/dist/tool/built-in/index.js.map +1 -0
- package/dist/tool/executor.d.ts +71 -0
- package/dist/tool/executor.d.ts.map +1 -0
- package/dist/tool/executor.js +116 -0
- package/dist/tool/executor.js.map +1 -0
- package/dist/tool/framework.d.ts +143 -0
- package/dist/tool/framework.d.ts.map +1 -0
- package/dist/tool/framework.js +371 -0
- package/dist/tool/framework.js.map +1 -0
- package/dist/types.d.ts +285 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/semaphore.d.ts +47 -0
- package/dist/utils/semaphore.d.ts.map +1 -0
- package/dist/utils/semaphore.js +85 -0
- package/dist/utils/semaphore.js.map +1 -0
- package/examples/01-single-agent.ts +131 -0
- package/examples/02-team-collaboration.ts +167 -0
- package/examples/03-task-pipeline.ts +201 -0
- package/examples/04-multi-model-team.ts +261 -0
- package/package.json +49 -0
- package/src/agent/agent.ts +364 -0
- package/src/agent/pool.ts +278 -0
- package/src/agent/runner.ts +413 -0
- package/src/index.ts +166 -0
- package/src/llm/adapter.ts +74 -0
- package/src/llm/anthropic.ts +388 -0
- package/src/llm/openai.ts +522 -0
- package/src/memory/shared.ts +181 -0
- package/src/memory/store.ts +124 -0
- package/src/orchestrator/orchestrator.ts +851 -0
- package/src/orchestrator/scheduler.ts +352 -0
- package/src/task/queue.ts +394 -0
- package/src/task/task.ts +232 -0
- package/src/team/messaging.ts +230 -0
- package/src/team/team.ts +334 -0
- package/src/tool/built-in/bash.ts +187 -0
- package/src/tool/built-in/file-edit.ts +154 -0
- package/src/tool/built-in/file-read.ts +105 -0
- package/src/tool/built-in/file-write.ts +81 -0
- package/src/tool/built-in/grep.ts +362 -0
- package/src/tool/built-in/index.ts +50 -0
- package/src/tool/executor.ts +178 -0
- package/src/tool/framework.ts +557 -0
- package/src/types.ts +362 -0
- package/src/utils/semaphore.ts +89 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,424 @@
|
|
|
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 OpenAI from 'openai';
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Internal helpers — framework → OpenAI
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Convert a framework {@link LLMToolDef} to an OpenAI {@link ChatCompletionTool}.
|
|
38
|
+
*
|
|
39
|
+
* OpenAI wraps the function definition inside a `function` key and a `type`
|
|
40
|
+
* discriminant. The `inputSchema` is already a JSON Schema object.
|
|
41
|
+
*/
|
|
42
|
+
function toOpenAITool(tool) {
|
|
43
|
+
return {
|
|
44
|
+
type: 'function',
|
|
45
|
+
function: {
|
|
46
|
+
name: tool.name,
|
|
47
|
+
description: tool.description,
|
|
48
|
+
parameters: tool.inputSchema,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Determine whether a framework message contains any `tool_result` content
|
|
54
|
+
* blocks, which must be serialised as separate OpenAI `tool`-role messages.
|
|
55
|
+
*/
|
|
56
|
+
function hasToolResults(msg) {
|
|
57
|
+
return msg.content.some((b) => b.type === 'tool_result');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Convert a single framework {@link LLMMessage} into one or more OpenAI
|
|
61
|
+
* {@link ChatCompletionMessageParam} entries.
|
|
62
|
+
*
|
|
63
|
+
* The expansion is necessary because OpenAI represents tool results as
|
|
64
|
+
* top-level messages with role `tool`, whereas in our model they are content
|
|
65
|
+
* blocks inside a `user` message.
|
|
66
|
+
*
|
|
67
|
+
* Expansion rules:
|
|
68
|
+
* - A `user` message containing only text/image blocks → single user message
|
|
69
|
+
* - A `user` message containing `tool_result` blocks → one `tool` message per
|
|
70
|
+
* tool_result block; any remaining text/image blocks are folded into an
|
|
71
|
+
* additional user message prepended to the group
|
|
72
|
+
* - An `assistant` message → single assistant message with optional tool_calls
|
|
73
|
+
*/
|
|
74
|
+
function toOpenAIMessages(messages) {
|
|
75
|
+
const result = [];
|
|
76
|
+
for (const msg of messages) {
|
|
77
|
+
if (msg.role === 'assistant') {
|
|
78
|
+
result.push(toOpenAIAssistantMessage(msg));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// user role
|
|
82
|
+
if (!hasToolResults(msg)) {
|
|
83
|
+
result.push(toOpenAIUserMessage(msg));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Split: text/image blocks become a user message (if any exist), then
|
|
87
|
+
// each tool_result block becomes an independent tool message.
|
|
88
|
+
const nonToolBlocks = msg.content.filter((b) => b.type !== 'tool_result');
|
|
89
|
+
if (nonToolBlocks.length > 0) {
|
|
90
|
+
result.push(toOpenAIUserMessage({ role: 'user', content: nonToolBlocks }));
|
|
91
|
+
}
|
|
92
|
+
for (const block of msg.content) {
|
|
93
|
+
if (block.type === 'tool_result') {
|
|
94
|
+
const toolMsg = {
|
|
95
|
+
role: 'tool',
|
|
96
|
+
tool_call_id: block.tool_use_id,
|
|
97
|
+
content: block.content,
|
|
98
|
+
};
|
|
99
|
+
result.push(toolMsg);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Convert a `user`-role framework message into an OpenAI user message.
|
|
109
|
+
* Image blocks are converted to the OpenAI image_url content part format.
|
|
110
|
+
*/
|
|
111
|
+
function toOpenAIUserMessage(msg) {
|
|
112
|
+
// If the entire content is a single text block, use the compact string form
|
|
113
|
+
// to keep the request payload smaller.
|
|
114
|
+
if (msg.content.length === 1 && msg.content[0]?.type === 'text') {
|
|
115
|
+
return { role: 'user', content: msg.content[0].text };
|
|
116
|
+
}
|
|
117
|
+
const parts = [];
|
|
118
|
+
for (const block of msg.content) {
|
|
119
|
+
if (block.type === 'text') {
|
|
120
|
+
parts.push({ type: 'text', text: block.text });
|
|
121
|
+
}
|
|
122
|
+
else if (block.type === 'image') {
|
|
123
|
+
parts.push({
|
|
124
|
+
type: 'image_url',
|
|
125
|
+
image_url: {
|
|
126
|
+
url: `data:${block.source.media_type};base64,${block.source.data}`,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// tool_result blocks are handled by the caller (toOpenAIMessages); skip here.
|
|
131
|
+
}
|
|
132
|
+
return { role: 'user', content: parts };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Convert an `assistant`-role framework message into an OpenAI assistant message.
|
|
136
|
+
*
|
|
137
|
+
* Any `tool_use` blocks become `tool_calls`; `text` blocks become the message content.
|
|
138
|
+
*/
|
|
139
|
+
function toOpenAIAssistantMessage(msg) {
|
|
140
|
+
const toolCalls = [];
|
|
141
|
+
const textParts = [];
|
|
142
|
+
for (const block of msg.content) {
|
|
143
|
+
if (block.type === 'tool_use') {
|
|
144
|
+
toolCalls.push({
|
|
145
|
+
id: block.id,
|
|
146
|
+
type: 'function',
|
|
147
|
+
function: {
|
|
148
|
+
name: block.name,
|
|
149
|
+
arguments: JSON.stringify(block.input),
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else if (block.type === 'text') {
|
|
154
|
+
textParts.push(block.text);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const assistantMsg = {
|
|
158
|
+
role: 'assistant',
|
|
159
|
+
content: textParts.length > 0 ? textParts.join('') : null,
|
|
160
|
+
};
|
|
161
|
+
if (toolCalls.length > 0) {
|
|
162
|
+
assistantMsg.tool_calls = toolCalls;
|
|
163
|
+
}
|
|
164
|
+
return assistantMsg;
|
|
165
|
+
}
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Internal helpers — OpenAI → framework
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
/**
|
|
170
|
+
* Convert an OpenAI {@link ChatCompletion} into a framework {@link LLMResponse}.
|
|
171
|
+
*
|
|
172
|
+
* We take only the first choice (index 0), consistent with how the framework
|
|
173
|
+
* is designed for single-output agents.
|
|
174
|
+
*/
|
|
175
|
+
function fromOpenAICompletion(completion) {
|
|
176
|
+
const choice = completion.choices[0];
|
|
177
|
+
if (choice === undefined) {
|
|
178
|
+
throw new Error('OpenAI returned a completion with no choices');
|
|
179
|
+
}
|
|
180
|
+
const content = [];
|
|
181
|
+
const message = choice.message;
|
|
182
|
+
if (message.content !== null && message.content !== undefined) {
|
|
183
|
+
const textBlock = { type: 'text', text: message.content };
|
|
184
|
+
content.push(textBlock);
|
|
185
|
+
}
|
|
186
|
+
for (const toolCall of message.tool_calls ?? []) {
|
|
187
|
+
let parsedInput = {};
|
|
188
|
+
try {
|
|
189
|
+
const parsed = JSON.parse(toolCall.function.arguments);
|
|
190
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
191
|
+
parsedInput = parsed;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Malformed arguments from the model — surface as empty object.
|
|
196
|
+
}
|
|
197
|
+
const toolUseBlock = {
|
|
198
|
+
type: 'tool_use',
|
|
199
|
+
id: toolCall.id,
|
|
200
|
+
name: toolCall.function.name,
|
|
201
|
+
input: parsedInput,
|
|
202
|
+
};
|
|
203
|
+
content.push(toolUseBlock);
|
|
204
|
+
}
|
|
205
|
+
const stopReason = normalizeFinishReason(choice.finish_reason ?? 'stop');
|
|
206
|
+
return {
|
|
207
|
+
id: completion.id,
|
|
208
|
+
content,
|
|
209
|
+
model: completion.model,
|
|
210
|
+
stop_reason: stopReason,
|
|
211
|
+
usage: {
|
|
212
|
+
input_tokens: completion.usage?.prompt_tokens ?? 0,
|
|
213
|
+
output_tokens: completion.usage?.completion_tokens ?? 0,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Normalize an OpenAI `finish_reason` string to the framework's canonical
|
|
219
|
+
* stop-reason vocabulary so consumers never need to branch on provider-specific
|
|
220
|
+
* strings.
|
|
221
|
+
*
|
|
222
|
+
* Mapping:
|
|
223
|
+
* - `'stop'` → `'end_turn'`
|
|
224
|
+
* - `'tool_calls'` → `'tool_use'`
|
|
225
|
+
* - `'length'` → `'max_tokens'`
|
|
226
|
+
* - `'content_filter'` → `'content_filter'`
|
|
227
|
+
* - anything else → passed through unchanged
|
|
228
|
+
*/
|
|
229
|
+
function normalizeFinishReason(reason) {
|
|
230
|
+
switch (reason) {
|
|
231
|
+
case 'stop': return 'end_turn';
|
|
232
|
+
case 'tool_calls': return 'tool_use';
|
|
233
|
+
case 'length': return 'max_tokens';
|
|
234
|
+
case 'content_filter': return 'content_filter';
|
|
235
|
+
default: return reason;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// Adapter implementation
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
/**
|
|
242
|
+
* LLM adapter backed by the OpenAI Chat Completions API.
|
|
243
|
+
*
|
|
244
|
+
* Thread-safe — a single instance may be shared across concurrent agent runs.
|
|
245
|
+
*/
|
|
246
|
+
export class OpenAIAdapter {
|
|
247
|
+
name = 'openai';
|
|
248
|
+
#client;
|
|
249
|
+
constructor(apiKey) {
|
|
250
|
+
this.#client = new OpenAI({
|
|
251
|
+
apiKey: apiKey ?? process.env['OPENAI_API_KEY'],
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// -------------------------------------------------------------------------
|
|
255
|
+
// chat()
|
|
256
|
+
// -------------------------------------------------------------------------
|
|
257
|
+
/**
|
|
258
|
+
* Send a synchronous (non-streaming) chat request and return the complete
|
|
259
|
+
* {@link LLMResponse}.
|
|
260
|
+
*
|
|
261
|
+
* Throws an `OpenAI.APIError` on non-2xx responses. Callers should catch and
|
|
262
|
+
* handle these (e.g. rate limits, context length exceeded).
|
|
263
|
+
*/
|
|
264
|
+
async chat(messages, options) {
|
|
265
|
+
const openAIMessages = buildOpenAIMessageList(messages, options.systemPrompt);
|
|
266
|
+
const completion = await this.#client.chat.completions.create({
|
|
267
|
+
model: options.model,
|
|
268
|
+
messages: openAIMessages,
|
|
269
|
+
max_tokens: options.maxTokens,
|
|
270
|
+
temperature: options.temperature,
|
|
271
|
+
tools: options.tools ? options.tools.map(toOpenAITool) : undefined,
|
|
272
|
+
stream: false,
|
|
273
|
+
}, {
|
|
274
|
+
signal: options.abortSignal,
|
|
275
|
+
});
|
|
276
|
+
return fromOpenAICompletion(completion);
|
|
277
|
+
}
|
|
278
|
+
// -------------------------------------------------------------------------
|
|
279
|
+
// stream()
|
|
280
|
+
// -------------------------------------------------------------------------
|
|
281
|
+
/**
|
|
282
|
+
* Send a streaming chat request and yield {@link StreamEvent}s incrementally.
|
|
283
|
+
*
|
|
284
|
+
* Sequence guarantees match {@link AnthropicAdapter.stream}:
|
|
285
|
+
* - Zero or more `text` events
|
|
286
|
+
* - Zero or more `tool_use` events (emitted once per tool call, after
|
|
287
|
+
* arguments have been fully assembled)
|
|
288
|
+
* - Exactly one terminal event: `done` or `error`
|
|
289
|
+
*/
|
|
290
|
+
async *stream(messages, options) {
|
|
291
|
+
const openAIMessages = buildOpenAIMessageList(messages, options.systemPrompt);
|
|
292
|
+
// We request usage in the final chunk so we can include it in the `done` event.
|
|
293
|
+
const streamResponse = await this.#client.chat.completions.create({
|
|
294
|
+
model: options.model,
|
|
295
|
+
messages: openAIMessages,
|
|
296
|
+
max_tokens: options.maxTokens,
|
|
297
|
+
temperature: options.temperature,
|
|
298
|
+
tools: options.tools ? options.tools.map(toOpenAITool) : undefined,
|
|
299
|
+
stream: true,
|
|
300
|
+
stream_options: { include_usage: true },
|
|
301
|
+
}, {
|
|
302
|
+
signal: options.abortSignal,
|
|
303
|
+
});
|
|
304
|
+
// Accumulate state across chunks.
|
|
305
|
+
let completionId = '';
|
|
306
|
+
let completionModel = '';
|
|
307
|
+
let finalFinishReason = 'stop';
|
|
308
|
+
let inputTokens = 0;
|
|
309
|
+
let outputTokens = 0;
|
|
310
|
+
// tool_calls are streamed piecemeal; key = tool call index
|
|
311
|
+
const toolCallBuffers = new Map();
|
|
312
|
+
// Full text accumulator for the `done` response.
|
|
313
|
+
let fullText = '';
|
|
314
|
+
try {
|
|
315
|
+
for await (const chunk of streamResponse) {
|
|
316
|
+
completionId = chunk.id;
|
|
317
|
+
completionModel = chunk.model;
|
|
318
|
+
// Usage is only populated in the final chunk when stream_options.include_usage is set.
|
|
319
|
+
if (chunk.usage !== null && chunk.usage !== undefined) {
|
|
320
|
+
inputTokens = chunk.usage.prompt_tokens;
|
|
321
|
+
outputTokens = chunk.usage.completion_tokens;
|
|
322
|
+
}
|
|
323
|
+
const choice = chunk.choices[0];
|
|
324
|
+
if (choice === undefined)
|
|
325
|
+
continue;
|
|
326
|
+
const delta = choice.delta;
|
|
327
|
+
// --- text delta ---
|
|
328
|
+
if (delta.content !== null && delta.content !== undefined) {
|
|
329
|
+
fullText += delta.content;
|
|
330
|
+
const textEvent = { type: 'text', data: delta.content };
|
|
331
|
+
yield textEvent;
|
|
332
|
+
}
|
|
333
|
+
// --- tool call delta ---
|
|
334
|
+
for (const toolCallDelta of delta.tool_calls ?? []) {
|
|
335
|
+
const idx = toolCallDelta.index;
|
|
336
|
+
if (!toolCallBuffers.has(idx)) {
|
|
337
|
+
toolCallBuffers.set(idx, {
|
|
338
|
+
id: toolCallDelta.id ?? '',
|
|
339
|
+
name: toolCallDelta.function?.name ?? '',
|
|
340
|
+
argsJson: '',
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const buf = toolCallBuffers.get(idx);
|
|
344
|
+
// buf is guaranteed to exist: we just set it above.
|
|
345
|
+
if (buf !== undefined) {
|
|
346
|
+
if (toolCallDelta.id)
|
|
347
|
+
buf.id = toolCallDelta.id;
|
|
348
|
+
if (toolCallDelta.function?.name)
|
|
349
|
+
buf.name = toolCallDelta.function.name;
|
|
350
|
+
if (toolCallDelta.function?.arguments) {
|
|
351
|
+
buf.argsJson += toolCallDelta.function.arguments;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (choice.finish_reason !== null && choice.finish_reason !== undefined) {
|
|
356
|
+
finalFinishReason = choice.finish_reason;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// Emit accumulated tool_use events after the stream ends.
|
|
360
|
+
const finalToolUseBlocks = [];
|
|
361
|
+
for (const buf of toolCallBuffers.values()) {
|
|
362
|
+
let parsedInput = {};
|
|
363
|
+
try {
|
|
364
|
+
const parsed = JSON.parse(buf.argsJson);
|
|
365
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
366
|
+
parsedInput = parsed;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// Malformed JSON — surface as empty object.
|
|
371
|
+
}
|
|
372
|
+
const toolUseBlock = {
|
|
373
|
+
type: 'tool_use',
|
|
374
|
+
id: buf.id,
|
|
375
|
+
name: buf.name,
|
|
376
|
+
input: parsedInput,
|
|
377
|
+
};
|
|
378
|
+
finalToolUseBlocks.push(toolUseBlock);
|
|
379
|
+
const toolUseEvent = { type: 'tool_use', data: toolUseBlock };
|
|
380
|
+
yield toolUseEvent;
|
|
381
|
+
}
|
|
382
|
+
// Build the complete content array for the done response.
|
|
383
|
+
const doneContent = [];
|
|
384
|
+
if (fullText.length > 0) {
|
|
385
|
+
const textBlock = { type: 'text', text: fullText };
|
|
386
|
+
doneContent.push(textBlock);
|
|
387
|
+
}
|
|
388
|
+
doneContent.push(...finalToolUseBlocks);
|
|
389
|
+
const finalResponse = {
|
|
390
|
+
id: completionId,
|
|
391
|
+
content: doneContent,
|
|
392
|
+
model: completionModel,
|
|
393
|
+
stop_reason: normalizeFinishReason(finalFinishReason),
|
|
394
|
+
usage: { input_tokens: inputTokens, output_tokens: outputTokens },
|
|
395
|
+
};
|
|
396
|
+
const doneEvent = { type: 'done', data: finalResponse };
|
|
397
|
+
yield doneEvent;
|
|
398
|
+
}
|
|
399
|
+
catch (err) {
|
|
400
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
401
|
+
const errorEvent = { type: 'error', data: error };
|
|
402
|
+
yield errorEvent;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// ---------------------------------------------------------------------------
|
|
407
|
+
// Private utility
|
|
408
|
+
// ---------------------------------------------------------------------------
|
|
409
|
+
/**
|
|
410
|
+
* Prepend a system message when `systemPrompt` is provided, then append the
|
|
411
|
+
* converted conversation messages.
|
|
412
|
+
*
|
|
413
|
+
* OpenAI represents system instructions as a message with `role: 'system'`
|
|
414
|
+
* at the top of the array, not as a separate API parameter.
|
|
415
|
+
*/
|
|
416
|
+
function buildOpenAIMessageList(messages, systemPrompt) {
|
|
417
|
+
const result = [];
|
|
418
|
+
if (systemPrompt !== undefined && systemPrompt.length > 0) {
|
|
419
|
+
result.push({ role: 'system', content: systemPrompt });
|
|
420
|
+
}
|
|
421
|
+
result.push(...toOpenAIMessages(messages));
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/llm/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAA;AAyB3B,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAE9E;;;;;GAKG;AACH,SAAS,YAAY,CAAC,IAAgB;IACpC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,WAAsC;SACxD;KACF,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,GAAe;IACrC,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,gBAAgB,CAAC,QAAsB;IAC9C,MAAM,MAAM,GAAiC,EAAE,CAAA;IAE/C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5C,CAAC;aAAM,CAAC;YACN,YAAY;YACZ,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAA;YACvC,CAAC;iBAAM,CAAC;gBACN,sEAAsE;gBACtE,8DAA8D;gBAC9D,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAA;gBACzE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,CAAA;gBAC5E,CAAC;gBAED,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;oBAChC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;wBACjC,MAAM,OAAO,GAAmC;4BAC9C,IAAI,EAAE,MAAM;4BACZ,YAAY,EAAE,KAAK,CAAC,WAAW;4BAC/B,OAAO,EAAE,KAAK,CAAC,OAAO;yBACvB,CAAA;wBACD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACtB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAe;IAC1C,4EAA4E;IAC5E,uCAAuC;IACvC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;QAChE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACvD,CAAC;IAGD,MAAM,KAAK,GAAkB,EAAE,CAAA;IAE/B,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;QAChD,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,WAAW;gBACjB,SAAS,EAAE;oBACT,GAAG,EAAE,QAAQ,KAAK,CAAC,MAAM,CAAC,UAAU,WAAW,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;iBACnE;aACF,CAAC,CAAA;QACJ,CAAC;QACD,8EAA8E;IAChF,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,GAAe;IAC/C,MAAM,SAAS,GAAoC,EAAE,CAAA;IACrD,MAAM,SAAS,GAAa,EAAE,CAAA;IAE9B,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE;oBACR,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;iBACvC;aACF,CAAC,CAAA;QACJ,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACjC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAAwC;QACxD,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI;KAC1D,CAAA;IAED,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,YAAY,CAAC,UAAU,GAAG,SAAS,CAAA;IACrC,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAE9E;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,UAA0B;IACtD,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IACjE,CAAC;IAED,MAAM,OAAO,GAAmB,EAAE,CAAA;IAClC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;IAE9B,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9D,MAAM,SAAS,GAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QACpE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QAChD,IAAI,WAAW,GAA4B,EAAE,CAAA;QAC7C,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YAC/D,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5E,WAAW,GAAG,MAAiC,CAAA;YACjD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;QAED,MAAM,YAAY,GAAiB;YACjC,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI;YAC5B,KAAK,EAAE,WAAW;SACnB,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAC5B,CAAC;IAED,MAAM,UAAU,GAAG,qBAAqB,CAAC,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,CAAA;IAExE,OAAO;QACL,EAAE,EAAE,UAAU,CAAC,EAAE;QACjB,OAAO;QACP,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,WAAW,EAAE,UAAU;QACvB,KAAK,EAAE;YACL,YAAY,EAAE,UAAU,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC;YAClD,aAAa,EAAE,UAAU,CAAC,KAAK,EAAE,iBAAiB,IAAI,CAAC;SACxD;KACF,CAAA;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,qBAAqB,CAAC,MAAc;IAC3C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,CAAW,OAAO,UAAU,CAAA;QACxC,KAAK,YAAY,CAAC,CAAK,OAAO,UAAU,CAAA;QACxC,KAAK,QAAQ,CAAC,CAAS,OAAO,YAAY,CAAA;QAC1C,KAAK,gBAAgB,CAAC,CAAC,OAAO,gBAAgB,CAAA;QAC9C,OAAO,CAAC,CAAe,OAAO,MAAM,CAAA;IACtC,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,QAAQ,CAAA;IAEf,OAAO,CAAQ;IAExB,YAAY,MAAe;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,MAAM,CAAC;YACxB,MAAM,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;SAChD,CAAC,CAAA;IACJ,CAAC;IAED,4EAA4E;IAC5E,SAAS;IACT,4EAA4E;IAE5E;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,CAAC,QAAsB,EAAE,OAAuB;QACxD,MAAM,cAAc,GAAG,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;QAE7E,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAC3D;YACE,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,cAAc;YACxB,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;YAClE,MAAM,EAAE,KAAK;SACd,EACD;YACE,MAAM,EAAE,OAAO,CAAC,WAAW;SAC5B,CACF,CAAA;QAED,OAAO,oBAAoB,CAAC,UAAU,CAAC,CAAA;IACzC,CAAC;IAED,4EAA4E;IAC5E,WAAW;IACX,4EAA4E;IAE5E;;;;;;;;OAQG;IACH,KAAK,CAAC,CAAC,MAAM,CACX,QAAsB,EACtB,OAAyB;QAEzB,MAAM,cAAc,GAAG,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;QAE7E,gFAAgF;QAChF,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAC/D;YACE,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,cAAc;YACxB,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;YAClE,MAAM,EAAE,IAAI;YACZ,cAAc,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;SACxC,EACD;YACE,MAAM,EAAE,OAAO,CAAC,WAAW;SAC5B,CACF,CAAA;QAED,kCAAkC;QAClC,IAAI,YAAY,GAAG,EAAE,CAAA;QACrB,IAAI,eAAe,GAAG,EAAE,CAAA;QACxB,IAAI,iBAAiB,GAAW,MAAM,CAAA;QACtC,IAAI,WAAW,GAAG,CAAC,CAAA;QACnB,IAAI,YAAY,GAAG,CAAC,CAAA;QAEpB,2DAA2D;QAC3D,MAAM,eAAe,GAAG,IAAI,GAAG,EAG5B,CAAA;QAEH,iDAAiD;QACjD,IAAI,QAAQ,GAAG,EAAE,CAAA;QAEjB,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;gBACzC,YAAY,GAAG,KAAK,CAAC,EAAE,CAAA;gBACvB,eAAe,GAAG,KAAK,CAAC,KAAK,CAAA;gBAE7B,uFAAuF;gBACvF,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBACtD,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,CAAA;oBACvC,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAA;gBAC9C,CAAC;gBAED,MAAM,MAAM,GAA2C,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;gBACvE,IAAI,MAAM,KAAK,SAAS;oBAAE,SAAQ;gBAElC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;gBAE1B,qBAAqB;gBACrB,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC1D,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAA;oBACzB,MAAM,SAAS,GAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAA;oBACpE,MAAM,SAAS,CAAA;gBACjB,CAAC;gBAED,0BAA0B;gBAC1B,KAAK,MAAM,aAAa,IAAI,KAAK,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;oBACnD,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,CAAA;oBAE/B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC9B,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE;4BACvB,EAAE,EAAE,aAAa,CAAC,EAAE,IAAI,EAAE;4BAC1B,IAAI,EAAE,aAAa,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;4BACxC,QAAQ,EAAE,EAAE;yBACb,CAAC,CAAA;oBACJ,CAAC;oBAED,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;oBACpC,oDAAoD;oBACpD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;wBACtB,IAAI,aAAa,CAAC,EAAE;4BAAE,GAAG,CAAC,EAAE,GAAG,aAAa,CAAC,EAAE,CAAA;wBAC/C,IAAI,aAAa,CAAC,QAAQ,EAAE,IAAI;4BAAE,GAAG,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAA;wBACxE,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;4BACtC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAA;wBAClD,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;oBACxE,iBAAiB,GAAG,MAAM,CAAC,aAAa,CAAA;gBAC1C,CAAC;YACH,CAAC;YAED,0DAA0D;YAC1D,MAAM,kBAAkB,GAAmB,EAAE,CAAA;YAC7C,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC3C,IAAI,WAAW,GAA4B,EAAE,CAAA;gBAC7C,IAAI,CAAC;oBACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;oBAChD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC5E,WAAW,GAAG,MAAiC,CAAA;oBACjD,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,4CAA4C;gBAC9C,CAAC;gBAED,MAAM,YAAY,GAAiB;oBACjC,IAAI,EAAE,UAAU;oBAChB,EAAE,EAAE,GAAG,CAAC,EAAE;oBACV,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,KAAK,EAAE,WAAW;iBACnB,CAAA;gBACD,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;gBACrC,MAAM,YAAY,GAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,CAAA;gBAC1E,MAAM,YAAY,CAAA;YACpB,CAAC;YAED,0DAA0D;YAC1D,MAAM,WAAW,GAAmB,EAAE,CAAA;YACtC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,SAAS,GAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;gBAC7D,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC7B,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,CAAA;YAEvC,MAAM,aAAa,GAAgB;gBACjC,EAAE,EAAE,YAAY;gBAChB,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAE,eAAe;gBACtB,WAAW,EAAE,qBAAqB,CAAC,iBAAiB,CAAC;gBACrD,KAAK,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE;aAClE,CAAA;YAED,MAAM,SAAS,GAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;YACpE,MAAM,SAAS,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YACjE,MAAM,UAAU,GAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;YAC9D,MAAM,UAAU,CAAA;QAClB,CAAC;IACH,CAAC;CACF;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;GAMG;AACH,SAAS,sBAAsB,CAC7B,QAAsB,EACtB,YAAgC;IAEhC,MAAM,MAAM,GAAiC,EAAE,CAAA;IAE/C,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAA;IACxD,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC1C,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared memory layer for teams of cooperating agents.
|
|
3
|
+
*
|
|
4
|
+
* Each agent writes under its own namespace (`<agentName>/<key>`) so entries
|
|
5
|
+
* remain attributable, while any agent may read any entry. The
|
|
6
|
+
* {@link SharedMemory.getSummary} method produces a human-readable digest
|
|
7
|
+
* suitable for injecting into an agent's context window.
|
|
8
|
+
*/
|
|
9
|
+
import type { MemoryEntry, MemoryStore } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Namespaced shared memory for a team of agents.
|
|
12
|
+
*
|
|
13
|
+
* Writes are namespaced as `<agentName>/<key>` so that entries from different
|
|
14
|
+
* agents never collide and are always attributable. Reads are namespace-aware
|
|
15
|
+
* but also accept fully-qualified keys, making cross-agent reads straightforward.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const mem = new SharedMemory()
|
|
20
|
+
*
|
|
21
|
+
* await mem.write('researcher', 'findings', 'TypeScript 5.5 ships const type params')
|
|
22
|
+
* await mem.write('coder', 'plan', 'Implement feature X using const type params')
|
|
23
|
+
*
|
|
24
|
+
* const entry = await mem.read('researcher/findings')
|
|
25
|
+
* const all = await mem.listByAgent('researcher')
|
|
26
|
+
* const summary = await mem.getSummary()
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class SharedMemory {
|
|
30
|
+
private readonly store;
|
|
31
|
+
constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Write `value` under the namespaced key `<agentName>/<key>`.
|
|
34
|
+
*
|
|
35
|
+
* Metadata is merged with a `{ agent: agentName }` marker so consumers can
|
|
36
|
+
* identify provenance when iterating all entries.
|
|
37
|
+
*
|
|
38
|
+
* @param agentName - The writing agent's name (used as a namespace prefix).
|
|
39
|
+
* @param key - Logical key within the agent's namespace.
|
|
40
|
+
* @param value - String value to store (serialise objects before writing).
|
|
41
|
+
* @param metadata - Optional extra metadata stored alongside the entry.
|
|
42
|
+
*/
|
|
43
|
+
write(agentName: string, key: string, value: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Read an entry by its fully-qualified key (`<agentName>/<key>`).
|
|
46
|
+
*
|
|
47
|
+
* Returns `null` when the key is absent.
|
|
48
|
+
*/
|
|
49
|
+
read(key: string): Promise<MemoryEntry | null>;
|
|
50
|
+
/** Returns every entry in the shared store, regardless of agent. */
|
|
51
|
+
listAll(): Promise<MemoryEntry[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Returns all entries written by `agentName` (i.e. those whose key starts
|
|
54
|
+
* with `<agentName>/`).
|
|
55
|
+
*/
|
|
56
|
+
listByAgent(agentName: string): Promise<MemoryEntry[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Produces a human-readable summary of all entries in the store.
|
|
59
|
+
*
|
|
60
|
+
* The output is structured as a markdown-style block, grouped by agent, and
|
|
61
|
+
* is designed to be prepended to an agent's system prompt or injected as a
|
|
62
|
+
* user turn so the agent has context about what its teammates know.
|
|
63
|
+
*
|
|
64
|
+
* Returns an empty string when the store is empty.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```
|
|
68
|
+
* ## Shared Team Memory
|
|
69
|
+
*
|
|
70
|
+
* ### researcher
|
|
71
|
+
* - findings: TypeScript 5.5 ships const type params
|
|
72
|
+
*
|
|
73
|
+
* ### coder
|
|
74
|
+
* - plan: Implement feature X using const type params
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
getSummary(): Promise<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Returns the underlying {@link MemoryStore} so callers that only need the
|
|
80
|
+
* raw key-value interface can receive a properly typed reference without
|
|
81
|
+
* accessing private fields via bracket notation.
|
|
82
|
+
*/
|
|
83
|
+
getStore(): MemoryStore;
|
|
84
|
+
private static namespaceKey;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/memory/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAO3D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;;IAUrC;;;;;;;;;;OAUG;IACG,KAAK,CACT,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC;IAYhB;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQpD,oEAAoE;IAC9D,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAIvC;;;OAGG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAU5D;;;;;;;;;;;;;;;;;;;OAmBG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAsCnC;;;;OAIG;IACH,QAAQ,IAAI,WAAW;IAQvB,OAAO,CAAC,MAAM,CAAC,YAAY;CAG5B"}
|