Skip to content

feat(sdk): allow graph creation without explicit secrets - #861

Open
breken-ai wants to merge 1 commit into
FailproofAI:mainfrom
breken-ai:feat/sdk-optional-graph-secrets
Open

feat(sdk): allow graph creation without explicit secrets#861
breken-ai wants to merge 1 commit into
FailproofAI:mainfrom
breken-ai:feat/sdk-optional-graph-secrets

Conversation

@breken-ai

Copy link
Copy Markdown

Closes #631.

What changes

StateManager.upsert_graph(graph_name, graph_nodes, secrets=None, …): the secrets mapping is optional. A graph that needs none is created without passing {}.

What deliberately does not change

The wire contract. The state manager's UpsertGraphTemplateRequest requires secrets, and GraphTemplate.set_secrets replaces a graph's stored secrets on every upsert. So an omitted argument is sent as an empty mapping, exactly what callers send today, and the docstring and README say in one sentence that omitting it when updating a graph that already has secrets clears them. Preserving them client-side is not possible (the API returns only secret names), so that would be a server change and is out of scope here. The body carries a copy of the caller's mapping (it was passed by reference before), and there is no shared mutable default.

Tests

python-sdk/tests/test_statemanager_optional_secrets.py, against a mocked aiohttp session that captures the PUT body:

  • omission → "secrets": {} on the wire, call succeeds
  • explicit mapping → sent unchanged, caller's dict not mutated, body holds a copy
  • two calls without secrets → no shared mutable default
  • positional call with secrets third → still binds

Before: 3 failed, 1 passed (TypeError: missing 1 required positional argument: 'secrets'; body was the caller's own dict). After: 4 passed; full SDK suite 178 passed; ruff check . clean.

Evidence record

Repository / issue:        FailproofAI/runtime #631
Upstream SHA / patch SHA:  2db4b154 / 0a8f982
Issue ownership:           open, unassigned, no linked or competing PR (checked 2026-09-12 21:41 UTC)
Server contract checked:   state-manager/app/models/graph_models.py (secrets required), controller/upsert_graph_template.py + models/db/graph_template_model.py:set_secrets (replace on every upsert)
Reproducer:                uv run pytest tests/test_statemanager_optional_secrets.py → 3 failed, 1 passed on 2db4b154
Patched:                   4 passed; uv run pytest → 178 passed; uv run ruff check . → clean
Checks not executed:       disposable-namespace integration against a live state manager
Contract decision open:    whether the server should ever preserve secrets on omission (not changed here)

`upsert_graph` required a `secrets` mapping even for a graph that uses none, so every
caller passed `{}` (FailproofAI#631). The parameter is now optional (`dict[str, str] | None = None`).

The wire contract is unchanged, on purpose: the state manager's upsert request requires
the `secrets` field and `GraphTemplate.set_secrets` replaces the stored secrets on every
upsert, so an omitted argument is sent as an empty mapping and the docstring says that
omitting it when updating a graph that already has secrets clears them. Preserving them
from the SDK is not possible (the API never returns secret values), so that would be a
server contract change and is not made here. The body carries a copy of the caller's
mapping, never the mapping itself; there is no shared mutable default.

Regression: tests/test_statemanager_optional_secrets.py — omission sends `{}` and
succeeds; an explicit mapping is sent unchanged and not mutated; repeated calls share no
state; positional binding is unchanged. 3 of 4 fail before the change (TypeError on
omission; the body carried the caller's own dict), all pass after.

Closes FailproofAI#631
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.

feat: Make secrets optional in SDK

1 participant