@poncho-ai/cli 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/cli@0.17.0 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
2
+ > @poncho-ai/cli@0.18.0 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
3
3
  > tsup src/index.ts src/cli.ts --format esm --dts
4
4
 
5
5
  CLI Building entry: src/cli.ts, src/index.ts
@@ -7,12 +7,12 @@
7
7
  CLI tsup v8.5.1
8
8
  CLI Target: es2022
9
9
  ESM Build start
10
- ESM dist/index.js 857.00 B
11
- ESM dist/run-interactive-ink-B6JJ33SN.js 55.30 KB
12
10
  ESM dist/cli.js 94.00 B
13
- ESM dist/chunk-GDB5X2OS.js 367.69 KB
14
- ESM ⚡️ Build success in 55ms
11
+ ESM dist/index.js 857.00 B
12
+ ESM dist/run-interactive-ink-VSO7GB3Y.js 55.30 KB
13
+ ESM dist/chunk-ETZ3YKFP.js 372.58 KB
14
+ ESM ⚡️ Build success in 72ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3969ms
16
+ DTS ⚡️ Build success in 3995ms
17
17
  DTS dist/cli.d.ts 20.00 B
18
- DTS dist/index.d.ts 3.56 KB
18
+ DTS dist/index.d.ts 3.59 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @poncho-ai/cli
2
2
 
3
+ ## 0.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`cd6ccd7`](https://github.com/cesr/poncho-ai/commit/cd6ccd7846e16fbaf17167617666796320ec29ce) Thanks [@cesr](https://github.com/cesr)! - Add MCP custom headers support, tool:generating streaming feedback, and cross-owner subagent recovery
8
+ - **MCP custom headers**: `poncho mcp add --header "Name: value"` and `headers` config field let servers like Arcade receive extra HTTP headers alongside bearer auth.
9
+ - **tool:generating event**: the harness now emits `tool:generating` events when the model begins writing tool-call arguments, so the web UI shows real-time "preparing <tool>" feedback instead of appearing stuck during large tool calls.
10
+ - **Subagent recovery**: `list`/`listSummaries` accept optional `ownerId` so stale-subagent recovery on server restart scans across all owners.
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [[`cd6ccd7`](https://github.com/cesr/poncho-ai/commit/cd6ccd7846e16fbaf17167617666796320ec29ce)]:
15
+ - @poncho-ai/sdk@1.3.0
16
+ - @poncho-ai/harness@0.18.0
17
+ - @poncho-ai/messaging@0.2.6
18
+
3
19
  ## 0.17.0
4
20
 
5
21
  ### Minor Changes
@@ -2547,8 +2547,32 @@ var getWebUiClientScript = (markedSource2) => `
2547
2547
  updateContextRing();
2548
2548
  }
2549
2549
  }
2550
+ if (eventName === "tool:generating") {
2551
+ const toolName = payload.tool || "tool";
2552
+ if (!Array.isArray(assistantMessage._activeActivities)) {
2553
+ assistantMessage._activeActivities = [];
2554
+ }
2555
+ assistantMessage._activeActivities.push({
2556
+ kind: "generating",
2557
+ tool: toolName,
2558
+ label: "Preparing " + toolName,
2559
+ });
2560
+ if (assistantMessage._currentText.length > 0) {
2561
+ assistantMessage._sections.push({
2562
+ type: "text",
2563
+ content: assistantMessage._currentText,
2564
+ });
2565
+ assistantMessage._currentText = "";
2566
+ }
2567
+ const prepText =
2568
+ "- preparing \\x60" + toolName + "\\x60";
2569
+ assistantMessage._currentTools.push(prepText);
2570
+ assistantMessage.metadata.toolActivity.push(prepText);
2571
+ renderIfActiveConversation(true);
2572
+ }
2550
2573
  if (eventName === "tool:started") {
2551
2574
  const toolName = payload.tool || "tool";
2575
+ removeActiveActivityForTool(assistantMessage, toolName);
2552
2576
  const startedActivity = addActiveActivityFromToolStart(
2553
2577
  assistantMessage,
2554
2578
  payload,
@@ -2560,14 +2584,24 @@ var getWebUiClientScript = (markedSource2) => `
2560
2584
  });
2561
2585
  assistantMessage._currentText = "";
