Merge remote-tracking branch 'origin/master' into xtr/agent-loop-message-machine

# Conflicts:
#	docs/architecture.i18n.yaml
#	docs/architecture.md
#	docs/architecture.zh.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/core-data-structures/llm-streaming.i18n.yaml
#	docs/core-data-structures/session.i18n.yaml
#	docs/event-producer-consumer.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	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/loop.ts
#	packages/core/agent/README.i18n.yaml
#	packages/core/agent/tests/llm-target.spec.ts
#	packages/core/session/tests/request-header.spec.ts
This commit is contained in:
_Kerman
2026-07-27 16:44:06 +08:00
220 changed files with 4592 additions and 969 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
README.md: db6bbf6970c73767c8e9df1148f98d23047d19b7
README.zh.md: 6a9b817cb5af2c43b8e66100333e46665359eba8
README.md: 3615f68953cfe6cdc0e6fc41bf75b8dfdf90a310
README.zh.md: c4a7d829cc1583b65d2c8afa1683d957f68722e9

View File

@@ -16,11 +16,11 @@ The list belongs to the ONE agent session that called the tool. There is no suba
## Validation
Beyond the schema's type/required/enum checks, `execute` rejects an empty or duplicate `content` and more than one `in_progress` task (a coherent plan has at most one task active). Ordering and the discipline of keeping the list current are left to the model via the tool description.
Beyond the schema's type/required/enum checks, `execute` rejects an empty or duplicate `content`, more than one `in_progress` task (a coherent plan has at most one task active), and any item key beyond `content`/`status` — an extended item shape (ids, nesting) fails loud instead of silently flattening, keeping the logged snapshot equal to what the model believes it wrote. Ordering and the discipline of keeping the list current are left to the model via the tool description.
## Rendering
The canonical result is `{ todos, counts: { pending, inProgress, completed } }`; its Native renderer returns the compact update acknowledgement. The tool also writes the full `todo/write` session event. UIs subscribe to the event stream and render that durable list themselves; the [TUI app](../../examples/tui-demo) shows it as a persistent plan.
The canonical result is `{ todos, counts: { pending, inProgress, completed } }`; its Native renderer returns the compact update acknowledgement. The tool also writes the full `todo/write` session event. UIs subscribe to the event stream and render that durable list themselves: the [TUI app](../../examples/tui-demo) shows it as a persistent plan, and the [web client](../../client/ui-conversation) renders a plan strip plus a dedicated tool row off `ConversationSnapshot.todos` ([Agent Note](../../../.agents/notes/implemented/feature/2026-07-23-web-todo-display.md)).
## Export shape

View File

@@ -16,11 +16,11 @@
## 验证
除 schema 的类型/必填/枚举检查外,`execute` 还会拒绝空或重复的 `content`,以及同时存在多个 `in_progress` 任务的情况(连贯计划最多只有一个活跃任务)。顺序与保持列表最新的纪律由模型根据工具描述负责。
除 schema 的类型/必填/枚举检查外,`execute` 还会拒绝空或重复的 `content`同时存在多个 `in_progress` 任务的情况(连贯计划最多只有一个活跃任务),以及 `content`/`status` 之外的任何条目键——扩展条目形状id、嵌套会响亮失败而不是被静默压平保证落日志的快照与模型自认为写入的内容一致。顺序与保持列表最新的纪律由模型根据工具描述负责。
## 渲染
规范结果为 `{ todos, counts: { pending, inProgress, completed } }`;其 Native 渲染器返回精简的更新确认。工具还会写入完整 `todo/write` 会话事件。UI 订阅事件流,并自行渲染该持久列表[TUI 应用](../../examples/tui-demo)将其显示为持久计划。
规范结果为 `{ todos, counts: { pending, inProgress, completed } }`;其 Native 渲染器返回精简的更新确认。工具还会写入完整 `todo/write` 会话事件。UI 订阅事件流,并自行渲染该持久列表[TUI 应用](../../examples/tui-demo)将其显示为持久计划[web 客户端](../../client/ui-conversation)则基于 `ConversationSnapshot.todos` 渲染计划横条与专属工具行([Agent Note](../../../.agents/notes/implemented/feature/2026-07-23-web-todo-display.md)
## 导出形状

View File

@@ -29,7 +29,10 @@ const DESCRIPTION =
/**
* Validate the value constraints the ParameterSchemaSpec can't express and build the canonical {@link
* TodoItem}[]: trimmed non-empty unique content and at most one in-progress item. The registry
* has already enforced the status enum; the cast below records that guarantee.
* has already enforced the status enum and rejected unknown item keys (`additionalProperties:
* false` — the logged snapshot must equal what the model believes it wrote, so a nested/extended
* item shape fails loud at the schema boundary instead of silently flattening); the cast below
* records that guarantee.
*/
function toTodoList(raw: { content: string; status: string }[]): TodoItem[] {
const todos: TodoItem[] = []
@@ -66,7 +69,7 @@ export function apply(ctx: Context): void {
description: 'The COMPLETE task list, replacing any previous list.',
items: {
type: 'object',
additionalProperties: true,
additionalProperties: false,
properties: {
content: { type: 'string', required: true, description: 'What the task is — a short imperative line.' },
status: {

View File

@@ -126,6 +126,7 @@ describe('dsh-tool-todo', () => {
{ label: 'empty content', todos: [{ content: ' ', status: 'pending' }], fragment: 'non-empty' },
{ label: 'duplicate content', todos: [{ content: 'dup', status: 'pending' }, { content: 'dup', status: 'completed' }], fragment: 'duplicate' },
{ label: 'two in_progress', todos: [{ content: 'a', status: 'in_progress' }, { content: 'b', status: 'in_progress' }], fragment: 'in_progress' },
{ label: 'unknown item keys', todos: [{ content: 'a', status: 'pending', children: [] }], fragment: 'not a declared property' },
])('rejects $label as an isError result', async ({ todos, fragment }) => {
const ctx = await setup()
const result = await callTodo(ctx, { todos })