@anchrd/colab-sdk 0.1.17 → 0.1.19

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.
@@ -8,6 +8,8 @@ export declare const DocumentCreateInput: z.ZodObject<{
8
8
  export type DocumentCreateInput = z.infer<typeof DocumentCreateInput>;
9
9
  export declare const DocumentGetInput: z.ZodObject<{
10
10
  documentId: z.ZodTemplateLiteral<`node_${string}`>;
11
+ cursor: z.ZodOptional<z.ZodString>;
12
+ known: z.ZodOptional<z.ZodPreprocess<z.ZodArray<z.ZodString>, unknown>>;
11
13
  }, z.core.$strict>;
12
14
  export type DocumentGetInput = z.infer<typeof DocumentGetInput>;
13
15
  export declare const DocumentUpdateInput: z.ZodObject<{
@@ -49,13 +51,68 @@ export declare const DocumentDetail: z.ZodObject<{
49
51
  appHandle: z.ZodNullable<z.ZodString>;
50
52
  rev: z.ZodNumber;
51
53
  archivedAt: z.ZodNullable<z.ZodISODateTime>;
52
- instructions: z.ZodOptional<z.ZodObject<{
54
+ instructions: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
53
55
  chain: z.ZodArray<z.ZodObject<{
54
56
  path: z.ZodString;
55
57
  status: z.ZodNullable<z.ZodString>;
56
58
  markdown: z.ZodString;
57
59
  }, z.core.$strip>>;
58
60
  hint: z.ZodOptional<z.ZodString>;
59
- }, z.core.$strip>>;
61
+ digest: z.ZodString;
62
+ }, z.core.$strip>, z.ZodObject<{
63
+ digest: z.ZodString;
64
+ known: z.ZodLiteral<true>;
65
+ }, z.core.$strip>]>>;
60
66
  }, z.core.$strip>;
61
67
  export type DocumentDetail = z.infer<typeof DocumentDetail>;
68
+ export declare const DocumentExcerpt: z.ZodObject<{
69
+ secret: z.ZodOptional<z.ZodLiteral<true>>;
70
+ locked: z.ZodOptional<z.ZodBoolean>;
71
+ documentId: z.ZodTemplateLiteral<`node_${string}`>;
72
+ name: z.ZodString;
73
+ hidden: z.ZodBoolean;
74
+ parentId: z.ZodNullable<z.ZodTemplateLiteral<`node_${string}`>>;
75
+ path: z.ZodObject<{
76
+ section: z.ZodEnum<{
77
+ users: "users";
78
+ own: "own";
79
+ shared: "shared";
80
+ }>;
81
+ items: z.ZodArray<z.ZodObject<{
82
+ nodeId: z.ZodTemplateLiteral<`node_${string}`>;
83
+ name: z.ZodString;
84
+ }, z.core.$strip>>;
85
+ }, z.core.$strip>;
86
+ content: z.ZodString;
87
+ version: z.ZodNullable<z.ZodNumber>;
88
+ savedAt: z.ZodNullable<z.ZodISODateTime>;
89
+ savedBy: z.ZodNullable<z.ZodObject<{
90
+ userId: z.ZodString;
91
+ name: z.ZodNullable<z.ZodString>;
92
+ kind: z.ZodNullable<z.ZodEnum<{
93
+ machine: "machine";
94
+ human: "human";
95
+ }>>;
96
+ }, z.core.$strip>>;
97
+ appHandle: z.ZodNullable<z.ZodString>;
98
+ archivedAt: z.ZodNullable<z.ZodISODateTime>;
99
+ instructions: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
100
+ chain: z.ZodArray<z.ZodObject<{
101
+ path: z.ZodString;
102
+ status: z.ZodNullable<z.ZodString>;
103
+ markdown: z.ZodString;
104
+ }, z.core.$strip>>;
105
+ hint: z.ZodOptional<z.ZodString>;
106
+ digest: z.ZodString;
107
+ }, z.core.$strip>, z.ZodObject<{
108
+ digest: z.ZodString;
109
+ known: z.ZodLiteral<true>;
110
+ }, z.core.$strip>]>>;
111
+ excerpt: z.ZodObject<{
112
+ offset: z.ZodNumber;
113
+ length: z.ZodNumber;
114
+ nextCursor: z.ZodNullable<z.ZodString>;
115
+ }, z.core.$strip>;
116
+ rev: z.ZodOptional<z.ZodNumber>;
117
+ }, z.core.$strip>;
118
+ export type DocumentExcerpt = z.infer<typeof DocumentExcerpt>;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
- import { Instructions } from "../instructions/instructions.js";
2
+ import { ExcerptCursor, TextExcerpt } from "../excerpt/excerpt.js";
3
+ import { InstructionsRead, Known } from "../instructions/instructions.js";
3
4
  import { NodeId, NodePath, NodePerson, SecretFields } from "../nodes/nodes.js";
