@poncho-ai/cli 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.turbo/turbo-build.log +5 -5
  2. package/CHANGELOG.md +18 -0
  3. package/dist/{chunk-6JHNHDFF.js → chunk-COLXQM6J.js} +9 -6
  4. package/dist/cli.js +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/{run-interactive-ink-X7VHWGLT.js → run-interactive-ink-Z3U5SV4C.js} +1 -1
  7. package/package.json +3 -3
  8. package/src/index.ts +9 -6
  9. package/.turbo/turbo-test.log +0 -389
  10. package/dist/chunk-42U2R3FH.js +0 -5752
  11. package/dist/chunk-4UDNQZ3G.js +0 -5752
  12. package/dist/chunk-5NHWU4QU.js +0 -5752
  13. package/dist/chunk-6CDE6R7D.js +0 -5752
  14. package/dist/chunk-74HD63WM.js +0 -5819
  15. package/dist/chunk-7TRWWFGI.js +0 -5752
  16. package/dist/chunk-B5HASFPF.js +0 -5803
  17. package/dist/chunk-DFV5DGX4.js +0 -5794
  18. package/dist/chunk-DHQN2X5P.js +0 -5803
  19. package/dist/chunk-G67AWHXV.js +0 -5752
  20. package/dist/chunk-GFGEMANG.js +0 -5820
  21. package/dist/chunk-HYTF3H3J.js +0 -5795
  22. package/dist/chunk-IZJUA24R.js +0 -5750
  23. package/dist/chunk-J2MTY7EY.js +0 -5780
  24. package/dist/chunk-KITZQSRW.js +0 -5801
  25. package/dist/chunk-KKQSJC2U.js +0 -5750
  26. package/dist/chunk-L65TFTEI.js +0 -5752
  27. package/dist/chunk-MGR2GJMB.js +0 -5803
  28. package/dist/chunk-O5NLOW2I.js +0 -5752
  29. package/dist/chunk-OGTT4YJG.js +0 -5752
  30. package/dist/chunk-OHKXVDVM.js +0 -5752
  31. package/dist/chunk-OTOMFL3L.js +0 -5773
  32. package/dist/chunk-PHVOJ2R5.js +0 -5781
  33. package/dist/chunk-Q3WHF2FP.js +0 -5752
  34. package/dist/chunk-RN7FDRZH.js +0 -5752
  35. package/dist/chunk-SWPCETEB.js +0 -5772
  36. package/dist/chunk-VKPDG7AE.js +0 -5803
  37. package/dist/chunk-VP4ABFQK.js +0 -5795
  38. package/dist/chunk-YARNE46F.js +0 -5803
  39. package/dist/chunk-ZCLLCLRR.js +0 -5752
  40. package/dist/chunk-ZHHKZDHY.js +0 -5795
  41. package/dist/run-interactive-ink-2CVZHZLL.js +0 -535
  42. package/dist/run-interactive-ink-3TNAVPQ7.js +0 -534
  43. package/dist/run-interactive-ink-54UJ6WGA.js +0 -535
  44. package/dist/run-interactive-ink-64XY2KJD.js +0 -535
  45. package/dist/run-interactive-ink-7EB3ZX6P.js +0 -535
  46. package/dist/run-interactive-ink-7OSESHKH.js +0 -535
  47. package/dist/run-interactive-ink-BU4ZKI3Z.js +0 -535
  48. package/dist/run-interactive-ink-CH7BVAFL.js +0 -535
  49. package/dist/run-interactive-ink-DFIJTWMT.js +0 -535
  50. package/dist/run-interactive-ink-DORF57NC.js +0 -535
  51. package/dist/run-interactive-ink-EL7MPT4C.js +0 -1957
  52. package/dist/run-interactive-ink-EOW4MLEH.js +0 -535
  53. package/dist/run-interactive-ink-EU3DN4MJ.js +0 -535
  54. package/dist/run-interactive-ink-FFIGZNGR.js +0 -535
  55. package/dist/run-interactive-ink-HMVUIZRO.js +0 -533
  56. package/dist/run-interactive-ink-LNSWAC2D.js +0 -1964
  57. package/dist/run-interactive-ink-M45PYHTA.js +0 -1964
  58. package/dist/run-interactive-ink-MQTTMSSO.js +0 -535
  59. package/dist/run-interactive-ink-NT66KRS5.js +0 -535
  60. package/dist/run-interactive-ink-O5AV46ZE.js +0 -535
  61. package/dist/run-interactive-ink-OC57VVOY.js +0 -535
  62. package/dist/run-interactive-ink-PTUDJKT5.js +0 -535
  63. package/dist/run-interactive-ink-PYQFHCNW.js +0 -537
  64. package/dist/run-interactive-ink-QXIIUBIC.js +0 -534
  65. package/dist/run-interactive-ink-SOGKAQAE.js +0 -522
  66. package/dist/run-interactive-ink-UPMUH72Q.js +0 -520
  67. package/dist/run-interactive-ink-W4NEF7FL.js +0 -522
  68. package/dist/run-interactive-ink-WBPOSHHC.js +0 -535
  69. package/dist/run-interactive-ink-X6PKW7NZ.js +0 -1964
  70. package/dist/run-interactive-ink-XEK5ZPSU.js +0 -535
  71. package/dist/run-interactive-ink-YWJ5OBNI.js +0 -535