2562
2586
  }
2587
+ const tick = "\\x60";
2588
+ const prepPrefix = "- preparing " + tick + toolName + tick;
2589
+ const prepToolIdx = assistantMessage._currentTools.indexOf(prepPrefix);
2590
+ if (prepToolIdx >= 0) {
2591
+ assistantMessage._currentTools.splice(prepToolIdx, 1);
2592
+ }
2593
+ const prepMetaIdx = assistantMessage.metadata.toolActivity.indexOf(prepPrefix);
2594
+ if (prepMetaIdx >= 0) {
2595
+ assistantMessage.metadata.toolActivity.splice(prepMetaIdx, 1);
2596
+ }
2563
2597
  const detail =
2564
2598
  startedActivity && typeof startedActivity.detail === "string"
2565
2599
  ? startedActivity.detail.trim()
2566
2600
  : "";
2567
2601
  const toolText =
2568
- "- start \\x60" +
2602
+ "- start " + tick +
2569
2603
  toolName +
2570
- "\\x60" +
2604
+ tick +
2571
2605
  (detail ? " (" + detail + ")" : "");
2572
2606
  assistantMessage._currentTools.push(toolText);
2573
2607
  assistantMessage.metadata.toolActivity.push(toolText);
@@ -3290,26 +3324,57 @@ var getWebUiClientScript = (markedSource2) => `
3290
3324
  updateContextRing();
3291
3325
  }
3292
3326
  }
3327
+ if (eventName === "tool:generating") {
3328
+ const toolName = payload.tool || "tool";
3329
+ if (!Array.isArray(assistantMessage._activeActivities)) {
3330
+ assistantMessage._activeActivities = [];
3331
+ }
3332
+ assistantMessage._activeActivities.push({
3333
+ kind: "generating",
3334
+ tool: toolName,
3335
+ label: "Preparing " + toolName,
3336
+ });
3337
+ if (assistantMessage._currentText.length > 0) {
3338
+ assistantMessage._sections.push({ type: "text", content: assistantMessage._currentText });
3339
+ assistantMessage._currentText = "";
3340
+ }
3341
+ if (!assistantMessage.metadata) assistantMessage.metadata = {};
3342
+ if (!assistantMessage.metadata.toolActivity) assistantMessage.metadata.toolActivity = [];
3343
+ const prepText = "- preparing \\x60" + toolName + "\\x60";
3344
+ assistantMessage._currentTools.push(prepText);
3345
+ assistantMessage.metadata.toolActivity.push(prepText);
3346
+ renderIfActiveConversation(true);
3347
+ }
3293
3348
  if (eventName === "tool:started") {
3294
3349
  const toolName = payload.tool || "tool";
3350
+ removeActiveActivityForTool(assistantMessage, toolName);
3295
3351
  const startedActivity = addActiveActivityFromToolStart(
3296
3352
  assistantMessage,
3297
3353
  payload,
3298
3354
  );
3299
- // If we have text accumulated, push it as a text section
3300
3355
  if (assistantMessage._currentText.length > 0) {
3301
3356
  assistantMessage._sections.push({ type: "text", content: assistantMessage._currentText });
3302
3357
  assistantMessage._currentText = "";
3303
3358
  }
3359
+ if (!assistantMessage.metadata) assistantMessage.metadata = {};
3360
+ if (!assistantMessage.metadata.toolActivity) assistantMessage.metadata.toolActivity = [];
3361
+ const tick = "\\x60";
3362
+ const prepPrefix = "- preparing " + tick + toolName + tick;
3363
+ const prepToolIdx = assistantMessage._currentTools.indexOf(prepPrefix);
3364
+ if (prepToolIdx >= 0) {
3365
+ assistantMessage._currentTools.splice(prepToolIdx, 1);
3366
+ }
3367
+ const prepMetaIdx = assistantMessage.metadata.toolActivity.indexOf(prepPrefix);
3368
+ if (prepMetaIdx >= 0) {
3369
+ assistantMessage.metadata.toolActivity.splice(prepMetaIdx, 1);
3370
+ }
3304
3371
  const detail =
3305
3372
  startedActivity && typeof startedActivity.detail === "string"
3306
3373
  ? startedActivity.detail.trim()
3307
3374
  : "";
3308
3375
  const toolText =
3309
- "- start \\x60" + toolName + "\\x60" + (detail ? " (" + detail + ")" : "");
3376
+ "- start " + tick + toolName + tick + (detail ? " (" + detail + ")" : "");
3310
3377
  assistantMessage._currentTools.push(toolText);
3311
- if (!assistantMessage.metadata) assistantMessage.metadata = {};
3312
- if (!assistantMessage.metadata.toolActivity) assistantMessage.metadata.toolActivity = [];
3313
3378
  assistantMessage.metadata.toolActivity.push(toolText);
3314
3379
  renderIfActiveConversation(true);
3315
3380
  }
@@ -6150,6 +6215,10 @@ Connect remote MCP servers and expose their tools to the agent:
6150
6215
  # Add remote MCP server
6151
6216
  poncho mcp add --url https://mcp.example.com/github --name github --auth-bearer-env GITHUB_TOKEN
6152
6217
 
6218
+ # Server with custom headers (e.g. Arcade)
6219
+ poncho mcp add --url https://mcp.arcade.dev --name arcade \\
6220
+ --auth-bearer-env ARCADE_API_KEY --header "Arcade-User-ID: user@example.com"
6221
+
6153
6222
  # List configured servers
6154
6223
  poncho mcp list
6155
6224
 
@@ -6231,6 +6300,8 @@ export default {
6231
6300
  url: "https://mcp.example.com/github",
6232
6301
  auth: { type: "bearer", tokenEnv: "GITHUB_TOKEN" },
6233
6302
  },
6303
+ // Custom headers for servers that require them (e.g. Arcade)
6304
+ // { name: "arcade", url: "https://mcp.arcade.dev", auth: { type: "bearer", tokenEnv: "ARCADE_API_KEY" }, headers: { "Arcade-User-ID": "user@example.com" } },
6234
6305
  ],
6235
6306
  // Tool access: true (available), false (disabled), 'approval' (requires human approval)
6236
6307
  tools: {
@@ -9065,9 +9136,11 @@ data: ${JSON.stringify(data)}
9065
9136
  handler._cronJobs = cronJobs;
9066
9137
  handler._conversationStore = conversationStore;
9067
9138
  try {
9068
- const allConvs = await conversationStore.list();
9069
- for (const conv of allConvs) {
9070
- if (conv.subagentMeta?.status === "running") {
9139
+ const allSummaries = await conversationStore.listSummaries();
9140
+ const subagentSummaries = allSummaries.filter((s) => s.parentConversationId);
9141
+ for (const s of subagentSummaries) {
9142
+ const conv = await conversationStore.get(s.conversationId);
9143
+ if (conv?.subagentMeta?.status === "running") {
9071
9144
  conv.subagentMeta.status = "stopped";
9072
9145
  conv.subagentMeta.error = { code: "SERVER_RESTART", message: "Interrupted by server restart" };
9073
9146
  conv.updatedAt = Date.now();
@@ -9299,7 +9372,7 @@ var runInteractive = async (workingDir, params) => {
9299
9372
  await harness.initialize();
9300
9373
  const identity = await ensureAgentIdentity2(workingDir);
9301
9374
  try {
9302
- const { runInteractiveInk } = await import("./run-interactive-ink-B6JJ33SN.js");
9375
+ const { runInteractiveInk } = await import("./run-interactive-ink-VSO7GB3Y.js");
9303
9376
  await runInteractiveInk({
9304
9377
  harness,
9305
9378
  params,
@@ -9680,6 +9753,15 @@ var mcpAdd = async (workingDir, options) => {
9680
9753
  if (!options.url.startsWith("http://") && !options.url.startsWith("https://")) {
9681
9754
  throw new Error("Invalid MCP URL. Expected http:// or https://.");
9682
9755
  }
9756
+ const parsedHeaders = options.headers && options.headers.length > 0 ? Object.fromEntries(
9757
+ options.headers.map((h) => {
9758
+ const idx = h.indexOf(":");
9759
+ if (idx < 1) {
9760
+ throw new Error(`Invalid header format "${h}". Expected "Name: value".`);
9761
+ }
9762
+ return [h.slice(0, idx).trim(), h.slice(idx + 1).trim()];
9763
+ })
9764
+ ) : void 0;
9683
9765
  const serverName = options.name ?? normalizeMcpName({ url: options.url });
9684
9766
  mcp.push({
9685
9767
  name: serverName,
@@ -9688,7 +9770,8 @@ var mcpAdd = async (workingDir, options) => {
9688
9770
  auth: options.authBearerEnv ? {
9689
9771
  type: "bearer",
9690
9772
  tokenEnv: options.authBearerEnv
9691
- } : void 0
9773
+ } : void 0,
9774
+ headers: parsedHeaders
9692
9775
  });
9693
9776
  await writeConfigFile(workingDir, { ...config, mcp });
9694
9777
  let envSeedMessage;
@@ -9732,8 +9815,10 @@ var mcpList = async (workingDir) => {
9732
9815
  process.stdout.write("Configured MCP servers:\n");
9733
9816
  for (const entry of mcp) {
9734
9817
  const auth = entry.auth?.type === "bearer" ? `auth=bearer:${entry.auth.tokenEnv}` : "auth=none";
9818
+ const headerKeys = entry.headers ? Object.keys(entry.headers) : [];
9819
+ const headerInfo = headerKeys.length > 0 ? `, headers=${headerKeys.join(",")}` : "";
9735
9820
  process.stdout.write(
9736
- `- ${entry.name ?? entry.url} (remote: ${entry.url}, ${auth})
9821
+ `- ${entry.name ?? entry.url} (remote: ${entry.url}, ${auth}${headerInfo})
9737
9822
  `
