@herdctl/chat 0.3.14 → 0.4.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.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for the transport-agnostic SDKMessage → chat-event translator.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=sdk-message-translator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-message-translator.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sdk-message-translator.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Tests for the transport-agnostic SDKMessage → chat-event translator.
3
+ */
4
+ import { describe, expect, it, vi } from "vitest";
5
+ import { createSDKMessageHandler, SDKMessageTranslator, } from "../sdk-message-translator.js";
6
+ // =============================================================================
7
+ // Helpers — build SDK messages in the shape the extractors expect
8
+ // =============================================================================
9
+ function assistantText(text) {
10
+ return { type: "assistant", message: { content: [{ type: "text", text }] } };
11
+ }
12
+ function assistantToolUse(id, name, input) {
13
+ return {
14
+ type: "assistant",
15
+ message: { content: [{ type: "tool_use", id, name, input }] },
16
+ };
17
+ }
18
+ function toolResult(toolUseId, output, isError = false) {
19
+ return {
20
+ type: "user",
21
+ message: {
22
+ content: [
23
+ { type: "tool_result", tool_use_id: toolUseId, content: output, is_error: isError },
24
+ ],
25
+ },
26
+ };
27
+ }
28
+ /**
29
+ * The CLI-runtime shape: a user message that carries the result BOTH as an
30
+ * id-less top-level `tool_use_result` (string/object, NO tool_use_id) AND as a
31
+ * nested `message.content[]` `tool_result` block that DOES carry the
32
+ * tool_use_id + is_error. Core's `extractToolResults` short-circuits on the
33
+ * top-level field (losing the id); the translator must prefer the nested block.
34
+ */
35
+ function cliToolResult(toolUseId, output, isError = false) {
36
+ return {
37
+ type: "user",
38
+ // Id-less top-level result (this is what short-circuits extractToolResults).
39
+ tool_use_result: output,
40
+ message: {
41
+ content: [
42
+ { type: "tool_result", tool_use_id: toolUseId, content: output, is_error: isError },
43
+ ],
44
+ },
45
+ };
46
+ }
47
+ /** SDK-runtime shape: only a top-level `tool_use_result`, no nested blocks. */
48
+ function sdkTopLevelToolResult(output) {
49
+ return {
50
+ type: "user",
51
+ tool_use_result: output,
52
+ };
53
+ }
54
+ describe("SDKMessageTranslator", () => {
55
+ describe("text deltas", () => {
56
+ it("emits assistant text via onText", async () => {
57
+ const onText = vi.fn();
58
+ const t = new SDKMessageTranslator({ onText });
59
+ await t.handle(assistantText("Hello "));
60
+ await t.handle(assistantText("world"));
61
+ expect(onText).toHaveBeenNthCalledWith(1, "Hello ");
62
+ expect(onText).toHaveBeenNthCalledWith(2, "world");
63
+ });
64
+ it("ignores non-assistant/non-user messages", async () => {
65
+ const onText = vi.fn();
66
+ const onToolCall = vi.fn();
67
+ const t = new SDKMessageTranslator({ onText, onToolCall });
68
+ await t.handle({ type: "system" });
69
+ await t.handle({ type: "result" });
70
+ await t.handle({ type: "stream_event" });
71
+ expect(onText).not.toHaveBeenCalled();
72
+ expect(onToolCall).not.toHaveBeenCalled();
73
+ });
74
+ it("does not emit onText for an assistant message with no text", async () => {
75
+ const onText = vi.fn();
76
+ const t = new SDKMessageTranslator({ onText });
77
+ await t.handle(assistantToolUse("t1", "Bash", { command: "ls" }));
78
+ expect(onText).not.toHaveBeenCalled();
79
+ });
80
+ });
81
+ describe("boundaries", () => {
82
+ it("emits a boundary between two consecutive assistant text turns", async () => {
83
+ const order = [];
84
+ const t = new SDKMessageTranslator({
85
+ onText: (text) => {
86
+ order.push(`text:${text}`);
87
+ },
88
+ onBoundary: () => {
89
+ order.push("boundary");
90
+ },
91
+ });
92
+ await t.handle(assistantText("first"));
93
+ await t.handle(assistantText("second"));
94
+ expect(order).toEqual(["text:first", "boundary", "text:second"]);
95
+ });
96
+ it("does not emit a boundary before the first text", async () => {
97
+ const onBoundary = vi.fn();
98
+ const t = new SDKMessageTranslator({ onText: vi.fn(), onBoundary });
99
+ await t.handle(assistantText("only"));
100
+ expect(onBoundary).not.toHaveBeenCalled();
101
+ });
102
+ it("does not emit a boundary for text that immediately follows a tool result", async () => {
103
+ const onBoundary = vi.fn();
104
+ const t = new SDKMessageTranslator({ onText: vi.fn(), onBoundary, onToolCall: vi.fn() });
105
+ await t.handle(assistantText("before tool"));
106
+ await t.handle(assistantToolUse("t1", "Read", { file_path: "/a" }));
107
+ await t.handle(toolResult("t1", "file contents"));
108
+ await t.handle(assistantText("after tool"));
109
+ // The tool result resets the text flag, so the post-tool text is NOT a boundary.
110
+ expect(onBoundary).not.toHaveBeenCalled();
111
+ });
112
+ });
113
+ describe("tool calls", () => {
114
+ it("pairs a tool_use with its result, including name, input summary and duration", async () => {
115
+ const calls = [];
116
+ let clock = 1000;
117
+ const t = new SDKMessageTranslator({ onToolCall: (c) => void calls.push(c) }, { now: () => clock });
118
+ await t.handle(assistantToolUse("t1", "Bash", { command: "echo hi" }));
119
+ clock = 1250; // 250ms later
120
+ await t.handle(toolResult("t1", "hi"));
121
+ expect(calls).toHaveLength(1);
122
+ expect(calls[0]).toEqual({
123
+ toolName: "Bash",
124
+ inputSummary: "echo hi",
125
+ output: "hi",
126
+ isError: false,
127
+ durationMs: 250,
128
+ toolUseId: "t1",
129
+ });
130
+ });
131
+ it("marks error results", async () => {
132
+ const calls = [];
133
+ const t = new SDKMessageTranslator({ onToolCall: (c) => void calls.push(c) });
134
+ await t.handle(assistantToolUse("t1", "Bash", { command: "false" }));
135
+ await t.handle(toolResult("t1", "boom", true));
136
+ expect(calls[0].isError).toBe(true);
137
+ expect(calls[0].output).toBe("boom");
138
+ });
139
+ it("falls back to 'Tool' when there is no matching tool_use", async () => {
140
+ const calls = [];
141
+ const t = new SDKMessageTranslator({ onToolCall: (c) => void calls.push(c) });
142
+ // Result arrives with no preceding tool_use of that id
143
+ await t.handle(toolResult("orphan", "result"));
144
+ expect(calls).toHaveLength(1);
145
+ expect(calls[0].toolName).toBe("Tool");
146
+ expect(calls[0].durationMs).toBeUndefined();
147
+ expect(calls[0].inputSummary).toBeUndefined();
148
+ });
149
+ it("does not emit tool calls when toolResults is false but still consumes pending uses", async () => {
150
+ const onToolCall = vi.fn();
151
+ const t = new SDKMessageTranslator({ onToolCall }, { toolResults: false });
152
+ await t.handle(assistantToolUse("t1", "Bash", { command: "ls" }));
153
+ await t.handle(toolResult("t1", "out"));
154
+ expect(onToolCall).not.toHaveBeenCalled();
155
+ });
156
+ describe("CLI runtime (double-encoded results)", () => {
157
+ it("pairs via the nested id-bearing block even when an id-less top-level tool_use_result is present", async () => {
158
+ const calls = [];
159
+ let clock = 1000;
160
+ const t = new SDKMessageTranslator({ onToolCall: (c) => void calls.push(c) }, { now: () => clock });
161
+ await t.handle(assistantToolUse("t1", "Bash", { command: "pwd" }));
162
+ clock = 1113; // 113ms later
163
+ // CLI shape: id-less top-level tool_use_result AND nested id-bearing block.
164
+ await t.handle(cliToolResult("t1", "/home/agent"));
165
+ expect(calls).toHaveLength(1);
166
+ expect(calls[0]).toEqual({
167
+ toolName: "Bash",
168
+ inputSummary: "pwd",
169
+ output: "/home/agent",
170
+ isError: false,
171
+ durationMs: 113,
172
+ toolUseId: "t1",
173
+ });
174
+ });
175
+ it("preserves is_error from the nested block in the CLI shape", async () => {
176
+ const calls = [];
177
+ const t = new SDKMessageTranslator({ onToolCall: (c) => void calls.push(c) });
178
+ await t.handle(assistantToolUse("t1", "Bash", { command: "false" }));
179
+ await t.handle(cliToolResult("t1", "boom", true));
180
+ expect(calls).toHaveLength(1);
181
+ expect(calls[0]).toMatchObject({
182
+ toolName: "Bash",
183
+ inputSummary: "false",
184
+ output: "boom",
185
+ isError: true,
186
+ toolUseId: "t1",
187
+ });
188
+ expect(calls[0].durationMs).toBeDefined();
189
+ });
190
+ it("does not mutate the original SDK message when stripping the top-level field", async () => {
191
+ const t = new SDKMessageTranslator({ onToolCall: vi.fn() });
192
+ await t.handle(assistantToolUse("t1", "Read", { file_path: "/a" }));
193
+ const msg = cliToolResult("t1", "contents");
194
+ await t.handle(msg);
195
+ // The id-less top-level field must still be present on the caller's object.
196
+ expect(msg.tool_use_result).toBe("contents");
197
+ });
198
+ it("still falls back to the id-less top-level result when there is no nested block (SDK shape)", async () => {
199
+ const calls = [];
200
+ const t = new SDKMessageTranslator({ onToolCall: (c) => void calls.push(c) });
201
+ // tool_use is tracked, but the SDK-shape result has no tool_use_id, so it
202
+ // cannot be paired — it falls back to the generic name (unchanged behavior).
203
+ await t.handle(assistantToolUse("t1", "Bash", { command: "ls" }));
204
+ await t.handle(sdkTopLevelToolResult("file-a\nfile-b"));
205
+ expect(calls).toHaveLength(1);
206
+ expect(calls[0].toolName).toBe("Tool");
207
+ expect(calls[0].output).toBe("file-a\nfile-b");
208
+ expect(calls[0].inputSummary).toBeUndefined();
209
+ expect(calls[0].durationMs).toBeUndefined();
210
+ expect(calls[0].toolUseId).toBeUndefined();
211
+ });
212
+ });
213
+ });
214
+ describe("backpressure", () => {
215
+ it("awaits async handlers in order", async () => {
216
+ const order = [];
217
+ const t = new SDKMessageTranslator({
218
+ onText: async (text) => {
219
+ await new Promise((r) => setTimeout(r, 5));
220
+ order.push(`text:${text}`);
221
+ },
222
+ onBoundary: async () => {
223
+ order.push("boundary");
224
+ },
225
+ });
226
+ await t.handle(assistantText("a"));
227
+ await t.handle(assistantText("b"));
228
+ expect(order).toEqual(["text:a", "boundary", "text:b"]);
229
+ });
230
+ });
231
+ describe("reset()", () => {
232
+ it("clears pending tool uses and text state", async () => {
233
+ const onBoundary = vi.fn();
234
+ const calls = [];
235
+ const t = new SDKMessageTranslator({
236
+ onText: vi.fn(),
237
+ onBoundary,
238
+ onToolCall: (c) => void calls.push(c),
239
+ });
240
+ await t.handle(assistantText("turn 1"));
241
+ await t.handle(assistantToolUse("t1", "Bash", { command: "x" }));
242
+ t.reset();
243
+ // After reset: previous text flag cleared (no boundary on next text)
244
+ await t.handle(assistantText("turn 2"));
245
+ expect(onBoundary).not.toHaveBeenCalled();
246
+ // After reset: the orphaned tool_use no longer pairs
247
+ await t.handle(toolResult("t1", "late"));
248
+ expect(calls[0].toolName).toBe("Tool");
249
+ });
250
+ });
251
+ });
252
+ describe("createSDKMessageHandler", () => {
253
+ it("returns an onMessage handler driving a fresh translator", async () => {
254
+ const onText = vi.fn();
255
+ const calls = [];
256
+ const handler = createSDKMessageHandler({
257
+ onText,
258
+ onToolCall: (c) => void calls.push(c),
259
+ });
260
+ await handler(assistantText("hi"));
261
+ await handler(assistantToolUse("t1", "Read", { file_path: "/f" }));
262
+ await handler(toolResult("t1", "contents"));
263
+ expect(onText).toHaveBeenCalledWith("hi");
264
+ expect(calls[0]).toMatchObject({ toolName: "Read", inputSummary: "/f", output: "contents" });
265
+ });
266
+ });
267
+ //# sourceMappingURL=sdk-message-translator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-message-translator.test.js","sourceRoot":"","sources":["../../src/__tests__/sdk-message-translator.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { DEFAULT_MESSAGE_DELAY_MS, DEFAULT_SPLIT_POINTS, findSplitPoint, formatC
16
16
  export { StreamingResponder, type StreamingResponderOptions, } from "./streaming-responder.js";
