fabro/lib/crates
fabro-sh-0530[bot] bf7ce485e1
feat(fabro-types): promote transcript primitives and extend agent event… (#357)
## Summary

This is the foundational step of the unified agent transcript
implementation: it establishes one canonical set of replay types in
`fabro-types` and threads them into the existing `agent.message`,
`agent.tool.started`, and `agent.tool.completed` event shapes — without
breaking any existing producers or consumers.

## What changed

**New `fabro-types::transcript` module** owns `ContentPart`,
`ImageData`, `AudioData`, `DocumentData`, `ThinkingData`, `ToolCall`,
`ToolResult`, `MessageKind`, `MessageSource`, `PairMessageRef`,
`TranscriptMessage`, and `MessageId`. These were previously defined in
`fabro-llm::types`; they now live at the canonical layer.

**`fabro-llm::types`** drops its local definitions and re-exports from
`fabro-types` so every existing `fabro_llm::types::*` import keeps
compiling without change.

**`AgentMessageProps`** gains an optional `message:
Option<TranscriptMessage>` field; `AgentToolStartedProps` gains
`tool_call`, `turn_id`, and `parent_message_id`;
`AgentToolCompletedProps` gains `tool_result` and `turn_id`. All new
fields use `#[serde(default, skip_serializing_if = "Option::is_none")]`
so existing stored events deserialize cleanly.

**All current event emitters** (`fabro-workflow/event/convert.rs`, demo
fixtures, test helpers) are updated to set the new fields to `None` —
this is a mechanical compatibility update; actual enrichment comes in
later tasks.

### Design decisions worth noting

- `MessageKind` captures LLM role semantics (system / user / reasoning /
agent); `MessageSource` captures audit provenance (steer, pair,
loop_detection, …). They are intentionally kept separate so a steering
message can be `kind=user, source=steer` without collapsing the
distinction.
- `TranscriptMessage` is named with the `Transcript` prefix specifically
to avoid import ambiguity with `fabro_agent::Message` and
`fabro_llm::types::Message`.
- `ProviderAnswer` and `ProviderReasoning` are included as
`MessageSource` variants so committed model outputs carry a first-class
audit label distinct from user-originated inputs.
- The new fields are additive-only; no narrow legacy fields were
removed. Consumer migration is a separate step.


### Fabro Details

<details>
<summary>Ran 9 stages in 47m 27s for $12.79</summary>

| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 1s | – | 0 |
| preflight_compile | 2m 6s | – | 0 |
| preflight_lint | 2m 21s | – | 0 |
| implement | 20m 6s | $8.53 | 0 |
| simplify_opus | 13m 36s | $2.68 | 0 |
| simplify_gpt | 4m 17s | $1.58 | 0 |
| verify | 4m 7s | – | 0 |
| fmt | 3s | – | 0 |
| **Total** | **47m 27s** | **$12.79** | **0** |

</details>

<details>
<summary>Ran <code>ImplementPlan.fabro</code> (12 nodes and 15
edges)</summary>

```dot
digraph ImplementPlan {
    graph [
        goal="Implement and simplify",
        model_stylesheet="
            * { model: claude-opus-4-7; }
        "
    ]
    rankdir=LR

    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare, label="Exit"]

    toolchain         [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
    preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
    preflight_lint    [label="Preflight Lint", shape=parallelogram, script="cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1", max_retries=0]
    fix_lints         [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
    implement         [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
    simplify_opus     [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
    simplify_gpt      [label="Simplify (GPT-55)", prompt="@prompts/simplify.md", model="gpt-55"]
    verify            [label="Verify", shape=parallelogram, script="cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1 && cargo dev docs refresh 2>&1 && cargo dev docs check 2>&1", goal_gate=true, retry_target="fixup"]
    fixup             [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings, test failures, and generated docs errors.", max_visits=3]
    fmt               [label="Format", shape=parallelogram, script="cargo +nightly-2026-04-14 fmt --all 2>&1", max_retries=0]

    start -> toolchain
    toolchain -> preflight_compile [condition="outcome=succeeded"]
    toolchain -> exit
    preflight_compile -> preflight_lint [condition="outcome=succeeded"]
    preflight_compile -> exit
    preflight_lint -> implement [condition="outcome=succeeded"]
    preflight_lint -> fix_lints
    fix_lints -> preflight_lint
    implement -> simplify_opus -> simplify_gpt -> verify
    verify -> fmt   [condition="outcome=succeeded"]
    verify -> fixup
    fixup -> verify
    fmt -> exit
}

```

</details>

⚒️ Generated with [Fabro](https://fabro.sh)

---------

Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
2026-05-22 20:40:10 -04:00
..
build-support fix(build): refresh embedded git sha on branch commits 2026-05-09 14:10:04 -04:00
fabro-acp fix(workflow): capture configured artifacts once (#337) 2026-05-21 10:52:22 -04:00
fabro-agent Add agent context observability events (memory, skills, MCP tools) (#356) 2026-05-22 19:06:00 -04:00
fabro-api feat: add run.checkpoint.skip_git_hooks to bypass Git commit hooks (#355) 2026-05-22 17:26:06 -04:00
fabro-auth feat(workflow): enforce strict api/acp backends (#307) 2026-05-18 13:20:56 -04:00
fabro-checkpoint Make git metadata sandbox-native 2026-04-27 21:43:15 -07:00
fabro-cli Add fabro_run_get read-only run inspection tool (#358) 2026-05-22 19:03:56 -04:00
fabro-client Stage-based pairing API and fabro_run_pair MCP tool (#344) 2026-05-21 21:57:55 -04:00
fabro-config feat: add run.checkpoint.skip_git_hooks to bypass Git commit hooks (#355) 2026-05-22 17:26:06 -04:00
fabro-core feat: Replace duration/elapsed fields with wall_time_ms and StageTiming (#343) 2026-05-21 21:06:40 -04:00
fabro-dev feat: add [run.agent] fabro_tools opt-in for worker run tools (#348) 2026-05-22 09:41:27 -04:00
fabro-devcontainer refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-dump feat: Replace duration/elapsed fields with wall_time_ms and StageTiming (#343) 2026-05-21 21:06:40 -04:00
fabro-github fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-graphviz fix(graph): support dotted Fabro graph attributes (#324) 2026-05-20 09:31:08 -04:00
fabro-hooks Add event-sourced todo tools for OpenAI and Anthropic profiles (#353) 2026-05-22 13:44:42 -04:00
fabro-http refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-install refactor(install): share persistence pipeline (#332) 2026-05-21 08:04:04 -04:00
fabro-interview Stage-based pairing API and fabro_run_pair MCP tool (#344) 2026-05-21 21:57:55 -04:00
fabro-llm feat(fabro-types): promote transcript primitives and extend agent event… (#357) 2026-05-22 20:40:10 -04:00
fabro-macros refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-manifest fix(workflow): allow workflow-root template partials (#322) 2026-05-20 09:22:28 -04:00
fabro-mcp Add agent context observability events (memory, skills, MCP tools) (#356) 2026-05-22 19:06:00 -04:00
fabro-mcp-server Add fabro_run_get read-only run inspection tool (#358) 2026-05-22 19:03:56 -04:00
fabro-model Compute LLM cost on-read for in-flight billing stages (#345) 2026-05-21 19:25:00 -04:00
fabro-oauth fix(error): preserve remaining error context 2026-05-02 10:51:15 -04:00
fabro-options-metadata refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-proc refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-redact refactor(integrations): make chat integrations Slack-only 2026-05-09 11:43:16 -04:00
fabro-sandbox fix(sandbox): derive daytona network policies (#341) 2026-05-21 14:36:04 -04:00
fabro-server feat(fabro-types): promote transcript primitives and extend agent event… (#357) 2026-05-22 20:40:10 -04:00
fabro-slack feat(slack): render plan summary + run link in interview messages (re #253, stacked on #252) (#254) 2026-05-13 07:41:54 -04:00
fabro-spa feat(dev): gitignore embedded spa assets 2026-04-26 21:31:11 -04:00
fabro-static refactor(llm): split provider identity from adapters (#280) 2026-05-16 13:13:41 -04:00
fabro-store feat(fabro-types): promote transcript primitives and extend agent event… (#357) 2026-05-22 20:40:10 -04:00
fabro-telemetry refactor(workflow): remove retro stage (#230) 2026-05-09 10:18:20 -04:00
fabro-template feat(template): resolve template error locations (#333) 2026-05-20 20:15:04 -04:00
fabro-test feat(cli): add Fabro MCP server (#236) 2026-05-11 18:20:50 -04:00
fabro-tool Add fabro_run_get read-only run inspection tool (#358) 2026-05-22 19:03:56 -04:00
fabro-tracker fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-types feat(fabro-types): promote transcript primitives and extend agent event… (#357) 2026-05-22 20:40:10 -04:00
fabro-util refactor(install): share persistence pipeline (#332) 2026-05-21 08:04:04 -04:00
fabro-validate fix(graph): support dotted Fabro graph attributes (#324) 2026-05-20 09:31:08 -04:00
fabro-vault refactor(auth): split credential sources and vault schemas (#306) 2026-05-18 11:07:42 -04:00
fabro-workflow feat(fabro-types): promote transcript primitives and extend agent event… (#357) 2026-05-22 20:40:10 -04:00