9738
9823
  );
9739
9824
  }
@@ -9937,13 +10022,17 @@ var buildCli = () => {
9937
10022
  ).option("--env <name>", "env variable (repeatable)", (value, all) => {
9938
10023
  all.push(value);
9939
10024
  return all;
10025
+ }, []).option("--header <header>", "custom header as 'Name: value' (repeatable)", (value, all) => {
10026
+ all.push(value);
10027
+ return all;
9940
10028
  }, []).action(
9941
10029
  async (options) => {
9942
10030
  await mcpAdd(process.cwd(), {
9943
10031
  url: options.url,
9944
10032
  name: options.name,
9945
10033
  envVars: options.env,
9946
- authBearerEnv: options.authBearerEnv
10034
+ authBearerEnv: options.authBearerEnv,
10035
+ headers: options.header
9947
10036
  });
9948
10037
  }
9949
10038
  );
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-GDB5X2OS.js";
4
+ } from "./chunk-ETZ3YKFP.js";
5
5
 
6
6
  // src/cli.ts
7
7
  void main();
package/dist/index.d.ts CHANGED
@@ -66,6 +66,7 @@ declare const mcpAdd: (workingDir: string, options: {
66
66
  name?: string;
67
67
  envVars?: string[];
68
68
  authBearerEnv?: string;
69
+ headers?: string[];
69
70
  }) => Promise<void>;
