Merge branch 'codex/simp-ui-identity-residue' into codex/simp-hide-concrete-agent-loop

# Conflicts:
#	docs/event-producer-consumer.md
#	examples/coding-agent/tests/code-mode.e2e.ts
#	examples/coding-agent/tests/harness.ts
#	examples/coding-agent/tests/resume.e2e.ts
#	examples/cordis-agent/tests/harness.ts
#	packages/bash/tool-bash/tests/integration.spec.ts
#	packages/compact/compact-basic/tests/compact-loop-repro.spec.ts
#	packages/cordis/tool-cordis/tests/integration.spec.ts
#	packages/core/agent-loop/tests/contract-regressions.spec.ts
#	packages/guard/repeat-tool-guard/tests/repeat-tool-guard.spec.ts
#	packages/hooks/hooks-claude/tests/bridge.spec.ts
#	packages/hooks/hooks-claude/tests/coverage.spec.ts
#	packages/hooks/hooks-codex/tests/bridge.spec.ts
#	packages/hooks/hooks-codex/tests/coverage.spec.ts
#	packages/todo/tool-todo/tests/integration.spec.ts
This commit is contained in:
Tianyi Cui
2026-07-18 12:33:49 +08:00
657 changed files with 36714 additions and 7631 deletions
@@ -96,7 +96,7 @@ describe('agent loop scheduling properties', () => {
async (texts) => {
const ctx = await harness()
try {
const agent = ctx.agentLoop.create(SessionId('a'), { model: 'mock' })
const agent = ctx.agentLoop.create(SessionId('a'), { provider: 'mock', model: 'mock' })
const { seen: trace } = recordStatus(ctx, agent)
const idle = nextIdle(ctx, agent)
// Send all in one synchronous tick: they queue before the loop wakes.
@@ -121,7 +121,7 @@ describe('agent loop scheduling properties', () => {
async (texts) => {
const ctx = await harness()
try {
const agent = ctx.agentLoop.create(SessionId('a'), { model: 'mock' })
const agent = ctx.agentLoop.create(SessionId('a'), { provider: 'mock', model: 'mock' })
for (const text of texts) {
const idle = nextIdle(ctx, agent)
agent.send([{ type: 'text', text }])
@@ -146,11 +146,9 @@ describe('agent loop scheduling properties', () => {
async (steps) => {
const ctx = await harness()
try {
const agent = ctx.agentLoop.create(SessionId('a'), { model: 'mock' })
// Capture an idle waiter before EACH send; the last one is guaranteed
// to resolve because the final send always triggers (or joins) a turn
// that ends idle. Awaiting an already-resolved waiter is a no-op, so a
// trailing settle step can't cause a hang.
const agent = ctx.agentLoop.create(SessionId('a'), { provider: 'mock', model: 'mock' })
// Capture before each send; the last waiter covers the final turn, and
// awaiting an already-settled earlier waiter is harmless.
let lastIdle: Promise<void> | undefined
for (const step of steps) {
const idle = nextIdle(ctx, agent)