17
17
  export { type ContentBlock, extractMessageContent, hasTextContent, isTextContentBlock, type SDKMessage, type TextContentBlock, } from "./message-extraction.js";
18
18
  export { extractToolResultContent, extractToolResults, extractToolUseBlocks, getToolInputSummary, TOOL_EMOJIS, type ToolResult, type ToolUseBlock, } from "./tool-parsing.js";
19
+ export { createSDKMessageHandler, type SDKMessageHandlers, SDKMessageTranslator, type SDKMessageTranslatorOptions, type TranslatedToolCall, } from "./sdk-message-translator.js";
19
20
  export { checkDMUserFilter, type DMConfig, type DMFilterResult, getDMMode, isDMEnabled, shouldProcessInMode, } from "./dm-filter.js";
20
21
  export { AlreadyConnectedError, ChatConnectionError, ChatConnectorError, ChatErrorCode, InvalidTokenError, isAlreadyConnectedError, isChatConnectionError, isChatConnectorError, isInvalidTokenError, isMissingTokenError, MissingTokenError, } from "./errors.js";
21
22
  export { type ClassifiedError, ErrorCategory, isAuthError, isRateLimitError, isTransientError, type RetryOptions, type RetryResult, safeExecute, safeExecuteWithReply, USER_ERROR_MESSAGES, type UserErrorMessageKey, withRetry, } from "./error-handler.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAEL,KAAK,cAAc,EAEnB,oBAAoB,EAEpB,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,oBAAoB,EAEpB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,2BAA2B,EAE3B,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AAMpC,YAAY,EAEV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EAEnB,kBAAkB,EAClB,gBAAgB,EAEhB,mBAAmB,EAEnB,cAAc,EACd,mBAAmB,IAAI,4BAA4B,EAEnD,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAMpB,OAAO,EAEL,wBAAwB,EACxB,oBAAoB,EAEpB,cAAc,EACd,eAAe,EAEf,KAAK,mBAAmB,EACxB,cAAc,EACd,UAAU,EACV,KAAK,WAAW,EAChB,YAAY,EACZ,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,0BAA0B,CAAC;AAMlC,OAAO,EACL,KAAK,YAAY,EACjB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAElB,oBAAoB,EACpB,mBAAmB,EAEnB,WAAW,EACX,KAAK,UAAU,EAEf,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EACL,iBAAiB,EACjB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,SAAS,EACT,WAAW,EACX,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EAEnB,kBAAkB,EAElB,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EAErB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,eAAe,EAEpB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,WAAW,EACX,oBAAoB,EAEpB,mBAAmB,EACnB,KAAK,mBAAmB,EAExB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAEL,KAAK,cAAc,EAEnB,oBAAoB,EAEpB,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,oBAAoB,EAEpB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,2BAA2B,EAE3B,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AAMpC,YAAY,EAEV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EAEnB,kBAAkB,EAClB,gBAAgB,EAEhB,mBAAmB,EAEnB,cAAc,EACd,mBAAmB,IAAI,4BAA4B,EAEnD,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAMpB,OAAO,EAEL,wBAAwB,EACxB,oBAAoB,EAEpB,cAAc,EACd,eAAe,EAEf,KAAK,mBAAmB,EACxB,cAAc,EACd,UAAU,EACV,KAAK,WAAW,EAChB,YAAY,EACZ,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,0BAA0B,CAAC;AAMlC,OAAO,EACL,KAAK,YAAY,EACjB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAElB,oBAAoB,EACpB,mBAAmB,EAEnB,WAAW,EACX,KAAK,UAAU,EAEf,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAEL,uBAAuB,EACvB,KAAK,kBAAkB,EAEvB,oBAAoB,EACpB,KAAK,2BAA2B,EAEhC,KAAK,kBAAkB,GACxB,MAAM,6BAA6B,CAAC;AAMrC,OAAO,EACL,iBAAiB,EACjB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,SAAS,EACT,WAAW,EACX,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EAEnB,kBAAkB,EAElB,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EAErB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,eAAe,EAEpB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,WAAW,EACX,oBAAoB,EAEpB,mBAAmB,EACnB,KAAK,mBAAmB,EAExB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -47,6 +47,14 @@ extractToolUseBlocks, getToolInputSummary,
