Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions docs/design/AGENT_SDK_PORTING_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,24 @@ The runtime verbs MUST behave exactly as follows:
be **reconstructible in the executor context** that runs it.

- If your worker executors are **spawned processes** (Python-style): callables
must be importable by qualified name or serializable by value — module-level
functions, or module-level classes instantiated with plain-data fields. Local
closures, lambdas capturing live objects, and functions defined inside other
functions MUST be rejected at registration time with an actionable error
("define the callable at module level"). Entry-point scripts must guard
top-level orchestration with the language's main-module idiom so a re-import in
the child does not re-run it.
must be importable by qualified name, deterministically reconstructible from
an importable decorator container, or serializable by value. Module-level
decorator functions remain valid when the decorator rebinds the public name:
support `__wrapped__`, stable container attributes such as `func` and
`coroutine`, and deterministic bounded nested/closure traversal for containers
such as OpenAI Agents SDK `FunctionTool`. Parent-side discovery and child-side
reconstruction MUST share the traversal implementation. Discovery retains all
importable plain-function candidates and selects only by the exact tool-name /
sole-candidate contract; it MUST NOT inspect signatures or exclude valid
`ctx`/`context` first parameters. Stable `FunctionKey` code identity is used
only to prove reconstruction of that already-selected function in the child.
Plain functions never silently fall back
to direct-object pickling; local functions, lambdas, and bound methods fail at
registration. Direct callable objects require a standard-pickle round trip.
Entry-point scripts must guard top-level orchestration with the language's
main-module idiom so a re-import in the child does not re-run it. The exact
Python types, traversal order, failure semantics, and version-pinned tests are
authoritative in [`architecture.md`](architecture.md).
- If your executors are **threads in-process** (Java/Go/C#/TS typical): the
invariant reduces to "no capture of per-run mutable runtime state"; document it,
and keep factory boundaries clean regardless (next point).
Expand All @@ -458,8 +469,25 @@ be **reconstructible in the executor context** that runs it.
**Acceptance criteria**
- [ ] Registering a closure/lambda as a tool fails fast with an actionable error
(process-spawn runtimes) or is impossible by API design (typed runtimes).
- [ ] A registration-time round-trip test: serialize/reconstruct each registered
callable the way the executor would, and invoke it.
- [ ] A module-level OpenAI Agents SDK `@function_tool` registers under `spawn`
even though the module global resolves to a `FunctionTool` container;
Python regression coverage uses the repository-local
`tests/requirements/openai_agents_0_18_2.txt` constraint, verifies the
installed version, and accepts either the deterministic `unwrap_depth` or
deep-extraction strategy.
- [ ] Valid decorated tools whose first parameter is named `context` and `ctx`
each traverse the production registration path and execute the intended
named callable in a real spawned child; parameter names never filter or
rank embedded-function candidates.
- [ ] A rebound global with no supported reconstruction path reports the rebound
container mismatch instead of incorrectly telling the user to move an
already module-level function to module scope.
- [ ] A registration-time round-trip test serializes through the framework
serializer into `WorkerInfo` records, passes those records to
`_register_framework_workers`, captures the registered worker through
`get_registered_workers()`, then reconstructs and invokes it in a real
spawned child. Exact fixtures and commands are defined in
[`architecture.md`](architecture.md).

---

Expand Down
27 changes: 21 additions & 6 deletions docs/design/WORKER_SDK_IMPLEMENTATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2540,12 +2540,27 @@ wrapped as a **passthrough worker**; its tools run as Conductor workers; lifecyc
tool-use events are pushed to the server for observability.

**Spawn-safety (critical).** Workers execute in spawned processes, so every worker/tool
callable must be **importable by qualified name or picklable by value** — a module-level
function, or a module-level callable *class instance* holding only plain data. **Never**
register a `<locals>` closure or a lambda. Entry scripts must guard top-level execution
with the language's "main module" guard (e.g. `if __name__ == "__main__":`) so a
re-imported spawn child does not re-run the orchestration. Framework worker factories
receive plain strings (server URL + credentials), never live client objects.
callable must be **importable by qualified name, deterministically reconstructible from
an importable decorator container, or picklable by value**. Decorators that rebind a
module global do not make the original module-level function unsafe: reconstruction
must support `__wrapped__`, stable `func`/`coroutine` container attributes, and a
deterministic bounded nested/closure traversal for containers such as OpenAI Agents
SDK `FunctionTool`. Discovery and reconstruction must share one implementation and
retain every importable plain-function candidate. Parent-side selection uses only the
exact tool-name / sole-candidate contract; it must not inspect signatures or exclude
valid first parameters named `ctx` or `context`. Stable `FunctionKey` code identity is
used only to prove reconstruction of the already-selected function in the child.
Plain functions must never fall
back to direct-object pickling; direct callable objects require a standard-pickle
round trip. **Never** register a true `<locals>` closure, lambda, or bound method.
Entry scripts must guard top-level execution with the language's "main module" guard (e.g.
`if __name__ == "__main__":`) so a re-imported spawn child does not re-run the
orchestration. Framework worker factories receive plain strings (server URL +
credentials), never live client objects. The exact Python types, resolution order,
traversal algorithm, failure semantics, repository-local
`openai-agents==0.18.2` constraint, and production-path `WorkerInfo` registration test
including the required `context` and `ctx` spawn regressions are defined in
[`architecture.md`](architecture.md).

### 25.8 Agent Credentials (runtimeMetadata contract)

Expand Down
Loading
Loading