Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.md
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.zh.md
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.i18n.yaml
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.md
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.zh.md
#	docs/architecture.i18n.yaml
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	docs/core-data-structures/core.md
#	docs/core-data-structures/core.zh.md
#	docs/defensive-patterns.i18n.yaml
#	packages/client/runtime/src/client/sessions/session.ts
#	packages/client/runtime/tests/queue-store.spec.ts
#	packages/context/time-context/tests/time-context.spec.ts
#	packages/context/workspace-context/tests/workspace-context.spec.ts
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-loop/README.i18n.yaml
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/README.zh.md
#	packages/core/agent-loop/src/agent.ts
#	packages/core/agent/README.i18n.yaml
#	packages/core/agent/README.md
#	packages/core/agent/README.zh.md
#	packages/core/agent/src/types.ts
#	packages/core/agent/tests/agent.spec.ts
#	packages/core/scope/src/scoped-events.generated.ts
#	packages/goal/command-goal/tests/command-goal.spec.ts
#	packages/goal/goal-session/src/index.ts
#	packages/goal/goal-session/tests/goal-session.spec.ts
#	packages/goal/goal/tests/goal.spec.ts
#	packages/goal/goal/tests/projection.spec.ts
#	packages/goal/tool-goal/tests/tool-goal.spec.ts
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/events.schema.ts
#	packages/host/apiproxy/src/api/events.ts
#	packages/host/apiproxy/tests/api-proxy-workspace.spec.ts
#	packages/llm/llm/README.i18n.yaml
#	packages/llm/llm/README.zh.md
#	packages/llm/llm/src/index.ts
#	packages/pty/pty-local/tests/index.spec.ts
#	packages/pty/pty-local/tests/local.spec.ts
#	packages/pty/pty/tests/service.spec.ts
#	packages/pty/tool-pty/tests/loader-composition.spec.ts
#	packages/pty/tool-pty/tests/tools.spec.ts
#	packages/skill/tool-skill/tests/tool-skill.spec.ts
#	packages/tasks/tasks-local/tests/tasks.spec.ts
#	packages/ui/tui/src/index.ts
#	packages/ui/tui/tests/harness.ts
#	packages/ui/tui/tests/tui.spec.ts
#	scripts/gen-cordis-catalog.ts
#	scripts/type-equiv.manifest.json
This commit is contained in:
_Kerman
2026-07-30 14:04:53 +08:00
1175 changed files with 49683 additions and 8452 deletions
@@ -19,6 +19,7 @@ import type {
LlmResolvedModelInfo,
Message,
StreamChunk,
TokenUsage,
} from '@deepseek-ai/dsh-llm'
import { Session, SessionId } from '@deepseek-ai/dsh-session'
import TokenMeterService from '@deepseek-ai/dsh-token-meter'
@@ -232,6 +233,8 @@ function oversizedToolResult(chars = 3_000, withCompactablePrompt = false): Sess
class TestCompactService extends BasicCompactService {
summary: ContentBlock[] = [{ type: 'text', text: 'small checkpoint' }]
rawOutput: ContentBlock[] | undefined
usage: TokenUsage | undefined
summaryProvider = 'summary-provider'
summaryModel = 'summary-model'
error: unknown
@@ -242,15 +245,24 @@ class TestCompactService extends BasicCompactService {
input: SummarizationInput,
_agent: Agent,
signal?: AbortSignal,
): Promise<{ summary: ContentBlock[]; provider: string; model: string; maxTokens?: number }> {
): Promise<{
summary: ContentBlock[]
rawOutput?: ContentBlock[]
provider: string
model: string
maxTokens?: number
usage?: TokenUsage
}> {
this.calls.push({ input, signal })
this.mutateDuringSummary?.()
if (this.error !== undefined) throw this.error
return {
summary: this.summary,
...this.rawOutput === undefined ? {} : { rawOutput: this.rawOutput },
provider: this.summaryProvider,
model: this.summaryModel,
maxTokens: 123,
...this.usage === undefined ? {} : { usage: this.usage },
}
}
}
@@ -828,6 +840,11 @@ describe('optional model-free tool-result pruning', () => {
describe('compaction region transaction', () => {
it('lands a framed, replayable checkpoint with exact pricing provenance', async () => {
const compact = service()
compact.rawOutput = [
{ type: 'reasoning', text: 'private compact thought' },
...compact.summary,
]
compact.usage = { inputTokens: 40, outputTokens: 5 }
const session = conversation(3)
const before = [...session.surface.nodes]
const result = await compact.compactRegion(
@@ -848,6 +865,8 @@ describe('compaction region transaction', () => {
provider: 'summary-provider',
model: 'summary-model',
maxTokens: 123,
rawOutput: compact.rawOutput,
usage: compact.usage,
})
const head = session.deriveMessages()[0]!
expect(head.content[0]?.type).toBe('text')
@@ -1087,6 +1106,7 @@ describe('compaction region transaction', () => {
class ScriptedAdapter extends LlmAdapter {
lastOptions: GenerateOptions | undefined
usage: TokenUsage | undefined
constructor(
private readonly blocks: readonly ContentBlock[],
@@ -1107,6 +1127,7 @@ class ScriptedAdapter extends LlmAdapter {
yield { type: 'block-end', index, block }
}
}
if (this.usage !== undefined) yield { type: 'usage', usage: this.usage }
yield { type: 'finish', reason: this.finish }
}
}
@@ -1116,7 +1137,14 @@ class ExposedCompactService extends BasicCompactService {
input: SummarizationInput,
owner: Agent,
signal?: AbortSignal,
): Promise<{ summary: ContentBlock[]; provider: string; model: string; maxTokens?: number }> {
): Promise<{
summary: ContentBlock[]
rawOutput?: ContentBlock[]
provider: string
model: string
maxTokens?: number
usage?: TokenUsage
}> {
return this.summarize(input, owner, signal)
}
}
@@ -1149,13 +1177,20 @@ describe('default one-shot summarizer', () => {
maxTokens: 321,
})
const session = conversation(1)
adapter.usage = { inputTokens: 12, outputTokens: 3 }
const output = await compact.runSummarize(promptInput('transcript'), agent(session, 'fallback'), SIGNAL)
expect(output).toEqual({
summary: [{ type: 'text', text: 'public summary' }],
rawOutput: [
{ type: 'reasoning', text: 'private' },
{ type: 'text', text: 'public summary' },
{ type: 'tool-call', id: CallId('unexpected'), name: 'x', arguments: '{}' },
],
provider: MODEL,
model: MODEL,
maxTokens: 321,
usage: adapter.usage,
})
expect(adapter.lastOptions).toMatchObject({
provider: MODEL,