47
47
  // Constants
48
48
  TOOL_EMOJIS, } from "./tool-parsing.js";
49
49
  // =============================================================================
50
+ // SDK Message Translation
51
+ // =============================================================================
52
+ export {
53
+ // Factory
54
+ createSDKMessageHandler,
55
+ // Class
56
+ SDKMessageTranslator, } from "./sdk-message-translator.js";
57
+ // =============================================================================
50
58
  // DM Filtering
51
59
  // =============================================================================
52
60
  export { checkDMUserFilter, getDMMode, isDMEnabled, shouldProcessInMode, } from "./dm-filter.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,OAAO;AAGL,UAAU;AACV,oBAAoB;AACpB,QAAQ;AACR,kBAAkB,EAGlB,sBAAsB,EACtB,oBAAoB;AACpB,oBAAoB;AACpB,yBAAyB,EAEzB,qBAAqB,EACrB,2BAA2B;AAC3B,SAAS;AACT,gBAAgB,EAChB,mBAAmB,EAGnB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AAyBpC,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,OAAO;AACL,YAAY;AACZ,wBAAwB,EACxB,oBAAoB;AACpB,YAAY;AACZ,cAAc,EACd,eAAe,EAGf,cAAc,EACd,UAAU,EAEV,YAAY,EACZ,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF,OAAO,EACL,kBAAkB,GAEnB,MAAM,0BAA0B,CAAC;AAElC,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,OAAO,EAEL,qBAAqB,EACrB,cAAc,EACd,kBAAkB,GAGnB,MAAM,yBAAyB,CAAC;AAEjC,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,OAAO,EACL,wBAAwB,EACxB,kBAAkB;AAClB,YAAY;AACZ,oBAAoB,EACpB,mBAAmB;AACnB,YAAY;AACZ,WAAW,GAIZ,MAAM,mBAAmB,CAAC;AAE3B,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EAGjB,SAAS,EACT,WAAW,EACX,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,gFAAgF;AAChF,SAAS;AACT,gFAAgF;AAEhF,OAAO,EACL,qBAAqB,EACrB,mBAAmB;AACnB,gBAAgB;AAChB,kBAAkB;AAClB,cAAc;AACd,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB;AACrB,cAAc;AACd,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,OAAO;AAGL,aAAa;AACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAGhB,WAAW,EACX,oBAAoB;AACpB,YAAY;AACZ,mBAAmB;AAEnB,YAAY;AACZ,SAAS,GACV,MAAM,oBAAoB,CAAC;AAE5B,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,OAAO;AAGL,UAAU;AACV,oBAAoB;AACpB,QAAQ;AACR,kBAAkB,EAGlB,sBAAsB,EACtB,oBAAoB;AACpB,oBAAoB;AACpB,yBAAyB,EAEzB,qBAAqB,EACrB,2BAA2B;AAC3B,SAAS;AACT,gBAAgB,EAChB,mBAAmB,EAGnB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AAyBpC,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,OAAO;AACL,YAAY;AACZ,wBAAwB,EACxB,oBAAoB;AACpB,YAAY;AACZ,cAAc,EACd,eAAe,EAGf,cAAc,EACd,UAAU,EAEV,YAAY,EACZ,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF,OAAO,EACL,kBAAkB,GAEnB,MAAM,0BAA0B,CAAC;AAElC,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,OAAO,EAEL,qBAAqB,EACrB,cAAc,EACd,kBAAkB,GAGnB,MAAM,yBAAyB,CAAC;AAEjC,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,OAAO,EACL,wBAAwB,EACxB,kBAAkB;AAClB,YAAY;AACZ,oBAAoB,EACpB,mBAAmB;AACnB,YAAY;AACZ,WAAW,GAIZ,MAAM,mBAAmB,CAAC;AAE3B,gFAAgF;AAChF,0BAA0B;AAC1B,gFAAgF;AAEhF,OAAO;AACL,UAAU;AACV,uBAAuB;AAEvB,QAAQ;AACR,oBAAoB,GAIrB,MAAM,6BAA6B,CAAC;AAErC,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EAGjB,SAAS,EACT,WAAW,EACX,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,gFAAgF;AAChF,SAAS;AACT,gFAAgF;AAEhF,OAAO,EACL,qBAAqB,EACrB,mBAAmB;AACnB,gBAAgB;AAChB,kBAAkB;AAClB,cAAc;AACd,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB;AACrB,cAAc;AACd,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,OAAO;AAGL,aAAa;AACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAGhB,WAAW,EACX,oBAAoB;AACpB,YAAY;AACZ,mBAAmB;AAEnB,YAAY;AACZ,SAAS,GACV,MAAM,oBAAoB,CAAC;AAE5B,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Transport-agnostic SDKMessage → chat-event translation
