Skip to content

feat(binding): support composite capability inputs - #67

Merged
jmgilman merged 2 commits into
masterfrom
feat/composite-inputs
Oct 6, 2026
Merged

jmgilman merged 2 commits into
masterfrom
feat/composite-inputs

Conversation

@jmgilman

@jmgilman jmgilman commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Capability inputs now accept the same structural types as outputs (with a few direction-specific exceptions), so agents can pass lists, dicts, and nested objects to capabilities.

  • Supported input types (recursive): string, bool, every signed/unsigned integer width (range-checked), float32/float64, *T (optional), []T (list or tuple; []byte = list of 0–255), map[string-kind]T, and nested structs (dicts with exactly the declared keys).
  • Rejected for inputs: arrays, interfaces, channels, funcs, complex, pointer-to-pointer, non-string map keys, recursive types, and json.Unmarshaler / encoding.TextUnmarshaler types (e.g. time.Time).
  • Ints accepted for float fields (they appear as float64 in canonical arguments).
  • Relaxed names: nested input names and all output names only need to be valid encoding/json tag names (e.g. from, created-at); notation quotes non-identifiers. Root input names stay Starlark identifiers (keyword arguments).
  • Diagnostics name the exact path: filter.owner, tags[1], labels['env'], window['until-day'], with "or None" for optional values and range messages for narrow integers.
  • Authorization: canonical arguments may now contain nested map[string]any / []any. Optional struct members that are omitted or None are absent at every level.

Design

  • One shared type compiler (internal/binding/compile.go) builds a post-order node arena for inputs and outputs with per-direction rules.
  • The input arena projects to a process-neutral binding.InputSchema that replaces the flat []FieldShape in the worker manifest and execution.CapabilityBinding. The worker validates it once at load and binds Starlark values against it, so model-facing detail stays child-origin (session 012 rule).
  • The parent re-binds the worker's canonical map against the same arena by reflection, so the authorizer sees exactly what the handler receives.
  • Model-facing FieldShape and the MCP schema stay flat; only the type strings got richer.

Prototyped in a throwaway spike first; this is the clean implementation.

Testing

  • go test -race ./... passes; golangci-lint run ./... reports 0 issues; moon run docs:build passes.
  • New unit tests: composite notation, bind/rebind round trip, exact diagnostics, parent wire-mismatch defense, schema JSON round trip, malformed-schema rejection.
  • New integration tests in internal/execution and internal/worker (real worker subprocess) carrying composite arguments.
  • New e2e TestActualMCPCompositeInputProgram (added to mcp-smoke): describe → execute over MCP → typed handler input + nested canonical authorization map; malformed calls return exact path diagnostics and never reach policy.
  • The composite example in docs/docs/reference/public-api.md was checked by running its exact signature and canonical maps against the implementation.

Inputs now bind lists, string-keyed dicts, nested structs, optionals, and
every integer and float width through one shared input/output type compiler.
The worker binds against a private post-order InputSchema; the parent
re-binds the canonical map by reflection before authorization.

Ints are accepted for float fields. Nested input and all output field names
only need to be valid JSON names; root input names stay Starlark identifiers.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T17:12:52.957424Z 029e45f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 029e45fa6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/binding/input.go
Comment on lines +90 to +91
target.SetFloat(checked)
return checked, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Canonicalize float32 values after narrowing

When a capability input contains a float32 field, SetFloat narrows the validated float64, but the canonical authorization map receives the original value. For example, a Starlark 0.1 is authorized as its float64 representation while the handler receives the different float32-rounded value; a boundary-based policy can therefore authorize a value other than the one acted upon. Return the widened value read back from target after assignment so authorization and handler inputs remain identical.

Useful? React with 👍 / 👎.

Address review findings on composite inputs:
- Worker Bind charges every argument node against MaxValueDepth and the
  MaxValueBytes-derived node budget before materializing, so aliased
  Starlark containers fail with ErrResourceLimit instead of expanding.
- Diagnostic paths are a push/pop segment stack rendered only on error,
  making worker Bind and parent BindValue linear in argument size.
- float32 inputs canonicalize to the rounded float32 value so policy sees
  exactly what the handler receives.
@jmgilman
jmgilman merged commit c777839 into master Oct 6, 2026
7 checks passed
@jmgilman
jmgilman deleted the feat/composite-inputs branch October 6, 2026 18:01
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