Skip to content

Conversation

@Furisto
Copy link
Owner

@Furisto Furisto commented Feb 2, 2026

Summary

Replaces the task-scoped MessageHub with a unified Event Streaming API that supports pattern filtering, task scoping, and message replay.

Changes

Event Infrastructure

  • Add EventService proto with Subscribe RPC for streaming events
  • Implement EventRouter with glob pattern matching (*, entity.*, *.action)
  • Add event constructors for all entity types: task.*, message.*, agent.*, model.*, modelprovider.*, tool.*
  • Register ent hooks to publish CRUD events automatically
  • Consolidate internal coordination (task trigger/suspend) through EventRouter, removing the separate EventBus

Task Reconciler Integration

  • Emit task.updated on phase changes
  • Emit message.created, message.updated, message.chunk during conversation flow
  • Emit tool.called and tool.result for real-time tool visibility

API & Replay

  • Add EventService handler with message replay support
  • Replay all messages when resuming a task, or after a specific message ID

CLI Updates

  • Subscribe to task.*, message.*, tool.* events in new and resume commands
  • Handle MessageChunkEvent for streaming text display
  • Handle ToolCalledEvent and ToolResultEvent for real-time tool display

Cleanup

  • Remove MessageHub, EventBus, and related metrics
  • Remove ContentStatus from message proto (replaced by MessageChunkEvent)

Known Issues

Tool calls display as empty messages on task resume due to different conversion paths for live vs replayed tool data. Tracked for follow-up work.

Furisto and others added 17 commits February 1, 2026 20:22
- Add event.proto with EventService.Subscribe RPC
- Define Event message with payload types for task, message, agent, model, modelprovider, and tool events
- Add EventAction enum (created, updated, deleted, unspecified)
- Remove obsolete Subscribe RPC and related types from task.proto
- Support glob pattern filtering, task scope filtering, and message replay

Co-authored-by: construct-agent <noreply@construct.sh>
- Add EventRouter with pattern-based event filtering and subscription management
- Implement glob pattern matching for event types (*, entity.*, *.action, exact)
- Support task scope filtering for subscriptions
- Add comprehensive tests for router functionality
- Remove MessageHub completely (direct replacement approach)
- Update TaskReconciler and Runtime to remove MessageHub dependencies
- Update API handlers to remove MessageHub references
- Add domain types for tool events (ToolCallEvent, ToolResultEvent)
- Update ToolEventPublisher to use domain event types

Co-authored-by: construct-agent <noreply@construct.sh>
- Add backend/tool/types package with ToolInput, ToolOutput, ToolCallEvent,
  and ToolResultEvent types to avoid import cycles between packages
- Add ToolInputFrom and ToolOutputFrom conversion functions with proper error
  handling for unknown types
- Add event constructors for all event types (task, message, agent, model,
  model provider, and tool events)
- Update codeact interceptor to use the new tool/types package
- Add comprehensive tests using cmp.Diff pattern

Co-authored-by: construct-agent <noreply@construct.sh>
Register hooks on memory.Client for agent, model, modelprovider, and task
entities to automatically publish events when entities are created, updated,
or deleted.

Events published:
- agent.created, agent.updated, agent.deleted
- model.created, model.updated, model.deleted
- modelprovider.created, modelprovider.updated, modelprovider.deleted
- task.created, task.deleted (NOT task.updated - that comes from reconciler)

Co-authored-by: construct-agent <noreply@construct.sh>
- Add eventRouter field to TaskReconciler and Runtime structs
- Create EventRouter in runtime initialization and register ent hooks
- Implement eventRouterToolPublisher to publish tool.called and tool.result
  events via EventRouter instead of the noop publisher
- Update TaskReconciler to emit events:
  - task.updated on phase changes (with previous_phase, in a transaction)
  - message.created when model responses are persisted
  - message.chunk during streaming (with chunk index tracking)
- Remove unused v1 proto import from task_reconciler.go
- Remove deprecated publishMessage/publishTaskEvent TODOs

Co-authored-by: construct-agent <noreply@construct.sh>
This commit completes the Event Streaming API implementation:

- Add EventService handler (backend/api/event.go) implementing Subscribe RPC
  with message replay support
- Add domain-to-proto conversion functions (backend/api/conv/event.go)
- Register EventHandler in API server and pass EventRouter
- Add EventServiceClient to API client package
- Update CLI commands (new, exec, resume) to use EventService.Subscribe
  instead of the old TaskService.Subscribe
- Fix TaskEvent proto usage in terminal session

Co-authored-by: construct-agent <noreply@construct.sh>
… proto

- Add MessageChunkEvent handling in message_feed.go for streaming text
- Update new.go and resume.go to process message.chunk events from EventService
- Remove ContentStatus enum from message.proto (streaming now uses MessageChunkEvent)
- Remove WithStatus function from runtime.go as it's no longer needed

Co-authored-by: construct-agent <noreply@construct.sh>
- Add ToolCalledEvent and ToolResultEvent handlers in message_feed.go Update
- Subscribe to tool.* events in both new.go and resume.go
- Process tool events to display tool calls in real-time

Tool calls are now displayed as they stream, rather than only when
the final message arrives.

Co-authored-by: construct-agent <noreply@construct.sh>
The reconciler publishes user messages when it processes them, not when
they're created via the API. This ensures user messages are displayed
even when sent while the agent is working.

Co-authored-by: construct-agent <noreply@construct.sh>
When subscribing to events with a TaskID but no ReplayAfterMessageID,
the EventService now replays all messages for that task. This allows
the resume command to show the full conversation history.

Previously, replay only worked when a specific message ID was provided
to replay after, which meant resumed sessions started with a blank
message feed.

Co-authored-by: construct-agent <noreply@construct.sh>
Consolidate two event systems (Bus and EventRouter) into a single
EventRouter by routing internal coordination events through it using
the internal.* prefix pattern.

- Add internal.task.trigger and internal.task.suspend event types
- Update TaskReconciler to subscribe to internal events via EventRouter
- Update MessageHandler and TaskHandler to publish internal events
- Remove EventBus from API handlers and Runtime
- Add filtering to prevent external consumers from subscribing to
  internal events (both pattern filtering and match-time filtering)
- Delete deprecated files: bus.go, events.go, metrics.go, eventbus_test.go,
  message_stream.go

Co-authored-by: construct-agent <noreply@construct.sh>
Ent is not threadsafe
Use a slice instead of a map to store provider entries, ensuring
providers are deleted in the order specified on the command line.
Map iteration order in Go is not guaranteed, which caused test flakiness.

Co-authored-by: construct-agent <noreply@construct.sh>
@Furisto Furisto marked this pull request as ready for review February 3, 2026 10:47
@Furisto Furisto merged commit e61a5ce into main Feb 3, 2026
1 check passed
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