@poncho-ai/cli 0.22.5 → 0.23.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/cli",
3
- "version": "0.22.5",
3
+ "version": "0.23.0",
4
4
  "description": "CLI for building and deploying AI agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,8 +28,8 @@
28
28
  "react-devtools-core": "^6.1.5",
29
29
  "yaml": "^2.8.1",
30
30
  "@poncho-ai/harness": "0.21.1",
31
- "@poncho-ai/messaging": "0.4.0",
32
- "@poncho-ai/sdk": "1.4.1"
31
+ "@poncho-ai/sdk": "1.4.1",
32
+ "@poncho-ai/messaging": "0.5.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -1499,6 +1499,47 @@ export const createRequestHandler = async (options?: {
1499
1499
  }
1500
1500
  }
1501
1501
  };
1502
+ type BrowserSessionForStatus = {
1503
+ isActiveFor: (cid: string) => boolean;
1504
+ getUrl: (cid: string) => string | undefined;
1505
+ };
1506
+ // Write a raw SSE event to all event-stream subscribers for a conversation
1507
+ // without buffering it (ephemeral events like browser:status shouldn't replay
1508
+ // on reconnect).
1509
+ const broadcastRawSse = (conversationId: string, event: string, data: unknown): void => {
1510
+ const stream = conversationEventStreams.get(conversationId);
1511
+ if (!stream) return;
1512
+ const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
1513
+ for (const subscriber of stream.subscribers) {
1514
+ try {
1515
+ subscriber.write(payload);
1516
+ } catch {
1517
+ stream.subscribers.delete(subscriber);
1518
+ }
1519
+ }
1520
+ };
1521
+ const emitBrowserStatusIfActive = (
1522
+ conversationId: string,
1523
+ event: AgentEvent,
1524
+ directResponse?: ServerResponse,
1525
+ ): void => {
1526
+ const bs = harness.browserSession as BrowserSessionForStatus | undefined;
1527
+ if (
1528
+ event.type !== "tool:completed" ||
1529
+ !event.tool.startsWith("browser_") ||
1530
+ !bs?.isActiveFor(conversationId)
1531
+ ) return;
1532
+ const statusPayload = {
1533
+ active: true,
1534
+ url: bs.getUrl(conversationId) ?? null,
1535
+ interactionAllowed: true,
1536
+ };
1537
+ const raw = `event: browser:status\ndata: ${JSON.stringify(statusPayload)}\n\n`;
1538
+ if (directResponse && !directResponse.destroyed) {
1539
+ try { directResponse.write(raw); } catch {}
1540
+ }
1541
+ broadcastRawSse(conversationId, "browser:status", statusPayload);
1542
+ };
1502
1543
  const onConversationEvent = (conversationId: string, cb: EventCallback): (() => void) => {
1503
1544
  let cbs = conversationEventCallbacks.get(conversationId);
1504
1545
  if (!cbs) {
@@ -2113,6 +2154,7 @@ export const createRequestHandler = async (options?: {
2113
2154
  }
2114
2155
  await telemetry.emit(event);
2115
2156
  broadcastEvent(conversationId, event);
2157
+ emitBrowserStatusIfActive(conversationId, event);
2116
2158
  }
2117
2159
  } catch (err) {
2118
2160
  console.error("[resume-run] error:", err instanceof Error ? err.message : err);
@@ -2262,6 +2304,9 @@ export const createRequestHandler = async (options?: {
2262
2304
  let checkpointedRun = false;
2263
2305
  let runContextTokens = 0;
2264
2306
  let runContextWindow = 0;
2307
+ let runContinuation = false;
2308
+ let runSteps = 0;
2309
+ let runMaxSteps: number | undefined;
2265
2310
 
2266
2311
  const buildMessages = (): Message[] => {
2267
2312
  const draftSections: Array<{ type: "text" | "tools"; content: string | string[] }> = [
@@ -2385,12 +2430,13 @@ export const createRequestHandler = async (options?: {
2385
2430
  });
2386
2431
  checkpointedRun = true;
2387
2432
  }
2388
- if (
2389
- event.type === "run:completed" &&
2390
- assistantResponse.length === 0 &&
2391
- event.result.response
2392
- ) {
2393
- assistantResponse = event.result.response;
2433
+ if (event.type === "run:completed") {
2434
+ if (assistantResponse.length === 0 && event.result.response) {
2435
+ assistantResponse = event.result.response;
2436
+ }
2437
+ runContinuation = event.result.continuation === true;
2438
+ runSteps = event.result.steps;
2439
+ if (typeof event.result.maxSteps === "number") runMaxSteps = event.result.maxSteps;
2394
2440
  }
2395
2441
  if (event.type === "run:error") {
2396
2442
  assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
@@ -2432,10 +2478,15 @@ export const createRequestHandler = async (options?: {
2432
2478
  runConversations.delete(latestRunId);
2433
2479
  }
2434
2480
 
2435
- console.log("[messaging-runner] run complete, response length:", assistantResponse.length);
2481
+ console.log("[messaging-runner] run complete, response length:", assistantResponse.length, runContinuation ? "(continuation)" : "");
2436
2482
  const response = assistantResponse;
2437
2483
 
2438
- return { response };
2484
+ return {
2485
+ response,
2486
+ continuation: runContinuation,
2487
+ steps: runSteps,
2488
+ maxSteps: runMaxSteps,
2489
+ };
2439
2490
  },
2440
2491
  };
2441
2492
 
@@ -3635,6 +3686,7 @@ export const createRequestHandler = async (options?: {
3635
3686
  // Client disconnected (e.g. browser refresh). Continue processing
3636
3687
  // so the run completes and conversation is persisted.
3637
3688
  }
3689
+ emitBrowserStatusIfActive(conversationId, event, response);
3638
3690
  }
3639
3691
  // Finalize sections
3640
3692
  if (currentTools.length > 0) {