@oh-my-pi/pi-agent-core 18.2.8 → 18.2.10

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.2.9] - 2026-09-22
6
+
7
+ ### Fixed
8
+
9
+ - Fixed stream finalization when a provider ends without emitting a completion or error event, ensuring the final assistant message is preserved and corresponding message lifecycle events are emitted.
10
+ - Fixed tool execution being incorrectly skipped when host steering callbacks reject during a tool batch.
11
+ - Fixed stream hangs and preserved the original error when host aside-commit or discard callbacks fail.
12
+
5
13
  ## [18.2.5] - 2026-09-17
6
14
 
7
15
  ### Fixed
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-agent-core",
4
- "version": "18.2.8",
4
+ "version": "18.2.10",
5
5
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Stencil Labs, Inc.",
@@ -35,16 +35,16 @@
35
35
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
36
36
  },
37
37
  "dependencies": {
38
- "@oh-my-pi/pi-ai": "18.2.8",
39
- "@oh-my-pi/pi-catalog": "18.2.8",
40
- "@oh-my-pi/pi-natives": "18.2.8",
41
- "@oh-my-pi/pi-utils": "18.2.8",
42
- "@oh-my-pi/pi-wire": "18.2.8",
43
- "@oh-my-pi/snapcompact": "18.2.8",
38
+ "@oh-my-pi/pi-ai": "18.2.10",
39
+ "@oh-my-pi/pi-catalog": "18.2.10",
40
+ "@oh-my-pi/pi-natives": "18.2.10",
41
+ "@oh-my-pi/pi-utils": "18.2.10",
42
+ "@oh-my-pi/pi-wire": "18.2.10",
43
+ "@oh-my-pi/snapcompact": "18.2.10",
44
44
  "@opentelemetry/api": "^1.9.1"
45
45
  },
46
46
  "devDependencies": {
47
- "@oh-my-pi/omptype": "18.2.8",
47
+ "@oh-my-pi/omptype": "18.2.10",
48
48
  "@opentelemetry/context-async-hooks": "^2.9.0",
49
49
  "@opentelemetry/sdk-trace-base": "^2.9.0",
50
50
  "@types/bun": "^1.3.14"
package/src/agent-loop.ts CHANGED
@@ -599,18 +599,18 @@ export function agentLoop(
599
599
  const stream = createAgentStream();
600
600
 
601
601
  (async () => {
602
- const newMessages: AgentMessage[] = [...prompts];
603
- const currentContext: AgentContext = {
604
- ...context,
605
- messages: [...context.messages, ...prompts],
606
- };
607
- for (const prompt of prompts) {
608
- (prompt as CommittableAsideMessage)[ASIDE_MESSAGE_COMMIT]?.();
609
- }
602
+ try {
603
+ const newMessages: AgentMessage[] = [...prompts];
604
+ const currentContext: AgentContext = {
605
+ ...context,
606
+ messages: [...context.messages, ...prompts],
607
+ };
608
+ for (const prompt of prompts) {
609
+ (prompt as CommittableAsideMessage)[ASIDE_MESSAGE_COMMIT]?.();
610
+ }
610
611
 
611
- stream.push({ type: "agent_start" });
612
+ stream.push({ type: "agent_start" });
612
613
 
613
- try {
614
614
  await runLoop(currentContext, newMessages, config, signal, stream, streamFn, prompts);
615
615
  } catch (err) {
616
616
  stream.fail(err);
@@ -668,12 +668,12 @@ export function agentLoopContinue(
668
668
  const stream = createAgentStream();
669
669
 
670
670
  (async () => {
671
- const newMessages: AgentMessage[] = [];
672
- const currentContext: AgentContext = { ...context, messages: [...context.messages] };
671
+ try {
672
+ const newMessages: AgentMessage[] = [];
673
+ const currentContext: AgentContext = { ...context, messages: [...context.messages] };
673
674
 
674
- stream.push({ type: "agent_start" });
675
+ stream.push({ type: "agent_start" });
675
676
 
676
- try {
677
677
  await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
678
678
  } catch (err) {
679
679
  stream.fail(err);
@@ -1112,7 +1112,11 @@ function resolveAsides(entries: AsideMessage[] | undefined): AgentMessage[] {
1112
1112
 
1113
1113
  function discardAsides(messages: readonly AgentMessage[], error: Error): void {
1114
1114
  for (const message of messages) {
1115
- (message as CommittableAsideMessage)[ASIDE_MESSAGE_DISCARD]?.(error);
1115
+ try {
1116
+ (message as CommittableAsideMessage)[ASIDE_MESSAGE_DISCARD]?.(error);
1117
+ } catch (discardError) {
1118
+ logger.error("Aside discard hook threw", { error: discardError });
1119
+ }
1116
1120
  }
1117
1121
  }
1118
1122
 
@@ -2331,8 +2335,11 @@ async function streamAssistantResponse(
2331
2335
  }
2332
2336
  if (addedPartial) {
2333
2337
  context.messages[context.messages.length - 1] = trailing;
2334
- stream.push({ type: "message_end", message: snapshotAssistantMessage(trailing) });
2338
+ } else {
2339
+ context.messages.push(trailing);
2340
+ stream.push({ type: "message_start", message: snapshotAssistantMessage(trailing) });
2335
2341
  }
2342
+ stream.push({ type: "message_end", message: snapshotAssistantMessage(trailing) });
2336
2343
  await finishChat(trailing);
2337
2344
  speculationSettled = true;
2338
2345
  providerStreamSettled = true;
@@ -3274,7 +3281,13 @@ async function executeToolCalls(
3274
3281
  toolName: toolCall.name,
3275
3282
  });
3276
3283
 
3277
- await checkSteering();
3284
+ // Best-effort steering probe: its own failure is surfaced by the
3285
+ // dedicated watch path (which guards the identical call), so a rejecting
3286
+ // host `hasSteeringMessages`/`hasIrcInterrupts` callback must not reject
3287
+ // this task. An unguarded rejection here fires after the tool already
3288
+ // ran and poisons the `start.then(runTool)` ordering chain, skipping
3289
+ // every later chained record with a phantom "pending steering" result.
3290
+ await checkSteering().catch(() => undefined);
3278
3291
  };
3279
3292
 
3280
3293
  let lastExclusive: Promise<void> = Promise.resolve();