CreateInProcessClient, then had to
re-implement the unexported round tripper to use sub-agents.createInProcessClient shipped in 0.16.0 as the semantic seam: Generate(request) -> response, no HTTP types. It is the answer to "my model is in this process".
agents.Options did not get the memo. It takes Transport http.RoundTripper and
LLM *LLMOptions (golang/agents/runtime.go:270-287) and nothing else. So a host
whose model is a function has exactly one way to reach the sub-agent runtime:
copy inProcessRoundTripper — the request decode, choices[0].message assembly,
finish_reason derivation, argument encoding, the usage block, the streaming
refusal — into its own tree, tracking an unexported file it cannot import.
That copy is guaranteed drift. It is also a parity trap: the same gap almost
certainly exists in the other six ports' sub-agent wiring, and nothing in CI would
notice, because options_manifest.json governs client options, not agent options.
The reporter offers three shapes. They are not equivalent:
InProcessTransport(generate) http.RoundTripper.
Smallest diff, and CreateInProcessClient becomes its caller. But it is
Go-shaped: it hands back an http.RoundTripper, the very HTTP type the semantic
seam exists to avoid, and four ports have no such type to hand back.agents.Options.InProcess *InProcessOptions — semantic, ports cleanly, but
adds a third mutually-exclusive way to configure a runtime's model (Transport |
LLM | InProcess), and mutually-exclusive option triples are how config bugs
are born.client.Transport() — same HTTP-shaped objection as (1), plus it implies
every client has a transport, which for four ports is a fiction.Prefer (2), expressed as one semantic field, with (1) as the Go-local convenience
— i.e. the cross-port contract is "a sub-agent runtime accepts a Generate", and Go
additionally exports the round tripper because Go hosts genuinely wire transports.
The mutually-exclusive triple is made safe by validating it at construction and
erroring, never by precedence rules.
The draft claimed four ports "have no HTTP type to hand back", making shape 1 a parity
hazard. Overstated. Every port already builds an analogous adapter privately — Java's
GenerateBackedHttpClient, C#'s GenerateBackedHandler, Python's _InProcessTransport,
plain functions in Elixir and Clojure. Exporting it is mechanically available everywhere,
merely cheaper in the dynamic ports.
Shape 3 (client.transport()) is dropped: the same new-accessor work in every port, for no
benefit over exporting the adapter.
GenerateBackedHandler.SendAsync
never yielded, so turns ran fully synchronously inside the runtime lock — shipped
behaviour since 0.16.0, affecting anyone using the in-process client there.GatedHttpClient had a hardcoded delegate and now takes one by constructor.openspec/changes/add-in-process-subagents/.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |