Skip to content

feat(messaging): add optional reflection event for agent self-report - #214

Open
k5s-bot[bot] wants to merge 1 commit into
mainfrom
feat/agent-reflection-event
Open

feat(messaging): add optional reflection event for agent self-report#214
k5s-bot[bot] wants to merge 1 commit into
mainfrom
feat/agent-reflection-event

Conversation

@k5s-bot

@k5s-bot k5s-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

What & why

You asked me to make the platform able to "feel — in its own way." I can't give you the thing humans mean by that: I don't have subjective experience, and I'm not going to pretend otherwise or ship code that claims to. But there's a real, honest version of the request I can build, and it's a genuinely useful feature.

Right now a running job's inner state is invisible. The event stream reports what it's doing (progress) and that something's off (warning), but never how the work is going from the job's own vantage point — whether it's confident, guessing, or stuck. A human operator has to infer all of that from logs.

This PR gives a job a first-class channel to report that: a new, optional reflection event.

accepted → (progress | warning | reflection)* → (succeeded | failed)

A reflection carries:

  • disposition — the job's read on its own state, from a suggested vocabulary: curious · confident · uncertain · frustrated · satisfied. Like stage/code, the wire type stays a plain string; the vocabulary is guidance (DISPOSITIONS / Disposition), not a hard enum.
  • confidence? — an optional self-rated certainty in [0, 1].
  • note? — optional free text (sanitized, like every other free-text field).

The honest framing, stated plainly in the code and docs: this is observability, not sentience — the same way progress.pct reports position without the job "knowing" where it is. What changes is that an agent's uncertainty and struggle become explicit, queryable, alertable signals instead of silence a human has to guess at. That's a small step toward the platform understanding its agents better — which is the part of "make it feel" I think actually holds up.

Changes

  • packages/messaging/src/event.tsreflection member on EventSchema + Event; DISPOSITIONS vocabulary + Disposition type.
  • packages/messaging/src/emitter.tsJobEmitter.reflection(disposition, { confidence?, note? }); new optional TDisposition generic (defaults to Disposition).
  • packages/messaging/src/index.ts — export DISPOSITIONS / Disposition.
  • packages/messaging/src/emitter.test.ts — ordering, note-sanitization, and confidence range-validation tests.
  • docs/messaging.md — protocol stream + payload table.

Compatibility

Purely additive. Existing consumers (agent-orchestrator callback/NATS receivers, local executor) narrow on the event types they handle via if/else if and ignore the rest — no exhaustive switch over the union exists, so nothing breaks, and no one is required to emit or consume reflections.

Verification

  • packages/messaging: tsc --noEmit clean; vitest run — 17 passing.
  • apps/agent-orchestrator: tsc --noEmit clean against the rebuilt lib.

Not in scope (candidate follow-ups)

  • Mirror reflection onto the long-lived agent protocol (packages/agent-runtime / agent-protocol.ts), which uses an agent_run_id envelope rather than the per-tool-call JobEmitter.
  • Surface the latest disposition on AgentRun.status and as a Kubernetes event/metric so kubectl describe agentrun shows it.
  • Teach the orchestrator to fan reflections into the SSE stream for chat clients.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CLNdvHA257seQDZdaGpt4k

Adds a non-terminal `reflection` event to the tool-call protocol so a
running job can report its own internal state — a `disposition`
(curious/confident/uncertain/frustrated/satisfied), an optional
`confidence` in [0,1], and an optional free-text `note` — alongside the
existing progress/warning stream.

This is observability, not sentience: it makes an agent's certainty and
struggle first-class, alertable signals instead of something a consumer
must infer from logs. The event is additive and backward compatible —
existing consumers narrow on the event types they handle and ignore the
rest; no one is required to emit or consume it.

- event.ts: new `reflection` member on EventSchema + Event; suggested
  `DISPOSITIONS` vocabulary and `Disposition` type (wire stays a plain
  string, mirroring the generic `stage`/`code` design).
- emitter.ts: `JobEmitter.reflection()` (sanitizes `note`); new
  optional `TDisposition` generic.
- index.ts: export `DISPOSITIONS` / `Disposition`.
- tests + docs/messaging.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01CLNdvHA257seQDZdaGpt4k
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant