@poncho-ai/cli 0.32.2 → 0.32.4

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.32.2 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
2
+ > @poncho-ai/cli@0.32.4 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
@@ -8,11 +8,11 @@
8
8
  CLI Target: es2022
9
9
  ESM Build start
10
10
  ESM dist/cli.js 94.00 B
11
- ESM dist/run-interactive-ink-GD3IRICQ.js 56.86 KB
12
11
  ESM dist/index.js 857.00 B
13
- ESM dist/chunk-TQRPRFR3.js 522.85 KB
14
- ESM ⚡️ Build success in 78ms
12
+ ESM dist/run-interactive-ink-GPCI4L6G.js 56.86 KB
13
+ ESM dist/chunk-F6NA3N2R.js 524.82 KB
14
+ ESM ⚡️ Build success in 66ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 4067ms
16
+ DTS ⚡️ Build success in 4059ms
17
17
  DTS dist/cli.d.ts 20.00 B
18
18
  DTS dist/index.d.ts 4.16 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @poncho-ai/cli
2
2
 
3
+ ## 0.32.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#58](https://github.com/cesr/poncho-ai/pull/58) [`07aad37`](https://github.com/cesr/poncho-ai/commit/07aad371ae5152199347bab11ed5c6270086db2b) Thanks [@cesr](https://github.com/cesr)! - Fix messaging conversation consistency for Telegram and other adapter-backed channels.
8
+
9
+ This serializes per-conversation messaging runs to avoid stale concurrent context, refreshes latest conversation history before each run, and normalizes internal assistant tool-call payloads in API conversation responses for cleaner Web UI rendering.
10
+
11
+ ## 0.32.3
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [[`28b2913`](https://github.com/cesr/poncho-ai/commit/28b291379e640dec53a66c41a2795d0a9fbb9ee7)]:
16
+ - @poncho-ai/harness@0.31.3
17
+
3
18
  ## 0.32.2
4
19
 
5
20
  ### Patch Changes
@@ -7528,6 +7528,24 @@ var parseParams = (values) => {
7528
7528
  }
7529
7529
  return params;
7530
7530
  };
7531
+ var normalizeMessageForClient = (message) => {
7532
+ if (message.role !== "assistant" || typeof message.content !== "string") {
7533
+ return message;
7534
+ }
7535
+ try {
7536
+ const parsed = JSON.parse(message.content);
7537
+ const text = typeof parsed.text === "string" ? parsed.text : void 0;
7538
+ const toolCalls = Array.isArray(parsed.tool_calls) ? parsed.tool_calls : void 0;
7539
+ if (typeof text === "string" && toolCalls) {
7540
+ return {
7541
+ ...message,
7542
+ content: text
7543
+ };
7544
+ }
7545
+ } catch {
7546
+ }
7547
+ return message;
7548
+ };
7531
7549
  var AGENT_TEMPLATE = (name, id, options) => `---
7532
7550
  name: ${name}
7533
7551
  id: ${id}
@@ -9706,6 +9724,7 @@ ${resultBody}`,
9706
9724
  }
9707
9725
  };
9708
9726
  const messagingRoutes = /* @__PURE__ */ new Map();