3
+ *
4
+ * Every chat surface built on herdctl (Discord, Slack, the web dashboard, and
5
+ * downstream apps like paddock) consumes the same stream of `SDKMessage`s from
6
+ * `FleetManager.trigger({ onMessage })` and turns it into the same handful of
7
+ * UI events:
8
+ * - assistant text deltas,
9
+ * - a boundary between distinct assistant turns,
10
+ * - paired tool calls (a `tool_use` matched to its later `tool_result`,
11
+ * enriched with an input summary and a wall-clock duration).
12
+ *
13
+ * That translation was previously reimplemented per connector (see
14
+ * `@herdctl/web`'s WebChatManager and paddock's `ws.ts`). This module extracts
15
+ * it into one stateful translator so transports only have to supply the
16
+ * destination handlers.
17
+ *
18
+ * @module sdk-message-translator
19
+ */
20
+ import { type SDKMessage } from "./message-extraction.js";
21
+ /**
22
+ * A paired tool call: a `tool_use` block matched with its `tool_result`.
23
+ */
24
+ export interface TranslatedToolCall {
25
+ /** Tool name (e.g. "Bash", "Read"); "Tool" if the pairing could not be resolved */
26
+ toolName: string;
27
+ /** Human-readable summary of the tool input (e.g. the bash command or file path) */
28
+ inputSummary?: string;
29
+ /** Tool output text (may be empty) */
30
+ output: string;
31
+ /** Whether the tool reported an error */
32
+ isError: boolean;
33
+ /** Wall-clock duration between the tool_use and its result, in milliseconds */
34
+ durationMs?: number;
35
+ /** The originating tool_use id, when present */
36
+ toolUseId?: string;
37
+ }
38
+ /**
39
+ * Handlers invoked as SDK messages are translated. All are optional and may be
40
+ * async; the translator awaits them in order so transports can apply
41
+ * backpressure (e.g. a slow WebSocket send).
42
+ */
43
+ export interface SDKMessageHandlers {
44
+ /** Called with each assistant text delta as it streams in. */
45
+ onText?: (text: string) => void | Promise<void>;
46
+ /**
47
+ * Called when a new assistant turn begins after a previous one produced text
48
+ * (or after a tool call interrupts the text), so transports can split bubbles.
49
+ */
50
+ onBoundary?: () => void | Promise<void>;
51
+ /** Called once per tool result, paired with its originating tool_use. */
52
+ onToolCall?: (toolCall: TranslatedToolCall) => void | Promise<void>;
53
+ }
54
+ /**
55
+ * Options for {@link SDKMessageTranslator}.
56
+ */
57
+ export interface SDKMessageTranslatorOptions {
58
+ /**
59
+ * Emit tool calls via `onToolCall`. When `false`, tool_use blocks are still
60
+ * tracked (so boundaries stay correct) but no `onToolCall` is fired.
61
+ * Defaults to `true`.
62
+ */
63
+ toolResults?: boolean;
64
+ /**
65
+ * Clock used for duration measurement. Injectable for deterministic tests.
66
+ * Defaults to `Date.now`.
67
+ */
68
+ now?: () => number;
69
+ }
70
+ /**
71
+ * Stateful translator from the Claude Agent SDK message stream to chat-UI events.
72
+ *
73
+ * Feed every `SDKMessage` from a trigger's `onMessage` callback into
74
+ * {@link SDKMessageTranslator.handle}; it extracts assistant text, tracks
75
+ * `tool_use` blocks so they can be paired with their later `tool_result`s, and
76
+ * emits boundaries between distinct assistant turns.
77
+ *
78
+ * One instance corresponds to one trigger/turn (it holds per-turn state such as
79
+ * pending tool uses). Create a fresh translator per `trigger()` call.
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const translator = new SDKMessageTranslator({
84
+ * onText: (t) => ws.send({ type: "chat:response", text: t }),
85
+ * onToolCall: (c) => ws.send({ type: "chat:tool_call", ...c }),
86
+ * onBoundary: () => ws.send({ type: "chat:boundary" }),
87
+ * });
88
+ *
89
+ * await fleet.trigger("agent", undefined, {
90
+ * prompt,
91
+ * onMessage: (m) => translator.handle(m),
92
+ * });
93
+ * ```
94
+ */
95
+ export declare class SDKMessageTranslator {
96
+ private readonly handlers;
97
+ private readonly toolResults;
98
+ private readonly now;
99
+ /** tool_use id -> pending call awaiting its result */
100
+ private readonly pendingToolUses;
101
+ /** Whether the current assistant turn has already emitted text */
102
+ private hasAssistantText;
103
+ constructor(handlers: SDKMessageHandlers, options?: SDKMessageTranslatorOptions);
104
+ /**
105
+ * Translate a single SDK message, invoking the configured handlers.
106
+ *
107
+ * Safe to call with any SDK message type — non-assistant/non-user messages
108
+ * (system, result, stream events, etc.) are ignored.
109
+ *
110
+ * @param message - One message from the trigger's `onMessage` stream
111
+ */
112
+ handle(message: SDKMessage): Promise<void>;
113
+ /**
114
+ * Reset per-turn state. Call between reused turns if you keep one translator
115
+ * across multiple triggers (not required when creating one per trigger).
116
+ */
117
+ reset(): void;
118
+ private handleAssistant;
119
+ private handleUser;
120
+ }
121
+ /**
122
+ * Build an `onMessage` callback that drives a fresh {@link SDKMessageTranslator}.
123
+ *
124
+ * Convenience for the common case: pass the returned function straight to
125
+ * `FleetManager.trigger({ onMessage })`. Creates one translator bound to the
126
+ * given handlers, so this represents a single trigger/turn.
127
+ *
128
+ * @param handlers - Destination handlers for text/boundary/tool events
129
+ * @param options - Translator options (toolResults toggle, injectable clock)
130
+ * @returns An async `onMessage` handler suitable for `TriggerOptions.onMessage`
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * await fleet.trigger("agent", undefined, {
135
+ * prompt,
136
+ * onMessage: createSDKMessageHandler({
137
+ * onText: (t) => stream(t),
138
+ * onToolCall: (c) => renderTool(c),
139
+ * }),
140
+ * });
141
+ * ```
142
+ */
143
+ export declare function createSDKMessageHandler(handlers: SDKMessageHandlers, options?: SDKMessageTranslatorOptions): (message: SDKMessage) => Promise<void>;
144
+ //# sourceMappingURL=sdk-message-translator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-message-translator.d.ts","sourceRoot":"","sources":["../src/sdk-message-translator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAYjF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,yEAAyE;IACzE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAsED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;IACrE,kEAAkE;IAClE,OAAO,CAAC,gBAAgB,CAAS;gBAErB,QAAQ,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,2BAA2B;IAM/E;;;;;;;OAOG;IACG,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAQhD;;;OAGG;IACH,KAAK,IAAI,IAAI;YAOC,eAAe;YAyBf,UAAU;CAqCzB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,2BAA2B,GACpC,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAGxC"}
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Transport-agnostic SDKMessage → chat-event translation
3
+ *
4
+ * Every chat surface built on herdctl (Discord, Slack, the web dashboard, and
5
+ * downstream apps like paddock) consumes the same stream of `SDKMessage`s from
6
+ * `FleetManager.trigger({ onMessage })` and turns it into the same handful of
7
+ * UI events:
8
+ * - assistant text deltas,
9
+ * - a boundary between distinct assistant turns,
10
+ * - paired tool calls (a `tool_use` matched to its later `tool_result`,
11
+ * enriched with an input summary and a wall-clock duration).
12
+ *
13
+ * That translation was previously reimplemented per connector (see
14
+ * `@herdctl/web`'s WebChatManager and paddock's `ws.ts`). This module extracts
15
+ * it into one stateful translator so transports only have to supply the
16
+ * destination handlers.
17
+ *
18
+ * @module sdk-message-translator
19
+ */
20
+ import { extractMessageContent } from "./message-extraction.js";
21
+ import { extractToolResults, extractToolUseBlocks, getToolInputSummary, } from "./tool-parsing.js";
22
+ /**
23
+ * Extract tool results from a user message, preferring the id-bearing nested
24
+ * `message.content[]` `tool_result` blocks over core's `extractToolResults`.
25
+ *
26
+ * The CLI runtime surfaces a tool result twice on the same user message:
27
+ * 1. a **top-level `tool_use_result`** (string/object) that carries NO
28
+ * `tool_use_id`, and
29
+ * 2. a nested `message.content[]` `tool_result` block that DOES carry the
30
+ * `tool_use_id` (plus `is_error` and string/array content).
31
+ *
32
+ * Core's {@link extractToolResults} short-circuits on the top-level field and
33
+ * returns the id-less result first — so the translator can't pair it back to
34
+ * its `tool_use` and falls back to a generic `toolName: "Tool"` with no input
35
+ * summary or duration.
36
+ *
37
+ * When a user message has BOTH a top-level `tool_use_result` AND nested
38
+ * id-bearing `tool_result` block(s), this helper strips the top-level field
39
+ * (on a shallow clone — the SDK's object is never mutated) so
40
+ * {@link extractToolResults} takes its nested branch and preserves the
41
+ * `tool_use_id` for correct name/summary/duration pairing. Every other shape
42
+ * — including SDK-runtime messages that only carry a top-level
43
+ * `tool_use_result` — is passed to {@link extractToolResults} unchanged, so
44
+ * existing SDK-runtime behavior is preserved.
45
+ */
46
+ function extractToolResultsPreferringNested(message) {
47
+ const content = message.message?.content;
48
+ if (Array.isArray(content)) {
49
+ const hasNestedToolResult = content.some((block) => block !== null &&
50
+ typeof block === "object" &&
51
+ "type" in block &&
52
+ block.type === "tool_result");
53
+ // Only prefer the nested path when the message actually carried nested
54
+ // tool_result blocks. When it does, extractToolResults already parses those
55
+ // id-bearing blocks correctly — the bug is only that the top-level
56
+ // `tool_use_result` short-circuit runs *first*, so we strip that field
57
+ // (on a shallow clone; the SDK's object is untouched) and let the core
58
+ // helper take its nested branch. Messages with only a top-level
59
+ // `tool_use_result` (SDK-runtime shape) fall through unchanged below.
60
+ if (hasNestedToolResult && message.tool_use_result !== undefined) {
61
+ const { tool_use_result: _dropped, ...withoutTopLevel } = message;
62
+ return extractToolResults(withoutTopLevel);
63
+ }
64
+ }
65
+ // No nested tool_result blocks: defer to the core helper, which also handles
66
+ // the top-level `tool_use_result` (SDK-runtime) shape.
67
+ return extractToolResults(message);
68
+ }
69
+ /**
70
+ * Stateful translator from the Claude Agent SDK message stream to chat-UI events.
71
+ *
72
+ * Feed every `SDKMessage` from a trigger's `onMessage` callback into
73
+ * {@link SDKMessageTranslator.handle}; it extracts assistant text, tracks
74
+ * `tool_use` blocks so they can be paired with their later `tool_result`s, and
75
+ * emits boundaries between distinct assistant turns.
76
+ *
77
+ * One instance corresponds to one trigger/turn (it holds per-turn state such as
78
+ * pending tool uses). Create a fresh translator per `trigger()` call.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const translator = new SDKMessageTranslator({
83
+ * onText: (t) => ws.send({ type: "chat:response", text: t }),
84
+ * onToolCall: (c) => ws.send({ type: "chat:tool_call", ...c }),
85
+ * onBoundary: () => ws.send({ type: "chat:boundary" }),
86
+ * });
87
+ *
88
+ * await fleet.trigger("agent", undefined, {
89
+ * prompt,
90
+ * onMessage: (m) => translator.handle(m),
91
+ * });
92
+ * ```
93
+ */
94
+ export class SDKMessageTranslator {
95
+ handlers;
96
+ toolResults;
97
+ now;
98
+ /** tool_use id -> pending call awaiting its result */
99
+ pendingToolUses = new Map();
100
+ /** Whether the current assistant turn has already emitted text */
101
+ hasAssistantText = false;
102
+ constructor(handlers, options) {
103
+ this.handlers = handlers;
104
+ this.toolResults = options?.toolResults ?? true;
105
+ this.now = options?.now ?? Date.now;
106
+ }
107
+ /**
108
+ * Translate a single SDK message, invoking the configured handlers.
109
+ *
110
+ * Safe to call with any SDK message type — non-assistant/non-user messages
111
+ * (system, result, stream events, etc.) are ignored.
112
+ *
113
+ * @param message - One message from the trigger's `onMessage` stream
114
+ */
115
+ async handle(message) {
116
+ if (message.type === "assistant") {
117
+ await this.handleAssistant(message);
118
+ }
119
+ else if (message.type === "user") {
120
+ await this.handleUser(message);
121
+ }
122
+ }
123
+ /**
124
+ * Reset per-turn state. Call between reused turns if you keep one translator
125
+ * across multiple triggers (not required when creating one per trigger).
126
+ */
127
+ reset() {
128
+ this.pendingToolUses.clear();
129
+ this.hasAssistantText = false;
130
+ }
131
+ // ---------------------------------------------------------------------------
132
+ async handleAssistant(message) {
133
+ const content = extractMessageContent(message);
134
+ if (content) {
135
+ // A new assistant turn after a previous one produced text → boundary.
136
+ if (this.hasAssistantText) {
137
+ this.hasAssistantText = false;
138
+ await this.handlers.onBoundary?.();
139
+ }
140
+ this.hasAssistantText = true;
141
+ await this.handlers.onText?.(content);
142
+ }
143
+ // Track tool_use blocks so we can pair them with results later. We track
144
+ // even when toolResults is disabled so boundary handling stays correct.
145
+ for (const block of extractToolUseBlocks(message)) {
146
+ if (block.id) {
147
+ this.pendingToolUses.set(block.id, {
148
+ name: block.name,
149
+ input: block.input,
150
+ startTime: this.now(),
151
+ });
152
+ }
153
+ }
154
+ }
155
+ async handleUser(message) {
156
+ const results = extractToolResultsPreferringNested(message);
157
+ if (results.length === 0) {
158
+ return;
159
+ }
160
+ // A tool result ends the current text run; the next assistant text is a new
161
+ // bubble. Drop the text flag so we don't emit a spurious boundary, but the
162
+ // transport already received the text via onText.
163
+ this.hasAssistantText = false;
164
+ if (!this.toolResults || !this.handlers.onToolCall) {
165
+ // Still consume pending tool uses so the map doesn't leak.
166
+ for (const result of results) {
167
+ if (result.toolUseId)
168
+ this.pendingToolUses.delete(result.toolUseId);
169
+ }
170
+ return;
171
+ }
172
+ for (const result of results) {
173
+ const toolUse = result.toolUseId ? this.pendingToolUses.get(result.toolUseId) : undefined;
174
+ if (result.toolUseId) {
175
+ this.pendingToolUses.delete(result.toolUseId);
176
+ }
177
+ await this.handlers.onToolCall({
178
+ toolName: toolUse?.name ?? "Tool",
179
+ inputSummary: toolUse ? getToolInputSummary(toolUse.name, toolUse.input) : undefined,
180
+ output: result.output,
181
+ isError: result.isError,
182
+ durationMs: toolUse ? this.now() - toolUse.startTime : undefined,
183
+ toolUseId: result.toolUseId,
184
+ });
185
+ }
186
+ }
187
+ }
188
+ /**
189
+ * Build an `onMessage` callback that drives a fresh {@link SDKMessageTranslator}.
190
+ *
191
+ * Convenience for the common case: pass the returned function straight to
192
+ * `FleetManager.trigger({ onMessage })`. Creates one translator bound to the
193
+ * given handlers, so this represents a single trigger/turn.
194
+ *
195
+ * @param handlers - Destination handlers for text/boundary/tool events
196
+ * @param options - Translator options (toolResults toggle, injectable clock)
197
+ * @returns An async `onMessage` handler suitable for `TriggerOptions.onMessage`
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * await fleet.trigger("agent", undefined, {
202
+ * prompt,
203
+ * onMessage: createSDKMessageHandler({
204
+ * onText: (t) => stream(t),
205
+ * onToolCall: (c) => renderTool(c),
206
+ * }),
207
+ * });
208
+ * ```
209
+ */
210
+ export function createSDKMessageHandler(handlers, options) {
211
+ const translator = new SDKMessageTranslator(handlers, options);
212
+ return (message) => translator.handle(message);
213
+ }
214
+ //# sourceMappingURL=sdk-message-translator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-message-translator.js","sourceRoot":"","sources":["../src/sdk-message-translator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herdctl/chat",
3
- "version": "0.3.14",
3
+ "version": "0.4.1",
4
4
  "description": "Shared chat infrastructure for herdctl connectors",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "yaml": "^2.3.0",
14
14
  "zod": "^3.22.0",
15
- "@herdctl/core": "5.10.1"
15
+ "@herdctl/core": "5.12.0"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@vitest/coverage-v8": "^4.0.17",