mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-01 02:04:24 +00:00
State the agent event contract in the docs
Pebble's CodingAgentEvent stream is the agent event contract: every event except streaming deltas is stored verbatim under its derived name and folded into StageProjection.agent with pebble's SessionProjection. The events doc, the events strategy, and the v2 shape doc say so, list the agent events fabro still emits for facts pebble cannot know, and tell consumers to read the fold rather than fold the events again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
7a6eea0399
commit
2c3c2d8b7f
3 changed files with 79 additions and 26 deletions
|
|
@ -175,11 +175,32 @@ Check:
|
|||
- store validation
|
||||
- tests or fixtures that inspect event names or fields
|
||||
|
||||
## Agent Events
|
||||
|
||||
Pebble's `CodingAgentEvent` stream is the agent event contract. The worker's
|
||||
event sink stores every event the coding agent publishes for a stage, except
|
||||
streaming deltas, verbatim as `EventBody::Agent` under a name derived from
|
||||
its variant (`fabro_types::coding_event_name`), and the store folds those
|
||||
events into `StageProjection.agent` with pebble's `SessionProjection`. Do not
|
||||
add a fabro event that restates a pebble event, and do not add a second fold
|
||||
of the stream: read `StageProjection.agent`, or the stored pebble event
|
||||
itself, instead.
|
||||
|
||||
Fabro emits an agent event of its own only for a fact pebble cannot know.
|
||||
Today those are `agent.session.activated`, `agent.session.deactivated`,
|
||||
`agent.tools.available`, `agent.pair.user_message`,
|
||||
`agent.pair.system_message`, `agent.interrupt.injected`,
|
||||
`agent.steer.buffered`, `agent.steer.dropped`, the `agent.acp.*` family, and
|
||||
`prompt.failover` for a one-shot prompt stage that walks its fallback plan
|
||||
without pebble. A new fabro agent event needs the same justification: name
|
||||
the fact pebble does not have.
|
||||
|
||||
## Consumer Guidance
|
||||
|
||||
When writing Rust consumers (listeners, store projections, CLI progress):
|
||||
|
||||
- Match on `event.body` using `EventBody::*` variants. This gives you typed access to event-specific fields.
|
||||
- Match on `event.body` using `EventBody::*` variants. This gives you typed access to event-specific fields. For a pebble event, match `EventBody::Agent(props)` and then `props.coding_event()`.
|
||||
- For a stage's agent facts (usage, route, MCP servers, skills, todos, subagents, files, failovers, compactions), read `StageProjection.agent` rather than folding the events again.
|
||||
- Use `event.node_id`, `event.node_label`, `event.session_id`, and `event.parent_session_id` for envelope metadata.
|
||||
- Only use `event.event_name()` or `event.properties()` for generic/display purposes (logging, forwarding). These involve serialization and should not be used on hot paths.
|
||||
|
||||
|
|
|
|||
|
|
@ -883,7 +883,36 @@ Emitted when execution loops back to an earlier node.
|
|||
|
||||
## Agent events
|
||||
|
||||
Most agent activity events are stage-scoped and carry `node_id` (the workflow stage), `node_label`, `stage_id`, `session_id`, and `parent_session_id` in the envelope. Session object lifecycle events are the exception: `agent.session.started` and `agent.session.ended` are not stage-scoped and intentionally omit `node_id`, `node_label`, `stage_id`, and `visit`.
|
||||
Pebble's `CodingAgentEvent` stream is the agent event contract. Every event
|
||||
the coding agent publishes for a stage, except streaming deltas, is stored
|
||||
verbatim as an `EventBody::Agent` under a name derived from its variant
|
||||
(`agent.message`, `agent.tool.started`, `agent.route.failover`,
|
||||
`agent.mcp.server.ready`, `todo.created`, and so on; the full list is
|
||||
`CODING_EVENT_NAMES`). Its `properties` are pebble's own envelope, so
|
||||
pebble's event types are part of fabro's stored format, and the store folds
|
||||
the same events into `StageProjection.agent` with pebble's
|
||||
`SessionProjection`, the one fold of that stream.
|
||||
|
||||
Fabro emits an agent event of its own only for a fact pebble cannot know:
|
||||
|
||||
- `agent.session.activated` and `agent.session.deactivated`: the stage's
|
||||
route, controls, permission level, and steering capabilities, as fabro
|
||||
resolved them.
|
||||
- `agent.tools.available`: the tool catalog fabro handed the agent.
|
||||
- `agent.pair.user_message` and `agent.pair.system_message`: pair mode.
|
||||
- `agent.interrupt.injected`, `agent.steer.buffered`, `agent.steer.dropped`:
|
||||
run-level steering as it reaches, waits for, or misses a session.
|
||||
- `agent.acp.started`, `agent.acp.completed`, `agent.acp.cancelled`,
|
||||
`agent.acp.timed_out`: an external ACP agent process, which pebble does
|
||||
not run.
|
||||
- `prompt.failover`: a one-shot prompt stage moving to a fallback route,
|
||||
which it does without pebble.
|
||||
|
||||
Every agent activity event is stage-scoped and carries `node_id` (the
|
||||
workflow stage), `node_label`, `stage_id`, `session_id`, and
|
||||
`parent_session_id` in the envelope. Pebble's session lifecycle events
|
||||
(`agent.session.started`, `agent.session.ended`) are stored with the stage
|
||||
that ran the session like the rest.
|
||||
|
||||
### `agent.session.started`
|
||||
|
||||
|
|
|
|||
|
|
@ -364,30 +364,33 @@ V2 keeps the current durable family surface broadly intact.
|
|||
|
||||
### Agent Durable Events
|
||||
|
||||
- `agent.session.started`
|
||||
- `agent.session.ended`
|
||||
- `agent.processing.end`
|
||||
- `agent.input`
|
||||
- `agent.message`
|
||||
- `agent.tool.started`
|
||||
- `agent.tool.completed`
|
||||
- `agent.error`
|
||||
- `agent.warning`
|
||||
- `agent.loop.detected`
|
||||
- `agent.steering.injected`
|
||||
- `agent.compaction.started`
|
||||
- `agent.compaction.completed`
|
||||
- `agent.llm.started`
|
||||
- `agent.llm.first_output`
|
||||
- `agent.llm.retry`
|
||||
- `agent.sub.spawned`
|
||||
- `agent.sub.completed`
|
||||
- `agent.sub.failed`
|
||||
- `agent.sub.closed`
|
||||
- `agent.mcp.ready`
|
||||
- `agent.mcp.failed`
|
||||
- `agent.mcp.disconnected`
|
||||
- `agent.failover`
|
||||
Pebble's events, stored verbatim under the names `fabro_types::CODING_EVENT_NAMES`
|
||||
lists (every `CodingEvent` variant except the streaming deltas):
|
||||
|
||||
- `agent.session.started`, `agent.session.ended`, `agent.processing.end`
|
||||
- `agent.input`, `agent.message`
|
||||
- `agent.llm.started`, `agent.llm.first_output`, `agent.llm.retry`
|
||||
- `agent.tool.started`, `agent.tool.completed`, `agent.tool.process.completed`, `agent.tool.rounds.exhausted`
|
||||
- `agent.error`, `agent.warning`, `agent.loop.detected`
|
||||
- `agent.steering.injected`, `agent.round.interrupted`
|
||||
- `agent.compaction.started`, `agent.compaction.completed`, `agent.compaction.failed`, `agent.compaction.cancelled`
|
||||
- `agent.route.failover`, `agent.route.failover.stopped`
|
||||
- `agent.mcp.server.ready`, `agent.mcp.server.failed`, `agent.mcp.server.disconnected`
|
||||
- `agent.sub.spawned`, `agent.sub.turn.started`, `agent.sub.completed`, `agent.sub.failed`, `agent.sub.closed`
|
||||
- `agent.memory.loaded`, `agent.skills.discovered`, `agent.skill.activated`
|
||||
- `todo.created`, `todo.updated`, `todo.deleted`
|
||||
|
||||
Fabro's own, for facts pebble cannot know:
|
||||
|
||||
- `agent.session.activated`, `agent.session.deactivated`, `agent.tools.available`
|
||||
- `agent.pair.user_message`, `agent.pair.system_message`
|
||||
- `agent.interrupt.injected`, `agent.steer.buffered`, `agent.steer.dropped`
|
||||
- `agent.acp.started`, `agent.acp.completed`, `agent.acp.cancelled`, `agent.acp.timed_out`
|
||||
- `prompt.failover` (a one-shot prompt stage's move to a fallback route)
|
||||
|
||||
The former mirrors `agent.mcp.ready`, `agent.mcp.failed`,
|
||||
`agent.mcp.disconnected`, and `agent.failover` are no longer emitted; runs
|
||||
recorded with them read them back as generic events.
|
||||
|
||||
### Git
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue