@maudecode/talaria-web-contracts 1.17.2 → 1.19.0

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 (92) hide show
  1. package/dist/gateway-session.d.ts +229 -0
  2. package/dist/gateway-session.js +46 -0
  3. package/dist/gateway-session.js.map +1 -0
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.js +4 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/openapi.js +9 -1
  8. package/dist/openapi.js.map +1 -1
  9. package/dist/router.d.ts +8256 -1763
  10. package/dist/routes/automation.d.ts +130 -25
  11. package/dist/routes/automation.js +8 -4
  12. package/dist/routes/automation.js.map +1 -1
  13. package/dist/routes/chat.d.ts +2484 -41
  14. package/dist/routes/chat.js +10 -4
  15. package/dist/routes/chat.js.map +1 -1
  16. package/dist/routes/core.d.ts +28 -6
  17. package/dist/routes/core.js +5 -2
  18. package/dist/routes/core.js.map +1 -1
  19. package/dist/routes/git.d.ts +76 -1
  20. package/dist/routes/git.js +13 -3
  21. package/dist/routes/git.js.map +1 -1
  22. package/dist/routes/raw.d.ts +3 -1
  23. package/dist/routes/raw.js +30 -6
  24. package/dist/routes/raw.js.map +1 -1
  25. package/dist/routes/sessions.d.ts +5181 -744
  26. package/dist/routes/sessions.js +76 -8
  27. package/dist/routes/sessions.js.map +1 -1
  28. package/dist/routes/settings.d.ts +457 -8
  29. package/dist/routes/settings.js +2 -2
  30. package/dist/routes/settings.js.map +1 -1
  31. package/dist/routes/tools.d.ts +1001 -33
  32. package/dist/routes/tools.js +82 -6
  33. package/dist/routes/tools.js.map +1 -1
  34. package/dist/routes/workspaces.d.ts +82 -0
  35. package/dist/routes/workspaces.js +18 -1
  36. package/dist/routes/workspaces.js.map +1 -1
  37. package/dist/run-status.d.ts +39 -0
  38. package/dist/run-status.js +13 -0
  39. package/dist/run-status.js.map +1 -0
  40. package/dist/sidecar/methods.d.ts +1299 -109
  41. package/dist/sidecar/methods.js +10 -2
  42. package/dist/sidecar/methods.js.map +1 -1
  43. package/dist/sidecar/namespaces.d.ts +1736 -123
  44. package/dist/sidecar/namespaces.js +332 -32
  45. package/dist/sidecar/namespaces.js.map +1 -1
  46. package/dist/sidecar/runtime.d.ts +61 -0
  47. package/dist/sidecar/runtime.js +20 -0
  48. package/dist/sidecar/runtime.js.map +1 -1
  49. package/dist/sidecar/version.d.ts +1 -1
  50. package/dist/sidecar/version.js +1 -1
  51. package/dist/speed.d.ts +14 -0
  52. package/dist/speed.js +6 -0
  53. package/dist/speed.js.map +1 -0
  54. package/dist/sse.d.ts +833 -14
  55. package/dist/sse.js +25 -9
  56. package/dist/sse.js.map +1 -1
  57. package/dist/theme.d.ts +10 -0
  58. package/dist/theme.js +10 -0
  59. package/dist/theme.js.map +1 -0
  60. package/dist/transcribe-stream.d.ts +34 -0
  61. package/dist/transcribe-stream.js +23 -0
  62. package/dist/transcribe-stream.js.map +1 -0
  63. package/dist/views.d.ts +2900 -159
  64. package/dist/views.js +380 -55
  65. package/dist/views.js.map +1 -1
  66. package/fixtures/sidecar/aux.json +134 -0
  67. package/fixtures/sidecar/chat.json +14 -0
  68. package/fixtures/sidecar/checkpoints.json +50 -0
  69. package/fixtures/sidecar/commands.json +258 -99
  70. package/fixtures/sidecar/config.json +15 -0
  71. package/fixtures/sidecar/connectors.json +218 -0
  72. package/fixtures/sidecar/cron.json +1008 -55
  73. package/fixtures/sidecar/gateway.json +39 -0
  74. package/fixtures/sidecar/goals.json +10 -8
  75. package/fixtures/sidecar/kanban.json +181 -90
  76. package/fixtures/sidecar/memory.json +50 -0
  77. package/fixtures/sidecar/models.json +122 -0
  78. package/fixtures/sidecar/personalities.json +92 -0
  79. package/fixtures/sidecar/plugins.json +262 -174
  80. package/fixtures/sidecar/process.json +31 -0
  81. package/fixtures/sidecar/profiles.json +12 -2
  82. package/fixtures/sidecar/providers.json +39 -13
  83. package/fixtures/sidecar/rpc.json +50 -1
  84. package/fixtures/sidecar/runtime.json +131 -22
  85. package/fixtures/sidecar/skills.json +256 -13
  86. package/fixtures/sidecar/state_db.json +34 -2
  87. package/fixtures/sidecar/stt.json +62 -1
  88. package/fixtures/sidecar/text.json +20 -2
  89. package/fixtures/sidecar/toolsets.json +468 -0
  90. package/fixtures/sidecar/usage.json +24 -4
  91. package/fixtures/sidecar/write_approval.json +98 -0
  92. package/package.json +1 -1
@@ -1,17 +1,35 @@
1
1
  import { z } from 'zod';
2
+ import { ProviderPhaseSchema } from '../run-status.js';
3
+ import { SpeedTierSchema } from '../speed.js';
4
+ import { GatewaySessionParamsSchema, GatewaySessionResultSchema } from '../gateway-session.js';
5
+ /** Warnings and wording come from the Agent's selection guard registry, including future guard kinds. */
6
+ export const ModelSelectionWarningSchema = z.object({ kind: z.string(), title: z.string(), model: z.string(), provider: z.string(), message: z.string() });
2
7
  /** Shared param shapes. */
3
8
  export const ProfileHomeParams = z.object({ profile_home: z.string().min(1) });
4
9
  export const BaseHomeParams = z.object({ base_home: z.string().min(1) });
5
10
  const Ok = z.object({ ok: z.boolean() });
6
11
  const Json = z.unknown();
7
12
  const Loose = z.record(z.string(), z.unknown());
13
+ /** Profile-scoped toolset choices; clients render policy and selection without deriving them. */
14
+ export const ToolsetsCatalogSchema = z.object({
15
+ toolsets: z.array(z.object({
16
+ name: z.string(), description: z.string(), available: z.boolean(), selected: z.boolean(),
17
+ unavailable_reason: z.enum(['disabled', 'unavailable']).nullable(),
18
+ })),
19
+ selected_toolsets: z.array(z.string()), using_defaults: z.boolean(),
20
+ });
21
+ export const TOOLSETS_METHODS = {
22
+ 'toolsets.catalog': { params: ProfileHomeParams.extend({ enabled_toolsets: z.array(z.string()).nullable() }), result: ToolsetsCatalogSchema },
23
+ };
8
24
  // ── goals ──────────────────────────────────────────────────────────────
9
25
  export const GoalStateSchema = z.object({
10
26
  goal: z.string(), status: z.string(), turns_used: z.number().int(), max_turns: z.number().int(),
11
27
  last_verdict: z.string().nullable(), last_reason: z.string().nullable(), paused_reason: z.string().nullable(),
12
28
  });
13
29
  const GoalSession = ProfileHomeParams.extend({ session_id: z.string().min(1), default_max_turns: z.number().int().positive().optional() });