@@ -1,535 +0,0 @@
1
- import {
2
- consumeFirstRunIntro,
3
- inferConversationTitle,
4
- resolveHarnessEnvironment
5
- } from "./chunk-HYTF3H3J.js";
6
-
7
- // src/run-interactive-ink.ts
8
- import * as readline from "readline";
9
- import { stdout } from "process";
10
- import {
11
- parseAgentFile
12
- } from "@poncho-ai/harness";
13
- var C = {
14
- reset: "\x1B[0m",
15
- bold: "\x1B[1m",
16
- dim: "\x1B[2m",
17
- cyan: "\x1B[36m",
18
- green: "\x1B[32m",
19
- yellow: "\x1B[33m",
20
- red: "\x1B[31m",
21
- gray: "\x1B[90m",
22
- magenta: "\x1B[35m"
23
- };
24
- var green = (s) => `${C.green}${s}${C.reset}`;
25
- var yellow = (s) => `${C.yellow}${s}${C.reset}`;
26
- var red = (s) => `${C.red}${s}${C.reset}`;
27
- var gray = (s) => `${C.gray}${s}${C.reset}`;
28
- var magenta = (s) => `${C.magenta}${s}${C.reset}`;
29
- var FAUX_TOOL_LOG_PATTERN = /Tool Used:|Tool Result:|\blist_skills\b|\bcreate_skill\b|\bedit_skill\b/i;
30
- var formatDuration = (ms) => ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
31
- var stringifyValue = (v) => {
32
- try {
33
- return JSON.stringify(v);
34
- } catch {
35
- return String(v);
36
- }
37
- };
38
- var truncate = (v, max) => v.length <= max ? v : `${v.slice(0, Math.max(0, max - 3))}...`;
39
- var compactPreview = (v, max = 120) => truncate(stringifyValue(v).replace(/\s+/g, " "), max);
40
- var loadMetadata = async (workingDir) => {
41
- let agentName = "agent";
42
- let model = "unknown";
43
- let provider = "unknown";
44
- try {
45
- const parsed = await parseAgentFile(workingDir);
46
- agentName = parsed.frontmatter.name ?? agentName;
47
- model = parsed.frontmatter.model?.name ?? model;
48
- provider = parsed.frontmatter.model?.provider ?? provider;
49
- } catch {
50
- }
51
- return {
52
- agentName,
53
- model,
54
- provider,
55
- workingDir,
56
- environment: resolveHarnessEnvironment()
57
- };
58
- };
59
- var ask = (rl, prompt) => new Promise((res) => {
60
- rl.question(prompt, (answer) => res(answer));
61
- });
62
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
63
- var streamTextAsTokens = async (text) => {
64
- const tokens = text.match(/\S+\s*|\n/g) ?? [text];
65
- for (const token of tokens) {
66
- stdout.write(token);
67
- const trimmed = token.trim();
68
- const delay = trimmed.length === 0 ? 0 : Math.max(4, Math.min(18, Math.floor(trimmed.length / 2)));
69
- await sleep(delay);
70
- }
71
- };
72
- var OWNER_ID = "local-owner";
73
- var computeTurn = (messages) => Math.max(1, Math.floor(messages.length / 2) + 1);
74
- var formatDate = (value) => {
75
- try {
76
- return new Date(value).toLocaleString();
77
- } catch {
78
- return String(value);
79
- }
80
- };
81
- var handleSlash = async (command, state, conversationStore) => {
82
- const [rawCommand, ...args] = command.trim().split(/\s+/);
83
- const norm = rawCommand.toLowerCase();
84
- if (norm === "/help") {
85
- console.log(
86
- gray(
87
- "commands> /help /clear /exit /tools /list /open <id> /new [title] /delete [id] /continue /reset [all]"
88
- )
89
- );
90
- return { shouldExit: false };
91
- }
92
- if (norm === "/clear") {
93
- process.stdout.write("\x1B[2J\x1B[H");
94
- return { shouldExit: false };
95
- }
96
- if (norm === "/exit") {
97
- return { shouldExit: true };
98
- }
99
- if (norm === "/list") {
100
- const conversations = await conversationStore.list(OWNER_ID);
101
- if (conversations.length === 0) {
102
- console.log(gray("conversations> none"));
103
- return { shouldExit: false };
104
- }
105
- console.log(gray("conversations>"));
106
- for (const conversation of conversations) {
107
- const activeMarker = state.activeConversationId === conversation.conversationId ? "*" : " ";
108
- const maxTitleLen = 40;
109
- const title = conversation.title.length > maxTitleLen ? conversation.title.slice(0, maxTitleLen - 1) + "\u2026" : conversation.title;
110
- console.log(
111
- gray(
112
- `${activeMarker} ${conversation.conversationId} | ${title} | ${formatDate(conversation.updatedAt)}`
113
- )
114
- );
115
- }
116
- return { shouldExit: false };
117
- }
118
- if (norm === "/open") {
119
- const conversationId = args[0];
120
- if (!conversationId) {
121
- console.log(yellow("usage> /open <conversationId>"));
122
- return { shouldExit: false };
123
- }
124
- const conversation = await conversationStore.get(conversationId);
125
- if (!conversation) {
126
- console.log(yellow(`conversations> not found: ${conversationId}`));
127
- return { shouldExit: false };
128
- }
129
- state.activeConversationId = conversation.conversationId;
130
- state.messages = [...conversation.messages];
131
- state.turn = computeTurn(state.messages);
132
- console.log(gray(`conversations> opened ${conversation.conversationId}`));
133
- return { shouldExit: false };
134
- }
135
- if (norm === "/new") {
136
- const title = args.join(" ").trim();
137
- const conversation = await conversationStore.create(OWNER_ID, title || void 0);
138
- state.activeConversationId = conversation.conversationId;
139
- state.messages = [];
140
- state.turn = 1;
141
- console.log(gray(`conversations> new ${conversation.conversationId}`));
142
- return { shouldExit: false };
143
- }
144
- if (norm === "/delete") {
145
- const targetConversationId = args[0] ?? state.activeConversationId ?? "";
146
- if (!targetConversationId) {
147
- console.log(yellow("usage> /delete <conversationId>"));
148
- return { shouldExit: false };
149
- }
150
- const removed = await conversationStore.delete(targetConversationId);
151
- if (!removed) {
152
- console.log(yellow(`conversations> not found: ${targetConversationId}`));
153
- return { shouldExit: false };
154
- }
155
- if (state.activeConversationId === targetConversationId) {
156
- state.activeConversationId = null;
157
- state.messages = [];
158
- state.turn = 1;
159
- }
160
- console.log(gray(`conversations> deleted ${targetConversationId}`));
161
- return { shouldExit: false };
162
- }
163
- if (norm === "/continue") {
164
- const conversations = await conversationStore.list(OWNER_ID);
165
- const latest = conversations[0];
166
- if (!latest) {
167
- console.log(yellow("conversations> no conversations to continue"));
168
- return { shouldExit: false };
169
- }
170
- state.activeConversationId = latest.conversationId;
171
- state.messages = [...latest.messages];
172
- state.turn = computeTurn(state.messages);
173
- console.log(gray(`conversations> continued ${latest.conversationId}`));
174
- return { shouldExit: false };
175
- }
176
- if (norm === "/reset") {
177
- if (args[0]?.toLowerCase() === "all") {
178
- const conversations = await conversationStore.list(OWNER_ID);
179
- for (const conversation2 of conversations) {
180
- await conversationStore.delete(conversation2.conversationId);
181
- }
182
- state.activeConversationId = null;
183
- state.messages = [];
184
- state.turn = 1;
185
- console.log(gray("conversations> reset all"));
186
- return { shouldExit: false };
187
- }
188
- if (!state.activeConversationId) {
189
- state.messages = [];
190
- state.turn = 1;
191
- console.log(gray("conversations> current session reset"));
192
- return { shouldExit: false };
193
- }
194
- const conversation = await conversationStore.get(state.activeConversationId);
195
- if (!conversation) {
196
- state.activeConversationId = null;
197
- state.messages = [];
198
- state.turn = 1;
199
- console.log(yellow("conversations> active conversation no longer exists"));
200
- return { shouldExit: false };
201
- }
202
- await conversationStore.update({
203
- ...conversation,
204
- messages: []
205
- });
206
- state.messages = [];
207
- state.turn = 1;
208
- console.log(gray(`conversations> reset ${conversation.conversationId}`));
209
- return { shouldExit: false };
210
- }
211
- console.log(yellow(`Unknown command: ${command}`));
212
- return { shouldExit: false };
213
- };
214
- var runInteractiveInk = async ({
215
- harness,
216
- params,
217
- workingDir,
218
- config,
219
- conversationStore,
220
- onSetApprovalCallback
221
- }) => {
222
- const metadata = await loadMetadata(workingDir);
223
- const rl = readline.createInterface({
224
- input: process.stdin,
225
- output: process.stdout,
226
- terminal: true
227
- });
228
- if (onSetApprovalCallback) {
229
- onSetApprovalCallback((req) => {
230
- process.stdout.write("\n");
231
- const preview = compactPreview(req.input, 100);
232
- rl.question(
233
- `${C.yellow}${C.bold}Tool "${req.tool}" requires approval${C.reset}
234
- ${C.gray}input: ${preview}${C.reset}
235
- ${C.yellow}approve? (y/n): ${C.reset}`,
236
- (answer) => {
237
- const approved = answer.trim().toLowerCase() === "y";
238
- console.log(
239
- approved ? green(` approved ${req.tool}`) : magenta(` denied ${req.tool}`)
240
- );
241
- req.resolve(approved);
242
- }
243
- );
244
- });
245
- }
246
- const mascot = [
247
- `${C.yellow} \u28C0\u28C0\u28C0\u28C0\u28C0\u28C0${C.reset}`,
248
- `${C.yellow} \u2820\u283E\u281B\u281B\u281B\u281B\u281B\u281B\u2837\u2804${C.reset}`,
249
- `${C.gray} \u2847${C.cyan} \u2836 \u2836 ${C.gray}\u28B8${C.reset}`,
250
- `${C.gray} \u2823\u2840${C.cyan} \u2812\u281A${C.gray}\u2880\u281C${C.reset}`,
251
- `${C.yellow} \u28FF\u28FF\u28FF\u28FF\u28FF\u28FF${C.reset}`,
252
- `${C.gray} \u2803 \u2818${C.reset}`
253
- ];
254
- console.log("");
255
- for (const line of mascot) {
256
- console.log(line);
257
- }
258
- console.log(`${C.bold}${C.cyan} poncho${C.reset}`);
259
- console.log("");
260
- console.log(
261
- gray(
262
- ` ${metadata.agentName} \xB7 ${metadata.provider}/${metadata.model} \xB7 ${metadata.environment}`
263
- )
264
- );
265
- console.log(gray(' Type "exit" to quit, "/help" for commands'));
266
- console.log(gray(" Press Ctrl+C during a run to stop streaming output."));
267
- console.log(
268
- gray(" Conversation controls: /list /open <id> /new [title] /delete [id] /continue /reset [all]\n")
269
- );
270
- const intro = await consumeFirstRunIntro(workingDir, {
271
- agentName: metadata.agentName,
272
- provider: metadata.provider,
273
- model: metadata.model,
274
- config
275
- });
276
- if (intro) {
277
- console.log(green("assistant>"));
278
- await streamTextAsTokens(intro);
279
- stdout.write("\n\n");
280
- }
281
- let messages = intro ? [{ role: "assistant", content: intro }] : [];
282
- let turn = 1;
283
- let activeConversationId = null;
284
- let showToolPayloads = false;
285
- let activeRunAbortController = null;
286
- rl.on("SIGINT", () => {
287
- if (activeRunAbortController && !activeRunAbortController.signal.aborted) {
288
- activeRunAbortController.abort();
289
- process.stdout.write("\n");
290
- console.log(gray("stop> cancelling current run..."));
291
- return;
292
- }
293
- rl.close();
294
- });
295
- const prompt = `${C.cyan}you> ${C.reset}`;
296
- while (true) {
297
- let task;
298
- try {
299
- task = await ask(rl, prompt);
300
- } catch {
301
- break;
302
- }
303
- const trimmed = task.trim();
304
- if (!trimmed) continue;
305
- if (trimmed.toLowerCase() === "exit") break;
306
- if (trimmed.startsWith("/")) {
307
- if (trimmed.toLowerCase() === "/exit") break;
308
- if (trimmed.toLowerCase() === "/tools") {
309
- showToolPayloads = !showToolPayloads;
310
- console.log(gray(`tool payloads: ${showToolPayloads ? "on" : "off"}`));
311
- continue;
312
- }
313
- const interactiveState = {
314
- messages,
315
- turn,
316
- activeConversationId
317
- };
318
- const slashResult = await handleSlash(
319
- trimmed,
320
- interactiveState,
321
- conversationStore
322
- );
323
- if (slashResult.shouldExit) {
324
- break;
325
- }
326
- messages = interactiveState.messages;
327
- turn = interactiveState.turn;
328
- activeConversationId = interactiveState.activeConversationId;
329
- continue;
330
- }
331
- console.log(gray(`
332
- --- turn ${turn} ---`));
333
- process.stdout.write(gray("thinking..."));
334
- let thinkingCleared = false;
335
- const clearThinking = () => {
336
- if (thinkingCleared) return;
337
- thinkingCleared = true;
338
- readline.clearLine(process.stdout, 0);
339
- readline.cursorTo(process.stdout, 0);
340
- };
341
- let responseText = "";
342
- let streamedText = "";
343
- let committedText = false;
344
- let sawChunk = false;
345
- let toolEvents = 0;
346
- const toolTimeline = [];
347
- const sections = [];
348
- let currentText = "";
349
- let currentTools = [];
350
- let runFailed = false;
351
- let runCancelled = false;
352
- let usage;
353
- let latestRunId = "";
354
- const startedAt = Date.now();
355
- activeRunAbortController = new AbortController();
356
- try {
357
- for await (const event of harness.run({
358
- task: trimmed,
359
- parameters: params,
360
- messages,
361
- abortSignal: activeRunAbortController.signal
362
- })) {
363
- if (event.type === "run:started") {
364
- latestRunId = event.runId;
365
- }
366
- if (event.type === "model:chunk") {
367
- sawChunk = true;
368
- if (currentTools.length > 0) {
369
- sections.push({ type: "tools", content: currentTools });
370
- currentTools = [];
371
- }
372
- responseText += event.content;
373
- streamedText += event.content;
374
- currentText += event.content;
375
- if (!thinkingCleared) {
376
- clearThinking();
377
- process.stdout.write(`${C.green}assistant> ${C.reset}`);
378
- }
379
- process.stdout.write(event.content);
380
- } else if (event.type === "tool:started" || event.type === "tool:completed" || event.type === "tool:error" || event.type === "tool:approval:required" || event.type === "tool:approval:granted" || event.type === "tool:approval:denied") {
381
- if (streamedText.length > 0) {
382
- committedText = true;
383
- streamedText = "";
384
- process.stdout.write("\n");
385
- }
386
- clearThinking();
387
- if (event.type === "tool:started") {
388
- if (currentText.length > 0) {
389
- sections.push({ type: "text", content: currentText });
390
- currentText = "";
391
- }
392
- const preview = showToolPayloads ? compactPreview(event.input, 400) : compactPreview(event.input, 100);
393
- console.log(yellow(`tools> start ${event.tool} input=${preview}`));
394
- const toolText = `- start \`${event.tool}\``;
395
- toolTimeline.push(toolText);
396
- currentTools.push(toolText);
397
- toolEvents += 1;
398
- } else if (event.type === "tool:completed") {
399
- const preview = showToolPayloads ? compactPreview(event.output, 400) : compactPreview(event.output, 100);
400
- console.log(
401
- yellow(
402
- `tools> done ${event.tool} in ${formatDuration(event.duration)}`
403
- )
404
- );
405
- if (showToolPayloads) {
406
- console.log(yellow(`tools> output ${preview}`));
407
- }
408
- const toolText = `- done \`${event.tool}\` in ${formatDuration(event.duration)}`;
409
- toolTimeline.push(toolText);
410
- currentTools.push(toolText);
411
- } else if (event.type === "tool:error") {
412
- console.log(
413
- red(`tools> error ${event.tool}: ${event.error}`)
414
- );
415
- const toolText = `- error \`${event.tool}\`: ${event.error}`;
416
- toolTimeline.push(toolText);
417
- currentTools.push(toolText);
418
- } else if (event.type === "tool:approval:required") {
419
- console.log(
420
- magenta(`tools> approval required for ${event.tool}`)
421
- );
422
- const toolText = `- approval required \`${event.tool}\``;
423
- toolTimeline.push(toolText);
424
- currentTools.push(toolText);
425
- } else if (event.type === "tool:approval:granted") {
426
- console.log(
427
- gray(`tools> approval granted (${event.approvalId})`)
428
- );
429
- const toolText = `- approval granted (${event.approvalId})`;
430
- toolTimeline.push(toolText);
431
- currentTools.push(toolText);
432
- } else if (event.type === "tool:approval:denied") {
433
- console.log(
434
- magenta(`tools> approval denied (${event.approvalId})`)
435
- );
436
- const toolText = `- approval denied (${event.approvalId})`;
437
- toolTimeline.push(toolText);
438
- currentTools.push(toolText);
439
- }
440
- } else if (event.type === "run:error") {
441
- clearThinking();
442
- runFailed = true;
443
- console.log(red(`error> ${event.error.message}`));
444
- } else if (event.type === "run:cancelled") {
445
- clearThinking();
446
- runCancelled = true;
447
- } else if (event.type === "model:response") {
448
- usage = event.usage;
449
- } else if (event.type === "run:completed" && !sawChunk) {
450
- clearThinking();
451
- responseText = event.result.response ?? "";
452
- if (responseText.length > 0) {
453
- process.stdout.write(
454
- `${C.green}assistant> ${C.reset}${responseText}
455
- `
456
- );
457
- }
458
- }
459
- }
460
- } catch (error) {
461
- clearThinking();
462
- if (activeRunAbortController.signal.aborted) {
463
- runCancelled = true;
464
- } else {
465
- runFailed = true;
466
- console.log(
467
- red(
468
- `error> ${error instanceof Error ? error.message : "Unknown error"}`
469
- )
470
- );
471
- }
472
- } finally {
473
- activeRunAbortController = null;
474
- }
475
- if (sawChunk && streamedText.length > 0) {
476
- process.stdout.write("\n");
477
- } else if (!sawChunk && !runFailed && !runCancelled && responseText.length === 0) {
478
- clearThinking();
479
- console.log(green("assistant> (no response)"));
480
- }
481
- const fullResponse = responseText || streamedText;
482
- if (!runFailed && toolEvents === 0 && FAUX_TOOL_LOG_PATTERN.test(fullResponse)) {
483
- console.log(
484
- magenta(
485
- "warning> assistant described tool execution but no real tool events occurred."
486
- )
487
- );
488
- }
489
- const durationMs = Date.now() - startedAt;
490
- console.log(
491
- gray(`meta> ${formatDuration(durationMs)} | tools: ${toolEvents}
492
- `)
493
- );
494
- if (!activeConversationId) {
495
- const created = await conversationStore.create(
496
- OWNER_ID,
497
- inferConversationTitle(trimmed)
498
- );
499
- activeConversationId = created.conversationId;
500
- }
501
- if (currentTools.length > 0) {
502
- sections.push({ type: "tools", content: currentTools });
503
- }
504
- if (currentText.length > 0) {
505
- sections.push({ type: "text", content: currentText });
506
- }
507
- messages.push({ role: "user", content: trimmed });
508
- const hasAssistantContent = responseText.length > 0 || toolTimeline.length > 0 || sections.length > 0;
509
- if (hasAssistantContent) {
510
- messages.push({
511
- role: "assistant",
512
- content: responseText,
513
- metadata: toolTimeline.length > 0 || sections.length > 0 ? {
514
- toolActivity: toolTimeline,
515
- sections: sections.length > 0 ? sections : void 0
516
- } : void 0
517
- });
518
- }
519
- turn = computeTurn(messages);
520
- const conversation = await conversationStore.get(activeConversationId);
521
- if (conversation) {
522
- const maybeTitle = conversation.messages.length === 0 && (conversation.title === "New conversation" || conversation.title.trim().length === 0) ? inferConversationTitle(trimmed) : conversation.title;
523
- await conversationStore.update({
524
- ...conversation,
525
- title: maybeTitle,
526
- messages: [...messages],
527
- runtimeRunId: latestRunId || conversation.runtimeRunId
528
- });
529
- }
530
- }
531
- rl.close();
532
- };
533
- export {
534
- runInteractiveInk
535
- };