4
5
  import { IdempotencyKey, Rev } from "../primitives/primitives.js";
5
6
  // Documents (#39, Nodes › Dokument, E36, E59): the inputs of `intelligence_document_create`, `_get`
@@ -22,7 +23,11 @@ export const DocumentCreateInput = z.strictObject({
22
23
  content: Content,
23
24
  idempotencyKey: IdempotencyKey,
24
25
  });
25
- export const DocumentGetInput = z.strictObject({ documentId: DocumentId });
26
+ export const DocumentGetInput = z.strictObject({
27
+ documentId: DocumentId,
28
+ cursor: ExcerptCursor.optional(),
29
+ known: Known.optional(),
30
+ });
26
31
  export const DocumentUpdateInput = z.strictObject({
27
32
  documentId: DocumentId,
28
33
  content: Content,
@@ -52,8 +57,17 @@ export const DocumentDetail = z.object({
52
57
  // The state the next save sends (E70).
53
58
  rev: z.number().int(),
54
59
  archivedAt: z.iso.datetime().nullable(),
55
- // Over MCP only, the INSTRUCTIONS of the document's folder (#39).
56
- instructions: Instructions.optional(),
60
+ // Over MCP only, the INSTRUCTIONS of the document's folder (#39); not again with a cursor (#674),
61
+ // the reference when known (E123, #677).
62
+ instructions: InstructionsRead.optional(),
57
63
  // A secret document (#357): `content` is empty while it is `locked` for this caller.
58
64
  ...SecretFields,
59
65
  });
66
+ // One excerpt of a document over MCP whose text is above `excerptChars` (E127, #674): `content` is
67
+ // this part, `excerpt` where it stands and the cursor of the next. ⚠️ `rev` comes with the last
68
+ // excerpt only: a save sends the whole text, and a `rev` beside a part of it would let a save of
69
+ // that part cut the rest away without a conflict.
70
+ export const DocumentExcerpt = DocumentDetail.extend({
71
+ excerpt: TextExcerpt,
72
+ rev: z.number().int().optional(),
73
+ });
@@ -11,18 +11,60 @@ export type ErrorCode = z.infer<typeof ErrorCode>;
11
11
  export declare const ErrorIssue: z.ZodObject<{
12
12
  path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
13
13
  message: z.ZodString;
14
+ expected: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
14
15
  }, z.core.$strict>;
15
16
  export type ErrorIssue = z.infer<typeof ErrorIssue>;
17
+ export declare const ErrorCurrent: z.ZodObject<{
18
+ taskId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
19
+ boardId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
20
+ documentId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
21
+ tableId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
22
+ fileId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
23
+ gadgetId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
24
+ nodeId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
25
+ machineId: z.ZodOptional<z.ZodTemplateLiteral<`user_${string}`>>;
26
+ rev: z.ZodNumber;
27
+ savedBy: z.ZodOptional<z.ZodObject<{
28
+ userId: z.ZodString;
29
+ name: z.ZodString;
30
+ }, z.core.$strict>>;
31
+ savedAt: z.ZodISODateTime;
32
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
33
+ }, z.core.$strict>;
34
+ export type ErrorCurrent = z.infer<typeof ErrorCurrent>;
16
35
  export declare const ErrorResponse: z.ZodObject<{
17
36
  error: z.ZodDiscriminatedUnion<[z.ZodObject<{
18
- code: z.ZodEnum<{
19
- invalid: "invalid";
20
- conflict: "conflict";
21
- }>;
37
+ code: z.ZodLiteral<"invalid">;
38
+ message: z.ZodString;
39
+ issues: z.ZodOptional<z.ZodArray<z.ZodObject<{
40
+ path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
41
+ message: z.ZodString;
42
+ expected: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
+ }, z.core.$strict>>>;
44
+ }, z.core.$strict>, z.ZodObject<{
45
+ code: z.ZodLiteral<"conflict">;
22
46
  message: z.ZodString;
23
47
  issues: z.ZodOptional<z.ZodArray<z.ZodObject<{
24
48
  path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
25
49
  message: z.ZodString;
50
+ expected: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
51
+ }, z.core.$strict>>>;
52
+ current: z.ZodOptional<z.ZodArray<z.ZodObject<{
53
+ taskId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
54
+ boardId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
55
+ documentId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
56
+ tableId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
57
+ fileId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
58
+ gadgetId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
59
+ nodeId: z.ZodOptional<z.ZodTemplateLiteral<`node_${string}`>>;
60
+ machineId: z.ZodOptional<z.ZodTemplateLiteral<`user_${string}`>>;
61
+ rev: z.ZodNumber;
62
+ savedBy: z.ZodOptional<z.ZodObject<{
63
+ userId: z.ZodString;
64
+ name: z.ZodString;
65
+ }, z.core.$strict>>;
66
+ savedAt: z.ZodISODateTime;
67
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
26
68
  }, z.core.$strict>>>;
27
69
  }, z.core.$strict>, z.ZodObject<{
28
70
  code: z.ZodEnum<{
@@ -34,9 +76,14 @@ export declare const ErrorResponse: z.ZodObject<{
34
76
  }, z.core.$strict>], "code">;
35
77
  }, z.core.$strict>;
36
78
  export type ErrorResponse = z.infer<typeof ErrorResponse>;
79
+ export declare function invalidInput(schema: z.ZodType, error: z.ZodError): ErrorResponse;
37
80
  export declare const Warning: z.ZodObject<{
38
81
  code: z.ZodEnum<{
39
82
  followup_failed: "followup_failed";
83
+ test_failed: "test_failed";
84
+ mail_failed: "mail_failed";
85
+ unused: "unused";
86
+ too_long: "too_long";
40
87
  }>;
41
88
  message: z.ZodString;
42
89
  }, z.core.$strip>;
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { idSchema } from "../ids/ids.js";
2
3
  // The one error shape of API and MCP (E68, E70). Missing rights answer `not_found`, never a code of
3
4
  // their own: a caller must not learn that something exists which it may not see.
4
5
  export const errorCodes = [
@@ -9,19 +10,50 @@ export const errorCodes = [
9
10
  "unavailable",
10
11
  ];
11
12
  export const ErrorCode = z.enum(errorCodes);
12
- // One entry per rejected field: where, and a sentence why.
13
+ // One entry per rejected field: where, and a sentence why. `expected` only where the tool's schema
14
+ // refused the input (#678): the form that field takes, the JSON Schema `tools/list` shows for it,
15
+ // derived from the schema and never written by hand, so the AI's next try needs no guess.
13
16
  export const ErrorIssue = z.strictObject({
14
17
  path: z.array(z.union([z.string(), z.number()])),
15
18
  message: z.string(),
19
+ expected: z.record(z.string(), z.unknown()).optional(),
20
+ });
21
+ const NodeRef = idSchema("node");
22
+ // What stands now where a save met a newer one (E128, #678), one entry per stale node: its `rev`,
23
+ // who saved it last (the author of its current version; absent for a kind without versions) and
24
+ // when, and under `values` today's value of exactly each field the call wanted to change, under the
25
+ // field's name in the call. Never a document's text: there the answer is to read it again. The id
26
+ // under its resource's name, as in `changed`; an Operator's under `machineId` (E135, #739). Nothing
27
+ // is merged and nothing overwritten (E70).
28
+ export const ErrorCurrent = z.strictObject({
29
+ taskId: NodeRef.optional(),
30
+ boardId: NodeRef.optional(),
31
+ documentId: NodeRef.optional(),
32
+ tableId: NodeRef.optional(),
33
+ fileId: NodeRef.optional(),
34
+ gadgetId: NodeRef.optional(),
35
+ nodeId: NodeRef.optional(),
36
+ machineId: idSchema("user").optional(),
37
+ rev: z.number().int(),
38
+ savedBy: z.strictObject({ userId: z.string(), name: z.string() }).optional(),
39
+ savedAt: z.iso.datetime(),
40
+ values: z.record(z.string(), z.unknown()).optional(),
16
41
  });
17
42
  // `issues` exists only next to `invalid` and `conflict` (a change of many entries names each stale
18
- // one, #630, #625); on every other code a strict object rejects it.
43
+ // one, #630, #625), `current` only next to `conflict` (E128); on every other code a strict object
44
+ // rejects them.
19
45
  export const ErrorResponse = z.strictObject({
20
46
  error: z.discriminatedUnion("code", [
21
47
  z.strictObject({
22
- code: z.enum(["invalid", "conflict"]),
48
+ code: z.literal("invalid"),
49
+ message: z.string(),
50
+ issues: z.array(ErrorIssue).optional(),
51
+ }),
52
+ z.strictObject({
53
+ code: z.literal("conflict"),
23
54
  message: z.string(),
24
55
  issues: z.array(ErrorIssue).optional(),
56
+ current: z.array(ErrorCurrent).optional(),
25
57
  }),
26
58
  z.strictObject({
27
59
  code: ErrorCode.exclude(["invalid", "conflict"]),
@@ -29,11 +61,114 @@ export const ErrorResponse = z.strictObject({
29
61
  }),
30
62
  ]),
31
63
  });
32
- // What a write answers beside its result when it went through and something stands out (E126): a
33
- // hint for the AI, never a refusal; a fixed code and a sentence. #623 brings the first code, #672
34
- // takes the field to every write over `/mcp` and adds its own.
35
- // - `followup_failed`: the change is saved, and a step after the save failed and was reported.
64
+ const isSchema = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
65
+ // A `$ref` of the converter (`#`, `#/definitions/…`, `#/$defs/…`), resolved against the root.
66
+ function resolved(node, root) {
67
+ const ref = node.$ref;
68
+ if (typeof ref !== "string" || !ref.startsWith("#"))
69
+ return node;
70
+ let found = root;
71
+ for (const part of ref.slice(1).split("/").filter(Boolean)) {
72
+ found = isSchema(found) ? found[part.replaceAll("~1", "/").replaceAll("~0", "~")] : undefined;
73
+ }
74
+ return isSchema(found) ? found : node;
75
+ }
76
+ // The alternatives a value may take at this place: a nullable or optional field is an `anyOf`.
77
+ function branches(node, root) {
78
+ const own = resolved(node, root);
79
+ const alternatives = [own.anyOf, own.oneOf, own.allOf].find(Array.isArray);
80
+ if (!alternatives)
81
+ return [own];
82
+ return alternatives.filter(isSchema).flatMap((branch) => branches(branch, root));
83
+ }
84
+ function child(node, part, root) {
85
+ for (const branch of branches(node, root)) {
86
+ if (typeof part === "number") {
87
+ if (Array.isArray(branch.items) && isSchema(branch.items[part]))
88
+ return branch.items[part];
89
+ if (isSchema(branch.items))
90
+ return branch.items;
91
+ if (Array.isArray(branch.prefixItems) && isSchema(branch.prefixItems[part])) {
92
+ return branch.prefixItems[part];
93
+ }
94
+ continue;
95
+ }
96
+ if (isSchema(branch.properties) && isSchema(branch.properties[part])) {
97
+ return branch.properties[part];
98
+ }
99
+ if (isSchema(branch.additionalProperties))
100
+ return branch.additionalProperties;
101
+ }
102
+ return undefined;
103
+ }
104
+ // The JSON Schema at a path of the input, as `tools/list` shows it (#678).
105
+ function schemaAt(root, path) {
106
+ let node = root;
107
+ for (const part of path) {
108
+ node = node && child(node, part, root);
109
+ }
110
+ if (!node)
111
+ return undefined;
112
+ const { $schema: _schema, ...shown } = resolved(node, root);
113
+ return shown;
114
+ }
115
+ // The fields an object at this place takes, to name beside a key it does not know.
116
+ function fieldsAt(root, path) {
117
+ const node = schemaAt(root, path);
118
+ if (!node)
119
+ return [];
120
+ return [
121
+ ...new Set(branches(node, root).flatMap((branch) => isSchema(branch.properties) ? Object.keys(branch.properties) : [])),
122
+ ];
123
+ }
124
+ // The options `@modelcontextprotocol/sdk` converts a tool's input with for `tools/list`.
125
+ function jsonSchemaOf(schema) {
126
+ try {
127
+ return z.toJSONSchema(schema, { target: "draft-7", io: "input" });
128
+ }
129
+ catch {
130
+ return null;
131
+ }
132
+ }
133
+ const dotted = (path) => path.length === 0 ? "its top level" : path.map(String).join(".");
134
+ // `invalid` for an input its tool's schema refused (#678), at `/api` and `/mcp` alike: each issue
135
+ // with the field's path, Zod's sentence and the form the field expects; a key the schema does not
136
+ // know names the fields that are there instead.
137
+ export function invalidInput(schema, error) {
138
+ const root = jsonSchemaOf(schema);
139
+ const issues = error.issues.map((issue) => {
140
+ const path = issue.path.map((part) => (typeof part === "symbol" ? String(part) : part));
141
+ if (issue.code === "unrecognized_keys") {
142
+ const fields = root ? fieldsAt(root, path) : [];
143
+ return {
144
+ path,
145
+ message: fields.length > 0
146
+ ? `${issue.message}; the fields here are ${fields.join(", ")}.`
147
+ : issue.message,
148
+ };
149
+ }
150
+ const expected = root ? schemaAt(root, path) : undefined;
151
+ return { path, message: issue.message, ...(expected && { expected }) };
152
+ });
153
+ const places = [...new Set(issues.map((issue) => dotted(issue.path)))];
154
+ return {
155
+ error: {
156
+ code: "invalid",
157
+ message: `The input does not match the schema at ${places.join(", ")}: issues name what each expects. Nothing was done.`,
158
+ issues,
159
+ },
160
+ };
161
+ }
162
+ // What a write answers beside what it changed when it went through and something stands out (E126,
163
+ // `Written`): a hint for the AI, never a refusal; a fixed code and a sentence.
164
+ // - `followup_failed`: the change is saved, and a step after the save failed and was reported
165
+ // (#623, #725); the answer holds only what the save itself knows.
166
+ // - `test_failed`: a credential or a connection was changed and then failed its test, with the
167
+ // provider's sentence (#743); the change stands.
168
+ // - `mail_failed`: the mail of an invitation was not accepted (#743); the invitation stands.
169
+ // - `unused`: a credential that no Operator uses yet (#676).
170
+ // - `too_long`: an INSTRUCTIONS was saved with more words than an AI follows reliably (E67, #675).
36
171
  export const Warning = z.object({
37
- code: z.enum(["followup_failed"]),
172
+ code: z.enum(["followup_failed", "test_failed", "mail_failed", "unused", "too_long"]),
38
173
  message: z.string(),
39
174
  });
@@ -13,6 +13,11 @@ export declare const ActorKind: z.ZodEnum<{
13
13
  human: "human";
14
14
  }>;
15
15
  export type ActorKind = z.infer<typeof ActorKind>;
16
+ export declare const EventSource: z.ZodEnum<{
17
+ mcp: "mcp";
18
+ api: "api";
19
+ }>;
20
+ export type EventSource = z.infer<typeof EventSource>;
16
21
  export declare const EventListInput: z.ZodObject<{
17
22
  actorId: z.ZodOptional<z.ZodUnion<readonly [z.ZodTemplateLiteral<`user_${string}`>, z.ZodTemplateLiteral<`service_${string}`>]>>;
18
23
  actorKind: z.ZodOptional<z.ZodEnum<{
@@ -62,7 +67,12 @@ export declare const Event: z.ZodObject<{
62
67
  human: "human";
63
68
  }>>;
64
69
  image: z.ZodNullable<z.ZodString>;
70
+ appHandle: z.ZodNullable<z.ZodString>;
65
71
  }, z.core.$strip>>;
72
+ source: z.ZodNullable<z.ZodEnum<{
73
+ mcp: "mcp";
74
+ api: "api";
75
+ }>>;
66
76
  failed: z.ZodBoolean;
67
77
  code: z.ZodNullable<z.ZodString>;
68
78
  ip: z.ZodNullable<z.ZodString>;
@@ -93,7 +103,12 @@ export declare const EventList: z.ZodObject<{
93
103
  human: "human";
94
104
  }>>;
95
105
  image: z.ZodNullable<z.ZodString>;
106
+ appHandle: z.ZodNullable<z.ZodString>;
96
107
  }, z.core.$strip>>;
108
+ source: z.ZodNullable<z.ZodEnum<{
109
+ mcp: "mcp";
110
+ api: "api";
111
+ }>>;
97
112
  failed: z.ZodBoolean;
98
113
  code: z.ZodNullable<z.ZodString>;
99
114
  ip: z.ZodNullable<z.ZodString>;
@@ -13,6 +13,8 @@ export const EventKind = z.enum(["change", "signin", "app", "connector"]);
13
13
  // Who did it: a person or a machine, or an outside service that declared its own interfaces under
14
14
  // `/auth/service` (#178).
15
15
  export const ActorKind = z.enum([...UserKind.options, "service"]);
16
+ // The doors of `ToolSource`, as a row of the protocol stores them (#738).
17
+ export const EventSource = z.enum(["api", "mcp"]);
16
18
  export const EventListInput = z.strictObject({
17
19
  // Who did it: a user, or a service for what it declared itself (#178).
18
20
  actorId: z.union([UserId, ServiceId]).optional(),
@@ -51,14 +53,22 @@ export const Event = z.object({
51
53
  // `access.directory.resolve` gives it: null for a machine, a service and a person without one
52
54
  // (#140). ⚠️ `userId` also carries a `service_…` id when `kind` is `service` (#178): the field
53
55
  // keeps its name so the answer's shape stays as the UI reads it.
56
+ // `appHandle` is the app a person's AI came through over `/mcp` (#738, E134), by its registered
57
+ // name like a chat's sender (E49), the stored client id where `access` no longer knows the client;
58
+ // null from the UI, for a machine's own token and for every row from before.
54
59
  actor: z
55
60
  .object({
56
61
  userId: z.string(),
57
62
  name: z.string().nullable(),
58
63
  kind: ActorKind.nullable(),
59
64
  image: z.string().nullable(),
65
+ appHandle: z.string().nullable(),
60
66
  })
61
67
  .nullable(),
68
+ // The door the event came through (#738, E134): `api` for `/api` and `/auth` (the UI, a sign-in, a
69
+ // service's own door), `mcp` for `/mcp`; null for what Colab does itself in a job and for every row
70
+ // from before.
71
+ source: EventSource.nullable(),
62
72
  failed: z.boolean(),
63
73
  // The refusal's code, only next to `failed`.
64
74
  code: z.string().nullable(),
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ export declare const excerptChars = 20000;
3
+ export declare const ExcerptCursor: z.ZodString;
4
+ export declare const TextExcerpt: z.ZodObject<{
5
+ offset: z.ZodNumber;
6
+ length: z.ZodNumber;
7
+ nextCursor: z.ZodNullable<z.ZodString>;
8
+ }, z.core.$strip>;
9
+ export type TextExcerpt = z.infer<typeof TextExcerpt>;
10
+ export declare const RowsExcerpt: z.ZodObject<{
11
+ firstRow: z.ZodNumber;
12
+ lastRow: z.ZodNumber;
13
+ rowCount: z.ZodNumber;
14
+ nextCursor: z.ZodNullable<z.ZodString>;
15
+ }, z.core.$strip>;
16
+ export type RowsExcerpt = z.infer<typeof RowsExcerpt>;
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ // Large texts over `/mcp` (E127, #674): the text of a document, a file or a table comes in excerpts of
3
+ // at most `excerptChars` characters, each with where it stands in the whole and a `cursor` for the
4
+ // next one, until everything is read. A text that fits comes whole, without `excerpt`. Nothing is cut
5
+ // at the end of an answer: a result cut off in the middle of its JSON is useless. Claude Code warns at
6
+ // 10,000 tokens of tool output and puts a text over 50,000 characters into a file the AI must read
7
+ // again; 20,000 characters are about 5,000 tokens.
8
+ export const excerptChars = 20_000;
9
+ // One cursor for every kind: the next excerpt of the same text, refused once the node has changed.
10
+ export const ExcerptCursor = z
11
+ .string()
12
+ .min(1)
13
+ .max(500)
14
+ .describe("The nextCursor of the previous excerpt, unchanged, for the next part of the same text. If the node was saved in between, the answer is conflict: read it again without cursor.");
15
+ // Where an excerpt of a document's Markdown or a file's text stands, in characters.
16
+ export const TextExcerpt = z.object({
17
+ // The characters of the whole text before this excerpt.
18
+ offset: z.number().int(),
19
+ // The characters of the whole text.
20
+ length: z.number().int(),
21
+ // Null with the last excerpt.
22
+ nextCursor: z.string().nullable(),
23
+ });
24
+ // Where an excerpt of a table stands: whole rows, never a row cut in two; the CSV's header line comes
25
+ // with the first excerpt only, so the excerpts joined are the table's CSV.
26
+ export const RowsExcerpt = z.object({
27
+ // The positions of the first and the last row in this excerpt, 1 for the first data row.
28
+ firstRow: z.number().int(),
29
+ lastRow: z.number().int(),
30
+ // The data rows of the whole table.
31
+ rowCount: z.number().int(),
32
+ nextCursor: z.string().nullable(),
33
+ });
@@ -27,6 +27,7 @@ export declare const FileUpdateInput: z.ZodObject<{
27
27
  export type FileUpdateInput = z.infer<typeof FileUpdateInput>;
28
28
  export declare const FileGetInput: z.ZodObject<{
29
29
  fileId: z.ZodTemplateLiteral<`node_${string}`>;
30
+ cursor: z.ZodOptional<z.ZodString>;
30
31
  }, z.core.$strict>;
31
32
  export type FileGetInput = z.infer<typeof FileGetInput>;
32
33
  export declare const UploadTicket: z.ZodObject<{
@@ -71,6 +72,11 @@ export declare const FileDetail: z.ZodObject<{
71
72
  reading: "reading";
72
73
  none: "none";
73
74
  }>;
75
+ excerpt: z.ZodOptional<z.ZodObject<{
76
+ offset: z.ZodNumber;
77
+ length: z.ZodNumber;
78
+ nextCursor: z.ZodNullable<z.ZodString>;
79
+ }, z.core.$strip>>;
74
80
  contentUrl: z.ZodURL;
75
81
  sourceUrl: z.ZodOptional<z.ZodString>;
76
82
  fetchedAt: z.ZodOptional<z.ZodISODateTime>;
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { ExcerptCursor, TextExcerpt } from "../excerpt/excerpt.js";
2
3
  import { idSchema } from "../ids/ids.js";
3
4
  import { NodeId } from "../nodes/nodes.js";
4
5
  import { IdempotencyKey, Rev } from "../primitives/primitives.js";
@@ -142,7 +143,7 @@ export const FileUpdateInput = z.strictObject({
142
143
  size: Size,
143
144
  rev: Rev,
144
145
  });
145
- export const FileGetInput = z.strictObject({ fileId: FileId });
146
+ export const FileGetInput = z.strictObject({ fileId: FileId, cursor: ExcerptCursor.optional() });
146
147
  // What `_create` and `_update` answer: the door, the ticket and the whole command. ⚠️ `ticket` is a
147
148
  // credential, and it is in this answer on purpose: it opens ONE upload for ONE person for fifteen
148
149
  // minutes. It appears nowhere else, never in an error and never in a log.
@@ -173,8 +174,11 @@ export const FileDetail = z.object({
173
174
  // The node's revision, to send with the next `_update`.
174
175
  rev: z.number().int(),
175
176
  // The text read from the current version for search and AI; null unless `textState` is `done`.
177
+ // Over MCP a text above `excerptChars` comes in excerpts (E127, #674): then this is one of them.
176
178
  text: z.string().nullable(),
177
179
  textState: FileTextState,
180
+ // Over MCP only, when the text comes in excerpts: where this one stands, and the cursor of the next.
181
+ excerpt: TextExcerpt.optional(),
178
182
  // Where the bytes are read, with a session or a token and the right to read the file.
179
183
  contentUrl: z.url(),
180
184
  // Only on a version Colab fetched from an address (#556): the address asked for and when.
@@ -17,3 +17,39 @@ export declare const Instructions: z.ZodObject<{
17
17
  hint: z.ZodOptional<z.ZodString>;
18
18
  }, z.core.$strip>;
19
19
  export type Instructions = z.infer<typeof Instructions>;
20
+ export declare const Digest: z.ZodString;
21
+ export type Digest = z.infer<typeof Digest>;
22
+ export declare const maxKnown = 100;
23
+ export declare const Known: z.ZodPreprocess<z.ZodArray<z.ZodString>, unknown>;
24
+ export declare const KnownText: z.ZodObject<{
25
+ digest: z.ZodString;
26
+ known: z.ZodLiteral<true>;
27
+ }, z.core.$strip>;
28
+ export type KnownText = z.infer<typeof KnownText>;
29
+ export declare function isKnownText(value: object): value is KnownText;
30
+ export declare const InstructionText: z.ZodObject<{
31
+ digest: z.ZodString;
32
+ markdown: z.ZodString;
33
+ }, z.core.$strip>;
34
+ export type InstructionText = z.infer<typeof InstructionText>;
35
+ export declare const InstructionRead: z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
36
+ digest: z.ZodString;
37
+ markdown: z.ZodString;
38
+ }, z.core.$strip>, z.ZodObject<{
39
+ digest: z.ZodString;
40
+ known: z.ZodLiteral<true>;
41
+ }, z.core.$strip>]>>;
42
+ export type InstructionRead = z.infer<typeof InstructionRead>;
43
+ export declare const InstructionsRead: z.ZodUnion<readonly [z.ZodObject<{
44
+ chain: z.ZodArray<z.ZodObject<{
45
+ path: z.ZodString;
46
+ status: z.ZodNullable<z.ZodString>;
47
+ markdown: z.ZodString;
48
+ }, z.core.$strip>>;
49
+ hint: z.ZodOptional<z.ZodString>;
50
+ digest: z.ZodString;
51
+ }, z.core.$strip>, z.ZodObject<{
52
+ digest: z.ZodString;
53
+ known: z.ZodLiteral<true>;
54
+ }, z.core.$strip>]>;
55
+ export type InstructionsRead = z.infer<typeof InstructionsRead>;
@@ -33,3 +33,32 @@ export const Instructions = z.object({
33
33
  // Only when the whole chain holds more than 3,000 words (E67): one English sentence.
34
34
  hint: z.string().optional(),
35
35
  });
36
+ // E123 (#677): a board's instruction and the INSTRUCTIONS come along over MCP only when the AI does
37
+ // not hold them in this version yet. Their version is `digest`: the first 16 hex characters of the
38
+ // SHA-256 of what the answer would carry, so it names the text as the caller gets it. The same
39
+ // text has the same digest wherever it stands; a changed text, status or path, or another cut of a
40
+ // machine's part, has a new one. ⚠️ Colab keeps nothing of what an AI got, because a client may
41
+ // compact its context or start anew: the AI sends what it holds under `known`, and without it every
42
+ // text comes whole. The system message of an Operator's run (E111) asks without `known`.
43
+ export const Digest = z
44
+ .string()
45
+ .regex(/^[0-9a-f]{16}$/)
46
+ .describe("The digest of an instruction or of INSTRUCTIONS, as an earlier read named it.");
47
+ // The most digests one read takes: one per board and folder an AI works in, with room to spare.
48
+ export const maxKnown = 100;
49
+ // Over REST one comma-separated value (`?known=…,…`): a query string carries text. No lower bound:
50
+ // an empty list holds nothing and means the same as leaving it out.
51
+ export const Known = z
52
+ .preprocess((value) => (typeof value === "string" ? value.split(",") : value), z.array(Digest).max(maxKnown))
53
+ .describe("The digests of the instruction and INSTRUCTIONS whose text you still hold from an earlier read, as that read named them under digest. Where one still matches, the answer carries only { digest, known: true } in place of the text; a changed text comes whole with its new digest. Leave out what is no longer in your context. Leaving it out gives every text whole.");
54
+ // What stands in place of the text when the caller sent its digest under `known`.
55
+ export const KnownText = z.object({ digest: Digest, known: z.literal(true) });
56
+ export function isKnownText(value) {
57
+ return "known" in value;
58
+ }
59
+ // A board's instruction over MCP (E87, #354): its Markdown with its digest.
60
+ export const InstructionText = z.object({ digest: Digest, markdown: z.string() });
61
+ // The instruction as a read over MCP answers it: the text, the reference, or null without one.
62
+ export const InstructionRead = z.union([InstructionText, KnownText]).nullable();
63
+ // The chain as a read over MCP answers it: whole with its digest, or the reference.
64
+ export const InstructionsRead = z.union([Instructions.extend({ digest: Digest }), KnownText]);