@theway-ai/sdk 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +108 -0
  2. package/dist/client.d.ts +180 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +531 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/generated/commands.d.ts +195 -0
  7. package/dist/generated/commands.d.ts.map +1 -0
  8. package/dist/generated/commands.js +633 -0
  9. package/dist/generated/commands.js.map +1 -0
  10. package/dist/generated/events.d.ts +158 -0
  11. package/dist/generated/events.d.ts.map +1 -0
  12. package/dist/generated/events.js +1122 -0
  13. package/dist/generated/events.js.map +1 -0
  14. package/dist/generated/extensions.d.ts +184 -0
  15. package/dist/generated/extensions.d.ts.map +1 -0
  16. package/dist/generated/extensions.js +1309 -0
  17. package/dist/generated/extensions.js.map +1 -0
  18. package/dist/generated/graph_engine.d.ts +422 -0
  19. package/dist/generated/graph_engine.d.ts.map +1 -0
  20. package/dist/generated/graph_engine.js +3048 -0
  21. package/dist/generated/graph_engine.js.map +1 -0
  22. package/dist/generated/health.d.ts +83 -0
  23. package/dist/generated/health.d.ts.map +1 -0
  24. package/dist/generated/health.js +179 -0
  25. package/dist/generated/health.js.map +1 -0
  26. package/dist/generated/session.d.ts +854 -0
  27. package/dist/generated/session.d.ts.map +1 -0
  28. package/dist/generated/session.js +6790 -0
  29. package/dist/generated/session.js.map +1 -0
  30. package/dist/generated/settings.d.ts +182 -0
  31. package/dist/generated/settings.d.ts.map +1 -0
  32. package/dist/generated/settings.js +324 -0
  33. package/dist/generated/settings.js.map +1 -0
  34. package/dist/generated/state.d.ts +304 -0
  35. package/dist/generated/state.d.ts.map +1 -0
  36. package/dist/generated/state.js +1391 -0
  37. package/dist/generated/state.js.map +1 -0
  38. package/dist/generated/tools.d.ts +413 -0
  39. package/dist/generated/tools.d.ts.map +1 -0
  40. package/dist/generated/tools.js +2487 -0
  41. package/dist/generated/tools.js.map +1 -0
  42. package/dist/health.d.ts +20 -0
  43. package/dist/health.d.ts.map +1 -0
  44. package/dist/health.js +62 -0
  45. package/dist/health.js.map +1 -0
  46. package/dist/index.d.ts +15 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +21 -0
  49. package/dist/index.js.map +1 -0
  50. package/docs/PROTOCOL.md +129 -0
  51. package/package.json +47 -0
  52. package/proto/commands.proto +70 -0
  53. package/proto/events.proto +87 -0
  54. package/proto/extensions.proto +99 -0
  55. package/proto/graph_engine.proto +236 -0
  56. package/proto/health.proto +26 -0
  57. package/proto/session.proto +498 -0
  58. package/proto/settings.proto +79 -0
  59. package/proto/state.proto +130 -0
  60. package/proto/tools.proto +238 -0
