Skip to content

Commit 2ff6284

Browse files
committed
further updates
1 parent d16ea40 commit 2ff6284

16 files changed

Lines changed: 628 additions & 42 deletions

AGENTS.md renamed to AGENT.md

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,33 @@ This guide provides a complete blueprint for creating or refactoring Conductor S
1414

1515
```
1616
┌─────────────────────────────────────────────────┐
17-
│ Application Layer
18-
│ (User's Application Code)
17+
│ Application Layer │
18+
│ (User's Application Code) │
1919
└─────────────────────────────────────────────────┘
2020
2121
┌─────────────────────────────────────────────────┐
22-
│ High-Level Clients
23-
│ (OrkesClients, WorkflowExecutor, Workers)
22+
│ High-Level Clients │
23+
│ (OrkesClients, WorkflowExecutor, Workers) │
2424
└─────────────────────────────────────────────────┘
2525
2626
┌─────────────────────────────────────────────────┐
27-
│ Domain-Specific Clients
28-
│ (TaskClient, WorkflowClient, SecretClient...)
27+
│ Domain-Specific Clients │
28+
│ (TaskClient, WorkflowClient, SecretClient...) │
2929
└─────────────────────────────────────────────────┘
3030
3131
┌─────────────────────────────────────────────────┐
32-
│ Orkes Implementations
33-
│ (OrkesTaskClient, OrkesWorkflowClient...)
32+
│ Orkes Implementations │
33+
│ (OrkesTaskClient, OrkesWorkflowClient...) │
3434
└─────────────────────────────────────────────────┘
3535
3636
┌─────────────────────────────────────────────────┐
37-
│ Resource API Layer
38-
│ (TaskResourceApi, WorkflowResourceApi...)
37+
│ Resource API Layer │
38+
│ (TaskResourceApi, WorkflowResourceApi...) │
3939
└─────────────────────────────────────────────────┘
4040
4141
┌─────────────────────────────────────────────────┐
42-
│ HTTP/API Client
43-
│ (ApiClient, HTTP Transport)
42+
│ HTTP/API Client │
43+
│ (ApiClient, HTTP Transport) │
4444
└─────────────────────────────────────────────────┘
4545
```
4646

@@ -255,6 +255,84 @@ Abstract Interface (20+ methods):
255255

256256
---
257257

