@geminixiang/mikan 1.0.0-beta.80 → 1.0.0-beta.82

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 (67) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/adapters/github/bot.d.ts.map +1 -1
  3. package/dist/adapters/github/bot.js +4 -4
  4. package/dist/adapters/github/bot.js.map +1 -1
  5. package/dist/adapters/github/client.d.ts +4 -0
  6. package/dist/adapters/github/client.d.ts.map +1 -1
  7. package/dist/adapters/github/client.js +41 -23
  8. package/dist/adapters/github/client.js.map +1 -1
  9. package/dist/adapters/github/github-ops.js +16 -12
  10. package/dist/adapters/github/github-ops.js.map +1 -1
  11. package/dist/adapters/slack/bot.d.ts.map +1 -1
  12. package/dist/adapters/slack/bot.js +6 -3
  13. package/dist/adapters/slack/bot.js.map +1 -1
  14. package/dist/adapters/web/server.d.ts +2 -0
  15. package/dist/adapters/web/server.d.ts.map +1 -1
  16. package/dist/adapters/web/server.js +11 -4
  17. package/dist/adapters/web/server.js.map +1 -1
  18. package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
  19. package/dist/adapters/web/session-view/portal.js +84 -63
  20. package/dist/adapters/web/session-view/portal.js.map +1 -1
  21. package/dist/adapters/web/session-view/types.d.ts +2 -0
  22. package/dist/adapters/web/session-view/types.d.ts.map +1 -1
  23. package/dist/adapters/web/session-view/types.js.map +1 -1
  24. package/dist/env-manifest.d.ts +1 -0
  25. package/dist/env-manifest.d.ts.map +1 -1
  26. package/dist/env-manifest.js +7 -0
  27. package/dist/env-manifest.js.map +1 -1
  28. package/dist/harness/loop-guard.d.ts +10 -0
  29. package/dist/harness/loop-guard.d.ts.map +1 -0
  30. package/dist/harness/loop-guard.js +111 -0
  31. package/dist/harness/loop-guard.js.map +1 -0
  32. package/dist/harness/presenter.d.ts.map +1 -1
  33. package/dist/harness/presenter.js +159 -142
  34. package/dist/harness/presenter.js.map +1 -1
  35. package/dist/harness/prompt.d.ts +1 -1
  36. package/dist/harness/prompt.d.ts.map +1 -1
  37. package/dist/harness/prompt.js +14 -21
  38. package/dist/harness/prompt.js.map +1 -1
  39. package/dist/harness/run-events.d.ts +10 -0
  40. package/dist/harness/run-events.d.ts.map +1 -0
  41. package/dist/harness/run-events.js +129 -0
  42. package/dist/harness/run-events.js.map +1 -0
  43. package/dist/harness/runner.d.ts.map +1 -1
  44. package/dist/harness/runner.js +79 -49
  45. package/dist/harness/runner.js.map +1 -1
  46. package/dist/harness/session.d.ts +5 -0
  47. package/dist/harness/session.d.ts.map +1 -1
  48. package/dist/harness/session.js +71 -1
  49. package/dist/harness/session.js.map +1 -1
  50. package/dist/harness/tools/react.d.ts +1 -0
  51. package/dist/harness/tools/react.d.ts.map +1 -1
  52. package/dist/harness/tools/react.js +3 -2
  53. package/dist/harness/tools/react.js.map +1 -1
  54. package/dist/harness/types.d.ts +61 -0
  55. package/dist/harness/types.d.ts.map +1 -1
  56. package/dist/harness/types.js.map +1 -1
  57. package/dist/main.js +11 -8
  58. package/dist/main.js.map +1 -1
  59. package/dist/runtime/conversation-runtime.js +1 -0
  60. package/dist/runtime/conversation-runtime.js.map +1 -1
  61. package/dist/runtime/types.d.ts +2 -1
  62. package/dist/runtime/types.d.ts.map +1 -1
  63. package/dist/runtime/types.js.map +1 -1
  64. package/dist/types.d.ts +2 -1
  65. package/dist/types.d.ts.map +1 -1
  66. package/dist/types.js.map +1 -1
  67. package/package.json +2 -2
