@agentxjs/core 1.9.10-dev → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +342 -0
- package/dist/{Processor-DT0N1qI6.d.ts → Processor-CeMyXtsX.d.ts} +1 -1
- package/dist/RpcClient-CMdhJxjS.d.ts +304 -0
- package/dist/agent/engine/internal/index.d.ts +22 -18
- package/dist/agent/engine/internal/index.js +1 -2
- package/dist/agent/engine/mealy/index.d.ts +4 -4
- package/dist/agent/engine/mealy/index.js +1 -2
- package/dist/agent/index.d.ts +92 -92
- package/dist/agent/index.js +16 -16
- package/dist/agent/types/index.d.ts +4 -4
- package/dist/agent/types/index.js +1 -2
- package/dist/bash/index.d.ts +29 -0
- package/dist/bash/index.js +7 -0
- package/dist/{bus-uF1DM2ox.d.ts → bus-C9FLWIu8.d.ts} +3 -1
- package/dist/{chunk-E5FPOAPO.js → chunk-22NTRYNO.js} +60 -60
- package/dist/chunk-22NTRYNO.js.map +1 -0
- package/dist/{chunk-7ZDX3O6I.js → chunk-AAFPAF67.js} +2 -2
- package/dist/{chunk-7ZDX3O6I.js.map → chunk-AAFPAF67.js.map} +1 -1
- package/dist/{chunk-EKHT54KN.js → chunk-APCBNCOW.js} +1 -1
- package/dist/{chunk-EKHT54KN.js.map → chunk-APCBNCOW.js.map} +1 -1
- package/dist/chunk-BHOD5PKR.js +55 -0
- package/dist/chunk-BHOD5PKR.js.map +1 -0
- package/dist/chunk-FI7WQFGV.js +37 -0
- package/dist/chunk-FI7WQFGV.js.map +1 -0
- package/dist/{chunk-AT5P47YA.js → chunk-RWIYC65R.js} +115 -115
- package/dist/chunk-RWIYC65R.js.map +1 -0
- package/dist/chunk-SKS7S2RY.js +1 -0
- package/dist/{chunk-I7GYR3MN.js → chunk-TUFZ2YH6.js} +77 -91
- package/dist/chunk-TUFZ2YH6.js.map +1 -0
- package/dist/{chunk-K6WXQ2RW.js → chunk-YSZG6XIM.js} +1 -2
- package/dist/chunk-YSZG6XIM.js.map +1 -0
- package/dist/{combinators-nEa5dD0T.d.ts → combinators-Dy-7lxKV.d.ts} +50 -50
- package/dist/common/logger/index.js +14 -16
- package/dist/common/logger/index.js.map +1 -1
- package/dist/container/index.d.ts +3 -4
- package/dist/container/index.js +0 -2
- package/dist/container/index.js.map +1 -1
- package/dist/driver/index.d.ts +2 -310
- package/dist/event/index.d.ts +4 -4
- package/dist/event/index.js +2 -3
- package/dist/event/types/index.d.ts +202 -208
- package/dist/event/types/index.js +1 -2
- package/dist/{event-CDuTzs__.d.ts → event-DNsF9EkO.d.ts} +5 -8
- package/dist/image/index.d.ts +9 -5
- package/dist/image/index.js +5 -2
- package/dist/image/index.js.map +1 -1
- package/dist/index--gxNpY5W.d.ts +609 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +17 -17
- package/dist/{message-BMrMm1pq.d.ts → message-Dn-I2vr0.d.ts} +10 -33
- package/dist/mq/index.d.ts +25 -25
- package/dist/mq/index.js +1 -3
- package/dist/mq/index.js.map +1 -1
- package/dist/network/index.d.ts +59 -347
- package/dist/network/index.js +30 -41
- package/dist/network/index.js.map +1 -1
- package/dist/persistence/index.d.ts +2 -155
- package/dist/platform/index.d.ts +76 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/runtime/index.d.ts +26 -59
- package/dist/runtime/index.js +117 -33
- package/dist/runtime/index.js.map +1 -1
- package/dist/session/index.d.ts +4 -52
- package/dist/session/index.js +4 -51
- package/dist/session/index.js.map +1 -1
- package/dist/types-Cb8tKM6Y.d.ts +90 -0
- package/package.json +10 -5
- package/src/agent/AgentStateMachine.ts +2 -2
- package/src/agent/__tests__/AgentStateMachine.test.ts +2 -2
- package/src/agent/__tests__/createAgent.test.ts +4 -4
- package/src/agent/__tests__/engine/internal/messageAssemblerProcessor.test.ts +301 -97
- package/src/agent/__tests__/engine/internal/stateEventProcessor.test.ts +6 -6
- package/src/agent/__tests__/engine/internal/turnTrackerProcessor.test.ts +59 -78
- package/src/agent/__tests__/engine/mealy/Mealy.test.ts +3 -3
- package/src/agent/__tests__/engine/mealy/Store.test.ts +1 -1
- package/src/agent/__tests__/engine/mealy/combinators.test.ts +4 -4
- package/src/agent/createAgent.ts +15 -15
- package/src/agent/engine/AgentProcessor.ts +7 -7
- package/src/agent/engine/MealyMachine.ts +4 -4
- package/src/agent/engine/internal/index.ts +11 -11
- package/src/agent/engine/internal/messageAssemblerProcessor.ts +113 -128
- package/src/agent/engine/internal/stateEventProcessor.ts +13 -15
- package/src/agent/engine/internal/turnTrackerProcessor.ts +27 -31
- package/src/agent/engine/mealy/Mealy.ts +2 -2
- package/src/agent/engine/mealy/combinators.ts +10 -10
- package/src/agent/engine/mealy/index.ts +9 -11
- package/src/agent/index.ts +30 -32
- package/src/agent/types/engine.ts +3 -3
- package/src/agent/types/event.ts +4 -12
- package/src/agent/types/index.ts +86 -88
- package/src/agent/types/message.ts +9 -43
- package/src/bash/index.ts +21 -0
- package/src/bash/tool.ts +57 -0
- package/src/bash/types.ts +108 -0
- package/src/common/logger/ConsoleLogger.ts +1 -1
- package/src/common/logger/LoggerFactoryImpl.ts +14 -14
- package/src/common/logger/index.ts +3 -3
- package/src/container/index.ts +4 -5
- package/src/container/types.ts +1 -1
- package/src/driver/index.ts +15 -16
- package/src/driver/types.ts +201 -73
- package/src/event/EventBus.ts +10 -10
- package/src/event/__tests__/EventBus.test.ts +2 -2
- package/src/event/index.ts +2 -3
- package/src/event/types/agent.ts +186 -191
- package/src/event/types/bus.ts +1 -1
- package/src/event/types/command.ts +293 -264
- package/src/event/types/container.ts +207 -222
- package/src/event/types/driver.ts +153 -155
- package/src/event/types/index.ts +6 -12
- package/src/event/types/session.ts +117 -130
- package/src/image/Image.ts +12 -2
- package/src/image/index.ts +4 -5
- package/src/image/types.ts +8 -2
- package/src/mq/OffsetGenerator.ts +1 -1
- package/src/mq/__tests__/OffsetGenerator.test.ts +1 -1
- package/src/mq/index.ts +4 -5
- package/src/network/RpcClient.ts +26 -25
- package/src/network/index.ts +41 -44
- package/src/network/jsonrpc.ts +5 -5
- package/src/persistence/index.ts +5 -5
- package/src/persistence/types.ts +5 -2
- package/src/platform/index.ts +21 -0
- package/src/platform/types.ts +84 -0
- package/src/runtime/AgentXRuntime.ts +188 -61
- package/src/runtime/__tests__/AgentXRuntime.test.ts +343 -0
- package/src/runtime/index.ts +12 -25
- package/src/runtime/types.ts +10 -62
- package/src/session/index.ts +2 -3
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-AT5P47YA.js.map +0 -1
- package/dist/chunk-E5FPOAPO.js.map +0 -1
- package/dist/chunk-I7GYR3MN.js.map +0 -1
- package/dist/chunk-K6WXQ2RW.js.map +0 -1
- package/dist/workspace/index.d.ts +0 -111
- package/dist/wrapper-Y3UTVU2E.js +0 -3635
- package/dist/wrapper-Y3UTVU2E.js.map +0 -1
- package/src/workspace/index.ts +0 -27
- package/src/workspace/types.ts +0 -131
- /package/dist/{workspace → bash}/index.js.map +0 -0
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-SKS7S2RY.js.map} +0 -0
- /package/dist/{workspace → platform}/index.js +0 -0
|
@@ -14,51 +14,54 @@
|
|
|
14
14
|
* - message_stop
|
|
15
15
|
*
|
|
16
16
|
* Output Events (Message Layer):
|
|
17
|
-
* -
|
|
17
|
+
* - assistant_message (Message - includes text and tool calls in content)
|
|
18
18
|
* - tool_result_message (Message - tool execution result)
|
|
19
|
-
* - assistant_message (Message - complete assistant response)
|
|
20
19
|
*/
|
|
21
20
|
|
|
22
|
-
import type { Processor, ProcessorDefinition } from "../mealy";
|
|
23
21
|
import type {
|
|
24
|
-
// Input: StreamEvent (from agent layer)
|
|
25
|
-
StreamEvent,
|
|
26
|
-
MessageStartEvent,
|
|
27
|
-
TextDeltaEvent,
|
|
28
|
-
ToolUseStartEvent,
|
|
29
|
-
InputJsonDeltaEvent,
|
|
30
|
-
ToolResultEvent,
|
|
31
|
-
MessageStopEvent,
|
|
32
|
-
// Output: Message events
|
|
33
|
-
AssistantMessageEvent,
|
|
34
|
-
ToolCallMessageEvent,
|
|
35
|
-
ToolResultMessageEvent,
|
|
36
|
-
ErrorMessageEvent,
|
|
37
22
|
// Message types
|
|
38
23
|
AssistantMessage,
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
// Output: Message events
|
|
25
|
+
AssistantMessageEvent,
|
|
41
26
|
ErrorMessage,
|
|
27
|
+
ErrorMessageEvent,
|
|
28
|
+
InputJsonDeltaEvent,
|
|
29
|
+
MessageStartEvent,
|
|
30
|
+
MessageStopEvent,
|
|
31
|
+
// Input: StreamEvent (from agent layer)
|
|
32
|
+
StreamEvent,
|
|
33
|
+
TextDeltaEvent,
|
|
42
34
|
// Content parts
|
|
43
35
|
TextPart,
|
|
44
36
|
ToolCallPart,
|
|
37
|
+
ToolResultEvent,
|
|
38
|
+
ToolResultMessage,
|
|
39
|
+
ToolResultMessageEvent,
|
|
45
40
|
ToolResultPart,
|
|
41
|
+
ToolUseStartEvent,
|
|
46
42
|
} from "../../types";
|
|
43
|
+
import type { Processor, ProcessorDefinition } from "../mealy";
|
|
47
44
|
|
|
48
45
|
// ===== State Types =====
|
|
49
46
|
|
|
50
47
|
/**
|
|
51
48
|
* Pending content accumulator
|
|
49
|
+
*
|
|
50
|
+
* Tracks content blocks in the order they appear in the stream.
|
|
51
|
+
* Text and tool_use blocks may be interleaved.
|
|
52
52
|
*/
|
|
53
53
|
export interface PendingContent {
|
|
54
54
|
type: "text" | "tool_use";
|
|
55
|
-
index: number;
|
|
56
55
|
// For text content
|
|
57
56
|
textDeltas?: string[];
|
|
58
57
|
// For tool use
|
|
59
58
|
toolId?: string;
|
|
60
59
|
toolName?: string;
|
|
61
60
|
toolInputJson?: string;
|
|
61
|
+
/** True when tool_use_stop has been processed and input is fully parsed */
|
|
62
|
+
assembled?: boolean;
|
|
63
|
+
/** Parsed tool input (set at tool_use_stop time) */
|
|
64
|
+
parsedInput?: Record<string, unknown>;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
/**
|
|
@@ -86,10 +89,10 @@ export interface MessageAssemblerState {
|
|
|
86
89
|
messageStartTime: number | null;
|
|
87
90
|
|
|
88
91
|
/**
|
|
89
|
-
* Pending content blocks
|
|
90
|
-
*
|
|
92
|
+
* Pending content blocks in stream order.
|
|
93
|
+
* Preserves the interleaved order of text and tool_use blocks.
|
|
91
94
|
*/
|
|
92
|
-
pendingContents:
|
|
95
|
+
pendingContents: PendingContent[];
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
98
|
* Pending tool calls waiting for results
|
|
@@ -105,7 +108,7 @@ export function createInitialMessageAssemblerState(): MessageAssemblerState {
|
|
|
105
108
|
return {
|
|
106
109
|
currentMessageId: null,
|
|
107
110
|
messageStartTime: null,
|
|
108
|
-
pendingContents:
|
|
111
|
+
pendingContents: [],
|
|
109
112
|
pendingToolCalls: {},
|
|
110
113
|
};
|
|
111
114
|
}
|
|
@@ -119,12 +122,21 @@ function generateId(): string {
|
|
|
119
122
|
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
120
123
|
}
|
|
121
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Find last index matching a predicate (Array.findLastIndex polyfill)
|
|
127
|
+
*/
|
|
128
|
+
function findLastIndex<T>(arr: readonly T[], predicate: (item: T) => boolean): number {
|
|
129
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
130
|
+
if (predicate(arr[i])) return i;
|
|
131
|
+
}
|
|
132
|
+
return -1;
|
|
133
|
+
}
|
|
134
|
+
|
|
122
135
|
/**
|
|
123
136
|
* Output event types from MessageAssembler
|
|
124
137
|
*/
|
|
125
138
|
export type MessageAssemblerOutput =
|
|
126
139
|
| AssistantMessageEvent
|
|
127
|
-
| ToolCallMessageEvent
|
|
128
140
|
| ToolResultMessageEvent
|
|
129
141
|
| ErrorMessageEvent;
|
|
130
142
|
|
|
@@ -188,7 +200,7 @@ function handleMessageStart(
|
|
|
188
200
|
...state,
|
|
189
201
|
currentMessageId: data.messageId,
|
|
190
202
|
messageStartTime: event.timestamp,
|
|
191
|
-
pendingContents:
|
|
203
|
+
pendingContents: [],
|
|
192
204
|
},
|
|
193
205
|
[],
|
|
194
206
|
];
|
|
@@ -196,34 +208,32 @@ function handleMessageStart(
|
|
|
196
208
|
|
|
197
209
|
/**
|
|
198
210
|
* Handle text_delta event
|
|
211
|
+
*
|
|
212
|
+
* Appends to the last text block if one exists, otherwise creates a new one.
|
|
213
|
+
* This preserves the interleaved order: text after a tool_use gets its own block.
|
|
199
214
|
*/
|
|
200
215
|
function handleTextDelta(
|
|
201
216
|
state: Readonly<MessageAssemblerState>,
|
|
202
217
|
event: StreamEvent
|
|
203
218
|
): [MessageAssemblerState, MessageAssemblerOutput[]] {
|
|
204
219
|
const { data } = event as TextDeltaEvent;
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
index,
|
|
217
|
-
textDeltas: [data.text],
|
|
218
|
-
};
|
|
220
|
+
const lastContent = state.pendingContents[state.pendingContents.length - 1];
|
|
221
|
+
|
|
222
|
+
// Append to last text block if it exists
|
|
223
|
+
if (lastContent?.type === "text") {
|
|
224
|
+
const updated = [...state.pendingContents];
|
|
225
|
+
updated[updated.length - 1] = {
|
|
226
|
+
...lastContent,
|
|
227
|
+
textDeltas: [...(lastContent.textDeltas || []), data.text],
|
|
228
|
+
};
|
|
229
|
+
return [{ ...state, pendingContents: updated }, []];
|
|
230
|
+
}
|
|
219
231
|
|
|
232
|
+
// Create a new text block (preserves position after any preceding tool_use)
|
|
220
233
|
return [
|
|
221
234
|
{
|
|
222
235
|
...state,
|
|
223
|
-
pendingContents: {
|
|
224
|
-
...state.pendingContents,
|
|
225
|
-
[index]: pendingContent,
|
|
226
|
-
},
|
|
236
|
+
pendingContents: [...state.pendingContents, { type: "text", textDeltas: [data.text] }],
|
|
227
237
|
},
|
|
228
238
|
[],
|
|
229
239
|
];
|
|
@@ -237,23 +247,19 @@ function handleToolUseStart(
|
|
|
237
247
|
event: StreamEvent
|
|
238
248
|
): [MessageAssemblerState, MessageAssemblerOutput[]] {
|
|
239
249
|
const { data } = event as ToolUseStartEvent;
|
|
240
|
-
const index = 1; // Tool use uses index 1
|
|
241
|
-
|
|
242
|
-
const pendingContent: PendingContent = {
|
|
243
|
-
type: "tool_use",
|
|
244
|
-
index,
|
|
245
|
-
toolId: data.toolCallId,
|
|
246
|
-
toolName: data.toolName,
|
|
247
|
-
toolInputJson: "",
|
|
248
|
-
};
|
|
249
250
|
|
|
250
251
|
return [
|
|
251
252
|
{
|
|
252
253
|
...state,
|
|
253
|
-
pendingContents:
|
|
254
|
+
pendingContents: [
|
|
254
255
|
...state.pendingContents,
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
{
|
|
257
|
+
type: "tool_use",
|
|
258
|
+
toolId: data.toolCallId,
|
|
259
|
+
toolName: data.toolName,
|
|
260
|
+
toolInputJson: "",
|
|
261
|
+
},
|
|
262
|
+
],
|
|
257
263
|
},
|
|
258
264
|
[],
|
|
259
265
|
];
|
|
@@ -267,102 +273,76 @@ function handleInputJsonDelta(
|
|
|
267
273
|
event: StreamEvent
|
|
268
274
|
): [MessageAssemblerState, MessageAssemblerOutput[]] {
|
|
269
275
|
const { data } = event as InputJsonDeltaEvent;
|
|
270
|
-
const index = 1; // Tool use uses index 1
|
|
271
|
-
const existingContent = state.pendingContents[index];
|
|
272
276
|
|
|
273
|
-
|
|
274
|
-
|
|
277
|
+
// Find the last tool_use content in the array
|
|
278
|
+
const lastToolIndex = findLastIndex(
|
|
279
|
+
state.pendingContents,
|
|
280
|
+
(c) => c.type === "tool_use" && !c.assembled
|
|
281
|
+
);
|
|
282
|
+
if (lastToolIndex === -1) {
|
|
275
283
|
return [state, []];
|
|
276
284
|
}
|
|
277
285
|
|
|
278
|
-
const
|
|
286
|
+
const existingContent = state.pendingContents[lastToolIndex];
|
|
287
|
+
const updated = [...state.pendingContents];
|
|
288
|
+
updated[lastToolIndex] = {
|
|
279
289
|
...existingContent,
|
|
280
290
|
toolInputJson: (existingContent.toolInputJson || "") + data.partialJson,
|
|
281
291
|
};
|
|
282
292
|
|
|
283
|
-
return [
|
|
284
|
-
{
|
|
285
|
-
...state,
|
|
286
|
-
pendingContents: {
|
|
287
|
-
...state.pendingContents,
|
|
288
|
-
[index]: pendingContent,
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
[],
|
|
292
|
-
];
|
|
293
|
+
return [{ ...state, pendingContents: updated }, []];
|
|
293
294
|
}
|
|
294
295
|
|
|
295
296
|
/**
|
|
296
297
|
* Handle tool_use_stop event
|
|
297
298
|
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
299
|
+
* Marks the tool_use entry as assembled with parsed input.
|
|
300
|
+
* The entry stays in pendingContents to preserve its position.
|
|
301
|
+
* No event is emitted — tool calls are part of the assistant message.
|
|
300
302
|
*/
|
|
301
303
|
function handleToolUseStop(
|
|
302
304
|
state: Readonly<MessageAssemblerState>,
|
|
303
305
|
_event: StreamEvent
|
|
304
306
|
): [MessageAssemblerState, MessageAssemblerOutput[]] {
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
307
|
+
// Find the last unassembled tool_use content
|
|
308
|
+
const lastToolIndex = findLastIndex(
|
|
309
|
+
state.pendingContents,
|
|
310
|
+
(c) => c.type === "tool_use" && !c.assembled
|
|
311
|
+
);
|
|
312
|
+
if (lastToolIndex === -1) {
|
|
309
313
|
return [state, []];
|
|
310
314
|
}
|
|
311
315
|
|
|
312
|
-
|
|
316
|
+
const pendingContent = state.pendingContents[lastToolIndex];
|
|
313
317
|
const toolId = pendingContent.toolId || "";
|
|
314
318
|
const toolName = pendingContent.toolName || "";
|
|
315
319
|
|
|
316
|
-
// Parse tool input JSON
|
|
320
|
+
// Parse tool input JSON
|
|
317
321
|
let toolInput: Record<string, unknown> = {};
|
|
318
322
|
try {
|
|
319
323
|
toolInput = pendingContent.toolInputJson ? JSON.parse(pendingContent.toolInputJson) : {};
|
|
320
324
|
} catch {
|
|
321
|
-
// Failed to parse, use empty object
|
|
322
325
|
toolInput = {};
|
|
323
326
|
}
|
|
324
327
|
|
|
325
|
-
//
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
// Mark as assembled in-place (preserves position)
|
|
329
|
+
const updated = [...state.pendingContents];
|
|
330
|
+
updated[lastToolIndex] = {
|
|
331
|
+
...pendingContent,
|
|
332
|
+
assembled: true,
|
|
333
|
+
parsedInput: toolInput,
|
|
331
334
|
};
|
|
332
335
|
|
|
333
|
-
// Create ToolCallMessage (complete Message object)
|
|
334
|
-
// parentId links this tool call to its parent assistant message
|
|
335
|
-
const messageId = generateId();
|
|
336
|
-
const timestamp = Date.now();
|
|
337
|
-
const toolCallMessage: ToolCallMessage = {
|
|
338
|
-
id: messageId,
|
|
339
|
-
role: "assistant",
|
|
340
|
-
subtype: "tool-call",
|
|
341
|
-
toolCall,
|
|
342
|
-
timestamp,
|
|
343
|
-
parentId: state.currentMessageId || undefined,
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
// Emit tool_call_message event - data is complete Message object
|
|
347
|
-
const toolCallMessageEvent: ToolCallMessageEvent = {
|
|
348
|
-
type: "tool_call_message",
|
|
349
|
-
timestamp,
|
|
350
|
-
data: toolCallMessage,
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
// Remove from pending contents, add to pending tool calls
|
|
354
|
-
const { [index]: _, ...remainingContents } = state.pendingContents;
|
|
355
|
-
|
|
356
336
|
return [
|
|
357
337
|
{
|
|
358
338
|
...state,
|
|
359
|
-
pendingContents:
|
|
339
|
+
pendingContents: updated,
|
|
360
340
|
pendingToolCalls: {
|
|
361
341
|
...state.pendingToolCalls,
|
|
362
342
|
[toolId]: { id: toolId, name: toolName },
|
|
363
343
|
},
|
|
364
344
|
},
|
|
365
|
-
[
|
|
345
|
+
[], // No event emitted
|
|
366
346
|
];
|
|
367
347
|
}
|
|
368
348
|
|
|
@@ -427,6 +407,9 @@ function handleToolResult(
|
|
|
427
407
|
|
|
428
408
|
/**
|
|
429
409
|
* Handle message_stop event
|
|
410
|
+
*
|
|
411
|
+
* Assembles the complete AssistantMessage from pendingContents in stream order.
|
|
412
|
+
* Text and tool call parts are interleaved as they appeared in the stream.
|
|
430
413
|
*/
|
|
431
414
|
function handleMessageStop(
|
|
432
415
|
state: Readonly<MessageAssemblerState>,
|
|
@@ -438,21 +421,31 @@ function handleMessageStop(
|
|
|
438
421
|
return [state, []];
|
|
439
422
|
}
|
|
440
423
|
|
|
441
|
-
//
|
|
442
|
-
const
|
|
443
|
-
const sortedContents = Object.values(state.pendingContents).sort((a, b) => a.index - b.index);
|
|
424
|
+
// Build content parts in stream order from pendingContents
|
|
425
|
+
const contentParts: Array<TextPart | ToolCallPart> = [];
|
|
444
426
|
|
|
445
|
-
for (const pending of
|
|
427
|
+
for (const pending of state.pendingContents) {
|
|
446
428
|
if (pending.type === "text" && pending.textDeltas) {
|
|
447
|
-
|
|
429
|
+
const text = pending.textDeltas.join("");
|
|
430
|
+
if (text.trim().length > 0) {
|
|
431
|
+
contentParts.push({ type: "text", text });
|
|
432
|
+
}
|
|
433
|
+
} else if (pending.type === "tool_use" && pending.assembled) {
|
|
434
|
+
contentParts.push({
|
|
435
|
+
type: "tool-call",
|
|
436
|
+
id: pending.toolId || "",
|
|
437
|
+
name: pending.toolName || "",
|
|
438
|
+
input: pending.parsedInput || {},
|
|
439
|
+
});
|
|
448
440
|
}
|
|
449
441
|
}
|
|
450
442
|
|
|
451
|
-
const
|
|
443
|
+
const hasToolCalls = contentParts.some((p) => p.type === "tool-call");
|
|
444
|
+
const hasText = contentParts.some((p) => p.type === "text");
|
|
452
445
|
|
|
453
|
-
// Skip empty messages (
|
|
446
|
+
// Skip truly empty messages (no text AND no tool calls)
|
|
454
447
|
const stopReason = data.stopReason;
|
|
455
|
-
if (!
|
|
448
|
+
if (!hasText && !hasToolCalls) {
|
|
456
449
|
const shouldPreserveToolCalls = stopReason === "tool_use";
|
|
457
450
|
return [
|
|
458
451
|
{
|
|
@@ -463,15 +456,7 @@ function handleMessageStop(
|
|
|
463
456
|
];
|
|
464
457
|
}
|
|
465
458
|
|
|
466
|
-
// Create
|
|
467
|
-
const contentParts: TextPart[] = [
|
|
468
|
-
{
|
|
469
|
-
type: "text",
|
|
470
|
-
text: textContent,
|
|
471
|
-
},
|
|
472
|
-
];
|
|
473
|
-
|
|
474
|
-
// Create AssistantMessage (complete Message object)
|
|
459
|
+
// Create AssistantMessage with interleaved content
|
|
475
460
|
const timestamp = state.messageStartTime || Date.now();
|
|
476
461
|
const assistantMessage: AssistantMessage = {
|
|
477
462
|
id: state.currentMessageId,
|
|
@@ -481,7 +466,7 @@ function handleMessageStop(
|
|
|
481
466
|
timestamp,
|
|
482
467
|
};
|
|
483
468
|
|
|
484
|
-
// Emit AssistantMessageEvent
|
|
469
|
+
// Emit AssistantMessageEvent
|
|
485
470
|
const assistantEvent: AssistantMessageEvent = {
|
|
486
471
|
type: "assistant_message",
|
|
487
472
|
timestamp,
|
|
@@ -18,25 +18,25 @@
|
|
|
18
18
|
* - tool_executing
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import
|
|
21
|
+
import { createLogger } from "commonxjs/logger";
|
|
22
22
|
import type {
|
|
23
|
+
ConversationEndEvent,
|
|
24
|
+
ConversationInterruptedEvent,
|
|
25
|
+
ConversationRespondingEvent,
|
|
26
|
+
// Output: State events
|
|
27
|
+
ConversationStartEvent,
|
|
23
28
|
// Base type
|
|
24
29
|
EngineEvent,
|
|
25
|
-
|
|
26
|
-
StreamEvent,
|
|
30
|
+
ErrorOccurredEvent,
|
|
27
31
|
MessageStartEvent,
|
|
28
32
|
MessageStopEvent,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
ConversationStartEvent,
|
|
32
|
-
ConversationRespondingEvent,
|
|
33
|
-
ConversationEndEvent,
|
|
34
|
-
ConversationInterruptedEvent,
|
|
35
|
-
ToolPlannedEvent,
|
|
33
|
+
// Input: StreamEvent (from agent layer)
|
|
34
|
+
StreamEvent,
|
|
36
35
|
ToolExecutingEvent,
|
|
37
|
-
|
|
36
|
+
ToolPlannedEvent,
|
|
37
|
+
ToolUseStartEvent,
|
|
38
38
|
} from "../../types";
|
|
39
|
-
import {
|
|
39
|
+
import type { Processor, ProcessorDefinition } from "../mealy";
|
|
40
40
|
|
|
41
41
|
const logger = createLogger("engine/stateEventProcessor");
|
|
42
42
|
|
|
@@ -50,9 +50,7 @@ const logger = createLogger("engine/stateEventProcessor");
|
|
|
50
50
|
*
|
|
51
51
|
* Currently empty - no context needed as all information comes from events.
|
|
52
52
|
*/
|
|
53
|
-
export
|
|
54
|
-
// Empty - all information comes from events
|
|
55
|
-
}
|
|
53
|
+
export type StateEventProcessorContext = {};
|
|
56
54
|
|
|
57
55
|
/**
|
|
58
56
|
* Initial context factory for StateEventProcessor
|
|
@@ -2,30 +2,28 @@
|
|
|
2
2
|
* turnTrackerProcessor
|
|
3
3
|
*
|
|
4
4
|
* Pure Mealy transition function that tracks request-response turn pairs.
|
|
5
|
+
* Derives turn events entirely from stream-layer events (no external injection).
|
|
5
6
|
*
|
|
6
|
-
* Input Events:
|
|
7
|
-
* -
|
|
8
|
-
* - message_stop (
|
|
9
|
-
* - assistant_message (Message Layer)
|
|
7
|
+
* Input Events (Stream Layer):
|
|
8
|
+
* - message_start → emit turn_request (a new turn begins)
|
|
9
|
+
* - message_stop → emit turn_response (turn completes, based on stop reason)
|
|
10
10
|
*
|
|
11
11
|
* Output Events (Turn Layer):
|
|
12
12
|
* - turn_request
|
|
13
13
|
* - turn_response
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import type { Processor, ProcessorDefinition } from "../mealy";
|
|
17
16
|
import type {
|
|
18
|
-
|
|
19
|
-
StreamEvent,
|
|
20
|
-
AgentMessageEvent,
|
|
17
|
+
MessageStartEvent,
|
|
21
18
|
MessageStopEvent,
|
|
22
|
-
|
|
19
|
+
StreamEvent,
|
|
20
|
+
// Data types
|
|
21
|
+
TokenUsage,
|
|
23
22
|
// Output: Turn events
|
|
24
23
|
TurnRequestEvent,
|
|
25
24
|
TurnResponseEvent,
|
|
26
|
-
// Data types
|
|
27
|
-
TokenUsage,
|
|
28
25
|
} from "../../types";
|
|
26
|
+
import type { Processor, ProcessorDefinition } from "../mealy";
|
|
29
27
|
|
|
30
28
|
// ===== State Types =====
|
|
31
29
|
|
|
@@ -88,9 +86,9 @@ export type TurnTrackerOutput = TurnRequestEvent | TurnResponseEvent;
|
|
|
88
86
|
|
|
89
87
|
/**
|
|
90
88
|
* Input event types for TurnTracker
|
|
91
|
-
*
|
|
89
|
+
* Only stream-layer events — turn events are derived, not injected.
|
|
92
90
|
*/
|
|
93
|
-
export type TurnTrackerInput = StreamEvent
|
|
91
|
+
export type TurnTrackerInput = StreamEvent;
|
|
94
92
|
|
|
95
93
|
/**
|
|
96
94
|
* turnTrackerProcessor
|
|
@@ -104,39 +102,37 @@ export const turnTrackerProcessor: Processor<
|
|
|
104
102
|
TurnTrackerOutput
|
|
105
103
|
> = (state, input): [TurnTrackerState, TurnTrackerOutput[]] => {
|
|
106
104
|
switch (input.type) {
|
|
107
|
-
case "
|
|
108
|
-
return
|
|
105
|
+
case "message_start":
|
|
106
|
+
return handleMessageStart(state, input as MessageStartEvent);
|
|
109
107
|
|
|
110
108
|
case "message_stop":
|
|
111
109
|
return handleMessageStop(state, input as StreamEvent);
|
|
112
110
|
|
|
113
|
-
case "assistant_message":
|
|
114
|
-
// Turn completion is handled in message_stop
|
|
115
|
-
// This handler is kept for potential future use
|
|
116
|
-
return [state, []];
|
|
117
|
-
|
|
118
111
|
default:
|
|
119
112
|
return [state, []];
|
|
120
113
|
}
|
|
121
114
|
};
|
|
122
115
|
|
|
123
116
|
/**
|
|
124
|
-
* Handle
|
|
117
|
+
* Handle message_start event — a new turn begins
|
|
125
118
|
*/
|
|
126
|
-
function
|
|
119
|
+
function handleMessageStart(
|
|
127
120
|
state: Readonly<TurnTrackerState>,
|
|
128
|
-
event:
|
|
121
|
+
event: MessageStartEvent
|
|
129
122
|
): [TurnTrackerState, TurnTrackerOutput[]] {
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
// If there's already a pending turn (e.g. tool_use didn't end the turn),
|
|
124
|
+
// don't start a new one
|
|
125
|
+
if (state.pendingTurn) {
|
|
126
|
+
return [state, []];
|
|
127
|
+
}
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
const
|
|
129
|
+
const turnId = generateId();
|
|
130
|
+
const messageId = event.data.messageId ?? "";
|
|
135
131
|
|
|
136
132
|
const pendingTurn: PendingTurn = {
|
|
137
133
|
turnId,
|
|
138
|
-
messageId
|
|
139
|
-
content:
|
|
134
|
+
messageId,
|
|
135
|
+
content: "",
|
|
140
136
|
requestedAt: event.timestamp,
|
|
141
137
|
};
|
|
142
138
|
|
|
@@ -145,8 +141,8 @@ function handleUserMessage(
|
|
|
145
141
|
timestamp: Date.now(),
|
|
146
142
|
data: {
|
|
147
143
|
turnId,
|
|
148
|
-
messageId
|
|
149
|
-
content:
|
|
144
|
+
messageId,
|
|
145
|
+
content: "",
|
|
150
146
|
timestamp: event.timestamp,
|
|
151
147
|
},
|
|
152
148
|
};
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
+
import { createLogger } from "commonxjs/logger";
|
|
34
35
|
import type { Processor } from "./Processor";
|
|
35
|
-
import type { Store } from "./Store";
|
|
36
36
|
import type { Sink, SinkDefinition } from "./Sink";
|
|
37
|
-
import {
|
|
37
|
+
import type { Store } from "./Store";
|
|
38
38
|
|
|
39
39
|
const logger = createLogger("engine/Mealy");
|
|
40
40
|
|
|
@@ -28,13 +28,11 @@ import type { Processor } from "./Processor";
|
|
|
28
28
|
* });
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
|
-
export function combineProcessors<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[K in keyof TState]: Processor<TState[K], TInput, TOutput>;
|
|
37
|
-
}): Processor<TState, TInput, TOutput> {
|
|
31
|
+
export function combineProcessors<TState extends Record<string, unknown>, TInput, TOutput>(
|
|
32
|
+
processors: {
|
|
33
|
+
[K in keyof TState]: Processor<TState[K], TInput, TOutput>;
|
|
34
|
+
}
|
|
35
|
+
): Processor<TState, TInput, TOutput> {
|
|
38
36
|
return (state: Readonly<TState>, event: TInput): [TState, TOutput[]] => {
|
|
39
37
|
const newState = {} as TState;
|
|
40
38
|
const allOutputs: TOutput[] = [];
|
|
@@ -55,9 +53,11 @@ export function combineProcessors<
|
|
|
55
53
|
/**
|
|
56
54
|
* combineInitialStates - Helper to create initial state for combined processors
|
|
57
55
|
*/
|
|
58
|
-
export function combineInitialStates<TState extends Record<string, unknown>>(
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
export function combineInitialStates<TState extends Record<string, unknown>>(
|
|
57
|
+
initialStates: {
|
|
58
|
+
[K in keyof TState]: () => TState[K];
|
|
59
|
+
}
|
|
60
|
+
): () => TState {
|
|
61
61
|
return () => {
|
|
62
62
|
const state = {} as TState;
|
|
63
63
|
for (const key in initialStates) {
|
|
@@ -16,30 +16,28 @@
|
|
|
16
16
|
|
|
17
17
|
// ===== Core Components =====
|
|
18
18
|
|
|
19
|
-
// Source - Input (input adapter)
|
|
20
|
-
export { type Source, type SourceDefinition } from "./Source";
|
|
21
|
-
|
|
22
19
|
// Processor - Processing (pure Mealy transition function)
|
|
23
|
-
export {
|
|
24
|
-
|
|
20
|
+
export type { Processor, ProcessorDefinition, ProcessorResult } from "./Processor";
|
|
25
21
|
// Sink - Output (output adapter)
|
|
26
|
-
export {
|
|
22
|
+
export type { Sink, SinkDefinition } from "./Sink";
|
|
23
|
+
// Source - Input (input adapter)
|
|
24
|
+
export type { Source, SourceDefinition } from "./Source";
|
|
27
25
|
|
|
28
26
|
// Store - State storage
|
|
29
|
-
export { type Store
|
|
27
|
+
export { MemoryStore, type Store } from "./Store";
|
|
30
28
|
|
|
31
29
|
// ===== Mealy Runtime =====
|
|
32
30
|
|
|
33
|
-
export {
|
|
31
|
+
export { createMealy, Mealy, type MealyConfig, type ProcessResult } from "./Mealy";
|
|
34
32
|
|
|
35
33
|
// ===== Combinators =====
|
|
36
34
|
|
|
37
35
|
export {
|
|
38
|
-
combineProcessors,
|
|
39
|
-
combineInitialStates,
|
|
40
36
|
chainProcessors,
|
|
37
|
+
combineInitialStates,
|
|
38
|
+
combineProcessors,
|
|
41
39
|
filterProcessor,
|
|
40
|
+
identityProcessor,
|
|
42
41
|
mapOutput,
|
|
43
42
|
withLogging,
|
|
44
|
-
identityProcessor,
|
|
45
43
|
} from "./combinators";
|