@poncho-ai/cli 0.19.1 → 0.20.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/cli@0.19.1 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
2
+ > @poncho-ai/cli@0.20.1 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-4KVVPMR3.js 55.30 KB
12
- ESM dist/chunk-7P53QSP5.js 381.82 KB
11
+ ESM dist/run-interactive-ink-S3D42QQY.js 55.30 KB
12
+ ESM dist/chunk-J4OZUXG5.js 383.23 KB
13
13
  ESM dist/index.js 857.00 B
14
14
  ESM ⚡️ Build success in 60ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3716ms
16
+ DTS ⚡️ Build success in 3870ms
17
17
  DTS dist/cli.d.ts 20.00 B
18
18
  DTS dist/index.d.ts 3.59 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @poncho-ai/cli
2
2
 
3
+ ## 0.20.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`a9563b0`](https://github.com/cesr/poncho-ai/commit/a9563b03dfbdb6eb8cc9536be72b2bfd76c042ef) Thanks [@cesr](https://github.com/cesr)! - Fix approval resume dying on Vercel: wrap the post-approval tool execution and run resumption in waitUntil so the serverless function stays alive until the work completes.
8
+
9
+ ## 0.20.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`5df6b5f`](https://github.com/cesr/poncho-ai/commit/5df6b5fcdc98e0445bea504dc9d077f02d1e954f) Thanks [@cesr](https://github.com/cesr)! - Add polling fallback for web UI on serverless deployments: when the SSE event stream is unavailable (different instance from the webhook handler), the UI polls the conversation every 2 seconds until the run completes. Conversations now track a persisted `runStatus` field.
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [[`5df6b5f`](https://github.com/cesr/poncho-ai/commit/5df6b5fcdc98e0445bea504dc9d077f02d1e954f)]:
18
+ - @poncho-ai/harness@0.20.0
19
+
3
20
  ## 0.19.1
4
21
 
5
22
  ### Patch Changes
@@ -2493,8 +2493,7 @@ var getWebUiClientScript = (markedSource2) => `
2493
2493
  setStreaming(true);
2494
2494
  streamConversationEvents(conversationId, { liveOnly: true }).finally(() => {
2495
2495
  if (state.activeConversationId === conversationId) {
2496
- setStreaming(false);
2497
- renderMessages(state.activeMessages, false);
2496
+ pollUntilRunIdle(conversationId);
2498
2497
  }
2499
2498
  });
2500
2499
  }
@@ -2561,6 +2560,30 @@ var getWebUiClientScript = (markedSource2) => `
2561
2560
  });
2562
2561
  };
2563
2562
 
2563
+ const pollUntilRunIdle = (conversationId) => {
2564
+ const poll = async () => {
2565
+ if (state.activeConversationId !== conversationId) return;
2566
+ try {
2567
+ var payload = await api("/api/conversations/" + encodeURIComponent(conversationId));
2568
+ if (state.activeConversationId !== conversationId) return;
2569
+ if (payload.conversation) {
2570
+ state.activeMessages = payload.conversation.messages || [];
2571
+ renderMessages(state.activeMessages, payload.hasActiveRun);
2572
+ }
2573
+ if (payload.hasActiveRun) {
2574
+ setTimeout(poll, 2000);
2575
+ } else {
2576
+ setStreaming(false);
2577
+ renderMessages(state.activeMessages, false);
2578
+ }
2579
+ } catch {
2580
+ setStreaming(false);
2581
+ renderMessages(state.activeMessages, false);
2582
+ }
2583
+ };
2584
+ setTimeout(poll, 1500);
2585
+ };
2586
+
2564
2587
  const streamConversationEvents = (conversationId, options) => {
2565
2588
  const liveOnly = options && options.liveOnly;
2566
2589
  return new Promise((resolve) => {
@@ -7867,11 +7890,19 @@ var createRequestHandler = async (options) => {
7867
7890
  }
7868
7891
  conv.runtimeRunId = latestRunId || conv.runtimeRunId;
7869
7892
  conv.pendingApprovals = [];
7893
+ conv.runStatus = "idle";
7870
7894
  if (runContextTokens > 0) conv.contextTokens = runContextTokens;
7871
7895
  if (runContextWindow > 0) conv.contextWindow = runContextWindow;
7872
7896
  conv.updatedAt = Date.now();
7873
7897
  await conversationStore.update(conv);
7874
7898
  }
7899
+ } else {
7900
+ const conv = await conversationStore.get(conversationId);
7901
+ if (conv) {
7902
+ conv.runStatus = "idle";
7903
+ conv.updatedAt = Date.now();
7904
+ await conversationStore.update(conv);
7905
+ }
7875
7906
  }
7876
7907
  finishConversationStream(conversationId);
7877
7908
  activeConversationRuns.delete(conversationId);
@@ -7922,6 +7953,7 @@ var createRequestHandler = async (options) => {
7922
7953
  };
7923
7954
  await updateConversation((c) => {
7924
7955
  c.messages = [...historyMessages, { role: "user", content: userContent }];
7956
+ c.runStatus = "running";
7925
7957
  });
7926
7958
  let latestRunId = "";
7927
7959
  let assistantResponse = "";
@@ -8072,9 +8104,14 @@ var createRequestHandler = async (options) => {
8072
8104
  c.messages = buildMessages();
8073
8105
  c.runtimeRunId = latestRunId || c.runtimeRunId;
8074
8106
  c.pendingApprovals = [];
8107
+ c.runStatus = "idle";
8075
8108
  if (runContextTokens > 0) c.contextTokens = runContextTokens;
8076
8109
  if (runContextWindow > 0) c.contextWindow = runContextWindow;
8077
8110
  });