258+
## 🤖 Agent SDK Layer
259+
260+
An **optional higher-level layer** for building LLM agents on top of the client +
261+
worker SDK. Agents are authored in code but **compiled and executed on the server**
262+
as durable Conductor workflows; an agent's tools are ordinary Conductor **workers**
263+
(reuse the entire Worker Framework, Phase 3). Full language-agnostic spec:
264+
[`docs/design/WORKER_SDK_IMPLEMENTATION_GUIDE.md` §25](docs/design/WORKER_SDK_IMPLEMENTATION_GUIDE.md#25-agent-sdk-layer-building-agents-on-the-worker-sdk).
265+
266+
### Two Planes
267+
268+
```
269+
┌───────────────────────────────┐
270+
│ AgentRuntime │ (facade)
271+
└───────────────────────────────┘
272+
│ │
273+
control plane │ │ worker plane
274+
▼ ▼
275+
┌───────────────────────┐ ┌────────────────────────────┐
276+
│ AgentClient │ │ WorkerManager/TaskHandler │
277+
│ /agent/* over the │ │ (Phase 3 workers serve │
278+
│ standard ApiClient │ │ the agent's tools) │
279+
└───────────────────────┘ └────────────────────────────┘
280+
```
281+
282+
### Core Components
283+
284+
| Component | Role |
285+
|---|---|
286+
| `AgentRuntime` | User-facing facade: `run`/`start`/`stream`/`deploy`/`serve`/`plan` (+ async). Composes a `Configuration`, `AgentConfig`, `AgentClient`, and a `WorkerManager`. |
287+
| `AgentClient` (interface) + `OrkesAgentClient` | Control plane (compile/deploy/start/status/stream/respond/stop/signal). Built on the **standard `ApiClient`** — reuses its token management; no separate token cache. Same interface + Orkes-impl pattern as the domain clients (Phase 2). |
288+
| `AgentConfig` | Agent-runtime **behaviour** only (worker pool, liveness, streaming, integration auto-register). Connection/auth/log level come from `Configuration`. |
289+
| `RunSettings` | Per-run LLM overrides (`model`/`temperature`/`max_tokens`/…) for a single `run`/`start`; applied to the serialized agent config before start. |
290+
| Framework adapters | Run agents authored in LangChain / LangGraph / OpenAI Agents SDK / Claude Agent SDK on the durable runtime as spawn-safe passthrough workers. |
291+
292+
### Verb Contract
293+
294+
| Method | Blocks | Returns | Starts workers | Registers on server |
295+
|---|---|---|---|---|
296+
| `run` | yes | result (output + ids) | yes | via start |
297+
| `start` | no | handle (`execution_id`) | yes | via start |
298+
| `deploy` | yes | deployment info | no | yes |
299+
| `serve` | yes (until signal) || yes | yes (`serve` = `deploy` + serve) |
300+
| `plan` | yes | workflow def | no | no |
301+
302+
### Key Principles
303+
304+
- **Single token authority** — control plane *and* worker-side agent posts reuse the one `ApiClient`'s mint/cache/TTL-refresh/401-retry; never a parallel token cache. In spawned workers, rebuild + cache a client per `(server_url, auth_key)`.
305+
- **Spawn-safety** — tool/worker callables must be module-level (importable/picklable), never `<locals>` closures; entry scripts use a main-module guard.
306+
- **Credentials** — declared per tool; the server resolves + delivers them on wire-only `Task.runtimeMetadata`; injected into the worker env for the call, never read from ambient env.
307+
- **Config single-source** — connection/auth/log level live on `Configuration`; `AgentConfig` is behaviour-only.
308+
309+
### Package Additions
310+
311+
```
312+
src/conductor/
313+
├── client/
314+
│ ├── agent_client.{ext} # AgentClient interface
315+
│ └── orkes/orkes_agent_client.{ext} # OrkesAgentClient (on ApiClient)
316+
└── ai/agents/ # agent authoring + runtime
317+
├── agent.{ext}, run_settings.{ext}
318+
├── runtime/ (runtime, config, worker_manager)
319+
├── _internal/agent_http.{ext} # single token authority for /agent/* posts
320+
└── frameworks/ (langchain, langgraph, claude_agent_sdk, …)
321+
```
322+
323+
### Agent-Layer Checklist
324+
325+
- [ ] `AgentClient` interface + Orkes impl on the standard `ApiClient` (sync + async; SSE reuses the client's auth header)
326+
- [ ] `AgentRuntime` facade with the exact verb contract above
327+
- [ ] `AgentConfig` behaviour-only; connection/auth/log level from `Configuration`
328+
- [ ] `RunSettings` per-run LLM overrides
329+
- [ ] Single token authority across control plane + worker-side posts
330+
- [ ] Tool workers reuse the Worker Framework (Phase 3); credentials via `runtimeMetadata`
331+
- [ ] Framework adapters as spawn-safe passthrough workers
332+
- [ ] Liveness monitor for stateful runs
333+
334+
---
335+
258336
## 🌐 Language-Specific Implementation
259337

260338
### Java Implementation

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ def train_model(dataset_id: str) -> dict:
306306
return {'model_id': model.id, 'accuracy': model.accuracy}
307307
```
308308
309-
Disabled by default. Enable per-worker via decorator, constructor, or environment variable (`conductor_worker_<task>_lease_extend_enabled=true`). See [LEASE_EXTENSION.md](LEASE_EXTENSION.md) for the full guide.
309+
Disabled by default. Enable per-worker via decorator, constructor, or environment variable (`conductor_worker_<task>_lease_extend_enabled=true`). See [LEASE_EXTENSION.md](docs/LEASE_EXTENSION.md) for the full guide.
310310
311311
### Monitoring with Metrics
312312
@@ -494,7 +494,7 @@ End-to-end examples covering all APIs for each domain:
494494
| [Worker Design](docs/design/WORKER_DESIGN.md) | Architecture: AsyncTaskRunner vs TaskRunner, discovery, lifecycle |
495495
| [Worker Guide](docs/WORKER.md) | All worker patterns (function, class, annotation, async) |
496496
| [Worker Configuration](WORKER_CONFIGURATION.md) | Hierarchical environment variable configuration |
497-
| [Lease Extension](LEASE_EXTENSION.md) | Automatic heartbeat for long-running tasks |
497+
| [Lease Extension](docs/LEASE_EXTENSION.md) | Automatic heartbeat for long-running tasks |
498498
| [Workflow Management](docs/WORKFLOW.md) | Start, pause, resume, terminate, retry, search |
499499
| [Workflow Testing](docs/WORKFLOW_TESTING.md) | Unit testing with mock outputs |
500500
| [Task Management](docs/TASK_MANAGEMENT.md) | Task operations |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ If a heartbeat API call fails, the SDK retries up to 3 times with backoff (`1s`,
128128

129129
## Example
130130

131-
See [examples/lease_extension_example.py](examples/lease_extension_example.py) for a complete runnable example that:
131+
See [examples/lease_extension_example.py](../examples/lease_extension_example.py) for a complete runnable example that:
132132
- Defines a long-running worker with `lease_extend_enabled=True`
133133
- Creates a workflow with a short `responseTimeoutSeconds`
134134
- Runs the workflow and proves the task completes despite sleeping longer than the timeout

docs/WORKER.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ class SimpleCppWorker(WorkerInterface):
610610

611611
## Long-Running Tasks and Lease Extension
612612

613-
For tasks that take longer than the configured `responseTimeoutSeconds`, the SDK provides automatic lease extension to prevent timeouts. See the comprehensive [Lease Extension Guide](../LEASE_EXTENSION.md) for:
613+
For tasks that take longer than the configured `responseTimeoutSeconds`, the SDK provides automatic lease extension to prevent timeouts. See the comprehensive [Lease Extension Guide](LEASE_EXTENSION.md) for:
614614

615615
- How lease extension works
616616
- Automatic vs manual control

docs/agents/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# Agentspan Python SDK
1+
# Conductor Agent Python SDK
22

33
> Ships as part of [`conductor-python`](https://pypi.org/project/conductor-python/) — install with the `agents` extra
44
> (`pip install 'conductor-python[agents]'`) — you're in the right place.
55
6-
Long-running, dynamic plan-execute, and event-driven AI agents in Python. You write plain Python; Agentspan compiles your agent into a Conductor workflow that runs on a server — with automatic retries, durable state, human-in-the-loop pauses, streaming, scheduling, dynamic plan-execute, and full execution history.
6+
Long-running, dynamic plan-execute, and event-driven AI agents in Python. You write plain Python; Conductor Agent compiles your agent into a Conductor workflow that runs on a server — with automatic retries, durable state, human-in-the-loop pauses, streaming, scheduling, dynamic plan-execute, and full execution history.
77

88
```python
99
from conductor.ai.agents import Agent, AgentRuntime

docs/agents/advanced.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ For one-off scripts, top-level functions use a shared singleton runtime:
4747

4848
```python
4949
import conductor.ai.agents as ag
50+
from conductor.client.configuration.configuration import Configuration
5051

51-
ag.configure(server_url="https://prod:8080/api") # before first run
52+
# Connection/auth via a Configuration; agent-behaviour knobs via config=AgentConfig(...).
53+
ag.configure(configuration=Configuration(server_api_url="https://prod:8080/api")) # before first run
5254
result = ag.run(agent, "Hello!")
5355
ag.shutdown() # explicit cleanup; not required for simple scripts
5456
```
@@ -64,13 +66,16 @@ ag.shutdown() # explicit cleanup; not required for simple scripts
6466
| `runtime.run(agent, prompt)` | yes | `AgentResult` | Simplest case — run and get the answer |
6567
| `runtime.start(agent, prompt)` | no | `AgentHandle` | Fire-and-forget; poll/control later |
6668
| `runtime.stream(agent, prompt)` | iterates | `AgentStream` | Watch events live; drive HITL |
67-
| `runtime.deploy(*agents)` | yes | `list[DeploymentInfo]` | CI/CD: compile + register, no execution |
68-
| `runtime.serve(*agents)` | yes (blocks) || Long-lived worker process; polls until interrupted |
69+
| `runtime.deploy(*agents)` | yes | `list[DeploymentInfo]` | CI/CD: compile + register, no workers, no execution |
70+
| `runtime.serve(*agents)` | yes (blocks) || Register agent(s) **and** serve workers; long-lived, polls until interrupted (`serve` = `deploy` + serve) |
6971
| `runtime.plan(agent)` | yes | `dict` | Compile to a workflow def without running anything |
7072

7173
`run`/`start`/`stream` accept `media=`, `session_id=`, `idempotency_key=`,
7274
`credentials=`, and extra `**kwargs` as workflow input. `run`/`run_async` also accept
7375
`on_event=` to stream while running synchronously, `timeout=`, and `context=`.
76+
`run`/`start` (and their async variants) also accept `run_settings=` — a `RunSettings`
77+
(or dict) that overrides the agent's `model`/`temperature`/`max_tokens`/… for that one
78+
call. See [API reference](api-reference.md#per-run-overrides--runsettings).
7479

7580
`plan(agent)` returns `{"workflowDef": ..., "requiredWorkers": ...}` — useful to
7681
inspect the compiled Conductor workflow:
@@ -91,9 +96,13 @@ runtime.deploy(agent)
9196
# agentspan deploy --path ./agents --agents greeter,support
9297

9398
# Long-lived worker process:
94-
runtime.serve(agent) # blocks, polling for tool tasks
99+
runtime.serve(agent) # registers the agent (idempotent) + blocks, polling for tool tasks
95100
```
96101

102+
`serve` also registers the agent on the server, so the explicit `deploy` step above
103+
is optional — it's still useful to register/upgrade the workflow from CI independently
104+
of the worker rollout.
105+
97106
`resume(execution_id, agent)` re-attaches to a previously `start`ed execution and
98107
re-registers its tool workers (e.g. after a process restart):
99108

docs/agents/api-reference.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ Context manager (sync and async: `with` / `async with`).
2929

3030
| Method | Signature | Purpose |
3131
|---|---|---|
32-
| `run` | `(agent, prompt=None, *, version=None, media=None, session_id=None, idempotency_key=None, on_event=None, timeout=None, credentials=None, context=None, **kwargs) -> AgentResult` | Run synchronously |
32+
| `run` | `(agent, prompt=None, *, version=None, media=None, session_id=None, idempotency_key=None, on_event=None, timeout=None, credentials=None, context=None, run_settings=None, **kwargs) -> AgentResult` | Start, wait for completion, return the result (also starts workers) |
3333
| `run_async` | same as `run` | Async run |
34-
| `start` | `(agent, prompt=None, *, version=None, media=None, session_id=None, idempotency_key=None, context=None, **kwargs) -> AgentHandle` | Fire-and-forget |
34+
| `start` | `(agent, prompt=None, *, version=None, media=None, session_id=None, idempotency_key=None, context=None, run_settings=None, **kwargs) -> AgentHandle` | Fire-and-forget; returns a handle (also starts workers) |
3535
| `start_async` | same as `start` | Async start |
3636
| `stream` | `(agent=None, prompt=None, *, version=None, handle=None, media=None, session_id=None, **kwargs) -> AgentStream` | Stream events |
3737
| `stream_async` | same as `stream` | `-> AsyncAgentStream` |
38-
| `deploy` | `(*agents, packages=None, schedules=_UNSET) -> list[DeploymentInfo]` | Compile + register |
38+
| `deploy` | `(*agents, packages=None, schedules=_UNSET) -> list[DeploymentInfo]` | Compile + register agent(s) on the server; does **not** start workers |
3939
| `deploy_async` | same | Async deploy |
40-
| `serve` | `(*agents, packages=None, blocking=True) -> None` | Register + poll workers |
40+
| `serve` | `(*agents, packages=None, blocking=True) -> None` | Register agent(s) on the server **and** serve/poll their workers (`serve` = `deploy` + serve) |
4141
| `plan` | `(agent) -> dict` | Compile to workflow def |
4242
| `resume` | `(execution_id, agent, *, timeout=None) -> AgentHandle` | Re-attach + re-register workers |
4343
| `resume_async` | same | Async resume |
@@ -57,6 +57,28 @@ Async variants exist for status/respond/approve/reject/send/stop/shutdown
5757
`start`, `start_async`, `stream`, `stream_async`, `resume`, `resume_async`, `deploy`,
5858
`deploy_async`, `serve`, `plan`, `configure`, `shutdown`.
5959

60+
### Per-run overrides — `RunSettings`
61+
62+
`run` / `start` (and their async variants and the module-level wrappers) accept
63+
`run_settings=` to override an agent's LLM settings for a single invocation
64+
without rebuilding the `Agent`:
65+
66+
```python
67+
from conductor.ai.agents import RunSettings
68+
69+
runtime.run(
70+
agent,
71+
"Summarize this.",
72+
run_settings=RunSettings(model="anthropic/claude-sonnet-4-6", temperature=0.0, max_tokens=512),
73+
)
74+
```
75+
76+
`RunSettings(model=None, temperature=None, max_tokens=None, reasoning_effort=None,
77+
thinking_budget_tokens=None)` — only the fields you set override; unset fields keep
78+
the agent's own values (so `temperature=0.0` is honored). A plain `dict` with the
79+
same keys is also accepted. Overrides apply to the root agent's config; sub-agents
80+
keep their own settings.
81+
6082
## Agent
6183

6284
`Agent(name, model="", instructions="", tools=None, agents=None,

docs/agents/framework-agents.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Framework agents
22

3-
Agentspan can run agents authored in other frameworks by bridging them onto its
4-
durable runtime. You keep your framework's authoring API; Agentspan handles
3+
Conductor Agent can run agents authored in other frameworks by bridging them onto its
4+
durable runtime. You keep your framework's authoring API; Conductor Agent handles
55
durability, retries, streaming, and observability.
66

77
Supported bridges: **OpenAI Agents SDK**, **LangChain**, **LangGraph**, **Claude
@@ -21,7 +21,7 @@ SDK's `Runner` with a native `Agent`.
2121
### Drop-in `Runner`
2222

2323
Change one import — `from conductor.ai import Runner` instead of `from agents import
24-
Runner` — and run your existing OpenAI-Agents agent on Agentspan:
24+
Runner` — and run your existing OpenAI-Agents agent on Conductor Agent:
2525

2626
```python
2727
from conductor.ai import Runner # the one line that changes
@@ -86,7 +86,7 @@ with AgentRuntime() as runtime:
8686
result.print_result()
8787
```
8888

89-
Agentspan also provides a thin wrapper, `conductor.ai.agents.langchain.create_agent`,
89+
Conductor Agent also provides a thin wrapper, `conductor.ai.agents.langchain.create_agent`,
9090
that captures the model, tools, and system prompt up front so they compile to native
9191
server-side model + tool tasks (rather than running the whole agent in one opaque
9292
worker).
@@ -157,4 +157,4 @@ functions are not yet supported there.
157157

158158
You can also bring `ClaudeCodeOptions` / a Claude Agent SDK agent directly; the bridge
159159
runs the full `query()` in one durable worker with instrumentation hooks that stream
160-
tool-use and lifecycle events back to Agentspan.
160+
tool-use and lifecycle events back to Conductor Agent.

docs/agents/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pip install 'conductor-python[agents]'
1111
Or, per framework, install just what you need — e.g. `conductor-python[langchain]`,
1212
`conductor-python[adk]`, `conductor-python[claude]`.
1313

14-
Point the SDK at a running Agentspan server (defaults to `http://localhost:8080/api`):
14+
Point the SDK at a running Conductor Agent server (defaults to `http://localhost:8080/api`):
1515

1616
```bash
1717
export AGENTSPAN_SERVER_URL=http://localhost:8080/api

0 commit comments

Comments
 (0)