Skip to content

feat(codemode): unify parallel() calling convention with the sequential ns.tool() form#7

Merged
revitteth merged 1 commit into
mainfrom
feat/codemode-parallel-unify
Jul 23, 2026
Merged

feat(codemode): unify parallel() calling convention with the sequential ns.tool() form#7
revitteth merged 1 commit into
mainfrom
feat/codemode-parallel-unify

Conversation

@revitteth

Copy link
Copy Markdown
Contributor

What

parallel() now accepts bound tool references in the same call form as the sequential path, in addition to the legacy string descriptor:

// New — matches how you already call tools sequentially:
parallel([[github.list_issues, {repo}], [linear.search, {query}]]);   // [fn, args] tuple
parallel([{tool: github.list_issues, args: {repo}}, ...]);            // object form, bound ref

// Still works (backward compatible):
parallel([{tool: "github__list_issues", args: {repo}}, ...]);        // legacy string

Why

The concurrent path required a separate string-descriptor convention that diverged from the natural ns.tool(args) sequential form. That mismatch is a recurring agent error source (wrong __ name, args nested wrong) and a second mental model for "call a tool." Unifying them means the multi-call path reads like the one-call path.

How

  • Each tool function is tagged with its canonical ns__name in a hidden (non-enumerable, non-writable) own property (tagToolFunc). parallel() recovers the name from a passed reference and dispatches via the same Go-goroutine concurrency as before — real concurrency is preserved; only the surface changes.
  • parseParallelArgs walks the live Goja values (not Export(), which erases the tag) to classify tuple vs object items and resolve the tool slot (function or string) and args.
  • Bonus consistency fix: no-arg parallel calls now send {} (matching the sequential marshalToolArgs) instead of null, in both dispatch and the audit record — a downstream tool expecting an object could reject null.
  • help() and both execute_code tool descriptions advertise the new form.

Tests

  • Bound tuple / object / mixed-batch dispatch with arg round-trip assertions
  • Non-tool closure rejected with an actionable message
  • Hidden tag invisible to Object.keys()
  • No-arg {} normalization
  • All existing string-descriptor tests unchanged (backward compat)

Isolated build (go build -tags p2p ./...) and go test ./internal/codemode/ green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MW9JEiRKg9zVffe14ybKGm

…al ns.tool() form

The concurrent path required a separate string-descriptor convention
(parallel([{tool: "ns__name", args}, ...])) that diverged from the natural
sequential form (ns.tool(args)) — a recurring agent error source and extra
mental model. parallel() now also accepts bound tool references, matching the
sequential call form:

  parallel([[github.list_issues, {repo}], [linear.search, {query}]])  // tuple
  parallel([{tool: github.list_issues, args}, ...])                   // object + ref

Each tool function carries its canonical "ns__name" in a hidden
(non-enumerable) property so parallel() recovers the name for concurrent
Go-goroutine dispatch — real concurrency is preserved; only the surface
changes. The legacy string form still works, so this is backward compatible.

Also normalizes no-arg parallel calls to send "{}" (matching the sequential
marshalToolArgs) instead of "null", which a downstream tool expecting an
object could reject — the two paths now send identical shapes for identical
calls, in dispatch and in the audit record.

help() and the execute_code tool descriptions advertise the new form.

Tests: bound tuple/object/mixed dispatch with arg round-trip, non-tool-closure
rejection, hidden-tag invisibility to Object.keys, and the no-arg "{}"
normalization; existing string-descriptor tests unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MW9JEiRKg9zVffe14ybKGm
@revitteth
revitteth merged commit 17822c5 into main Jul 23, 2026
4 checks passed
@revitteth
revitteth deleted the feat/codemode-parallel-unify branch July 23, 2026 20:16
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.

1 participant