@maudecode/talaria-web-contracts 1.16.1 → 1.17.2

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 (40) hide show
  1. package/dist/router.d.ts +634 -20
  2. package/dist/routes/automation.d.ts +147 -9
  3. package/dist/routes/automation.js +15 -8
  4. package/dist/routes/automation.js.map +1 -1
  5. package/dist/routes/chat.d.ts +51 -0
  6. package/dist/routes/git.d.ts +22 -1
  7. package/dist/routes/git.js +7 -3
  8. package/dist/routes/git.js.map +1 -1
  9. package/dist/routes/raw.js +2 -2
  10. package/dist/routes/raw.js.map +1 -1
  11. package/dist/routes/sessions.d.ts +315 -0
  12. package/dist/routes/sessions.js +10 -0
  13. package/dist/routes/sessions.js.map +1 -1
  14. package/dist/routes/settings.d.ts +101 -2
  15. package/dist/routes/settings.js +4 -4
  16. package/dist/routes/settings.js.map +1 -1
  17. package/dist/routes/tools.d.ts +73 -8
  18. package/dist/routes/tools.js +1 -1
  19. package/dist/routes/tools.js.map +1 -1
  20. package/dist/routes/workspaces.d.ts +14 -0
  21. package/dist/sidecar/methods.d.ts +120 -0
  22. package/dist/sidecar/namespaces.d.ts +204 -1
  23. package/dist/sidecar/namespaces.js +53 -7
  24. package/dist/sidecar/namespaces.js.map +1 -1
  25. package/dist/sidecar/version.d.ts +1 -1
  26. package/dist/sidecar/version.js +1 -1
  27. package/dist/sidecar/version.js.map +1 -1
  28. package/dist/sse.d.ts +42 -4
  29. package/dist/sse.js +12 -4
  30. package/dist/sse.js.map +1 -1
  31. package/dist/views.d.ts +618 -9
  32. package/dist/views.js +109 -18
  33. package/dist/views.js.map +1 -1
  34. package/fixtures/sidecar/commands.json +195 -92
  35. package/fixtures/sidecar/kanban.json +24 -8
  36. package/fixtures/sidecar/process.json +25 -0
  37. package/fixtures/sidecar/rpc.json +2 -0
  38. package/fixtures/sidecar/runtime.json +3 -3
  39. package/fixtures/sidecar/usage.json +38 -0
  40. package/package.json +1 -1
package/dist/views.js CHANGED
@@ -17,8 +17,14 @@ export const AttachmentSchema = z.looseObject({
17
17
  });
18
18
  /** The server's display class for a tool call: clients map it to an icon and localized verb, and never classify names themselves. */
19
19
  export const ToolKindSchema = z.enum(['shell', 'read', 'list', 'search', 'web', 'write', 'skill', 'memory', 'delegate', 'unknown']);
20
- /** Server-derived display fields every tool call carries: the kind, and the redacted first-line label of its main argument (`''` when none; omitted on a live frame with none, which keeps its start frame's target). */
21
- export const ToolDisplayFields = { kind: ToolKindSchema.optional(), target: z.string().optional() };
20
+ /**
21
+ * TAL-448: a completed file-edit call's change, from its result's unified diff: `added` / `removed` count the whole diff's
22
+ * lines (file headers excluded); `diff` is the redacted diff, capped at 400 lines, with `truncated` when cut. Absent on a
23
+ * call whose result has no diff.
24
+ */
25
+ export const ToolEditDiffSchema = z.object({ added: z.number().int(), removed: z.number().int(), diff: z.string(), truncated: z.boolean() });
26
+ /** Server-derived display fields every tool call carries: the kind, and the redacted first-line label of its main argument (`''` when none; omitted on a live frame with none, which keeps its start frame's target), and a file edit's `edit_diff`. */
27
+ export const ToolDisplayFields = { kind: ToolKindSchema.optional(), target: z.string().optional(), edit_diff: ToolEditDiffSchema.optional() };
22
28
  /**
23
29
  * TAL-315: a tool result's display sections, decided by the server's one rule for live, replayed and persisted results
24
30
  * alike. Clients show `stdout`, `stderr`, a labelled `error` and a labelled `exit_code` (sent only when worth showing), or
@@ -118,6 +124,11 @@ export const MessageSchema = z.looseObject({
118
124
  /** A settled body too long to lay out whole: clients render `_display_excerpt` collapsed, with a local "Show more" for `content`. */
119
125
  _display_truncated: z.boolean().optional(),
120
126
  _display_excerpt: z.string().optional(),
127
+ /**
128
+ * TAL-452: a typed user message (never a steer, background update or marker) longer than 20 lines or 2,000
129
+ * characters. Clients show it folded to a few lines with a local "Show more"; copy and edit use the whole `content`.
130
+ */
131
+ _collapsible: z.boolean().optional(),
121
132
  /**
122
133
  * TAL-186: an assistant row's text with each media reference the server serves rewritten to standard Markdown: an
123
134
  * image to `![alt](url)`, any other file to `[name](url)`. Clients render it in place of `content` as one Markdown
@@ -179,6 +190,7 @@ const ReadOnlySchema = z.boolean().describe('The session cannot be modified from
179
190
  const CanBranchSchema = z.boolean().describe('Web may branch this session: never a subagent child, and a read-only session only when it is a cron run.');
180
191
  const CanPinSchema = z.boolean().describe('Web may pin or unpin this session: never a subagent child.');
181
192
  const CanArchiveSchema = z.boolean().describe('Web may archive or unarchive this session: never a subagent child.');
193
+ const CanDeleteSchema = z.boolean().describe('Web may delete this session: never a read-only session (a read-only import, a view-only subagent child, or a foreign session whose owner refuses claiming).');
182
194
  const CanDuplicateSchema = z.boolean().describe('Web may duplicate this session: it has a WebUI copy and is not a subagent child.');
183
195
  // TAL-310: the server classifies every session's source once; clients file rows by it and never scan source markers.
184
196
  export const SourceKindSchema = z.enum(['webui', 'cli', 'messaging', 'cron', 'webhook', 'subagent', 'claude_code', 'kanban', 'api', 'other'])
@@ -191,6 +203,15 @@ const IsMessagingSessionSchema = z.boolean().describe('`source_kind` is `messagi
191
203
  * the folder name (TAL-303). Null without a workspace; absent from an older server, where clients show no label.
192
204
  */