70
71
  declare const mcpList: (workingDir: string) => Promise<void>;
71
72
  declare const mcpRemove: (workingDir: string, name: string) => Promise<void>;
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  runTests,
24
24
  startDevServer,
25
25
  updateAgentGuidance
26
- } from "./chunk-GDB5X2OS.js";
26
+ } from "./chunk-ETZ3YKFP.js";
27
27
  export {
28
28
  addSkill,
29
29
  buildCli,
@@ -2,7 +2,7 @@ import {
2
2
  consumeFirstRunIntro,
3
3
  inferConversationTitle,
4
4
  resolveHarnessEnvironment
5
- } from "./chunk-GDB5X2OS.js";
5
+ } from "./chunk-ETZ3YKFP.js";
6
6
 
7
7
  // src/run-interactive-ink.ts
8
8
  import * as readline from "readline";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/cli",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "CLI for building and deploying AI agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,9 +27,9 @@
27
27
  "react": "^19.2.4",
28
28
  "react-devtools-core": "^6.1.5",
29
29
  "yaml": "^2.8.1",
30
- "@poncho-ai/harness": "0.17.0",
31
- "@poncho-ai/messaging": "0.2.5",
32
- "@poncho-ai/sdk": "1.2.0"
30
+ "@poncho-ai/harness": "0.18.0",
31
+ "@poncho-ai/messaging": "0.2.6",
32
+ "@poncho-ai/sdk": "1.3.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -455,6 +455,10 @@ Connect remote MCP servers and expose their tools to the agent:
455
455
  # Add remote MCP server
