@osovv/vv-opencode 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +41 -10
- package/dist/lib/agent-tool-catalog.d.ts +144 -0
- package/dist/lib/agent-tool-catalog.js +2551 -0
- package/dist/lib/agent-tool-catalog.js.map +1 -0
- package/dist/lib/agent-tool-contract.d.ts +200 -0
- package/dist/lib/agent-tool-contract.js +407 -0
- package/dist/lib/agent-tool-contract.js.map +1 -0
- package/dist/lib/workflow-contract.d.ts +12 -0
- package/dist/lib/workflow-contract.js +71 -18
- package/dist/lib/workflow-contract.js.map +1 -1
- package/dist/plugins/hashline-edit/index.js +102 -97
- package/dist/plugins/hashline-edit/index.js.map +1 -1
- package/dist/plugins/hashline-edit/normalize-edits.d.ts +2 -8
- package/dist/plugins/hashline-edit/normalize-edits.js +32 -17
- package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -1
- package/dist/plugins/hashline-edit/schemas.d.ts +246 -0
- package/dist/plugins/hashline-edit/schemas.js +659 -0
- package/dist/plugins/hashline-edit/schemas.js.map +1 -0
- package/dist/plugins/hashline-edit/str-replace-editor.d.ts +6 -17
- package/dist/plugins/hashline-edit/str-replace-editor.js +19 -21
- package/dist/plugins/hashline-edit/str-replace-editor.js.map +1 -1
- package/dist/plugins/hashline-edit/tool-description.d.ts +1 -0
- package/dist/plugins/hashline-edit/tool-description.js +20 -4
- package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
- package/dist/plugins/system-context-injection/index.js +9 -4
- package/dist/plugins/system-context-injection/index.js.map +1 -1
- package/dist/plugins/web-tools/fetch-service.d.ts +8 -5
- package/dist/plugins/web-tools/fetch-service.js +30 -45
- package/dist/plugins/web-tools/fetch-service.js.map +1 -1
- package/dist/plugins/web-tools/index.js +23 -5
- package/dist/plugins/web-tools/index.js.map +1 -1
- package/dist/plugins/web-tools/schemas.d.ts +469 -0
- package/dist/plugins/web-tools/schemas.js +523 -0
- package/dist/plugins/web-tools/schemas.js.map +1 -0
- package/dist/plugins/web-tools/search-service.d.ts +6 -3
- package/dist/plugins/web-tools/search-service.js +24 -29
- package/dist/plugins/web-tools/search-service.js.map +1 -1
- package/dist/plugins/workflow/authority.d.ts +6 -0
- package/dist/plugins/workflow/authority.js +45 -10
- package/dist/plugins/workflow/authority.js.map +1 -1
- package/dist/plugins/workflow/authorization.js +16 -8
- package/dist/plugins/workflow/authorization.js.map +1 -1
- package/dist/plugins/workflow/checkpoints.d.ts +41 -2
- package/dist/plugins/workflow/checkpoints.js +176 -47
- package/dist/plugins/workflow/checkpoints.js.map +1 -1
- package/dist/plugins/workflow/delegated.d.ts +15 -1
- package/dist/plugins/workflow/delegated.js +65 -35
- package/dist/plugins/workflow/delegated.js.map +1 -1
- package/dist/plugins/workflow/execution.d.ts +15 -30
- package/dist/plugins/workflow/execution.js +133 -33
- package/dist/plugins/workflow/execution.js.map +1 -1
- package/dist/plugins/workflow/index.js +177 -112
- package/dist/plugins/workflow/index.js.map +1 -1
- package/dist/plugins/workflow/input-validation.d.ts +48 -0
- package/dist/plugins/workflow/input-validation.js +536 -0
- package/dist/plugins/workflow/input-validation.js.map +1 -0
- package/dist/plugins/workflow/inspection.d.ts +60 -0
- package/dist/plugins/workflow/inspection.js +316 -0
- package/dist/plugins/workflow/inspection.js.map +1 -0
- package/dist/plugins/workflow/protocol.d.ts +2 -0
- package/dist/plugins/workflow/protocol.js +26 -4
- package/dist/plugins/workflow/protocol.js.map +1 -1
- package/dist/plugins/workflow/recovery.d.ts +2 -1
- package/dist/plugins/workflow/recovery.js +79 -12
- package/dist/plugins/workflow/recovery.js.map +1 -1
- package/dist/plugins/workflow/repair.d.ts +1 -1
- package/dist/plugins/workflow/repair.js +9 -10
- package/dist/plugins/workflow/repair.js.map +1 -1
- package/dist/plugins/workflow/results.d.ts +2566 -0
- package/dist/plugins/workflow/results.js +1111 -0
- package/dist/plugins/workflow/results.js.map +1 -0
- package/dist/plugins/workflow/schemas.d.ts +214 -24
- package/dist/plugins/workflow/schemas.js +350 -89
- package/dist/plugins/workflow/schemas.js.map +1 -1
- package/dist/plugins/workflow/state.d.ts +3 -2
- package/dist/plugins/workflow/state.js +15 -8
- package/dist/plugins/workflow/state.js.map +1 -1
- package/dist/plugins/workflow/system-instruction.md +17 -1
- package/dist/plugins/workflow/tooling.d.ts +2 -18
- package/dist/plugins/workflow/tooling.js +477 -460
- package/dist/plugins/workflow/tooling.js.map +1 -1
- package/dist/plugins/workflow/transactions.d.ts +13 -0
- package/dist/plugins/workflow/transactions.js +13 -3
- package/dist/plugins/workflow/transactions.js.map +1 -1
- package/package.json +6 -3
- package/schemas/vvoc/v3.json +1 -1
- package/templates/agents/vv-code-reviewer.md +13 -4
- package/templates/agents/vv-controller.md +17 -0
- package/templates/agents/vv-implementer.md +20 -9
- package/templates/agents/vv-spec-reviewer.md +13 -4
- package/templates/skills/vv-execute/SKILL.md +3 -3
- package/templates/skills/vv-execute/references/tool-contracts.md +1750 -0
- package/templates/skills/vv-review/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 1.7.0 (2026-09-25)
|
|
2
|
+
|
|
3
|
+
### Summary
|
|
4
|
+
|
|
5
|
+
Version 1.7.0 refines the correctness and evidence discipline carried by vvoc-managed agent prompts and the universal guidance injected into primary sessions. Agents now keep an evidence-supported conclusion settled until a concrete trigger reopens it — contradictory evidence, a specific counterexample, a changed requirement, or changed relevant inputs — rather than flipping on vague doubt or unsupported pressure, and they surface false premises and investigate the actual mechanism instead of silently substituting a different goal or adding an unnecessary dependency. Test results are treated as evidence against the request and established contracts rather than as the authoritative specification, so a failing test that contradicts the agreed contract is reported rather than triggering automatic rewrites of code or tests, and conflicting or mutually exclusive reviewer findings are routed back to the controller instead of quietly redefining requirements. This matters because it keeps agent work anchored to the task contract and observed evidence, reduces churn and unrequested changes, and makes disagreements and unmet checks visible to users. In addition, the release tooling now defaults release changelog summary generation to the deepseek/deepseek-flash model, restoring reliable release summaries after the previous default began returning server errors.
|
|
6
|
+
|
|
7
|
+
* feat(prompts): refine evidence-based revision discipline ([4534b81](https://github.com/osovv/vv-opencode/commit/4534b81))
|
|
8
|
+
* fix(release): default release summary model to deepseek/deepseek-flash ([995656e](https://github.com/osovv/vv-opencode/commit/995656e))
|
|
9
|
+
|
|
10
|
+
## 1.6.0 (2026-09-24)
|
|
11
|
+
|
|
12
|
+
### Summary
|
|
13
|
+
|
|
14
|
+
Version 1.6.0 strengthens the public contract of all nine vvoc-owned agent tools so agents can call them reliably without reverse-engineering installed code. Every tool now publishes a closed input schema and rejects invalid or contradictory arguments before it mutates state, edits a file, or dispatches a provider request: unknown keys are refused instead of silently stripped, and a supplied value that conflicts with the chosen action or decision is diagnosed rather than ignored. Workflow failures now return machine-readable results with a stable error code and a category (input, state, authorization, host context, persistence, or internal) plus bounded, field-level issues, and outcomes stay truthful after side effects so a reporting failure is never misreported as a rejected call or an invitation to replay. `work_item_list` also gains read-only same-session inspection of work items and generic/native executions with the loaded package and contract identity, and a generated on-demand nine-tool reference ships with the vv-execute skill. Two new gates keep this honest: a read-only contracts check wired into `check` and `pack:check`, and an isolated live-host matrix exercised against the built package. Tool names, exports, schema v3, persistence v4, defaults, and authorization semantics are unchanged, so existing workflows keep working; the tightening only stops accepting calls whose constraints were previously dropped.
|
|
15
|
+
|
|
16
|
+
* chore(grace): apply and archive C-AGENT-TOOL-CONTRACTS ([df24116](https://github.com/osovv/vv-opencode/commit/df24116))
|
|
17
|
+
* feat(tools): enforce strict public contracts for all nine vvoc agent tools ([0831078](https://github.com/osovv/vv-opencode/commit/0831078))
|
|
18
|
+
|
|
1
19
|
## 1.5.0 (2026-09-22)
|
|
2
20
|
|
|
3
21
|
### Summary
|
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ grep '<COMPONENT-' .vvoc/specs/*/*.xml # component map across spec and plan
|
|
|
169
169
|
| **ModelRolesPlugin** | Semantic model roles (`vv-role:smart`, `vv-role:fast`, …) instead of hardcoded model IDs in agents, subagents, and commands — resolved per machine or project at startup. |
|
|
170
170
|
| **GuardianPlugin** | Keeps long or AFK runs moving by auto-approving routine low-risk permission requests; anything risky stays in OpenCode's normal manual approval flow. |
|
|
171
171
|
| **HashlineEditPlugin** | Routes each model to exactly one native edit tool (host `edit` for GLM/Qwen/Kimi, host `apply_patch` for GPT, `str_replace_editor` for DeepSeek, `hashline_edit` for unmatched models) and hides the other edit tools per session. |
|
|
172
|
-
| **SystemContextInjectionPlugin** | Injects universal guidance — including correctness obligations for behavior changes — plus the work policy selected by the orchestration profile into vv-controller at startup, and registers skill discovery; subagents stay unpolluted. |
|
|
172
|
+
| **SystemContextInjectionPlugin** | Injects universal guidance — including correctness obligations and evidence discipline for behavior changes — plus the work policy selected by the orchestration profile into vv-controller at startup, and registers skill discovery; subagents stay unpolluted. |
|
|
173
173
|
| **SecretsRedactionPlugin** | Redacts tokens, keys, emails, and other sensitive values before messages reach the model, restoring them only where local execution needs the originals. |
|
|
174
174
|
| **WebToolsPlugin** | Two provider-neutral tools — `web_search` and `web_fetch` — over Exa, Brave, Z.AI, native retrieval, or Spider, with permission checks and normalized output. |
|
|
175
175
|
| **ToolHistoryCompactionPlugin** | Shrinks the context replayed to the model by compacting old tool outputs non-destructively, without touching on-disk history. |
|
|
@@ -192,7 +192,7 @@ All prompt files are scaffolded by `vvoc install` / `vvoc sync`:
|
|
|
192
192
|
| `investigator` | Finds the root cause first when behavior is unclear or a failure needs diagnosis |
|
|
193
193
|
| `guardian` | Supports GuardianPlugin by reviewing permission requests and auto-approving only routine low-risk ones |
|
|
194
194
|
|
|
195
|
-
Managed prompts and the universal guidance injected into primary sessions carry explicit correctness obligations. For behavior changes, agents derive the material properties that must be preserved from the request and established contracts, separate write scope from impact and verification scope, investigate directly affected consumers, challenge a material assumption with a diagnostic counterexample, and choose verification at the level the risk arises. Controllers tie completion claims to observed evidence rather than status markers; reviewers distinguish no discovered defect from sufficient support for a material claim and can fail a change for a material verification gap. These obligations are prompt-level guidance only: `vvoc install` / `vvoc sync` deliver the current wording, changes take effect after an OpenCode restart like all vvoc config changes, and the bundled contract tests check instruction delivery and wording — they do not evaluate or guarantee how a real model behaves.
|
|
195
|
+
Managed prompts and the universal guidance injected into primary sessions carry explicit correctness obligations. For behavior changes, agents derive the material properties that must be preserved from the request and established contracts, separate write scope from impact and verification scope, investigate directly affected consumers, challenge a material assumption with a diagnostic counterexample, and choose verification at the level the risk arises. Controllers tie completion claims to observed evidence rather than status markers; reviewers distinguish no discovered defect from sufficient support for a material claim and can fail a change for a material verification gap. Agents also keep evidence-supported conclusions settled until a concrete trigger — contradictory evidence, a specific counterexample, a changed requirement, or changed inputs — reopens them; they surface false premises instead of silently satisfying them, distinguish unsupported pressure from concrete evidence, and interpret test results as evidence against the request and contracts rather than as the specification. These obligations are prompt-level guidance only: `vvoc install` / `vvoc sync` deliver the current wording, changes take effect after an OpenCode restart like all vvoc config changes, and the bundled contract tests check instruction delivery and wording — they do not evaluate or guarantee how a real model behaves.
|
|
196
196
|
|
|
197
197
|
### Managed skills
|
|
198
198
|
|
|
@@ -461,7 +461,7 @@ For review-only reports, use `"mode": "review_only"`. In review-only mode, revie
|
|
|
461
461
|
|
|
462
462
|
#### Delegated execution and review checkpoints
|
|
463
463
|
|
|
464
|
-
|
|
464
|
+
The workflow plugin registers two control tools — `work_item_decide` and `work_checkpoint` — for the primary vv-controller session independent of the startup profile. Registration is profile-independent; enforcement is not: child sessions, untrusted workspaces, and unverifiable session identity are denied by the root-controller guard.
|
|
465
465
|
|
|
466
466
|
Delegated tasks are opened with `"mode": "delegated"`, an explicitly empty `requiredReviewers` array, and a declared `writeScope` of workspace-relative files. One worker (`vv-implementer`) is launched per task with a bounded packet; attempts are bound to the host call identity, so stale or duplicate callbacks fail without side effects. A `DONE` worker parks the item in `awaiting_acceptance` — it never closes the item and the worker never accepts its own result. The controller explicitly decides with `work_item_decide`:
|
|
467
467
|
|
|
@@ -482,14 +482,14 @@ When a tracked subagent returns a recognized task envelope whose inner result is
|
|
|
482
482
|
|
|
483
483
|
Independent review happens at checkpoints declared in the plan. An approved delegated plan carries an `<execution><mode>delegated</mode>` section with `<review_checkpoints>` (`CHECKPOINT-R-NNN` identities, each with kind, wave barrier, covered tasks, reviewed scope files, reviewer set, acceptance criteria, and verification commands) and per-task `<write_scope>` lists. Registration accepts only this supported approved native plan package (the approved spec and plan pair under `.vvoc/specs/`); a provided plan or conversation-scoped execution stays on its own source and lifecycle rather than being converted into a native package. `work_checkpoint` handles these actions:
|
|
484
484
|
|
|
485
|
-
- `register` — with `planPath`, loads an approved active plan plus its linked approved spec, fully lints them, and binds the run to their content hashes and the canonical workspace root. With a generic `runId` instead, it appends checkpoints to that execution. Re-registering identical inputs is idempotent; changed approved inputs are explicit plan drift, never a progress reset.
|
|
485
|
+
- `register` — with `planPath`, loads an approved active plan plus its linked approved spec, fully lints them, and binds the run to their content hashes and the canonical workspace root. With a generic `runId` and its required `amendmentId` plus `rationale` instead, it appends a validated task batch (tasks and checkpoints) to that existing execution; it never starts a fresh run. Re-registering identical inputs is idempotent; changed approved inputs are explicit plan drift, never a progress reset.
|
|
486
486
|
- `start` — after every covered task is accepted, captures a fingerprint over the checkpoint scope (native scope files and existence, or the generic accepted-attempt coverage) and opens exactly the declared reviewer set as an ordinary `review_only` item. Writes overlapping an in-flight checkpoint scope are refused.
|
|
487
487
|
- `verify` — for native runs, derives `passed`, `failed`, `stale`, or `stopped` from the recorded reviewer results plus freshly recomputed fingerprints and approval hashes. A checkpoint passes only when every declared reviewer passes for the pinned snapshot; a closed review-only `FAIL` report is findings, not approval; edits during review make the generation stale. The final checkpoint seals the run only via `verify` with `complete: true` after every task is accepted, every earlier checkpoint passed, and the complete declared write scope is covered with fresh verification. Completion is refused while a declared reviewer is missing: a skipped reviewer is never fabricated into a pass.
|
|
488
|
-
- `review` / `bind` —
|
|
488
|
+
- `review` / `bind` — `review` records one generic reviewer result; `bind` is the outcome-recording alias that settles the generation from the linked review item's recorded result when every declared reviewer reported. The callID launch binding itself is a host hook, not this tool action.
|
|
489
489
|
- `complete` — complete a generic execution when every active task is accepted and every assigned checkpoint passed for the current revision, reporting `controller_accepted` or `independently_reviewed` honestly.
|
|
490
490
|
- `amend` — append validated tasks or checkpoints to a generic execution without replaying accepted work.
|
|
491
491
|
- `authorize` / `record_approval` / `revoke_authority` — record a bounded advance authority from an eligible root-user instruction, record a truthful controller-delegated stage approval, or revoke/narrow future authority credits.
|
|
492
|
-
- `recover` — bounded recovery for a checkpoint generation that stopped (`NEEDS_CONTEXT`) or exhausted its ordinary generations.
|
|
492
|
+
- `recover` — bounded recovery for a checkpoint generation that stopped (`NEEDS_CONTEXT`) or exhausted its ordinary generations. Common required fields are `diagnosis`, `changedCondition`, `verification`, and `recoveryId`. For a native-package checkpoint, recovery supports `userMessageId`: a stopped generation resumes, and an exhausted generation follows the one-unit autonomous-then-authorized policy (a fresh root-user message, or a recorded advance). For a generic checkpoint, `userMessageId` is rejected: a stopped generation is a cost-free bounded resume with no automatic budget reset, and only an *exhausted* generic checkpoint needs a recorded advance authority referenced by `runId` and `authorityId` — a stopped generic checkpoint does not require one. Recovering a stopped generation settles it into history as a `stopped` entry — it does not convert the stop into a failure, so checkpoint rework stays locked until a real failed generation exists — and recovering an exhausted checkpoint grants exactly one further generation with a fresh snapshot at the next `start`. Recovery never satisfies prerequisites, erases a `FAIL`, or seals a run: only the required passing final review does.
|
|
493
493
|
|
|
494
494
|
Passed milestones stay historical: later planned edits are covered by later checkpoints or the final gate, not by an old approval. Hard stops (`BLOCKED`, `NEEDS_CONTEXT`) are never reset or bypassed by acceptance or checkpoint handling; only a separately recorded recovery decision resumes the affected work. Checkpoint state persists per session and survives restarts; a persisted `PASS` is not fresh evidence until `verify` recomputes current hashes.
|
|
495
495
|
|
|
@@ -499,6 +499,26 @@ Delegated and checkpoint state persists under `$XDG_DATA_HOME/vvoc/workflow/<ses
|
|
|
499
499
|
|
|
500
500
|
Plans without an `<execution>` section keep their legacy meaning; executing them with different acceptance or review obligations requires an explicit agreed plan amendment, and archived plans are never rewritten. In a deterministic dispatch-count scenario, a twenty-task plan with two intermediate code-review checkpoints and one final spec+code checkpoint needs exactly four initial reviewer launches instead of forty — that is a property of the declared checkpoint policy, not a wall-clock or model-quality benchmark.
|
|
501
501
|
|
|
502
|
+
#### Public tool contracts and strict input
|
|
503
|
+
|
|
504
|
+
The nine vvoc-owned tools keep their existing names: `work_item_open`, `work_item_list`, `work_item_close`, `work_item_decide`, `work_checkpoint`, `hashline_edit`, `str_replace_editor`, `web_search`, and `web_fetch`. Every one now publishes a closed public input contract and rejects invalid or contradictory calls before it mutates state, edits a file, or dispatches a provider request.
|
|
505
|
+
|
|
506
|
+
This is an intentional compatibility tightening: unknown keys in a vvoc-controlled request object are rejected before mutation instead of being stripped, and a supplied value that conflicts with the selected operation or action is diagnosed instead of being silently ignored. A misspelled authority stage or reserved stop, alone or mixed with valid entries, rejects the entire authority operation — it is never filtered down to the valid subset — and cannot create an authority, claim an authorization message, consume reserve, or grant a launch. Missing optional fields keep their documented defaults; only *invalid supplied* fields are refused. Tool names, package exports, canonical vvoc config schema v3, and persistence snapshot version 4 are unchanged, no config or persistence migration is introduced, and runtime plugin changes still take effect only after an OpenCode restart.
|
|
507
|
+
|
|
508
|
+
The five workflow tools (`work_item_open`, `work_item_list`, `work_item_close`, `work_item_decide`, `work_checkpoint`) return workflow failures as machine-readable JSON carrying a stable `errorCode` plus a `category` — one of `input`, `state`, `authorization`, `host_context`, `persistence`, or `internal` — and bounded `issues` with tokenized argument paths, the violated expectation, and a safe value/type summary. The edit tools keep their existing human-readable `text`/`Error` result surface plus apply warnings rather than a JSON envelope, and the web tools keep their `ToolResult` text/metadata/attachment delivery. Web structural validation throws the bounded `ContractInputError`; provider failures keep the existing `WebProviderError` behavior (a provider-named code and message with no universal bounded-payload or JSON-shape promise). All nine share the same bounded field-level structural diagnostics, but the host is not promised to expose an output schema for any tool and edit/web output is not forced into JSON; the workflow JSON result shapes are a producer/test contract, not an assumed model-visible SDK feature. Owned structural and workflow diagnostics never echo a full payload and never parse free-form message prose to recover a lost field path; edit text and web document or binary content stay opaque. In particular:
|
|
509
|
+
|
|
510
|
+
- Invalid `execution.source.kind` is reported as an input error, not as a missing workspace root; a failed generic lookup is not disguised as a missing native-only argument.
|
|
511
|
+
- The generic execution descriptor accepts only `conversation-scoped` or a provided-plan variant carrying its bounded reference. The native-package path is not reachable through that descriptor: it loads only through the approved native `planPath` loader, with spec linkage, lint, and content-hash binding preserved.
|
|
512
|
+
- Standalone `implementation`/`review_only` items require a non-empty unique reviewer set and reject delegated write scopes or native plan bindings. Standalone `delegated` items require an empty reviewer set, an exact-file `writeScope`, and paired optional native bindings. Generic tasks accept an explicit empty or non-empty reviewer set and default `taskId` from `key` and `goal` from `title`.
|
|
513
|
+
|
|
514
|
+
Path contracts are explicit. `writeScope` entries are exact workspace-relative files and reject wildcards, absolute/home/drive paths, backslashes, traversal, empty segments, and a trailing separator; `boundary.directories` keeps its established one-trailing-separator directory-subtree normalization, so an exact file and a directory subtree are never conflated.
|
|
515
|
+
|
|
516
|
+
`work_item_list` is read-only over the current session and additively exposes generic and native executions alongside the existing `items` and `planRuns`, with the latest attempt status, current generations, remaining allowances, assigned obligations, and bounded prerequisites. The same response carries the loaded contract identity (`packageName`, `packageVersion`, `toolContractRevision`, and `referencePath`) so an agent can discover the exact reference material shipped with the running release; `toolContractRevision` is the loaded `AGENT_TOOL_CONTRACT_REVISION`. Guidance is snapshotted from the same eligibility gates the mutations use: it is a statement about current state, not a future permission, and it never promises a launch will still be available after concurrent state changes. Inspecting state or describing a recovery path neither grants recovery nor consumes a unit.
|
|
517
|
+
|
|
518
|
+
For a workflow mutation whose outcome is genuinely unknown — for example a post-side-effect reporting failure — the response never claims the change was untouched, never labels it a pre-execution input rejection, and never invites a blind replay; the truthful `committed`/`not_applied`/`rolled_back`/`unknown` outcome is preserved in the workflow result and the safe next step is to inspect with `work_item_list` before retrying. This workflow envelope is not forced onto the edit and web tools, which keep their own text/`Error` or `ToolResult` delivery.
|
|
519
|
+
|
|
520
|
+
The full nine-tool contract lives in `templates/skills/vv-execute/references/tool-contracts.md`. It is generated from the pure catalog (`bun run contracts:generate`), shipped with the skill, and kept honest by a coverage gate; it is loaded on demand from the shipped file, not generated when you read it. It is deliberately on-demand documentation rather than a manual injected on every turn, so load the section you need. A declared `writeScope` is an edit boundary, not a universal filesystem sandbox, and nothing here claims that free-form evidence strings mechanically prove a claim or that stricter schemas reduce model errors.
|
|
521
|
+
|
|
502
522
|
### Edit format routing
|
|
503
523
|
|
|
504
524
|
`HashlineEditPlugin` resolves an edit mode per session model and exposes exactly one native edit tool to that model — either a host-owned tool or one of the plugin profiles:
|
|
@@ -526,6 +546,8 @@ The default routing table sends `deepseek` to `str_replace_editor`, `kimi`, `qwe
|
|
|
526
546
|
|
|
527
547
|
Routing changes require an OpenCode restart, like other runtime plugin settings.
|
|
528
548
|
|
|
549
|
+
`hashline_edit` and `str_replace_editor` publish closed input contracts and reject conflicting or malformed fields before touching a file, without changing literal edit behavior: `replace` keeps its optional inclusive `end` (the `replace_range` alias still works), `lines` accepts a string, a string array, or `null` (an empty array or `null` deletes the range), `append`/`prepend` perform boundary insertion, `new_str` may be intentionally empty to delete, and `view_range` may end at `-1` to view to end of file. Supplying conflicting anchors, an unknown field, or a malformed range is a structural error that leaves file content, paths, freshness metadata, and the metadata sink unchanged, and the existing current-file and stale-anchor checks stay authoritative before any mutation.
|
|
550
|
+
|
|
529
551
|
### Tool history compaction
|
|
530
552
|
|
|
531
553
|
`ToolHistoryCompactionPlugin` shrinks the context replayed to the model on every turn without touching on-disk storage. It rewrites only the in-memory message copy through the `experimental.chat.messages.transform` hook, and only the `output` of old completed tool parts — `input` and part structure (callID/type/order) are never changed, so provider tool_use/tool_result stitching stays intact.
|
|
@@ -663,6 +685,8 @@ The `web-tools` vvoc plugin toggle is enabled by default. Provider selection bel
|
|
|
663
685
|
|
|
664
686
|
Supported search providers are `exa` (default), `brave`, and `zai`. Supported fetch providers are `native` (default, no credential required), `spider`, and `zai`. A `zai` section must set `region` to either `international` or `china`; the plugin never guesses or falls back to another region.
|
|
665
687
|
|
|
688
|
+
Both tools validate a closed caller contract before any provider dispatch. `web_search` accepts `query`, an optional `count` (1–20), and an optional `freshness`; `web_fetch` accepts a URL, an optional `format`, and an optional `timeout` in seconds greater than 0 and at most 120 (fractional values such as `0.5` are allowed). Unknown keys, an invalid URL scheme or shape, or an out-of-range provided value are rejected before the permission prompt or any provider request, so no provider is dispatched and no network call is made. Provider credentials are resolved from configuration once at startup as described below; structural validation only prevents the permission prompt, provider dispatch, and network use, and does not re-resolve or override that startup resolution. Document text, binary/media content, and per-call provider or credential selection are never part of the caller contract. Defaults are applied at execution time even when OpenCode forwards raw, unparsed arguments, so the effective behavior is unchanged: an omitted `count` is 8, an omitted `format` is `markdown`, and an omitted `timeout` is 30 seconds (bounded at 120). Provider and credential configuration is still resolved once at startup from `vvoc.json`; changing it takes effect only after restarting OpenCode through the same `vvoc sync` and restart flow as before.
|
|
689
|
+
|
|
666
690
|
Direct Z.AI endpoint routing:
|
|
667
691
|
|
|
668
692
|
| Region | Search | Reader | Search engine |
|
|
@@ -706,12 +730,19 @@ The `context` vvoc plugin toggle defaults to enabled. Disable it with `vvoc plug
|
|
|
706
730
|
## Local development
|
|
707
731
|
|
|
708
732
|
```bash
|
|
709
|
-
bun install
|
|
710
|
-
bun run check
|
|
711
|
-
bun run fmt
|
|
712
|
-
bun run
|
|
733
|
+
bun install # Install dependencies
|
|
734
|
+
bun run check # Typecheck + lint + format check + GRACE markup + tool-contract check + test
|
|
735
|
+
bun run fmt # Auto-format source files
|
|
736
|
+
bun run contracts:check # Read-only nine-tool contract completeness gate
|
|
737
|
+
bun run contracts:generate # Regenerate the on-demand tool-contracts reference
|
|
738
|
+
bun run contracts:host # Isolated live-host contract gate (see below)
|
|
739
|
+
bun run release:check # Verify package/schema release consistency
|
|
713
740
|
```
|
|
714
741
|
|
|
742
|
+
`bun run contracts:check` is a repository-only, read-only gate: it censuses owned tool registrations independently of the catalog, executes every catalog fixture through the real validators and result schemas, and fails on a fake tool, a missing fixture or result variant, an opaque known object, a changed default, or a stale generated reference. It is part of `bun run check` and requires no network or host process. Run `bun run contracts:generate` only as a deliberate, reviewed step when a contract change is intended — the generated file is checked for currency, so editing it by hand fails the gate.
|
|
743
|
+
|
|
744
|
+
`bun run contracts:host` proves the same contract against the real host. It requires a locally installed `opencode` at the pinned live version (1.18.32 recorded by the current evidence), a current `bun run build` (it exercises the built `dist/` plugins), and the existing evidence target directory `.grace/changes/active/C-AGENT-TOOL-CONTRACTS/`. The runner only checks that this directory exists: it does not validate the GRACE approval state and it does not accept an arbitrary active bundle. It never creates or recreates the directory, never writes into an archive, and never finalizes lifecycle state — approval and lifecycle are owned by the GRACE controller. It creates disposable HOME/XDG/config/workspace directories, uses only local built plugin URLs, synthetic agents/messages/credentials, and loopback OpenAI-compatible and Anthropic-compatible responders, and it sends no real provider or paid request. `bun scripts/check-tool-contracts-host.ts --probe` runs the minimal host-seam feasibility test, while the default full run executes the nine-tool matrix and writes `compatibility-evidence.json` only on a full observed pass; a missing executable, an unsupported host version, or any failed scenario exits nonzero instead of recording a skipped success. The generated evidence is one of three distinct levels and never stands in for the separately executed SDK-floor/normalizer unit fixtures (the pinned 1.18.2 projection plus OpenAI/Anthropic/Google lowering fixtures) or for real remote-provider acceptance and model quality.
|
|
745
|
+
|
|
715
746
|
Git hooks are managed via `lefthook`.
|
|
716
747
|
|
|
717
748
|
Smoke-test the built CLI against an isolated config home:
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { ZodRawShape, ZodType } from "zod";
|
|
2
|
+
import { type ContractIssue, type OwnedToolContract } from "./agent-tool-contract.js";
|
|
3
|
+
/** One checked positive/negative input fixture with independent coverage metadata. */
|
|
4
|
+
export interface CatalogOperation {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
readonly expect: "accept" | "reject";
|
|
8
|
+
readonly input: Record<string, unknown>;
|
|
9
|
+
/** Vocabulary field path to value this operation positively covers. */
|
|
10
|
+
readonly covers?: Readonly<Record<string, string>>;
|
|
11
|
+
/** Independent negative-scenario tags (e.g. unknown_key, missing_required). */
|
|
12
|
+
readonly tags?: readonly string[];
|
|
13
|
+
/** State/host prerequisites the fixture does not itself establish. */
|
|
14
|
+
readonly prerequisites?: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
/** A model-facing closed vocabulary for one discriminated input field. */
|
|
17
|
+
export interface CatalogVocabulary {
|
|
18
|
+
readonly field: string;
|
|
19
|
+
readonly values: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/** An execute-time default applied by a tool schema. */
|
|
22
|
+
export interface CatalogDefault {
|
|
23
|
+
readonly field: string;
|
|
24
|
+
readonly value: unknown;
|
|
25
|
+
readonly note: string;
|
|
26
|
+
}
|
|
27
|
+
/** Declared meaning and rules for one path argument. */
|
|
28
|
+
export interface CatalogPathKind {
|
|
29
|
+
readonly field: string;
|
|
30
|
+
readonly kind: "exact-file" | "directory-subtree" | "absolute-file" | "url";
|
|
31
|
+
readonly rules: string;
|
|
32
|
+
}
|
|
33
|
+
/** One checked result-family fixture for a tool. */
|
|
34
|
+
export interface CatalogResultVariant {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly label: string;
|
|
37
|
+
readonly fixture: unknown;
|
|
38
|
+
}
|
|
39
|
+
/** Representative failure diagnostic path/expectation. */
|
|
40
|
+
export interface CatalogErrorExample {
|
|
41
|
+
readonly path: string;
|
|
42
|
+
readonly expectation: string;
|
|
43
|
+
}
|
|
44
|
+
/** Structural validation outcome exposed for fixture checks. */
|
|
45
|
+
export interface CatalogValidationResult {
|
|
46
|
+
readonly ok: boolean;
|
|
47
|
+
readonly data?: unknown;
|
|
48
|
+
readonly issues?: readonly ContractIssue[];
|
|
49
|
+
}
|
|
50
|
+
/** Aggregated catalog entry for one owned tool. */
|
|
51
|
+
export interface AgentToolCatalogEntry {
|
|
52
|
+
readonly toolId: string;
|
|
53
|
+
readonly summary: string;
|
|
54
|
+
readonly contract: OwnedToolContract<ZodRawShape>;
|
|
55
|
+
readonly validate: (raw: unknown) => CatalogValidationResult;
|
|
56
|
+
readonly resultSchema: ZodType;
|
|
57
|
+
readonly vocabularies: readonly CatalogVocabulary[];
|
|
58
|
+
readonly operations: readonly CatalogOperation[];
|
|
59
|
+
readonly defaults: readonly CatalogDefault[];
|
|
60
|
+
readonly prerequisites: readonly string[];
|
|
61
|
+
readonly conditionals: readonly string[];
|
|
62
|
+
readonly pathKinds: readonly CatalogPathKind[];
|
|
63
|
+
readonly results: readonly CatalogResultVariant[];
|
|
64
|
+
readonly errors: readonly CatalogErrorExample[];
|
|
65
|
+
readonly normalization: readonly string[];
|
|
66
|
+
}
|
|
67
|
+
/** Package-relative path of the generated reference document. */
|
|
68
|
+
export declare const CONTRACT_REFERENCE_PACKAGE_PATH = "templates/skills/vv-execute/references/tool-contracts.md";
|
|
69
|
+
/**
|
|
70
|
+
* Recorded pre-change contract-size baseline with provenance.
|
|
71
|
+
* Measured once from the clean starting commit; future checks compare against the
|
|
72
|
+
* catalog-derived current measurement rather than reading mutable git history.
|
|
73
|
+
*/
|
|
74
|
+
export declare const CONTRACT_SIZE_BASELINE: {
|
|
75
|
+
readonly provenance: {
|
|
76
|
+
readonly commit: "f4319f8";
|
|
77
|
+
readonly sdk: "@opencode-ai/plugin@1.18.2";
|
|
78
|
+
readonly method: "source-extraction";
|
|
79
|
+
readonly detail: "UTF-8 byte sizes measured at the clean starting commit f4319f8 by extracting each owned tool's model-facing description string and projecting its pre-change registered argument map with the pinned SDK (io:\"input\"). This is a declaration/projection size, not a provider-exact token count and not a model-quality or model-effectiveness claim.";
|
|
80
|
+
readonly procedure: "Reproduce the baseline: `git show f4319f8:<tool-source> | extract the model-facing description`, then project each pre-change registered argument map with @opencode-ai/plugin@1.18.2 via tool.schema.toJSONSchema(schema, { io: \"input\" }) and sum Buffer.byteLength(value, \"utf8\"). \"After\" is the catalog-derived `measureCatalogContractSize()` value printed below as \"Current model-facing size\"; compare it to this baseline. Numbers reported are exact UTF-8 byte counts, never estimated token counts.";
|
|
81
|
+
};
|
|
82
|
+
readonly before: {
|
|
83
|
+
readonly descriptionBytes: 8796;
|
|
84
|
+
readonly inputSchemaBytes: 6815;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
/** The nine owned tool catalog entries in stable registration order. */
|
|
88
|
+
export declare const agentToolCatalog: readonly AgentToolCatalogEntry[];
|
|
89
|
+
/** Sorted tool ids covered by the catalog. */
|
|
90
|
+
export declare const AGENT_TOOL_CATALOG_TOOL_IDS: readonly string[];
|
|
91
|
+
/** Sorted tool ids covered by the catalog. */
|
|
92
|
+
export declare function catalogToolIds(): string[];
|
|
93
|
+
/** Current description/input-schema UTF-8 byte measurement derived from the catalog. */
|
|
94
|
+
export declare function measureCatalogContractSize(entries?: readonly AgentToolCatalogEntry[]): {
|
|
95
|
+
descriptionBytes: number;
|
|
96
|
+
inputSchemaBytes: number;
|
|
97
|
+
totalBytes: number;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Run every catalog fixture through the actual exporting validator, and every
|
|
101
|
+
* result-family fixture through the actual result schema. This is the shared
|
|
102
|
+
* fixture gate used by both the catalog test and scripts/check-tool-contracts.ts.
|
|
103
|
+
*/
|
|
104
|
+
export declare function validateAgentToolCatalog(): {
|
|
105
|
+
ok: boolean;
|
|
106
|
+
failures: string[];
|
|
107
|
+
checked: number;
|
|
108
|
+
};
|
|
109
|
+
/** One ancestor union option that a fixture must also satisfy for a nested branch. */
|
|
110
|
+
export interface ResultBranchAncestor {
|
|
111
|
+
readonly valuePath: readonly string[];
|
|
112
|
+
readonly schema: unknown;
|
|
113
|
+
}
|
|
114
|
+
/** One union branch location reachable from a result schema, with its fixture value path. */
|
|
115
|
+
export interface ResultBranchLocation {
|
|
116
|
+
readonly path: string;
|
|
117
|
+
readonly valuePath: readonly string[];
|
|
118
|
+
readonly schema: unknown;
|
|
119
|
+
readonly ancestors: readonly ResultBranchAncestor[];
|
|
120
|
+
}
|
|
121
|
+
export declare function collectResultBranches(schema: unknown): ResultBranchLocation[];
|
|
122
|
+
/** Result-schema union branches a single catalog entry's fixtures do not cover. */
|
|
123
|
+
export declare function resultBranchGaps(entry: AgentToolCatalogEntry): string[];
|
|
124
|
+
/** Result-schema union branches not covered by any catalog result fixture. */
|
|
125
|
+
export declare function resultCoverageGaps(entries?: readonly AgentToolCatalogEntry[]): string[];
|
|
126
|
+
/**
|
|
127
|
+
* Find arbitrary (non-closed) object or unconstrained nodes in a published input schema.
|
|
128
|
+
* A node is opaque when it accepts an arbitrary value: an object that does not close
|
|
129
|
+
* `additionalProperties` to false (including a missing `additionalProperties`), an empty
|
|
130
|
+
* or keyword-free schema, a `true` schema, or an unresolvable `$ref`. Known object
|
|
131
|
+
* properties, unions (`anyOf`/`oneOf`/`allOf`), array items, and resolvable local refs
|
|
132
|
+
* are visited. Genuine opaque input regions are not permitted for public inputs; there is
|
|
133
|
+
* no whole-tool exemption.
|
|
134
|
+
*/
|
|
135
|
+
export declare function findOpaqueInputObjects(schema: unknown, basePath?: string, root?: unknown, visiting?: ReadonlySet<string>): string[];
|
|
136
|
+
/**
|
|
137
|
+
* Render the deterministic, on-demand tool-contracts reference from the catalog.
|
|
138
|
+
* No timestamps, absolute paths, or environment values are embedded, so the
|
|
139
|
+
* output is byte-stable and can be checked for currency by `bun run contracts:check`.
|
|
140
|
+
* Each checked example's outcome is derived from running the actual validator, so
|
|
141
|
+
* mislabeled metadata cannot be published as a passing example. `entries` is
|
|
142
|
+
* injectable so self-tests can validate an isolated catalog without the global one.
|
|
143
|
+
*/
|
|
144
|
+
export declare function renderToolContractsReference(entries?: readonly AgentToolCatalogEntry[]): string;
|