@@ -1,10 +1,10 @@
1
1
  import { contentText } from "@earendil-works/pi-ai";
2
- import { mergeSubagentProgress, parseSubagentProgressSnapshot, renderSubagentDashboard, settleSubagentProgress, } from "./tools/subagent.js";
2
+ import { mergeSubagentProgress, renderSubagentDashboard, settleSubagentProgress, } from "./tools/subagent.js";
3
3
  import { addLifecycleEvent, metricAttributes, recordCounter, recordDistribution, recordGauge, reportUserFacingError, startOperationSpan, updateActiveSpanAttribution, } from "../observability/index.js";
4
4
  import { appendTriggerAttribution } from "./prompt.js";
5
5
  import { START_TASK_TOOL, TASK_STATUS_TOOL } from "./tools/task.js";
6
- import { JEV_TOOL } from "./tools/jev.js";
7
- import { JEV_BROWSER_TOOL } from "./tools/jev-browser.js";
6
+ import { toRunEvent, toolResultText } from "./run-events.js";
7
+ import { REACT_TOOL } from "./tools/react.js";
8
8
  import * as log from "../log.js";
9
9
  import { errorMessage } from "../unknown-values.js";
10
10
  const operationSpans = new WeakMap();
@@ -53,6 +53,9 @@ function createRunStateDefaults() {
53
53
  subagentToolCalls: new Set(),
54
54
  subagentProgressShown: false,
55
55
  suppressResponseDeltas: false,
56
+ answerStreamStarted: false,
57
+ workAcknowledged: false,
58
+ publishRunEvent: undefined,
56
59
  lastSubagentProgressAt: 0,
57
60
  toolProgressTimer: undefined,
58
61
  totalUsage: createEmptyUsageTotals(),
@@ -92,6 +95,7 @@ export function activateRunPresentation(runState, context) {
92
95
  sessionId: context.sessionUuid,
93
96
  },
94
97
  triggerAttribution: context.triggerAttribution,
98
+ publishRunEvent: context.publishRunEvent,
95
99
  });
96
100
  const { responder } = context;
97
101
  let queueChain = Promise.resolve();
@@ -124,6 +128,7 @@ export function activateRunPresentation(runState, context) {
124
128
  runState.responder = null;
125
129
  runState.logCtx = null;
126
130
  runState.queue = null;
131
+ runState.publishRunEvent = undefined;
127
132
  },
128
133
  };
129
134
  }