@@ -0,0 +1,498 @@
1
+ // Session domain: the full session state plane (snapshot, sidebar, feed,
2
+ // model catalog, status), session resource messages
3
+ // (list/create/rename/delete), and the SessionService RPC surface.
4
+
5
+ syntax = "proto3";
6
+ package theway.grpc.v1;
7
+
8
+ import "commands.proto";
9
+ import "extensions.proto";
10
+ import "graph_engine.proto";
11
+
12
+ // Incremental transcript patch: appends/replacements since a consumer cursor.
13
+ message FeedBlockPatch {
14
+ // index == consumer length appends; index < length replaces; index > length
15
+ // is a gap and requires a full snapshot resync.
16
+ uint64 index = 1;
17
+ FeedBlock block = 2;
18
+ }
19
+
20
+ // Token usage for the current/last turn, plus the model's context window size.
21
+ message ContextUsage {
22
+ uint64 cached_tokens = 1;
23
+ uint64 new_tokens = 2;
24
+ uint64 total_input_tokens = 3;
25
+ uint64 output_tokens = 4;
26
+ uint64 cache_write_tokens = 5;
27
+ optional double provider_cache_hit_rate = 6;
28
+ optional double prefix_cache_hit_rate = 7;
29
+ optional uint64 prefix_hit_tokens = 8;
30
+ uint32 context_window = 9;
31
+ }
32
+
33
+ message ProviderGroup {
34
+ string provider = 1;
35
+ bool has_credential = 2;
36
+ repeated ModelEntry models = 3;
37
+ }
38
+
39
+ message ModelEntry {
40
+ string id = 1;
41
+ string name = 2;
42
+ }
43
+
44
+ message TriggerPollStatus {
45
+ string checked_at = 1;
46
+ string trace_id = 2;
47
+ string source_label = 3;
48
+ string event_label = 4;
49
+ string summary = 5;
50
+ }
51
+
52
+ message GoalSnapshot {
53
+ string condition = 1;
54
+ string status = 2;
55
+ uint32 iterations = 3;
56
+ optional string last_reason = 4;
57
+ }
58
+
59
+ message ControlPlanePromptSnapshot {
60
+ string tool_name = 1;
61
+ string label = 2;
62
+ string reason = 3;
63
+ string args_hash = 4;
64
+ string payload = 5;
65
+ }
66
+
67
+ message SidebarSnapshot {
68
+ uint32 inbox_new = 1;
69
+ SkillsSnapshot skills = 2;
70
+ TriggersSnapshot triggers = 3;
71
+ CronSnapshot cron = 4;
72
+ McpSnapshot mcp = 5;
73
+ ToolsSnapshot tools = 6;
74
+ repeated string hooks = 7;
75
+ repeated string runtime = 8;
76
+ // Slash-prefixed file-command names (claude-code format, issue #37):
77
+ // discovered from .agents/commands + .claude/commands.
78
+ repeated string commands = 9;
79
+ // Daemon runtime revision, bumped by the `reload` agent tool; clients
80
+ // watch it to re-read local resources (e.g. ~/.theway/theme.toml).
81
+ uint64 runtime_revision = 10;
82
+ }
83
+
84
+ message SkillsSnapshot {
85
+ uint32 total = 1;
86
+ uint32 enabled = 2;
87
+ uint32 disabled = 3;
88
+ uint32 builtin = 4;
89
+ uint32 user = 5;
90
+ uint32 project = 6;
91
+ repeated SkillSnapshot items = 7;
92
+ }
93
+
94
+ message SkillSnapshot {
95
+ string name = 1;
96
+ string source = 2;
97
+ string file_path = 3;
98
+ bool enabled = 4;
99
+ }
100
+
101
+ message TriggersSnapshot {
102
+ uint32 total = 1;
103
+ uint32 enabled = 2;
104
+ uint32 disabled = 3;
105
+ repeated TriggerRuleSnapshot rules = 4;
106
+ }
107
+
108
+ message TriggerRuleSnapshot {
109
+ string id = 1;
110
+ string full_id = 2;
111
+ bool enabled = 3;
112
+ string mode = 4;
113
+ string condition = 5;
114
+ string action = 6;
115
+ }
116
+
117
+ message CronSnapshot {
118
+ uint32 total = 1;
119
+ uint32 enabled = 2;
120
+ uint32 disabled = 3;
121
+ repeated CronJobSnapshot jobs = 4;
122
+ }
123
+
124
+ message CronJobSnapshot {
125
+ string id = 1;
126
+ bool enabled = 2;
127
+ string schedule = 3;
128
+ string action = 4;
129
+ uint64 skipped_overlap_count = 5;
130
+ optional string last_error = 6;
131
+ }
132
+
133
+ message McpSnapshot {
134
+ uint32 servers = 1;
135
+ uint32 tools = 2;
136
+ uint32 notification_hooks = 3;
137
+ repeated string server_names = 4;
138
+ repeated string tool_names = 5;
139
+ }
140
+
141
+ message ToolsSnapshot {
142
+ uint32 total = 1;
143
+ repeated string names = 2;
144
+ }
145
+
146
+ // One renderable feed entry. oneof mirrors the serde tagged enum WireFeedBlock;
147
+ // JSON channels keep serde shape until the protojson migration.
148
+ message FeedBlock {
149
+ oneof kind {
150
+ UserBlock user = 1;
151
+ AssistantBlock assistant = 2;
152
+ ThinkingBlock thinking = 3;
153
+ ToolResultBlock tool_result = 5;
154
+ PlainBlock plain = 6;
155
+ ToolCallBlock tool_call = 7;
156
+ ErrorBlock error = 8;
157
+ }
158
+ }
159
+
160
+ message UserBlock {
161
+ string text = 1;
162
+ optional string timestamp = 2; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
163
+ }
164
+
165
+ message AssistantBlock {
166
+ string text = 1;
167
+ optional string timestamp = 2; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
168
+ }
169
+
170
+ message ThinkingBlock {
171
+ string text = 1;
172
+ optional string timestamp = 2; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
173
+ }
174
+
175
+ message ToolCallBlock {
176
+ string name = 1;
177
+ string args = 2;
178
+ optional string metadata = 3; // Optional tool-call metadata (JSON string).
179
+ optional string timestamp = 4; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
180
+ }
181
+
182
+ message ErrorBlock {
183
+ string message = 1;
184
+ optional string code = 2;
185
+ bool recoverable = 3;
186
+ optional string timestamp = 4; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
187
+ }
188
+
189
+ message ToolResultBlock {
190
+ repeated string lines = 1;
191
+ bool is_error = 2;
192
+ optional string timestamp = 3; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
193
+ }
194
+
195
+ message PlainBlock {
196
+ string text = 1;
197
+ string level = 2; // "output" | "system" | "error" | "note" (serde snake_case variant names)
198
+ optional string timestamp = 3; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
199
+ }
200
+
201
+ message SessionSummary {
202
+ // Canonical session id. New clients should use this field; `session_id`
203
+ // remains as a deprecated alias for compatibility with older consumers.
204
+ string id = 13;
205
+ // Compatibility alias; new clients should read `id`.
206
+ string session_id = 1;
207
+ string name = 2;
208
+ string cwd = 3;
209
+ string model = 4;
210
+ string created_at = 5; // RFC3339 / ISO-8601 with offset (UTC).
211
+ int64 last_activity_at = 6; // Deprecated epoch milliseconds; use last_activity_at_rfc3339.
212
+ uint32 graph_count = 7;
213
+ uint32 active_graph_count = 8;
214
+ bool busy = 9;
215
+ optional string preview = 10;
216
+ map<string, string> metadata = 11;
217
+ optional string last_activity_at_rfc3339 = 12; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
218
+ string tree_prefix = 14; // Pi-style tree prefix (`├─ ` / `└─ ` / `│ `) for fork-lineage display.
219
+ }
220
+
221
+ // Thinking levels supported by the runtime.
222
+ enum ThinkingLevel {
223
+ THINKING_LEVEL_UNSPECIFIED = 0;
224
+ THINKING_LEVEL_OFF = 1;
225
+ THINKING_LEVEL_MINIMAL = 2;
226
+ THINKING_LEVEL_LOW = 3;
227
+ THINKING_LEVEL_MEDIUM = 4;
228
+ THINKING_LEVEL_HIGH = 5;
229
+ THINKING_LEVEL_XHIGH = 6;
230
+ }
231
+
232
+ // A resolved model reference in a session runtime.
233
+ message ModelRef {
234
+ string provider = 1;
235
+ string model = 2;
236
+ optional string base_url = 3;
237
+ }
238
+
239
+ // Static/dynamic session identity and display metadata.
240
+ message SessionInfo {
241
+ string id = 1;
242
+ string name = 2;
243
+ string cwd = 3;
244
+ string created_at = 4; // RFC3339 / ISO-8601 with offset (UTC).
245
+ int64 last_activity_at = 5; // Deprecated epoch milliseconds.
246
+ optional string last_activity_at_rfc3339 = 6; // RFC3339 / ISO-8601 with offset (UTC), null when absent.
247
+ bool busy = 7;
248
+ optional string preview = 8;
249
+ map<string, string> metadata = 9;
250
+ uint32 graph_count = 10;
251
+ uint32 active_graph_count = 11;
252
+ uint32 queued_count = 12;
253
+ SidebarSnapshot sidebar = 13;
254
+ }
255
+
256
+ // Live runtime configuration and model/context metadata.
257
+ message SessionRuntime {
258
+ ModelRef model = 1;
259
+ ThinkingLevel thinking_level = 2;
260
+ repeated ThinkingLevel supported_thinking_levels = 3;
261
+ optional ContextUsage context_usage = 4;
262
+ optional ContextUsage session_context_usage = 5;
263
+ optional uint32 tui_max_feed_lines = 6;
264
+ repeated ProviderGroup model_catalog = 7;
265
+ optional TriggerPollStatus latest_trigger_poll = 8;
266
+ optional GoalSnapshot goal = 9;
267
+ optional ControlPlanePromptSnapshot control_plane_prompt = 10;
268
+ ExtensionSnapshot extensions = 11;
269
+ // Full rendered system context for the next request (base prompt + skills +
270
+ // tool inventory + working directory + memory + lineage). Mirrors the
271
+ // request/header epoch snapshot in deepseek-harness session logs.
272
+ string system_context = 12;
273
+ }
274
+
275
+ // Transcript plane of a session snapshot.
276
+ message SessionFeed {
277
+ repeated FeedBlock blocks = 1;
278
+ repeated string lines = 2;
279
+ uint64 blocks_base = 3;
280
+ uint64 lines_base = 4;
281
+ repeated FeedBlockPatch block_patches = 5;
282
+ }
283
+
284
+ // Graph-mode state mounted under a session snapshot.
285
+ message SessionGraphState {
286
+ repeated DagRunSnapshot dags = 1;
287
+ repeated SubagentJobSnapshot subagents = 2;
288
+ repeated SessionGraphNode nodes = 3;
289
+ optional string active_node_id = 4;
290
+ }
291
+
292
+ // Session lineage for fork/collapse ancestry.
293
+ message SessionLineage {
294
+ optional string parent_session_id = 1;
295
+ optional string root_session_id = 2;
296
+ repeated string ancestor_session_ids = 3;
297
+ repeated string child_session_ids = 4;
298
+ optional string collapsed_from_session_id = 5;
299
+ optional string collapsed_into_session_id = 6;
300
+ }
301
+
302
+ // Full structured session snapshot: the single-version authoritative current
303
+ // state shape served by GetSnapshot and StreamEvents snapshot frames.
304
+ message SessionSnapshot {
305
+ string session_id = 1;
306
+ SessionInfo info = 2;
307
+ SessionRuntime runtime = 3;
308
+ SessionFeed feed = 4;
309
+ SessionGraphState graph_state = 5;
310
+ SessionLineage lineage = 6;
311
+ }
312
+
313
+ // Cursor-paginated read of the session's full message history. Entries are
314
+ // addressed by storage entry id; `before_entry_id` returns the page of
315
+ // message blocks strictly older than that entry.
316
+ message ListSessionMessagesRequest {
317
+ string session_id = 1;
318
+ // Omitted = newest page of the active branch.
319
+ optional string before_entry_id = 2;
320
+ // Page size; server caps at 500.
321
+ uint32 limit = 3;
322
+ }
323
+
324
+ message SessionMessagePage {
325
+ string session_id = 1;
326
+ // Oldest → newest within the page.
327
+ repeated FeedBlock blocks = 2;
328
+ // Entry id of the oldest message in this page; empty when no older page.
329
+ optional string next_before_entry_id = 3;
330
+ bool has_more = 4;
331
+ // Total message count on the active branch.
332
+ uint64 total = 5;
333
+ }
334
+
335
+ // Collapse a session into a graph node, optionally under another session.
336
+ message CollapseSessionRequest {
337
+ string session_id = 1;
338
+ optional string into_session_id = 2;
339
+ optional string title = 3;
340
+ optional string summary = 4;
341
+ }
342
+
343
+ message CollapseSessionResponse {
344
+ string session_id = 1;
345
+ SessionGraphNode node = 2;
346
+ CollapsedSessionNode collapsed = 3;
347
+ }
348
+
349
+ message GetSessionGraphNodeRequest {
350
+ string session_id = 1;
351
+ string node_id = 2;
352
+ }
353
+
354
+ message GetSessionGraphNodeResponse {
355
+ SessionGraphNode node = 1;
356
+ }
357
+
358
+ message ListSessionGraphNodeMessagesRequest {
359
+ string session_id = 1;
360
+ string node_id = 2;
361
+ uint32 offset = 3;
362
+ uint32 limit = 4;
363
+ }
364
+
365
+ message ListSessionGraphNodeMessagesResponse {
366
+ repeated FeedBlock blocks = 1;
367
+ }
368
+
369
+ message StreamSessionGraphNodeRequest {
370
+ string session_id = 1;
371
+ string node_id = 2;
372
+ }
373
+
374
+ // Streaming frame for node changes and message appends.
375
+ message SessionGraphNodeStreamFrame {
376
+ oneof payload {
377
+ SessionGraphNode node = 1;
378
+ FeedBlock block = 2;
379
+ }
380
+ }
381
+
382
+ message SessionStateRequest {
383
+ string session_id = 1;
384
+ }
385
+
386
+ message UpdateSessionMetadataRequest {
387
+ string session_id = 1;
388
+ map<string, string> metadata = 2;
389
+ }
390
+
391
+ message ListSessionsResponse {
392
+ repeated SessionSummary sessions = 1;
393
+ string current_session_id = 2;
394
+ }
395
+
396
+ message CreateSessionRequest {
397
+ optional string name = 1;
398
+ optional string session_id = 2;
399
+ map<string, string> metadata = 3;
400
+ }
401
+
402
+ message CreateSessionResponse {
403
+ SessionSummary session = 1;
404
+ }
405
+
406
+ message RenameSessionRequest {
407
+ string session_id = 1;
408
+ string name = 2;
409
+ }
410
+
411
+ message DeleteSessionRequest {
412
+ string session_id = 1;
413
+ }
414
+
415
+ message DeleteSessionResponse {
416
+ // Non-empty = deletion refused, these graphs are still running.
417
+ repeated string running_run_ids = 1;
418
+ }
419
+
420
+ // Daemon path context (issue #68): home / base / work_dir are fixed at daemon
421
+ // startup; skills_dirs reflects the current skill search directories and is
422
+ // the only mutable part (see SetSkillDirs).
423
+ message PathContext {
424
+ string home = 1;
425
+ string base = 2;
426
+ string work_dir = 3;
427
+ repeated string skills_dirs = 4;
428
+ }
429
+
430
+ message SetSkillDirsRequest {
431
+ repeated string dirs = 1;
432
+ }
433
+
434
+ // Session activation (issue #26): explicit client key and optional runtime.
435
+ // Runtime is a singular message so its presence remains observable.
436
+ message SessionRuntimeContext {
437
+ string work_dir = 1;
438
+ optional string provider = 2;
439
+ optional string model = 3;
440
+ optional string base_url = 4;
441
+ optional bool thinking = 5;
442
+ }
443
+
444
+ message ActivateSessionRequest {
445
+ optional string session_id = 1;
446
+ string client_key = 2;
447
+ optional string name = 3;
448
+ SessionRuntimeContext runtime = 4;
449
+ }
450
+
451
+ message ActivateSessionResponse {
452
+ SessionSummary session = 1;
453
+ bool created = 2;
454
+ }
455
+
456
+ message SetCredentialRequest {
457
+ string session_id = 1;
458
+ string provider = 2;
459
+ bytes secret = 3;
460
+ }
461
+
462
+ message ClearCredentialRequest {
463
+ string session_id = 1;
464
+ optional string provider = 2;
465
+ }
466
+
467
+ service SessionService {
468
+ // Full nested session snapshot: the single authoritative current snapshot.
469
+ rpc GetSnapshot(SessionStateRequest) returns (SessionSnapshot);
470
+ // Cursor-paginated full message history on the session's active branch.
471
+ rpc ListSessionMessages(ListSessionMessagesRequest) returns (SessionMessagePage);
472
+ // Collapse a session into a graph node (session-snapshot-collapse).
473
+ rpc CollapseSession(CollapseSessionRequest) returns (CollapseSessionResponse);
474
+ rpc GetSessionGraphNode(GetSessionGraphNodeRequest) returns (GetSessionGraphNodeResponse);
475
+ rpc ListSessionGraphNodeMessages(ListSessionGraphNodeMessagesRequest) returns (ListSessionGraphNodeMessagesResponse);
476
+ rpc StreamSessionGraphNode(StreamSessionGraphNodeRequest) returns (stream SessionGraphNodeStreamFrame);
477
+ // Session resources: list (with current marker) / create / rename /
478
+ // delete. DeleteSession reports the offending run ids when refused because
479
+ // the session still has running graphs.
480
+ rpc ListSessions(Empty) returns (ListSessionsResponse);
481
+ rpc CreateSession(CreateSessionRequest) returns (CreateSessionResponse);
482
+ rpc RenameSession(RenameSessionRequest) returns (CommandResult);
483
+ rpc DeleteSession(DeleteSessionRequest) returns (DeleteSessionResponse);
484
+ // Update arbitrary session metadata KV (opaque to thewayd).
485
+ rpc UpdateSessionMetadata(UpdateSessionMetadataRequest) returns (CommandResult);
486
+ // Daemon path context (issue #68): home/base/work_dir plus the current
487
+ // skill search directories.
488
+ rpc GetPathContext(Empty) returns (PathContext);
489
+ // Replace the extra skill directories dynamically; the command is queued
490
+ // into the event loop, which applies it authoritatively (hot-reload).
491
+ // `accepted` = the command was queued.
492
+ rpc SetSkillDirs(SetSkillDirsRequest) returns (CommandResult);
493
+ // Session activation and credentials (issue #26): activate/resume a session
494
+ // and manage provider credentials without echoing secrets.
495
+ rpc ActivateSession(ActivateSessionRequest) returns (ActivateSessionResponse);
496
+ rpc SetCredential(SetCredentialRequest) returns (CommandResult);
497
+ rpc ClearCredential(ClearCredentialRequest) returns (CommandResult);
498
+ }
@@ -0,0 +1,79 @@
1
+ // Settings domain (issue #72): the daemon configuration surface. Controllers
2
+ // read the daemon's current configuration view (GetConfig) and push partial
3
+ // updates (SetConfig / Configure) that the serialized event loop applies
4
+ // authoritatively.
5
+
6
+ syntax = "proto3";
7
+ package theway.grpc.v1;
8
+
9
+ import "commands.proto";
10
+
11
+ // Daemon configuration snapshot / partial update (issue #72).
12
+ //
13
+ // Update semantics: a present `optional` field replaces the daemon's current
14
+ // value; an absent one keeps it. Non-empty repeated values replace lists.
15
+ // `clear_fields` explicitly clears optional or repeated fields, avoiding
16
+ // proto3's absent-vs-empty ambiguity. When a field is both cleared and set in
17
+ // one request, the set value wins.
18
+ //
19
+ // Covered areas: model selection (provider / model / base_url / thinking),
20
+ // skills (builtin_skills / skills_dirs), triggers (trigger_poll_secs), and
21
+ // TUI display (tui_max_feed_lines). Further config areas (relay,
22
+ // orchestrator, hooks, cron, ...) gain fields here in later phases; field
23
+ // numbers are append-only.
24
+ message DaemonConfig {
25
+ // ── model selection ──
26
+ optional string provider = 1;
27
+ optional string model = 2;
28
+ // Custom provider endpoint URL.
29
+ optional string base_url = 3;
30
+ // Extended-thinking toggle.
31
+ optional bool thinking = 4;
32
+
33
+ // ── skills ──
34
+ // Enabled builtin skill names.
35
+ repeated string builtin_skills = 5;
36
+ // Extra skill search directories (mirrors PathContext.skills_dirs).
37
+ repeated string skills_dirs = 6;
38
+
39
+ // ── triggers ──
40
+ optional uint32 trigger_poll_secs = 7;
41
+
42
+ // ── tui ──
43
+ optional uint32 tui_max_feed_lines = 8;
44
+
45
+ // ── controller tool endpoint (issue #77) ──
46
+ // Address of the controller's ToolService server (host:port). When set, the
47
+ // daemon forwards file/process operations to this endpoint instead of
48
+ // executing them locally.
49
+ optional string tool_service_addr = 9;
50
+
51
+ // ── controller storage endpoint (issue #85) ──
52
+ // Address of the controller's StorageService server (host:port). When set,
53
+ // the daemon uses controller-backed runtime storage (sessions, DAG runs,
54
+ // trigger rules, cron jobs) over RPC instead of local storage directly.
55
+ optional string storage_service_addr = 10;
56
+
57
+ // ── thinking level (persisted last-choice default) ──
58
+ // Full thinking level string ("off" | "minimal" | "low" | "medium" |
59
+ // "high" | "xhigh"). Finer-grained than the `thinking` toggle; the toggle
60
+ // stays for legacy compatibility.
61
+ optional string thinking_level = 12;
62
+
63
+ // Field names to clear before applying values present in this message.
64
+ // Unknown names make the daemon reject the patch without partial changes.
65
+ repeated string clear_fields = 11;
66
+ }
67
+
68
+ service SettingsService {
69
+ // Current daemon configuration view: only values successfully applied by
70
+ // the serialized daemon event loop. `clear_fields` is empty in snapshots.
71
+ rpc GetConfig(Empty) returns (DaemonConfig);
72
+ // Push a partial configuration update. The command is queued into the
73
+ // serialized event loop, which applies it authoritatively;
74
+ // `accepted` = the command was queued.
75
+ rpc SetConfig(DaemonConfig) returns (CommandResult);
76
+ // Same operation as SetConfig; kept as a distinct method name so the
77
+ // JSON-RPC / WS / MCP surfaces can align on a `configure` verb.
78
+ rpc Configure(DaemonConfig) returns (CommandResult);
79
+ }
@@ -0,0 +1,130 @@
1
+ // Runtime state externalization domain (issue #84): the StorageService RPC
2
+ // contract for the daemon's persistent runtime state. This is the transport
3
+ // twin of the daemon-side RuntimeStorage seam (#79/#80): a controller/storage
4
+ // side can list/create/rename/delete sessions, persist and reload DAG run
5
+ // snapshots, and back up trigger rules and cron jobs without coupling to the
6
+ // local filesystem/SQLite layout.
7
+ //
8
+ // Session methods mirror SessionService so external storage can drive the same
9
+ // resource lifecycle; DAG/trigger/cron methods carry the serde wire twins from
10
+ // `crate::wire` and are implemented by a StorageOps handler in the daemon.
11
+
12
+ syntax = "proto3";
13
+ package theway.grpc.v1;
14
+
15
+ import "commands.proto";
16
+ import "session.proto";
17
+
18
+ // One persisted DAG run. `snapshot` is the portable JSON `PersistedRun` shape
19
+ // used by GraphEngineService checkpoint/restore, so storage backends treat DAG
20
+ // state as opaque JSON (definition + node progress).
21
+ message StoredDagRun {
22
+ string session_id = 1;
23
+ string run_id = 2;
24
+ string snapshot = 3;
25
+ }
26
+
27
+ message SaveDagRunRequest {
28
+ string session_id = 1;
29
+ string run_id = 2;
30
+ string snapshot = 3;
31
+ }
32
+
33
+ message SaveDagRunResponse {
34
+ bool saved = 1;
35
+ }
36
+
37
+ message LoadDagRunsRequest {
38
+ string session_id = 1;
39
+ // Omitted = load every stored run for the session; set = load one run.
40
+ optional string run_id = 2;
41
+ }
42
+
43
+ message LoadDagRunsResponse {
44
+ repeated StoredDagRun runs = 1;
45
+ }
46
+
47
+ // Session-scoped dynamic trigger rule, persisted in the sidecar format
48
+ // (`triggers.json`) but exposed as a portable storage contract.
49
+ message StoredTriggerRule {
50
+ string id = 1;
51
+ string condition = 2;
52
+ string action = 3;
53
+ bool enabled = 4;
54
+ bool fire_once = 5;
55
+ optional string fired_at = 6; // RFC3339, when the rule has fired
56
+ bool promote_to_chat = 7;
57
+ string created_at = 8; // RFC3339
58
+ }
59
+
60
+ message SaveTriggerRulesRequest {
61
+ string session_id = 1;
62
+ repeated StoredTriggerRule rules = 2;
63
+ }
64
+
65
+ message SaveTriggerRulesResponse {
66
+ uint32 count = 1;
67
+ }
68
+
69
+ message LoadTriggerRulesRequest {
70
+ string session_id = 1;
71
+ }
72
+
73
+ message LoadTriggerRulesResponse {
74
+ repeated StoredTriggerRule rules = 1;
75
+ }
76
+
77
+ // Session-scoped cron job, persisted in the sidecar format (`cron.toml`) but
78
+ // exposed as a portable storage contract.
79
+ message StoredCronJob {
80
+ string id = 1;
81
+ string schedule = 2; // standard 5-field cron expression
82
+ string action = 3;
83
+ bool enabled = 4;
84
+ optional string running_trace_id = 5;
85
+ optional string last_due_at = 6; // RFC3339
86
+ optional string last_fired_at = 7; // RFC3339
87
+ optional string last_completed_at = 8; // RFC3339
88
+ optional string last_error = 9;
89
+ uint64 skipped_overlap_count = 10;
90
+ bool stateful = 11;
91
+ string created_at = 12; // RFC3339
92
+ }
93
+
94
+ message SaveCronJobsRequest {
95
+ string session_id = 1;
96
+ repeated StoredCronJob jobs = 2;
97
+ }
98
+
99
+ message SaveCronJobsResponse {
100
+ uint32 count = 1;
101
+ }
102
+
103
+ message LoadCronJobsRequest {
104
+ string session_id = 1;
105
+ }
106
+
107
+ message LoadCronJobsResponse {
108
+ repeated StoredCronJob jobs = 1;
109
+ }
110
+
111
+ service StorageService {
112
+ // Session resources (mirror SessionService).
113
+ rpc ListSessions(Empty) returns (ListSessionsResponse);
114
+ rpc CreateSession(CreateSessionRequest) returns (CreateSessionResponse);
115
+ rpc RenameSession(RenameSessionRequest) returns (CommandResult);
116
+ rpc DeleteSession(DeleteSessionRequest) returns (DeleteSessionResponse);
117
+ rpc UpdateSessionMetadata(UpdateSessionMetadataRequest) returns (CommandResult);
118
+
119
+ // DAG run persistence.
120
+ rpc SaveDagRun(SaveDagRunRequest) returns (SaveDagRunResponse);
121
+ rpc LoadDagRuns(LoadDagRunsRequest) returns (LoadDagRunsResponse);
122
+
123
+ // Trigger rules persistence.
124
+ rpc SaveTriggerRules(SaveTriggerRulesRequest) returns (SaveTriggerRulesResponse);
125
+ rpc LoadTriggerRules(LoadTriggerRulesRequest) returns (LoadTriggerRulesResponse);
126
+
127
+ // Cron jobs persistence.
128
+ rpc SaveCronJobs(SaveCronJobsRequest) returns (SaveCronJobsResponse);
129
+ rpc LoadCronJobs(LoadCronJobsRequest) returns (LoadCronJobsResponse);
130
+ }