Repository navigation
feat(session): 会话格式 v4、外部 Session 导入与模型设置(含暗病修复) - #2
Merged
Merged
Conversation
# Conflicts: # docs/config-catalog.i18n.yaml # docs/persistence-changes/historical-formats/README.i18n.yaml # packages/session/session-format-catalog/README.i18n.yaml
# Conflicts: # .agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml # packages/experimental/webworker-packer/README.i18n.yaml # packages/experimental/webworker-packer/src/preview.ts # packages/experimental/webworker-packer/tests/preview.spec.ts
# Conflicts: # docs/event-producer-consumer.i18n.yaml # docs/persistence-catalog.i18n.yaml # packages/core/session/README.i18n.yaml
Represent tool results as tool-role messages and migrate released wrappers without losing outer own JSON fields, call identity, error state, or writer field order. Refuse nested or wrapper-only information that has no lossless current representation before successor publication. Validate current event relationships directly instead of projecting V4 data back into V3. Keep lifecycle, PTC, title/command, compaction, system-field and retired-syntax checks on catalog restoration and ordinary JSONL opens. The Worker JSON equality helper must inspect own keys so it cannot admit PTC arguments that Node rejects. Keep the source role change, required native admission and consumer fixture updates in one complete review layer. Explain shared-type changes in the persistence record and the native reader rationale in its existing note. Use checked branded fixture identities and discriminant narrowing instead of unknown double casts; fixture values and assertions remain intact. This recomposes the original tool-role work by _Kerman with the independently validated migration and admission repairs by Tianyi Cui. Frozen generations and snapshot input version selection are retained. Co-authored-by: Tianyi Cui <53024+tianyicui@users.noreply.github.com> # Conflicts: # apps/web/tests/web-search-round.e2e.ts # docs/persistence-catalog.i18n.yaml # docs/persistence-changes/historical-formats/README.i18n.yaml
Give durable user context its producer-owned source kind instead of a generic plugin wrapper. The V3-to-V4 conversion preserves the frozen rename and collision rules, all own JSON metadata, event coordinates, and historical request-only kinds. Native catalog and JSONL admission retain source validation so unknown attribution can survive without its producer while malformed owned sources are refused. Use an explicit user-only RequestUserInput for auxiliary LLM prompts that do not own durable message identity. Auto Review and compaction remove their request-only source registrations while retaining prompt content and freezing; provider serializers and projections keep the same wire data, assistant replay isolation, image ordering, and tool correlation. Session writes, Agent delivery, and recorded title requests continue to require identified durable messages. Bind the saved compatibility policy only to user sources and qualify tmux location attribution without weakening fixed system, model, or tool semantics. Rebuild the current inventory and unpublished V4 acknowledgement on the actual tool-role parent, preserving its rationale and all accepted historical records. The catalog format version records tooling metadata; Session remains V4. Developer-role policy and activation belong to their own feature. The latest-master Messages adapter, serialization, request-input typing, EpochHeader reservation, and attribution checks pass 103 tests across five files. The retained V3 Messages input-history snapshot passes through the source profile; Host/Client typechecks and all 41 documentation gates pass. The generated comparison records four changed roots and 447 unchanged type fingerprints. Latest-master ARIA changes are retained, with producer source labels applied independently; new Messages fixtures retain their producer names as declared source kinds and use the fixed system-message helper; recorded Session generations are unchanged by this regrouping. Co-authored-by: Tianyi Cui <53024+tianyicui@users.noreply.github.com> # Conflicts: # docs/event-producer-consumer.i18n.yaml # docs/persistence-changes/2026-09-16-session-format-v4.i18n.yaml # docs/persistence-changes/historical-formats/README.i18n.yaml # packages/llm/llm-deepseek/tests/messages/fixtures/input-history.ts # packages/llm/llm/README.i18n.yaml # snapshots/web/feedback-release/ack-expanded.expected.md # snapshots/web/web-search-round/ui.expected.md
The producer-source refactor introduced the unreleased V4 discriminator code-mode even though this source identifies images deferred from successful PTC subcalls. Name it ptc-mode before V4 ships so persisted attribution matches the producer and does not freeze obsolete terminology into new logs. Keep the live writer, V3-to-V4 migration output, collision guard, and reserved producer policy aligned. Both released tools-code-mode and tools-ptc plugin lookup keys map to ptc-mode. Preserve those historical keys, opaque message text and IDs, all frozen V0-to-V3 generations, and recorded Session inputs. Update the owning tests, producer documentation, current catalog, and V4 acknowledgement. The canonical schema audit identifies exactly three changed roots; reversing only the source literal restores each prior digest. The large generated JSON diff comes from graph ordering, with 61 roots and 572 types retained. Validation: the seven-file focused run passed 298 tests and exposed four stale current-output expectations in two migration files. After correcting those expectations, both files passed all 23 tests. All 41 documentation gates and full lint passed; frozen generations and recorded inputs are unchanged. # Conflicts: # scripts/persistence-source-policy.ts
Session V4 reserves developer-role messages for incremental model-visible session changes. The role, tool addition/removal blocks, and deferred-loading marker need a durable representation before independent provider and UI integrations can emit or consume them. Known developer events must match an open turn and step; unsupported providers and UI consumers fail explicitly. Request headers already capture full tool definitions. Persisting another ToolSchema in each addition would duplicate Session information and create two definitions that could drift. Additions therefore store toolName, and the containing developer event uses headerSeq to select one earlier known request/header for all its additions. A same-name replacement keeps its historical definition identity through restart, fork and surface changes. Removals require no definition copy, and ordinary developer messages omit headerSeq. Generic sourceEventSeqs remains independent derivation metadata. The rejected inline tool field is optional never with @persistenceReserved. The schema extractor retains that uninhabited slot, so permitting a future value requires a format bump instead of being mistaken for compatible optional metadata. Unrelated optional fields remain additive and readable. Native and Session admission reject missing, forward, non-header, unknown, ambiguous and incomplete referenced definitions, and reject the retired inline tool field. Validate complete schema fields only for referenced definitions, preserving unrelated header behavior and extra JSON metadata. Unknown ignorable records remain opaque. Empty developer nodes retain their surface position without producing a message or shadowing the system head. No automatic emitter, provider activation, UI implementation, or speculative public resolver is added. Keep the core-owned developer source binding beside the introduced role, including the request-only type rejection and attribution round trips. Update consumer guards, SDK/snapshot handling, bilingual owner documentation, and the same unreleased V4 acknowledgement. Keep earlier tool/source migration work and its documentation in the parent. Preserve the existing recorded Cordis inspection generation from the original developer change. Integration keeps the final source layer as the sole parent and preserves master's Messages input filtering, empty-user omission, empty tool results, and system-update placement. Developer/deferred guards still run before conversion. Native V4 admission, header references, reservation declarations, and generic tooling match the validated marker candidate. Parent-owned fixture and generator fixes remain in the parent. Earlier feature validation passed full build, full lint, 41 doc-sync gates, and 16 hygiene gates. The unchanged native implementation retains that evidence. The focused Session/V4/request-input run passes 884 tests across 38 files with 100% statement, branch, function and line coverage for the V3-to-V4 package and Session surface. Consumer tests pass 482 with one existing skip; tool, message and optional-field tests pass 146. Cordis inspection and compaction replays pass in both source and built modes (two cases per mode). Ten invalid referenced-definition/unknown-header controls failed before their scoped guards and pass after them. Reservation validation: the actual generated developer root records tool as optional primitive never. Widening it requires a bump, while traceId remains additive and preserved; all 85 focused reader/classifier tests pass. Final-parent validation: 205 tests across eight provider, type, catalog, Session and native-format files pass. The preserved parent fixture verifies Messages input-history replay; runtime/declaration and parent-owned-file comparisons show no loss during the final rebase. Co-authored-by: Tianyi Cui <53024+tianyicui@users.noreply.github.com> # Conflicts: # docs/persistence-catalog.i18n.yaml # packages/api/session-controller/README.i18n.yaml
Released V3 accepts tool-result wrappers in ordinary user content. Leaving those wrappers in a V4 artifact violates its declared content types and reaches provider serializers that cannot represent them. Converting such rows would require a new event, role, or source ownership decision. Reject retired result tags only in known interpreted content slots and raw Assistant stream block starts/ends. Reuse the native retired-syntax admission path before recoverable suffix suppression and target artifact restoration before successor publication. Preserve the existing system and tool-result validators and the canonical V3 tool/result wrapper lift. Known ignorable developer rows receive the same check during encoding; unaware physical readers still defer their opaque developer payloads. Tool arguments, replay state, schema parameters, nested metadata, and unknown ignorable event payloads are not recursively scanned. Real JSONL regressions cover V3 migration and native V4 read/write in plain and Zstandard storage, including a corrupt native prefix. Refusals preserve source bytes and the sole generation; opaque payloads survive. No declared schema, frozen V0-V3 codec, or snapshot generation changes. # Conflicts: # .agents/notes/implemented/architecture/2026-09-17-native-v4-read-validation.i18n.yaml
The retired-content guard runs on parsed physical JSON before normal event admission so recovery cannot suppress a retired wrapper after another invalid row. At that point type and sequence fields are still JSON values rather than validated event fields. Implicit interpolation therefore violates the typed lint rule on the final combined branch. Use explicit String conversions only for the error subject. Keep the guard's ordering and refusal checks unchanged; requiring an already-valid envelope here would weaken the pre-recovery check. This does not change the stored representation or add a migration rule.
V3 permits external event, source and content identities and additional request-tool fields. Copying those values into V4 can give an old plugin named tool a core source identity, turn old tool-addition content into a registry instruction, or activate formerly ignored deferLoading and delivery metadata. Rejecting such collisions would instead refuse valid source logs. Keep historical extensions in the existing extensible JSON representation. Prefix unknown content and ignorable event tags with plugin:, preserving all other content fields and opaque event payloads. Prefix external source identities with plugin:plugin: or plugin:source: so wrapper and direct kinds cannot collide even when original names already contain a category prefix. Known first-party mappings remain explicit and unchanged. Prefix extra request-tool field names and block-start field names with plugin:, retaining exact values and existing-prefix doubling. Core schema parameters, arguments, replay state and nested plugin data are not traversed. Keep future-generation delivery records inactive after header promotion. Pin the V3 event vocabulary independently of the current writer and provide an offline verifier against an explicitly selected historical source commit. Attachment authorization and export inspect declared event content only. Team checkpoints preserve all own keys of unknown JSON blocks while still rejecting malformed known content and retired core tool-result blocks. Exercise physical read/write/reopen, prefix injectivity, own __proto__ keys, provider opacity and retained source-identity snapshots. No generic extension block, metadata wrapper or new schema-tooling type is introduced. V4 type declarations, persistence schema, checkpoint and frozen V0-V3 codecs remain unchanged. Canonical tool-result lifting and incomplete child-catalog policy remain separate concerns. Adapted from the extension-preservation work in 7ba7e174dd1 by Tianyi Cui. Co-authored-by: Tianyi Cui <53024+tianyicui@users.noreply.github.com> # Conflicts: # .agents/notes/implemented/architecture/2026-09-17-persistence-attribution-policy.i18n.yaml # docs/session-format-status.i18n.yaml # packages/session/session-format-v3-to-v4/README.i18n.yaml
V3 and V4 declare the same block-start fields: type, index and blockType. The migration's identifier policy can qualify an extension blockType, but prefixing every additional field has no current V4 field collision to solve. That rewrite changed captured keys to anticipate hypothetical future fields. Retain every non-blockType field and value exactly, including already prefixed names and own JSON keys. Keep the approved blockType identifier prefix and the separate ToolSchema field policy unchanged. Update the local conversion tests to verify both known and extension starts retain metadata and to use the actual raw-record time field. Later field-specific conversion belongs to a concrete source/target change instead of this edge.
A V3 delivery marker claiming generation 4 would become active when its header advances to V4. The integration baseline already refused that case. Renaming every higher-generation marker instead introduced a general conversion policy for future formats that this V3-to-V4 edge does not own. Restore the targeted generation 4 refusal. Keep other delivery event names, payloads and coordinates unchanged, including generations 5 and 99, which remain inactive in V4. Their future activation checks belong to a concrete later format edge. Preserve the separate plugin-event identifier policy. Cover read/write opens for both plain and zstd storage: target-generation refusal preserves source bytes and publishes no successor, while later markers survive V4 publication and native reopening unchanged. Update the snapshot-normalizer cases and document the alpha converter coverage limit: unsupported histories may fail without source mutation, and later converter fixes may expand support without a new version when V4 output stays compatible.
…etation The physical V3 codec admits an unclassified event envelope without deciding whether its type is required. The V3-to-V4 stage then used shared message walkers and target vocabulary, so an invalid required developer/message could acquire the V4 developer role although historical V3 restoration rejects it. Generic required unknown events were also left to the wrong version's reader. After preserving explicitly ignorable extensions, require every remaining source type to belong to the fixed V3 vocabulary before interpreting payloads. This is a fail-loud check for invalid or nonconforming source data, not new compatibility handling for third-party events, which carry ignorable:true. The approved plugin identifier conversion and native V4 readers are unchanged. Exercise a complete developer-event sequence through direct migration, historical/current catalogs, ignorable conversion and native V4 restoration; add a generic unknown type. Both negative controls accepted the invalid source before this guard. Plain/zstd read/write regressions verify refusal preserves the source generation and never publishes a partial V4 successor.
The preserved direct-source set is the predecessor migration's accepted set without the plugin wrapper. It includes older coordinator and subagent-report identities even though those names have no current producer declaration. Describe that historical admission fact instead of implying every retained identity has a live V4 owner. No mapping or runtime behavior changes.
Convert an unknown legacy plugin wrapper such as
{kind: 'plugin', plugin: 'acme'} into {kind: 'plugin:acme'}, retaining the
complete plugin name after one prefix. Keep the existing explicit
first-party producer renames and preserve all non-identity metadata.
A direct source already records its producer in kind. Reclassifying
unknown direct kinds into plugin:source:<name> needlessly changes that
attribution and forces plugin consumers to adopt new identifiers even
though V4 accepts their existing representation. Return every valid
direct source unchanged, including already-prefixed names. Remove the
obsolete direct-kind table and two-category identity helper rather than
adding collision classification or another mapping layer.
Update the source conversion examples, codec/restore regressions, and
native fixture producers together. Refresh only the owning Python
advanced scenario's unshipped V4 outputs; preserve historical V0-V3
recordings and their generation selection. Event names, content tags,
and ToolSchema migration remain separate concerns.
Refs deepseek-ai#2692
The V3 writer on master declares and emits only name, description and parameters. deferLoading is a first-class V4 persistence addition whose provider behavior is not implemented yet. Prefixing every historical extra ToolSchema key changes ordinary plugin metadata without a format need. Preserve all ordinary tool-definition keys and JSON values unchanged, including vendor metadata, own __proto__ properties, already-prefixed keys and nested parameters. Remove the general key-renaming mapper. Reject only an own top-level deferLoading field in V3 input: there is no established V3 meaning to translate, and the alpha converter may refuse unsupported source forms rather than invent compatibility semantics. Leave native V4's optional-true declaration, admission and provider refusal behavior intact. The regression tests fail on the old mapper for metadata preservation and unsupported-field refusal. Physical plain/zstd read/write tests verify source bytes and identity remain unchanged and no V4 successor appears on refusal; controls preserve nested parameters.deferLoading and native V4 true values. No Session format/schema change, frozen codec edit, or historical recording version bump is needed.
A readable V3 child may have no own descriptor, an unknown descriptor version, or multiple descriptors. Those states do not provide a unique discovery fact, but they do not make the parent or the retained child history unreadable. Rejecting the entire parent prevented otherwise valid V3 Sessions from opening. Append a missing parent catalog row only for exactly one supported own child descriptor. Keep existing parent entries and every child record when no fact is available. Retain rejection of mismatched creation times, unambiguous mode/label conflicts, malformed known fields, unreadable membership and revision drift. Cover raw and compressed read/write publication, preserved source bytes, late descriptor availability, inherited descriptors and Preview packing. Document that unavailable discovery evidence can leave a child absent from its parent catalog and does not trigger automatic backfill after the V4 successor exists. Extracts the child-evidence behavior from 7ba7e174dd1 and the Preview regression from 9c85eb60bd25, preserving the original migration authors' work while keeping message representation and extension interpretation outside this commit. Co-authored-by: Dudu-0223 <fsyo0223@gmail.com>
The ordinary V3 writer records a user-role message containing one result wrapper. V4 writes the same tool output directly in a tool-role message. Keep that native V4 representation instead of introducing a nested message content type for hypothetical historical shapes. Preserve extra historical fields when removing the wrapper. Prefix outer message fields with plugin:message: and result fields with plugin:result: so equal names retain their original ownership and cannot overwrite the interpreted call ID or error flag. Include the complete old name, even when it is already prefixed, and preserve every JSON value and own key. Only the validated wrapper supplies the interpreted result fields. Leave unimplemented nested-result conversion as an explicit refusal that preserves its source. Describe this as the converter's current limit, not an impossibility or a reason to extend the established V4 format. Cover owner/name collisions, opaque special keys, absent error flags, unchanged sources and strict native reopening through plain and compressed read/write persistence. No current message type or schema is added.
The exported converter rejects malformed wrappers with SessionFormatError in addition to refusing unsupported nesting. Document both failure categories so callers can distinguish corruption from a converter support limit. Remove the obsolete claim that recorded replay compares serialized field order: the native-writer parity assertion compares parsed objects. The emitted fields and their order remain unchanged.
# Conflicts: # .agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.i18n.yaml # .agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml # .agents/notes/implemented/architecture/2026-09-16-desktop-policy-login-loading.i18n.yaml # .agents/notes/implemented/bug-fix/2026-09-19-v3-incomplete-child-catalog-evidence.i18n.yaml # .agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.md # .agents/notes/implemented/simplification/2026-09-08-web-subagent-catalog-projections.zh.md # docs/subsystems/subagent.i18n.yaml # docs/tool-catalog.i18n.yaml # packages/client/ui-subagent/README.i18n.yaml # packages/client/ui-workspace/README.i18n.yaml # packages/session/session-persistence-jsonl/README.i18n.yaml # packages/subagent/subagent/README.i18n.yaml # packages/subagent/tool-subagent-control/README.i18n.yaml
# Conflicts: # .agents/notes/implemented/bug-fix/2026-09-19-session-local-subagent-migration.i18n.yaml # scripts/migrate-sessions-to-v4.spec.ts # scripts/no-unknown-casts.baseline.json
# Conflicts: # packages/api/session-controller/README.i18n.yaml # packages/session/session-format-v3-to-v4/README.i18n.yaml
# Conflicts: # .agents/notes/implemented/process/2026-09-11-persistence-type-history.i18n.yaml # docs/persistence-changes/README.i18n.yaml
# Conflicts: # .agents/notes/implemented/simplification/2026-09-17-plugin-inventory-phase-dot.i18n.yaml # .agents/notes/implemented/simplification/2026-09-17-unified-subagent-activations.md # .agents/notes/implemented/simplification/2026-09-17-unified-subagent-activations.zh.md # docs/persistence-catalog.i18n.yaml # docs/persistence-changes/2026-09-18-schedule-optional-title.i18n.yaml # docs/persistence-changes/2026-09-19-external-subagent-catalog.md # docs/persistence-changes/2026-09-19-external-subagent-catalog.zh.md # docs/subsystems/subagent.i18n.yaml # packages/client/ui-subagent/README.i18n.yaml # packages/session/session-format-v3-to-v4/README.i18n.yaml # packages/subagent/subagent/README.i18n.yaml # packages/subagent/subagent/tests/external-activation.spec.ts
# Conflicts: # .agents/notes/implemented/simplification/2026-09-17-plugin-inventory-phase-dot.i18n.yaml # packages/subagent/subagent/src/manager.ts # packages/test-support/client-runtime/README.i18n.yaml # snapshots/sdk/subagent-dsh-sdk-diagnostic/session.v4.jsonl # snapshots/sdk/subagent-dsh-sdk-dynamic-route/session.v4.jsonl # snapshots/session/product-subagent-result-diagnostic/session.v4.jsonl # snapshots/session/subagent-acp-diagnostic/session.v4.jsonl
…ai#4689) * fix(session): repair interrupted turns during V3 migration * docs(session-format-v3-to-v4): state reference remapping in the summary and code The frontmatter summary still promised preserved references after the edge began remapping audited same-artifact references around an inserted interrupted turn/end. Two local comments record why the opaque branch moves only `seq` and why the open-step flag needs no reset at a turn boundary. * docs(session-format-catalog): describe the V3-to-V4 edge as a converting link The catalog listed the edge as an identity conversion, which stopped being true once it inserted an evidenced interrupted turn/end and remapped the audited local references that follow.
Replays the upstream V4 commit series (v3-to-v4 codec, migration, catalog, persistence, builders and consumers) and rescopes it to @mutantcat. Adds the 0.2-era packages the V4 consumers depend on (working-directory, tool-working-directory, agent-preset, agent-preset-registry, llm-deepseek-api-key). Not green yet: those consumers also need 0.2 core and vendor APIs that this base predates.
Drops the 0.2-era packages the upstream V4 consumers pull in
(working-directory, tool-working-directory, agent-preset,
agent-preset-registry, llm-deepseek-api-key) and restores the fork's
subagent, session-controller and schedule surfaces from main, so the port
keeps the fork's own features. Ports scripts/migration-failure-summary.ts and
points the V4 migration CLI at the package default export.
Not green: the fork's consumers still carry the retired {kind:'plugin'}
message source and the pre-V4 consumer API, so host and client typechecks
report fallout that the upstream saga commits had converted elsewhere.
Session format v4 with the catalog payload vocabulary (v0 local, v1 adds `unknown`, v2 external), its persistence record chain down to the 2026-10-21 successor, and the regenerated historical-format references. Harness session import: a Host gateway that lists another harness's sessions and adopts them one commit per session, plus the settings page that drives it. Model settings gain the pi-ai reasoning-effort control and route-wide input fallback; attachments classify drops the platform delivers without an entry path. Fixes found while auditing: - agent-loop dropped a step interrupt that no provider chunk had delivered: the interrupt controller now joins the request signal, so `interruptModelStep()` cuts an in-flight wait instead of leaving the turn parked until the provider answers. - llm-deepseek re-validated `defaultInput` against the modality list its own schema already enforces; the empty and duplicate guards stay. - ModelRow handed one optional-value callback to both the id and the name input, so both editors carried an unreachable `?? ''` for the id; the row now distinguishes `onIdChange` from `onNameChange`. - Persistence record anchors were duplicated in the catalog successor and its digest disagreed with the finalized chain. Test reliability under a loaded host: native-filesystem waits and the pi-ai idle-watchdog close observation had wall-clock bounds tighter than a saturated runner; both now allow the delay they actually measure.
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
…y generation The Python SDK snapshot suite passes `native_writer_output` and a source generation to the comparison helpers, but `scripts/smoke-python-runtime.py` had neither: the keyless SDK lane failed with a TypeError instead of comparing anything. The helpers now mirror the TypeScript comparison — each side tokenizes the delivery markers it recorded at its own generation, the default comparison keeps every generation exact, and a comparison whose Session roles span generations refuses instead of comparing mixed artifacts.
…igration
- AgentDefaultModelConfig: add static inject = ['settings'] so the settings
section is installed before newSession reads currentSelection(), fixing the
{{model}} prompt-variable race in ACP sessions.
- ToolRuntime scheduler symbol: use Symbol.for() so the built and source
module copies share one key across the source/artifact plane split.
- Composer keymap: route plain-text pastes above 4000 characters to file
attachment intake instead of inline editor insertion, preventing Lexical
reconciler stalls on large pastes.
- Snapshots: migrate all scenarios to v4 session format, restore missing
web-search-round and feedback-release fixtures, update borrower manifests
to point at v4 owner sessions, and adjust corpus policy expectations.
- tsconfig.host.json: remove dead feedback-release.e2e.ts include.
- scripts/session-snapshot-corpus.corpus.ts: update retained scenario count.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
把会话格式 v4 的移植收尾并落到可合并状态:v4 词汇、外部 Session 导入、模型设置页的推理档位与输入兜底,并修掉本轮全面排查中发现的暗病(详见 Changes)。版本号已是
1.0.20261021。Changes
持久化 / 会话格式
SESSION_FORMAT_VERSION = 4;catalog payload 词汇 v0(local,一次性/可续)/ v1(新增unknown)/ v2(external)。2026-10-21-native-catalog-payload-vocabulary(same-version,链到2026-09-19-external-subagent-catalog),补齐.schema.json与 i18n 记录,摘要与finalized/v4.json一致。<a id>锚点与失配摘要;historical-formats/README由persistence-formats.ts --write重新生成。外部 Session 导入
ui-settings-import-sessions设置页(列表、根目录覆盖、刷新)。模型设置
defaultInput兜底。暗病修复
agent-loop的步骤中断此前只对已产出首块的服务商生效:中断控制器没有并入请求信号,interruptModelStep()对「一个块都没回」的等待不起作用,回合会一直挂到服务商返回。现在AbortSignal.any([turnSignal, interrupt.signal])参与请求,立即切断在途等待。llm-deepseek对defaultInput重复校验了 schema 已经保证的模态取值,删除该冗余守卫,保留空表与重复项校验。ModelRow把同一个可空回调同时给 id 与 name 输入,两个编辑器因此各带一处不可达的?? '';拆成onIdChange/onNameChange后两处死分支消失。oxlint-disable指令位置(prefer-promise-reject-errors与no-deprecated),使 staged 与全量 lint 同时为 0 error。测试
model-step-interrupt.spec.ts、failure-code.spec.ts、harness-import.{host,client}.spec.ts、foreign.spec.ts、image-capability.client.spec.ts、model-reasoning-efforts.client.spec.tsx,并为上述缺陷补齐回归用例。Testing
tsc -b tsconfig.client.json(typecheck:contracts-ready)+ 全部项目 typecheck:通过,pre-push hook 亦为绿。Proof
pnpm run lint:contracts-ready(全量 oxlint,4241 文件):0 warnings / 0 errors。Proof
run-gates ci-static:55/55 通过(含 Session 格式引用、包路径、各类生成目录一致性)。Proof
run-gates ci-coverage(本机 macOS,非分区模式,逐文件 100%):27174 passed / 0 failed;仅subprocess-local/src/linux-execve.ts与ptc-runtime-python/src/index.ts的/proc读取分支在本机不可达(Linux 通道覆盖)。Proof
doc-quick20/20、verify-translation-pairing(1026 对)、verify-doc-links(2050 文件)、persistence-formatsv0–v4、type-equiv455/455:通过。Proof