@@ -134,14 +139,6 @@ export function getFinalAssistantText(session) {
134
139
  export function isEventTriggerAttribution(triggerAttribution) {
135
140
  return triggerAttribution?.startsWith("[event:") === true;
136
141
  }
137
- function extractToolLabel(toolName, args) {
138
- const label = args?.label;
139
- const text = typeof label === "string" ? label.trim() || toolName : toolName;
140
- if ((toolName === JEV_TOOL || toolName === JEV_BROWSER_TOOL) && text !== toolName) {
141
- return `${toolName} · ${text}`;
142
- }
143
- return text;
144
- }
145
142
  function formatToolProgress(runState) {
146
143
  const lines = Array.from(runState.toolProgress.entries()).flatMap(([toolCallId, item]) => {
147
144
  if (runState.subagentToolCalls.has(toolCallId))
@@ -206,14 +203,6 @@ function flushToolProgressUpdate(responder, runState) {
206
203
  markSubagentProgressShown(runState, subagentProgress);
207
204
  runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, subagentProgress), "tool progress update");
208
205
  }
209
- function extractSubagentProgress(partialResult) {
210
- if (!partialResult || typeof partialResult !== "object")
211
- return undefined;
212
- const details = partialResult.details;
213
- if (!details || typeof details !== "object")
214
- return undefined;
215
- return parseSubagentProgressSnapshot(details.progress);
216
- }
217
206
  async function finalizeErrorResponse(responder, runState, options) {
218
207
  if (!runState.reportedLlmError) {
219
208
  runState.reportedLlmError = true;
@@ -272,7 +261,7 @@ export async function finalizeRunResponse(responder, session, runState, options)
272
261
  if (!finalText.trim())
273
262
  return;
274
263
  const published = await publishFinalResponse(responder, runState, finalText, options);
275
- const didWork = Object.keys(session.getLastRunStats().toolCallCounts).some((name) => ![TASK_STATUS_TOOL, START_TASK_TOOL, "react"].includes(name));
264
+ const didWork = Object.keys(session.getLastRunStats().toolCallCounts).some((name) => ![TASK_STATUS_TOOL, START_TASK_TOOL, REACT_TOOL].includes(name));
276
265
  if (published && runState.stopReason === "stop" && (didWork || options?.initialTask))
277
266
  await responder.notifyCompletion?.();
278
267
  }
@@ -416,22 +405,6 @@ export async function reportUsageSummary(ctx) {
416
405
  await waitForQueue();
417
406
  }
418
407
  }
419
- function toolResultContentText(result) {
420
- if (!result || typeof result !== "object" || !("content" in result))
421
- return undefined;
422
- const content = result.content;
423
- if (!Array.isArray(content))
424
- return undefined;
425
- const textParts = content
426
- .filter((part) => part.type === "text" && part.text)
427
- .map((part) => part.text);
428
- return textParts.length > 0 ? textParts.join("\n") : undefined;
429
- }
430
- function extractToolResultText(result) {
431
- if (typeof result === "string")
432
- return result;
433
- return toolResultContentText(result) ?? JSON.stringify(result);
434
- }
435
408
  function serializedLength(value) {
436
409
  if (typeof value === "string")
437
410
  return value.length;
@@ -455,8 +428,8 @@ function toolCategory(name, roles) {
455
428
  return "platform";
456
429
  return "function";
457
430
  }
458
- function handleToolStart(event, context) {
459
- const { runState, responder, logCtx, queue, baseAttrs } = context;
431
+ function observeToolStart(event, context) {
432
+ const { runState, logCtx, baseAttrs } = context;
460
433
  const args = (event.args ?? {});
461
434
  const label = args.label || event.toolName;
462
435
  runState.toolCallCount += 1;
@@ -468,18 +441,6 @@ function handleToolStart(event, context) {
468
441
  });
469
442
  if (event.toolName === START_TASK_TOOL)
470
443
  return;
471
- if (event.toolName !== TASK_STATUS_TOOL) {
472
- runState.toolProgress.set(event.toolCallId, {
473
- label: extractToolLabel(event.toolName, event.args),
474
- status: "running",
475
- });
476
- }
477
- if (event.toolName === "subagent") {
478
- runState.subagentToolCalls.add(event.toolCallId);
479
- }
480
- else if (event.toolName !== TASK_STATUS_TOOL) {
481
- queue.enqueue(() => replaceResponseWithToolProgress(responder, runState), "tool progress update");
482
- }
483
444
  spansFor(runState).tools.set(event.toolCallId, startOperationSpan(`execute_tool ${event.toolName}`, metricAttributes({
484
445
  "gen_ai.operation.name": "execute_tool",
485
446
  "gen_ai.tool.name": event.toolName,
@@ -492,15 +453,6 @@ function handleToolStart(event, context) {
492
453
  addLifecycleEvent("agent.tool.started", { tool: event.toolName, ...baseAttrs });
493
454
  log.logToolStart(logCtx, event.toolName, label, event.args);
494
455
  }
495
- function handleToolUpdate(event, context) {
496
- const subagentProgress = extractSubagentProgress(event.partialResult);
497
- if (!subagentProgress)
498
- return;
499
- context.runState.subagentProgress.set(event.toolCallId, subagentProgress);
500
- context.runState.subagentToolCalls.add(event.toolCallId);
501
- context.runState.suppressResponseDeltas = true;
502
- scheduleToolProgressUpdate(context.responder, context.runState);
503
- }
504
456
  function recordToolMetrics(event, durationMs, context) {
505
457
  recordCounter("agent.tool.calls", 1, metricAttributes({
506
458
  tool: event.toolName,
@@ -518,16 +470,15 @@ function recordToolMetrics(event, durationMs, context) {
518
470
  ...context.baseAttrs,
519
471
  });
520
472
  }
521
- function handleToolEnd(event, context) {
522
- const { runState, responder, logCtx } = context;
523
- const resultStr = extractToolResultText(event.result);
473
+ function observeToolEnd(event, context) {
474
+ const { runState, logCtx } = context;
524
475
  const outputCharacters = serializedLength(event.result);
525
476
  runState.toolOutputCharacters += outputCharacters;
526
477
  if (event.isError)
527
478
  runState.toolErrorCount += 1;
528
479
  const pending = runState.pendingTools.get(event.toolCallId);
480
+ runState.pendingTools.delete(event.toolCallId);
529
481
  if (event.toolName === START_TASK_TOOL) {
530
- runState.pendingTools.delete(event.toolCallId);
531
482
  if (!event.isError)
532
483
  runState.finalResponseHandledByTool = true;
533
484
  else
@@ -540,20 +491,6 @@ function handleToolEnd(event, context) {
540
491
  });
541
492
  return;
542
493
  }
543
- const progress = runState.toolProgress.get(event.toolCallId);
544
- if (progress)
545
- progress.status = event.isError ? "error" : "done";
546
- const subagentProgress = runState.subagentProgress.get(event.toolCallId);
547
- if (subagentProgress) {
548
- runState.subagentProgress.set(event.toolCallId, settleSubagentProgress(subagentProgress, event.isError));
549
- }
550
- if (event.toolName !== TASK_STATUS_TOOL)
551
- flushToolProgressUpdate(responder, runState);
552
- const completedProgress = runState.subagentProgress.get(event.toolCallId);
553
- if (completedProgress)
554
- runState.completedSubagentProgress.push(completedProgress);
555
- runState.subagentProgress.delete(event.toolCallId);
556
- runState.pendingTools.delete(event.toolCallId);
557
494
  const durationMs = pending ? Date.now() - pending.startTime : 0;
558
495
  const toolSpan = spansFor(runState).tools.get(event.toolCallId);
559
496
  toolSpan?.end({
@@ -570,6 +507,7 @@ function handleToolEnd(event, context) {
570
507
  });
571
508
  spansFor(runState).tools.delete(event.toolCallId);
572
509
  recordToolMetrics(event, durationMs, context);
510
+ const resultStr = toolResultText(event.result);
573
511
  if (event.isError) {
574
512
  log.logToolError(logCtx, event.toolName, durationMs, resultStr);
575
513
  return;
@@ -579,7 +517,7 @@ function handleToolEnd(event, context) {
579
517
  runState.finalResponseHandledByTool = true;
580
518
  }
581
519
  }
582
- function handleMessageStart(event, context) {
520
+ function observeMessageStart(event, context) {
583
521
  if (event.message.role !== "assistant")
584
522
  return;
585
523
  context.runState.llmCallCount += 1;
@@ -603,7 +541,7 @@ function handleMessageStart(event, context) {
603
541
  });
604
542
  log.logResponseStart(context.logCtx);
605
543
  }
606
- function handleMessageUpdate(event, context) {
544
+ function observeMessageUpdate(event, context) {
607
545
  const update = event.assistantMessageEvent;
608
546
  if (update.type !== "text_delta" || !update.delta)
609
547
  return;
@@ -612,11 +550,6 @@ function handleMessageUpdate(event, context) {
612
550
  llmEntry.firstTokenAt = Date.now();
613
551
  context.runState.firstTokenLatencyMs ??= llmEntry.firstTokenAt - llmEntry.startedAt;
614
552
  }
615
- if (context.responder.appendResponseDelta && !context.runState.suppressResponseDeltas) {
616
- context.queue.enqueue(async () => {
617
- await context.responder.appendResponseDelta?.(update.delta);
618
- }, "response delta");
619
- }
620
553
  }
621
554
  function recordAssistantUsage(message, context) {
622
555
  if (!message.usage)
@@ -661,43 +594,7 @@ function recordAssistantUsage(message, context) {
661
594
  cost_total_usd: message.usage.cost.total,
662
595
  });
663
596
  }
664
- function presentThinking(thinking, context) {
665
- log.logThinking(context.logCtx, thinking);
666
- context.queue.enqueue(() => context.responder.respond(`_${thinking}_`), "thinking main");
667
- context.queue.enqueue(() => context.responder.respondDiagnostic(`_${thinking}_`), "thinking diagnostic");
668
- }
669
- function presentFinalText(text, context) {
670
- const finalText = appendTriggerAttribution(formatResponseWithToolProgress(text, context.runState), context.runState.triggerAttribution);
671
- log.logResponse(context.logCtx, text);
672
- if (context.runState.completedSubagentProgress.length > 0)
673
- return;
674
- if (context.responder.finishResponse) {
675
- context.queue.enqueue(async () => {
676
- await context.responder.finishResponse?.(finalText);
677
- }, "response finish");
678
- }
679
- else {
680
- context.queue.enqueue(() => context.responder.respond(finalText), "response main");
681
- }
682
- }
683
- function presentAssistantMessage(message, context) {
684
- const thinkingParts = [];
685
- const textParts = [];
686
- const hasToolCall = message.content.some((part) => ["tool_use", "toolCall", "tool-call"].includes(part.type ?? ""));
687
- for (const part of message.content) {
688
- if (part.type === "thinking")
689
- thinkingParts.push(part.thinking);
690
- else if (part.type === "text")
691
- textParts.push(part.text);
692
- }
693
- for (const thinking of thinkingParts)
694
- presentThinking(thinking, context);
695
- const text = textParts.join("\n");
696
- if (!text.trim() || hasToolCall || context.runState.finalResponseHandledByTool)
697
- return;
698
- presentFinalText(text, context);
699
- }
700
- function handleMessageEnd(event, context) {
597
+ function observeMessageEnd(event, context) {
701
598
  if (event.message.role !== "assistant")
702
599
  return;
703
600
  const message = event.message;
@@ -740,14 +637,11 @@ function handleMessageEnd(event, context) {
740
637
  }),
741
638
  error: message.errorMessage ? operationError("LLMError") : undefined,
742
639
  });
743
- presentAssistantMessage(message, context);
744
640
  }
745
- function handleLifecycleEvent(event, context) {
641
+ function observeLifecycleEvent(event, context) {
746
642
  if (event.type === "compaction_start") {
747
643
  context.runState.compactionCount += 1;
748
- const text = "_Compacting context..._";
749
644
  log.logInfo(`Auto-compaction started (reason: ${event.reason})`);
750
- context.queue.enqueue(() => context.responder.respond(text), "compaction start");
751
645
  return;
752
646
  }
753
647
  if (event.type === "compaction_end") {
@@ -762,55 +656,168 @@ function handleLifecycleEvent(event, context) {
762
656
  if (event.type === "auto_retry_start") {
763
657
  context.runState.retryCount += 1;
764
658
  log.logWarning(`Retrying (${event.attempt}/${event.maxAttempts})`, event.errorMessage);
765
- const text = `_Retrying (${event.attempt}/${event.maxAttempts})..._`;
766
- context.queue.enqueue(() => context.responder.respond(text), "retry");
767
659
  return;
768
660
  }
769
661
  context.runState.budgetExceeded = true;
770
662
  log.logWarning("Run stopped by budget circuit breaker", `${event.reason} (tokens=${event.tokens}, cost=${event.costUsd.toFixed(2)}, calls=${event.llmCalls}, ${event.durationMs}ms)`);
771
- const text = `_Stopped: run budget exceeded (${event.reason})_`;
772
- context.queue.enqueue(() => context.responder.respondDiagnostic(text, { style: "error" }), "budget exceeded");
773
663
  }
774
- function handlePresenterEvent(event, context) {
664
+ function observeHarnessEvent(event, context) {
775
665
  switch (event.type) {
776
666
  case "tool_execution_start":
777
- handleToolStart(event, context);
778
- return;
779
- case "tool_execution_update":
780
- handleToolUpdate(event, context);
667
+ observeToolStart(event, context);
781
668
  return;
782
669
  case "tool_execution_end":
783
- handleToolEnd(event, context);
670
+ observeToolEnd(event, context);
784
671
  return;
785
672
  case "message_start":
786
- handleMessageStart(event, context);
673
+ observeMessageStart(event, context);
787
674
  return;
788
675
  case "message_update":
789
- handleMessageUpdate(event, context);
676
+ observeMessageUpdate(event, context);
790
677
  return;
791
678
  case "message_end":
792
- handleMessageEnd(event, context);
679
+ observeMessageEnd(event, context);
793
680
  return;
794
681
  case "compaction_start":
795
682
  case "compaction_end":
796
683
  case "auto_retry_start":
797
684
  case "budget_exceeded":
798
- handleLifecycleEvent(event, context);
685
+ observeLifecycleEvent(event, context);
799
686
  return;
800
687
  default:
801
688
  return;
802
689
  }
803
690
  }
691
+ const WORK_ACKNOWLEDGEMENT_REACTION = "saluting_face";
692
+ const TOOLS_THAT_ARE_NOT_WORK = new Set([START_TASK_TOOL, TASK_STATUS_TOOL, REACT_TOOL]);
693
+ function acknowledgeWorkOnce(context) {
694
+ const { runState, responder } = context;
695
+ if (runState.workAcknowledged || !responder.react)
696
+ return;
697
+ runState.workAcknowledged = true;
698
+ responder.react(WORK_ACKNOWLEDGEMENT_REACTION).catch((error) => {
699
+ log.logWarning("Could not acknowledge work with a reaction", errorMessage(error));
700
+ });
701
+ }
702
+ function presentToolStarted(event, context) {
703
+ const { runState, responder, queue } = context;
704
+ if (!TOOLS_THAT_ARE_NOT_WORK.has(event.toolName))
705
+ acknowledgeWorkOnce(context);
706
+ if (event.toolName === START_TASK_TOOL || event.toolName === TASK_STATUS_TOOL)
707
+ return;
708
+ runState.answerStreamStarted = false;
709
+ runState.toolProgress.set(event.toolCallId, { label: event.label, status: "running" });
710
+ if (event.toolName === "subagent") {
711
+ runState.subagentToolCalls.add(event.toolCallId);
712
+ return;
713
+ }
714
+ queue.enqueue(() => replaceResponseWithToolProgress(responder, runState), "tool progress update");
715
+ }
716
+ function presentSubagentProgress(event, context) {
717
+ context.runState.subagentProgress.set(event.toolCallId, event.snapshot);
718
+ context.runState.subagentToolCalls.add(event.toolCallId);
719
+ context.runState.suppressResponseDeltas = true;
720
+ scheduleToolProgressUpdate(context.responder, context.runState);
721
+ }
722
+ function presentToolEnded(event, context) {
723
+ const { runState, responder } = context;
724
+ if (event.toolName === START_TASK_TOOL)
725
+ return;
726
+ const progress = runState.toolProgress.get(event.toolCallId);
727
+ if (progress)
728
+ progress.status = event.isError ? "error" : "done";
729
+ const subagentProgress = runState.subagentProgress.get(event.toolCallId);
730
+ if (subagentProgress) {
731
+ runState.subagentProgress.set(event.toolCallId, settleSubagentProgress(subagentProgress, event.isError));
732
+ }
733
+ if (event.toolName !== TASK_STATUS_TOOL)
734
+ flushToolProgressUpdate(responder, runState);
735
+ const completedProgress = runState.subagentProgress.get(event.toolCallId);
736
+ if (completedProgress)
737
+ runState.completedSubagentProgress.push(completedProgress);
738
+ runState.subagentProgress.delete(event.toolCallId);
739
+ }
740
+ function presentAssistantDelta(event, context) {
741
+ const { runState } = context;
742
+ if (!context.responder.appendResponseDelta || runState.suppressResponseDeltas)
743
+ return;
744
+ const delta = runState.answerStreamStarted
745
+ ? event.delta
746
+ : formatResponseWithToolProgress(event.delta, runState);
747
+ runState.answerStreamStarted = true;
748
+ context.queue.enqueue(async () => {
749
+ await context.responder.appendResponseDelta?.(delta);
750
+ }, "response delta");
751
+ }
752
+ function presentThinking(thinking, context) {
753
+ log.logThinking(context.logCtx, thinking);
754
+ context.queue.enqueue(() => context.responder.respond(`_${thinking}_`), "thinking main");
755
+ context.queue.enqueue(() => context.responder.respondDiagnostic(`_${thinking}_`), "thinking diagnostic");
756
+ }
757
+ function presentFinalText(text, context) {
758
+ const finalText = appendTriggerAttribution(formatResponseWithToolProgress(text, context.runState), context.runState.triggerAttribution);
759
+ log.logResponse(context.logCtx, text);
760
+ if (context.runState.completedSubagentProgress.length > 0)
761
+ return;
762
+ if (context.responder.finishResponse) {
763
+ context.queue.enqueue(async () => {
764
+ await context.responder.finishResponse?.(finalText);
765
+ }, "response finish");
766
+ }
767
+ else {
768
+ context.queue.enqueue(() => context.responder.respond(finalText), "response main");
769
+ }
770
+ }
771
+ function presentAssistantMessage(event, context) {
772
+ for (const thinking of event.thinking)
773
+ presentThinking(thinking, context);
774
+ if (!event.text.trim() || event.callsTools || context.runState.finalResponseHandledByTool)
775
+ return;
776
+ presentFinalText(event.text, context);
777
+ }
778
+ function presentRunEvent(event, context) {
779
+ switch (event.type) {
780
+ case "tool_started":
781
+ presentToolStarted(event, context);
782
+ return;
783
+ case "subagent_progress":
784
+ presentSubagentProgress(event, context);
785
+ return;
786
+ case "tool_ended":
787
+ presentToolEnded(event, context);
788
+ return;
789
+ case "assistant_delta":
790
+ presentAssistantDelta(event, context);
791
+ return;
792
+ case "assistant_message":
793
+ presentAssistantMessage(event, context);
794
+ return;
795
+ case "compaction_started":
796
+ context.queue.enqueue(() => context.responder.respond("_Compacting context..._"), "compaction start");
797
+ return;
798
+ case "retry_started": {
799
+ const text = `_Retrying (${event.attempt}/${event.maxAttempts})..._`;
800
+ context.queue.enqueue(() => context.responder.respond(text), "retry");
801
+ return;
802
+ }
803
+ case "budget_exceeded": {
804
+ const text = `_Stopped: run budget exceeded (${event.reason})_`;
805
+ context.queue.enqueue(() => context.responder.respondDiagnostic(text, { style: "error" }), "budget exceeded");
806
+ return;
807
+ }
808
+ case "run_started":
809
+ case "run_ended":
810
+ return;
811
+ }
812
+ }
804
813
  export function attachSessionEventHandlers(params) {
805
814
  const { session, runState, model, agentConfig, platformToolRoles } = params;
806
815
  session.subscribe((event) => {
807
816
  if (!runState.responder || !runState.logCtx || !runState.queue)
808
817
  return;
809
- handlePresenterEvent(event, {
818
+ observeHarnessEvent(event, {
810
819
  runState,
811
- responder: runState.responder,
812
820
  logCtx: runState.logCtx,
813
- queue: runState.queue,
814
821
  baseAttrs: {
815
822
  channel_id: runState.logCtx.conversationId,
816
823
  session_id: runState.logCtx.sessionId,
@@ -819,6 +826,16 @@ export function attachSessionEventHandlers(params) {
819
826
  agentConfig,
820
827
  platformToolRoles,
821
828
  });
829
+ const runEvent = toRunEvent(event);
830
+ if (!runEvent)
831
+ return;
832
+ runState.publishRunEvent?.(runEvent);
833
+ presentRunEvent(runEvent, {
834
+ runState,
835
+ responder: runState.responder,
836
+ logCtx: runState.logCtx,
837
+ queue: runState.queue,
838
+ });
822
839
  });
823
840
  }
824
841
  //# sourceMappingURL=presenter.js.map