feat: support editable workflow contracts

This commit is contained in:
lda
2026-09-01 00:34:39 +07:00 Verified
parent 700cfaddf3
commit ef79eae6bf
7 changed files with 525 additions and 16 deletions
+22 -8
View File
@@ -134,20 +134,30 @@ arguments may be JSON Schema dictionaries or the application's schema model
values:
```python
from pydantic import BaseModel
from wf_client import App
from wf_authoring import input_from, input_value, output_to, state_path
class Input(BaseModel):
request_id: str
class State(BaseModel):
value: str | None = None
class Output(BaseModel):
value: str
app = App.from_http_jsonrpc("http://localhost:8765/rpc")
capability = await app.capability("wf.std.constant")
graph = app.new_workflow(
"example",
input_schema={"type": "object", "properties": {}},
state_schema={"type": "object", "properties": {"value": {"type": "string"}}},
output_schema={
"type": "object",
"properties": {"value": {"type": "string"}},
"required": ["value"],
},
input_schema=Input,
state_schema=State,
output_schema=Output,
)
step = graph.use(
capability,
@@ -162,12 +172,16 @@ graph.set_output([input_from(state_path("value"), "value")])
validation = await graph.validate()
validation.raise_for_errors()
artifact = await graph.save(version=1)
run = await artifact.run({})
run = await artifact.run({"request_id": "request-1"})
```
The graph is a local, mutable builder. `validate()` checks its structure locally
and then asks the server to validate the serialized plan. `save()` persists an
immutable artifact version; it does not deploy or execute the graph.
Pydantic models are normalized into canonical schemas. During authoring,
`set_contract()` can atomically replace selected input, state, output, or
outcome contracts; it preserves existing bindings so validation can expose any
paths made invalid by the replacement.
`artifact.run()` selects or creates a deployment, validates its source bindings,
and starts a durable run. The returned run is a loaded snapshot; call
`refresh()`, `resume()`, or bounded `trace(start=..., limit=...)` when more
+25 -8
View File
@@ -114,20 +114,30 @@ Hypothetically, an application that wants to turn a discovered capability into
a durable run would use the following complete flow:
```python
from pydantic import BaseModel
from wf_client import App
from wf_authoring import input_from, input_value, output_to, state_path
class Input(BaseModel):
request_id: str
class State(BaseModel):
value: str | None = None
class Output(BaseModel):
value: str
app = App.from_http_jsonrpc("http://localhost:8765/rpc")
capability = await app.capability("wf.std.constant")
graph = app.new_workflow(
"example",
input_schema={"type": "object", "properties": {}},
state_schema={"type": "object", "properties": {"value": {"type": "string"}}},
output_schema={
"type": "object",
"properties": {"value": {"type": "string"}},
"required": ["value"],
},
input_schema=Input,
state_schema=State,
output_schema=Output,
)
step = graph.use(
capability,
@@ -142,9 +152,16 @@ graph.set_output([input_from(state_path("value"), "value")])
validation = await graph.validate()
validation.raise_for_errors()
artifact = await graph.save(version=1)
run = await artifact.run({})
run = await artifact.run({"request_id": "request-1"})
```
Pydantic models, typed mappings, and raw JSON Schema are accepted, but Python
applications should normally keep their contracts as Python types. If a
contract changes while the graph is being authored, call
`graph.set_contract(state_schema=..., output_schema=..., outcomes=...)`.
Supplied fields replace their whole contract atomically; omitted fields and
existing graph bindings remain, so validate after the replacement.
The graph is an in-process builder. Validation is local structural checking
plus a server plan check. Saving creates an immutable, versioned artifact; it
does not execute anything. A deployment is the server's runnable configuration