193
205
  const WorkspaceNameSchema = NullableString.optional();
206
+ /**
207
+ * TAL-560: the "Context compaction · Reference only" card, on payloads that carry `messages`. Clients render `text` after
208
+ * the row at full-transcript index `after_message_index` (row `after_message_index - _messages_offset` of `messages`), or
209
+ * above the loaded rows when it is null or before them. Null: no card.
210
+ */
211
+ export const CompressionReferenceSchema = z.object({
212
+ text: z.string(),
213
+ after_message_index: z.number().int().nonnegative().nullable().describe('The full-transcript index of the row the card follows; null puts it above the transcript.'),
214
+ });
194
215
  /** Full session record from `GET /api/session` and mutations returning `session`. */
195
216
  export const SessionSchema = z.looseObject({
196
217
  session_id: SessionIdSchema, title: z.string(), workspace: z.string().optional(), created_workspace: z.string().nullable().optional(), model: NullableString.optional(), model_provider: NullableString.optional(),
@@ -201,9 +222,9 @@ export const SessionSchema = z.looseObject({
201
222
  cache_hit_percent: NullableNumber.optional(), estimated_cost: NullableNumber.optional(), active_stream_id: ActiveStreamIdSchema, is_streaming: IsStreamingSchema, active_turn_origin: ActiveTurnOriginSchema, pending_steers: z.array(PendingSteerSchema).optional().describe('TAL-424: the active stream\'s pending steers, oldest first.'), has_pending_user_message: z.boolean().optional(),
202
223
  pending_user_message: NullableString.optional(), pending_attachments: z.array(AttachmentSchema).optional(), pending_started_at: NullableNumber.optional(), pending_user_source: NullableString.optional(),
203
224
  context_length: NullableNumber.optional(), threshold_tokens: NullableNumber.optional(), last_prompt_tokens: NullableNumber.optional(), post_compression_context_tokens_estimate: NullableNumber.optional(), ...ContextUsageFields,
204
- enabled_toolsets: z.array(z.string()).nullable().optional(), composer_draft: ComposerDraftSchema.optional(), is_cli_session: z.boolean().optional(), source_kind: SourceKindSchema, is_messaging_session: IsMessagingSessionSchema, sort_ts: SortTsSchema, read_only: ReadOnlySchema, can_branch: CanBranchSchema, can_pin: CanPinSchema, can_archive: CanArchiveSchema, can_duplicate: CanDuplicateSchema, source_tag: NullableString.optional(),
225
+ enabled_toolsets: z.array(z.string()).nullable().optional(), composer_draft: ComposerDraftSchema.optional(), is_cli_session: z.boolean().optional(), source_kind: SourceKindSchema, is_messaging_session: IsMessagingSessionSchema, sort_ts: SortTsSchema, read_only: ReadOnlySchema, can_branch: CanBranchSchema, can_pin: CanPinSchema, can_archive: CanArchiveSchema, can_delete: CanDeleteSchema, can_duplicate: CanDuplicateSchema, source_tag: NullableString.optional(),
205
226
  source_label: NullableString.optional(), session_source: NullableString.optional(), raw_source: NullableString.optional(), parent_session_id: NullableString.optional(), worktree_path: NullableString.optional(),
206
- worktree_branch: NullableString.optional(), worktree_repo_root: NullableString.optional(), share_token: NullableString.optional(), share_created_at: NullableNumber.optional(), manual_title: z.boolean().optional(),
227
+ worktree_branch: NullableString.optional(), worktree_repo_root: NullableString.optional(), share_token: NullableString.optional(), share_url: NullableString.optional(), share_created_at: NullableNumber.optional(), manual_title: z.boolean().optional(),
207
228
  compression_anchor_summary: NullableString.optional(), compression_recovery: z.record(z.string(), Json).optional(), recommended_recovery_action: NullableString.optional(), compression_recovery_action: NullableString.optional(),
208
229
  compression_recovery_source_session_id: NullableString.optional(), gateway_routing: Json.optional(), _messages_offset: z.number().optional(), _messages_truncated: z.boolean().optional(), _msg_limit_max: z.number().optional(), _load_revision: z.string().optional(),
209
230
  /**
@@ -215,15 +236,16 @@ export const SessionSchema = z.looseObject({
215
236
  /** The agent's display name: a named profile's own name, else the `bot_name` setting (TAL-458). */
216
237
  assistant_name: z.string().optional(),
217
238
  workspace_name: WorkspaceNameSchema,
239
+ compression_reference: CompressionReferenceSchema.nullable().optional(),
218
240
  });
219
241
  export const SessionEnvelopeSchema = z.looseObject({ session: SessionSchema });
220
242
  /** Sidebar row from `GET /api/sessions`. */
221
243
  export const SessionRowSchema = z.looseObject({
222
244
  session_id: SessionIdSchema, title: z.string(), workspace: z.string().optional(), model: NullableString.optional(), created_at: UnixSeconds.optional(), updated_at: UnixSeconds.optional(), last_message_at: NullableNumber.optional(),
223
245
  message_count: z.number().optional(), pinned: z.boolean().optional(), archived: z.boolean().optional(), project_id: NullableString.optional(), profile: NullableString.optional(), is_streaming: IsStreamingSchema,
224
- is_cli_session: z.boolean().optional(), source_kind: SourceKindSchema, is_messaging_session: IsMessagingSessionSchema, sort_ts: SortTsSchema, cron_running: z.boolean().optional(), read_only: ReadOnlySchema, can_branch: CanBranchSchema, can_pin: CanPinSchema, can_archive: CanArchiveSchema, can_duplicate: CanDuplicateSchema, attention: z.looseObject({ kind: z.string().optional(), count: z.number().optional() }).nullable().optional(),
246
+ is_cli_session: z.boolean().optional(), source_kind: SourceKindSchema, is_messaging_session: IsMessagingSessionSchema, sort_ts: SortTsSchema, cron_running: z.boolean().optional(), read_only: ReadOnlySchema, can_branch: CanBranchSchema, can_pin: CanPinSchema, can_archive: CanArchiveSchema, can_delete: CanDeleteSchema, can_duplicate: CanDuplicateSchema, attention: z.looseObject({ kind: z.string().optional(), count: z.number().optional() }).nullable().optional(),
225
247
  source_tag: NullableString.optional(), source_label: NullableString.optional(), session_source: NullableString.optional(), raw_source: NullableString.optional(), parent_session_id: NullableString.optional(),
226
- active_stream_id: ActiveStreamIdSchema, share_token: NullableString.optional(), worktree_branch: NullableString.optional(), match_type: z.enum(['title', 'metadata', 'content']).optional(), match_preview: NullableString.optional(),
248
+ active_stream_id: ActiveStreamIdSchema, share_token: NullableString.optional(), share_url: NullableString.optional(), worktree_branch: NullableString.optional(), match_type: z.enum(['title', 'metadata', 'content']).optional(), match_preview: NullableString.optional(),
227
249
  workspace_name: WorkspaceNameSchema,
228
250
  ...ContextUsageFields,
229
251
  });
@@ -254,7 +276,12 @@ export const ChatStartResponseSchema = z.looseObject({
254
276
  stream_id: z.string().optional(), session_id: SessionIdSchema.optional(), turn_id: z.string().optional(), user_message_id: z.union([z.string(), z.number()]).nullable().optional(), pending_started_at: z.number().nullable().optional(),
255
277
  title: z.string().optional(), effective_model: z.string().optional(), effective_model_provider: z.string().optional(), queued: z.boolean().optional(), ok: z.boolean().optional(), status: z.string().optional(), reason: z.string().optional(), session: SessionSchema.optional(),
256
278
  });
257
- export const StreamStatusSchema = z.looseObject({ active: z.boolean(), stream_id: z.string(), replay_available: z.boolean().optional(), journal: Json.optional() });
279
+ /**
280
+ * `active` is whether this stream's channel is still live. `blocking_stream_id` (TAL-622) is the run that still holds the
281
+ * stream's session: this run while it unwinds after a Stop, or a successor such as a goal continuation. A session delete
282
+ * answers 409 while it is set, so a client draining a session before deleting it waits until it is null.
283
+ */
284
+ export const StreamStatusSchema = z.looseObject({ active: z.boolean(), stream_id: z.string(), replay_available: z.boolean().optional(), journal: Json.optional(), blocking_stream_id: z.string().nullable() });
258
285
  /**
259
286
  * TAL-424: a pending steer is no longer pending without the Agent taking it: Edit and Cancel by the user, `stopped` by a
260
287
  * Stop (`text` goes back to the composer), or `followup` when the server sends it as the next turn. `steer_id` is null
@@ -301,7 +328,9 @@ export const ClarifyRespondRequestSchema = z.looseObject({ session_id: SessionId
301
328
  export const ClarifyRespondResponseSchema = z.looseObject({ ok: z.boolean(), response: z.string().optional(), error: z.string().optional(), stale: z.boolean().optional() });
302
329
  export const DraftSchema = z.looseObject({ text: z.string(), files: z.array(Json) });
303
330
  export const DraftResponseSchema = z.looseObject({ ok: z.literal(true), draft: DraftSchema, draft_version: z.string().nullable(), unchanged: z.boolean().optional() });
304
- export const UploadResponseSchema = z.looseObject({ filename: z.string(), path: z.string(), size: z.number(), mime: z.string(), is_image: z.boolean().optional(), rollback_token: z.string().optional() });
331
+ /** At most this many attachments ride one chat message; the server names each in the prompt (TAL-276, TAL-635). */
332
+ export const MAX_CHAT_ATTACHMENTS = 20;
333
+ export const UploadResponseSchema = z.looseObject({ filename: z.string(), path: z.string(), size: z.number(), mime: z.string(), is_image: z.boolean().optional(), rollback_token: z.string().optional(), named_in_prompt: z.boolean().optional(), max_attachments_per_message: z.number().int().positive().optional() });
305
334
  export const GoalViewSchema = z.looseObject({ text: z.string().optional(), state: z.string().optional(), status: z.string().optional(), turns: z.number().optional(), max_turns: z.number().optional(), reason: z.string().optional() });
306
335
  export const GoalResponseSchema = z.looseObject({ ok: z.boolean().optional(), action: z.string().optional(), goal: GoalViewSchema.nullable().optional(), message: z.string().optional(), message_key: z.string().optional(), stream_id: z.string().optional(), status: z.string().optional(), reason: z.string().optional() });
307
336
  export const BackgroundResultSchema = z.looseObject({ id: z.string().optional(), task_id: z.string().optional(), status: z.string().optional(), title: z.string().optional(), summary: z.string().optional(), prompt: z.string().optional(), answer: NullableString.optional(), error: z.string().optional(), completed_at: z.number().nullable().optional() });
@@ -352,6 +381,11 @@ export const SessionNewRequestSchema = z.looseObject({
352
381
  });
353
382
  export const TranscribeCapabilitySchema = z.looseObject({ ok: z.literal(true), available: z.boolean(), provider: z.string() });
354
383
  // ── settings, profiles, models, providers ───────────────────────────────
384
+ /** TAL-411: the request profile's quota urgency thresholds. A save patches valid fields and clamps critical to at most warning. */
385
+ export const QuotaThresholdsSchema = z.object({
386
+ warning_remaining_percent: z.number().int().min(1).max(99), critical_remaining_percent: z.number().int().min(0).max(99), pace_tolerance_percent: z.number().int().min(0).max(25),
387
+ pace_warning_burn_rate_percent: z.number().int().min(100).max(300), pace_critical_burn_rate_percent: z.number().int().min(100).max(400), pace_minimum_elapsed_hours: z.number().int().min(0).max(72),
388
+ });
355
389
  export const LoginResponseSchema = z.looseObject({ ok: z.literal(true), message: z.string().optional() });
356
390
  export const SettingsSchema = z.looseObject({
357
391
  bot_name: z.string().optional(), default_model: z.string().optional(), default_workspace: z.string().optional(), language: z.string().optional(), send_key: z.string().optional(), font_size: z.string().optional(),
@@ -364,6 +398,7 @@ export const SettingsSchema = z.looseObject({
364
398
  dictation_append: z.boolean().optional(), persisted_speech_keys: z.array(z.string()).optional(),
365
399
  /** TAL-279: ask before opening external chat links; `trusted_link_hosts` are exact, server-normalized hostnames that skip the ask. */
366
400
  confirm_external_links: z.boolean().optional(), trusted_link_hosts: z.array(z.string()).optional(),
401
+ provider_quota_thresholds: QuotaThresholdsSchema.optional(),
367
402
  });
368
403
  export const ProfileSchema = z.looseObject({
369
404
  name: z.string(), path: z.string().optional(), is_active: z.boolean().optional(), is_default: z.boolean().optional(), model: NullableString.optional(), provider: NullableString.optional(), skill_count: z.number().optional(),
@@ -378,16 +413,21 @@ export const ReasoningStatusSchema = z.looseObject({ show_reasoning: z.boolean()
378
413
  export const ModelEntrySchema = z.looseObject({ id: z.string(), label: z.string().optional(), provider: z.string().optional(), provider_id: z.string().optional(), bare_id: z.string().optional(), supports_fast_tier: z.boolean().optional() });
379
414
  export const ModelGroupSchema = z.looseObject({ provider: z.string(), provider_id: z.string().optional(), models: z.array(ModelEntrySchema), extra_models: z.array(ModelEntrySchema).optional() });
380
415
  export const ModelsSchema = z.looseObject({ active_provider: NullableString.optional(), default_model: z.string().optional(), default_provider_id: NullableString.optional(), default_bare_id: z.string().optional(), default_option_id: NullableString.optional(), groups: z.array(ModelGroupSchema), aliases: z.record(z.string(), Json).optional(), configured_model_badges: z.record(z.string(), Json).optional() });
416
+ /** `has_key` reports a credential; `configured` (TAL-570) is the row's setup status, which a keyless Ollama or LM Studio endpoint also meets. */
381
417
  export const ProviderSchema = z.looseObject({
382
- id: z.string(), display_name: z.string().optional(), has_key: z.boolean().optional(), configurable: z.boolean().optional(), is_oauth: z.boolean().optional(), is_plugin_provider: z.boolean().optional(), is_self_hosted: z.boolean().optional(),
418
+ id: z.string(), display_name: z.string().optional(), has_key: z.boolean().optional(), configured: z.boolean().optional(), configurable: z.boolean().optional(), is_oauth: z.boolean().optional(), is_plugin_provider: z.boolean().optional(), is_self_hosted: z.boolean().optional(),
383
419
  is_custom: z.boolean().optional(), key_source: z.string().optional(), base_url: NullableString.optional(), auth_error: NullableString.optional(), env_var: NullableString.optional(), models: z.array(ModelEntrySchema).optional(), models_total: z.number().optional(),
384
420
  });
385
421
  export const ProvidersSchema = z.looseObject({ providers: z.array(ProviderSchema), active_provider: NullableString.optional() });
422
+ export const QuotaLevelSchema = z.enum(['healthy', 'warning', 'critical', 'stale', 'unavailable']);
423
+ /** TAL-411: the server's classification per colour basis; `/api/provider/quotas` only, at the profile's thresholds. */
424
+ export const QuotaUrgencySchema = z.looseObject({ remaining: QuotaLevelSchema, pace: QuotaLevelSchema.describe('Burn rate and pace tolerance; the remaining classification when the window has no pace.') });
386
425
  /** TAL-409: a window's pace as of the envelope's `computed_at`. Stale once `valid_until` (the window's reset) passes. */
387
426
  export const QuotaPaceSchema = z.looseObject({
388
427
  expected_remaining_percent: z.number(), pace_delta_percent: z.number(), burn_rate: z.number(), minutes_to_reset: z.number(),
389
428
  projected_minutes_to_empty: NullableNumber.describe('Minutes until the window empties at the current burn; null when nothing has been used.'),
390
429
  elapsed_minutes: z.number(), valid_until: z.string(),
430
+ status: z.enum(['over', 'on', 'under']).optional().describe('TAL-411, `/api/provider/quotas` only: over when behind pace by at least the tolerance, under when more than 1 point ahead.'),
391
431
  });
392
432
  export const QuotaForecastSchema = z.looseObject({
393
433
  outcome: z.enum(['safe', 'warning']).describe('`warning` when the projection empties the window before it resets.'),
@@ -399,6 +439,8 @@ export const QuotaWindowSchema = z.looseObject({
399
439
  window_seconds: NullableNumber.describe('The provider value, else 5h or weekly from the label; null when unknown.'),
400
440
  pace: QuotaPaceSchema.nullable().describe('Null for a window without a future reset, a usage value, or a 5h/weekly length.'),
401
441
  forecast: QuotaForecastSchema.nullable(),
442
+ projection_eligible: z.boolean().optional().describe('TAL-411, `/api/provider/quotas` only: the burn-rate breakpoints apply (enough elapsed time and use, and the projection empties the window before reset).'),
443
+ urgency: QuotaUrgencySchema.optional(),
402
444
  });
403
445
  const QuotaWindowIndex = z.number().int().nullable().optional();
404
446
  export const QuotaSourceSchema = z.looseObject({
@@ -406,6 +448,7 @@ export const QuotaSourceSchema = z.looseObject({
406
448
  is_active_provider: z.boolean().optional(), quota: Json.optional(), windows: z.array(QuotaWindowSchema).optional(), balances: Json.optional(), plan: Json.optional(), details: Json.optional(), unavailable_reason: Json.optional(), retry_after: Json.optional(), fetched_at: Json.optional(),
407
449
  pace_window_index: QuotaWindowIndex.describe('The window a pace-coloured widget shows: the weekly one, else the first 5h/session window.'),
408
450
  session_window_index: QuotaWindowIndex.describe('The session (else 5h) window.'), weekly_window_index: QuotaWindowIndex.describe('The weekly window.'),
451
+ urgency: QuotaUrgencySchema.optional().describe('TAL-411: `remaining` of the first window, `pace` of the pace window; alerts and the source colour follow it.'),
409
452
  });
410
453
  /** An account-usage provider's normalised snapshot on `/api/provider/quota` (the same windows and indexes as a quotas source). */
411
454
  export const QuotaAccountLimitsSchema = z.looseObject({
@@ -426,6 +469,22 @@ export const ProviderQuotasSchema = z.looseObject({
426
469
  missing_source: z.boolean().describe('True when `?source=` names a source id this scope no longer has; `sources` is then empty.'),
427
470
  sources: z.array(QuotaSourceSchema).describe('Each live source id exactly once, ordered by `provider_id`, then `account_label`, then `source_id`. Clients render this list as-is; a `?source=` read returns that one row.'),
428
471
  });
472
+ /** One day of OpenRouter spend on `/api/provider/cost-history` (TAL-412). */
473
+ export const CostSnapshotSchema = z.looseObject({
474
+ date: z.string().describe('UTC day, `YYYY-MM-DD`.'), used: NullableNumber.describe('Cumulative OpenRouter usage in USD that day.'),
475
+ delta: NullableNumber.describe("Spend since the previous day; the day's `used` after a credit reset; null for the first day or a missing `used`."),
476
+ bar_percent: z.number().describe('Bar height: `delta` as a percent of the window\'s largest delta, at least 2 for any positive delta, 0 for a null delta.'),
477
+ });
478
+ /** Python `get_provider_cost_history`: OpenRouter daily spend with the server-computed monthly pace and budget standing. */
479
+ export const ProviderCostHistorySchema = z.looseObject({
480
+ ok: z.boolean(), provider: NullableString, display_name: z.string().optional(), supported: z.boolean().optional(), status: z.string().describe('`available`, `unavailable` (the snapshots are the last known data), `no_key`, `unsupported`, or `missing_provider`.'), message: z.string(),
481
+ window_days: z.number().int().optional(), snapshots: z.array(CostSnapshotSchema).optional(), limit: NullableNumber.optional(), label: NullableString.optional(),
482
+ monthly_budget: NullableNumber.optional().describe('Settings `provider_cost_budget`.'),
483
+ monthly_pace: NullableNumber.optional().describe('Mean of the non-null deltas × 30, in USD rounded to cents; null without a delta.'),
484
+ has_enough_data: z.boolean().optional().describe('At least one non-null delta (two daily snapshots).'),
485
+ budget_percent: NullableNumber.optional().describe('round(pace / budget × 100); null without a positive pace and a budget.'),
486
+ budget_level: z.enum(['ok', 'warn', 'over']).nullable().optional().describe('`warn` from 80%, `over` from 100%; null without `budget_percent`.'),
487
+ });
429
488
  export const PersonalitiesSchema = z.looseObject({ personalities: z.array(z.looseObject({ name: z.string(), description: z.string().optional() })) });
430
489
  /** One auxiliary task slot in server order (TAL-388). The server owns ordering, normalization, and catalog matching. */
431
490
  export const AuxiliaryTaskSchema = z.looseObject({
@@ -453,7 +512,15 @@ export const FileEntrySchema = z.looseObject({
453
512
  birthtime_ns: z.union([z.number(), z.string()]).nullable().optional(), hidden: z.boolean().optional(), workspace_sort_rank: z.number().int().optional(), target: z.string().optional(), target_outside_workspace: z.boolean().optional(),
454
513
  });
455
514
  export const DirListingSchema = z.looseObject({ path: z.string().optional(), entries: z.array(FileEntrySchema), signature: z.string().optional(), workspace: z.string().optional(), workspace_recovered: z.boolean().optional(), is_git: z.boolean().optional() });
456
- export const FileContentSchema = z.looseObject({ path: z.string().optional(), content: z.string().optional(), lines: z.number().optional(), size: z.number().optional(), truncated: z.boolean().optional(), binary: z.boolean().optional(), mime: z.string().optional() });
515
+ /** How a workspace file renders (TAL-566): media streams from `/api/file/raw`; text kinds carry `content`. */
516
+ export const FilePreviewKindSchema = z.enum(['text', 'markdown', 'csv', 'html', 'image', 'pdf', 'audio', 'video', 'binary']);
517
+ /** `table` is a `csv` preview's leading rows (header first); `table_truncated` says the file has more. `preview_url` is an
518
+ * `html` preview's app-relative frame URL, under which the page's relative assets also resolve. */
519
+ export const FileContentSchema = z.looseObject({
520
+ path: z.string().optional(), content: z.string().optional(), lines: z.number().optional(), size: z.number().optional(), truncated: z.boolean().optional(), binary: z.boolean().optional(), mime: z.string().optional(),
521
+ preview: FilePreviewKindSchema.optional(), table: z.array(z.array(z.string())).optional(), table_truncated: z.boolean().optional(),
522
+ preview_url: z.string().optional(),
523
+ });
457
524
  export const GitInfoSchema = z.looseObject({ git: z.looseObject({ is_git: z.boolean().optional(), branch: NullableString.optional(), dirty: z.number().optional(), modified: z.number().optional(), untracked: z.number().optional(), ahead: z.number().optional(), behind: z.number().optional() }).nullable().optional() });
458
525
  // ── tools ────────────────────────────────────────────────────────────────
459
526
  export const SkillSchema = z.looseObject({ name: z.string(), description: NullableString.optional(), category: NullableString.optional(), disabled: z.boolean().optional() });
@@ -472,13 +539,14 @@ export const PromptsSchema = z.looseObject({ prompts: z.array(PromptSchema) });
472
539
  * first, then the Agent registry, in display order; each name appears once. `handler` says who runs it, `clients` which
473
540
  * clients can run it, and `unsupported_message` is the English text a client outside `clients` shows when it is typed.
474
541
  * Clients suggest the entries listing them whose name or any alias starts with the typed text (case-insensitive), and
475
- * resolve a typed alias to the entry's `name`.
542
+ * resolve a typed alias to the entry's `name`. `exec` marks an Agent entry `POST /api/commands/exec` runs: the client
543
+ * posts the typed text there and shows the returned output instead of starting a chat turn (TAL-561).
476
544
  */
477
545
  export const CommandClientSchema = z.enum(['web', 'ios']);
478
546
  export const CommandRowSchema = z.looseObject({
479
547
  name: z.string(), description: z.string().optional(), aliases: z.array(z.string()), args_hint: z.string().optional(), category: z.string().optional(),
480
548
  handler: z.enum(['client', 'agent']), clients: z.array(CommandClientSchema), unsupported_message: z.string().optional(),
481
- cli_only: z.boolean().optional(), gateway_only: z.boolean().optional(), subcommands: z.array(Json).optional(),
549
+ cli_only: z.boolean().optional(), gateway_only: z.boolean().optional(), subcommands: z.array(Json).optional(), exec: z.boolean().optional(),
482
550
  });
483
551
  export const CommandsSchema = z.looseObject({ commands: z.array(CommandRowSchema) });
484
552
  export const LogsSchema = z.looseObject({ file: z.string(), tail: z.number().optional(), lines: z.array(z.string()), truncated: z.boolean().optional(), total_bytes: z.number().optional(), mtime: NullableNumber.optional(), hint: z.string().optional() });
@@ -494,7 +562,14 @@ export const SystemHealthSchema = z.looseObject({
494
562
  available: z.boolean().optional(), status: z.string().optional(), checked_at: z.string().optional(), cpu: Json.nullable().optional(), memory: Json.nullable().optional(), disk: z.looseObject({ percent: z.number().optional(), total_bytes: z.number().optional(), used_bytes: z.number().optional() }).nullable().optional(),
495
563
  errors: z.array(z.looseObject({ code: z.string().optional(), metric: z.string().optional() })).optional(), webui_runtime: Json.optional(),
496
564
  });
497
- export const UpdateTargetSchema = z.looseObject({ name: z.string().optional(), channel: z.enum(['stable', 'experimental']).optional(), unsupported: z.boolean().optional(), supported_revision: z.string().optional(), supported_version: z.string().optional(), candidate_revision: z.string().optional(), behind: z.number().nullable().optional(), current_sha: z.string().nullable().optional(), latest_sha: z.string().nullable().optional(), compare_url: z.string().optional(), repo_url: z.string().optional(), error: z.string().optional(), ok: z.boolean().optional(), manual_update: z.boolean().optional(), no_git: z.boolean().optional(), install_kind: z.literal('npm').optional(), npm: z.string().optional(), channel_switch: z.boolean().optional(), dirty: z.boolean().optional(), metadata_repair: z.boolean().optional(), release_url: z.string().optional(), ignored: z.boolean().optional(), stale_check: z.boolean().optional(), current_version: z.string().optional() });
565
+ export const UpdateStateSchema = z.enum(['up_to_date', 'release_ready', 'commits_behind', 'local_changes', 'finish', 'manual', 'check_failed', 'off', 'unknown']);
566
+ export const UpdateTargetSchema = z.looseObject({ name: z.string().optional(), channel: z.enum(['stable', 'experimental']).optional(), unsupported: z.boolean().optional(), supported_revision: z.string().optional(), supported_version: z.string().optional(), candidate_revision: z.string().optional(), behind: z.number().nullable().optional(), current_sha: z.string().nullable().optional(), latest_sha: z.string().nullable().optional(), compare_url: z.string().optional(), repo_url: z.string().optional(), error: z.string().optional(), ok: z.boolean().optional(), manual_update: z.boolean().optional(), no_git: z.boolean().optional(), install_kind: z.literal('npm').optional(), npm: z.string().optional(), channel_switch: z.boolean().optional(), dirty: z.boolean().optional(), metadata_repair: z.boolean().optional(), release_url: z.string().optional(), ignored: z.boolean().optional(), stale_check: z.boolean().optional(), current_version: z.string().optional(),
567
+ state: UpdateStateSchema.describe('TAL-559: the status clients word; `off` when checks are disabled or Agent updates are ignored.'),
568
+ can_apply: z.boolean().describe('The apply action is available for this target.'),
569
+ installed_unverified: z.boolean().describe('`release_ready` only: the installed revision sits on no release tag.'),
570
+ manual_link: z.boolean().describe('Show the manual-install (releases) link.'),
571
+ target_version: z.string().nullable().describe('The version the update path leads to, when one is shown.'),
572
+ });
498
573
  export const UpdatesCheckSchema = z.looseObject({ disabled: z.boolean().optional(), cached: z.boolean().optional(), channel: z.string().optional(), agent_channel: z.enum(['stable', 'experimental']).optional(), checked_at: z.number().optional(), include_agent: z.boolean().optional(), webui: UpdateTargetSchema.nullable().optional(), agent: UpdateTargetSchema.nullable().optional() });
499
574
  export const UpdatesSummarySchema = z.looseObject({ summary: z.string().optional(), text: z.string().optional(), ok: z.boolean().optional(), error: z.string().optional(), diff_links: z.array(Json).optional() });
500
575
  export const UpdateApplySchema = z.looseObject({ ok: z.boolean().optional(), status: z.string().optional(), error: z.string().optional(), message: z.string().optional(), lock: Json.optional(), confirmation_required: z.boolean().optional(), candidate_revision: z.string().optional(), supported_revision: z.string().optional(), supported_version: z.string().optional(), agent_channel: z.enum(['stable', 'experimental']).optional(), notification_id: z.uuid().optional(), channel_switch: z.boolean().optional(), backup_dir: z.string().nullable().optional(), backup_failed: z.boolean().optional(), stash_conflict: z.boolean().optional() });
@@ -558,12 +633,12 @@ export const UpdateNotificationsSchema = z.object({
558
633
  });
559
634
  export const PluginSchema = z.looseObject({ key: z.string(), name: z.string().optional(), kind: z.string().optional(), enabled: z.boolean().optional(), description: z.string().optional(), version: z.string().optional(), activation: z.string().optional(), is_active_provider: z.boolean().optional(), hooks: z.array(Json).optional() });
560
635
  export const PluginsSchema = z.looseObject({ plugins: z.array(PluginSchema), empty: z.boolean().optional(), read_only: z.boolean().optional(), supported_hooks: z.array(z.string()).optional(), unavailable: z.boolean().optional() });
561
- export const McpServerSchema = z.looseObject({ name: z.string(), id: z.string().optional(), transport: z.string().optional(), enabled: z.boolean().optional(), active: z.boolean().optional(), status: z.string().optional(), tools: z.number().optional(), tool_count: z.number().int().nullable().optional(), health: z.string().optional(), health_detail: z.string().optional(), health_checked_at: Json.optional(), health_pending: z.boolean().optional() });
636
+ export const McpServerSchema = z.looseObject({ name: z.string(), id: z.string().optional(), transport: z.string().optional(), enabled: z.boolean().optional(), can_toggle: z.boolean().optional().describe('Whether PATCH can enable or disable this server; false for invalid config.'), active: z.boolean().optional(), status: z.string().optional(), tools: z.number().optional(), tool_count: z.number().int().nullable().optional(), health: z.string().optional(), health_detail: z.string().optional(), health_checked_at: Json.optional(), health_pending: z.boolean().optional() });
562
637
  export const McpServersSchema = z.looseObject({ servers: z.array(McpServerSchema), health_pending: z.boolean().optional(), reload_required: z.boolean().optional(), toggle_supported: z.boolean().optional() });
563
638
  export const McpToolsSchema = z.looseObject({ tools: z.array(z.looseObject({ name: z.string().optional(), server: z.string().optional(), description: z.string().optional() })), total: z.number().int().optional(), source: z.string().optional(), inventory_scope: z.string().optional(), unavailable_servers: z.array(z.string()).optional() });
564
639
  export const NotesSourcesSchema = z.looseObject({ enabled: z.boolean().optional(), sources: z.array(Json).optional(), source: z.string().optional(), inventory_scope: z.string().optional(), recent_ai_notes: z.array(Json).optional(), attach_supported: z.boolean().optional(), automatic_recall_unchanged: z.boolean().optional() });
565
640
  export const TodoItemSchema = z.looseObject({ id: z.union([z.string(), z.number()]).optional(), text: z.string().optional(), content: z.string().optional(), title: z.string().optional(), status: z.string().optional(), done: z.boolean().optional(), completed: z.boolean().optional() });
566
- export const TodoStateSchema = z.looseObject({ session_id: z.string().optional(), todos: z.array(TodoItemSchema).optional(), version: z.number().optional(), ts: z.number().optional(), source: z.string().optional(), description: z.string().optional(), pending_count: z.number().optional() });
641
+ export const TodoStateSchema = z.looseObject({ session_id: z.string().optional(), todos: z.array(TodoItemSchema).optional(), summary: z.record(z.string(), z.unknown()).optional(), version: z.number().optional(), ts: z.number().optional(), source: z.string().optional(), description: z.string().optional(), pending_count: z.number().optional() });
567
642
  // ── onboarding ───────────────────────────────────────────────────────────
568
643
  /** `oauth_flow` (TAL-398): `device_code` when the provider signs in through `/api/onboarding/oauth/*` instead of taking an API key; `oauth_label` then names the account to sign in with, and `signed_in` says whether the profile already holds its credential. */
569
644
  export const OnboardingProviderSchema = z.looseObject({ id: z.string(), name: z.string().optional(), label: z.string().optional(), kind: z.string().optional(), oauth: z.boolean().optional(), needs_key: z.boolean().optional(), base_url: NullableString.optional(), models: z.array(Json).optional(), category: z.string().optional(), default_model: z.string().optional(), oauth_flow: z.literal('device_code').nullable().optional(), oauth_label: z.string().optional(), signed_in: z.boolean().optional() });
@@ -614,10 +689,26 @@ export const CronRunSummarySchema = z.looseObject({ filename: z.string(), size:
614
689
  export const CronHistorySchema = z.looseObject({ job_id: z.string().optional(), runs: z.array(CronRunSummarySchema), total: z.number().optional(), offset: z.number().optional() });
615
690
  export const CronRunSchema = z.looseObject({ content: z.string().optional(), snippet: z.string().optional(), usage: CronRunUsageSchema.optional(), error: z.string().optional() });
616
691
  export const CronStatusSchema = z.looseObject({ running: z.union([z.boolean(), z.record(z.string(), z.number())]).optional() });
617
- export const KanbanTaskViewSchema = z.looseObject({ id: z.union([z.string(), z.number()]), title: z.string().optional(), status: z.string().optional(), assignee: NullableString.optional(), priority: z.union([z.string(), z.number()]).nullable().optional(), description: z.string().optional(), tags: z.array(z.string()).optional(), session_id: NullableString.optional(), archived: z.boolean().optional(), created_at: Json.optional(), updated_at: Json.optional() });
692
+ /** Card actions the server offers for a task's current status (TAL-557); clients show exactly these. `move_to` lists the statuses a Move may target, in display order. */
693
+ export const KanbanTaskActionsSchema = z.object({ block: z.boolean(), unblock: z.boolean(), complete: z.boolean(), archive: z.boolean(), move_to: z.array(z.string()) });
694
+ /** Server-computed card policy on every task the Kanban routes return (TAL-557). `requires_running_exit_confirmation`: any action takes the task out of a live run, so clients confirm first. */
695
+ export const KanbanTaskPolicyShape = { available_actions: KanbanTaskActionsSchema, requires_running_exit_confirmation: z.boolean() };
696
+ export const KanbanTaskViewSchema = z.looseObject({ id: z.union([z.string(), z.number()]), title: z.string().optional(), status: z.string().optional(), assignee: NullableString.optional(), priority: z.union([z.string(), z.number()]).nullable().optional(), description: z.string().optional(), tags: z.array(z.string()).optional(), session_id: NullableString.optional(), archived: z.boolean().optional(), created_at: Json.optional(), updated_at: Json.optional(), ...KanbanTaskPolicyShape });
618
697
  export const KanbanColumnSchema = z.looseObject({ name: z.string(), tasks: z.array(KanbanTaskViewSchema) });
619
- export const KanbanBoardViewSchema = z.looseObject({ columns: z.array(KanbanColumnSchema).optional(), assignees: z.array(Json).optional(), filters: Json.optional(), latest_event_id: z.number().optional(), read_only: z.boolean().optional(), tenants: z.array(Json).optional(), changed: z.boolean().optional() });
620
- export const KanbanBoardsViewSchema = z.looseObject({ boards: z.array(z.looseObject({ slug: z.string(), name: z.string().nullable().optional(), is_current: z.boolean().optional(), total: z.number().optional(), archived: z.boolean().optional(), color: z.string().optional(), icon: z.string().optional(), description: z.string().optional() })), current: z.string().optional(), read_only: z.boolean().optional() });
698
+ /** One profile lane (TAL-567): an assignee's tasks (`null` = unassigned) across every board column, with its task count. */
699
+ export const KanbanLaneSchema = z.object({ assignee: z.string().nullable(), count: z.number().int(), columns: z.array(KanbanColumnSchema) });
700
+ export const KanbanBoardViewSchema = z.looseObject({ columns: z.array(KanbanColumnSchema).optional(), assignees: z.array(Json).optional(), filters: Json.optional(), latest_event_id: z.number().optional(), read_only: z.boolean().optional(), tenants: z.array(Json).optional(), changed: z.boolean().optional(),
701
+ /** Statuses a bulk status change may target (TAL-557). */
702
+ bulk_move_targets: z.array(z.string()),
703
+ /** The saved board view (TAL-567): `true` groups the board into `lanes` by assignee. */
704
+ lane_by_profile: z.boolean(),
705
+ /** Present when `lane_by_profile`: the columns split into profile lanes, assignees in name order, unassigned last. */
706
+ lanes: z.array(KanbanLaneSchema).optional() });
707
+ export const KanbanBoardsViewSchema = z.looseObject({ boards: z.array(z.looseObject({ slug: z.string(), name: z.string().nullable().optional(), is_current: z.boolean().optional(), total: z.number().optional(), archived: z.boolean().optional(), color: z.string().optional(), icon: z.string().optional(), description: z.string().optional(),
708
+ /** Whether the board can be archived or deleted; the default board cannot (TAL-567). */
709
+ removable: z.boolean() })), current: z.string().optional(), read_only: z.boolean().optional() });
710
+ /** Board-wide task counts (TAL-567): `status_counts` in board-column order, unknown statuses after; `total` excludes archived tasks. */
711
+ export const KanbanStatsViewSchema = z.looseObject({ by_status: z.record(z.string(), z.number()), total: z.number().int(), status_counts: z.array(z.object({ status: z.string(), count: z.number().int() })) });
621
712
  export const ExtensionStatusSchema = z.looseObject({
622
713
  enabled: z.boolean(), extension_dir_configured: z.boolean().optional(), extension_dir_valid: z.boolean().optional(), script_urls: z.array(z.string()).optional(), stylesheet_urls: z.array(z.string()).optional(), sidecars: z.array(Json).optional(),
623
714
  extensions: z.array(z.looseObject({ id: z.string(), enabled: z.boolean().optional(), name: z.string().optional(), version: z.string().optional() })).optional(), warnings: z.array(Json).optional(),