9727
+ const messagingRunQueues = /* @__PURE__ */ new Map();
9709
9728
  const messagingRouteRegistrar = (method, path, routeHandler) => {
9710
9729
  let byMethod = messagingRoutes.get(path);
9711
9730
  if (!byMethod) {
@@ -9748,245 +9767,265 @@ ${resultBody}`,
9748
9767
  return { messages: [] };
9749
9768
  },
9750
9769
  async run(conversationId, input2) {
9751
- const isContinuation = input2.task == null;
9752
- console.log("[messaging-runner] starting run for", conversationId, isContinuation ? "(continuation)" : `task: ${input2.task.slice(0, 80)}`);
9753
- const historyMessages = [...input2.messages];
9754
- const preRunMessages = [...input2.messages];
9755
- const userContent = input2.task;
9756
- const updateConversation = async (patch) => {
9757
- const fresh = await conversationStore.get(conversationId);
9758
- if (!fresh) return;
9759
- patch(fresh);
9760
- fresh.updatedAt = Date.now();
9761
- await conversationStore.update(fresh);
9762
- };
9763
- await updateConversation((c) => {
9764
- if (!isContinuation) {
9765
- c.messages = [...historyMessages, { role: "user", content: userContent }];
9766
- }
9767
- c.runStatus = "running";
9770
+ const previous = messagingRunQueues.get(conversationId) ?? Promise.resolve();
9771
+ let releaseQueue;
9772
+ const current = new Promise((resolve4) => {
9773
+ releaseQueue = resolve4;
9768
9774
  });
9769
- let latestRunId = "";
9770
- let assistantResponse = "";
9771
- const toolTimeline = [];
9772
- const sections = [];
9773
- let currentTools = [];
9774
- let currentText = "";
9775
- let checkpointedRun = false;
9776
- let runContextTokens = 0;
9777
- let runContextWindow = 0;
9778
- let runContinuation2 = false;
9779
- let runContinuationMessages;
9780
- let runSteps = 0;
9781
- let runMaxSteps;
9782
- const buildMessages = () => {
9783
- const draftSections = [
9784
- ...sections.map((s) => ({
9785
- type: s.type,
9786
- content: Array.isArray(s.content) ? [...s.content] : s.content
9787
- }))
9788
- ];
9789
- if (currentTools.length > 0) {
9790
- draftSections.push({ type: "tools", content: [...currentTools] });
9791
- }
9792
- if (currentText.length > 0) {
9793
- draftSections.push({ type: "text", content: currentText });
9794
- }
9795
- const userTurn = userContent != null ? [{ role: "user", content: userContent }] : [];
9796
- const hasDraftContent = assistantResponse.length > 0 || toolTimeline.length > 0 || draftSections.length > 0;
9797
- if (!hasDraftContent) {
9798
- return [...historyMessages, ...userTurn];
9799
- }
9800
- return [
9801
- ...historyMessages,
9802
- ...userTurn,
9803
- {
9804
- role: "assistant",
9805
- content: assistantResponse,
9806
- metadata: toolTimeline.length > 0 || draftSections.length > 0 ? {
9807
- toolActivity: [...toolTimeline],
9808
- sections: draftSections.length > 0 ? draftSections : void 0
9809
- } : void 0
9810
- }
9811
- ];
9812
- };
9813
- const persistDraftAssistantTurn = async () => {
9814
- if (assistantResponse.length === 0 && toolTimeline.length === 0) return;
9815
- await updateConversation((c) => {
9816
- c.messages = buildMessages();
9817
- });
9818
- };
9819
- const runInput = {
9820
- task: input2.task,
9821
- conversationId,
9822
- messages: input2.messages,
9823
- files: input2.files,
9824
- parameters: input2.metadata ? {
9825
- __messaging_platform: input2.metadata.platform,
9826
- __messaging_sender_id: input2.metadata.sender.id,
9827
- __messaging_sender_name: input2.metadata.sender.name ?? "",
9828
- __messaging_thread_id: input2.metadata.threadId
9829
- } : void 0
9830
- };
9775
+ const chained = previous.then(() => current);
9776
+ messagingRunQueues.set(conversationId, chained);
9777
+ await previous;
9831
9778
  try {
9832
- for await (const event of harness.runWithTelemetry(runInput)) {
9833
- if (event.type === "run:started") {
9834
- latestRunId = event.runId;
9835
- runOwners.set(event.runId, "local-owner");
9836
- runConversations.set(event.runId, conversationId);
9837
- }
9838
- if (event.type === "model:chunk") {
9839
- if (currentTools.length > 0) {
9840
- sections.push({ type: "tools", content: currentTools });
9841
- currentTools = [];
9842
- if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
9843
- assistantResponse += " ";
9844
- }
9845
- }
9846
- assistantResponse += event.content;
9847
- currentText += event.content;
9848
- }
9849
- if (event.type === "tool:started") {
9850
- if (currentText.length > 0) {
9851
- sections.push({ type: "text", content: currentText });
9852
- currentText = "";
9853
- }
9854
- const toolText = `- start \`${event.tool}\``;
9855
- toolTimeline.push(toolText);
9856
- currentTools.push(toolText);
9779
+ const latestConversation = await conversationStore.get(conversationId);
9780
+ const latestMessages = latestConversation ? latestConversation._harnessMessages?.length ? [...latestConversation._harnessMessages] : [...latestConversation.messages] : [...input2.messages];
9781
+ const isContinuation = input2.task == null;
9782
+ console.log("[messaging-runner] starting run for", conversationId, isContinuation ? "(continuation)" : `task: ${input2.task.slice(0, 80)}`);
9783
+ const historyMessages = [...latestMessages];
9784
+ const preRunMessages = [...latestMessages];
9785
+ const userContent = input2.task;
9786
+ const updateConversation = async (patch) => {
9787
+ const fresh = await conversationStore.get(conversationId);
9788
+ if (!fresh) return;
9789
+ patch(fresh);
9790
+ fresh.updatedAt = Date.now();
9791
+ await conversationStore.update(fresh);
9792
+ };
9793
+ await updateConversation((c) => {
9794
+ if (!isContinuation) {
9795
+ c.messages = [...historyMessages, { role: "user", content: userContent }];
9857
9796
  }
9858
- if (event.type === "tool:completed") {
9859
- const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
9860
- toolTimeline.push(toolText);
9861
- currentTools.push(toolText);
9797
+ c.runStatus = "running";
9798
+ });
9799
+ let latestRunId = "";
9800
+ let assistantResponse = "";
9801
+ const toolTimeline = [];
9802
+ const sections = [];
9803
+ let currentTools = [];
9804
+ let currentText = "";
9805
+ let checkpointedRun = false;
9806
+ let runContextTokens = 0;
9807
+ let runContextWindow = 0;
9808
+ let runContinuation2 = false;
9809
+ let runContinuationMessages;
9810
+ let runSteps = 0;
9811
+ let runMaxSteps;
9812
+ const buildMessages = () => {
9813
+ const draftSections = [
9814
+ ...sections.map((s) => ({
9815
+ type: s.type,
9816
+ content: Array.isArray(s.content) ? [...s.content] : s.content
9817
+ }))
9818
+ ];
9819
+ if (currentTools.length > 0) {
9820
+ draftSections.push({ type: "tools", content: [...currentTools] });
9862
9821
  }
9863
- if (event.type === "tool:error") {
9864
- const toolText = `- error \`${event.tool}\`: ${event.error}`;
9865
- toolTimeline.push(toolText);
9866
- currentTools.push(toolText);
9822
+ if (currentText.length > 0) {
9823
+ draftSections.push({ type: "text", content: currentText });
9867
9824
  }
9868
- if (event.type === "step:completed") {
9869
- await persistDraftAssistantTurn();
9825
+ const userTurn = userContent != null ? [{ role: "user", content: userContent }] : [];
9826
+ const hasDraftContent = assistantResponse.length > 0 || toolTimeline.length > 0 || draftSections.length > 0;
9827
+ if (!hasDraftContent) {
9828
+ return [...historyMessages, ...userTurn];
9870
9829
  }
9871
- if (event.type === "tool:approval:required") {
9872
- const toolText = `- approval required \`${event.tool}\``;
9873
- toolTimeline.push(toolText);
9874
- currentTools.push(toolText);
9875
- await persistDraftAssistantTurn();
9830
+ return [
9831
+ ...historyMessages,
9832
+ ...userTurn,
9833
+ {
9834
+ role: "assistant",
9835
+ content: assistantResponse,
9836
+ metadata: toolTimeline.length > 0 || draftSections.length > 0 ? {
9837
+ toolActivity: [...toolTimeline],
9838
+ sections: draftSections.length > 0 ? draftSections : void 0
9839
+ } : void 0
9840
+ }
9841
+ ];
9842
+ };
9843
+ const persistDraftAssistantTurn = async () => {
9844
+ if (assistantResponse.length === 0 && toolTimeline.length === 0) return;
9845
+ await updateConversation((c) => {
9846
+ c.messages = buildMessages();
9847
+ });
9848
+ };
9849
+ const runInput = {
9850
+ task: input2.task,
9851
+ conversationId,
9852
+ messages: historyMessages,
9853
+ files: input2.files,
9854
+ parameters: {
9855
+ ...input2.metadata ? {
9856
+ __messaging_platform: input2.metadata.platform,
9857
+ __messaging_sender_id: input2.metadata.sender.id,
9858
+ __messaging_sender_name: input2.metadata.sender.name ?? "",
9859
+ __messaging_thread_id: input2.metadata.threadId
9860
+ } : {},
9861
+ __activeConversationId: conversationId
9876
9862
  }
9877
- if (event.type === "tool:approval:checkpoint") {
9878
- await updateConversation((c) => {
9879
- c.messages = buildMessages();
9880
- c.pendingApprovals = event.approvals.map((a) => ({
9881
- approvalId: a.approvalId,
9882
- runId: latestRunId,
9883
- tool: a.tool,
9884
- toolCallId: a.toolCallId,
9885
- input: a.input,
9886
- checkpointMessages: event.checkpointMessages,
9887
- baseMessageCount: historyMessages.length,
9888
- pendingToolCalls: event.pendingToolCalls
9889
- }));
9890
- });
9891
- checkpointedRun = true;
9892
- const conv = await conversationStore.get(conversationId);
9893
- if (conv?.channelMeta?.platform === "telegram") {
9894
- const tgAdapter = messagingAdapters.get("telegram");
9895
- if (tgAdapter) {
9896
- const approvals = event.approvals.map((a) => ({
9863
+ };
9864
+ try {
9865
+ for await (const event of harness.runWithTelemetry(runInput)) {
9866
+ if (event.type === "run:started") {
9867
+ latestRunId = event.runId;
9868
+ runOwners.set(event.runId, "local-owner");
9869
+ runConversations.set(event.runId, conversationId);
9870
+ }
9871
+ if (event.type === "model:chunk") {
9872
+ if (currentTools.length > 0) {
9873
+ sections.push({ type: "tools", content: currentTools });
9874
+ currentTools = [];
9875
+ if (assistantResponse.length > 0 && !/\s$/.test(assistantResponse)) {
9876
+ assistantResponse += " ";
9877
+ }
9878
+ }
9879
+ assistantResponse += event.content;
9880
+ currentText += event.content;
9881
+ }
9882
+ if (event.type === "tool:started") {
9883
+ if (currentText.length > 0) {
9884
+ sections.push({ type: "text", content: currentText });
9885
+ currentText = "";
9886
+ }
9887
+ const toolText = `- start \`${event.tool}\``;
9888
+ toolTimeline.push(toolText);
9889
+ currentTools.push(toolText);
9890
+ }
9891
+ if (event.type === "tool:completed") {
9892
+ const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
9893
+ toolTimeline.push(toolText);
9894
+ currentTools.push(toolText);
9895
+ }
9896
+ if (event.type === "tool:error") {
9897
+ const toolText = `- error \`${event.tool}\`: ${event.error}`;
9898
+ toolTimeline.push(toolText);
9899
+ currentTools.push(toolText);
9900
+ }
9901
+ if (event.type === "step:completed") {
9902
+ await persistDraftAssistantTurn();
9903
+ }
9904
+ if (event.type === "tool:approval:required") {
9905
+ const toolText = `- approval required \`${event.tool}\``;
9906
+ toolTimeline.push(toolText);
9907
+ currentTools.push(toolText);
9908
+ await persistDraftAssistantTurn();
9909
+ }
9910
+ if (event.type === "tool:approval:checkpoint") {
9911
+ await updateConversation((c) => {
9912
+ c.messages = buildMessages();
9913
+ c.pendingApprovals = event.approvals.map((a) => ({
9897
9914
  approvalId: a.approvalId,
9915
+ runId: latestRunId,
9898
9916
  tool: a.tool,
9899
- input: a.input
9917
+ toolCallId: a.toolCallId,
9918
+ input: a.input,
9919
+ checkpointMessages: event.checkpointMessages,
9920
+ baseMessageCount: historyMessages.length,
9921
+ pendingToolCalls: event.pendingToolCalls
9900
9922
  }));
9901
- void tgAdapter.sendApprovalRequest(
9902
- conv.channelMeta.channelId,
9903
- approvals
9904
- ).catch((err) => {
9905
- console.error("[messaging-runner] failed to send Telegram approval request:", err instanceof Error ? err.message : err);
9923
+ });
9924
+ checkpointedRun = true;
9925
+ const conv = await conversationStore.get(conversationId);
9926
+ if (conv?.channelMeta?.platform === "telegram") {
9927
+ const tgAdapter = messagingAdapters.get("telegram");
9928
+ if (tgAdapter) {
9929
+ const approvals = event.approvals.map((a) => ({
9930
+ approvalId: a.approvalId,
9931
+ tool: a.tool,
9932
+ input: a.input
9933
+ }));
9934
+ void tgAdapter.sendApprovalRequest(
9935
+ conv.channelMeta.channelId,
9936
+ approvals
9937
+ ).catch((err) => {
9938
+ console.error("[messaging-runner] failed to send Telegram approval request:", err instanceof Error ? err.message : err);
9939
+ });
9940
+ }
9941
+ }
9942
+ }
9943
+ if (event.type === "compaction:completed") {
9944
+ if (event.compactedMessages) {
9945
+ historyMessages.length = 0;
9946
+ historyMessages.push(...event.compactedMessages);
9947
+ const preservedFromHistory = historyMessages.length - 1;
9948
+ const removedCount = preRunMessages.length - Math.max(0, preservedFromHistory);
9949
+ await updateConversation((c) => {
9950
+ const existingHistory = c.compactedHistory ?? [];
9951
+ c.compactedHistory = [
9952
+ ...existingHistory,
9953
+ ...preRunMessages.slice(0, removedCount)
9954
+ ];
9906
9955
  });
9907
9956
  }
9908
9957
  }
9909
- }
9910
- if (event.type === "compaction:completed") {
9911
- if (event.compactedMessages) {
9912
- historyMessages.length = 0;
9913
- historyMessages.push(...event.compactedMessages);
9914
- const preservedFromHistory = historyMessages.length - 1;
9915
- const removedCount = preRunMessages.length - Math.max(0, preservedFromHistory);
9916
- await updateConversation((c) => {
9917
- const existingHistory = c.compactedHistory ?? [];
9918
- c.compactedHistory = [
9919
- ...existingHistory,
9920
- ...preRunMessages.slice(0, removedCount)
9921
- ];
9922
- });
9958
+ if (event.type === "run:completed") {
9959
+ if (assistantResponse.length === 0 && event.result.response) {
9960
+ assistantResponse = event.result.response;
9961
+ }
9962
+ runContinuation2 = event.result.continuation === true;
9963
+ if (event.result.continuationMessages) {
9964
+ runContinuationMessages = event.result.continuationMessages;
9965
+ }
9966
+ runSteps = event.result.steps;
9967
+ if (typeof event.result.maxSteps === "number") runMaxSteps = event.result.maxSteps;
9968
+ runContextTokens = event.result.contextTokens ?? runContextTokens;
9969
+ runContextWindow = event.result.contextWindow ?? runContextWindow;
9970
+ }
9971
+ if (event.type === "run:error") {
9972
+ assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
9923
9973
  }
9974
+ broadcastEvent(conversationId, event);
9924
9975
  }
9925
- if (event.type === "run:completed") {
9926
- if (assistantResponse.length === 0 && event.result.response) {
9927
- assistantResponse = event.result.response;
9976
+ } catch (err) {
9977
+ console.error("[messaging-runner] run failed:", err instanceof Error ? err.message : err);
9978
+ assistantResponse = assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
9979
+ }
9980
+ if (currentTools.length > 0) {
9981
+ sections.push({ type: "tools", content: currentTools });
9982
+ currentTools = [];
9983
+ }
9984
+ if (currentText.length > 0) {
9985
+ sections.push({ type: "text", content: currentText });
9986
+ currentText = "";
9987
+ }
9988
+ if (!checkpointedRun) {
9989
+ await updateConversation((c) => {
9990
+ if (runContinuation2 && runContinuationMessages) {
9991
+ c._continuationMessages = runContinuationMessages;
9992
+ } else {
9993
+ c._continuationMessages = void 0;
9994
+ c.messages = buildMessages();
9928
9995
  }
9929
- runContinuation2 = event.result.continuation === true;
9930
- if (event.result.continuationMessages) {
9931
- runContinuationMessages = event.result.continuationMessages;
9996
+ if (runContinuationMessages) {
9997
+ c._harnessMessages = runContinuationMessages;
9932
9998
  }
9933
- runSteps = event.result.steps;
9934
- if (typeof event.result.maxSteps === "number") runMaxSteps = event.result.maxSteps;
9935
- runContextTokens = event.result.contextTokens ?? runContextTokens;
9936
- runContextWindow = event.result.contextWindow ?? runContextWindow;
9937
- }
9938
- if (event.type === "run:error") {
9939
- assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
9940
- }
9941
- broadcastEvent(conversationId, event);
9999
+ c.runtimeRunId = latestRunId || c.runtimeRunId;
10000
+ c.pendingApprovals = [];
10001
+ c.runStatus = "idle";
10002
+ if (runContextTokens > 0) c.contextTokens = runContextTokens;
10003
+ if (runContextWindow > 0) c.contextWindow = runContextWindow;
10004
+ });
10005
+ } else {
10006
+ await updateConversation((c) => {
10007
+ c.runStatus = "idle";
10008
+ });
10009
+ }
10010
+ finishConversationStream(conversationId);
10011
+ if (latestRunId) {
10012
+ runOwners.delete(latestRunId);
10013
+ runConversations.delete(latestRunId);
10014
+ }
10015
+ console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation2 ? "(continuation)" : "");
10016
+ const response = assistantResponse;
10017
+ return {
10018
+ response,
10019
+ continuation: runContinuation2,
10020
+ steps: runSteps,
10021
+ maxSteps: runMaxSteps
10022
+ };
10023
+ } finally {
10024
+ releaseQueue?.();
10025
+ if (messagingRunQueues.get(conversationId) === chained) {
10026
+ messagingRunQueues.delete(conversationId);
9942
10027
  }
9943
- } catch (err) {
9944
- console.error("[messaging-runner] run failed:", err instanceof Error ? err.message : err);
9945
- assistantResponse = assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
9946
- }
9947
- if (currentTools.length > 0) {
9948
- sections.push({ type: "tools", content: currentTools });
9949
- currentTools = [];
9950
- }
9951
- if (currentText.length > 0) {
9952
- sections.push({ type: "text", content: currentText });
9953
- currentText = "";
9954
- }
9955
- if (!checkpointedRun) {
9956
- await updateConversation((c) => {
9957
- if (runContinuation2 && runContinuationMessages) {
9958
- c._continuationMessages = runContinuationMessages;
9959
- } else {
9960
- c._continuationMessages = void 0;
9961
- c.messages = buildMessages();
9962
- }
9963
- if (runContinuationMessages) {
9964
- c._harnessMessages = runContinuationMessages;
9965
- }
9966
- c.runtimeRunId = latestRunId || c.runtimeRunId;
9967
- c.pendingApprovals = [];
9968
- c.runStatus = "idle";
9969
- if (runContextTokens > 0) c.contextTokens = runContextTokens;
9970
- if (runContextWindow > 0) c.contextWindow = runContextWindow;
9971
- });
9972
- } else {
9973
- await updateConversation((c) => {
9974
- c.runStatus = "idle";
9975
- });
9976
- }
9977
- finishConversationStream(conversationId);
9978
- if (latestRunId) {
9979
- runOwners.delete(latestRunId);
9980
- runConversations.delete(latestRunId);
9981
10028
  }
9982
- console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation2 ? "(continuation)" : "");
9983
- const response = assistantResponse;
9984
- return {
9985
- response,
9986
- continuation: runContinuation2,
9987
- steps: runSteps,
9988
- maxSteps: runMaxSteps
9989
- };
9990
10029
  }
9991
10030
  };
9992
10031
  let waitUntilHook;
@@ -11457,6 +11496,7 @@ data: ${JSON.stringify(frame)}
11457
11496
  writeJson(response, 200, {
11458
11497
  conversation: {
11459
11498
  ...conversation,
11499
+ messages: conversation.messages.map(normalizeMessageForClient),
11460
11500
  pendingApprovals: storedPending,
11461
11501
  _continuationMessages: void 0,
11462
11502
  _harnessMessages: void 0
@@ -12920,7 +12960,7 @@ var runInteractive = async (workingDir, params) => {
12920
12960
  await harness.initialize();
12921
12961
  const identity = await ensureAgentIdentity2(workingDir);
12922
12962
  try {
12923
- const { runInteractiveInk } = await import("./run-interactive-ink-GD3IRICQ.js");
12963
+ const { runInteractiveInk } = await import("./run-interactive-ink-GPCI4L6G.js");
12924
12964
  await runInteractiveInk({
12925
12965
  harness,
12926
12966
  params,
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-TQRPRFR3.js";
4
+ } from "./chunk-F6NA3N2R.js";
5
5
 
6
6
  // src/cli.ts
7
7
  void main();
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  runTests,
24
24
  startDevServer,
25
25
  updateAgentGuidance
26
- } from "./chunk-TQRPRFR3.js";
26
+ } from "./chunk-F6NA3N2R.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-TQRPRFR3.js";
5
+ } from "./chunk-F6NA3N2R.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.32.2",
3
+ "version": "0.32.4",
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.31.2",
31
- "@poncho-ai/messaging": "0.7.6",
32
- "@poncho-ai/sdk": "1.7.1"
30
+ "@poncho-ai/harness": "0.31.3",
31
+ "@poncho-ai/sdk": "1.7.1",
32
+ "@poncho-ai/messaging": "0.7.6"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -292,6 +292,26 @@ const parseParams = (values: string[]): Record<string, string> => {
292
292
  return params;
293
293
  };
294
294
 
295
+ const normalizeMessageForClient = (message: Message): Message => {
296
+ if (message.role !== "assistant" || typeof message.content !== "string") {
297
+ return message;
298
+ }
299
+ try {
300
+ const parsed = JSON.parse(message.content) as Record<string, unknown>;
301
+ const text = typeof parsed.text === "string" ? parsed.text : undefined;
302
+ const toolCalls = Array.isArray(parsed.tool_calls) ? parsed.tool_calls : undefined;
303
+ if (typeof text === "string" && toolCalls) {
304
+ return {
305
+ ...message,
306
+ content: text,
307
+ };
308
+ }
309
+ } catch {
310
+ // Keep original assistant content when it's plain text or non-JSON.
311
+ }
312
+ return message;
313
+ };
314
+
295
315
  const AGENT_TEMPLATE = (
296
316
  name: string,
297
317
  id: string,
@@ -2766,6 +2786,7 @@ export const createRequestHandler = async (options?: {
2766
2786
  // adapter handles its own request verification (e.g. Slack signing secret).
2767
2787
  // ---------------------------------------------------------------------------
2768
2788
  const messagingRoutes = new Map<string, Map<string, (req: IncomingMessage, res: ServerResponse) => Promise<void>>>();
2789
+ const messagingRunQueues = new Map<string, Promise<void>>();
2769
2790
  const messagingRouteRegistrar: RouteRegistrar = (method, path, routeHandler) => {
2770
2791
  let byMethod = messagingRoutes.get(path);
2771
2792
  if (!byMethod) {
@@ -2811,12 +2832,28 @@ export const createRequestHandler = async (options?: {
2811
2832
  return { messages: [] };
2812
2833
  },
2813
2834
  async run(conversationId, input) {
2814
- const isContinuation = input.task == null;
2815
- console.log("[messaging-runner] starting run for", conversationId, isContinuation ? "(continuation)" : `task: ${input.task!.slice(0, 80)}`);
2835
+ const previous = messagingRunQueues.get(conversationId) ?? Promise.resolve();
2836
+ let releaseQueue: (() => void) | undefined;
2837
+ const current = new Promise<void>((resolve) => {
2838
+ releaseQueue = resolve;
2839
+ });
2840
+ const chained = previous.then(() => current);
2841
+ messagingRunQueues.set(conversationId, chained);
2842
+ await previous;
2843
+ try {
2844
+ const latestConversation = await conversationStore.get(conversationId);
2845
+ const latestMessages = latestConversation
2846
+ ? (latestConversation._harnessMessages?.length
2847
+ ? [...latestConversation._harnessMessages]
2848
+ : [...latestConversation.messages])
2849
+ : [...input.messages];
2816
2850
 
2817
- const historyMessages = [...input.messages];
2818
- const preRunMessages = [...input.messages];
2819
- const userContent = input.task;
2851
+ const isContinuation = input.task == null;
2852
+ console.log("[messaging-runner] starting run for", conversationId, isContinuation ? "(continuation)" : `task: ${input.task!.slice(0, 80)}`);
2853
+
2854
+ const historyMessages = [...latestMessages];
2855
+ const preRunMessages = [...latestMessages];
2856
+ const userContent = input.task;
2820
2857
 
2821
2858
  // Read-modify-write helper: always fetches the latest version from
2822
2859
  // the store before writing, so concurrent writers don't get clobbered.
@@ -2899,14 +2936,17 @@ export const createRequestHandler = async (options?: {
2899
2936
  const runInput = {
2900
2937
  task: input.task,
2901
2938
  conversationId,
2902
- messages: input.messages,
2939
+ messages: historyMessages,
2903
2940
  files: input.files,
2904
- parameters: input.metadata ? {
2905
- __messaging_platform: input.metadata.platform,
2906
- __messaging_sender_id: input.metadata.sender.id,
2907
- __messaging_sender_name: input.metadata.sender.name ?? "",
2908
- __messaging_thread_id: input.metadata.threadId,
2909
- } : undefined,
2941
+ parameters: {
2942
+ ...(input.metadata ? {
2943
+ __messaging_platform: input.metadata.platform,
2944
+ __messaging_sender_id: input.metadata.sender.id,
2945
+ __messaging_sender_name: input.metadata.sender.name ?? "",
2946
+ __messaging_thread_id: input.metadata.threadId,
2947
+ } : {}),
2948
+ __activeConversationId: conversationId,
2949
+ },
2910
2950
  };
2911
2951
 
2912
2952
  try {
@@ -3067,15 +3107,21 @@ export const createRequestHandler = async (options?: {
3067
3107
  runConversations.delete(latestRunId);
3068
3108
  }
3069
3109
 
3070
- console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation ? "(continuation)" : "");
3071
- const response = assistantResponse;
3110
+ console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation ? "(continuation)" : "");
3111
+ const response = assistantResponse;
3072
3112
 
3073
- return {
3074
- response,
3075
- continuation: runContinuation,
3076
- steps: runSteps,
3077
- maxSteps: runMaxSteps,
3078
- };
3113
+ return {
3114
+ response,
3115
+ continuation: runContinuation,
3116
+ steps: runSteps,
3117
+ maxSteps: runMaxSteps,
3118
+ };
3119
+ } finally {
3120
+ releaseQueue?.();
3121
+ if (messagingRunQueues.get(conversationId) === chained) {
3122
+ messagingRunQueues.delete(conversationId);
3123
+ }
3124
+ }
3079
3125
  },
3080
3126
  };
3081
3127
 
@@ -4782,6 +4828,7 @@ export const createRequestHandler = async (options?: {
4782
4828
  writeJson(response, 200, {
4783
4829
  conversation: {
4784
4830
  ...conversation,
4831
+ messages: conversation.messages.map(normalizeMessageForClient),
4785
4832
  pendingApprovals: storedPending,
4786
4833
  _continuationMessages: undefined,
4787
4834
  _harnessMessages: undefined,