14
- export const GoalStatusSchema = z.object({ goal: GoalStateSchema.nullable(), active: z.boolean(), message: z.string(), message_key: z.string().optional(), message_args: z.array(Json).optional() });
30
+ /** TAL-808: `parked` is an active goal's live wait barrier: its reason and, for a timed wait, the Unix-seconds deadline. */
31
+ export const GoalParkedSchema = z.object({ reason: z.string().nullable(), until: z.number().nullable() });
32
+ export const GoalStatusSchema = z.object({ goal: GoalStateSchema.nullable(), active: z.boolean(), parked: GoalParkedSchema.nullable(), message: z.string(), message_key: z.string().optional(), message_args: z.array(Json).optional() });
15
33
  export const GoalCommandResultSchema = z.object({
16
34
  ok: z.boolean(), action: z.string(), message: z.string(), goal: GoalStateSchema.nullable(), error: z.string().optional(), kickoff_prompt: z.string().optional(),
17
35
  message_key: z.string().optional(), message_args: z.array(Json).optional(),
@@ -22,10 +40,11 @@ export const GoalDecisionSchema = z.object({
22
40
  });
23
41
  export const GOALS_METHODS = {
24
42
  'goals.get': { params: GoalSession, result: GoalStatusSchema },
25
- 'goals.command': { params: GoalSession.extend({ args: z.string(), stream_running: z.boolean().optional() }), result: GoalCommandResultSchema },
43
+ // `workspace`: the session's declared workspace, where the Agent runs goal gates (TAL-882).
44
+ 'goals.command': { params: GoalSession.extend({ args: z.string(), stream_running: z.boolean().optional(), workspace: z.string().optional() }), result: GoalCommandResultSchema },
26
45
  'goals.snapshot': { params: GoalSession, result: z.object({ goal: GoalStateSchema.nullable(), snapshot: z.string().nullable() }) },
27
46
  'goals.restore': { params: GoalSession.extend({ snapshot: z.string().nullable() }), result: z.object({ goal: GoalStateSchema.nullable() }) },
28
- 'goals.evaluate': { params: GoalSession.extend({ last_response: z.string(), user_initiated: z.boolean().optional() }), result: GoalDecisionSchema },
47
+ 'goals.evaluate': { params: GoalSession.extend({ last_response: z.string(), user_initiated: z.boolean().optional(), workspace: z.string().optional() }), result: GoalDecisionSchema },
29
48
  };
30
49
  // ── commands / plugins ─────────────────────────────────────────────────
31
50
  export const CommandSchema = z.object({
@@ -33,29 +52,71 @@ export const CommandSchema = z.object({
33
52
  cli_only: z.boolean(), gateway_only: z.boolean(),
34
53
  /** `commands.exec` runs it: the sidecar's runtime commands and every plugin command (TAL-561). */
35
54
  exec: z.boolean(),
55
+ /**
56
+ * An Agent prompt built-in, which every Agent surface answers by sending its builder's prompt as the turn (TAL-817):
57
+ * `expand` when `commands.expand_prompt` can build it on this Agent, `unsupported` when it cannot; null for any other command.
58
+ */
59
+ prompt: z.enum(['expand', 'unsupported']).nullable(),
36
60
  });
37
61
  /**
38
62
  * A model-provider plugin installed and enabled in the profile (TAL-288); bundled providers are built-ins. `setup` is the Agent's
39
63
  * own verdict without spawning the plugin's CLI: `not_loaded` means the installed plugin could not be loaded (import failure, or its
40
64
  * provider id or directory name is taken by another profile's plugin in this process-wide registry).
41
65
  */
66
+ /**
67
+ * TAL-806: one field of a plugin manifest's `config_schema` (Agent `plugin_settings_fields`) with its current value from
68
+ * `plugins.entries.<key>.settings`, else `default`. A `secret` field carries its `.env` name and `has_value`, never a value.
69
+ */
70
+ export const PluginSettingFieldSchema = z.object({
71
+ key: z.string(), type: z.enum(['string', 'number', 'boolean', 'enum', 'json', 'secret']), label: z.string(), description: z.string(), required: z.boolean(),
72
+ choices: z.array(z.string()).optional(), default: Json.optional(), value: Json.optional(), env: z.string().optional(), has_value: z.boolean().optional(),
73
+ });
42
74
  export const PluginProviderSchema = z.object({ name: z.string(), display_name: z.string(), auth_type: z.string(), setup: z.enum(['ready', 'missing_cli', 'needs_setup', 'not_loaded', 'unavailable']) });
75
+ /** A skill bundle: `/<name>` loads its `skill_count` skills in one message (TAL-265). */
76
+ export const CommandBundleSchema = z.object({ name: z.string(), description: z.string(), skill_count: z.number().int(), source: z.literal('bundle') });
77
+ /** `message` is the user message that loads the bundle's skills; members not installed or disabled are in `missing_skills` or left out. */
78
+ export const CommandBundleInvocationSchema = z.object({ name: z.string(), source: z.literal('bundle'), message: z.string(), loaded_skills: z.array(z.string()), missing_skills: z.array(z.string()) });
43
79
  export const COMMANDS_METHODS = {
44
80
  'commands.registry': { params: ProfileHomeParams, result: z.object({ commands: z.array(CommandSchema) }) },
45
- 'commands.exec': { params: ProfileHomeParams.extend({ command: z.string().min(1) }), result: z.object({ output: z.string(), source: z.enum(['agent', 'plugin']) }) },
81
+ /** With `session_id`, a plugin command runs under that chat's session binding and `workspace` (TAL-904). */
82
+ 'commands.exec': { params: ProfileHomeParams.extend({ command: z.string().min(1), session_id: z.string().min(1).optional(), workspace: z.string().optional() }), result: z.object({ output: z.string(), source: z.enum(['agent', 'plugin']) }) },
83
+ /**
84
+ * `/<prompt built-in> [args]` as the turn text (`message`) the Agent's builder writes for the session's profile, workspace and toolsets.
85
+ * `name` is the built-in's canonical name, null when the command is not one; `message` is null when this Agent has no builder for it.
86
+ * A failing builder errors `prompt_expand_failed`.
87
+ */
88
+ 'commands.expand_prompt': { params: ProfileHomeParams.extend({ command: z.string().min(1), workspace: z.string(), enabled_toolsets: z.array(z.string()).nullable() }), result: z.object({ name: z.string().nullable(), message: z.string().nullable() }) },
89
+ 'commands.bundles': { params: ProfileHomeParams, result: z.object({ bundles: z.array(CommandBundleSchema) }) },
90
+ 'commands.bundle_resolve': { params: ProfileHomeParams.extend({ command: z.string().min(1) }), result: CommandBundleInvocationSchema },
46
91
  'commands.moa_preset': { params: ProfileHomeParams.extend({ preset: z.string().nullable().optional() }), result: z.object({ moa: Loose }) },
47
92
  'plugins.providers': { params: ProfileHomeParams, result: z.object({ providers: z.array(PluginProviderSchema) }) },
48
93
  'plugins.list': { params: ProfileHomeParams.extend({ selected_providers: z.record(z.string(), z.string()).optional() }), result: z.object({ plugins: z.array(z.object({ name: z.string(), key: z.string(), version: z.string(), description: z.string(), enabled: z.boolean(), kind: z.string(), activation: z.string(), hooks: z.array(z.string()), is_active_provider: z.boolean().optional() })), supported_hooks: z.array(z.string()) }) },
94
+ /** TAL-820: each profile's `plugins.isolation` and installed third-party plugin count, read without loading a plugin. */
95
+ 'plugins.isolation': { params: BaseHomeParams, result: z.object({ profiles: z.array(z.object({ name: z.string(), isolation: z.enum(['in_process', 'host']), third_party_plugins: z.number().int() })) }) },
96
+ /** TAL-806: plugins whose manifest declares settings; `supported` is false on an Agent without `hermes_cli.plugins_settings`. */
97
+ 'plugins.settings': { params: ProfileHomeParams, result: z.object({ supported: z.boolean(), plugins: z.array(z.object({ key: z.string(), fields: z.array(PluginSettingFieldSchema) })) }) },
98
+ /**
99
+ * TAL-806: write non-secret `values` through the Agent's locked plugin-state writer and return the refreshed fields.
100
+ * An undeclared key, a secret or a type mismatch is invalid params; a managed install or key errors `plugin_settings_managed`.
101
+ * `secret_envs` (secret key → `.env` name the caller wrote) is checked against the current manifest before anything is
102
+ * written; a key that is no longer a secret stored under that name errors `plugin_settings_changed`.
103
+ */
104
+ 'plugins.settings_save': { params: ProfileHomeParams.extend({ key: z.string().min(1), values: z.record(z.string(), Json), secret_envs: z.record(z.string(), z.string()).optional() }), result: z.object({ key: z.string(), written: z.array(z.string()), fields: z.array(PluginSettingFieldSchema) }) },
49
105
  };
50
106
  // ── kanban ─────────────────────────────────────────────────────────────
51
107
  const Board = ProfileHomeParams.extend({ board: z.string().nullable().optional() });
52
- /** `claim_live`: a running task's worker still holds its claim. `has_completion_evidence`: the task stores a result, which the Agent requires to complete it (TAL-557). */
53
- export const KanbanTaskSchema = z.object({ id: z.string(), title: z.string(), status: z.string(), priority: z.number().int(), claim_live: z.boolean(), has_completion_evidence: z.boolean() }).catchall(Json);
108
+ /** `claim_live`: a running task's worker still holds its claim. `has_completion_evidence`: the task stores a result, which the Agent requires to complete it (TAL-557).
109
+ * `agent_move_targets`: the Agent workflow's manual moves from the task's status, `null` before Agent 0.21.6 (TAL-796). */
110
+ export const KanbanTaskSchema = z.object({ id: z.string(), title: z.string(), status: z.string(), priority: z.number().int(), claim_live: z.boolean(), has_completion_evidence: z.boolean(), agent_move_targets: z.array(z.string()).nullable() }).catchall(Json);
54
111
  const TaskEnvelope = z.object({ task: KanbanTaskSchema, read_only: z.boolean() });
112
+ /** Task detail's links (TAL-809): `link_tasks` names each linked task that still exists; `current_run_started_at` is the active run's start, `null` without one (`started_at` is the first-ever start). */
113
+ export const KanbanTaskLinksShape = { links: z.object({ parents: z.array(z.string()), children: z.array(z.string()) }), link_tasks: z.array(z.object({ id: z.string(), title: z.string(), status: z.string() })) };
114
+ export const KanbanRunStartShape = { current_run_started_at: z.number().nullable() };
55
115
  export const KanbanBoardSchema = z.union([
56
116
  z.object({ changed: z.literal(false), latest_event_id: z.number().int(), read_only: z.boolean() }),
57
117
  z.object({
58
- changed: z.literal(true), columns: z.array(z.object({ name: z.string(), tasks: z.array(KanbanTaskSchema) })), tenants: z.array(z.string()), assignees: z.array(z.string()),
118
+ /** The Agent workflow's columns in board order (TAL-796): `name` is the status key, `label` the Agent's English label. */
119
+ changed: z.literal(true), columns: z.array(z.object({ name: z.string(), label: z.string(), tasks: z.array(KanbanTaskSchema) })), tenants: z.array(z.string()), assignees: z.array(z.string()),
59
120
  latest_event_id: z.number().int(), read_only: z.boolean(),
60
121
  filters: z.object({ tenant: z.string().nullable(), assignee: z.string().nullable(), include_archived: z.boolean(), only_mine: z.boolean(), profile: z.string().nullable() }),
61
122
  }),
@@ -70,7 +131,7 @@ export const KANBAN_METHODS = {
70
131
  'kanban.update_board': { params: ProfileHomeParams.extend({ slug: z.string(), board_spec: Loose }), result: z.object({ board: KanbanBoardMetaSchema, read_only: z.boolean() }) },
71
132
  'kanban.delete_board': { params: ProfileHomeParams.extend({ slug: z.string(), delete: z.boolean().optional() }), result: z.object({ result: Json, current: z.string(), read_only: z.boolean() }) },
72
133
  'kanban.switch_board': { params: ProfileHomeParams.extend({ slug: z.string() }), result: z.object({ current: z.string(), read_only: z.boolean() }) },
73
- 'kanban.task': { params: Board.extend({ task_id: z.string() }), result: z.object({ task: KanbanTaskSchema, comments: z.array(Loose), events: z.array(Loose), links: z.object({ parents: z.array(z.string()), children: z.array(z.string()) }), runs: z.array(Loose), read_only: z.boolean() }) },
134
+ 'kanban.task': { params: Board.extend({ task_id: z.string() }), result: z.object({ task: KanbanTaskSchema.extend(KanbanRunStartShape), comments: z.array(Loose), events: z.array(Loose), ...KanbanTaskLinksShape, runs: z.array(Loose), read_only: z.boolean() }) },
74
135
  'kanban.create_task': { params: Board.extend({ task: Loose }), result: TaskEnvelope },
75
136
  'kanban.patch_task': { params: Board.extend({ task_id: z.string(), patch: Loose }), result: TaskEnvelope },
76
137
  'kanban.task_action': { params: Board.extend({ task_id: z.string(), action: z.enum(['block', 'unblock']), reason: z.string().nullable().optional(), confirm_running_exit: z.boolean().optional() }), result: TaskEnvelope },
@@ -80,24 +141,49 @@ export const KANBAN_METHODS = {
80
141
  'kanban.normalize_board': { params: Board, result: z.object({ board: z.string() }) },
81
142
  'kanban.events': { params: Board.extend({ since: z.number().int().optional(), limit: z.number().int().optional() }), result: z.object({ events: z.array(KanbanEventSchema), cursor: z.number().int(), latest_event_id: z.number().int(), read_only: z.boolean() }) },
82
143
  'kanban.config': { params: Board, result: z.object({ columns: z.array(z.string()), assignees: z.array(KanbanAssigneeSchema), default_tenant: z.string(), lane_by_profile: z.boolean(), include_archived_by_default: z.boolean(), render_markdown: z.boolean(), read_only: z.boolean() }) },
83
- 'kanban.stats': { params: Board, result: Loose },
144
+ /** `column_order`: the Agent workflow's column keys in board order (TAL-796). */
145
+ 'kanban.stats': { params: Board, result: z.object({ column_order: z.array(z.string()) }).catchall(Json) },
84
146
  'kanban.assignees': { params: Board, result: z.object({ assignees: z.array(KanbanAssigneeSchema) }) },
85
147
  'kanban.task_log': { params: Board.extend({ task_id: z.string(), tail: z.number().int().optional() }), result: z.object({ task_id: z.string(), path: z.string(), exists: z.boolean(), size_bytes: z.number().int(), content: z.string(), truncated: z.boolean() }) },
86
148
  'kanban.bulk': { params: Board.extend({ bulk: Loose }), result: z.object({ results: z.array(z.object({ id: z.string(), ok: z.boolean(), error: z.string().optional() })), read_only: z.boolean() }) },
87
149
  'kanban.dispatch': { params: Board.extend({ dry_run: z.boolean().optional(), max: z.number().int().optional() }), result: Loose },
88
150
  };
89
151
  // ── state_db ───────────────────────────────────────────────────────────
152
+ /** Busy Agent work, or retained canonical history that this Agent cannot safely retire. */
153
+ export const SessionDeleteRefusedSchema = z.enum(['active_turn', 'runtime_history_unsupported']);
90
154
  const Session = ProfileHomeParams.extend({ session_id: z.string().min(1) });
91
155
  export const STATE_DB_METHODS = {
92
156
  'state_db.sync_start': { params: Session.extend({ model: z.string().nullable().optional() }), result: Ok },
93
157
  'state_db.sync_usage': { params: Session.extend({ input_tokens: z.number().int().optional(), output_tokens: z.number().int().optional(), estimated_cost: z.number().nullable().optional(), model: z.string().nullable().optional(), title: z.string().nullable().optional(), message_count: z.number().int().nullable().optional(), cache_read_tokens: z.number().int().optional(), cache_write_tokens: z.number().int().optional(), api_call_count: z.number().int().nullable().optional() }), result: Ok },
94
- 'state_db.sync_title': { params: Session.extend({ title: z.string() }), result: Ok },
95
- 'state_db.delete_cli_session': { params: Session, result: Ok },
158
+ /** TAL-574: `manual` writes a user-requested title (rename or regenerate) with `user` provenance; otherwise it is an `llm` auto title. */
159
+ 'state_db.sync_title': { params: Session.extend({ title: z.string(), manual: z.boolean().optional() }), result: Ok },
160
+ /**
161
+ * TAL-792: `include_compression_lineage` also removes the session's compression continuations, resolved and removed in the
162
+ * same transaction (tip first). `refused` when another Agent process holds a live turn lease or compression lock on any
163
+ * row the delete would remove, or the Agent lacks retirement APIs for retained canonical history; nothing is removed. `deleted_ids` is the transaction's committed target set,
164
+ * including continuations/delegates; it remains present when only post-commit artifact cleanup failed.
165
+ */
166
+ 'state_db.delete_cli_session': { params: Session.extend({ include_compression_lineage: z.boolean().optional() }), result: Ok.extend({ refused: SessionDeleteRefusedSchema.optional(), deleted_ids: z.array(z.string().min(1)).optional() }) },
167
+ /** TAL-258: append one row through the Agent's `SessionDB.append_message` (bumps `message_count`); `ok` is false without a state.db. */
168
+ 'state_db.append_message': { params: Session.extend({ role: z.string().min(1), content: z.string(), tool_name: z.string().nullable().optional(), timestamp: z.number().nullable().optional() }), result: Ok },
96
169
  };
97
170
  // ── profiles ───────────────────────────────────────────────────────────
171
+ /** TAL-213: the profile's canonical Bot Chat (its session titled exactly "Bot Chat") and that chat's live compression tip. */
172
+ export const CanonicalBotChatSchema = z.object({ session_id: z.string(), tip_session_id: z.string() });
173
+ /**
174
+ * TAL-805: a profile's gateway under the host multiplexer. `own` runs its own gateway process, `served` is served by the
175
+ * live host gateway, `parked` was stopped through the host (`hermes -p X gateway stop`) and nothing runs, `standalone` opted out of the host
176
+ * and is not running, `stopped` is none of these. Only `own` and `served` are running; Agents without the multiplexer
177
+ * helpers report `own` or `stopped`.
178
+ */
179
+ export const GatewayModeSchema = z.enum(['own', 'served', 'parked', 'standalone', 'stopped']);
98
180
  export const ProfileRowSchema = z.object({
99
181
  name: z.string(), path: z.string(), is_default: z.boolean(), gateway_running: z.boolean(), model: z.string().nullable(), provider: z.string().nullable(), has_env: z.boolean(),
100
182
  visible: z.boolean(), skill_count: z.number().int(), enabled_skills: z.number().int(), total_skills: z.number().int(),
183
+ gateway_mode: GatewayModeSchema.default('stopped'),
184
+ // Absent reads as no identity and no chat, so hand-built rows (test fakes) need not spell them out.
185
+ display_name: z.string().default(''), description: z.string().default(''), has_avatar: z.boolean().default(false),
186
+ canonical_session: CanonicalBotChatSchema.nullable().default(null),
101
187
  });
102
188
  export const PROFILES_METHODS = {
103
189
  'profiles.list': { params: BaseHomeParams, result: z.object({ profiles: z.array(ProfileRowSchema) }) },
@@ -107,15 +193,19 @@ export const PROFILES_METHODS = {
107
193
  'profiles.skills_stats': { params: ProfileHomeParams, result: z.object({ enabled: z.number().int(), total: z.number().int() }) },
108
194
  };
109
195
  // ── skills ─────────────────────────────────────────────────────────────
110
- export const SkillRowSchema = z.object({ name: z.string(), description: z.string(), category: z.string().nullable(), disabled: z.boolean() });
196
+ export const SkillCatalogIdentitySchema = z.object({
197
+ load_name: z.string().optional(), declared_name: z.string().optional(),
198
+ status: z.enum(['unique', 'ambiguous', 'shadowed']).optional(), tier: z.number().int().optional(),
199
+ });
200
+ export const SkillRowSchema = SkillCatalogIdentitySchema.extend({ name: z.string(), description: z.string(), category: z.string().nullable(), disabled: z.boolean() });
111
201
  export const SkillViewSchema = z.union([
112
- z.object({ success: z.literal(true), name: z.string(), description: z.string(), tags: z.array(z.string()), related_skills: z.array(z.string()), content: z.string(), path: z.string(), skill_dir: z.string().nullable(), linked_files: z.record(z.string(), z.array(z.string())) }),
202
+ z.object({ success: z.literal(true), name: z.string(), description: z.string(), tags: z.array(z.string()), related_skills: z.array(z.string()), content: z.string(), path: z.string(), skill_dir: z.string().nullable(), linked_files: z.record(z.string(), z.array(z.string())), editable: z.boolean().optional() }),
113
203
  z.object({ success: z.literal(false), error: z.string(), available_skills: z.array(z.string()).optional(), available_skills_truncated: z.boolean().optional(), total_skills: z.number().int().optional(), hint: z.string().optional() }),
114
204
  ]);
115
205
  export const SKILLS_METHODS = {
116
206
  'skills.list': { params: ProfileHomeParams.extend({ category: z.string().nullable().optional() }), result: z.object({ success: z.boolean().optional(), skills: z.array(SkillRowSchema), categories: z.array(z.string()), count: z.number().int(), message: z.string().optional() }) },
117
207
  'skills.view': { params: ProfileHomeParams.extend({ name: z.string().min(1) }), result: SkillViewSchema },
118
- 'skills.find': { params: ProfileHomeParams.extend({ name: z.string().min(1) }), result: z.object({ found: z.boolean(), skill_dir: z.string().nullable(), skill_md: z.string().nullable() }) },
208
+ 'skills.find': { params: ProfileHomeParams.extend({ name: z.string().min(1) }), result: z.object({ found: z.boolean(), skill_dir: z.string().nullable(), skill_md: z.string().nullable(), load_name: z.string().optional(), declared_name: z.string().optional(), sibling_load_names: z.array(z.string()).optional() }) },
119
209
  };
120
210
  // ── mcp ────────────────────────────────────────────────────────────────
121
211
  export const MCP_METHODS = {
@@ -123,18 +213,90 @@ export const MCP_METHODS = {
123
213
  'mcp.registry_tools': { params: ProfileHomeParams, result: z.object({ tools: z.array(z.object({ name: z.string(), server: z.string(), schema: Loose })) }) },
124
214
  'mcp.reload': { params: ProfileHomeParams, result: z.object({ output: z.string() }) },
125
215
  };
216
+ // ── connectors (TAL-818) ───────────────────────────────────────────────
217
+ const ConnectorSlug = z.string().regex(/^[a-z0-9][a-z0-9_-]*$/);
218
+ /** One portal policy layer's rules (the Agent's `PolicyBody`): `allow` names the apps that stay on, `deny` the ones off; `tools` turns single tools off. */
219
+ export const ConnectorPolicyBodySchema = z.object({
220
+ mode: z.enum(['unrestricted', 'deny-all', 'allow', 'deny']),
221
+ connectors: z.array(z.string()).optional(), disabled_connectors: z.array(z.string()).optional(),
222
+ tools: z.record(z.string(), z.object({ disable: z.array(z.string()) })).optional(),
223
+ tags: z.object({ enable: z.array(z.string()).optional(), disable: z.array(z.string()).optional() }).optional(),
224
+ });
225
+ /** A connection operation's target (`tools/connectors/operation.py`): a hosted app account, or an MCP server the card approves. */
226
+ export const ConnectorOperationTargetSchema = z.object({
227
+ name: z.string(), kind: z.string(), state: z.enum(['pending', 'initiated', 'connected', 'skipped', 'failed', 'expired', 'not_connected']), detail: z.string(),
228
+ connect_url: z.string().nullable().optional(),
229
+ required_env: z.array(z.object({ name: z.string(), prompt: z.string(), required: z.boolean(), secret: z.boolean() })),
230
+ });
231
+ /** `owner`: `account` for the Connectors page's connect, `session` for a chat card, which `tool_call_id` opened. */
232
+ export const ConnectorOperationSnapshotSchema = z.object({ op_id: z.string(), settled: z.boolean(), owner: z.enum(['account', 'session']), tool_call_id: z.string().nullable(), targets: z.array(ConnectorOperationTargetSchema) });
233
+ const ConnectorOp = ProfileHomeParams.extend({ op_id: z.string().min(1) });
234
+ /**
235
+ * Failures carry `data.condition`: `connectors_unavailable`, `connectors_sign_in`, `connectors_forbidden`, `connectors_org_required`,
236
+ * `connector_not_found`, `connection_not_found`, `policy_conflict` (the member rules changed since `expected_revision`), `policy_invalid`,
237
+ * `operation_not_found`, `operation_settled`, `operation_refused`, `connectors_failed`.
238
+ */
239
+ export const CONNECTORS_METHODS = {
240
+ /** The Agent's `connectors_available()`; never creates an identity. */
241
+ 'connectors.available': { params: ProfileHomeParams, result: z.object({ available: z.boolean() }) },
242
+ 'connectors.catalog': { params: ProfileHomeParams, result: z.object({ connectors: z.array(z.object({ slug: z.string(), name: z.string(), description: z.string(), category: z.string(), logo_url: z.string().nullable() })) }) },
243
+ 'connectors.accounts': { params: ProfileHomeParams, result: z.object({ accounts: z.array(z.object({ connection_id: z.string(), connector: z.string(), status: z.string(), status_reason: z.string().nullable(), label: z.string(), alias: z.string().nullable(), active: z.boolean(), disabled: z.boolean(), created_at: z.string() })) }) },
244
+ 'connectors.remove': { params: ProfileHomeParams.extend({ connection_id: z.string().min(1) }), result: z.object({ connection_id: z.string(), connector: z.string(), status: z.literal('removed') }) },
245
+ 'connectors.tools': { params: ProfileHomeParams.extend({ connector: ConnectorSlug, refresh: z.boolean().optional() }), result: z.object({ connector: z.string(), tools: z.array(z.object({ slug: z.string(), name: z.string(), description: z.string(), facet: z.string(), hints: z.array(z.string()), categories: z.array(z.string()), deprecated: z.boolean() })) }) },
246
+ 'connectors.policy.get': { params: ProfileHomeParams, result: z.object({ layers: z.array(z.object({ kind: z.enum(['org', 'role', 'member']), revision: z.string(), body: ConnectorPolicyBodySchema })), effective: ConnectorPolicyBodySchema.extend({ revision: z.string() }) }) },
247
+ /** One member-rule change: `enabled` turns the app on or off; `tool` with `tool_enabled` turns one of its tools on or off. */
248
+ 'connectors.policy.set': { params: ProfileHomeParams.extend({ connector: ConnectorSlug, expected_revision: z.string().min(1), enabled: z.boolean().optional(), tool: z.string().min(1).optional(), tool_enabled: z.boolean().optional() }), result: z.object({ revision: z.string() }) },
249
+ /** Starts (or rejoins) the account-owned connect and waits for its authorization link. */
250
+ 'connectors.connect': { params: ProfileHomeParams.extend({ connector: ConnectorSlug }), result: ConnectorOperationSnapshotSchema },
251
+ 'connectors.operation': { params: ConnectorOp, result: ConnectorOperationSnapshotSchema },
252
+ 'connectors.respond': { params: ConnectorOp.extend({ action: z.enum(['skip', 'retry', 'approve', 'continue']), target: z.string().optional(), env: z.record(z.string(), z.string()).optional() }), result: ConnectorOperationSnapshotSchema },
253
+ };
126
254
  // ── stt ────────────────────────────────────────────────────────────────
127
255
  export const STT_METHODS = {
128
- 'stt.capability': { params: ProfileHomeParams, result: z.object({ available: z.boolean(), provider: z.string() }) },
129
- 'stt.transcribe': { params: ProfileHomeParams.extend({ audio_b64: z.string().min(1), suffix: z.string().optional() }), result: z.object({ transcript: z.string() }) },
256
+ /**
257
+ * `streaming` (TAL-802): `stt.streaming` is on and the provider has a live wire with credentials, so `stt.stream` would open.
258
+ * `warm_supported` (TAL-916): the available provider is the local engine and the Agent can pre-load it (`tools.stt_lease`),
259
+ * so `stt.warm` does real work.
260
+ */
261
+ 'stt.capability': { params: ProfileHomeParams, result: z.object({ available: z.boolean(), provider: z.string(), streaming: z.boolean(), warm_supported: z.boolean() }) },
262
+ /**
263
+ * TAL-916: pre-load the profile's local engine (first-use download and model load) so the next `stt.transcribe` starts
264
+ * hot. Blocks until loaded; a no-op (`warmed: false`) for remote providers, and `action: 'unsupported'` on an Agent
265
+ * without the warmer.
266
+ */
267
+ 'stt.warm': { params: ProfileHomeParams, result: z.object({ provider: z.string(), warmed: z.boolean(), action: z.string(), error: z.string().optional() }) },
268
+ 'stt.transcribe': { params: ProfileHomeParams.extend({ audio_b64: z.string().min(1), suffix: z.string().optional() }), result: z.object({ transcript: z.string(), filtered: z.boolean() }) },
269
+ /**
270
+ * TAL-802: one live dictation. Opens the profile's streaming session for s16le mono PCM at `sample_rate` (the sidecar
271
+ * resamples), emits `ready` with the `stream_id` that `stt.stream_audio` feeds, then `partial` text as the provider
272
+ * recognizes it, and returns the session's final transcript once audio ends. Cancelling the call cancels the session.
273
+ */
274
+ 'stt.stream': {
275
+ params: ProfileHomeParams.extend({ sample_rate: z.number().int().min(8000).max(48000) }),
276
+ result: z.object({ transcript: z.string(), filtered: z.boolean(), provider: z.string() }),
277
+ stream: z.discriminatedUnion('event', [
278
+ z.object({ event: z.literal('ready'), data: z.object({ stream_id: z.string() }) }),
279
+ z.object({ event: z.literal('partial'), data: z.object({ text: z.string() }) }),
280
+ ]),
281
+ },
282
+ /** TAL-802: feed one PCM chunk to an open `stt.stream`, in order; `end` marks the end of speech. */
283
+ 'stt.stream_audio': { params: z.object({ stream_id: z.string().min(1), audio_b64: z.string().optional(), end: z.boolean().optional() }), result: z.object({ ok: z.literal(true) }) },
130
284
  };
131
285
  // ── cron ───────────────────────────────────────────────────────────────
132
- export const CronJobSchema = z.object({ id: z.string(), name: z.string().nullable().optional(), profile: z.string().nullable(), toast_notifications: z.boolean(), monitor: z.string(), continuity: z.boolean() }).catchall(Json);
286
+ /** `running_elsewhere`: a live execution owner. `recovery_only`: a retained snapshot, not a source for new task context. */
287
+ export const CronJobSchema = z.object({ id: z.string(), name: z.string().nullable().optional(), profile: z.string().nullable(), toast_notifications: z.boolean(), monitor: z.string(), continuity: z.boolean(), running_elsewhere: z.boolean().optional(), recovery_only: z.boolean().optional() }).catchall(Json);
133
288
  const CronJob = ProfileHomeParams.extend({ job_id: z.string().min(1) });
134
289
  const JobEnvelope = z.object({ job: CronJobSchema });
135
290
  export const CronUsageSchema = z.object({ model: z.string().optional(), provider: z.string().optional(), estimated_cost_usd: z.number().optional(), duration_seconds: z.number().optional(), input_tokens: z.number().int().nullable().optional(), output_tokens: z.number().int().nullable().optional(), total_tokens: z.number().int().nullable().optional() });
291
+ export const CronBlueprintSlotSchema = z.object({ name: z.string(), type: z.string(), label: z.string(), default: z.string().nullable(), options: z.array(z.string()), optional: z.boolean(), strict: z.boolean(), help: z.string() });
292
+ export const CronBlueprintsSchema = z.object({ blueprints: z.array(z.object({ key: z.string(), title: z.string(), description: z.string(), category: z.string(), source: z.enum(['builtin', 'plugin']), plugin: z.string().nullable(), schedule_label: z.string(), slots: z.array(CronBlueprintSlotSchema) })) });
293
+ export const CronBlueprintFillInputSchema = z.object({ key: z.string().min(1), values: z.record(z.string(), z.string()) });
294
+ export const CronBlueprintFillSchema = z.object({ draft: z.object({ name: z.string(), prompt: z.string(), schedule: z.string(), deliver: z.string(), skills: z.array(z.string()) }) });
136
295
  export const CRON_METHODS = {
137
- 'cron.list': { params: ProfileHomeParams, result: z.object({ jobs: z.array(CronJobSchema) }) },
296
+ 'cron.blueprints': { params: ProfileHomeParams, result: CronBlueprintsSchema },
297
+ 'cron.blueprint_fill': { params: CronBlueprintFillInputSchema.extend({ profile_home: z.string().optional() }), result: CronBlueprintFillSchema },
298
+ /** `probe_store` adds the store's write probe (TAL-810): null when writes land or the Agent predates the probe. */
299
+ 'cron.list': { params: ProfileHomeParams.extend({ probe_store: z.boolean().optional() }), result: z.object({ jobs: z.array(CronJobSchema), store_health: z.object({ store: z.string(), error: z.string(), since: z.string(), fix: z.string() }).nullable().optional() }) },
138
300
  'cron.get': { params: CronJob, result: z.object({ job: CronJobSchema.nullable() }) },
139
301
  'cron.create': { params: ProfileHomeParams.extend({ job: Loose, execution_home: z.string().nullable().optional() }), result: JobEnvelope },
140
302
  'cron.update': { params: CronJob.extend({ updates: Loose }), result: JobEnvelope },
@@ -153,12 +315,20 @@ export const CRON_METHODS = {
153
315
  'cron.delivery_options': { params: z.object({}), result: z.object({ platforms: z.array(z.object({ value: z.string(), label: z.string() })) }) },
154
316
  };
155
317
  // ── providers / models ─────────────────────────────────────────────────
318
+ /**
319
+ * `providers.model_ids` `fallback` (TAL-799): the Agent served its curated list because the live catalog was unreachable.
320
+ * `providers.local_models` (TAL-798): the GGUFs staged for the Agent's managed llama.cpp provider `provider_id`, and the
321
+ * running server's base URL (`current_endpoint`, null while it is off).
322
+ */
156
323
  export const PROVIDERS_METHODS = {
157
324
  'providers.registry': { params: ProfileHomeParams, result: z.object({ providers: z.record(z.string(), z.object({ id: z.string(), name: z.string(), auth_type: z.string() }).catchall(Json)) }) },
158
325
  'providers.auth_status': { params: ProfileHomeParams.extend({ provider: z.string().nullable().optional() }), result: z.object({ status: z.object({ logged_in: z.boolean() }).catchall(Json) }) },
159
- 'providers.model_ids': { params: ProfileHomeParams.extend({ provider: z.string().min(1), force_refresh: z.boolean().optional() }), result: z.object({ provider: z.string(), model_ids: z.array(z.string()) }) },
326
+ 'providers.model_ids': { params: ProfileHomeParams.extend({ provider: z.string().min(1), force_refresh: z.boolean().optional() }), result: z.object({ provider: z.string(), model_ids: z.array(z.string()), fallback: z.boolean().default(false) }) },
327
+ 'providers.local_models': { params: ProfileHomeParams, result: z.object({ provider_id: z.string(), models: z.array(z.string()), current_endpoint: z.string().nullable() }) },
160
328
  'providers.resolve_runtime': { params: ProfileHomeParams.extend({ requested: z.string().nullable().optional(), api_key: z.string().nullable().optional(), base_url: z.string().nullable().optional(), target_model: z.string().nullable().optional() }), result: z.object({ runtime: Loose }) },
161
329
  'providers.credential_pool': { params: ProfileHomeParams.extend({ provider: z.string().min(1) }), result: z.object({ available: z.boolean(), strategy: z.string(), entries: z.array(Loose) }) },
330
+ 'models.selection_warnings': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), model: z.string().min(1), provider: z.string().nullable(), current_model: z.string().nullable(), current_provider: z.string().nullable(), context_tokens: z.number().int().positive().nullable(), messages: z.array(Loose) }), result: z.object({ warnings: z.array(ModelSelectionWarningSchema), context_tokens: z.number().int().positive().nullable(), provider: z.string(), base_url: z.string() }) },
331
+ 'models.speed_tiers': { params: ProfileHomeParams.extend({ routes: z.array(z.object({ model: z.string().min(1), provider: z.string(), base_url: z.string().optional() })) }), result: z.object({ tiers: z.array(z.array(SpeedTierSchema)) }) },
162
332
  'models.context_length': { params: ProfileHomeParams.extend({ model: z.string().min(1), base_url: z.string().optional(), api_key: z.string().optional(), provider: z.string().optional(), config_context_length: z.number().int().nullable().optional() }), result: z.object({ model: z.string(), context_length: z.number().int().nullable() }) },
163
333
  'models.estimate_tokens': { params: z.object({ messages: z.array(Loose) }), result: z.object({ tokens: z.number().int() }) },
164
334
  'models.capabilities': { params: ProfileHomeParams.extend({ provider: z.string(), model: z.string() }), result: z.object({ capabilities: Loose.nullable() }) },
@@ -181,14 +351,60 @@ export const OAUTH_METHODS = {
181
351
  // ── aux / text / process / usage / gateway ─────────────────────────────
182
352
  export const AuxUsageSchema = z.object({ prompt_tokens: z.number().int().optional(), completion_tokens: z.number().int().optional(), total_tokens: z.number().int().optional() });
183
353
  export const AUX_METHODS = {
184
- 'aux.complete': { params: ProfileHomeParams.extend({ task: z.string().min(1), messages: z.array(Loose).min(1), main_runtime: Loose.nullable().optional(), main_fallback: z.boolean().optional(), max_tokens: z.number().int().nullable().optional(), temperature: z.number().nullable().optional() }), result: z.object({ model: z.string(), text: z.string(), usage: AuxUsageSchema.nullable() }), stream: z.discriminatedUnion('event', [z.object({ event: z.literal('token'), data: z.object({ text: z.string() }) })]) },
354
+ /**
355
+ * One auxiliary completion. TAL-258: `model` (with `provider`) asks that model itself, reasoning off and no tools, instead
356
+ * of the task's auxiliary route; `credential_missing` means it has no credential. `finish_reason` is the provider's, when known.
357
+ */
358
+ 'aux.complete': { params: ProfileHomeParams.extend({ task: z.string().min(1), messages: z.array(Loose).min(1), main_runtime: Loose.nullable().optional(), main_fallback: z.boolean().optional(), max_tokens: z.number().int().nullable().optional(), temperature: z.number().nullable().optional(), model: z.string().nullable().optional(), provider: z.string().nullable().optional() }), result: z.object({ model: z.string(), text: z.string(), usage: AuxUsageSchema.nullable(), finish_reason: z.string().nullable().default(null) }), stream: z.discriminatedUnion('event', [z.object({ event: z.literal('token'), data: z.object({ text: z.string() }) })]) },
359
+ /**
360
+ * TAL-800: the profile's auxiliary slots in Agent order (built-ins, then the profile's plugin tasks). `reasoning_effort`
361
+ * is the slot's resolved effort (`''` = provider default); `effective` is the route an `inherit_from` task resolves to now.
362
+ * `reserved`: the Agent's other `auxiliary.*` keys (settings and unlisted routes); a reset never touches them.
363
+ */
364
+ 'aux.tasks': { params: ProfileHomeParams, result: z.object({ tasks: z.array(z.object({ key: z.string().min(1), label: z.string(), description: z.string(), inherit_from: z.string().nullable(), reasoning_effort: z.string(), effective: z.object({ provider: z.string(), model: z.string(), base_url: z.string() }).nullable() })), reserved: z.array(z.string()) }) },
185
365
  'aux.resolve': { params: ProfileHomeParams.extend({ task: z.string().min(1), main_runtime: Loose.nullable().optional() }), result: z.object({ configured: z.boolean(), model: z.string().nullable(), error: z.string().optional() }) },
186
366
  };
187
367
  export const TEXT_METHODS = {
188
368
  'text.image_mode': { params: ProfileHomeParams.extend({ provider: z.string(), model: z.string(), cfg: Loose.nullable().optional(), requested_provider: z.string().optional() }), result: z.object({ mode: z.enum(['native', 'text']), reason: z.string(), supports_vision: z.boolean().nullable() }) },
189
369
  'text.portal_tags': { params: ProfileHomeParams, result: z.object({ client_tag: z.string().nullable(), conversation_tag: z.string().nullable(), tags: z.union([z.array(z.string()), Loose]) }) },
370
+ /** TAL-906: the Agent's read-aloud script (`prepare_spoken_text`); `text` as written on an Agent without it. */
371
+ 'text.spoken': { params: z.object({ text: z.string() }), result: z.object({ spoken_text: z.string() }) },
190
372
  };
191
- export const ProcessEventSchema = z.object({ process_id: z.string(), consumed: z.boolean(), type: z.string().optional(), session_key: z.string().optional(), origin_ui_session_id: z.string().optional() }).catchall(Json);
373
+ /**
374
+ * TAL-886: the Agent's `MemoryStore` reading of a MEMORY.md / USER.md body: its char count and the profile's limit for that store.
375
+ * TAL-784: `memory.write` replaces a memory page file with `content` only while its bytes still hash (SHA-256 hex) to `base`,
376
+ * holding the Agent's per-file lock (`<file>.lock`); `written: false` means the file changed and is untouched.
377
+ */
378
+ export const MEMORY_METHODS = {
379
+ 'memory.check': { params: ProfileHomeParams.extend({ target: z.enum(['memory', 'user']), content: z.string() }), result: z.object({ count: z.number().int(), limit: z.number().int() }) },
380
+ 'memory.write': { params: ProfileHomeParams.extend({ section: z.enum(['memory', 'user', 'soul']), base: z.string(), content: z.string() }), result: z.object({ written: z.boolean() }) },
381
+ };
382
+ /**
383
+ * TAL-819: one write the Agent staged for approval (`skills.write_approval` / `memory.write_approval`). `target` is the skill
384
+ * name(s), or `memory` / `user` for the memory store; `op` the staged action; `diff` the unified diff an approval would apply
385
+ * (a skill create shows the new file, a write that would fail says why); `revision` is the SHA-256 of that diff, which an approval
386
+ * must send back. `approvable` is false when no diff could be built or the Agent would refuse the write (`diff` says why;
387
+ * `revision` is empty); such a write can only be rejected.
388
+ */
389
+ export const PendingWriteSchema = z.object({
390
+ id: z.string().regex(/^[A-Za-z0-9_-]{1,64}$/), kind: z.enum(['skills', 'memory']), target: z.string(), op: z.string(), summary: z.string(),
391
+ origin: z.string(), created_at: z.number(), diff: z.string(), approvable: z.boolean(), revision: z.string(),
392
+ });
393
+ export const PendingWriteRefSchema = z.object({ id: PendingWriteSchema.shape.id, revision: z.string() });
394
+ const WriteApprovalParams = ProfileHomeParams.extend({ kind: z.enum(['skills', 'memory']), writes: z.array(PendingWriteRefSchema).min(1) });
395
+ const WriteApprovalResult = z.object({ results: z.array(z.object({ id: z.string(), done: z.boolean(), message: z.string() })) });
396
+ /**
397
+ * TAL-819: the profile's staged writes of `kind`, oldest first, and whether its gate is on; `supported` is false on an Agent
398
+ * without the review handlers. `approve` / `reject` run the Agent's `/skills` or `/memory` handler per write; `done` is true
399
+ * once the record is gone (applied or dropped) and `message` is the handler's text. An approval whose diff no longer has the
400
+ * reviewed `revision` is refused (`done: false`) without applying.
401
+ */
402
+ export const WRITE_APPROVAL_METHODS = {
403
+ 'write_approval.pending': { params: ProfileHomeParams.extend({ kind: z.enum(['skills', 'memory']) }), result: z.object({ supported: z.boolean(), enabled: z.boolean(), items: z.array(PendingWriteSchema) }) },
404
+ 'write_approval.approve': { params: WriteApprovalParams, result: WriteApprovalResult },
405
+ 'write_approval.reject': { params: WriteApprovalParams, result: WriteApprovalResult },
406
+ };
407
+ export const ProcessEventSchema = z.object({ process_id: z.string(), consumed: z.boolean(), type: z.string().optional(), session_key: z.string().optional(), origin_ui_session_id: z.string().optional(), child_process: z.boolean().optional(), reconciliation_profile_home: z.string().optional() }).catchall(Json);
192
408
  export const PROCESS_METHODS = {
193
409
  'process.drain': { params: ProfileHomeParams.extend({ max_events: z.number().int().positive().optional() }), result: z.object({ events: z.array(ProcessEventSchema) }) },
194
410
  /** TAL-533: re-adopt the base home's and every named profile's checkpointed background processes in a fresh sidecar. */
@@ -198,7 +414,7 @@ export const PROCESS_METHODS = {
198
414
  /** TAL-532: the subset the agent already holds from its own turn (consumed via wait/log, or poll-observed). */
199
415
  'process.consumed': { params: z.object({ process_ids: z.array(z.string().min(1)) }), result: z.object({ consumed: z.array(z.string()) }) },
200
416
  /** TAL-459: the Agent's durable delivery ledger. A null claim means another consumer delivered (or holds) it; "" means nothing durable to acknowledge. */
201
- 'process.claim_delivery': { params: ProfileHomeParams.extend({ event: Loose, consumer: z.string().min(1) }), result: z.object({ claim_id: z.string().nullable() }) },
417
+ 'process.claim_delivery': { params: ProfileHomeParams.extend({ event: Loose, consumer: z.string().min(1) }), result: z.object({ claim_id: z.string().nullable(), retryable: z.boolean().optional() }) },
202
418
  'process.complete_delivery': { params: ProfileHomeParams.extend({ event: Loose, claim_id: z.string() }), result: Ok },
203
419
  'process.release_delivery': { params: ProfileHomeParams.extend({ event: Loose, claim_id: z.string() }), result: Ok },
204
420
  /** Hands back a claim the busy target never admitted, without spending one of the Agent's delivery attempts. */
@@ -226,7 +442,7 @@ export const PROCESS_METHODS = {
226
442
  export const AccountUsageSnapshotSchema = z.object({ provider: z.string().nullable(), available: z.boolean(), unavailable_reason: z.string().nullable().optional(), windows: z.array(Loose), details: z.array(Json) }).catchall(Json);
227
443
  /**
228
444
  * TAL-548: one credential-pool entry's local state (no network, no secrets); the server derives a quota source per entry.
229
- * `matches_api_key`: the entry's key is the server-resolved `api_key` passed to `usage.pool`.
445
+ * `matches_api_key`: the entry's key is the configured key, passed as `api_key` or resolved from `env_vars` in the profile's secret scope.
230
446
  */
231
447
  export const PoolEntrySchema = z.object({
232
448
  credential_id: z.string(), label: z.string(), status: z.enum(['available', 'exhausted', 'dead']), unavailable_reason: z.string().nullable(), retry_after: z.string().nullable(),
@@ -234,7 +450,7 @@ export const PoolEntrySchema = z.object({
234
450
  });
235
451
  const BalanceNumber = z.number().nullable();
236
452
  /**
237
- * TAL-548: one key-based balance read. The key is the pool entry's (`credential_id`) or the server-resolved `api_key`.
453
+ * TAL-548: one key-based balance read. The key is the pool entry's (`credential_id`), a raw `api_key`, or resolved from `env_vars` in the profile's secret scope.
238
454
  * `ok` carries the provider's sanitised fields: OpenRouter `quota`/`label`, DeepSeek `balances`/`is_available`, OpenCode Go
239
455
  * `windows`; `http_error` carries the status code.
240
456
  */
@@ -245,22 +461,45 @@ export const BalanceResultSchema = z.object({
245
461
  windows: z.array(z.object({ key: z.enum(['rolling', 'weekly', 'monthly']), used_percent: z.number(), reset_at: z.string(), rate_limited: z.boolean() })),
246
462
  });
247
463
  const CredentialId = z.string().min(1).nullable().optional();
464
+ /** TAL-807: the Agent's `CredentialPool.limit_state`: every live account benched until `resets_at`, else the given models no usable account serves until their ISO reset. */
465
+ export const PoolLimitSchema = z.discriminatedUnion('scope', [
466
+ z.object({ scope: z.literal('account'), resets_at: z.string() }),
467
+ z.object({ scope: z.literal('models'), models: z.record(z.string(), z.string()) }),
468
+ ]);
248
469
  export const USAGE_METHODS = {
249
470
  'usage.account': { params: ProfileHomeParams.extend({ provider: z.string().min(1), base_url: z.string().nullable().optional(), api_key: z.string().nullable().optional(), credential_id: CredentialId }), result: z.object({ snapshot: AccountUsageSnapshotSchema.nullable() }) },
250
- 'usage.pool': { params: ProfileHomeParams.extend({ provider: z.string().min(1), api_key: z.string().nullable().optional() }), result: z.object({ entries: z.array(PoolEntrySchema) }) },
471
+ 'usage.pool': { params: ProfileHomeParams.extend({ provider: z.string().min(1), api_key: z.string().nullable().optional(), env_vars: z.array(z.string().min(1)).optional() }), result: z.object({ entries: z.array(PoolEntrySchema), has_api_key: z.boolean().optional() }) },
251
472
  /** TAL-548: the providers whose persisted credential pool holds an account the user added, keyed or not. */
252
- 'usage.pool_providers': { params: ProfileHomeParams, result: z.object({ providers: z.array(z.string()) }) },
253
- 'usage.balance': { params: ProfileHomeParams.extend({ provider: z.enum(['openrouter', 'deepseek', 'opencode-go']), credential_id: CredentialId, api_key: z.string().nullable().optional() }), result: BalanceResultSchema },
473
+ 'usage.pool_providers': { params: ProfileHomeParams.extend({ key_envs: z.record(z.string(), z.array(z.string().min(1))).optional() }), result: z.object({ providers: z.array(z.string()), keys: z.record(z.string(), z.object({ present: z.boolean(), revision: z.string().nullable() })).default({}) }) },
474
+ /** TAL-807: pool rate limits by provider slug, only for pooled providers that are limited; `models` are bare ids. */
475
+ 'usage.limits': { params: ProfileHomeParams.extend({ providers: z.array(z.object({ slug: z.string().min(1), models: z.array(z.string()) })) }), result: z.object({ limits: z.record(z.string(), PoolLimitSchema) }) },
476
+ 'usage.balance': { params: ProfileHomeParams.extend({ provider: z.enum(['openrouter', 'deepseek', 'opencode-go']), credential_id: CredentialId, api_key: z.string().nullable().optional(), env_vars: z.array(z.string().min(1)).optional() }), result: BalanceResultSchema },
254
477
  };
255
478
  export const CONFIG_METHODS = {
256
479
  // `config_path` is the server-resolved file (honouring HERMES_CONFIG_PATH); the sidecar reads and writes exactly that path.
257
480
  'config.get': { params: ProfileHomeParams.extend({ config_path: z.string().min(1) }), result: z.object({ path: z.string(), exists: z.boolean(), config: Loose }) },
258
481
  'config.set': { params: ProfileHomeParams.extend({ config_path: z.string().min(1), config: Loose }), result: z.object({ ok: z.literal(true), path: z.string() }) },
482
+ /** TAL-797: `.env` edits through the Agent's locked writer; `null` removes a key, an empty value is skipped; line breaks, spaces, quotes, `#` and non-ASCII are refused. */
483
+ 'config.env_write': { params: ProfileHomeParams.extend({ updates: z.record(z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/), z.string().nullable()) }), result: z.object({ ok: z.literal(true), path: z.string() }) },
259
484
  'models.reasoning_efforts': { params: ProfileHomeParams.extend({ model: z.string(), provider: z.string() }), result: z.object({ efforts: z.array(z.string()), supports_reasoning: z.boolean().nullable() }) },
485
+ /**
486
+ * TAL-901: the Agent's personalities for `config` (its built-ins, then the top-level `personalities:` block, then
487
+ * `agent.personalities`), by case-folded name in the Agent's order; `prompt` is the rendered overlay text.
488
+ */
489
+ 'personalities.list': { params: z.object({ config: Loose }), result: z.object({ personalities: z.array(z.object({ name: z.string().min(1), description: z.string(), prompt: z.string() })) }) },
260
490
  };
261
491
  export const WORKTREE_METHODS = {
262
492
  'worktree.create': { params: ProfileHomeParams.extend({ repo_root: z.string().min(1) }), result: z.object({ path: z.string(), branch: z.string(), repo_root: z.string(), base: z.string().nullable() }) },
263
493
  };
494
+ /** TAL-913: a workspace's checkpoints, read and restored through the Agent's `CheckpointManager`; `store` is its shared git store. */
495
+ const CheckpointTarget = ProfileHomeParams.extend({ workspace: z.string().min(1) });
496
+ export const AgentCheckpointSchema = z.object({ hash: z.string(), short_hash: z.string(), timestamp: z.string(), reason: z.string(), files_changed: z.number().int(), insertions: z.number().int(), deletions: z.number().int() });
497
+ export const CHECKPOINTS_METHODS = {
498
+ 'checkpoints.list': { params: CheckpointTarget, result: z.object({ checkpoints: z.array(AgentCheckpointSchema), store: z.string() }) },
499
+ /** `diff` is `git diff <checkpoint> --cached` over the workspace: `a/` is the checkpoint, `b/` the files now. */
500
+ 'checkpoints.diff': { params: CheckpointTarget.extend({ checkpoint: z.string().min(1) }), result: z.object({ stat: z.string(), diff: z.string() }) },
501
+ 'checkpoints.restore': { params: CheckpointTarget.extend({ checkpoint: z.string().min(1) }), result: z.object({ restored_to: z.string(), reason: z.string() }) },
502
+ };
264
503
  // ── chat / approval / clarify ──────────────────────────────────────────
265
504
  export const ChatUsageSchema = z.object({ prompt_tokens: z.number().int(), completion_tokens: z.number().int(), cache_read_tokens: z.number().int(), cache_write_tokens: z.number().int(), estimated_cost_usd: z.number().nullable() });
266
505
  /**
@@ -270,10 +509,16 @@ export const ChatUsageSchema = z.object({ prompt_tokens: z.number().int(), compl
270
509
  * A completed `compressed` turn also carries `context_messages`, its `messages` with tool output pruned and capped for the model (row for row),
271
510
  * and `post_compression_context_tokens_estimate`, the next request's estimated size (TAL-539); both are null otherwise.
272
511
  */
512
+ /**
513
+ * The turn agent's context figures (`context_length`, `threshold_tokens`, `last_prompt_tokens`, `compression_count`). TAL-1005:
514
+ * `next_turn_threshold_tokens` is the compression threshold the next turn runs under, the primary runtime's when a fallback ran
515
+ * this one (the Agent restores the primary each turn); absent when the Agent reports none.
516
+ */
517
+ const ChatContextSchema = z.looseObject({ next_turn_threshold_tokens: z.number().int().positive().optional() });
273
518
  export const ChatStartResultSchema = z.object({
274
519
  status: z.enum(['completed', 'cancelled', 'error']), messages: z.array(Loose), context_messages: z.array(Loose).nullable().optional(), post_compression_context_tokens_estimate: z.number().int().nullable().optional(), final_response: z.string(), error: z.string().nullable(),
275
520
  failed: z.boolean(), partial: z.boolean(), compression_exhausted: z.boolean(),
276
- tool_limit_reached: z.boolean(), max_iterations_summary_request: z.string(), usage: ChatUsageSchema, context: Loose, model: z.string(), provider: z.string(), compressed: z.boolean(), agent_session_id: z.string(),
521
+ tool_limit_reached: z.boolean(), max_iterations_summary_request: z.string(), usage: ChatUsageSchema, context: ChatContextSchema, model: z.string(), provider: z.string(), compressed: z.boolean(), agent_session_id: z.string(),
277
522
  token_sent: z.boolean(), pending_steer: z.string(), live_tool_calls: z.array(Loose),
278
523
  });
279
524
  const Text = z.object({ text: z.string() }).catchall(Json);
@@ -282,6 +527,8 @@ const Text = z.object({ text: z.string() }).catchall(Json);
282
527
  * (scalars as sent, text and nested values as capped text) or its capped text. The server decides `is_error` from it and never forwards it; `is_error` is only an older sidecar's `false`.
283
528
  * A `todo` tool's frame also carries `todo_result`, the tool's full result text, which the server turns into `todo_state` (TAL-397) and never forwards.
284
529
  * A result with a string `diff` also carries `result_diff`, that whole diff, which the server turns into `edit_diff` (TAL-448) and never forwards.
530
+ * TAL-909: `display_metadata` is the dict the sidecar returned for the Agent to persist on the tool-result row (a file edit's unified `diff`
531
+ * from the Agent's before-snapshot); the server turns its `diff` into `edit_diff` when the result has none, and never forwards it.
285
532
  */
286
533
  const ToolFrame = z.object({ event_type: z.string(), name: z.string().nullable().optional(), preview: Json.optional(), args: Loose.optional(), tid: z.string().optional(), is_error: z.boolean().optional() }).catchall(Json);
287
534
  export const ChatStreamSchema = z.discriminatedUnion('event', [
@@ -297,11 +544,26 @@ export const ChatStreamSchema = z.discriminatedUnion('event', [
297
544
  z.object({ event: z.literal('approval'), data: Loose }),
298
545
  z.object({ event: z.literal('clarify'), data: Loose }),
299
546
  z.object({ event: z.literal('clarify_resolved'), data: Loose }),
547
+ /** TAL-818: a `manage_connections` card opened; `tool_call_id` is the call that opened it. */
548
+ z.object({ event: z.literal('connection'), data: ConnectorOperationSnapshotSchema }),
300
549
  /** The Agent stopped waiting on an approval: `reason` is its settle cause (`resolved`, `timeout`, `interrupted`, `session_closed`). */
301
550
  z.object({ event: z.literal('approval_resolved'), data: z.looseObject({ approval_id: z.string(), session_id: z.string().optional(), reason: z.string().optional() }) }),
302
551
  z.object({ event: z.literal('compressing'), data: Loose }),
552
+ /** TAL-1006: the Agent finished the compaction the last `compressing` started; an aborted one sends none. */
553
+ z.object({ event: z.literal('compression_finished'), data: Loose }),
303
554
  z.object({ event: z.literal('warning'), data: Loose }),
304
555
  z.object({ event: z.literal('status'), data: Loose }),
556
+ /**
557
+ * TAL-803: the Agent's `AgentNotice` (`kind` `sticky` or `ttl`, `ttl_ms` only for `ttl`), the clear of one by `key`, and
558
+ * `notices_reset` before a new agent for the session is built: the notices of the one it replaces with
559
+ * `lapses_with_agent` lapse (an Agent startup warning, raised once per process, does not).
560
+ */
561
+ z.object({ event: z.literal('notice'), data: z.looseObject({ id: z.string().nullable().optional(), key: z.string().nullable().optional(), level: z.string(), kind: z.string(), ttl_ms: z.number().int().nullable().optional(), text: z.string(), lapses_with_agent: z.boolean().optional() }) }),
562
+ z.object({ event: z.literal('notice_clear'), data: z.looseObject({ key: z.string() }) }),
563
+ z.object({ event: z.literal('notices_reset'), data: Loose }),
564
+ z.object({ event: z.literal('provider_phase'), data: z.object({ phase: ProviderPhaseSchema.nullable() }) }),
565
+ /** TAL-821: the Agent's live rate-limit wait (`until`, epoch seconds: the limit's reset or the Agent's retry, as `until_kind` says); a null `until` ends it. */
566
+ z.object({ event: z.literal('rate_limit_wait'), data: z.looseObject({ provider: z.string().nullable(), until: z.number().nullable(), until_kind: z.enum(['reset', 'retry']).optional() }) }),
305
567
  ]);
306
568
  export const CHAT_METHODS = {
307
569
  'chat.start': {
@@ -316,6 +578,14 @@ export const CHAT_METHODS = {
316
578
  persist_user_message: z.string().optional(),
317
579
  /** TAL-529: a `/btw` side question, whose throwaway session the Agent keeps out of the profile's state.db. */
318
580
  ephemeral: z.boolean().optional(),
581
+ /** TAL-801: a spoken turn, which the Agent runs on the profile's `auxiliary.voice_chat` slot when it has that route. */
582
+ voice_turn: z.boolean().optional(),
583
+ /** TAL-818: attach the Agent's `connection_callback`, so `manage_connections` streams a `connection` frame and waits on the card. */
584
+ connect_card: z.boolean().optional(),
585
+ /** Bind turn-local skill capture only for a client that renders the masked prompt. */
586
+ skill_secret: z.boolean().optional(),
587
+ /** TAL-903: `workspace` is a host path (the profile's terminal runs locally), so the Agent anchors AGENTS.md discovery and its memory provider there. A remote backend's target-side path is never read on the host. */
588
+ workspace_local: z.boolean().optional(),
319
589
  }),
320
590
  result: ChatStartResultSchema,
321
591
  stream: ChatStreamSchema,
@@ -335,11 +605,11 @@ export const CHAT_METHODS = {
335
605
  /**
336
606
  * TAL-424: deliver `pending[index]` now with the Agent's `redirect`: `delivery: redirect` restarts the model request with
337
607
  * it, `delivery: steer` puts it last on the slot while tools yield. Not redirected: it stays pending, `requeued` in its
338
- * place (`kept`) or last (`last`); `withdrawn: false` when the Agent already took it.
608
+ * place (`kept`) or last (`last`); `withdrawn: false` when the Agent already took it, or `reason: not_running` when the run or Agent is absent.
339
609
  */
340
610
  'chat.steer_now': {
341
611
  params: z.object({ stream_id: z.string().optional(), session_id: z.string().optional(), pending: z.array(z.string().min(1)).min(1), index: z.number().int().nonnegative() }),
342
- result: z.object({ redirected: z.boolean(), withdrawn: z.boolean(), delivery: z.enum(['redirect', 'steer']).optional(), requeued: z.enum(['kept', 'last']).optional() }),
612
+ result: z.object({ redirected: z.boolean(), withdrawn: z.boolean(), delivery: z.enum(['redirect', 'steer']).optional(), requeued: z.enum(['kept', 'last']).optional(), reason: z.enum(['not_running']).optional() }),
343
613
  },
344
614
  /**
345
615
  * TAL-255: manual `/compress` of `conversation_history` through the Agent's `compress_now` on a throwaway agent. Nothing is
@@ -360,14 +630,44 @@ export const CHAT_METHODS = {
360
630
  },
361
631
  /** TAL-255: second phase of `chat.compress`; `finalized: false` when the token is unknown or already expired. */
362
632
  'chat.compress_finalize': { params: z.object({ commit_token: z.string().min(1), committed: z.boolean() }), result: z.object({ finalized: z.boolean() }) },
633
+ 'chat.finalize_session': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), reason: z.enum(['clear', 'delete']) }), result: z.object({ messages: z.array(z.string()) }) },
363
634
  'chat.evict_agent': { params: z.object({ session_id: z.string().min(1), clear_session: z.boolean().optional() }), result: z.object({ evicted: z.boolean() }) },
364
635
  'chat.commit_memory': { params: ProfileHomeParams.extend({ session_id: z.string().min(1) }), result: z.object({ committed: z.boolean() }) },
636
+ /**
637
+ * TAL-902: `/refine [focus]`, the Agent's on-demand memory/skill review of `messages` (the session's model context) on the
638
+ * session's cached agent, else one built from the turn parameters and cached like a turn's. `output` is the Agent's
639
+ * wording: the review started, or why not (a turn is running, the conversation is empty).
640
+ */
641
+ 'chat.refine': {
642
+ params: ProfileHomeParams.extend({
643
+ session_id: z.string().min(1), messages: z.array(Loose), focus: z.string(), model: z.string(), model_provider: z.string().nullable().optional(),
644
+ enabled_toolsets: z.array(z.string()).nullable().optional(), max_iterations: z.number().int().nullable().optional(), max_tokens: z.number().int().nullable().optional(),
645
+ reasoning_config: z.object({ enabled: z.boolean(), effort: z.string().optional() }).nullable().optional(),
646
+ /** TAL-903: the session's workspace, as `chat.start` sends it, so the agent built here is the one its next turn reuses. */
647
+ workspace: z.string().optional(), workspace_local: z.boolean().optional(),
648
+ }),
649
+ result: z.object({ output: z.string() }),
650
+ },
365
651
  'approval.respond': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), choice: z.enum(['once', 'session', 'always', 'deny']), request_id: z.string().nullable().optional() }), result: z.object({ ok: z.boolean(), resolved: z.number().int(), choice: z.string() }) },
366
652
  'approval.pending': { params: z.object({ session_id: z.string().min(1) }), result: z.object({ pending: z.array(Loose) }) },
367
653
  'approval.set_yolo': { params: z.object({ session_id: z.string().min(1), enabled: z.boolean() }), result: z.object({ yolo_enabled: z.boolean(), released: z.number().int() }) },
368
- 'clarify.respond': { params: z.object({ stream_id: z.string().optional(), session_id: z.string().optional(), clarify_id: z.string().optional(), response: z.string().min(1) }), result: z.object({ ok: z.boolean(), clarify_id: z.string().optional() }) },
654
+ 'clarify.respond': { params: z.object({ stream_id: z.string().optional(), session_id: z.string().optional(), clarify_id: z.string().optional(), response: z.string() }), result: z.object({ ok: z.boolean(), clarify_id: z.string().optional() }) },
369
655
  };
656
+ const GatewayActionParams = ProfileHomeParams.extend({ cli_profile: z.string().nullable().optional(), quick_timeout_seconds: z.number().optional(), background_wait_seconds: z.number().optional() });
657
+ /**
658
+ * A lifecycle run of `hermes --profile <name> gateway <action>` for the profile at `profile_home` (TAL-894). `busy` means another
659
+ * action holds the lock; `timed_out` marks a child killed after `background_wait_seconds` (a restart defaults to the Agent CLI's own
660
+ * restart budget plus 30 s) or cancelled. `detail` is CLI output, never shown to a browser; `reason` is the Agent's first error line of a
661
+ * failed run (TAL-884), the one line the server shows.
662
+ */
663
+ const GatewayActionResult = z.object({ status: z.enum(['completed', 'failed', 'busy']), message: z.string(), detail: z.string().optional(), returncode: z.number().int().optional(), reason: z.string().optional(), timed_out: z.boolean().optional() });
664
+ const GatewayActionStream = z.discriminatedUnion('event', [z.object({ event: z.literal('progress'), data: z.object({ phase: z.enum(['started', 'draining']) }) })]);
665
+ export const GATEWAY_ACTIONS = ['start', 'stop', 'restart'];
370
666
  export const GATEWAY_METHODS = {
371
- 'gateway.restart': { params: ProfileHomeParams.extend({ cli_profile: z.string().nullable().optional(), quick_timeout_seconds: z.number().optional(), background_wait_seconds: z.number().optional() }), result: z.object({ status: z.enum(['completed', 'failed', 'busy']), message: z.string(), detail: z.string().optional(), returncode: z.number().int().optional() }), stream: z.discriminatedUnion('event', [z.object({ event: z.literal('progress'), data: z.object({ phase: z.enum(['started', 'draining']) }) })]) },
667
+ 'gateway.session': { params: GatewaySessionParamsSchema, result: GatewaySessionResultSchema, stream: z.object({ event: z.enum(['snapshot', 'event']), data: Loose }) },
668
+ 'gateway.control': { params: GatewayActionParams.extend({ action: z.enum(GATEWAY_ACTIONS) }), result: GatewayActionResult, stream: GatewayActionStream },
669
+ 'gateway.restart': { params: GatewayActionParams, result: GatewayActionResult, stream: GatewayActionStream },
670
+ /** TAL-805: the gateway mode of the profile `name` at `profile_home`; the root profile (`is_default`) is the host itself. */
671
+ 'gateway.mode': { params: ProfileHomeParams.extend({ name: z.string().min(1), is_default: z.boolean() }), result: z.object({ gateway_mode: GatewayModeSchema }) },
372
672
  };
373
673
  //# sourceMappingURL=namespaces.js.map