@otto-code/protocol 0.7.0 → 0.7.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.
package/dist/messages.js CHANGED
@@ -432,6 +432,13 @@ export const MutableDaemonConfigSchema = z
432
432
  // Defaults false so a new client parsing an old daemon's config keeps the
433
433
  // action visible. Gated by server_info features.hideMergeIntoBaseSetting.
434
434
  hideMergeIntoBaseAction: z.boolean().default(false),
435
+ // Retention for the images agents produce (docs/attachment-lifecycle.md).
436
+ // Host-level, because the store they govern is the daemon's. Defaults match
437
+ // the constants the daemon shipped with, so a client parsing an old daemon's
438
+ // config sees the policy actually in force rather than zeros. 0 on either
439
+ // disables that lever. Gated by server_info features.attachmentStorage.
440
+ attachmentImageMaxAgeDays: z.number().int().min(0).default(30),
441
+ attachmentImageMaxTotalMb: z.number().int().min(0).default(512),
435
442
  enableTerminalAgentHooks: z.boolean().default(false),
436
443
  appendSystemPrompt: z.string().default(""),
437
444
  terminalProfiles: z.array(TerminalProfileSchema).optional(),
@@ -492,6 +499,9 @@ export const MutableDaemonConfigPatchSchema = z
492
499
  autoArchiveAfterMerge: z.boolean().optional(),
493
500
  // Gated by server_info features.hideMergeIntoBaseSetting.
494
501
  hideMergeIntoBaseAction: z.boolean().optional(),
502
+ // Gated by server_info features.attachmentStorage.
503
+ attachmentImageMaxAgeDays: z.number().int().min(0).optional(),
504
+ attachmentImageMaxTotalMb: z.number().int().min(0).optional(),
495
505
  enableTerminalAgentHooks: z.boolean().optional(),
496
506
  appendSystemPrompt: z.string().optional(),
497
507
  terminalProfiles: z.array(TerminalProfileSchema).optional(),
@@ -1251,6 +1261,58 @@ export const UpdateAgentRequestMessageSchema = z.object({
1251
1261
  labels: z.record(z.string(), z.string()).optional(),
1252
1262
  requestId: z.string(),
1253
1263
  });
