Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters

# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl
#	examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/skill-load/session.jsonl
#	examples/acp-agent/tests/snapshots/text-turn/session.jsonl
#	examples/sandbox-acp-agent/cordis.yml
#	examples/sandbox-acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/mode-switching/session.jsonl
#	packages/compact/compact-basic/README.md
#	packages/compact/compact-basic/src/index.ts
#	packages/compact/compact-basic/tests/compact-basic.spec.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/agent-loop/tests/properties.spec.ts
#	packages/core/session/README.md
#	packages/core/session/src/types.ts
#	packages/core/session/tests/derived-cache.spec.ts
#	packages/llm/llm-deepseek/src/index.ts
#	packages/llm/llm-pi-ai/README.md
#	packages/llm/llm-pi-ai/src/adapter.ts
#	packages/llm/llm-pi-ai/src/convert.ts
#	packages/llm/llm-pi-ai/tests/adapter.spec.ts
#	packages/llm/llm/README.md
#	packages/llm/llm/src/call-config.ts
#	packages/llm/llm/src/index.ts
#	packages/ui/acp-agent/src/index.ts
#	packages/ui/acp/tests/harness.ts
#	packages/ui/jsonrpc/README.md
#	packages/ui/jsonrpc/src/server.ts
#	packages/ui/stdio-agent/README.md
#	packages/ui/stdio-agent/src/index.ts
#	python/sdk/README.i18n.yaml
This commit is contained in:
Yichen Jiang
2026-07-14 22:17:50 +08:00
672 changed files with 10295 additions and 14200 deletions

View File

@@ -118,9 +118,6 @@ describe('Session', () => {
const before = structuredClone(session.events)
// A misbehaving consumer tries to mutate the messages it was handed.
// Derived messages are frozen shared projections (cloned once off the
// log, then deep-frozen): every mutation attempt THROWS in strict mode —
// isolation by unrepresentability, not by per-call cloning.
const messages = session.deriveMessages()
const userBlock = messages[0]!.content[0]!
expect(() => { if (userBlock.type === 'text') userBlock.text = 'HACKED' }).toThrow(TypeError)
@@ -169,11 +166,8 @@ describe('Session', () => {
it('rejects a surface-eligible append with no surfaceOp marker (runtime guard for the union-widening loophole)', () => {
const session = new Session(SessionId('s5b'))
session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
// The typed overload makes surfaceOp mandatory only when the type argument is
// a SPECIFIC SurfaceEventType literal. A caller iterating raw events widens it
// to the SessionEventType union, where the conditional rest collapses to
// optional — the exact shape `for (const e of log) append(e.type, e.data)`
// produces. Reproduce that here and assert the runtime guard rejects it.
// A widened SessionEventType bypasses the overload's conditional requirement,
// so the runtime guard must still reject the missing surface marker.
const widenedType = 'user/message' as SessionEventType
expect(() => session.append(widenedType, { content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' } }))
.toThrow(/surface-eligible and requires a surfaceOp marker/)
@@ -700,10 +694,8 @@ describe('SessionStore', () => {
})
it('enter() rejects a stale prepared session whose id is already live (no overwrite)', async () => {
// prepare()/enter() are public cross-package primitives that a caller may
// separate with arbitrary work. A stale prepared session must NOT overwrite
// a live store entry of the same id — its detach disposer would later delete
// the REAL session, breaking the store-uniqueness invariant.
// A stale prepared object must not replace the live same-id entry; its later
// detach would otherwise remove the wrong session.
const ctx = new Context()
await ctx.plugin(SessionStore)
const stale = ctx.sessions.prepare(SessionId('racy'))