456
456
  poncho mcp add --url https://mcp.example.com/github --name github --auth-bearer-env GITHUB_TOKEN
457
457
 
458
+ # Server with custom headers (e.g. Arcade)
459
+ poncho mcp add --url https://mcp.arcade.dev --name arcade \\
460
+ --auth-bearer-env ARCADE_API_KEY --header "Arcade-User-ID: user@example.com"
461
+
458
462
  # List configured servers
459
463
  poncho mcp list
460
464
 
@@ -536,6 +540,8 @@ export default {
536
540
  url: "https://mcp.example.com/github",
537
541
  auth: { type: "bearer", tokenEnv: "GITHUB_TOKEN" },
538
542
  },
543
+ // Custom headers for servers that require them (e.g. Arcade)
544
+ // { name: "arcade", url: "https://mcp.arcade.dev", auth: { type: "bearer", tokenEnv: "ARCADE_API_KEY" }, headers: { "Arcade-User-ID": "user@example.com" } },
539
545
  ],
540
546
  // Tool access: true (available), false (disabled), 'approval' (requires human approval)
541
547
  tools: {
@@ -3753,11 +3759,14 @@ export const createRequestHandler = async (options?: {
3753
3759
  handler._cronJobs = cronJobs;
3754
3760
  handler._conversationStore = conversationStore;
3755
3761
 
3756
- // Recover stale subagent runs that were "running" when the server last stopped
3762
+ // Recover stale subagent runs that were "running" when the server last stopped.
3763
+ // Pass no ownerId so we scan across all owners (not just "local-owner").
3757
3764
  try {
3758
- const allConvs = await conversationStore.list();
3759
- for (const conv of allConvs) {
3760
- if (conv.subagentMeta?.status === "running") {
3765
+ const allSummaries = await conversationStore.listSummaries();
3766
+ const subagentSummaries = allSummaries.filter((s) => s.parentConversationId);
3767
+ for (const s of subagentSummaries) {
3768
+ const conv = await conversationStore.get(s.conversationId);
3769
+ if (conv?.subagentMeta?.status === "running") {
3761
3770
  conv.subagentMeta.status = "stopped";
3762
3771
  conv.subagentMeta.error = { code: "SERVER_RESTART", message: "Interrupted by server restart" };
3763
3772
  conv.updatedAt = Date.now();
@@ -4535,6 +4544,7 @@ export const mcpAdd = async (
4535
4544
  name?: string;
4536
4545
  envVars?: string[];
4537
4546
  authBearerEnv?: string;
4547
+ headers?: string[];
4538
4548
  },
4539
4549
  ): Promise<void> => {
4540
4550
  const config = (await loadPonchoConfig(workingDir)) ?? { mcp: [] };
@@ -4548,6 +4558,18 @@ export const mcpAdd = async (
4548
4558
  if (!options.url.startsWith("http://") && !options.url.startsWith("https://")) {
4549
4559
  throw new Error("Invalid MCP URL. Expected http:// or https://.");
4550
4560
  }
4561
+ const parsedHeaders: Record<string, string> | undefined =
4562
+ options.headers && options.headers.length > 0
4563
+ ? Object.fromEntries(
4564
+ options.headers.map((h) => {
4565
+ const idx = h.indexOf(":");
4566
+ if (idx < 1) {
4567
+ throw new Error(`Invalid header format "${h}". Expected "Name: value".`);
4568
+ }
4569
+ return [h.slice(0, idx).trim(), h.slice(idx + 1).trim()];
4570
+ }),
4571
+ )
4572
+ : undefined;
4551
4573
  const serverName = options.name ?? normalizeMcpName({ url: options.url });
4552
4574
  mcp.push({
4553
4575
  name: serverName,
@@ -4559,6 +4581,7 @@ export const mcpAdd = async (
4559
4581
  tokenEnv: options.authBearerEnv,
4560
4582
  }
4561
4583
  : undefined,
4584
+ headers: parsedHeaders,
4562
4585
  });
4563
4586
 
4564
4587
  await writeConfigFile(workingDir, { ...config, mcp });
@@ -4605,8 +4628,10 @@ export const mcpList = async (workingDir: string): Promise<void> => {
4605
4628
  for (const entry of mcp) {
4606
4629
  const auth =
4607
4630
  entry.auth?.type === "bearer" ? `auth=bearer:${entry.auth.tokenEnv}` : "auth=none";
4631
+ const headerKeys = entry.headers ? Object.keys(entry.headers) : [];
4632
+ const headerInfo = headerKeys.length > 0 ? `, headers=${headerKeys.join(",")}` : "";
4608
4633
  process.stdout.write(
4609
- `- ${entry.name ?? entry.url} (remote: ${entry.url}, ${auth})\n`,
4634
+ `- ${entry.name ?? entry.url} (remote: ${entry.url}, ${auth}${headerInfo})\n`,
4610
4635
  );
4611
4636
  }
4612
4637
  };
@@ -4933,6 +4958,10 @@ export const buildCli = (): Command => {
4933
4958
  all.push(value);
4934
4959
  return all;
4935
4960
  }, [] as string[])
4961
+ .option("--header <header>", "custom header as 'Name: value' (repeatable)", (value, all: string[]) => {
4962
+ all.push(value);
4963
+ return all;
4964
+ }, [] as string[])
4936
4965
  .action(
4937
4966
  async (
4938
4967
  options: {
@@ -4940,6 +4969,7 @@ export const buildCli = (): Command => {
4940
4969
  name?: string;
4941
4970
  authBearerEnv?: string;
4942
4971
  env: string[];
4972
+ header: string[];
4943
4973
  },
4944
4974
  ) => {
4945
4975
  await mcpAdd(process.cwd(), {
@@ -4947,6 +4977,7 @@ export const buildCli = (): Command => {
4947
4977
  name: options.name,
4948
4978
  envVars: options.env,
4949
4979
  authBearerEnv: options.authBearerEnv,
4980
+ headers: options.header,
4950
4981
  });
4951
4982
  },
4952
4983
  );
@@ -1062,8 +1062,32 @@ export const getWebUiClientScript = (markedSource: string): string => `
1062
1062
  updateContextRing();
1063
1063
  }
1064
1064
  }
1065
+ if (eventName === "tool:generating") {
1066
+ const toolName = payload.tool || "tool";
1067
+ if (!Array.isArray(assistantMessage._activeActivities)) {
1068
+ assistantMessage._activeActivities = [];
1069
+ }
1070
+ assistantMessage._activeActivities.push({
1071
+ kind: "generating",
1072
+ tool: toolName,
1073
+ label: "Preparing " + toolName,
1074
+ });
1075
+ if (assistantMessage._currentText.length > 0) {
1076
+ assistantMessage._sections.push({
1077
+ type: "text",
1078
+ content: assistantMessage._currentText,
1079
+ });
1080
+ assistantMessage._currentText = "";
1081
+ }
1082
+ const prepText =
1083
+ "- preparing \\x60" + toolName + "\\x60";
1084
+ assistantMessage._currentTools.push(prepText);
1085
+ assistantMessage.metadata.toolActivity.push(prepText);
1086
+ renderIfActiveConversation(true);
1087
+ }
1065
1088
  if (eventName === "tool:started") {
1066
1089
  const toolName = payload.tool || "tool";
1090
+ removeActiveActivityForTool(assistantMessage, toolName);
1067
1091
  const startedActivity = addActiveActivityFromToolStart(
1068
1092
  assistantMessage,
1069
1093
  payload,
@@ -1075,14 +1099,24 @@ export const getWebUiClientScript = (markedSource: string): string => `
1075
1099
  });
1076
1100
  assistantMessage._currentText = "";
1077
1101
  }
1102
+ const tick = "\\x60";
1103
+ const prepPrefix = "- preparing " + tick + toolName + tick;
1104
+ const prepToolIdx = assistantMessage._currentTools.indexOf(prepPrefix);
1105
+ if (prepToolIdx >= 0) {
1106
+ assistantMessage._currentTools.splice(prepToolIdx, 1);
1107
+ }
1108
+ const prepMetaIdx = assistantMessage.metadata.toolActivity.indexOf(prepPrefix);
1109
+ if (prepMetaIdx >= 0) {
1110
+ assistantMessage.metadata.toolActivity.splice(prepMetaIdx, 1);
1111
+ }
1078
1112
  const detail =
1079
1113
  startedActivity && typeof startedActivity.detail === "string"
1080
1114
  ? startedActivity.detail.trim()
1081
1115
  : "";
1082
1116
  const toolText =
1083
- "- start \\x60" +
1117
+ "- start " + tick +
1084
1118
  toolName +
1085
- "\\x60" +
1119
+ tick +
1086
1120
  (detail ? " (" + detail + ")" : "");
1087
1121
  assistantMessage._currentTools.push(toolText);
1088
1122
  assistantMessage.metadata.toolActivity.push(toolText);
@@ -1805,26 +1839,57 @@ export const getWebUiClientScript = (markedSource: string): string => `
1805
1839
  updateContextRing();
1806
1840
  }
1807
1841
  }
1842
+ if (eventName === "tool:generating") {
1843
+ const toolName = payload.tool || "tool";
1844
+ if (!Array.isArray(assistantMessage._activeActivities)) {
1845
+ assistantMessage._activeActivities = [];
1846
+ }
1847
+ assistantMessage._activeActivities.push({
1848
+ kind: "generating",
1849
+ tool: toolName,
1850
+ label: "Preparing " + toolName,
1851
+ });
1852
+ if (assistantMessage._currentText.length > 0) {
1853
+ assistantMessage._sections.push({ type: "text", content: assistantMessage._currentText });
1854
+ assistantMessage._currentText = "";
1855
+ }
1856
+ if (!assistantMessage.metadata) assistantMessage.metadata = {};
1857
+ if (!assistantMessage.metadata.toolActivity) assistantMessage.metadata.toolActivity = [];
1858
+ const prepText = "- preparing \\x60" + toolName + "\\x60";
1859
+ assistantMessage._currentTools.push(prepText);
1860
+ assistantMessage.metadata.toolActivity.push(prepText);
1861
+ renderIfActiveConversation(true);
1862
+ }
1808
1863
  if (eventName === "tool:started") {
1809
1864
  const toolName = payload.tool || "tool";
1865
+ removeActiveActivityForTool(assistantMessage, toolName);
1810
1866
  const startedActivity = addActiveActivityFromToolStart(
1811
1867
  assistantMessage,
1812
1868
  payload,
1813
1869
  );
1814
- // If we have text accumulated, push it as a text section
1815
1870
  if (assistantMessage._currentText.length > 0) {
1816
1871
  assistantMessage._sections.push({ type: "text", content: assistantMessage._currentText });
1817
1872
  assistantMessage._currentText = "";
1818
1873
  }
1874
+ if (!assistantMessage.metadata) assistantMessage.metadata = {};
1875
+ if (!assistantMessage.metadata.toolActivity) assistantMessage.metadata.toolActivity = [];
1876
+ const tick = "\\x60";
1877
+ const prepPrefix = "- preparing " + tick + toolName + tick;
1878
+ const prepToolIdx = assistantMessage._currentTools.indexOf(prepPrefix);
1879
+ if (prepToolIdx >= 0) {
1880
+ assistantMessage._currentTools.splice(prepToolIdx, 1);
1881
+ }
1882
+ const prepMetaIdx = assistantMessage.metadata.toolActivity.indexOf(prepPrefix);
1883
+ if (prepMetaIdx >= 0) {
1884
+ assistantMessage.metadata.toolActivity.splice(prepMetaIdx, 1);
1885
+ }
1819
1886
  const detail =
1820
1887
  startedActivity && typeof startedActivity.detail === "string"
1821
1888
  ? startedActivity.detail.trim()
1822
1889
  : "";
1823
1890
  const toolText =
1824
- "- start \\x60" + toolName + "\\x60" + (detail ? " (" + detail + ")" : "");
1891
+ "- start " + tick + toolName + tick + (detail ? " (" + detail + ")" : "");
1825
1892
  assistantMessage._currentTools.push(toolText);
1826
- if (!assistantMessage.metadata) assistantMessage.metadata = {};
1827
- if (!assistantMessage.metadata.toolActivity) assistantMessage.metadata.toolActivity = [];
1828
1893
  assistantMessage.metadata.toolActivity.push(toolText);
1829
1894
  renderIfActiveConversation(true);
1830
1895
  }