1264
+ // ── Attachment storage ──────────────────────────────────────────────────────
1265
+ // Agents produce image bytes continuously (browser screenshots above all), and
1266
+ // the daemon materializes each one to $OTTO_HOME/attachments so the timeline has
1267
+ // a file to point at. These two RPCs are the user's window into that store: how
1268
+ // much is there, and give it back. See docs/attachment-lifecycle.md.
1269
+ //
1270
+ // Scope is deliberately global, not per-chat or per-workspace. Filenames are a
1271
+ // content hash, so the same bytes may be referenced from several transcripts and
1272
+ // "this workspace's images" is a fiction we would have to invent and maintain.
1273
+ // Gated by server_info.features.attachmentStorage.
1274
+ export const AttachmentsImagesStatsRequestSchema = z.object({
1275
+ type: z.literal("attachments.images.get_stats.request"),
1276
+ requestId: z.string(),
1277
+ });
1278
+ export const AttachmentsImagesStatsResponseSchema = z.object({
1279
+ type: z.literal("attachments.images.get_stats.response"),
1280
+ payload: z.object({
1281
+ fileCount: z.number().int().nonnegative(),
1282
+ totalBytes: z.number().nonnegative(),
1283
+ // ISO timestamp of the oldest image, or null when the store is empty. The
1284
+ // readout quotes it so "512 MB" comes with "since March".
1285
+ oldestAt: z.string().nullable(),
1286
+ // The policy currently in force, so the settings row shows real numbers
1287
+ // rather than the client's idea of the defaults.
1288
+ maxAgeDays: z.number().int().nonnegative(),
1289
+ maxTotalMb: z.number().int().nonnegative(),
1290
+ error: z.string().nullable(),
1291
+ requestId: z.string(),
1292
+ }),
1293
+ });
1294
+ export const AttachmentsImagesClearRequestSchema = z.object({
1295
+ type: z.literal("attachments.images.clear.request"),
1296
+ // 0 = every stored image. N = only images untouched for at least N days.
1297
+ olderThanDays: z.number().int().min(0).default(0),
1298
+ // Safe by default: a request that omits the flag previews instead of deleting.
1299
+ // The client always sends it explicitly. Same contract as
1300
+ // history.agents.clear_archived, and for the same reason — the client cannot
1301
+ // enumerate the set, and there is no undo.
1302
+ dryRun: z.boolean().default(true),
1303
+ requestId: z.string(),
1304
+ });
1305
+ export const AttachmentsImagesClearResponseSchema = z.object({
1306
+ type: z.literal("attachments.images.clear.response"),
1307
+ payload: z.object({
1308
+ matched: z.number().int().nonnegative(),
1309
+ deleted: z.number().int().nonnegative(),
1310
+ freedBytes: z.number().nonnegative(),
1311
+ dryRun: z.boolean(),
1312
+ error: z.string().nullable(),
1313
+ requestId: z.string(),
1314
+ }),
1315
+ });
1254
1316
  export const ProjectRenameRequestSchema = z.object({
1255
1317
  type: z.literal("project.rename.request"),
1256
1318
  projectId: z.string(),
@@ -1970,6 +2032,13 @@ export const ImportAgentRequestMessageSchema = z.object({
1970
2032
  sessionId: z.string().optional(),
1971
2033
  providerHandleId: z.string().optional(),
1972
2034
  cwd: z.string().optional(),
2035
+ // The workspace the import was requested from. Present when the client has a
2036
+ // workspace context (a chat tab); absent from the home screen, where the
2037
+ // daemon resolves a workspace for the cwd instead.
2038
+ // COMPAT(importAgentWorkspaceId): added in v0.7.1, drop the optionality when
2039
+ // the floor is >= v0.7.1. An older client omits it and keeps the
2040
+ // resolve-by-directory behaviour.
2041
+ workspaceId: z.string().optional(),
1973
2042
  labels: z.record(z.string(), z.string()).optional(),
1974
2043
  requestId: z.string(),
1975
2044
  });
@@ -2196,6 +2265,16 @@ export const ContextCategorySchema = z.enum([
2196
2265
  export const ContextCostClassSchema = z.enum(["fixed", "conditional", "referenced"]);
2197
2266
  export const ContextSeveritySchema = z.enum(["ok", "notice", "warn", "critical"]);
2198
2267
  export const ContextConfidenceSchema = z.enum(["exact", "convention", "unverified"]);
2268
+ // Per-category disclosure of how well the daemon can see a provider's payload.
2269
+ // `not_visible` is the reason this exists: a CLI-backed provider composes its
2270
+ // own preset and hands MCP servers to a subprocess, so those categories are
2271
+ // unmeasurable rather than empty, and the row has to be able to say which.
2272
+ export const ContextCategoryVisibilitySchema = z.enum([
2273
+ "exact",
2274
+ "convention",
2275
+ "unverified",
2276
+ "not_visible",
2277
+ ]);
2199
2278
  export const ContextFindingKindSchema = z.enum([
2200
2279
  "dead_import",
2201
2280
  "dead_reference",
@@ -2265,6 +2344,10 @@ export const ContextCategoryTotalSchema = z.object({
2265
2344
  estTokens: z.number(),
2266
2345
  sharePercent: z.number(),
2267
2346
  severity: ContextSeveritySchema,
2347
+ // COMPAT(contextCategoryVisibility): added in v0.7.1, drop the optionality
2348
+ // when the floor is >= v0.7.1. An older client ignores the field and still
2349
+ // gets correct totals; a newer client seeing it absent renders no badge.
2350
+ visibility: ContextCategoryVisibilitySchema.optional(),
2268
2351
  });
2269
2352
  export const ContextReportSchema = z.object({
2270
2353
  workspaceId: z.string(),
@@ -2325,6 +2408,43 @@ export const ContextReportGetResponseMessageSchema = z.object({
2325
2408
  report: ContextReportSchema.nullable(),
2326
2409
  }),
2327
2410
  });
2411
+ // One readable block of the assembled prompt. `text` is absent exactly when
2412
+ // `visibility` is "not_visible" — the provider composes that part internally and
2413
+ // Otto has nothing to show, which the section states rather than hides.
2414
+ export const ContextPromptSectionSchema = z.object({
2415
+ category: ContextCategorySchema,
2416
+ label: z.string(),
2417
+ visibility: ContextCategoryVisibilitySchema,
2418
+ text: z.string().optional(),
2419
+ estTokens: z.number(),
2420
+ });
2421
+ export const ContextPromptPreviewSchema = z.object({
2422
+ sections: z.array(ContextPromptSectionSchema),
2423
+ estTokens: z.number(),
2424
+ });
2425
+ // Read-only by design: there is no matching write RPC. Editing happens per file
2426
+ // through the existing file pane, against the real file rather than a
2427
+ // concatenation of several.
2428
+ export const ContextPromptPreviewGetRequestMessageSchema = z.object({
2429
+ type: z.literal("context.prompt.preview.get.request"),
2430
+ requestId: z.string(),
2431
+ workspaceId: z.string(),
2432
+ provider: z.string().optional(),
2433
+ windowTokens: z.number().optional(),
2434
+ personalityId: z.string().optional(),
2435
+ // Assemble only this category. The tab reads one section at a time — the user
2436
+ // clicked a row in the tree — and assembling the rest would re-read every
2437
+ // context file on disk to build text nobody asked to see. Omitted means all,
2438
+ // which is what an older client sends.
2439
+ category: ContextCategorySchema.optional(),
2440
+ });
2441
+ export const ContextPromptPreviewGetResponseMessageSchema = z.object({
2442
+ type: z.literal("context.prompt.preview.get.response"),
2443
+ payload: z.object({
2444
+ requestId: z.string(),
2445
+ preview: ContextPromptPreviewSchema.nullable(),
2446
+ }),
2447
+ });
2328
2448
  // Converts one edge between "always loaded" and "link only". Server-side
2329
2449
  // because the parent file may live outside the workspace root.
2330
2450
  export const ContextEdgeConvertRequestMessageSchema = z.object({
@@ -4108,6 +4228,8 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
4108
4228
  ArchiveAgentRequestMessageSchema,
4109
4229
  CloseItemsRequestMessageSchema,
4110
4230
  HistoryAgentsClearArchivedRequestSchema,
4231
+ AttachmentsImagesStatsRequestSchema,
4232
+ AttachmentsImagesClearRequestSchema,
4111
4233
  UpdateAgentRequestMessageSchema,
4112
4234
  ProjectRenameRequestSchema,
4113
4235
  ProjectRemoveRequestSchema,
@@ -4146,6 +4268,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
4146
4268
  ProviderUsageListRequestMessageSchema,
4147
4269
  StatsActivityGetRequestMessageSchema,
4148
4270
  ContextReportGetRequestMessageSchema,
4271
+ ContextPromptPreviewGetRequestMessageSchema,
4149
4272
  ContextEdgeConvertRequestMessageSchema,
4150
4273
  ContextFindingsFixRequestMessageSchema,
4151
4274
  PersonalityMemoryListRequestMessageSchema,
@@ -4721,6 +4844,14 @@ export const ServerInfoStatusPayloadSchema = z
4721
4844
  // There is no client-side substitute (the client never touches the
4722
4845
  // filesystem), so an old daemon simply does not get the menu items.
4723
4846
  fileMutations: z.boolean().optional(),
4847
+ // COMPAT(attachmentStorage): added in v0.7.1, drop the gate when daemon floor >= v0.7.1.
4848
+ // Set when the daemon serves `attachments.images.get_stats` and
4849
+ // `attachments.images.clear` — the readout and reclaim for the images it
4850
+ // materializes on the agent's behalf. The client has no way to size or
4851
+ // clear a directory on the host, so an old daemon simply does not get
4852
+ // the daemon half of the Storage section; the app-side preview cache row
4853
+ // is local and always shown.
4854
+ attachmentStorage: z.boolean().optional(),
4724
4855
  })
4725
4856
  .optional(),
4726
4857
  })
@@ -7842,6 +7973,8 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
7842
7973
  AgentPermissionResolvedMessageSchema,
7843
7974
  AgentDeletedMessageSchema,
7844
7975
  HistoryAgentsClearArchivedResponseSchema,
7976
+ AttachmentsImagesStatsResponseSchema,
7977
+ AttachmentsImagesClearResponseSchema,
7845
7978
  AgentArchivedMessageSchema,
7846
7979
  CloseItemsResponseSchema,
7847
7980
  CheckoutStatusResponseSchema,
@@ -7947,6 +8080,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
7947
8080
  ProviderUsageListResponseMessageSchema,
7948
8081
  StatsActivityGetResponseMessageSchema,
7949
8082
  ContextReportGetResponseMessageSchema,
8083
+ ContextPromptPreviewGetResponseMessageSchema,
7950
8084
  ContextEdgeConvertResponseMessageSchema,
7951
8085
  ContextFindingsFixResponseMessageSchema,
7952
8086
  PersonalityMemoryListResponseMessageSchema,
@@ -24,17 +24,24 @@ export const KNOWN_MODEL_TIERS = {
24
24
  // Opus variants are "deep", non-1M Opus and Sonnet are "standard", Haiku is
25
25
  // "fast". Fable (1M, most powerful) is "deep".
26
26
  "claude-fable-5": "deep",
27
+ // Opus 4.7/4.8/5 are natively 1M, so the plain ids are "deep" and the manifest
28
+ // ships no `[1m]` row for them. The decorated ids stay mapped here because the
29
+ // CLI still accepts them and a user's settings.json or an older agent record
30
+ // may carry one.
27
31
  "claude-opus-5[1m]": "deep",
28
- "claude-opus-5": "standard",
32
+ "claude-opus-5": "deep",
29
33
  "claude-opus-4-8[1m]": "deep",
30
- "claude-opus-4-8": "standard",
34
+ "claude-opus-4-8": "deep",
31
35
  "claude-opus-4-7[1m]": "deep",
32
- "claude-opus-4-7": "standard",
36
+ "claude-opus-4-7": "deep",
33
37
  "claude-opus-4-6[1m]": "deep",
34
38
  "claude-opus-4-6": "standard",
39
+ "claude-opus-4-5": "standard",
35
40
  "claude-sonnet-5": "standard",
36
41
  "claude-sonnet-4-6[1m]": "standard",
37
42
  "claude-sonnet-4-6": "standard",
43
+ "claude-sonnet-4-5[1m]": "standard",
44
+ "claude-sonnet-4-5": "standard",
38
45
  "claude-haiku-4-5": "fast",
39
46
  "claude-haiku-4-5-20251001": "fast",
40
47
  // OpenAI (GPT / o-series)
@@ -4118,6 +4118,8 @@ export declare const WSOutboundMessageSchema: {
4118
4118
  }, import("zod/v4/core").$loose>>;
4119
4119
  autoArchiveAfterMerge: import("zod").ZodDefault<import("zod").ZodBoolean>;
4120
4120
  hideMergeIntoBaseAction: import("zod").ZodDefault<import("zod").ZodBoolean>;
4121
+ attachmentImageMaxAgeDays: import("zod").ZodDefault<import("zod").ZodNumber>;
4122
+ attachmentImageMaxTotalMb: import("zod").ZodDefault<import("zod").ZodNumber>;
4121
4123
  enableTerminalAgentHooks: import("zod").ZodDefault<import("zod").ZodBoolean>;
4122
4124
  appendSystemPrompt: import("zod").ZodDefault<import("zod").ZodString>;
4123
4125
  terminalProfiles: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
@@ -4290,6 +4292,8 @@ export declare const WSOutboundMessageSchema: {
4290
4292
  }, import("zod/v4/core").$loose>>;
4291
4293
  autoArchiveAfterMerge: import("zod").ZodDefault<import("zod").ZodBoolean>;
4292
4294
  hideMergeIntoBaseAction: import("zod").ZodDefault<import("zod").ZodBoolean>;
4295
+ attachmentImageMaxAgeDays: import("zod").ZodDefault<import("zod").ZodNumber>;
4296
+ attachmentImageMaxTotalMb: import("zod").ZodDefault<import("zod").ZodNumber>;
4293
4297
  enableTerminalAgentHooks: import("zod").ZodDefault<import("zod").ZodBoolean>;
4294
4298
  appendSystemPrompt: import("zod").ZodDefault<import("zod").ZodString>;
4295
4299
  terminalProfiles: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
@@ -4851,6 +4855,12 @@ export declare const WSOutboundMessageSchema: {
4851
4855
  warn: "warn";
4852
4856
  critical: "critical";
4853
4857
  }>;
4858
+ visibility: import("zod").ZodOptional<import("zod").ZodEnum<{
4859
+ exact: "exact";
4860
+ convention: "convention";
4861
+ unverified: "unverified";
4862
+ not_visible: "not_visible";
4863
+ }>>;
4854
4864
  }, import("zod/v4/core").$strip>>;
4855
4865
  fixedTotal: import("zod").ZodNumber;
4856
4866
  conditionalTotal: import("zod").ZodNumber;
@@ -5133,6 +5143,27 @@ export declare const WSOutboundMessageSchema: {
5133
5143
  error: import("zod").ZodNullable<import("zod").ZodString>;
5134
5144
  requestId: import("zod").ZodString;
5135
5145
  }, import("zod/v4/core").$strip>;
5146
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
5147
+ type: import("zod").ZodLiteral<"attachments.images.get_stats.response">;
5148
+ payload: import("zod").ZodObject<{
5149
+ fileCount: import("zod").ZodNumber;
5150
+ totalBytes: import("zod").ZodNumber;
5151
+ oldestAt: import("zod").ZodNullable<import("zod").ZodString>;
5152
+ maxAgeDays: import("zod").ZodNumber;
5153
+ maxTotalMb: import("zod").ZodNumber;
5154
+ error: import("zod").ZodNullable<import("zod").ZodString>;
5155
+ requestId: import("zod").ZodString;
5156
+ }, import("zod/v4/core").$strip>;
5157
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
5158
+ type: import("zod").ZodLiteral<"attachments.images.clear.response">;
5159
+ payload: import("zod").ZodObject<{
5160
+ matched: import("zod").ZodNumber;
5161
+ deleted: import("zod").ZodNumber;
5162
+ freedBytes: import("zod").ZodNumber;
5163
+ dryRun: import("zod").ZodBoolean;
5164
+ error: import("zod").ZodNullable<import("zod").ZodString>;
5165
+ requestId: import("zod").ZodString;
5166
+ }, import("zod/v4/core").$strip>;
5136
5167
  }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
5137
5168
  type: import("zod").ZodLiteral<"agent_archived">;
5138
5169
  payload: import("zod").ZodObject<{
@@ -8346,6 +8377,12 @@ export declare const WSOutboundMessageSchema: {
8346
8377
  warn: "warn";
8347
8378
  critical: "critical";
8348
8379
  }>;
8380
+ visibility: import("zod").ZodOptional<import("zod").ZodEnum<{
8381
+ exact: "exact";
8382
+ convention: "convention";
8383
+ unverified: "unverified";
8384
+ not_visible: "not_visible";
8385
+ }>>;
8349
8386
  }, import("zod/v4/core").$strip>>;
8350
8387
  fixedTotal: import("zod").ZodNumber;
8351
8388
  conditionalTotal: import("zod").ZodNumber;
@@ -8383,6 +8420,33 @@ export declare const WSOutboundMessageSchema: {
8383
8420
  personalityMemoryTokens: import("zod").ZodOptional<import("zod").ZodNumber>;
8384
8421
  }, import("zod/v4/core").$strip>>;
8385
8422
  }, import("zod/v4/core").$strip>;
8423
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
8424
+ type: import("zod").ZodLiteral<"context.prompt.preview.get.response">;
8425
+ payload: import("zod").ZodObject<{
8426
+ requestId: import("zod").ZodString;
8427
+ preview: import("zod").ZodNullable<import("zod").ZodObject<{
8428
+ sections: import("zod").ZodArray<import("zod").ZodObject<{
8429
+ category: import("zod").ZodEnum<{
8430
+ context_files: "context_files";
8431
+ memory_index: "memory_index";
8432
+ skills_roster: "skills_roster";
8433
+ mcp_tools: "mcp_tools";
8434
+ otto_injected: "otto_injected";
8435
+ system_prompt: "system_prompt";
8436
+ }>;
8437
+ label: import("zod").ZodString;
8438
+ visibility: import("zod").ZodEnum<{
8439
+ exact: "exact";
8440
+ convention: "convention";
8441
+ unverified: "unverified";
8442
+ not_visible: "not_visible";
8443
+ }>;
8444
+ text: import("zod").ZodOptional<import("zod").ZodString>;
8445
+ estTokens: import("zod").ZodNumber;
8446
+ }, import("zod/v4/core").$strip>>;
8447
+ estTokens: import("zod").ZodNumber;
8448
+ }, import("zod/v4/core").$strip>>;
8449
+ }, import("zod/v4/core").$strip>;
8386
8450
  }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
8387
8451
  type: import("zod").ZodLiteral<"context.edge.convert.response">;
8388
8452
  payload: import("zod").ZodObject<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-code/protocol",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Otto shared protocol schemas and wire types",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "files": [