half a decision
half a grill sesh will finish later
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
*.html
|
||||
*.pdf
|
||||
*.tex
|
||||
+215
-454
@@ -1,12 +1,15 @@
|
||||
---
|
||||
title: |
|
||||
lda.chat\
|
||||
\Large wf: Architecture \& Design
|
||||
title: "lda.chat wf"
|
||||
subtitle: "Workflow Platform Architecture and Demo"
|
||||
author: "draft"
|
||||
date: "2026-05-30"
|
||||
date: "2026-06-12"
|
||||
lang: "en-US"
|
||||
documentclass: report
|
||||
papersize: a4
|
||||
fontsize: 12pt
|
||||
fontsize: 10pt
|
||||
toc: true
|
||||
toc-depth: 2
|
||||
numbersections: true
|
||||
geometry:
|
||||
- top=30mm
|
||||
- bottom=30mm
|
||||
@@ -16,527 +19,285 @@ mainfont: "Libertinus Serif"
|
||||
sansfont: "Libertinus Sans"
|
||||
monofont: "Libertinus Mono"
|
||||
mathfont: "Libertinus Math"
|
||||
colorlinks: true
|
||||
linkcolor: "MidnightBlue"
|
||||
urlcolor: "MidnightBlue"
|
||||
toccolor: "MidnightBlue"
|
||||
keywords:
|
||||
- workflow
|
||||
- agents
|
||||
- JSON-RPC
|
||||
- MCP
|
||||
- Python sources
|
||||
header-includes:
|
||||
- \usepackage{graphicx}
|
||||
- \usepackage{booktabs}
|
||||
- \usepackage{hyperref}
|
||||
- \usepackage{hyperxmp}
|
||||
- \usepackage[dvipsnames]{xcolor}
|
||||
- \usepackage{fancyhdr}
|
||||
- \pagestyle{fancy}
|
||||
- \fancyhead[L]{\small\leftmark}
|
||||
- \fancyhead[R]{\small lda.chat}
|
||||
- \fancyhead[L]{\small wf platform}
|
||||
- \fancyhead[R]{\small\leftmark}
|
||||
- \fancyfoot[C]{\thepage}
|
||||
- \setlength{\parskip}{0.6em}
|
||||
- \setlength{\parindent}{0pt}
|
||||
- \setkeys{Gin}{width=\linewidth,height=0.55\textheight,keepaspectratio}
|
||||
- \renewcommand{\arraystretch}{1.3}
|
||||
- \newcommand{\status}[1]{\texorpdfstring{\hfill{\normalfont\small\textsc{#1}}}{}}
|
||||
- \hypersetup{pdfauthor={lda.chat}, pdftitle={lda.chat wf Workflow Platform Architecture and Demo}}
|
||||
diagram:
|
||||
engine:
|
||||
mermaid:
|
||||
theme: neutral
|
||||
outputFormat: svg
|
||||
---
|
||||
|
||||
# Introduction
|
||||
# Workflow Platform Presentation
|
||||
|
||||
`lda.chat` is an AI agent that turns natural language requests into executable
|
||||
workspace workflows. The LLM plans a directed graph of typed steps. A
|
||||
deterministic executor runs it. Registered node handlers do the real
|
||||
work---whether those handlers call MCP tools, run local Python functions,
|
||||
execute saved subworkflows, or compose authoring-layer operations.
|
||||
This is a compact presentation narrative for the current product shape. It is
|
||||
not a full architecture reference; use the linked docs for implementation
|
||||
detail.
|
||||
|
||||
The core architectural split:
|
||||
## One-Sentence Thesis
|
||||
|
||||
> **The LLM plans, but does not execute. The executor executes, but does not
|
||||
> think. Nodes do work. Edges are dumb routing.**
|
||||
LLMs should plan typed workflows, while a deterministic runtime executes those
|
||||
workflows against explicit, validated capability sources.
|
||||
|
||||
**Thesis scope** is narrow: prove the planner/executor/tool split end to end
|
||||
with a few working MCP tools, LLM-generated workflow JSON, validated execution,
|
||||
and structured results. The broader product vision---tool registries, scheduling,
|
||||
multi-user---is out of scope.
|
||||
## The Problem
|
||||
|
||||
# System Architecture \status{implemented}
|
||||
Agents are good at deciding what should happen next, but bad at being the thing
|
||||
that directly owns side effects, retries, durable state, and schema contracts.
|
||||
|
||||
## Package Structure
|
||||
The platform separates those jobs:
|
||||
|
||||
The system is organized into three main packages with strict dependency
|
||||
boundaries.
|
||||
- The LLM or human author chooses and edits workflow structure.
|
||||
- The workflow runtime executes a typed graph.
|
||||
- Source providers expose callable capabilities.
|
||||
- Stores persist artifacts, deployments, and stopped runs.
|
||||
- Transports let CLI, future UI, and other clients talk to the same server.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Core["wf_core --- Execution Kernel"]
|
||||
direction TB
|
||||
Models["models"]
|
||||
Runtime["runtime"]
|
||||
Scheduler["scheduler"]
|
||||
Ops["runtime.ops"]
|
||||
Validation["validation"]
|
||||
Paths["paths"]
|
||||
RunState["run_state"]
|
||||
end
|
||||
## Current Product Path
|
||||
|
||||
subgraph Authoring["wf_authoring --- DSL"]
|
||||
direction TB
|
||||
Builder["WorkflowBuilder"]
|
||||
NodeDec["@node"]
|
||||
DSL["dsl/"]
|
||||
Reducers["reducers/"]
|
||||
end
|
||||
|
||||
subgraph MCP["wf_mcp --- MCP Platform"]
|
||||
direction TB
|
||||
Broker["broker/"]
|
||||
Proxy["proxy/"]
|
||||
SDK["sdk/"]
|
||||
WorkflowSurf["workflow_surface/"]
|
||||
WfConvert["workflow/"]
|
||||
end
|
||||
|
||||
Authoring --> Core
|
||||
MCP --> Core
|
||||
MCP --> Authoring
|
||||
```text
|
||||
wf CLI
|
||||
-> JSON-RPC transport
|
||||
-> WorkflowServer
|
||||
-> WorkflowApi
|
||||
-> wf_core runtime + wf_artifacts stores + wf_sources_* providers
|
||||
```
|
||||
|
||||
**Dependency rules:**
|
||||
The preferred server entrypoint is:
|
||||
|
||||
- `wf_core` must not import `wf_authoring` or `wf_mcp`.
|
||||
- `wf_mcp.sdk` should not import `wf_core` or `wf_authoring`.
|
||||
- `wf_mcp.proxy` should not import `wf_mcp.workflow`.
|
||||
- `wf_mcp.workflow` is the only layer that converts MCP tools into node specs.
|
||||
|
||||
## Data Flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User["User request"] --> LLM["LLM Planner"]
|
||||
LLM --> WJ["Workflow JSON"]
|
||||
WJ --> EX["Deterministic Executor"]
|
||||
EX --> NH["Node Handlers"]
|
||||
NH --> State["Shared Workflow State"]
|
||||
```powershell
|
||||
uv run wf-rpc-server --config wf.config.json
|
||||
```
|
||||
|
||||
# Workflow Model \status{implemented}
|
||||
The preferred client entrypoint is:
|
||||
|
||||
A workflow is a directed graph with explicit schemas and explicit control flow.
|
||||
|
||||
## Top-Level Structure
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Workflow {
|
||||
+str name
|
||||
+SchemaRef input_schema
|
||||
+StateSchema state_schema
|
||||
+SchemaRef output_schema
|
||||
+list~InputBinding~ output
|
||||
+list~NodeDef~ node_defs
|
||||
+list~str~ outcomes
|
||||
+str start
|
||||
+list~Step~ nodes
|
||||
+list~Edge~ edges
|
||||
}
|
||||
|
||||
class NodeDef {
|
||||
+str name
|
||||
+SchemaRef input_schema
|
||||
+SchemaRef output_schema
|
||||
+list~str~ outcomes
|
||||
}
|
||||
|
||||
class Edge {
|
||||
+str from
|
||||
+str outcome
|
||||
+str to
|
||||
}
|
||||
|
||||
Workflow --> NodeDef
|
||||
Workflow --> Edge
|
||||
```powershell
|
||||
uv run wf --config wf.config.json status
|
||||
```
|
||||
|
||||
## Schema Boundaries
|
||||
`wf-mcp` still exists for legacy/special-purpose MCP-facing work, but the
|
||||
durable product path is now `wf-rpc-server` plus `wf`.
|
||||
|
||||
Three schemas define distinct contracts:
|
||||
## Core Model
|
||||
|
||||
- **`input_schema`** validates run input once. Input is stored independently and
|
||||
remains readable throughout execution via `input.*` paths.
|
||||
- **`state_schema`** defines typed workflow memory with per-field merge
|
||||
reducers. Nodes read/write state via `state.*` paths.
|
||||
- **`output_schema`** declares the output contract. Output is projected via
|
||||
explicit `workflow.output` bindings that can read from `state.*`, `input.*`,
|
||||
or `context.*` paths. A legacy fallback derives output from same-name top-level
|
||||
state keys when bindings are omitted.
|
||||
A workflow is a typed graph:
|
||||
|
||||
Input, state, and context are **separate read roots**. The runtime resolves
|
||||
bindings against all three independently; input is not merged into state.
|
||||
- `input_schema` validates run input.
|
||||
- `state_schema` defines workflow memory and reducer behavior.
|
||||
- `output_schema` defines the final result contract.
|
||||
- Nodes do real work through `NodeSpec` handlers.
|
||||
- Edges route by declared outcomes.
|
||||
- Deployments bind logical source requirements to concrete sources.
|
||||
|
||||
## Step Types
|
||||
The runtime does not know whether a node came from MCP, Python, OpenAPI, or a
|
||||
built-in package. It resolves a `NodeSpec`, validates payloads, executes, records
|
||||
trace, and commits reducer-aware state changes.
|
||||
|
||||
Steps form a discriminated union on the `type` field:
|
||||
## Source Model
|
||||
|
||||
```mermaid
|
||||
graph
|
||||
Step["Step (type)"]
|
||||
Step --> NU["NodeUse"]
|
||||
Step --> SG["SubgraphNode"]
|
||||
Step --> CN["ConditionNode"]
|
||||
Step --> FE["ForeachNode"]
|
||||
Step --> JN["JoinNode"]
|
||||
Step --> EN["EndNode"]
|
||||
Step --> IN["InterruptNode"]
|
||||
The common provider output is `CapabilitySource`.
|
||||
|
||||
```text
|
||||
source provider
|
||||
-> CapabilitySource
|
||||
-> WorkflowSpecProvider
|
||||
-> WorkflowApi
|
||||
```
|
||||
|
||||
**NodeUse** binds a reusable `NodeDef` with explicit input/output path
|
||||
bindings. **ConditionNode** evaluates structured JSON expressions (not code
|
||||
strings). **ForeachNode** iterates serial or concurrent. **InterruptNode**
|
||||
pauses for typed external input. **EndNode** sets non-`ok` workflow outcomes.
|
||||
Current source families:
|
||||
|
||||
## Path Bindings
|
||||
| Source | Kind | Role |
|
||||
| --- | --- | --- |
|
||||
| `wf.std` | `system` | built-in standard workflow nodes and reducers |
|
||||
| `wf.recipes` | `system` | first-party workflow recipes |
|
||||
| MCP sources | `connection` | upstream MCP tools/resources/prompts via persistent sessions |
|
||||
| Python sources | `python` | trusted project-local `NodeSpec` registries |
|
||||
|
||||
Bindings connect graph state to node-local payloads using structural paths:
|
||||
The first explicit provider seam is intentionally small:
|
||||
|
||||
```python
|
||||
class WorkflowSourceProvider(Protocol):
|
||||
def load_sources(self) -> Mapping[str, CapabilitySource]: ...
|
||||
```
|
||||
|
||||
This seam is for static source inventory. MCP also has runtime pools,
|
||||
auth/catalog stores, admin/apply behavior, and live checks, so it should not be
|
||||
forced into a tiny static interface too early.
|
||||
|
||||
## Demo: Python Source End To End
|
||||
|
||||
Write `ops.py`:
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from wf_authoring import node
|
||||
|
||||
|
||||
class EchoInput(BaseModel):
|
||||
text: str
|
||||
|
||||
|
||||
class EchoOutput(BaseModel):
|
||||
echoed: str
|
||||
|
||||
|
||||
@node(name="echo")
|
||||
def echo(payload: EchoInput) -> EchoOutput:
|
||||
return EchoOutput(echoed=payload.text)
|
||||
|
||||
|
||||
registry = [echo]
|
||||
```
|
||||
|
||||
Configure it:
|
||||
|
||||
```json
|
||||
{
|
||||
"input": [
|
||||
{ "target": { "root": "local", "parts": ["text"] },
|
||||
"path": { "root": "input", "parts": ["text"] } }
|
||||
],
|
||||
"output": [
|
||||
{ "source": { "root": "local", "parts": ["echoed"] },
|
||||
"target": { "root": "state", "parts": ["echoed"] } }
|
||||
]
|
||||
"version": 1,
|
||||
"client": {
|
||||
"target": {
|
||||
"kind": "rpc_http",
|
||||
"url": "http://127.0.0.1:8766/rpc",
|
||||
"timeout_seconds": 30
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"store": {"kind": "filesystem", "root": ".wf_python_store"},
|
||||
"transports": [
|
||||
{"kind": "rpc_http", "host": "127.0.0.1", "port": 8766, "path": "/rpc"}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"kind": "python",
|
||||
"id": "local.ops",
|
||||
"path": ".",
|
||||
"module": "ops",
|
||||
"registry": "registry"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Three path kinds: **LocalPath** (node payload), **GraphSourcePath**
|
||||
(read from `input`/`state`/`context`), **StatePath** (write to state).
|
||||
Validate before starting:
|
||||
|
||||
## State Reducers
|
||||
|
||||
State fields declare merge behavior. This matters for parallel and foreach
|
||||
execution where multiple writers target the same path.
|
||||
|
||||
| Reducer | Policy | Use case |
|
||||
|:--------|:-------|:---------|
|
||||
| `wf.std.replace` | exclusive | Default scalars |
|
||||
| `wf.std.append` | mergeable | Foreach accumulation |
|
||||
| `wf.std.merge_object` | mergeable | Parallel object updates |
|
||||
| `wf.std.add` | mergeable | Counters |
|
||||
| `wf.std.set_union` | mergeable | Tag/ID collection |
|
||||
|
||||
# Runtime Execution \status{implemented}
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```mermaid
|
||||
flowchart
|
||||
A["execute_workflow()"] --> B["prepare_new_run()"]
|
||||
B --> C["create_run_state()"]
|
||||
C --> D["resume_workflow()"]
|
||||
D --> E{"select_next_frame()"}
|
||||
E -->|"frame found"| F["step_workflow()"]
|
||||
F --> G{"interrupted?"}
|
||||
G -->|Yes| H["return RunState"]
|
||||
G -->|No| E
|
||||
E -->|"no frames"| I{"classify terminal"}
|
||||
I -->|"completed"| J["finalize_run()"]
|
||||
I -->|"failed"| K["return RunState"]
|
||||
J --> M["return RunState"]
|
||||
```powershell
|
||||
uv run wf config validate wf.python.config.json
|
||||
```
|
||||
|
||||
The executor loops: select a frame from the ready queue, dispatch one step,
|
||||
re-enqueue or terminate. It never thinks. It only routes.
|
||||
Start the server:
|
||||
|
||||
## Step Dispatch
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
SW["step_workflow()"] -->|"NodeUse"| NE["execute node"]
|
||||
SW -->|"Condition"| CE["evaluate"]
|
||||
SW -->|"Foreach"| FE["foreach step"]
|
||||
SW -->|"Join"| JO["done"]
|
||||
SW -->|"End"| EN["complete"]
|
||||
SW -->|"Interrupt"| IR["pause run"]
|
||||
SW -->|"Subgraph"| SG["child scope"]
|
||||
```powershell
|
||||
uv run wf-rpc-server --config wf.python.config.json
|
||||
```
|
||||
|
||||
Node handlers are registered callables---anything from a thin MCP tool wrapper
|
||||
to a full Python function. The executor does not distinguish handler origin; it
|
||||
resolves by name from the registry, invokes, validates, and commits.
|
||||
Call the capability:
|
||||
|
||||
## Node Execution
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant E as Executor
|
||||
participant H as Handler
|
||||
participant S as State
|
||||
|
||||
E->>E: resolve input bindings
|
||||
E->>H: handler(payload, context)
|
||||
H-->>E: NodeResult{outcome, output}
|
||||
E->>E: validate outcome + output
|
||||
E->>S: commit state patch (reducer-aware)
|
||||
E->>E: record trace, advance frame
|
||||
```powershell
|
||||
uv run wf --config wf.python.config.json cap call local.ops.echo --input '{"text":"hello"}'
|
||||
```
|
||||
|
||||
Two channels stay separate: **outcome** controls routing, **output** carries
|
||||
typed business data.
|
||||
Turn it into a saved workflow:
|
||||
|
||||
## Scheduler
|
||||
```powershell
|
||||
uv run wf --config wf.python.config.json draft create-from-capability `
|
||||
python_echo_ws local.ops.echo --name python_echo
|
||||
|
||||
The scheduler uses an explicit FIFO **ready queue** of frame IDs.
|
||||
uv run wf --config wf.python.config.json draft save python_echo_ws `
|
||||
--artifact python_echo `
|
||||
--version 1 `
|
||||
--title "Python Echo" `
|
||||
--outcome ok `
|
||||
--binding local.ops=local.ops `
|
||||
--binding wf.std=wf.std
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> PENDING
|
||||
PENDING --> RUNNING: scheduler selects
|
||||
RUNNING --> PENDING: re-enqueue
|
||||
RUNNING --> COMPLETED: reached end
|
||||
RUNNING --> FAILED: unhandled error
|
||||
RUNNING --> INTERRUPTED: interrupt node
|
||||
RUNNING --> BLOCKED: waiting on child
|
||||
BLOCKED --> PENDING: child completes
|
||||
INTERRUPTED --> PENDING: resume delivered
|
||||
uv run wf --config wf.python.config.json deploy save python_echo.default `
|
||||
--artifact python_echo `
|
||||
--version 1 `
|
||||
--binding local.ops=local.ops `
|
||||
--binding wf.std=wf.std
|
||||
|
||||
uv run wf --config wf.python.config.json run start python_echo.default `
|
||||
--input '{"text":"hello workflow"}'
|
||||
```
|
||||
|
||||
When the ready queue is empty, the scheduler classifies the run as completed,
|
||||
interrupted, failed, or deadlocked.
|
||||
Expected run result:
|
||||
|
||||
# Foreach \status{implemented}
|
||||
|
||||
## Serial
|
||||
|
||||
Each iteration creates a child frame, blocks the parent, and runs to
|
||||
completion before the next item starts.
|
||||
|
||||
## Concurrent
|
||||
|
||||
Multiple item frames run simultaneously. Each gets its own **lineage**---a
|
||||
write overlay that isolates sibling state. At the barrier, patches commit in
|
||||
item-index order through declared reducers.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
PF["foreach parent"] --> C1["item 0"]
|
||||
PF --> C2["item 1"]
|
||||
PF --> C3["item 2"]
|
||||
C1 & C2 & C3 --> BUF["buffer patches"]
|
||||
BUF --> BARRIER["barrier: all done?"]
|
||||
BARRIER --> COMMIT["commit in index order"]
|
||||
COMMIT --> DONE["done / completed_with_errors"]
|
||||
```json
|
||||
{
|
||||
"status": "completed",
|
||||
"outcome": "ok",
|
||||
"output": {"echoed": "hello workflow"}
|
||||
}
|
||||
```
|
||||
|
||||
Capacity is bounded by `ForeachConcurrentPolicy`: `max_active` (default 4)
|
||||
limits ready/running item frames; `max_outstanding` (default 20) limits
|
||||
active + blocked. Item error policies: **fail** (stop), **skip** (continue,
|
||||
no state), **collect** (continue, write structured error records).
|
||||
## What Works Today
|
||||
|
||||
# Interrupts \status{implemented}
|
||||
- CLI can target local or remote workflow servers.
|
||||
- JSON-RPC server can run from neutral config.
|
||||
- `wf config validate` checks config shape, config-relative paths, and trusted
|
||||
Python source imports.
|
||||
- `wf status` summarizes target, sources, capabilities, runs, admin surfaces,
|
||||
and registry availability.
|
||||
- Capabilities can be listed, inspected, and called directly.
|
||||
- Drafts can be created from capabilities and saved as immutable artifacts.
|
||||
- Deployments bind logical sources to concrete sources.
|
||||
- Runs are persisted at stopped boundaries and can be inspected/listed.
|
||||
- MCP upstream sessions are stateful through `McpRuntimePool`.
|
||||
- Python sources can run through the full draft -> artifact -> deployment -> run
|
||||
lifecycle.
|
||||
|
||||
Interrupts are graph-native and typed, not arbitrary line-level pauses.
|
||||
## Honest Limits
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant N as Node
|
||||
participant I as InterruptNode
|
||||
participant R as Runtime
|
||||
participant E as Caller
|
||||
- Python sources are trusted in-process code; there is no sandbox.
|
||||
- Python sources are static at server startup; no hot reload yet.
|
||||
- Python source registry/apply support is not implemented yet.
|
||||
- `WorkflowSourceProvider` covers static inventory only, not runtime/admin/apply
|
||||
lifecycle.
|
||||
- Run deletion is not implemented.
|
||||
- File-backed stores are the proven storage backend; SQL/secret-manager stores
|
||||
are future work.
|
||||
- MCP app/widget passthrough is not a durable workflow product feature yet.
|
||||
|
||||
N->>I: outcome "needs_input"
|
||||
I->>R: InterruptRequest{kind, payload}
|
||||
R->>E: surface request
|
||||
E->>R: resume payload + outcome
|
||||
R->>I: map resume into state
|
||||
I->>I: continue routing
|
||||
```
|
||||
## Next Direction
|
||||
|
||||
Pause points stay visible in the graph. Payloads are validated by `kind`.
|
||||
Traces stay clean.
|
||||
Near-term work should make source providers more regular without prematurely
|
||||
flattening them:
|
||||
|
||||
# Subgraph Composition \status{implemented}
|
||||
- Provider lifecycle for add/update/remove/apply/reload across source families.
|
||||
- OpenAPI source provider using the same `CapabilitySource` shape.
|
||||
- Clearer config/status diagnostics for source health.
|
||||
- Optional Python source development reload.
|
||||
- Production-grade auth/secret store integration.
|
||||
|
||||
A workflow can be used as a node, giving **graph composition** with one
|
||||
consistent contract.
|
||||
## Reading Map
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Parent["Parent"]
|
||||
P1["A"] --> SG["SubgraphNode"]
|
||||
SG --> P2["C"]
|
||||
end
|
||||
subgraph Child["Child (prepared)"]
|
||||
C1["X"] --> C2["Y"]
|
||||
end
|
||||
SG --> C1
|
||||
C2 --> SG
|
||||
```
|
||||
|
||||
The parent supplies input bindings. The child runs in its own scope with its
|
||||
own lineage. Output bindings project child state back to the parent.
|
||||
|
||||
**Interrupt bubbling (v1):** When a child subgraph hits an interrupt node, the
|
||||
runtime constructs an `InterruptRoute` that identifies the child frame, scope,
|
||||
and workflow ref. The parent subgraph frame stays `BLOCKED`; the entire run
|
||||
returns `INTERRUPTED`. Resume restores the child scope and continues inside it.
|
||||
This works for prepared local children. Artifact/deployment resolution for
|
||||
nested saved children remains outside core; the platform resolves saved
|
||||
descendants before execution starts.
|
||||
|
||||
# Authoring Layer \status{implemented}
|
||||
|
||||
## WorkflowBuilder
|
||||
|
||||
Fluent Python DSL for constructing workflows without raw dicts:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
WB["WorkflowBuilder"] -->|"use(spec)"| NU["NodeUse"]
|
||||
WB -->|"condition()"| CN["Condition"]
|
||||
WB -->|"foreach()"| FE["Foreach"]
|
||||
WB -->|"interrupt()"| IN["Interrupt"]
|
||||
WB -->|"compile()"| WF["Workflow"]
|
||||
```
|
||||
|
||||
Common operations: `use(spec)`, `connect(from, outcome, to)`,
|
||||
`branch(from, branches)`, `when(cond, then, otherwise)`,
|
||||
`match(value, cases)`, `foreach(over, mode)`.
|
||||
|
||||
## @node Decorator
|
||||
|
||||
Converts a typed Python function into a reusable `NodeSpec`:
|
||||
|
||||
```python
|
||||
@node(name="summarize", outcomes=["ok"])
|
||||
def summarize_doc(input: SummarizeInput, ctx: RuntimeContext) -> SummarizeOutput:
|
||||
"""Summarize a single document."""
|
||||
return SummarizeOutput(summary=input.text[:500])
|
||||
```
|
||||
|
||||
The decorator infers input/output models from type annotations, detects async,
|
||||
and generates the `NodeDef` with schema refs.
|
||||
|
||||
# MCP Platform \status{implemented}
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Server["Unified MCP Server"]
|
||||
Admin["wf.admin.*"]
|
||||
Wf["wf.workflow.*"]
|
||||
Proxy["connection.tool_name"]
|
||||
end
|
||||
subgraph Broker["WfMcpService"]
|
||||
Cat["catalog"]
|
||||
Disc["discovery"]
|
||||
Art["artifacts"]
|
||||
Drf["drafts"]
|
||||
end
|
||||
subgraph ProxyLayer["ProxyRuntime"]
|
||||
Mount["mount registry"]
|
||||
FMP["proxy per connection"]
|
||||
end
|
||||
Server --> Broker
|
||||
Server --> ProxyLayer
|
||||
ProxyLayer --> Upstream["Upstream MCP Servers"]
|
||||
```
|
||||
|
||||
Each upstream connection gets a namespaced `FastMCPProxy` mount
|
||||
(`connection_id.tool_name`). Hot reload is best-effort; FastMCP lacks a
|
||||
complete unmount lifecycle.
|
||||
|
||||
## Tool Conversion
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
DT["DiscoveredTool"] --> WDT["wrap_discovered_tool()"]
|
||||
WDT --> NS["NodeSpec"]
|
||||
NS --> CS["CapabilitySource"]
|
||||
```
|
||||
|
||||
Every MCP tool gets `outcomes=("ok", "error")` by default. The wrapper
|
||||
preserves the original JSON Schema as a contract and generates an async
|
||||
handler that calls the upstream tool.
|
||||
|
||||
# Artifact Lifecycle \status{implemented}
|
||||
|
||||
## Draft to Deployment
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
D["Draft<br/>(mutable)"] -->|"compile"| A["Artifact<br/>(immutable)"]
|
||||
A -->|"bind sources"| DP["Deployment"]
|
||||
DP -->|"execute"| R["Run"]
|
||||
```
|
||||
|
||||
**Draft workspaces** support iterative LLM authoring with optimistic
|
||||
concurrency (revision-checked patches). **Artifacts** are versioned snapshots
|
||||
with dependency contract hashes. **Deployments** bind logical source aliases
|
||||
to concrete MCP connections.
|
||||
|
||||
## Durable Runs \status{v1 boundaries}
|
||||
|
||||
Every `run_deployment` call persists a stopped run record (file-backed JSON)
|
||||
with a stable `run_id`. Interrupted runs can be resumed via `resume_run` after
|
||||
process restart, provided the same `FileRunStore` root is accessible.
|
||||
|
||||
**V1 limits:**
|
||||
|
||||
- Checkpointing happens at stopped boundaries only (interrupted, completed,
|
||||
failed). No per-node or mid-call crash recovery.
|
||||
- Resume revalidates the pinned dependency environment. If a required source is
|
||||
missing or disabled, resume returns `resume_readiness=blocked` without
|
||||
consuming the payload.
|
||||
- During live execution, source failures produce a `failed` run, not a
|
||||
`blocked` one. The `blocked` gate applies only at resume time.
|
||||
|
||||
Two deployments can point the same artifact at different accounts:
|
||||
|
||||
```
|
||||
summarize_docs.personal -> context7.personal
|
||||
summarize_docs.work -> context7.work
|
||||
```
|
||||
|
||||
# Validation \status{implemented}
|
||||
|
||||
## Structural (Pre-Execution)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
VW["validate_workflow()"] --> A["node def uniqueness"]
|
||||
VW --> B["node id uniqueness"]
|
||||
VW --> C["edge source/dest existence"]
|
||||
VW --> D["outcome declarations"]
|
||||
VW --> E["binding path validity"]
|
||||
VW --> F["reachable outcome wiring"]
|
||||
```
|
||||
|
||||
Reports multiple issues via `ValidationReport` instead of failing at the
|
||||
first.
|
||||
|
||||
## Runtime
|
||||
|
||||
At runtime: outcome is declared, output matches schema, merge conflicts are
|
||||
caught, final output validates against `output_schema`.
|
||||
|
||||
# Open Questions
|
||||
|
||||
- Should the legacy same-name top-level state output fallback be removed once
|
||||
explicit final output bindings are used everywhere?
|
||||
- Trace model for raw extra node output?
|
||||
- Isolated pure-Python execution: node type, tool backend, or separate API?
|
||||
- Retry policy vs non-idempotent side-effecting tools?
|
||||
|
||||
# Stack
|
||||
|
||||
| Layer | Technology |
|
||||
|:------|:-----------|
|
||||
| Language | Python 3.14+ |
|
||||
| Validation | Pydantic v2 |
|
||||
| Tool protocol | MCP |
|
||||
| MCP framework | FastMCP 3.2.4+ |
|
||||
| Storage | File-backed JSON stores today; SQLite/PostgreSQL planned |
|
||||
|
||||
---
|
||||
|
||||
*Incomplete. See `docs/README.md` for the full documentation index.*
|
||||
- [`wf_cli.md`](../wf_cli.md): CLI command reference.
|
||||
- [`runbooks/python-source.md`](../runbooks/python-source.md): Python source
|
||||
runbook.
|
||||
- [`source_architecture.md`](../source_architecture.md): source provider
|
||||
package map.
|
||||
- [`project_map.md`](../project_map.md): package and entrypoint map.
|
||||
- [`current_roadmap.md`](../current_roadmap.md): active roadmap.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# goal:
|
||||
# use pandoc -M to change the key: diagram:engine:mermaid:outputFormat to svg or pdf if output is html or pdf.
|
||||
# use the script at stuff/pandoc-diagram.ps1 to set the env vars and pass the filter to pandoc.
|
||||
param(
|
||||
[string]$type,
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
[string[]]$RemainingArgs
|
||||
)
|
||||
function funny([string] $output) {
|
||||
return @{
|
||||
"diagram" = @{
|
||||
"engine" = @{
|
||||
"mermaid" = @{
|
||||
"outputFormat" = "$output"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#
|
||||
if ($type -eq "html") {
|
||||
$outputFormat = "svg"
|
||||
}
|
||||
elseif ($type -eq "pdf") {
|
||||
$outputFormat = "pdf"
|
||||
}
|
||||
else {
|
||||
Write-Error "Unsupported type: $type. Supported types are: html, pdf."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$metadata = funny $outputFormat | ConvertTo-Json -Depth 10
|
||||
$pandoc_diagram = Join-Path $PSScriptRoot "../../stuff/pandoc-diagram.ps1"
|
||||
|
||||
$metatempfile = New-TemporaryFile
|
||||
|
||||
try {
|
||||
Set-Content -Path $metatempfile -Value $metadata
|
||||
& $pandoc_diagram --metadata-file=$metatempfile --embed-resources --standalone @RemainingArgs
|
||||
}
|
||||
finally {
|
||||
Remove-Item $metatempfile
|
||||
}
|
||||
+235
-7
@@ -14,6 +14,49 @@ The short version:
|
||||
> The LLM plans. The runtime executes. Source providers expose capabilities.
|
||||
> Stores preserve durable workflow state.
|
||||
|
||||
## Research Question
|
||||
|
||||
Primary research question:
|
||||
|
||||
> How can an AI-agent-facing workflow platform represent, validate, execute, and
|
||||
> persist reusable workspace automations while keeping planning separate from
|
||||
> deterministic execution?
|
||||
|
||||
Product motivation:
|
||||
|
||||
> How can external AI agents help workspace operators create reusable
|
||||
> automations without requiring them to write scripts, while preserving
|
||||
> validation, inspection, and durable execution?
|
||||
|
||||
## Main Contribution
|
||||
|
||||
The thesis contribution is a platform architecture, not a new foundation model:
|
||||
|
||||
1. typed workflow artifact/deployment/run lifecycle
|
||||
2. source-provider boundary for MCP, Python, and future OpenAPI sources
|
||||
3. durable server/API/CLI surface that external agents can drive
|
||||
4. validation and inspection mechanisms that reduce planner trial-and-error
|
||||
5. next-action guidance that points an agent toward useful lifecycle operations
|
||||
without replacing validation
|
||||
|
||||
## Working Title
|
||||
|
||||
Safer current title:
|
||||
|
||||
> Design and Implementation of lda.chat: Infrastructure for AI Agents to Author
|
||||
> and Execute Workspace Workflows
|
||||
|
||||
Aspirational product title:
|
||||
|
||||
> Design and Implementation of lda.chat: An AI Agent Platform for Authoring and
|
||||
> Executing Workspace Workflows
|
||||
|
||||
Use the safer title if the thesis must describe exactly what exists today:
|
||||
external agents such as Claude Desktop and OpenCode can drive the platform, but
|
||||
`lda.chat` does not yet bundle its own autonomous agent brain. Use the
|
||||
aspirational title only if the thesis explicitly frames `lda.chat` as the
|
||||
platform intended to host or serve AI agents, not as a completed built-in agent.
|
||||
|
||||
## 1. Problem Statement
|
||||
|
||||
Current agent/tool systems often let the LLM directly orchestrate side effects
|
||||
@@ -27,9 +70,14 @@ through ad hoc tool calls. This creates practical problems:
|
||||
|
||||
The thesis should frame the platform as a response to those pressures.
|
||||
|
||||
The automation target is reusable workspace procedures, not arbitrary office
|
||||
work end-to-end. Examples include document transformation, data collection,
|
||||
tool/API calls, report preparation, monitoring checks, and scheduled workspace
|
||||
operations.
|
||||
|
||||
## 2. Thesis
|
||||
|
||||
The proposed model is a workflow platform for AI-assisted work:
|
||||
The proposed model is a prototype platform for AI-assisted work:
|
||||
|
||||
- workflows are typed graphs
|
||||
- source capabilities are exposed through explicit contracts
|
||||
@@ -38,21 +86,54 @@ The proposed model is a workflow platform for AI-assisted work:
|
||||
- clients interact through stable APIs/transports rather than direct runtime
|
||||
internals
|
||||
|
||||
Natural language belongs in the authoring loop: a workspace operator can express
|
||||
intent to an external LLM agent, but the reusable output should be a typed
|
||||
workflow artifact and deployment rather than an opaque prompt transcript.
|
||||
|
||||
Be explicit about actors:
|
||||
|
||||
- the workflow owner wants to see useful workflow runs and outputs
|
||||
- the external LLM agent may be the one driving CLI/API operations
|
||||
- the developer/operator configures sources, secrets, server processes, and
|
||||
trusted Python code
|
||||
|
||||
The CLI should be described as agent-operable first and human-usable second. Its
|
||||
structured output, status/inspect/list commands, validation commands, compact
|
||||
summaries, and guarded destructive actions make it a practical surface for
|
||||
external agents.
|
||||
|
||||
This is not a claim that LLMs cannot operate tools. It is a claim that durable,
|
||||
inspectable, reusable work benefits from a separate execution substrate.
|
||||
|
||||
Use “prototype platform” deliberately. The implementation proves the core
|
||||
lifecycle and architecture, but it is not yet a finished product with scheduling,
|
||||
visual workflow editing, production secrets, general fork/gather, and broad
|
||||
real-world evaluation.
|
||||
|
||||
Next actions and repairable validation failures should be framed as
|
||||
machine-client UX. Human interfaces use buttons and affordances; an agent-facing
|
||||
API needs compact structured hints, stable diagnostic fields, and suggested next
|
||||
operations so an LLM agent can recover without blind probing.
|
||||
|
||||
## 3. Design Goals
|
||||
|
||||
The design goals should be stated early and then revisited in evaluation:
|
||||
|
||||
- deterministic execution
|
||||
- validation-centered lifecycle for LLM-authored workflows
|
||||
- typed inputs, state, outputs, and node payloads
|
||||
- explicit source binding
|
||||
- scoped workflow portability through artifact requirements and deployment
|
||||
binding contracts
|
||||
- durable artifacts, deployments, and stopped runs
|
||||
- inspectable trace slices
|
||||
- reviewable lifecycle points for drafts, deployments, runs, diagnostics, and
|
||||
guarded destructive actions
|
||||
- resumability after interruption
|
||||
- transport neutrality for CLI, server, and future UI/MCP clients
|
||||
- source-provider extensibility for MCP, Python, OpenAPI, and future families
|
||||
- source-provider correctness, especially for external systems whose tools,
|
||||
resources, prompts, or authentication depend on initialized stateful sessions
|
||||
|
||||
## 4. Architecture
|
||||
|
||||
@@ -69,18 +150,39 @@ wf_cli
|
||||
Important layers:
|
||||
|
||||
- `wf_core`: deterministic workflow kernel
|
||||
- `wf_authoring`: Python authoring helpers and `NodeSpec` creation
|
||||
- `wf_authoring`: authoring support for `NodeSpec`, drafts, wrappers, API
|
||||
surfaces, source providers, and MCP/admin tools
|
||||
- `wf_api`: application surface for capabilities, drafts, artifacts,
|
||||
deployments, runs, and admin/source operations
|
||||
- `wf_server`: durable server composition boundary
|
||||
- `wf_transport_rpc_http`: JSON-RPC-over-HTTP transport
|
||||
- `wf_sources_mcp`: MCP upstream source implementation and persistent runtime
|
||||
- `wf_sources_python`: trusted in-process Python source loading
|
||||
- `wf_mcp`: legacy/special-purpose MCP frontend and compatibility package
|
||||
- `wf_mcp`: legacy/special-purpose MCP compatibility package
|
||||
|
||||
The thesis should explain why the old “everything in MCP” shape was split:
|
||||
transport, source provider, workflow API, and runtime concerns are different.
|
||||
|
||||
Architecture spine:
|
||||
|
||||
- workflow core: deterministic execution semantics for graph, state, outcomes,
|
||||
trace, and resume rules
|
||||
- platform domain: artifacts, deployments, runs, stores, sources, binding
|
||||
contracts, validation, and admin concepts
|
||||
- workflow API surface: lifecycle operations exposed to clients
|
||||
- server/transport composition: concrete stores, sources, runtimes, and
|
||||
communication mechanisms
|
||||
|
||||
JSON-RPC is an implementation of the Workflow API Surface. It should not be
|
||||
presented as the product boundary or as the place where workflow semantics live.
|
||||
`wf_server` is composition: it assembles concrete stores, sources, runtimes, and
|
||||
admin surfaces into a long-lived service. It should not own workflow semantics.
|
||||
`wf_authoring` is support infrastructure used by drafts, API surfaces, source
|
||||
providers, and MCP tools; it is not a fifth runtime/product layer.
|
||||
If MCP is discussed, distinguish upstream MCP sources from a future client-facing
|
||||
MCP frontend. The former exists as a source family; the latter should not be
|
||||
claimed as a completed clean platform surface.
|
||||
|
||||
## 5. Workflow Model
|
||||
|
||||
Describe workflows as typed graphs:
|
||||
@@ -94,11 +196,43 @@ Describe workflows as typed graphs:
|
||||
- interrupts: represent typed external input points
|
||||
- subgraphs: compose workflows as nodes
|
||||
|
||||
Separate lifecycle objects:
|
||||
|
||||
- draft workspace: mutable authoring state for agent/user iteration
|
||||
- workflow artifact: immutable versioned workflow definition
|
||||
- deployment: binding contract from artifact version to concrete source/runtime
|
||||
context
|
||||
- run: execution record with status, diagnostics, output, trace, and resumable
|
||||
stopped/interrupted state where applicable
|
||||
|
||||
Key distinction:
|
||||
|
||||
- outcome controls routing
|
||||
- output carries business data
|
||||
|
||||
The graph model is also a safety boundary. It is not safer because it can make
|
||||
all tools safe; it is safer than arbitrary generated scripts because structure,
|
||||
schemas, source bindings, state, outcomes, and review points are explicit. This
|
||||
is the answer to “why not just have the AI write a Playwright script?” Scripts
|
||||
can be simple and maintainable, but they do not automatically provide the same
|
||||
validation and lifecycle affordances.
|
||||
|
||||
Code ends at the source-provider boundary. A workflow can call trusted Python,
|
||||
Playwright, API, MCP, or future LLM capabilities, but those should appear as
|
||||
typed source capabilities. The workflow itself remains an orchestration artifact,
|
||||
not an embedded code blob.
|
||||
|
||||
Durability is a contract over time, not just storage. Artifacts, deployments,
|
||||
bindings, run records, and traces preserve workflow intent. Validation against
|
||||
the current source catalog determines whether that intent is still runnable. If
|
||||
a source changes incompatibly and a deployment becomes `unrunnable`, the system
|
||||
has preserved the contract instead of silently drifting.
|
||||
|
||||
Trace claims should be grounded in the current code: run summaries expose
|
||||
`trace_count`, and clients can request caller-bounded trace slices for debugging.
|
||||
Do not overstate this as production observability, distributed tracing, metrics,
|
||||
or OpenTelemetry support.
|
||||
|
||||
## 6. Source Model
|
||||
|
||||
The common boundary is `CapabilitySource`.
|
||||
@@ -116,6 +250,9 @@ The thesis should stress that the runtime does not care where a `NodeSpec` came
|
||||
from. Source-specific behavior belongs in provider packages and server
|
||||
composition.
|
||||
|
||||
MCP should be presented as one source family and a useful stress test for
|
||||
source-provider correctness, not as the platform identity.
|
||||
|
||||
Current provider seam:
|
||||
|
||||
```python
|
||||
@@ -126,6 +263,10 @@ class WorkflowSourceProvider(Protocol):
|
||||
This seam is intentionally narrow: it covers static inventory, not runtime
|
||||
pools, admin/apply, auth, or live health checks.
|
||||
|
||||
For MCP, source-provider correctness includes stateful runtime behavior. A
|
||||
workflow capability call should not silently turn a stateful external provider
|
||||
into a fresh one-off client call when provider state is part of correctness.
|
||||
|
||||
## 7. Implementation Vertical Slice
|
||||
|
||||
Use the working product path as evidence:
|
||||
@@ -155,6 +296,10 @@ A strong demonstration is the Python source flow:
|
||||
|
||||
This shows the source abstraction is not MCP-only.
|
||||
|
||||
Frame Python sources as trusted developer extensibility. They are useful because
|
||||
project-local code can become typed workflow capabilities quickly, but they are
|
||||
not sandboxed non-programmer plugins yet.
|
||||
|
||||
## 8. Evaluation
|
||||
|
||||
Evaluation should use concrete evidence:
|
||||
@@ -163,12 +308,44 @@ Evaluation should use concrete evidence:
|
||||
- live smoke test against `wf-rpc-server`
|
||||
- durable run/resume tests
|
||||
- stateful MCP session reuse tests
|
||||
- MCP source-provider correctness tests covering tools, resources, prompts, and
|
||||
session reuse through the same server path
|
||||
- Python source workflow-run integration test
|
||||
- config validation catching import/path errors before server startup
|
||||
- planner-efficiency checks: validation, source catalogs, compact output, and
|
||||
inspectable errors should reduce repeated blind LLM attempts
|
||||
- next-action guidance should reduce planner uncertainty before and after
|
||||
validation calls
|
||||
- attempt-count comparison on representative tasks, for example old interaction
|
||||
traces with many failed attempts versus the current structured lifecycle
|
||||
- draft-validation and run-failure analysis, especially cases where old session
|
||||
or source assumptions caused repeated failed runs
|
||||
- source-drift cases where old deployments become unrunnable with diagnostics
|
||||
instead of silently executing against incompatible capabilities
|
||||
|
||||
Avoid vague claims such as “robust” or “production-ready” unless backed by
|
||||
specific checks.
|
||||
|
||||
Evidence package:
|
||||
|
||||
- architecture/code walkthrough tied to the four-layer model
|
||||
- automated tests for lifecycle, validation, source providers, persistence,
|
||||
resume, stateful MCP reuse, and Python source integration
|
||||
- live CLI/server smoke run
|
||||
- before/after failed-attempt case study from old ad-hoc interaction to
|
||||
structured workflow lifecycle
|
||||
- explicit limitations and future work
|
||||
|
||||
Recommended case study:
|
||||
|
||||
- document/report preparation, not an echo demo
|
||||
- deterministic current sources first, such as Python source text transforms
|
||||
- optional/future LLM summarization as a typed source capability, not required
|
||||
- output should be a structured report or Markdown/JSON artifact that a workflow
|
||||
owner would plausibly want
|
||||
- package the example with fixture input, Python source code, workflow config,
|
||||
store/environment setup, and CLI/server commands
|
||||
|
||||
Possible evaluation questions:
|
||||
|
||||
- Can a source capability be discovered, called, saved into a workflow, deployed,
|
||||
@@ -177,6 +354,43 @@ Possible evaluation questions:
|
||||
- Can the same server be used through CLI and JSON-RPC transport?
|
||||
- Can a new source family be added without changing `wf_core`?
|
||||
- Are large/raw provider payloads bounded in CLI output?
|
||||
- Can an external LLM agent converge on a valid workflow without spending most
|
||||
of the interaction on tool-output spam and trial-and-error?
|
||||
- Does the structured surface reduce failed attempts before success compared to
|
||||
earlier ad-hoc agent/tool interaction traces?
|
||||
- Do `wf draft validate`, deployment validation, and run inspection catch or
|
||||
explain the kinds of issues that previously caused repeated failed runs?
|
||||
- Does deployment validation surface source drift as runnable/unrunnable state
|
||||
with diagnostics rather than silent behavior changes?
|
||||
|
||||
## 8.1 Positioning Against Existing Automation Platforms
|
||||
|
||||
The thesis should discuss the space it fits into through multiple baselines:
|
||||
direct LLM tool use, manual scripts, Zapier-style automation platforms, RPA
|
||||
tools, and workflow engines. The goal is not to claim feature parity with mature
|
||||
products. The goal is to explain the trade-off this prototype explores.
|
||||
|
||||
Zapier and similar platforms are stronger today at:
|
||||
|
||||
- polished non-programmer UI
|
||||
- large integration catalogs
|
||||
- hosted scheduling and triggers
|
||||
- operational maturity
|
||||
|
||||
Manual scripts are powerful and often faster for technical users, so the thesis
|
||||
should not dismiss them. The fair comparison is accessibility and adaptability:
|
||||
how much skill and maintenance effort is required before a workspace operator or
|
||||
external agent can turn a repeated task into a reusable workflow?
|
||||
|
||||
This prototype explores a different center of gravity:
|
||||
|
||||
- external AI agents can drive the authoring/execution lifecycle directly
|
||||
- workflows are typed graphs with explicit schemas and source bindings
|
||||
- local Python, MCP, and future OpenAPI sources can share one workflow surface
|
||||
- runs, traces, artifacts, and deployments are first-class inspectable records
|
||||
|
||||
Use the comparison to position the work, not as a claim that the prototype
|
||||
outperforms existing automation products.
|
||||
|
||||
## 9. Limitations
|
||||
|
||||
@@ -185,11 +399,19 @@ State limitations explicitly:
|
||||
- Python sources are trusted in-process code; no sandbox yet.
|
||||
- Python sources are static at server startup; no hot reload yet.
|
||||
- Source provider lifecycle is early, especially for non-MCP mutable sources.
|
||||
- File-backed stores are the proven storage backend; SQL/secret manager support
|
||||
is future work.
|
||||
- Workflow portability is scoped; local Python code, MCP catalogs, auth records,
|
||||
and source stores can differ between environments.
|
||||
- File-backed stores are the current implementation proof for durable lifecycle;
|
||||
durability itself should not be framed as filesystem-specific.
|
||||
- Auth records/admin surfaces exist as prototype plumbing, but end-to-end
|
||||
production credential handling is not verified as a core thesis claim.
|
||||
- Run deletion is not implemented.
|
||||
- MCP widgets/apps are not carried through the durable workflow path.
|
||||
- MCP widget/resource proxying is not supported; upstream interactive widgets
|
||||
are not carried through the durable workflow path.
|
||||
- Crash recovery is at stopped boundaries, not arbitrary mid-node checkpoints.
|
||||
- Offline scheduling is not implemented yet.
|
||||
- General fork/gather workflow control is future work.
|
||||
- There is no full approval, roles, policy, or multi-user review system.
|
||||
|
||||
Limitations make the thesis more credible. They also motivate future work.
|
||||
|
||||
@@ -198,12 +420,17 @@ Limitations make the thesis more credible. They also motivate future work.
|
||||
Likely future-work sections:
|
||||
|
||||
- provider lifecycle: add/update/remove/apply/reload for multiple source families
|
||||
- OpenAPI source provider
|
||||
- OpenAPI or fetch-style source provider for broader HTTP integration
|
||||
- Python development reload
|
||||
- LLM nodes as typed source capabilities
|
||||
- production auth/secret stores
|
||||
- SQL/transactional stores
|
||||
- scheduler/server daemon operations
|
||||
- offline scheduling for deployments
|
||||
- fork/gather workflow control
|
||||
- richer run rewind/time-travel debugging beyond stopped/interrupted resume
|
||||
- UI/admin dashboard
|
||||
- first-party workflow UI for listing, inspecting, and editing workflows
|
||||
- richer evaluation with real workflows and larger source catalogs
|
||||
|
||||
## What Not To Do
|
||||
@@ -220,6 +447,7 @@ Do not claim unimplemented production properties:
|
||||
- no general provider hot reload
|
||||
- no production secret manager
|
||||
- no full MCP widget passthrough
|
||||
- no unmeasured performance or production-readiness claims
|
||||
|
||||
The strongest version is an honest systems argument:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user