Skip to content

fix(v2): register tools with the opencode2 API shape - #8

Closed
rorshopping wants to merge 1 commit into
masterfrom
fix/v2-tools
Closed

fix(v2): register tools with the opencode2 API shape#8
rorshopping wants to merge 1 commit into
masterfrom
fix/v2-tools

Conversation

@rorshopping

Copy link
Copy Markdown
Collaborator

What

Fixes the opencode2 tool registration in packages/v2. The four bili_* tools were registered as raw V1 ToolDef objects, but opencode2's tools.add() expects the AI-SDK-style shape: { name, description, input (JSON schema), execute(input, ctx) }.

Also fixes a non-idempotent system-prompt injection in the V2 context hook.

Changes

  • packages/v2/src/tools.ts (new) — V2 wrappers over @bili/core's tool makers:
    • name (bili_compress / bili_decompress / bili_search / bili_status)
    • input: JSON-schema (was zod args; V2 Info.input is a ValueSchema, the zod object was never usable as a schema)
    • execute(input, ctx) maps the V2 ToolContext ({ sessionID, agent?, messageID?, id, progress? }) onto the V1 ToolContext (callID: ctx.id, no directory/worktree) and returns { content } (V2 Tool.Result)
  • packages/v2/src/index.ts — register the V2-shaped tools; SYSTEM_MARKER changed from "BILI CONTEXT MANAGEMENT" to "ACP TOOLS (billion-context)" (the actual header line of @bili/core's SYSTEM_PROMPT). Previously findIndex never matched, so a duplicate system prompt was appended on every dispatch.
  • packages/v2/smoke.mjs (new) + smoke script — regression test asserting the tool shape, idempotent system upsert, end-to-end hook→compress→search→decompress flow, and that compressCallId maps from V2 ctx.id.

Verification

  • npm run typecheck (all workspaces) — pass
  • npm test (v1) — 26/26 pass
  • npm run build (v1 + v2) — pass
  • npm run smoke --workspace billion-context-opencode-v2 — all assertions pass (tool shape, idempotent tags, bili_status/bili_compress/bili_search/bili_decompress return { content }, compressCallId = V2 call id)

Notes

  • @bili/core keeps its V1 ToolDef untouched — the V2 adaptation lives in packages/v2 only.
  • Not covered here: the compressToolName pairing fix (kernel hardcodes 'compress'; consumed bili_compress invocations leak). Kernel change is PR-ready on rorshopping/acp-kernel; happy to follow up.

@rorshopping

Copy link
Copy Markdown
Collaborator Author

Verified & ready to merge — requesting approval.

The fixed build was installed as the plugin in the running opencode2 and confirmed live; the full suite is green:

  • typecheck (all workspaces) ✓
  • v1 tests: 26/26 ✓
  • build v1+v2 ✓
  • v2 smoke (packages/v2/smoke.mjs): all pass ✓ (tools shape, idempotent system upsert, compressCallId mapping, compress/search/decompress flow)
  • same smoke against the installed bundle in \plugins/acp_ocv2\ ✓
  • plugin loaded into opencode2, verified via \�ili_status\

Known follow-up (not part of this PR): the \compressToolName\ kernel fix on
orshopping/acp-kernel\ (commits 9666436 + ec9b85d) — until that lands, consumed \�ili_compress\ call+result pairs can remain visible in context (cosmetic, no crash).

@ranxianglei

Copy link
Copy Markdown
Owner

@rorshopping heads up — repo contribution policy update 🎉

master branch protection has been relaxed so you can drive this repo autonomously without waiting on maintainer approval.

What changed: required_approving_review_count is now 0 (was 1). You no longer need an approving review from @ranxianglei to merge.

What this means for you:

Guardrails still in place (unchanged):

  • ✅ CI must pass: build (typecheck + tests on Node 22/24) and pr-validation (branch-name + devlog/changelog checks).
  • ✅ No force-push to master; PRs only (can't push straight to master).
  • @ranxianglei stays admin and can override anytime.

Soft ask: for external-contributor PRs (@5258MF's), please give the code a quick eyeball before merging — the review gate is now voluntary rather than enforced. For your own PRs you're trusted.

Your Write access (push/triage) is active. Feel free to triage the open PRs, rebase/merge what's ready, and keep pushing V2 work. Welcome to drive the repo. 🚀

@ranxianglei

Copy link
Copy Markdown
Owner

Closing as superseded by #18 (now merged). Huge thanks @rorshopping — you correctly identified and fixed two real bugs, and both were confirmed present on master:

  1. V2 tool registration shapesetupV2 was spreading the V1 ToolDef ({ description, args(zod), execute(args, ToolContext) }) straight into tools.add(), but opencode V2 needs { name, description, input(JSON Schema), execute(input, ctx) → { content } }. So the four bili_* tools had no name, a zod object instead of a JSON Schema, and an unmapped execute ctx.
  2. Non-idempotent system promptSYSTEM_MARKER was "BILI CONTEXT MANAGEMENT" while SYSTEM_PROMPT actually begins with ACP TOOLS (billion-context), so the upsert never matched and a duplicate system prompt was appended every dispatch.

Why this PR wasn't merged directly, and your fixes were ported instead:

  • This PR ships the fixes as a second package packages/v2/ (billion-context-opencode-v2). The project deliberately went the other way — AGENTS.md §2.3 makes the dual-shape single package load-bearing: export default Object.assign(biliAcpPluginV1, { id, setup: setupV2 }) — one callable function that also carries { id, setup }, so the same package loads on both opencode V1 (calls it) and V2 (reads .id/.setup). It explicitly says "Do not refactor the dual-shape export into two separate entries." master removed packages/v2/ precisely to adopt dual-shape, which is also why this PR's base predates that removal and shows as conflicted.
  • So the right home for these fixes is the existing setupV2 in packages/billion-context-opencode/src/index.ts, which is exactly what fix(v2): register tools with AI-SDK shape + idempotent system prompt #18 does.

What landed in #18 (your work, credited):

  • New src/v2-tools.tstoV2Tool(name, tool) wraps V1 → V2 shape, maps the V2 ctx onto the V1 ToolContext (callID ← ctx.id, empty directory/worktree), unwraps the result to { content }.
  • One improvement over this PR: the input JSON Schema is derived via z.toJSONSchema(z.object(tool.args)) (zod 4.4.3, already bundled) rather than hand-written, so it can't drift from the zod definitions.
  • SYSTEM_MARKER corrected to "ACP TOOLS (billion-context)".
  • 4 regression tests (shape, schema projection, ctx mapping, marker idempotency). Typecheck ✅, 54/54 tests ✅, build ✅ (677 KB, zero new deps), smoke ✅.

You're credited in the #18 commit message and PR description. The one thing neither this PR nor #18 covers is the kernel hardcoding the generic tool name 'compress' in its call↔result pairing — you mentioned you have that PR-ready on rorshopping/acp-kernel; that'd be a great follow-up there.

Thanks again for the solid diagnosis. 🙇

@ranxianglei

Copy link
Copy Markdown
Owner

前面的我尽可能的都合并了,新进来再修可能的问题.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants