feat: consolidate agent control-plane onto AgentClient; fix worker credential delivery#421
Open
v1r3n wants to merge 10 commits into
Open
feat: consolidate agent control-plane onto AgentClient; fix worker credential delivery#421v1r3n wants to merge 10 commits into
v1r3n wants to merge 10 commits into
Conversation
…edential delivery Refactors the agent runtime's server access onto the standard client stack and fixes worker credential resolution to the server's runtimeMetadata contract. AgentClient (interface + Orkes impl) - Add `conductor.client.agent_client.AgentClient` (ABC) + `OrkesAgentClient` following the WorkflowClient/OrkesWorkflowClient pattern, built on the shared ApiClient (sync) / AsyncApiClient (async) so JWT mint / X-Authorization / TTL refresh / 401-retry are reused, not re-implemented. SSE reuses the ApiClient token via a new public `get_authentication_headers()`. - `OrkesClients.get_agent_client()` returns the new client. - Delete the duplicate transport (`client/ai/agent_api_client.py`) and the DX wrapper (`ai/agents/runtime/http_client.py`); AgentRuntime uses the one client for all /agent/* calls (start/deploy/compile/status/execution/respond/stop/ signal/SSE), sync and async. AgentRuntime / Configuration - `AgentRuntime(configuration: Configuration = None, *, settings: AgentConfig = None)`: server config comes solely from the standard Configuration; AgentConfig carries runtime behaviour only. Remove the custom `to_conductor_configuration()` bridge and the private log-level poke. - `Configuration` host resolution falls back CONDUCTOR_SERVER_URL -> AGENTSPAN_SERVER_URL. Worker credentials via runtimeMetadata (conductor-oss PR #1255 contract) - Add `Task.runtime_metadata` and `TaskDef.runtime_metadata` model fields. - Stamp `TaskDef.runtimeMetadata` from a tool/agent's declared credentials at registration so the SDK's overwrite-registration no longer wipes the value the server compiles. - Worker dispatch (+ langchain/langgraph/claude_agent_sdk wrappers) reads the host-resolved secrets off `Task.runtimeMetadata` instead of the retired execution-token / POST /workers/secrets path. Retire WorkerCredentialFetcher, `_extract_execution_token`, `_get_credential_fetcher`; `resolve_credentials(task, names)` now reads runtimeMetadata. Remove server auto-start - Delete `runtime/server.py` and the `auto_start_server` / AGENTSPAN_AUTO_START_SERVER config surface; runtime no longer probes or launches a local server. CLI tools spawn-safety - `cli_config._make_cli_tool` builds the `run_command` worker from a module-level `_CliCommandRunner` instance (not a <locals> closure), so registration's spawn-safety probe passes. Tests / docs / examples - New: orkes_agent_client, task/taskdef runtimeMetadata serde, runtime_metadata registration, e2e suite26 (worker credentials + CLI spawn-safety) unit/e2e tests. - Update credential/dispatch/runtime/sse/signals tests to the new contracts; rewrite e2e suite24 for the transport-only client + runtime DX. - Docs + examples updated (GH_TOKEN, Configuration-based AgentRuntime).
CI sets CONDUCTOR_AUTH_KEY/SECRET (a service account). The new Configuration-based client correctly reads them, which broke two tests that assumed an anonymous environment: - test_runtime: assert settings.auth_key is *ignored* (rt._auth_key != "ignored") instead of asserting anonymity — env-independent. - test_sse_client TestStreamSSEAuth: autouse fixture clears ambient auth env so "no auth configured -> no X-Authorization" holds regardless of CI env. Verified: full tests/unit + serdesertest + backwardcompatibility on py3.12 with CONDUCTOR_AUTH_* set -> 3549 passed.
…credential tests - suite23: build the respond URL via runtime.client._agent_url() (the removed runtime._agent_api_url helper). - suite26: function-scoped runtime fixture so each credential test re-registers the worker TaskDef (with overwrite), making TaskDef.runtimeMetadata reflect the test's own code path instead of a value left by a prior test in the module. Verified via fail-first mutation: removing the registration stamping now fails both credential tests together (previously the module-scoped runtime masked it).
…support Released agentspan servers (through v0.4.2) do not implement the TaskDef.runtimeMetadata credential-delivery contract (conductor-oss PR #1255) — they drop the field — so worker credential injection cannot work there, and the credential-delivery e2e tests would fail for a server-version reason unrelated to the SDK. Add a server-capability probe (does a registered TaskDef.runtimeMetadata persist?) and a `requires_runtime_metadata` fixture that skips the credential-delivery tests when unsupported. Applied to suite26 TestWorkerCredentials, suite2 test_credential_lifecycle, suite3 test_cli_credential_lifecycle. The CLI spawn-safety test is left unguarded (server-independent). Verified both ways: against the dev server (supports it) the tests RUN and pass; against v0.4.2 (does not) they SKIP with a TODO to bump AGENTSPAN_VERSION once a release ships runtimeMetadata.
…vel on Configuration Connection/auth (server_url, api_key, auth_key, auth_secret) and the dead llm_retry_count / secret_strict_mode fields are removed from AgentConfig — connection and auth belong to the conductor Configuration. log_level moves onto Configuration (settable param + CONDUCTOR_LOG_LEVEL/AGENTSPAN_LOG_LEVEL env) so it is SDK-wide; the runtime reads it from there. run.configure() now takes a Configuration for connection. AgentConfig keeps worker + liveness settings only. Unit tests updated.
…e parallel token cache Framework workers (claude_agent_sdk, langchain, langgraph) posted to Agentspan /agent/* endpoints with raw requests + a standalone token mint/cache in token_utils, a second token authority parallel to ApiClient. New _internal/agent_http.py reconstructs a cached ApiClient per (server_url, auth_key) inside the spawned worker and posts via ApiClient.call_api, reusing the SDK's token management (mint/cache/TTL-refresh/401-retry). _task_client folds into the same cache so /tasks and /agent/* share one token. token_utils is reduced to decode_jwt_exp. Adds test_agent_http.py (in-process server; mint-once-and-cache guard); test_token_utils trimmed to the decoder.
…RLs; add run-all harness GPTAssistantAgent's assistant tool becomes a module-level picklable callable (spawn-safe). Examples: add if-__main__ guards to stateful/looping workers (75/76/82/83/84), hoist <locals> tools to module level (92, 16g) and make 82 spawn-safe (env-shared IPC + client rebuild), use settings.llm_model in 58, read server URL from env in the schedule examples, add missing 'import sys' (72/73). Adds run_all_examples.py harness and gitignores its generated report + coding-agent output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Consolidates the agent runtime's
/agent/*access onto the standard client stack and fixes worker credential resolution to the server'sruntimeMetadatacontract (conductor-oss PR #1255). Also removes the now-unused server auto-start and fixes a CLI-tool spawn-safety bug.Verified end-to-end against a live agentspan server; unit + e2e suites pass.
AgentClient — interface + Orkes impl
conductor.client.agent_client.AgentClient(ABC) +conductor.client.orkes.orkes_agent_client.OrkesAgentClient, following theWorkflowClient/OrkesWorkflowClientpattern. Built on the sharedApiClient(sync) /AsyncApiClient(async), so JWT minting,X-Authorization, TTL refresh and 401-retry are reused, not re-implemented. SSE reuses theApiClienttoken via a new publicget_authentication_headers().OrkesClients.get_agent_client()returns it.client/ai/agent_api_client.py) and the DX wrapper (ai/agents/runtime/http_client.py).AgentRuntimenow uses the one client for all/agent/*calls (start/deploy/compile/status/execution/respond/stop/signal/SSE), sync + async.AgentRuntime + Configuration
AgentRuntime(configuration: Configuration = None, *, settings: AgentConfig = None)— server config comes solely from the standardConfiguration(same objectApiClientuses);AgentConfigcarries runtime behaviour only. Removed the customto_conductor_configuration()bridge and the private log-level poke.Configurationhost resolution falls backCONDUCTOR_SERVER_URL→AGENTSPAN_SERVER_URL.Worker credentials via
runtimeMetadataFixes the "Required credentials not found … No execution token available" failure. The server resolves a worker's declared
TaskDef.runtimeMetadatasecret names at poll time and delivers values on the wire-onlyTask.runtimeMetadata; the SDK was still on the retired execution-token /POST /workers/secretspath and was wipingTaskDef.runtimeMetadataon registration.Task.runtime_metadataandTaskDef.runtime_metadatamodel fields.TaskDef.runtimeMetadatafrom declared credentials at registration (native@tool, framework, and passthrough workers) so overwrite-registration no longer clobbers the server-compiled value.Task.runtimeMetadata. RetiredWorkerCredentialFetcher,_extract_execution_token,_get_credential_fetcher;resolve_credentials(task, names)now readsruntimeMetadata.Remove server auto-start
runtime/server.pyand theauto_start_server/AGENTSPAN_AUTO_START_SERVERconfig surface. The runtime no longer probes or launches a local server.CLI tools spawn-safety
cli_config._make_cli_toolnow backsrun_commandwith a module-level_CliCommandRunnerinstance instead of a<locals>closure, so the registration spawn-safety probe passes (cli_allowed_commandsagents register + run).Tests / docs / examples
test_orkes_agent_client, task/taskdefruntimeMetadataserde,runtime_metadataregistration, CLI spawn-safety regression.test_suite26_worker_credentials(credential injection viaruntimeMetadata,TaskDef.runtimeMetadatastamping, env isolation, CLI spawn-safety) — stores secrets via REST/api/secrets(no CLI dependency).suite24for the transport-only client + runtime DX.api-reference,advanced,getting-started) and examples updated (GH_TOKEN,Configuration-basedAgentRuntime).Verification
tests/unit+tests/backwardcompatibility+tests/serdesertest: green.suite26(4),suite24(5),suite1(9) pass. (The CLI-credential suitessuite2/suite3are blocked by an unrelated local CLI↔server API skew —/api/credentialsvs/api/secrets— not by these changes.)Notes
runtime.clientis now the transportAgentClient; the old control-plane DX (runtime.client.run/start/deploy/schedule) was removed — use the runtime's ownrun/start/deploy/schedules_client().