8111
+ } else {
8112
+ await updateConversation((c) => {
8113
+ c.runStatus = "idle";
8114
+ });
8078
8115
  }
8079
8116
  finishConversationStream(conversationId);
8080
8117
  if (latestRunId) {
@@ -8086,20 +8123,20 @@ var createRequestHandler = async (options) => {
8086
8123
  return { response };
8087
8124
  }
8088
8125
  };
8126
+ let waitUntilHook;
8127
+ if (process.env.VERCEL) {
8128
+ try {
8129
+ const modName = "@vercel/functions";
8130
+ const mod = await import(
8131
+ /* webpackIgnore: true */
8132
+ modName
8133
+ );
8134
+ waitUntilHook = mod.waitUntil;
8135
+ } catch {
8136
+ }
8137
+ }
8089
8138
  const messagingBridges = [];
8090
8139
  if (config?.messaging && config.messaging.length > 0) {
8091
- let waitUntilHook;
8092
- if (process.env.VERCEL) {
8093
- try {
8094
- const modName = "@vercel/functions";
8095
- const mod = await import(
8096
- /* webpackIgnore: true */
8097
- modName
8098
- );
8099
- waitUntilHook = mod.waitUntil;
8100
- } catch {
8101
- }
8102
- }
8103
8140
  for (const channelConfig of config.messaging) {
8104
8141
  if (channelConfig.platform === "slack") {
8105
8142
  const adapter = new SlackAdapter({
@@ -8549,9 +8586,10 @@ data: ${JSON.stringify(data)}
8549
8586
  return;
8550
8587
  }
8551
8588
  foundConversation.pendingApprovals = [];
8589
+ foundConversation.runStatus = "running";
8552
8590
  await conversationStore.update(foundConversation);
8553
8591
  const checkpointRef = allApprovals[0];
8554
- void (async () => {
8592
+ const resumeWork = (async () => {
8555
8593
  const toolContext = {
8556
8594
  runId: checkpointRef.runId,
8557
8595
  agentId: identity.id,
@@ -8592,6 +8630,9 @@ data: ${JSON.stringify(data)}
8592
8630
  toolResults
8593
8631
  );
8594
8632
  })();
8633
+ if (waitUntilHook) {
8634
+ waitUntilHook(resumeWork);
8635
+ }
8595
8636
  writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: true });
8596
8637
  return;
8597
8638
  }
@@ -8697,7 +8738,7 @@ data: ${JSON.stringify(data)}
8697
8738
  }
8698
8739
  }
8699
8740
  const activeStream = conversationEventStreams.get(conversationId);
8700
- const hasActiveRun = !!activeStream && !activeStream.finished;
8741
+ const hasActiveRun = !!activeStream && !activeStream.finished || conversation.runStatus === "running";
8701
8742
  writeJson(response, 200, {
8702
8743
  conversation: {
8703
8744
  ...conversation,
@@ -9620,7 +9661,7 @@ var runInteractive = async (workingDir, params) => {
9620
9661
  await harness.initialize();
9621
9662
  const identity = await ensureAgentIdentity2(workingDir);
9622
9663
  try {
9623
- const { runInteractiveInk } = await import("./run-interactive-ink-4KVVPMR3.js");
9664
+ const { runInteractiveInk } = await import("./run-interactive-ink-S3D42QQY.js");
9624
9665
  await runInteractiveInk({
9625
9666
  harness,
9626
9667
  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-7P53QSP5.js";
4
+ } from "./chunk-J4OZUXG5.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-7P53QSP5.js";
26
+ } from "./chunk-J4OZUXG5.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-7P53QSP5.js";
5
+ } from "./chunk-J4OZUXG5.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.19.1",
3
+ "version": "0.20.1",
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.19.1",
31
- "@poncho-ai/sdk": "1.4.0",
32
- "@poncho-ai/messaging": "0.2.7"
30
+ "@poncho-ai/harness": "0.20.0",
31
+ "@poncho-ai/messaging": "0.2.7",
32
+ "@poncho-ai/sdk": "1.4.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -2081,11 +2081,19 @@ export const createRequestHandler = async (options?: {
2081
2081
  }
2082
2082
  conv.runtimeRunId = latestRunId || conv.runtimeRunId;
2083
2083
  conv.pendingApprovals = [];
2084
+ conv.runStatus = "idle";
2084
2085
  if (runContextTokens > 0) conv.contextTokens = runContextTokens;
2085
2086
  if (runContextWindow > 0) conv.contextWindow = runContextWindow;
2086
2087
  conv.updatedAt = Date.now();
2087
2088
  await conversationStore.update(conv);
2088
2089
  }
2090
+ } else {
2091
+ const conv = await conversationStore.get(conversationId);
2092
+ if (conv) {
2093
+ conv.runStatus = "idle";
2094
+ conv.updatedAt = Date.now();
2095
+ await conversationStore.update(conv);
2096
+ }
2089
2097
  }
2090
2098
 
2091
2099
  finishConversationStream(conversationId);
@@ -2148,9 +2156,10 @@ export const createRequestHandler = async (options?: {
2148
2156
  await conversationStore.update(fresh);
2149
2157
  };
2150
2158
 
2151
- // Persist user turn immediately so the web UI shows it while the agent runs.
2159
+ // Persist user turn and mark the run as active so the web UI can detect it.
2152
2160
  await updateConversation((c) => {
2153
2161
  c.messages = [...historyMessages, { role: "user" as const, content: userContent }];
2162
+ c.runStatus = "running";
2154
2163
  });
2155
2164
 
2156
2165
  let latestRunId = "";
@@ -2317,9 +2326,14 @@ export const createRequestHandler = async (options?: {
2317
2326
  c.messages = buildMessages();
2318
2327
  c.runtimeRunId = latestRunId || c.runtimeRunId;
2319
2328
  c.pendingApprovals = [];
2329
+ c.runStatus = "idle";
2320
2330
  if (runContextTokens > 0) c.contextTokens = runContextTokens;
2321
2331
  if (runContextWindow > 0) c.contextWindow = runContextWindow;
2322
2332
  });
2333
+ } else {
2334
+ await updateConversation((c) => {
2335
+ c.runStatus = "idle";
2336
+ });
2323
2337
  }
2324
2338
  finishConversationStream(conversationId);
2325
2339
  if (latestRunId) {
@@ -2334,21 +2348,19 @@ export const createRequestHandler = async (options?: {
2334
2348
  },
2335
2349
  };
2336
2350
 
2337
- const messagingBridges: AgentBridge[] = [];
2338
- if (config?.messaging && config.messaging.length > 0) {
2339
- let waitUntilHook: ((promise: Promise<unknown>) => void) | undefined;
2340
- if (process.env.VERCEL) {
2341
- try {
2342
- // Dynamic require via variable so TypeScript doesn't attempt static
2343
- // resolution of @vercel/functions (only present in Vercel deployments).
2344
- const modName = "@vercel/functions";
2345
- const mod = await import(/* webpackIgnore: true */ modName);
2346
- waitUntilHook = mod.waitUntil;
2347
- } catch {
2348
- // @vercel/functions not installed -- fall through to no-op.
2349
- }
2351
+ let waitUntilHook: ((promise: Promise<unknown>) => void) | undefined;
2352
+ if (process.env.VERCEL) {
2353
+ try {
2354
+ const modName = "@vercel/functions";
2355
+ const mod = await import(/* webpackIgnore: true */ modName);
2356
+ waitUntilHook = mod.waitUntil;
2357
+ } catch {
2358
+ // @vercel/functions not installed -- fall through to no-op.
2350
2359
  }
2360
+ }
2351
2361
 
2362
+ const messagingBridges: AgentBridge[] = [];
2363
+ if (config?.messaging && config.messaging.length > 0) {
2352
2364
  for (const channelConfig of config.messaging) {
2353
2365
  if (channelConfig.platform === "slack") {
2354
2366
  const adapter = new SlackAdapter({
@@ -2890,12 +2902,13 @@ export const createRequestHandler = async (options?: {
2890
2902
 
2891
2903
  // All approvals in the batch are decided — execute and resume
2892
2904
  foundConversation.pendingApprovals = [];
2905
+ foundConversation.runStatus = "running";
2893
2906
  await conversationStore.update(foundConversation);
2894
2907
 
2895
2908
  // Use the first approval as the checkpoint reference (all share the same checkpoint data)
2896
2909
  const checkpointRef = allApprovals[0]!;
2897
2910
 
2898
- void (async () => {
2911
+ const resumeWork = (async () => {
2899
2912
  const toolContext = {
2900
2913
  runId: checkpointRef.runId,
2901
2914
  agentId: identity.id,
@@ -2943,6 +2956,9 @@ export const createRequestHandler = async (options?: {
2943
2956
  toolResults,
2944
2957
  );
2945
2958
  })();
2959
+ if (waitUntilHook) {
2960
+ waitUntilHook(resumeWork);
2961
+ }
2946
2962
 
2947
2963
  writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: true });
2948
2964
  return;
@@ -3057,7 +3073,7 @@ export const createRequestHandler = async (options?: {
3057
3073
  }
3058
3074
  }
3059
3075
  const activeStream = conversationEventStreams.get(conversationId);
3060
- const hasActiveRun = !!activeStream && !activeStream.finished;
3076
+ const hasActiveRun = (!!activeStream && !activeStream.finished) || conversation.runStatus === "running";
3061
3077
  writeJson(response, 200, {
3062
3078
  conversation: {
3063
3079
  ...conversation,
@@ -962,8 +962,7 @@ export const getWebUiClientScript = (markedSource: string): string => `
962
962
  setStreaming(true);
963
963
  streamConversationEvents(conversationId, { liveOnly: true }).finally(() => {
964
964
  if (state.activeConversationId === conversationId) {
965
- setStreaming(false);
966
- renderMessages(state.activeMessages, false);
965
+ pollUntilRunIdle(conversationId);
967
966
  }
968
967
  });
969
968
  }
@@ -1030,6 +1029,30 @@ export const getWebUiClientScript = (markedSource: string): string => `
1030
1029
  });
1031
1030
  };
1032
1031
 
1032
+ const pollUntilRunIdle = (conversationId) => {
1033
+ const poll = async () => {
1034
+ if (state.activeConversationId !== conversationId) return;
1035
+ try {
1036
+ var payload = await api("/api/conversations/" + encodeURIComponent(conversationId));
1037
+ if (state.activeConversationId !== conversationId) return;
1038
+ if (payload.conversation) {
1039
+ state.activeMessages = payload.conversation.messages || [];
1040
+ renderMessages(state.activeMessages, payload.hasActiveRun);
1041
+ }
1042
+ if (payload.hasActiveRun) {
1043
+ setTimeout(poll, 2000);
1044
+ } else {
1045
+ setStreaming(false);
1046
+ renderMessages(state.activeMessages, false);
1047
+ }
1048
+ } catch {
1049
+ setStreaming(false);
1050
+ renderMessages(state.activeMessages, false);
1051
+ }
1052
+ };
1053
+ setTimeout(poll, 1500);
1054
+ };
1055
+
1033
1056
  const streamConversationEvents = (conversationId, options) => {
1034
1057
  const liveOnly = options && options.liveOnly;
1035
1058
  return new Promise((resolve) => {