docs: add thesis report workflow evidence

This commit is contained in:
lda
2026-06-14 17:16:40 +07:00 Verified
parent 03762b1aa9
commit 1aa40285b1
10 changed files with 328 additions and 3 deletions
+66
View File
@@ -0,0 +1,66 @@
# Report Workflow Example
This example is the deterministic thesis case study. It demonstrates a trusted
Python source that turns project notes into a typed report object without using
remote OAuth, LLM calls, or provider quota.
## Files
- `input.md` — fixture notes.
- `cap-input.json` — capability-call payload generated from the fixture notes.
- `run-input.json` — workflow-run payload generated from the fixture notes.
- `ops.py` — Python source exposing `read_notes`, `extract_report`, and
`render_markdown_report`.
- `wf.config.json` — local server/client config using the `local.report` Python
source.
## Run
From the repository root:
```powershell
uv run wf config validate examples/report_workflow/wf.config.json
uv run wf-rpc-server --config examples/report_workflow/wf.config.json
```
In another terminal:
```powershell
uv run wf --config examples/report_workflow/wf.config.json status
uv run wf --config examples/report_workflow/wf.config.json cap list --source local.report
uv run wf --config examples/report_workflow/wf.config.json cap call local.report.extract_report --input-file examples/report_workflow/cap-input.json --format compact
```
The full artifact/deployment/run path is covered by
`tests/examples/test_report_workflow_example.py`. To exercise the same lifecycle
manually through the CLI, use the source capability as the draft seed:
```powershell
uv run wf --config examples/report_workflow/wf.config.json draft create-from-capability report_ws local.report.extract_report --name report_case_study --title "Report Case Study"
uv run wf --config examples/report_workflow/wf.config.json draft validate report_ws
uv run wf --config examples/report_workflow/wf.config.json draft save report_ws --artifact report_case_study --version 1 --title "Report Case Study" --binding local.report=local.report
uv run wf --config examples/report_workflow/wf.config.json deploy save report_case_study.default --artifact report_case_study --version 1 --binding local.report=local.report
uv run wf --config examples/report_workflow/wf.config.json deploy validate report_case_study.default
uv run wf --config examples/report_workflow/wf.config.json run start report_case_study.default --input-file examples/report_workflow/run-input.json --trace-from 0 --trace-limit 5
uv run wf --config examples/report_workflow/wf.config.json run list --limit 5
uv run wf --config examples/report_workflow/wf.config.json run inspect <run_id>
uv run wf --config examples/report_workflow/wf.config.json run trace <run_id> --from 0 --limit 5
```
The expected report includes:
- title: `Weekly Project Update`
- three action items
- at least one risk mentioning Google Drive MCP quota
- followups for Markdown rendering and baseline comparison
## Thesis Evidence
The example supports these claims:
- Python sources can expose typed capabilities through the same workflow surface
as built-in and MCP sources.
- The case-study path is deterministic and does not depend on an LLM or remote
provider.
- The workflow lifecycle can be exercised through config validation, capability
inventory, capability calls, artifacts, deployments, runs, inspect, and trace.
+3
View File
@@ -0,0 +1,3 @@
{
"text": "# Weekly Project Update\n\nSummary:\nThe workflow platform demo is ready for a deterministic thesis case study. The\nteam wants a repeatable report that does not depend on remote OAuth, LLM output,\nor provider quotas.\n\nActions:\n- Alice | Prepare demo config | Friday\n- Bao | Run five agent attempts | Monday\n- Casey | Capture trace screenshots | Tuesday\n\nRisks:\n- Google Drive MCP quota is too low for regression evidence\n- Unbounded provider output can waste tokens\n\nFollowups:\n- Add optional Markdown renderer\n- Compare direct script baseline against workflow lifecycle\n"
}
+19
View File
@@ -0,0 +1,19 @@
# Weekly Project Update
Summary:
The workflow platform demo is ready for a deterministic thesis case study. The
team wants a repeatable report that does not depend on remote OAuth, LLM output,
or provider quotas.
Actions:
- Alice | Prepare demo config | Friday
- Bao | Run five agent attempts | Monday
- Casey | Capture trace screenshots | Tuesday
Risks:
- Google Drive MCP quota is too low for regression evidence
- Unbounded provider output can waste tokens
Followups:
- Add optional Markdown renderer
- Compare direct script baseline against workflow lifecycle
+110
View File
@@ -0,0 +1,110 @@
from __future__ import annotations
from pathlib import Path
from pydantic import BaseModel, Field
from wf_authoring import node
class ReadInput(BaseModel):
path: str = Field(description="Path to a UTF-8 Markdown notes file.")
class ReadOutput(BaseModel):
text: str
class ExtractInput(BaseModel):
text: str
class ActionItem(BaseModel):
owner: str
task: str
due: str
class ReportOutput(BaseModel):
title: str
summary: str
action_items: list[ActionItem]
risks: list[str]
followups: list[str]
class MarkdownInput(BaseModel):
report: ReportOutput
class MarkdownOutput(BaseModel):
markdown: str
@node(name="read_notes")
def read_notes(payload: ReadInput) -> ReadOutput:
return ReadOutput(text=Path(payload.path).read_text(encoding="utf-8"))
@node(name="extract_report")
def extract_report(payload: ExtractInput) -> ReportOutput:
title = ""
summary_lines: list[str] = []
actions: list[ActionItem] = []
risks: list[str] = []
followups: list[str] = []
section: str | None = None
for raw_line in payload.text.splitlines():
line = raw_line.strip()
if not line:
continue
if line.startswith("# "):
title = line.removeprefix("# ").strip()
continue
if line.endswith(":"):
section = line[:-1].lower()
continue
if section == "summary":
summary_lines.append(line)
elif section == "actions" and line.startswith("- "):
parts = [part.strip() for part in line.removeprefix("- ").split("|")]
if len(parts) == 3:
owner, task, due = parts
actions.append(ActionItem(owner=owner, task=task, due=due))
elif section == "risks" and line.startswith("- "):
risks.append(line.removeprefix("- ").strip())
elif section == "followups" and line.startswith("- "):
followups.append(line.removeprefix("- ").strip())
return ReportOutput(
title=title,
summary=" ".join(summary_lines),
action_items=actions,
risks=risks,
followups=followups,
)
@node(name="render_markdown_report")
def render_markdown_report(payload: MarkdownInput) -> MarkdownOutput:
report = payload.report
lines = [
f"# {report.title}",
"",
report.summary,
"",
"## Action Items",
]
lines.extend(
f"- {item.owner}: {item.task} (due: {item.due})"
for item in report.action_items
)
lines.extend(["", "## Risks"])
lines.extend(f"- {risk}" for risk in report.risks)
lines.extend(["", "## Followups"])
lines.extend(f"- {followup}" for followup in report.followups)
return MarkdownOutput(markdown="\n".join(lines))
registry = [read_notes, extract_report, render_markdown_report]
+3
View File
@@ -0,0 +1,3 @@
{
"text": "# Weekly Project Update\n\nSummary:\nThe workflow platform demo is ready for a deterministic thesis case study. The\nteam wants a repeatable report that does not depend on remote OAuth, LLM output,\nor provider quotas.\n\nActions:\n- Alice | Prepare demo config | Friday\n- Bao | Run five agent attempts | Monday\n- Casey | Capture trace screenshots | Tuesday\n\nRisks:\n- Google Drive MCP quota is too low for regression evidence\n- Unbounded provider output can waste tokens\n\nFollowups:\n- Add optional Markdown renderer\n- Compare direct script baseline against workflow lifecycle\n"
}