@camox/api-contract 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics.d.ts +19 -0
- package/dist/analytics.js +18 -0
- package/dist/drafts.d.ts +82 -0
- package/dist/drafts.js +145 -0
- package/dist/icon-catalog.d.ts +7 -0
- package/dist/icon-catalog.js +48 -0
- package/dist/icons-BAxwOBBX.d.ts +19 -0
- package/dist/icons-Bk4igP2j.js +15 -0
- package/dist/ids.d.ts +26 -0
- package/dist/ids.js +40 -0
- package/dist/index.d.ts +12359 -7641
- package/dist/index.js +70 -0
- package/dist/projects.d.ts +28 -0
- package/dist/projects.js +50 -0
- package/dist/query-keys.d.ts +58 -38
- package/dist/query-keys.js +118 -28
- package/dist/threads.d.ts +277 -0
- package/dist/threads.js +263 -0
- package/package.json +57 -5
- package/src/analytics.ts +22 -0
- package/src/artifact.ts +38 -0
- package/src/drafts.ts +197 -0
- package/src/icon-catalog.ts +60 -0
- package/src/icons.ts +27 -0
- package/src/ids.ts +43 -0
- package/src/index.ts +6 -0
- package/src/projects.ts +67 -0
- package/src/query-keys.ts +65 -27
- package/src/reference-query.ts +48 -0
- package/src/threads.ts +327 -0
package/dist/index.js
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { n as scopeIconSvgIds, r as validateIconValue, t as ICON_CATALOG_VERSION } from "./icons-Bk4igP2j.js";
|
|
2
|
+
import { PAGE_TEXT_LINK_PREFIX, generateUuidv7, projectIdSchema, uuidv7JsonSchema, uuidv7Schema } from "./ids.js";
|
|
3
|
+
|
|
4
|
+
//#region src/artifact.ts
|
|
5
|
+
/**
|
|
6
|
+
* Artifact titles, shared by the SDK (frame titles, studio sidebar) and the API (Markdown
|
|
7
|
+
* Representation, write warnings), so every surface names an artifact the same way.
|
|
8
|
+
*/
|
|
9
|
+
const UNTITLED_ARTIFACT = "Untitled artifact";
|
|
10
|
+
const entities = {
|
|
11
|
+
amp: "&",
|
|
12
|
+
lt: "<",
|
|
13
|
+
gt: ">",
|
|
14
|
+
quot: "\"",
|
|
15
|
+
apos: "'",
|
|
16
|
+
nbsp: " "
|
|
17
|
+
};
|
|
18
|
+
function decodeEntities(text) {
|
|
19
|
+
return text.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, (match, entity) => {
|
|
20
|
+
if (entity[0] !== "#") return entities[entity.toLowerCase()] ?? match;
|
|
21
|
+
const code = entity[1] === "x" || entity[1] === "X" ? Number.parseInt(entity.slice(2), 16) : Number(entity.slice(1));
|
|
22
|
+
return Number.isNaN(code) ? match : String.fromCodePoint(code);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** The non-empty `<title>` of an artifact source, if it has one. */
|
|
26
|
+
function artifactSourceTitle(source) {
|
|
27
|
+
const match = /<title\b[^>]*>([\s\S]*?)<\/title\s*>/i.exec(source);
|
|
28
|
+
return (match ? decodeEntities(match[1]).replace(/\s+/g, " ").trim() : "") || void 0;
|
|
29
|
+
}
|
|
30
|
+
/** The artifact's name: its source's `<title>`, or "Untitled artifact". */
|
|
31
|
+
function artifactTitle(source) {
|
|
32
|
+
return artifactSourceTitle(source) ?? "Untitled artifact";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/reference-query.ts
|
|
37
|
+
/**
|
|
38
|
+
* Rules for query-backed reference lists, shared by the SDK (builders) and the API (definition
|
|
39
|
+
* sync), so both accept and reject the same queries.
|
|
40
|
+
*/
|
|
41
|
+
/** The most records a query-backed list resolves to, and its default `limit`. */
|
|
42
|
+
const QUERY_LIMIT_CAP = 100;
|
|
43
|
+
const SYSTEM_ORDER_KEYS = ["createdAt", "publishedAt"];
|
|
44
|
+
function isSystemOrderKey(key) {
|
|
45
|
+
return SYSTEM_ORDER_KEYS.includes(key);
|
|
46
|
+
}
|
|
47
|
+
/** Whether a reference list field is query-backed: code defines its records, nothing is stored. */
|
|
48
|
+
function isQueryBacked(field) {
|
|
49
|
+
return !!field && field.query !== void 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Why a query is invalid, if it is. `fieldTypeOf` gives the collection field type an ordering
|
|
53
|
+
* key names; keys must name a `String` field or system metadata.
|
|
54
|
+
*/
|
|
55
|
+
function referenceQueryProblem(query, fieldTypeOf) {
|
|
56
|
+
if (!query || typeof query !== "object" || Array.isArray(query)) return "query must be an object";
|
|
57
|
+
const { orderBy, limit, ...rest } = query;
|
|
58
|
+
if (Object.keys(rest).length) return "query only supports orderBy and limit";
|
|
59
|
+
if (limit !== void 0 && !(typeof limit === "number" && Number.isInteger(limit) && limit >= 1 && limit <= 100)) return `limit must be an integer from 1 to ${100}`;
|
|
60
|
+
if (orderBy === void 0) return;
|
|
61
|
+
const entries = orderBy && typeof orderBy === "object" && !Array.isArray(orderBy) ? Object.entries(orderBy) : [];
|
|
62
|
+
if (entries.length !== 1) return "orderBy takes a single key";
|
|
63
|
+
const [[key, direction]] = entries;
|
|
64
|
+
if (direction !== "asc" && direction !== "desc") return "order must be \"asc\" or \"desc\"";
|
|
65
|
+
if (isSystemOrderKey(key)) return;
|
|
66
|
+
if (fieldTypeOf(key) !== "String") return `cannot order by "${key}"`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { ICON_CATALOG_VERSION, PAGE_TEXT_LINK_PREFIX, QUERY_LIMIT_CAP, SYSTEM_ORDER_KEYS, UNTITLED_ARTIFACT, artifactSourceTitle, artifactTitle, generateUuidv7, isQueryBacked, isSystemOrderKey, projectIdSchema, referenceQueryProblem, scopeIconSvgIds, uuidv7JsonSchema, uuidv7Schema, validateIconValue };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/projects.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Project Slugs Camox keeps for its own hosts and pages, so no project's `<slug>.camox.site`
|
|
5
|
+
* looks like one of them.
|
|
6
|
+
*/
|
|
7
|
+
export declare const RESERVED_PROJECT_SLUGS: ReadonlySet<string>;
|
|
8
|
+
/**
|
|
9
|
+
* A Project Slug: one lowercase DNS label, the only depth Universal SSL covers on `camox.site`,
|
|
10
|
+
* made of letters, digits and inner hyphens.
|
|
11
|
+
*/
|
|
12
|
+
export declare const projectSlugSchema: z.ZodString;
|
|
13
|
+
/** Why a slug can't be given to a new project. */
|
|
14
|
+
export type UnavailableSlugReason = "invalid" | "reserved" | "taken";
|
|
15
|
+
/** What a member is told when a slug can't be used, by reason. */
|
|
16
|
+
export declare const UNAVAILABLE_SLUG_MESSAGES: Record<UnavailableSlugReason, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Where a project is in its life: `settingUp` from its creation until its first release
|
|
19
|
+
* succeeds, then `live`. `setupFailed` when its setup gave up: Camox is told and fixes it.
|
|
20
|
+
*/
|
|
21
|
+
export type ProjectStatus = "settingUp" | "live" | "setupFailed";
|
|
22
|
+
/**
|
|
23
|
+
* The steps a project's setup goes through before it's live, as its page lists them: copying the
|
|
24
|
+
* Template into its repo, then its first release building it and serving it from its Worker.
|
|
25
|
+
*/
|
|
26
|
+
export type ProjectSetupStep = "copyTemplate" | "build" | "serve";
|
|
27
|
+
export declare const PROJECT_SETUP_STEPS: readonly ProjectSetupStep[];
|
|
28
|
+
//#endregion
|
package/dist/projects.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/projects.ts
|
|
4
|
+
/**
|
|
5
|
+
* Project Slugs Camox keeps for its own hosts and pages, so no project's `<slug>.camox.site`
|
|
6
|
+
* looks like one of them.
|
|
7
|
+
*/
|
|
8
|
+
const RESERVED_PROJECT_SLUGS = /* @__PURE__ */ new Set([
|
|
9
|
+
"www",
|
|
10
|
+
"api",
|
|
11
|
+
"app",
|
|
12
|
+
"dashboard",
|
|
13
|
+
"studio",
|
|
14
|
+
"sites",
|
|
15
|
+
"site",
|
|
16
|
+
"docs",
|
|
17
|
+
"blog",
|
|
18
|
+
"help",
|
|
19
|
+
"support",
|
|
20
|
+
"status",
|
|
21
|
+
"admin",
|
|
22
|
+
"auth",
|
|
23
|
+
"login",
|
|
24
|
+
"mail",
|
|
25
|
+
"email",
|
|
26
|
+
"cdn",
|
|
27
|
+
"static",
|
|
28
|
+
"assets",
|
|
29
|
+
"files",
|
|
30
|
+
"camox"
|
|
31
|
+
]);
|
|
32
|
+
/**
|
|
33
|
+
* A Project Slug: one lowercase DNS label, the only depth Universal SSL covers on `camox.site`,
|
|
34
|
+
* made of letters, digits and inner hyphens.
|
|
35
|
+
*/
|
|
36
|
+
const projectSlugSchema = /* @__PURE__ */ z.string().min(1, "Enter a slug").max(63, "Use at most 63 characters").regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Use lowercase letters, digits and hyphens, without a hyphen at either end");
|
|
37
|
+
/** What a member is told when a slug can't be used, by reason. */
|
|
38
|
+
const UNAVAILABLE_SLUG_MESSAGES = {
|
|
39
|
+
invalid: "Use lowercase letters, digits and hyphens, without a hyphen at either end.",
|
|
40
|
+
reserved: "This slug is reserved by Camox. Choose another.",
|
|
41
|
+
taken: "This slug is already taken. Choose another."
|
|
42
|
+
};
|
|
43
|
+
const PROJECT_SETUP_STEPS = [
|
|
44
|
+
"copyTemplate",
|
|
45
|
+
"build",
|
|
46
|
+
"serve"
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { PROJECT_SETUP_STEPS, RESERVED_PROJECT_SLUGS, UNAVAILABLE_SLUG_MESSAGES, projectSlugSchema };
|
package/dist/query-keys.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { EndedDraft } from "./drafts.js";
|
|
2
|
+
//#region src/query-keys.d.ts
|
|
1
3
|
/**
|
|
2
4
|
* Use TypeScript to enforce 'camox' as the first query key to ensure they're all namespaced.
|
|
3
5
|
* This is because the Tanstack Query client on the frontend may be shared with the user's routes,
|
|
@@ -5,46 +7,64 @@
|
|
|
5
7
|
*/
|
|
6
8
|
export type QueryKey = [first: "camox", ...rest: Array<string | number>];
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* source select is instant once both have been seeded.
|
|
12
|
-
*
|
|
13
|
-
* Block / page-read query keys include the source as the trailing key segment.
|
|
14
|
-
* Omitting it on `invalidateQueries` is a prefix invalidation that hits every
|
|
15
|
-
* source — used for navigation events and other source-agnostic invalidations.
|
|
16
|
-
* Edit-time invalidations (which only touch draft data) pass `'draft'`
|
|
17
|
-
* explicitly so the `'live'` cache stays untouched.
|
|
10
|
+
* The key prefixes the API's realtime invalidations name (ADR 0011). The studio caches each read
|
|
11
|
+
* under one of them, with the scope appended, so an invalidation reaches every read it should;
|
|
12
|
+
* the studio's own keys live with its reads, in the SDK.
|
|
18
13
|
*/
|
|
19
|
-
export type ReadSource = "draft" | "live";
|
|
20
14
|
export declare const queryKeys: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
15
|
+
collections: {
|
|
16
|
+
record: (projectUuid: string, collectionId: string, id: string) => ["camox", string, string, string, string, string];
|
|
17
|
+
records: (projectUuid: string, collectionId: string) => ["camox", string, string, string, string];
|
|
18
|
+
};
|
|
19
|
+
pages: {
|
|
20
|
+
list: ["camox", string, string];
|
|
21
|
+
getByPath: (path: string) => ["camox", string, string, string];
|
|
22
|
+
getByPathAll: ["camox", string, string];
|
|
23
|
+
getById: (id: string) => ["camox", string, string, string];
|
|
24
|
+
};
|
|
25
|
+
files: {
|
|
26
|
+
list: ["camox", string, string];
|
|
27
|
+
get: (id: string) => ["camox", string, string, string];
|
|
28
|
+
};
|
|
29
|
+
blocks: {
|
|
30
|
+
get: (id: string) => ["camox", string, string, string];
|
|
31
|
+
getUsageCounts: ["camox", string, string];
|
|
32
|
+
getSyncedContent: (type: string) => ["camox", string, string, string, string];
|
|
33
|
+
getPageMarkdown: (pageId: string) => ["camox", string, string, string];
|
|
34
|
+
};
|
|
35
|
+
layouts: {
|
|
36
|
+
all: ["camox", string];
|
|
37
|
+
};
|
|
38
|
+
drafts: {
|
|
39
|
+
all: ["camox", string];
|
|
40
|
+
list: ["camox", string, string];
|
|
41
|
+
get: ["camox", string, string];
|
|
42
|
+
};
|
|
46
43
|
};
|
|
44
|
+
/** The last segment of a query key: what the query reads, Live or a draft (ADR 0011). */
|
|
45
|
+
export declare const LIVE_KEY_SCOPE = "live";
|
|
46
|
+
/**
|
|
47
|
+
* A query key read from Live (`draftId` null) or from a draft. The keys above are prefixes naming
|
|
48
|
+
* what a query reads; the cache holds them with the scope appended, so each draft's queries are
|
|
49
|
+
* kept and invalidated apart.
|
|
50
|
+
*/
|
|
51
|
+
export declare function inScope(key: QueryKey, draftId: string | null): QueryKey;
|
|
52
|
+
/** The scope a scoped query key ends in: `"live"` or a draft's id. */
|
|
53
|
+
export declare function scopeOfKey(key: readonly unknown[]): unknown;
|
|
54
|
+
/**
|
|
55
|
+
* Refetch the queries under these prefixes. `draftId` names the draft the change came from, so
|
|
56
|
+
* only that draft's queries refetch; a Live change (`null`) refetches every draft's too, since
|
|
57
|
+
* drafts read Live wherever they change nothing.
|
|
58
|
+
*/
|
|
47
59
|
export type InvalidationMessage = {
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
type: "invalidate";
|
|
61
|
+
draftId: string | null;
|
|
62
|
+
targets: QueryKey[];
|
|
50
63
|
};
|
|
64
|
+
/** A draft was published or discarded: its viewers go back to Live. */
|
|
65
|
+
export type DraftEndedMessage = {
|
|
66
|
+
type: "draftEnded";
|
|
67
|
+
} & EndedDraft;
|
|
68
|
+
/** Everything the project room broadcasts. */
|
|
69
|
+
export type ProjectRoomMessage = InvalidationMessage | DraftEndedMessage;
|
|
70
|
+
//#endregion
|
package/dist/query-keys.js
CHANGED
|
@@ -1,29 +1,119 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
//#region src/query-keys.ts
|
|
2
|
+
/**
|
|
3
|
+
* The key prefixes the API's realtime invalidations name (ADR 0011). The studio caches each read
|
|
4
|
+
* under one of them, with the scope appended, so an invalidation reaches every read it should;
|
|
5
|
+
* the studio's own keys live with its reads, in the SDK.
|
|
6
|
+
*/
|
|
7
|
+
const queryKeys = {
|
|
8
|
+
collections: {
|
|
9
|
+
record: (projectUuid, collectionId, id) => [
|
|
10
|
+
"camox",
|
|
11
|
+
"collections",
|
|
12
|
+
"record",
|
|
13
|
+
projectUuid,
|
|
14
|
+
collectionId,
|
|
15
|
+
id
|
|
16
|
+
],
|
|
17
|
+
records: (projectUuid, collectionId) => [
|
|
18
|
+
"camox",
|
|
19
|
+
"collections",
|
|
20
|
+
"records",
|
|
21
|
+
projectUuid,
|
|
22
|
+
collectionId
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
pages: {
|
|
26
|
+
list: [
|
|
27
|
+
"camox",
|
|
28
|
+
"pages",
|
|
29
|
+
"list"
|
|
30
|
+
],
|
|
31
|
+
getByPath: (path) => [
|
|
32
|
+
"camox",
|
|
33
|
+
"pages",
|
|
34
|
+
"getByPath",
|
|
35
|
+
path
|
|
36
|
+
],
|
|
37
|
+
getByPathAll: [
|
|
38
|
+
"camox",
|
|
39
|
+
"pages",
|
|
40
|
+
"getByPath"
|
|
41
|
+
],
|
|
42
|
+
getById: (id) => [
|
|
43
|
+
"camox",
|
|
44
|
+
"pages",
|
|
45
|
+
"getById",
|
|
46
|
+
id
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
files: {
|
|
50
|
+
list: [
|
|
51
|
+
"camox",
|
|
52
|
+
"files",
|
|
53
|
+
"list"
|
|
54
|
+
],
|
|
55
|
+
get: (id) => [
|
|
56
|
+
"camox",
|
|
57
|
+
"files",
|
|
58
|
+
"get",
|
|
59
|
+
id
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
blocks: {
|
|
63
|
+
get: (id) => [
|
|
64
|
+
"camox",
|
|
65
|
+
"blocks",
|
|
66
|
+
"get",
|
|
67
|
+
id
|
|
68
|
+
],
|
|
69
|
+
getUsageCounts: [
|
|
70
|
+
"camox",
|
|
71
|
+
"blocks",
|
|
72
|
+
"getUsageCounts"
|
|
73
|
+
],
|
|
74
|
+
getSyncedContent: (type) => [
|
|
75
|
+
"camox",
|
|
76
|
+
"blocks",
|
|
77
|
+
"getUsageCounts",
|
|
78
|
+
"synced",
|
|
79
|
+
type
|
|
80
|
+
],
|
|
81
|
+
getPageMarkdown: (pageId) => [
|
|
82
|
+
"camox",
|
|
83
|
+
"blocks",
|
|
84
|
+
"getPageMarkdown",
|
|
85
|
+
pageId
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
layouts: { all: ["camox", "layouts"] },
|
|
89
|
+
drafts: {
|
|
90
|
+
all: ["camox", "drafts"],
|
|
91
|
+
list: [
|
|
92
|
+
"camox",
|
|
93
|
+
"drafts",
|
|
94
|
+
"list"
|
|
95
|
+
],
|
|
96
|
+
get: [
|
|
97
|
+
"camox",
|
|
98
|
+
"drafts",
|
|
99
|
+
"get"
|
|
100
|
+
]
|
|
101
|
+
}
|
|
29
102
|
};
|
|
103
|
+
/** The last segment of a query key: what the query reads, Live or a draft (ADR 0011). */
|
|
104
|
+
const LIVE_KEY_SCOPE = "live";
|
|
105
|
+
/**
|
|
106
|
+
* A query key read from Live (`draftId` null) or from a draft. The keys above are prefixes naming
|
|
107
|
+
* what a query reads; the cache holds them with the scope appended, so each draft's queries are
|
|
108
|
+
* kept and invalidated apart.
|
|
109
|
+
*/
|
|
110
|
+
function inScope(key, draftId) {
|
|
111
|
+
return [...key, draftId ?? "live"];
|
|
112
|
+
}
|
|
113
|
+
/** The scope a scoped query key ends in: `"live"` or a draft's id. */
|
|
114
|
+
function scopeOfKey(key) {
|
|
115
|
+
return key[key.length - 1];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
export { LIVE_KEY_SCOPE, inScope, queryKeys, scopeOfKey };
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AgentEvent } from "@earendil-works/pi-durable";
|
|
3
|
+
//#region src/threads.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The kind of the transcript entry recording an editor's message, with its sender and the
|
|
6
|
+
* operation id the studio sent it with as data (`editorMessageDataSchema`).
|
|
7
|
+
*/
|
|
8
|
+
export declare const EDITOR_MESSAGE_ENTRY = "camox.editor-message";
|
|
9
|
+
/** The kind of the transcript entry recording that an editor stopped a run, with them as data. */
|
|
10
|
+
export declare const RUN_STOPPED_ENTRY = "camox.run-stopped";
|
|
11
|
+
/** Who sent a message in a thread. */
|
|
12
|
+
export declare const threadSenderSchema: z.ZodObject<{
|
|
13
|
+
id: z.ZodString;
|
|
14
|
+
name: z.ZodString;
|
|
15
|
+
image: z.ZodNullable<z.ZodString>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type ThreadSender = z.infer<typeof threadSenderSchema>;
|
|
18
|
+
/** Whether `data` names a sender. */
|
|
19
|
+
export declare const isSender: (data: unknown) => data is ThreadSender;
|
|
20
|
+
/** What an editor's message entry records: who sent it, and the operation id it was sent with. */
|
|
21
|
+
export declare const editorMessageDataSchema: z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
name: z.ZodString;
|
|
24
|
+
image: z.ZodNullable<z.ZodString>;
|
|
25
|
+
operationId: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
/**
|
|
28
|
+
* A draft a Live thread started with its first write, becoming its thread, and the operation ids
|
|
29
|
+
* of the messages of the run that made the write: the studio that sent one of them enters the
|
|
30
|
+
* draft with the thread.
|
|
31
|
+
*/
|
|
32
|
+
export declare const startedDraftSchema: z.ZodObject<{
|
|
33
|
+
draftId: z.ZodString;
|
|
34
|
+
operationIds: z.ZodArray<z.ZodString>;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
export type StartedDraft = z.infer<typeof startedDraftSchema>;
|
|
37
|
+
/** How a write touched what it names. */
|
|
38
|
+
export declare const touchKindSchema: z.ZodEnum<{
|
|
39
|
+
created: "created";
|
|
40
|
+
edited: "edited";
|
|
41
|
+
moved: "moved";
|
|
42
|
+
deleted: "deleted";
|
|
43
|
+
settings: "settings";
|
|
44
|
+
}>;
|
|
45
|
+
export type TouchKind = z.infer<typeof touchKindSchema>;
|
|
46
|
+
export declare const touchSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
47
|
+
kind: z.ZodEnum<{
|
|
48
|
+
created: "created";
|
|
49
|
+
edited: "edited";
|
|
50
|
+
moved: "moved";
|
|
51
|
+
deleted: "deleted";
|
|
52
|
+
settings: "settings";
|
|
53
|
+
}>;
|
|
54
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
55
|
+
entity: z.ZodLiteral<"page">;
|
|
56
|
+
pageId: z.ZodString;
|
|
57
|
+
blockId: z.ZodOptional<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
59
|
+
kind: z.ZodEnum<{
|
|
60
|
+
created: "created";
|
|
61
|
+
edited: "edited";
|
|
62
|
+
moved: "moved";
|
|
63
|
+
deleted: "deleted";
|
|
64
|
+
settings: "settings";
|
|
65
|
+
}>;
|
|
66
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
67
|
+
entity: z.ZodLiteral<"synced-block">;
|
|
68
|
+
blockType: z.ZodString;
|
|
69
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
kind: z.ZodEnum<{
|
|
71
|
+
created: "created";
|
|
72
|
+
edited: "edited";
|
|
73
|
+
moved: "moved";
|
|
74
|
+
deleted: "deleted";
|
|
75
|
+
settings: "settings";
|
|
76
|
+
}>;
|
|
77
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
78
|
+
entity: z.ZodLiteral<"layout">;
|
|
79
|
+
layoutId: z.ZodString;
|
|
80
|
+
blockId: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strip>], "entity">;
|
|
82
|
+
export type Touch = z.infer<typeof touchSchema>;
|
|
83
|
+
/**
|
|
84
|
+
* What one code-mode script's successful writes touched, in write order, and the operation ids
|
|
85
|
+
* of the messages of the run it belongs to: only the studio that sent one of them follows it.
|
|
86
|
+
*/
|
|
87
|
+
export declare const touchedBatchSchema: z.ZodObject<{
|
|
88
|
+
operationIds: z.ZodArray<z.ZodString>;
|
|
89
|
+
touches: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
90
|
+
kind: z.ZodEnum<{
|
|
91
|
+
created: "created";
|
|
92
|
+
edited: "edited";
|
|
93
|
+
moved: "moved";
|
|
94
|
+
deleted: "deleted";
|
|
95
|
+
settings: "settings";
|
|
96
|
+
}>;
|
|
97
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
98
|
+
entity: z.ZodLiteral<"page">;
|
|
99
|
+
pageId: z.ZodString;
|
|
100
|
+
blockId: z.ZodOptional<z.ZodString>;
|
|
101
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
102
|
+
kind: z.ZodEnum<{
|
|
103
|
+
created: "created";
|
|
104
|
+
edited: "edited";
|
|
105
|
+
moved: "moved";
|
|
106
|
+
deleted: "deleted";
|
|
107
|
+
settings: "settings";
|
|
108
|
+
}>;
|
|
109
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
110
|
+
entity: z.ZodLiteral<"synced-block">;
|
|
111
|
+
blockType: z.ZodString;
|
|
112
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
113
|
+
kind: z.ZodEnum<{
|
|
114
|
+
created: "created";
|
|
115
|
+
edited: "edited";
|
|
116
|
+
moved: "moved";
|
|
117
|
+
deleted: "deleted";
|
|
118
|
+
settings: "settings";
|
|
119
|
+
}>;
|
|
120
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
121
|
+
entity: z.ZodLiteral<"layout">;
|
|
122
|
+
layoutId: z.ZodString;
|
|
123
|
+
blockId: z.ZodOptional<z.ZodString>;
|
|
124
|
+
}, z.core.$strip>], "entity">>;
|
|
125
|
+
}, z.core.$strip>;
|
|
126
|
+
export type TouchedBatch = z.infer<typeof touchedBatchSchema>;
|
|
127
|
+
/** A message the studio shows in a thread. */
|
|
128
|
+
export type ThreadMessage = {
|
|
129
|
+
id: string;
|
|
130
|
+
from: "editor";
|
|
131
|
+
sender: ThreadSender;
|
|
132
|
+
text: string;
|
|
133
|
+
} |
|
|
134
|
+
/** The agent's final message of a turn, in Markdown. */
|
|
135
|
+
{
|
|
136
|
+
id: string;
|
|
137
|
+
from: "agent";
|
|
138
|
+
text: string;
|
|
139
|
+
} |
|
|
140
|
+
/**
|
|
141
|
+
* In place of the agent's message, for a turn that ended without one: the model failed (after
|
|
142
|
+
* Pi's retries), or its answer was cut short. Sending again retries.
|
|
143
|
+
*/
|
|
144
|
+
{
|
|
145
|
+
id: string;
|
|
146
|
+
from: "failed";
|
|
147
|
+
} |
|
|
148
|
+
/** In place of the agent's message, for a turn an editor stopped: `sender` stopped it. */
|
|
149
|
+
{
|
|
150
|
+
id: string;
|
|
151
|
+
from: "stopped";
|
|
152
|
+
sender: ThreadSender;
|
|
153
|
+
};
|
|
154
|
+
/** Where a Live thread's messages went when it started a draft, beside its transcript. */
|
|
155
|
+
type LiveThreadHandoff = {
|
|
156
|
+
/**
|
|
157
|
+
* The draft this Live thread started with its first write, whose thread it became. The studio
|
|
158
|
+
* that sent a message of that run enters the draft with the thread; other tabs on Live move to
|
|
159
|
+
* the editor's fresh Live thread.
|
|
160
|
+
*/
|
|
161
|
+
startedDraft?: StartedDraft;
|
|
162
|
+
/** The draft the editor's previous Live thread continued in, for a fresh Live thread. */
|
|
163
|
+
continuedIn?: StartedDraft;
|
|
164
|
+
};
|
|
165
|
+
/** Everything the studio shows for a thread. */
|
|
166
|
+
export type ThreadView = LiveThreadHandoff & {
|
|
167
|
+
messages: readonly ThreadMessage[];
|
|
168
|
+
/** Whether a run is going: the agent is working on a turn, and stopping would end it. */
|
|
169
|
+
running: boolean;
|
|
170
|
+
};
|
|
171
|
+
export declare const EMPTY_THREAD_VIEW: ThreadView;
|
|
172
|
+
/**
|
|
173
|
+
* What a thread's view is folded from: the steps of its transcript that matter to the studio,
|
|
174
|
+
* and whether a run is going. The studio and the tests fold Pi's events into this, and derive
|
|
175
|
+
* the view from it with `threadViewOf`, so a snapshot and the events that led to it show the same.
|
|
176
|
+
*/
|
|
177
|
+
export type ThreadState = LiveThreadHandoff & {
|
|
178
|
+
steps: readonly ThreadStep[];
|
|
179
|
+
running: boolean;
|
|
180
|
+
};
|
|
181
|
+
export declare const EMPTY_THREAD_STATE: ThreadState;
|
|
182
|
+
/** One transcript entry, as far as the studio's view is concerned. */
|
|
183
|
+
type ThreadStep = {
|
|
184
|
+
id: string;
|
|
185
|
+
} & ({
|
|
186
|
+
type: "editor";
|
|
187
|
+
sender: ThreadSender;
|
|
188
|
+
text: string;
|
|
189
|
+
} | {
|
|
190
|
+
type: "answer";
|
|
191
|
+
text: string;
|
|
192
|
+
} |
|
|
193
|
+
/** A round of tool calls, or their results: the run goes on after it. */
|
|
194
|
+
{
|
|
195
|
+
type: "tools";
|
|
196
|
+
} |
|
|
197
|
+
/** A model call that ended without an answer: failed, aborted, or cut short. */
|
|
198
|
+
{
|
|
199
|
+
type: "unfinished";
|
|
200
|
+
} | {
|
|
201
|
+
type: "stopped";
|
|
202
|
+
sender: ThreadSender;
|
|
203
|
+
});
|
|
204
|
+
/** Studio → thread. */
|
|
205
|
+
export declare const threadClientMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
206
|
+
type: z.ZodLiteral<"send">;
|
|
207
|
+
operationId: z.ZodString;
|
|
208
|
+
text: z.ZodString;
|
|
209
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
210
|
+
type: z.ZodLiteral<"stop">;
|
|
211
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
212
|
+
type: z.ZodLiteral<"resync">;
|
|
213
|
+
}, z.core.$strip>], "type">;
|
|
214
|
+
export type ThreadClientMessage = z.infer<typeof threadClientMessageSchema>;
|
|
215
|
+
/** Thread → studio. */
|
|
216
|
+
export type ThreadServerMessage =
|
|
217
|
+
/**
|
|
218
|
+
* Pi's agent events. The first batch after connecting or resyncing starts with a `snapshot`,
|
|
219
|
+
* which replaces whatever the studio folded before.
|
|
220
|
+
*/
|
|
221
|
+
{
|
|
222
|
+
type: "events";
|
|
223
|
+
events: readonly AgentEvent[];
|
|
224
|
+
} |
|
|
225
|
+
/** The thread recorded the message sent with this operation id (once, however often sent). */
|
|
226
|
+
{
|
|
227
|
+
type: "accepted";
|
|
228
|
+
operationId: string;
|
|
229
|
+
} |
|
|
230
|
+
/** This Live thread started a draft with its first write, and became that draft's thread. */
|
|
231
|
+
{
|
|
232
|
+
type: "started-draft";
|
|
233
|
+
startedDraft: StartedDraft;
|
|
234
|
+
} |
|
|
235
|
+
/**
|
|
236
|
+
* The editor's previous Live thread continued in this draft: this one is fresh. Sent before
|
|
237
|
+
* the snapshot.
|
|
238
|
+
*/
|
|
239
|
+
{
|
|
240
|
+
type: "continued-in";
|
|
241
|
+
continuedIn: StartedDraft;
|
|
242
|
+
} |
|
|
243
|
+
/**
|
|
244
|
+
* A code-mode script that wrote something ended, failed or not: what its successful writes
|
|
245
|
+
* touched. Sent once per such script, live only: a snapshot never replays past touches.
|
|
246
|
+
*/
|
|
247
|
+
{
|
|
248
|
+
type: "touched";
|
|
249
|
+
touched: TouchedBatch;
|
|
250
|
+
} | {
|
|
251
|
+
type: "error";
|
|
252
|
+
operationId?: string;
|
|
253
|
+
message: string;
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* The code a thread closes its sockets with once it ended with its draft, and for good: it's
|
|
257
|
+
* deleted, so reconnecting reaches nothing. A development draft, which stays open, gets a new
|
|
258
|
+
* thread the next time the studio connects.
|
|
259
|
+
*/
|
|
260
|
+
export declare const THREAD_ENDED_CLOSE_CODE = 4000;
|
|
261
|
+
/**
|
|
262
|
+
* What the studio shows for a thread. A turn starts with an editor's message, and messages sent
|
|
263
|
+
* while it runs join it. It ends with the agent's final message; text written beside tool calls
|
|
264
|
+
* is never shown. A stopped turn shows who stopped it instead, and whatever its run wrote after
|
|
265
|
+
* the stop is left out. A turn that ended without either shows a failed line in its place: its
|
|
266
|
+
* run is over, or a later message started another run after its last model call came back
|
|
267
|
+
* unfinished. While Pi retries a failed call, the run goes on, so the turn shows as working.
|
|
268
|
+
*/
|
|
269
|
+
export declare function threadViewOf({ steps, running, ...drafts }: ThreadState): ThreadView;
|
|
270
|
+
/** Folds one of Pi's agent events into the thread's state. */
|
|
271
|
+
export declare function reduceThreadState(state: ThreadState, event: AgentEvent): ThreadState;
|
|
272
|
+
/** Folds a batch of Pi's agent events into the thread's state. */
|
|
273
|
+
export declare const reduceThreadEvents: (state: ThreadState, events: readonly AgentEvent[]) => ThreadState;
|
|
274
|
+
/** Folds what the thread sent over its socket into the thread's state. */
|
|
275
|
+
export declare function reduceThreadFrame(state: ThreadState, frame: ThreadServerMessage): ThreadState;
|
|
276
|
+
//#endregion
|
|
277
|
+
export {};
|