Skip to content

feat: dynamic tool factories + unified HTTP request architecture#38

Merged
v3g42 merged 21 commits intoclaude/multi-entry-workflows-XrOSsfrom
chore/http-request-tool
Mar 29, 2026
Merged

feat: dynamic tool factories + unified HTTP request architecture#38
v3g42 merged 21 commits intoclaude/multi-entry-workflows-XrOSsfrom
chore/http-request-tool

Conversation

@v3g42
Copy link
Copy Markdown
Contributor

@v3g42 v3g42 commented Mar 29, 2026

Summary

  • Dynamic tool factories — new [[tools.dynamic]] config in agent definitions creates named API tools at runtime. First factory type: http — bakes in base_url and default headers
  • Typed HTTP structsHttpRequestInput, HttpRequestResponse, HttpFactoryConfig replace raw JSON parsing
  • Variable resolution extracted to distri-types — shared across crates
  • distri-formatter crateFormatter trait + TextFormatter for CLI and gateway
  • Builtin tool validation — agent push rejects unknown tool names
  • ExternalToolRegistry Send fix — RwLockReadGuard no longer held across .await
  • Removed generic http_request builtin — replaced by dynamic factories
  • Typed RunContext for CLI --context parsing

Agent definition example

[[tools.dynamic]]
name = "zippy_request"
type = "http"
config = { base_url = "$REQUEST_BASE_URL", headers = { "Authorization" = "Bearer $REQUEST_AUTH_TOKEN" } }

Test plan

  • cargo check — zero errors, zero warnings
  • cargo test -p distri-core — 126 passed
  • E2E: zippy_generator agent successfully calls APIs via dynamic factory
  • Agent push validation rejects unknown builtin tools

@v3g42 v3g42 changed the base branch from main to claude/multi-entry-workflows-XrOSs March 29, 2026 06:39
@v3g42 v3g42 changed the base branch from claude/multi-entry-workflows-XrOSs to main March 29, 2026 06:41
@v3g42 v3g42 changed the base branch from main to claude/multi-entry-workflows-XrOSs March 29, 2026 06:41
v3g42 and others added 20 commits March 29, 2026 15:58
The std::sync::RwLockReadGuard is !Send and was held across an .await
in try_handle(), making stream_agent's future non-Send. Clone the
handler before dropping the guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract shared event formatting logic into a new crate that can be used
by both the CLI (distri) and the gateway (distri-gateway). Includes:
- Formatter trait for pluggable output formats
- ChatState and helper types extracted from printer.rs
- TextFormatter for plain-text output (Telegram, WhatsApp, logs)
- format_tool_call/is_probe_call pure-logic helpers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move pure functions (extract_vars, extract_vars_from_value, substitute_string,
substitute_value) from distri-core to distri-types::resolve, re-exporting them
from distri-core to preserve the existing API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a new endpoint that resolves raw secret values for specified keys,
allowing clients to resolve $VAR_NAME references in a single round-trip.
Missing keys are silently omitted from the response.

- distri-server: POST /secrets/resolve handler
- distri client: resolve_secrets() method

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds local execution of http_request tool calls with secret resolution
via the Distri cloud API, eliminating server round-trips for HTTP requests.

- SecretCache: caches resolved secrets and connection tokens with TTL
- client_http_request: mirrors server-side HttpRequestTool input/output
  contract with $VAR_NAME resolution and x-connection-id Bearer injection
- Wired into distri-cli for both Run and Tui commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…date tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e HttpRequestTool

Replace SecretCache-based resolution with typed proxy_request on the
client and a POST /request endpoint on the server. Client auto-detects
local vs proxy execution. TypeScript parity added in distrijs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds VALID_BUILTIN_TOOLS canonical list in distri-types. Agent
create, update, and validate endpoints now reject unknown builtin
tool names with a clear error message listing valid options.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The LLM needs the tool definition in the builtin list to know it
exists. When a CLI client is connected, it intercepts via
ExternalToolRegistry and executes client-side or proxies via
POST /request. When no client is connected (self-hosted), the
server executes directly using the typed execute_http_request.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The server has full ExecutorContext with env_vars from --context.
Client-side interception doesn't have access to those env_vars,
causing unresolved variable errors. Let the server builtin handle it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The env_vars from --context (REQUEST_BASE_URL, etc.) are now passed
to register_client_http_request so the client can resolve $VAR_NAME
references locally without round-tripping to the server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Errors now include method, URL, and reason (invalid input, unresolved
vars, proxy failure, HTTP failure) instead of generic "builder error".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces raw JSON .get()/.as_object() chains with proper typed
deserialization. Accepts "envs", "env_vars", and "secrets" keys —
all merge into env_vars for both server metadata and client-side
http_request handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…handler

- Relative URLs (starting with /) auto-prepend REQUEST_BASE_URL from env_vars
- Typed RunContext struct for --context parsing (accepts envs, env_vars, secrets)
- Client-side http_request handler receives env_vars from --context

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The server has full ExecutorContext with env_vars from --context.
Client-side interception can't work because is_external()=false means
the server executes the tool before the client can intercept.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the builtin http_request tool with a dynamic factory system.
Agent definitions can now declare named HTTP tools with baked-in
base_url and headers via [[tools.dynamic]] config blocks. The factory
resolves $VAR_NAME references and reuses execute_http_request for
actual execution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed: client_http_request.rs, register_client_http_request,
register_http_request_handler, proxy_request, SecretCache references,
client_env_vars. All HTTP requests now go through dynamic tool
factories executed server-side.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@v3g42 v3g42 changed the title Chore/http request tool feat: dynamic tool factories + unified HTTP request architecture Mar 29, 2026
@v3g42 v3g42 merged commit 9891d75 into claude/multi-entry-workflows-XrOSs Mar 29, 2026
@v3g42 v3g42 deleted the chore/http-request-tool branch March 29, 2026 15:09
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