Skip to content
This repository was archived by the owner on Aug 25, 2026. It is now read-only.

feat: TaskOutput non-blocking + persist turn.ended + interruption reminder (upstream ports) - #10

Merged
YaseenHQ merged 4 commits into
mainfrom
upstream-port/loop-turn-surface
Aug 8, 2026
Merged

YaseenHQ merged 4 commits into
mainfrom
upstream-port/loop-turn-surface

Conversation

@YaseenHQ

@YaseenHQ YaseenHQ commented Aug 3, 2026 •

Copy link
Copy Markdown
Owner

Related Issue

Upstream port batch 3 of 6. Three interlocked loop/turn-surface improvements from MoonshotAI/kimi-code, applied in strict dependency order.

What changed

  1. Remove TaskOutput blocking wait (691ec4679, fix: remove the blocking wait from the TaskOutput tool MoonshotAI/kimi-code#2379): the TaskOutput tool could block a whole turn for up to 3600s waiting on a background task. Removes the block/timeout params (kept in model-facing parity), simplifies retrieval_status to success/not_ready. Both engines + docs.
  2. Persist terminal turn.ended wire record (4c4df1bb0, feat(agent-core-v2): persist the terminal turn.ended wire record MoonshotAI/kimi-code#2457): ensures the final turn.ended fact (reason/error/durationMs) is always persisted, even on abort/error, so downstream history rebuilds recover how a turn ended.
  3. Interruption reminder for user-cancelled turns (1f3f5dada, feat(agent-core-v2): interruption reminder for user-cancelled turns MoonshotAI/kimi-code#2400): on Esc-interrupt, appends a durable <system-reminder> so the model does not replay a deliberately-cancelled action. Adds a new interruptionReminder domain.

Conflicts resolved

  • loopService.ts: took upstream side (adds partial-token accumulation for interruption persistence), re-added the fork's openai_compaction case that upstream's switch didn't include.
  • turnOps.ts (x2): pure header-comment merges.
  • state-manifest.d.ts: regenerated via gen:state-manifest.
  • loop.test.ts + tool.test.ts: updated snapshots (turn.ended now carries reason/durationMs; tool-description hashes are fork-specific).

Verification

  • Typecheck clean: agent-core, agent-core-v2
  • Tests pass: agent-core 4009, agent-core-v2 4222

Checklist

  • Tests pass on both engines.

Summary by CodeRabbit

  • New Features

    • Interrupted turns now preserve partial assistant output and display a reminder when canceled with Esc.
    • Conversation history records turn completion status, duration, errors, and interruption details.
    • Resuming a session restores pending interruption reminders without duplicating messages.
    • Background task completion continues through automatic notifications.
  • Bug Fixes

    • TaskOutput now always returns an immediate task snapshot and no longer waits or times out.
    • User cancellations are distinguished from programmatic interruptions for clearer transcript timelines.
  • Documentation

    • Updated TaskOutput and background-task guidance in English and Chinese.

RealKai42 and others added 3 commits August 3, 2026 05:42
* fix: remove the blocking wait from the TaskOutput tool

The block/timeout parameters let a model stall the whole turn waiting
for a background task (up to 3600s), even though completion already
arrives via automatic notification. Remove both parameters from the v1
and v2 engines (kept in model-facing parity), simplify retrieval_status
to success/not_ready, and update the tool, Bash, and Agent prompt
wording plus user docs accordingly. Stale callers passing block are
silently treated as a non-blocking snapshot.

* fix: align background-task prompts with the non-blocking TaskOutput

The compaction reminder promised TaskOutput could fetch a task's result
for tasks that are still running, where it now returns not_ready —
reword it to snapshot semantics and point at the completion
notification. Also list AskUserQuestion(background=true) as a task
source in the TaskOutput description.

* test: exercise stale TaskOutput args through the runtime validator

A stale block/timeout argument never reaches the tool: the executor's
preflight validates args against the closed tool schema and rejects
them immediately, so the old test documented silent-tolerance semantics
the runtime never exhibits. Assert the real behavior through
compileToolArgsValidator/validateToolArgs instead, and drop
statement-adjacent comments to match the package's header-only comment
convention.
…nshotAI#2457)

* feat(agent-core-v2): persist the terminal turn.ended wire record

- add a persisted turn.ended op (turnId, reason, error, durationMs)
  dispatched from the loop's runTurn finally block, alongside the event
- fold the record back in the transcript cold rebuild: terminal state
  (blocked folded into failed, mirroring the live wire edge), durationMs,
  error message and endedAt; journals without the record keep the
  grouping default
- restrict the test harness's snapshot waiters to emit entries so the
  same-named wire record no longer shadows the turn.ended event

* chore(agent-core-v2): stabilize unique-symbol keys in the state manifest

The checker names a unique symbol key __@name@NNNN, where NNNN is a
compilation-global counter that shifts with unrelated type additions and
churns the generated manifest. Render the stable __@name form instead.

* fix(transcript): map turn.ended around hidden turns in the cold fold

RetryStepRequest opens a real engine turn with origin 'retry' but
contributes no context messages, and a queued-then-cancelled
reservation consumes an engine id without starting. Both make engine
turn ids drift from the grouping ordinals, so matching turn.ended by
ordinal could stamp a later visible turn with the wrong terminal state.
Replay the loop's turn-clock records (turn.prompt / turn.cancel) and
map engine ids to ordinals past the hidden ids; the hidden turns' own
end records map nowhere and are dropped.
…oonshotAI#2400)

* feat(agent-core-v2): interruption reminder for user-cancelled turns

When the user interrupts a turn with Esc, append a durable
<system-reminder> (origin: injection/interruption) to the agent context
via a new loop aspect watching turn.ended, so the model learns the
previous turn was deliberately cut off. The marker persists to the
wire, replays on resume, stays hidden from transcripts, skips non-user
aborts and steer, and does not stack on repeated cancels.

Two supporting fixes:

- An aborted LLM stream now persists its accumulated partial
  text/thinking as content.part loop events instead of dropping every
  produced token; gated on the turn signal so retried or
  step-cancelled attempts keep their partial output out of the record.
- The turn.cancel wire op carries an optional reason
  ('user_cancelled' | 'aborted') so cold readers can tell deliberate
  interrupts from programmatic aborts. Goal-lifecycle cancels now pass
  an explicit programmatic reason to keep that field honest.

* feat(transcript): mark user-cancelled turns with an interruption marker

Project the deliberate user interrupt onto the transcript timeline: the
live projector emits an 'interruption' marker when a turn ends with
interruptReason 'user_cancelled', and the cold fold consumes the
persisted turn.cancel reason into the same marker. Programmatic aborts
keep surfacing through their own outlets (errors, goal/task state), and
queued cancels that left no visible residue are skipped.

* fix(agent-core-v2): make user-turn cancellation idempotent and reconcile interruption reminders on restore

* fix(transcript): dedupe user-cancelled interruption markers by turn in the cold fold

* chore(agent-core-v2): regenerate state manifest after merging main

* refactor(agent-core-v2): split interruptionReminder out of the loop domain

The loop domain owns turn execution mechanics; whether an interrupted turn
should produce a model-visible reminder is a model-context policy. Move it
into its own L4 domain with its own wire model that cross-reduces the
loop's turn.cancel fact, and rename the op to interruptionReminder.recorded.

---------

Signed-off-by: Haozhe <yanghaozhe@moonshot.ai>
Co-authored-by: Haozhe <yanghaozhe@moonshot.ai>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds interruption-aware turn persistence, partial-output recovery, interruption reminders, and transcript folding. It also changes TaskOutput to always return immediate snapshots and removes blocking parameters, waiting behavior, and related guidance.

Changes

Interruption lifecycle

Layer / File(s) Summary
Turn and wire contracts
packages/agent-core-v2/src/agent/loop/*, packages/agent-core-v2/src/agent/interruptionReminder/*, packages/agent-core-v2/docs/wire-manifest.d.ts
Turn cancellation and completion records now include reasons, errors, and duration. Interruption reminder operations and service contracts are registered.
Cancellation and partial-output recovery
packages/agent-core-v2/src/agent/loop/loopService.ts, packages/agent-core-v2/src/agent/goal/goalService.ts
The loop preserves streamed content when cancellation interrupts a turn and emits normalized interruption metadata. Goal cancellation supplies explicit abort errors.
Interruption reminder service
packages/agent-core-v2/src/agent/interruptionReminder/*, packages/agent-core-v2/src/index.ts
The Agent-scoped service restores pending reminders, avoids duplicate injections, skips empty partial assistant messages, and persists recorded reminders.
Turn records and transcript projection
packages/transcript/src/history/*, packages/kap-server/src/*, packages/klient/src/contract/agent/events.ts
User cancellations produce interruption markers. Persisted turn-end records update visible transcript turns with terminal state, time, duration, and errors.
Interruption integration coverage
packages/agent-core-v2/test/*, packages/kap-server/test/*, packages/klient/test/*, packages/transcript/test/*
Tests cover cancellation classification, restoration, wire records, event filtering, interruption markers, and hidden-turn mapping.
Generated manifest stability
packages/agent-core-v2/scripts/gen-state-manifest.mts, packages/agent-core-v2/docs/state-manifest.d.ts
Unique-symbol manifest keys now use stable names.

Non-blocking TaskOutput

Layer / File(s) Summary
Non-blocking TaskOutput contract
packages/agent-core-v2/src/agent/tools/task/task-output/*, packages/agent-core/src/tools/background/task-output.*, docs/*, packages/agent-core*/src/**
TaskOutput now accepts only task_id, returns an immediate snapshot, and reports success or not_ready. Blocking guidance and timeout handling were removed.
TaskOutput caller and test updates
packages/agent-core-v2/test/agent/task/*, packages/agent-core-v2/test/os/*, packages/agent-core/test/tools/*, packages/agent-core/test/harness/*
Callers omit block and timeout. Tests validate stale-argument rejection and non-blocking behavior.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AgentLoop
  participant WirePersistence
  participant Transcript
  User->>AgentLoop: cancel active turn with Esc
  AgentLoop->>WirePersistence: persist turn.cancel and turn.ended
  AgentLoop->>WirePersistence: persist preserved partial assistant output
  WirePersistence->>Transcript: fold terminal turn facts
  Transcript-->>User: expose interruption marker and completed turn state
Loading

Suggested reviewers: sailist, kermanx, 7sageer

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the three primary changes: non-blocking TaskOutput, persisted turn.ended records, and interruption reminders.
Description check ✅ Passed The description clearly explains the changes, related issue numbers, conflict resolutions, and verification results, although most checklist items are omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upstream-port/loop-turn-surface

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@YaseenHQ
YaseenHQ merged commit 8bc24fe into main Aug 8, 2026
14 of 15 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/task-output-nonblocking.md:
- Around line 1-5: Change the changeset bump for "`@moonshot-ai/kimi-code`" from
patch to minor in task-output-nonblocking.md, reflecting the removed public
TaskOutput inputs while leaving the release note unchanged.

In `@packages/agent-core-v2/src/agent/loop/loopService.ts`:
- Around line 1127-1129: Remove the statement-level comment inside the
openai_compaction case of createStreamPartHandler, leaving the existing return
behavior unchanged; do not add a replacement inline comment.

In `@packages/agent-core-v2/src/agent/loop/turnOps.ts`:
- Around line 81-89: Update the error field in endTurn’s turn.ended schema to
perform runtime validation instead of relying solely on
z.custom<KimiErrorPayload>(). Add or reuse an ErrorPayload Zod predicate that
validates the serialized KimiErrorPayload shape, while keeping the field
optional and preserving the existing turn.ended schema behavior.

In `@packages/agent-core-v2/test/snapshot/events.ts`:
- Around line 58-64: Update the matching logic for onceWaiters and
onceAnyWaiters to require entry.type === '[rpc]' before comparing event names,
consistent with until and take. Preserve existing event-name matching and
resolution behavior for valid [rpc] entries.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c392554f-05b5-4c67-abc9-1c6eb409a567

📥 Commits

Reviewing files that changed from the base of the PR and between ab30fa6 and 99e9f39.

📒 Files selected for processing (51)
  • .changeset/interrupt-reminder.md
  • .changeset/task-output-nonblocking.md
  • docs/en/reference/tools.md
  • docs/zh/reference/tools.md
  • packages/agent-core-v2/docs/state-manifest.d.ts
  • packages/agent-core-v2/docs/wire-manifest.d.ts
  • packages/agent-core-v2/scripts/gen-state-manifest.mts
  • packages/agent-core-v2/src/agent/goal/goalService.ts
  • packages/agent-core-v2/src/agent/interruptionReminder/interruptionReminder.ts
  • packages/agent-core-v2/src/agent/interruptionReminder/interruptionReminderOps.ts
  • packages/agent-core-v2/src/agent/interruptionReminder/interruptionReminderService.ts
  • packages/agent-core-v2/src/agent/loop/loopService.ts
  • packages/agent-core-v2/src/agent/loop/turnEvents.ts
  • packages/agent-core-v2/src/agent/loop/turnOps.ts
  • packages/agent-core-v2/src/agent/task/taskService.ts
  • packages/agent-core-v2/src/agent/tools/agent/agent-background-enabled.md
  • packages/agent-core-v2/src/agent/tools/os/bash/bash.md
  • packages/agent-core-v2/src/agent/tools/os/bash/bashTool.ts
  • packages/agent-core-v2/src/agent/tools/task/task-output/task-output.md
  • packages/agent-core-v2/src/agent/tools/task/task-output/task-output.ts
  • packages/agent-core-v2/src/agent/tools/task/task-output/taskOutputTool.ts
  • packages/agent-core-v2/src/index.ts
  • packages/agent-core-v2/test/agent/fullCompaction/fullCompaction.test.ts
  • packages/agent-core-v2/test/agent/goal/goal.test.ts
  • packages/agent-core-v2/test/agent/loop/loop.test.ts
  • packages/agent-core-v2/test/agent/plan/plan.test.ts
  • packages/agent-core-v2/test/agent/task/taskService.test.ts
  • packages/agent-core-v2/test/agent/task/tools/task-tools.test.ts
  • packages/agent-core-v2/test/app/config/config.test.ts
  • packages/agent-core-v2/test/harness/agent.ts
  • packages/agent-core-v2/test/index.test.ts
  • packages/agent-core-v2/test/os/backends/node-local/tools/bash.test.ts
  • packages/agent-core-v2/test/snapshot/events.ts
  • packages/agent-core-v2/test/tool/tool.test.ts
  • packages/agent-core-v2/test/wire/resume.test.ts
  • packages/agent-core/src/agent/injection/manager.ts
  • packages/agent-core/src/tools/background/task-output.md
  • packages/agent-core/src/tools/background/task-output.ts
  • packages/agent-core/src/tools/builtin/collaboration/agent-background-enabled.md
  • packages/agent-core/src/tools/builtin/shell/bash.md
  • packages/agent-core/src/tools/builtin/shell/bash.ts
  • packages/agent-core/test/harness/coder-subagent-tools.test.ts
  • packages/agent-core/test/tools/background/task-tools.test.ts
  • packages/kap-server/src/protocol/events-zod.ts
  • packages/kap-server/src/services/transcript/coreEventMap.ts
  • packages/kap-server/test/services/transcript.test.ts
  • packages/klient/src/contract/agent/events.ts
  • packages/klient/test/e2e/invalid-input-matrix.test.ts
  • packages/transcript/src/history/foldFacts.ts
  • packages/transcript/src/history/groupTurns.ts
  • packages/transcript/test/layers.test.ts
💤 Files with no reviewable changes (1)
  • packages/agent-core-v2/src/agent/tools/task/task-output/task-output.ts

Comment on lines +1 to +5
---
"@moonshot-ai/kimi-code": patch
---

Remove the blocking `block`/`timeout` wait from the TaskOutput tool so checking a background task can no longer stall the conversation; it now always returns an immediate snapshot, and completion still arrives via automatic notification.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use a minor changeset for the removed TaskOutput inputs.

Removing block and timeout changes the public tool input contract. A patch release can break callers that still send either field. Change the bump to minor.

As per coding guidelines, .changeset/*.{md,yml,yaml} requires minor when major is not explicitly confirmed and minor is clear.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/task-output-nonblocking.md around lines 1 - 5, Change the
changeset bump for "`@moonshot-ai/kimi-code`" from patch to minor in
task-output-nonblocking.md, reflecting the removed public TaskOutput inputs
while leaving the release note unchanged.

Source: Coding guidelines

Comment on lines +1127 to +1129
case 'openai_compaction': {
// Opaque compaction replay items are not streamed to the UI.
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the statement-level comment.

Line 1128 adds a comment inside createStreamPartHandler. Keep this explanation out of the implementation body.

As per coding guidelines, packages/agent-core-v2/src/**/*.ts must use only a top-of-file /** */ comment block and must not place comments beside functions, methods, or statements.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core-v2/src/agent/loop/loopService.ts` around lines 1127 -
1129, Remove the statement-level comment inside the openai_compaction case of
createStreamPartHandler, leaving the existing return behavior unchanged; do not
add a replacement inline comment.

Source: Coding guidelines

Comment on lines +81 to +89
export const endTurn = TurnModel.defineOp('turn.ended', {
schema: z.object({
turnId: z.number(),
reason: z.enum(['completed', 'cancelled', 'failed', 'blocked']),
error: z.custom<KimiErrorPayload>().optional(),
durationMs: z.number().optional(),
}),
apply: (s) => s,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 'interface ErrorPayload|type ErrorPayload|KimiErrorPayload|z\.custom' packages/agent-core-v2/src

Repository: YaseenHQ/kimi

Length of output: 26321


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== turnOps outline =="
ast-grep outline packages/agent-core-v2/src/agent/loop/turnOps.ts --match endTurn --view expanded || true
echo

echo "== turnOps relevant lines =="
sed -n '1,130p' packages/agent-core-v2/src/agent/loop/turnOps.ts | cat -n

echo
echo "== wire model schema definitions =="
rg -n -C 3 'defineOp|toEvent|fromEvent|payload|schema' packages/agent-core-v2/src/wire packages/agent-core-v2/src/agent/loop/turnOps.ts packages/agent-core-v2/src/agent/loop/loopService.ts | sed -n '1,220p'

echo
echo "== ErrorPayload implementation =="
sed -n '1,120p' packages/agent-core-v2/src/_base/errors/serialize.ts | cat -n

echo
echo "== Zod custom predicate usages =="
rg -n -C 2 'z\.custom\([^)]*(\{\s*[^}]+\}\s*|=>|predicate|check)' packages/agent-core-v2/src/_base/types packages/agent-core-v2/src || true

Repository: YaseenHQ/kimi

Length of output: 25734


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
try:
    from pathlib import Path
    import tomllib
    data = tomllib.loads(Path('package.json').read_text())
    print("root zod:", data.get('dependencies', {}).get('zod') or data.get('devDependencies', {}).get('zod'))
except Exception as e:
    print("root package.json zod not found:", type(e).__name__, str(e))

for path in ['packages/agent-core-v2/package.json']:
    try:
        data = tomllib.loads(Path(path).read_text())
    except Exception as e:
        print(f"{path}: {type(e).__name__} {str(e)}")
        continue
    print(f"{path} zod:", data.get('dependencies', {}).get('zod') or data.get('devDependencies', {}).get('zod'))

try:
    import zod, inspect
    print("installed zod:", getattr(zod, '__version__', 'unknown'))
    print("z.custom source signature:")
    print(inspect.getsource(zod.ZodType.custom))
except Exception as e:
    print("zod runtime probe unavailable:", type(e).__name__, str(e))
PY

echo
sed -n '1,180p' packages/agent-core-v2/src/wire/wireService.ts | cat -n

Repository: YaseenHQ/kimi

Length of output: 7737


Add a runtime predicate to the error serializer.

z.custom<KimiErrorPayload>() only narrows TypeScript type inference. The turn.ended wire replay path accepts this schema at the record boundary, so a malformed persisted error payload can bypass validation and flow into transcript restoration. Add an ErrorPayload Zod validation predicate, or otherwise check the serialized payload shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core-v2/src/agent/loop/turnOps.ts` around lines 81 - 89,
Update the error field in endTurn’s turn.ended schema to perform runtime
validation instead of relying solely on z.custom<KimiErrorPayload>(). Add or
reuse an ErrorPayload Zod predicate that validates the serialized
KimiErrorPayload shape, while keeping the field optional and preserving the
existing turn.ended schema behavior.

Comment on lines +58 to +64
// Snapshot-returning waiters match EMIT entries only: a persisted wire
// record can share its type with an event (e.g. `turn.ended`), and the
// waiter's intent is the event — resolving on the wire entry would also
// truncate the matching emit entry out of the returned snapshot.
for (let index = eventWaiters.length - 1; index >= 0; index -= 1) {
const waiter = eventWaiters[index]!;
if (waiter.event !== entry.event) continue;
if (entry.type !== '[rpc]' || waiter.event !== entry.event) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 '\.(once|onceAny)\s*\(' packages/agent-core-v2/test

Repository: YaseenHQ/kimi

Length of output: 39723


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== snapshots.ts outline =="
ast-grep outline packages/agent-core-v2/test/snapshot/events.ts --view expanded || true

echo "== relevant snapshot code =="
cat -n packages/agent-core-v2/test/snapshot/events.ts | sed -n '1,120p'

echo "== harness relevant lines =="
cat -n packages/agent-core-v2/test/harness/agent.ts | sed -n '1560,1595p'

echo "== tests using onceAny with compaction =="
cat -n packages/agent-core-v2/test/agent/fullCompaction/fullCompaction.test.ts | sed -n '520,568p'
cat -n packages/agent-core-v2/test/agent/fullCompaction/fullCompaction.test.ts | sed -n '680,702p'

Repository: YaseenHQ/kimi

Length of output: 9819


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== snapshot files =="
fd -a 'snapshots\.(ts|tsx)$|event\.test\.ts$' packages/agent-core-v2/test | sed 's#^\./##'

echo "== event emitter implementation references =="
rg -n "class Event|interface Event|type Event|createEventSnapshotter|export function createEventSnapshotter|createSnapshot|recordedEntries|Emit|records|WireRecord|type:" packages/agent-core-v2/test packages/agent-core-v2/src -g '*.{ts,tsx}' | head -200

echo "== snapshot implementation around createEventSnapshotter =="
fd -a 'snapshots\.(ts|tsx)$' packages/agent-core-v2/test | xargs -r -I{} sh -c 'echo "--- {}"; cat -n "{}" | sed -n "1,240p"'

Repository: YaseenHQ/kimi

Length of output: 32435


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== snapshot events remainder =="
cat -n packages/agent-core-v2/test/snapshot/events.ts | sed -n '120,220p'

echo "== inspect existing one-time tests for same-name wire entries =="
rg -n -C 8 "once\\(|onceAny\\(" packages/agent-core-v2/test/agent packages/agent-core-v2/test/snapshot | head -220

echo "== deterministic semantics probe for current dispatch/order =="
python3 - <<'PY'
entries = []
once_waiters = []
once_any_waiters = []
while True:
    pass
PY

echo "== git diff stat/name =="
git diff --stat
git diff -- packages/agent-core-v2/test/snapshot/events.ts | sed -n '1,220p'

Repository: YaseenHQ/kimi

Length of output: 143


Align once/onceAny with the [rpc] event filter.

until and take only resolve on [rpc] entries. once and onceAny still match any persisted wire entry with the same event name. If these helpers wait for emitted notifications, filter onceWaiters/onceAnyWaiters for [rpc] entries too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-core-v2/test/snapshot/events.ts` around lines 58 - 64, Update
the matching logic for onceWaiters and onceAnyWaiters to require entry.type ===
'[rpc]' before comparing event names, consistent with until and take. Preserve
existing event-name matching and resolution behavior for valid [rpc] entries.

@github-actions github-actions Bot mentioned this pull request Aug 11, 2026
@YaseenHQ
YaseenHQ deleted the upstream-port/loop-turn-surface branch August 24, 2026 23:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants