|
| 1 | +// Event API provides real-time event streaming for Construct. |
| 2 | +// Events notify clients of changes to tasks, messages, agents, models, and other resources. |
| 3 | +// Clients can subscribe with pattern-based filtering and task scope filtering. |
| 4 | +syntax = "proto3"; |
| 5 | + |
| 6 | +package construct.v1; |
| 7 | + |
| 8 | +import "buf/validate/validate.proto"; |
| 9 | +import "construct/v1/agent.proto"; |
| 10 | +import "construct/v1/message.proto"; |
| 11 | +import "construct/v1/model.proto"; |
| 12 | +import "construct/v1/modelprovider.proto"; |
| 13 | +import "construct/v1/task.proto"; |
| 14 | +import "google/protobuf/timestamp.proto"; |
| 15 | + |
| 16 | +option go_package = "github.com/furisto/construct/api/go/v1"; |
| 17 | + |
| 18 | +// EventService provides real-time event streaming. |
| 19 | +// Clients can subscribe to events with optional filtering by event type patterns and task scope. |
| 20 | +service EventService { |
| 21 | + // Subscribe streams events matching the filter criteria. |
| 22 | + // Supports pattern-based filtering (e.g., "task.*", "*.created") and task scope filtering. |
| 23 | + rpc Subscribe(EventSubscribeRequest) returns (stream EventSubscribeResponse) {} |
| 24 | +} |
| 25 | + |
| 26 | +// EventSubscribeRequest specifies the subscription filter criteria. |
| 27 | +message EventSubscribeRequest { |
| 28 | + // event_types specifies which event types to receive using glob patterns. |
| 29 | + // Supports: "*" (all), "entity.*" (e.g., "task.*"), "*.action" (e.g., "*.created"), or exact match. |
| 30 | + // Empty list subscribes to all events. |
| 31 | + repeated string event_types = 1; |
| 32 | + |
| 33 | + // task_id filters events to only those related to a specific task (UUID format, optional). |
| 34 | + // When set, only task-scoped events (task.*, message.*, tool.*) for this task are delivered. |
| 35 | + optional string task_id = 2 [(buf.validate.field).string.uuid = true]; |
| 36 | + |
| 37 | + // replay_after_message_id enables replay of message.created events after this message ID. |
| 38 | + // Only applicable when task_id is also set. Only message.created events are replayed. |
| 39 | + optional string replay_after_message_id = 3 [(buf.validate.field).string.uuid = true]; |
| 40 | +} |
| 41 | + |
| 42 | +// EventSubscribeResponse wraps an event in the stream. |
| 43 | +message EventSubscribeResponse { |
| 44 | + // event is the streamed event. |
| 45 | + Event event = 1 [(buf.validate.field).required = true]; |
| 46 | +} |
| 47 | + |
| 48 | +// EventAction represents the type of change that occurred to a resource. |
| 49 | +enum EventAction { |
| 50 | + // EVENT_ACTION_UNSPECIFIED is used for non-CRUD events like message.chunk or tool events. |
| 51 | + EVENT_ACTION_UNSPECIFIED = 0; |
| 52 | + |
| 53 | + // EVENT_ACTION_CREATED indicates the resource was created. |
| 54 | + EVENT_ACTION_CREATED = 1; |
| 55 | + |
| 56 | + // EVENT_ACTION_UPDATED indicates the resource was modified. |
| 57 | + EVENT_ACTION_UPDATED = 2; |
| 58 | + |
| 59 | + // EVENT_ACTION_DELETED indicates the resource was deleted. |
| 60 | + EVENT_ACTION_DELETED = 3; |
| 61 | +} |
| 62 | + |
| 63 | +// Event represents a single event in the stream. |
| 64 | +message Event { |
| 65 | + // type is the event type string for filtering (e.g., "task.created", "message.chunk", "tool.called"). |
| 66 | + string type = 1 [(buf.validate.field).required = true]; |
| 67 | + |
| 68 | + // action is the action that occurred: created, updated, deleted, or unspecified (for non-CRUD events). |
| 69 | + EventAction action = 2 [(buf.validate.field).enum.defined_only = true]; |
| 70 | + |
| 71 | + // timestamp is when the change occurred (entity timestamp, e.g., created_at, updated_at). |
| 72 | + google.protobuf.Timestamp timestamp = 3 [(buf.validate.field).required = true]; |
| 73 | + |
| 74 | + // payload contains the event-specific data. |
| 75 | + oneof payload { |
| 76 | + TaskEvent task = 10; |
| 77 | + MessageEvent message = 11; |
| 78 | + MessageChunkEvent message_chunk = 12; |
| 79 | + AgentEvent agent = 13; |
| 80 | + ModelEvent model = 14; |
| 81 | + ModelProviderEvent model_provider = 15; |
| 82 | + ToolCalledEvent tool_called = 16; |
| 83 | + ToolResultEvent tool_result = 17; |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +// TaskEvent contains task event data. |
| 88 | +message TaskEvent { |
| 89 | + // task is the task entity. For delete events, may only have ID populated. |
| 90 | + Task task = 1 [(buf.validate.field).required = true]; |
| 91 | + |
| 92 | + // previous_phase is populated on phase change updates. |
| 93 | + optional string previous_phase = 2; |
| 94 | +} |
| 95 | + |
| 96 | +// MessageEvent contains message event data (created, updated, deleted). |
| 97 | +message MessageEvent { |
| 98 | + // message is the message entity. For delete events, may only have ID populated. |
| 99 | + Message message = 1 [(buf.validate.field).required = true]; |
| 100 | +} |
| 101 | + |
| 102 | +// MessageChunkEvent contains streaming message chunk data. |
| 103 | +// Note: Chunk events are not replayed. After streaming completes, a message.created event is emitted. |
| 104 | +message MessageChunkEvent { |
| 105 | + // task_id is the task this message belongs to. |
| 106 | + string task_id = 1 [(buf.validate.field).string.uuid = true]; |
| 107 | + |
| 108 | + // message_id is the message being streamed. |
| 109 | + string message_id = 2 [(buf.validate.field).string.uuid = true]; |
| 110 | + |
| 111 | + // chunk is the delta content (incremental text to append), not cumulative. |
| 112 | + string chunk = 3; |
| 113 | + |
| 114 | + // chunk_index is 0-based, per-message, monotonically increasing. |
| 115 | + int32 chunk_index = 4; |
| 116 | +} |
| 117 | + |
| 118 | +// AgentEvent contains agent event data. |
| 119 | +message AgentEvent { |
| 120 | + // agent is the agent entity. For delete events, may only have ID populated. |
| 121 | + Agent agent = 1 [(buf.validate.field).required = true]; |
| 122 | +} |
| 123 | + |
| 124 | +// ModelEvent contains model event data. |
| 125 | +message ModelEvent { |
| 126 | + // model is the model entity. For delete events, may only have ID populated. |
| 127 | + Model model = 1 [(buf.validate.field).required = true]; |
| 128 | +} |
| 129 | + |
| 130 | +// ModelProviderEvent contains model provider event data. |
| 131 | +// Note: Must never include credentials/API keys in the payload. |
| 132 | +message ModelProviderEvent { |
| 133 | + // model_provider is the model provider entity. For delete events, may only have ID populated. |
| 134 | + ModelProvider model_provider = 1 [(buf.validate.field).required = true]; |
| 135 | +} |
| 136 | + |
| 137 | +// ToolCalledEvent contains tool call event data. |
| 138 | +// Emitted before tool execution begins. |
| 139 | +message ToolCalledEvent { |
| 140 | + // task_id is the task where this tool was called. |
| 141 | + string task_id = 1 [(buf.validate.field).string.uuid = true]; |
| 142 | + |
| 143 | + // tool_call contains the tool name and input. |
| 144 | + ToolCall tool_call = 2 [(buf.validate.field).required = true]; |
| 145 | +} |
| 146 | + |
| 147 | +// ToolResultEvent contains tool result event data. |
| 148 | +// Emitted after tool execution completes. |
| 149 | +message ToolResultEvent { |
| 150 | + // task_id is the task where this tool was executed. |
| 151 | + string task_id = 1 [(buf.validate.field).string.uuid = true]; |
| 152 | + |
| 153 | + // tool_result contains the tool name and output. |
| 154 | + ToolResult tool_result = 2 [(buf.validate.field).required = true]; |
| 155 | +} |
0 commit comments