@camox/api-contract 0.69.0 → 0.72.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/drafts.d.ts +53 -5
- package/dist/drafts.js +16 -6
- package/dist/index.d.ts +23 -0
- package/dist/index.js +46 -1
- package/dist/router.d.ts +17 -140
- package/dist/threads.d.ts +18 -4
- package/dist/threads.js +113 -103
- package/package.json +1 -1
- package/src/drafts.ts +63 -5
- package/src/empty-values.ts +52 -0
- package/src/index.ts +1 -0
- package/src/threads.ts +31 -11
package/dist/drafts.d.ts
CHANGED
|
@@ -42,17 +42,17 @@ export declare const LOOK_PATH_PARAM = "path";
|
|
|
42
42
|
export declare const LOOK_LOCALE_PARAM = "locale";
|
|
43
43
|
/**
|
|
44
44
|
* The look document's Block Definition mode: instead of a page, the block of the Block Definition
|
|
45
|
-
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with
|
|
46
|
-
*
|
|
47
|
-
* the shape the content tools take.
|
|
45
|
+
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with empty fields and the
|
|
46
|
+
* content and Block Settings `LOOK_CONTENT_PARAM` and `LOOK_SETTINGS_PARAM` give as JSON merged
|
|
47
|
+
* on, in the shape the content tools take.
|
|
48
48
|
*/
|
|
49
49
|
export declare const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
50
50
|
export declare const LOOK_CONTENT_PARAM = "content";
|
|
51
51
|
export declare const LOOK_SETTINGS_PARAM = "settings";
|
|
52
52
|
/**
|
|
53
53
|
* The look document's Layout Definition mode: instead of a page, the curated Layout
|
|
54
|
-
* `LOOK_LAYOUT_DEFINITION_PARAM` names, alone in the site's shell, its blocks with
|
|
55
|
-
* content and Block Settings
|
|
54
|
+
* `LOOK_LAYOUT_DEFINITION_PARAM` names, alone in the site's shell, its blocks with empty fields
|
|
55
|
+
* and the content and Block Settings `LOOK_BLOCKS_PARAM` gives as JSON merged on, by Block
|
|
56
56
|
* Definition name (`{ navbar: { content, settings } }`), around a labelled placeholder where a
|
|
57
57
|
* page's content goes, as tall as `LOOK_PLACEHOLDER_PARAM` says: one of `LOOK_PLACEHOLDER_HEIGHTS`,
|
|
58
58
|
* the first without.
|
|
@@ -69,6 +69,54 @@ export type LookPlaceholderHeight = (typeof LOOK_PLACEHOLDER_HEIGHTS)[number];
|
|
|
69
69
|
* `[data-camox-viewport-block="unplaced"]`.
|
|
70
70
|
*/
|
|
71
71
|
export declare const UNPLACED_BLOCK_ID = "unplaced";
|
|
72
|
+
/**
|
|
73
|
+
* The attributes the website's artifact frames carry: the artifact field's name, and the id of the
|
|
74
|
+
* Repeatable Item holding it, when an item's. With the block's `data-camox-viewport-block`, they
|
|
75
|
+
* find one artifact's frame (`lookArtifactSelector`).
|
|
76
|
+
*/
|
|
77
|
+
export declare const ARTIFACT_FIELD_ATTRIBUTE = "data-camox-artifact";
|
|
78
|
+
export declare const ARTIFACT_ITEM_ATTRIBUTE = "data-camox-item";
|
|
79
|
+
/** The CSS selector of the frame of an artifact field of a block, or of one of its items. */
|
|
80
|
+
export declare const lookArtifactSelector: ({ block, item, field }: {
|
|
81
|
+
block: string;
|
|
82
|
+
item?: string;
|
|
83
|
+
field: string;
|
|
84
|
+
}) => string;
|
|
85
|
+
/** An artifact's Timeline, as its runtime declares it: Marks by name, at times in ms. */
|
|
86
|
+
export type LookTimeline = {
|
|
87
|
+
duration: number;
|
|
88
|
+
loop: boolean;
|
|
89
|
+
marks: Record<string, number>;
|
|
90
|
+
/** The Mark whose frame stands for the artifact, or null. */
|
|
91
|
+
poster: string | null;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* One finding of an artifact's guardrail report, about motion that escapes its Timeline or will
|
|
95
|
+
* look broken: a Web Animation the runtime didn't make (a CSS animation, a CSS transition that no
|
|
96
|
+
* visitor triggered, one the source made itself), a live timer, a Track the runtime skipped
|
|
97
|
+
* because it can't play it, Tracks on one element and property that overlap, or a loop cut,
|
|
98
|
+
* where a looping Timeline's last frame differs from its first.
|
|
99
|
+
*/
|
|
100
|
+
export type LookGuardrailFinding = {
|
|
101
|
+
kind: "animation" | "timer" | "track" | "overlap" | "loop-cut";
|
|
102
|
+
/** What's wrong and what to do instead, for the Artifact Agent. */
|
|
103
|
+
text: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* What the look document's artifact frames hold under `LOOK_ARTIFACT_CAPTURE`, for the browser
|
|
107
|
+
* `look` drives: the artifact's Timeline, null when it declares none; seeking it to `t` ms,
|
|
108
|
+
* resolved once the frame at that time painted, with the error `render` threw, if it did; and its
|
|
109
|
+
* guardrail report, empty when nothing escapes its Timeline. Frames of an SDK older than
|
|
110
|
+
* Timelines hold nothing there.
|
|
111
|
+
*/
|
|
112
|
+
export type LookArtifactCapture = {
|
|
113
|
+
timeline(): Promise<LookTimeline | null>;
|
|
114
|
+
seek(t: number): Promise<{
|
|
115
|
+
error?: string;
|
|
116
|
+
}>;
|
|
117
|
+
guardrail(): Promise<LookGuardrailFinding[]>;
|
|
118
|
+
};
|
|
119
|
+
export declare const LOOK_ARTIFACT_CAPTURE = "camoxCapture";
|
|
72
120
|
/**
|
|
73
121
|
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
74
122
|
* exist yet. Its value is `"1"`.
|
package/dist/drafts.js
CHANGED
|
@@ -42,17 +42,17 @@ const LOOK_PATH_PARAM = "path";
|
|
|
42
42
|
const LOOK_LOCALE_PARAM = "locale";
|
|
43
43
|
/**
|
|
44
44
|
* The look document's Block Definition mode: instead of a page, the block of the Block Definition
|
|
45
|
-
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with
|
|
46
|
-
*
|
|
47
|
-
* the shape the content tools take.
|
|
45
|
+
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with empty fields and the
|
|
46
|
+
* content and Block Settings `LOOK_CONTENT_PARAM` and `LOOK_SETTINGS_PARAM` give as JSON merged
|
|
47
|
+
* on, in the shape the content tools take.
|
|
48
48
|
*/
|
|
49
49
|
const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
50
50
|
const LOOK_CONTENT_PARAM = "content";
|
|
51
51
|
const LOOK_SETTINGS_PARAM = "settings";
|
|
52
52
|
/**
|
|
53
53
|
* The look document's Layout Definition mode: instead of a page, the curated Layout
|
|
54
|
-
* `LOOK_LAYOUT_DEFINITION_PARAM` names, alone in the site's shell, its blocks with
|
|
55
|
-
* content and Block Settings
|
|
54
|
+
* `LOOK_LAYOUT_DEFINITION_PARAM` names, alone in the site's shell, its blocks with empty fields
|
|
55
|
+
* and the content and Block Settings `LOOK_BLOCKS_PARAM` gives as JSON merged on, by Block
|
|
56
56
|
* Definition name (`{ navbar: { content, settings } }`), around a labelled placeholder where a
|
|
57
57
|
* page's content goes, as tall as `LOOK_PLACEHOLDER_PARAM` says: one of `LOOK_PLACEHOLDER_HEIGHTS`,
|
|
58
58
|
* the first without.
|
|
@@ -69,6 +69,16 @@ const LOOK_PLACEHOLDER_HEIGHTS = ["short", "tall"];
|
|
|
69
69
|
*/
|
|
70
70
|
const UNPLACED_BLOCK_ID = "unplaced";
|
|
71
71
|
/**
|
|
72
|
+
* The attributes the website's artifact frames carry: the artifact field's name, and the id of the
|
|
73
|
+
* Repeatable Item holding it, when an item's. With the block's `data-camox-viewport-block`, they
|
|
74
|
+
* find one artifact's frame (`lookArtifactSelector`).
|
|
75
|
+
*/
|
|
76
|
+
const ARTIFACT_FIELD_ATTRIBUTE = "data-camox-artifact";
|
|
77
|
+
const ARTIFACT_ITEM_ATTRIBUTE = "data-camox-item";
|
|
78
|
+
/** The CSS selector of the frame of an artifact field of a block, or of one of its items. */
|
|
79
|
+
const lookArtifactSelector = ({ block, item, field }) => `[data-camox-viewport-block="${block}"] iframe[${ARTIFACT_FIELD_ATTRIBUTE}="${field}"]` + (item ? `[${ARTIFACT_ITEM_ATTRIBUTE}="${item}"]` : `:not([${ARTIFACT_ITEM_ATTRIBUTE}])`);
|
|
80
|
+
const LOOK_ARTIFACT_CAPTURE = "camoxCapture";
|
|
81
|
+
/**
|
|
72
82
|
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
73
83
|
* exist yet. Its value is `"1"`.
|
|
74
84
|
*/
|
|
@@ -236,4 +246,4 @@ function isContentWrite(path) {
|
|
|
236
246
|
}
|
|
237
247
|
|
|
238
248
|
//#endregion
|
|
239
|
-
export { CAMOX_ACTOR, CAMOX_NAME, CHECKS_RUNNING_ERROR, CONFLICTS_CHANGED_ERROR, DRAFT_CREATE_HEADER, DRAFT_ENDED_ERROR_CODE, DRAFT_HEADER, DRAFT_SEARCH_PARAM, FINDINGS_OPEN_ERROR, LIVE_READ_ONLY_ERROR, LOCALE_HEADER, LOOK_BLOCKS_PARAM, LOOK_BLOCK_DEFINITION_PARAM, LOOK_CONTENT_PARAM, LOOK_DOCUMENT_PATH, LOOK_LAYOUT_DEFINITION_PARAM, LOOK_LOCALE_PARAM, LOOK_PATH_PARAM, LOOK_PLACEHOLDER_HEIGHTS, LOOK_PLACEHOLDER_PARAM, LOOK_SETTINGS_PARAM, LOOK_TOKEN_COOKIE, LOOK_TOKEN_HEADER, NOT_PUBLISHED_CODES, PUBLISHING_DRAFT_HEADER, PUBLISHING_DRAFT_VAR, PUBLISH_ABORT_REASONS, PUBLISH_BLOCKED_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR, UNPLACED_BLOCK_ID, isContentWrite };
|
|
249
|
+
export { ARTIFACT_FIELD_ATTRIBUTE, ARTIFACT_ITEM_ATTRIBUTE, CAMOX_ACTOR, CAMOX_NAME, CHECKS_RUNNING_ERROR, CONFLICTS_CHANGED_ERROR, DRAFT_CREATE_HEADER, DRAFT_ENDED_ERROR_CODE, DRAFT_HEADER, DRAFT_SEARCH_PARAM, FINDINGS_OPEN_ERROR, LIVE_READ_ONLY_ERROR, LOCALE_HEADER, LOOK_ARTIFACT_CAPTURE, LOOK_BLOCKS_PARAM, LOOK_BLOCK_DEFINITION_PARAM, LOOK_CONTENT_PARAM, LOOK_DOCUMENT_PATH, LOOK_LAYOUT_DEFINITION_PARAM, LOOK_LOCALE_PARAM, LOOK_PATH_PARAM, LOOK_PLACEHOLDER_HEIGHTS, LOOK_PLACEHOLDER_PARAM, LOOK_SETTINGS_PARAM, LOOK_TOKEN_COOKIE, LOOK_TOKEN_HEADER, NOT_PUBLISHED_CODES, PUBLISHING_DRAFT_HEADER, PUBLISHING_DRAFT_VAR, PUBLISH_ABORT_REASONS, PUBLISH_BLOCKED_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR, UNPLACED_BLOCK_ID, isContentWrite, lookArtifactSelector };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,29 @@ export declare function artifactTitle(source: string): string;
|
|
|
17
17
|
*/
|
|
18
18
|
export declare function artifactSourceHash(source: string): Promise<string>;
|
|
19
19
|
//#endregion
|
|
20
|
+
//#region src/empty-values.d.ts
|
|
21
|
+
/**
|
|
22
|
+
* What a field holds before anyone writes it: the empty value of its kind. Fields declare no
|
|
23
|
+
* default, so content missing a field, or holding a value of the wrong kind, reads as this.
|
|
24
|
+
* Shared by the SDK (rendering, new repeatable items, authoring forms) and the API (creating
|
|
25
|
+
* content, conforming it on read), so both agree on what an unset field is.
|
|
26
|
+
*/
|
|
27
|
+
/** A link that goes nowhere yet. */
|
|
28
|
+
export declare const EMPTY_LINK: {
|
|
29
|
+
readonly type: "external";
|
|
30
|
+
readonly text: "";
|
|
31
|
+
readonly href: "";
|
|
32
|
+
readonly newTab: false;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The empty value of a field, from its stored JSON Schema (`fieldType` and, for an enum, its
|
|
36
|
+
* options): `""` for text, a link to nowhere, `false`, an enum's first option, `null` for one
|
|
37
|
+
* asset or record, and `[]` for lists and repeaters. A fresh copy each call.
|
|
38
|
+
*/
|
|
39
|
+
export declare function emptyFieldValue(fieldSchema: unknown): unknown;
|
|
40
|
+
/** The empty value of every field of a content or settings schema, by name. */
|
|
41
|
+
export declare function emptyFieldValues(schema: unknown): Record<string, unknown>;
|
|
42
|
+
//#endregion
|
|
20
43
|
//#region src/record-templates.d.ts
|
|
21
44
|
/**
|
|
22
45
|
* A collection's `toTitle` and `toDescription` are record templates: text with `{{field}}` tokens
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,51 @@ async function artifactSourceHash(source) {
|
|
|
43
43
|
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/empty-values.ts
|
|
48
|
+
/**
|
|
49
|
+
* What a field holds before anyone writes it: the empty value of its kind. Fields declare no
|
|
50
|
+
* default, so content missing a field, or holding a value of the wrong kind, reads as this.
|
|
51
|
+
* Shared by the SDK (rendering, new repeatable items, authoring forms) and the API (creating
|
|
52
|
+
* content, conforming it on read), so both agree on what an unset field is.
|
|
53
|
+
*/
|
|
54
|
+
/** A link that goes nowhere yet. */
|
|
55
|
+
const EMPTY_LINK = {
|
|
56
|
+
type: "external",
|
|
57
|
+
text: "",
|
|
58
|
+
href: "",
|
|
59
|
+
newTab: false
|
|
60
|
+
};
|
|
61
|
+
function isObject(value) {
|
|
62
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The empty value of a field, from its stored JSON Schema (`fieldType` and, for an enum, its
|
|
66
|
+
* options): `""` for text, a link to nowhere, `false`, an enum's first option, `null` for one
|
|
67
|
+
* asset or record, and `[]` for lists and repeaters. A fresh copy each call.
|
|
68
|
+
*/
|
|
69
|
+
function emptyFieldValue(fieldSchema) {
|
|
70
|
+
const schema = isObject(fieldSchema) ? fieldSchema : {};
|
|
71
|
+
switch (schema.fieldType) {
|
|
72
|
+
case "Link": return { ...EMPTY_LINK };
|
|
73
|
+
case "Boolean": return false;
|
|
74
|
+
case "Enum": return (Array.isArray(schema.enum) ? schema.enum : []).find((option) => typeof option === "string") ?? "";
|
|
75
|
+
case "Image":
|
|
76
|
+
case "File":
|
|
77
|
+
case "Reference": return null;
|
|
78
|
+
case "ImageList":
|
|
79
|
+
case "FileList":
|
|
80
|
+
case "ReferenceList":
|
|
81
|
+
case "Repeater": return [];
|
|
82
|
+
default: return "";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** The empty value of every field of a content or settings schema, by name. */
|
|
86
|
+
function emptyFieldValues(schema) {
|
|
87
|
+
const properties = isObject(schema) && isObject(schema.properties) ? schema.properties : {};
|
|
88
|
+
return Object.fromEntries(Object.entries(properties).map(([name, field]) => [name, emptyFieldValue(field)]));
|
|
89
|
+
}
|
|
90
|
+
|
|
46
91
|
//#endregion
|
|
47
92
|
//#region src/record-templates.ts
|
|
48
93
|
/**
|
|
@@ -144,4 +189,4 @@ function isSettingCondition(value) {
|
|
|
144
189
|
}
|
|
145
190
|
|
|
146
191
|
//#endregion
|
|
147
|
-
export { ARTICLE_TYPES, ICON_CATALOG_VERSION, PAGE_TEXT_LINK_PREFIX, QUERY_LIMIT_CAP, SYSTEM_ORDER_KEYS, UNTITLED_ARTIFACT, artifactSourceHash, artifactSourceTitle, artifactTitle, generateUuidv7, isPageUrlMarker, isQueryBacked, isSettingCondition, isSystemOrderKey, linkedRecordId, nonStringTemplateFields, projectIdSchema, recordLink, recordText, referenceQueryProblem, scopeIconSvgIds, templateFields, uuidv7JsonSchema, uuidv7Schema, validateIconValue };
|
|
192
|
+
export { ARTICLE_TYPES, EMPTY_LINK, ICON_CATALOG_VERSION, PAGE_TEXT_LINK_PREFIX, QUERY_LIMIT_CAP, SYSTEM_ORDER_KEYS, UNTITLED_ARTIFACT, artifactSourceHash, artifactSourceTitle, artifactTitle, emptyFieldValue, emptyFieldValues, generateUuidv7, isPageUrlMarker, isQueryBacked, isSettingCondition, isSystemOrderKey, linkedRecordId, nonStringTemplateFields, projectIdSchema, recordLink, recordText, referenceQueryProblem, scopeIconSvgIds, templateFields, uuidv7JsonSchema, uuidv7Schema, validateIconValue };
|
package/dist/router.d.ts
CHANGED
|
@@ -2279,8 +2279,8 @@ declare const schema: {
|
|
|
2279
2279
|
}, {}, {
|
|
2280
2280
|
length: number | undefined;
|
|
2281
2281
|
}>;
|
|
2282
|
-
|
|
2283
|
-
name: "
|
|
2282
|
+
openingRequest: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
2283
|
+
name: "opening_request";
|
|
2284
2284
|
tableName: "drafts";
|
|
2285
2285
|
dataType: "string";
|
|
2286
2286
|
columnType: "SQLiteText";
|
|
@@ -2298,8 +2298,8 @@ declare const schema: {
|
|
|
2298
2298
|
}, {}, {
|
|
2299
2299
|
length: number | undefined;
|
|
2300
2300
|
}>;
|
|
2301
|
-
|
|
2302
|
-
name: "
|
|
2301
|
+
overviewHeadline: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
2302
|
+
name: "overview_headline";
|
|
2303
2303
|
tableName: "drafts";
|
|
2304
2304
|
dataType: "string";
|
|
2305
2305
|
columnType: "SQLiteText";
|
|
@@ -4728,40 +4728,6 @@ declare const schema: {
|
|
|
4728
4728
|
identity: undefined;
|
|
4729
4729
|
generated: undefined;
|
|
4730
4730
|
}, {}, {}>;
|
|
4731
|
-
defaultContent: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
4732
|
-
name: "default_content";
|
|
4733
|
-
tableName: "block_definitions";
|
|
4734
|
-
dataType: "json";
|
|
4735
|
-
columnType: "SQLiteTextJson";
|
|
4736
|
-
data: unknown;
|
|
4737
|
-
driverParam: string;
|
|
4738
|
-
notNull: false;
|
|
4739
|
-
hasDefault: false;
|
|
4740
|
-
isPrimaryKey: false;
|
|
4741
|
-
isAutoincrement: false;
|
|
4742
|
-
hasRuntimeDefault: false;
|
|
4743
|
-
enumValues: undefined;
|
|
4744
|
-
baseColumn: never;
|
|
4745
|
-
identity: undefined;
|
|
4746
|
-
generated: undefined;
|
|
4747
|
-
}, {}, {}>;
|
|
4748
|
-
defaultSettings: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
4749
|
-
name: "default_settings";
|
|
4750
|
-
tableName: "block_definitions";
|
|
4751
|
-
dataType: "json";
|
|
4752
|
-
columnType: "SQLiteTextJson";
|
|
4753
|
-
data: unknown;
|
|
4754
|
-
driverParam: string;
|
|
4755
|
-
notNull: false;
|
|
4756
|
-
hasDefault: false;
|
|
4757
|
-
isPrimaryKey: false;
|
|
4758
|
-
isAutoincrement: false;
|
|
4759
|
-
hasRuntimeDefault: false;
|
|
4760
|
-
enumValues: undefined;
|
|
4761
|
-
baseColumn: never;
|
|
4762
|
-
identity: undefined;
|
|
4763
|
-
generated: undefined;
|
|
4764
|
-
}, {}, {}>;
|
|
4765
4731
|
layoutOnly: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
4766
4732
|
name: "layout_only";
|
|
4767
4733
|
tableName: "block_definitions";
|
|
@@ -9934,11 +9900,9 @@ declare const TRANSLATED_ENTITIES: readonly ["page", "block", "sharedContent", "
|
|
|
9934
9900
|
type TranslatedEntity = (typeof TRANSLATED_ENTITIES)[number];
|
|
9935
9901
|
/**
|
|
9936
9902
|
* A job translating a default-locale entity into one locale of a draft (ADR 0015). Jobs are keyed
|
|
9937
|
-
* by entity, locale, draft and source, and debounced like generation jobs. A job
|
|
9938
|
-
* `
|
|
9939
|
-
*
|
|
9940
|
-
* merging with `live` merges the draft's localization with Live's, which Live changed since the
|
|
9941
|
-
* draft copied it, so it's no longer a conflict (ADR 0016).
|
|
9903
|
+
* by entity, locale, draft and source, and debounced like generation jobs. A job merging with
|
|
9904
|
+
* `live` merges the draft's localization with Live's, which Live changed since the draft copied
|
|
9905
|
+
* it, so it's no longer a conflict (ADR 0016).
|
|
9942
9906
|
*/
|
|
9943
9907
|
type TranslationJob = {
|
|
9944
9908
|
kind: "translation";
|
|
@@ -9946,7 +9910,7 @@ type TranslationJob = {
|
|
|
9946
9910
|
entityId: string;
|
|
9947
9911
|
locale: string;
|
|
9948
9912
|
draftId: string;
|
|
9949
|
-
source?: "
|
|
9913
|
+
source?: "live";
|
|
9950
9914
|
};
|
|
9951
9915
|
/**
|
|
9952
9916
|
* A job writing a draft's Draft Overview from its changes, keyed by draft: a newer request
|
|
@@ -10243,8 +10207,6 @@ type Field = FieldBase & ({
|
|
|
10243
10207
|
itemContentSchema: unknown;
|
|
10244
10208
|
/** The settings schema of the repeater's items, if they have settings. */
|
|
10245
10209
|
itemSettingsSchema: unknown;
|
|
10246
|
-
/** How many items a new block starts with. */
|
|
10247
|
-
defaultItems: number;
|
|
10248
10210
|
} | {
|
|
10249
10211
|
kind: "Reference";
|
|
10250
10212
|
collectionId: string;
|
|
@@ -10324,7 +10286,10 @@ type DraftSummary = {
|
|
|
10324
10286
|
createdAt: number;
|
|
10325
10287
|
/** When the draft last stored a change, or null while it stores nothing. */
|
|
10326
10288
|
lastChangedAt: number | null;
|
|
10327
|
-
/**
|
|
10289
|
+
/**
|
|
10290
|
+
* How many changes the draft has: the entities its publish preview lists, and its code as one
|
|
10291
|
+
* more once the agent changed it, as publishing ships it.
|
|
10292
|
+
*/
|
|
10328
10293
|
changeCount: number;
|
|
10329
10294
|
/** The tags of the locales the draft has pending translations into (ADR 0015). */
|
|
10330
10295
|
translatingLocales: string[];
|
|
@@ -10376,12 +10341,10 @@ type Overview =
|
|
|
10376
10341
|
} |
|
|
10377
10342
|
/**
|
|
10378
10343
|
* Written. A `stale` one describes an older version of the draft's changes: it's still shown
|
|
10379
|
-
* while a new one is written.
|
|
10380
|
-
* null for an overview written before overviews had one.
|
|
10344
|
+
* while a new one is written.
|
|
10381
10345
|
*/
|
|
10382
10346
|
{
|
|
10383
10347
|
status: "ready";
|
|
10384
|
-
name: string | null;
|
|
10385
10348
|
headline: string;
|
|
10386
10349
|
bullets: string[];
|
|
10387
10350
|
stale: boolean;
|
|
@@ -17026,8 +16989,6 @@ declare const router: {
|
|
|
17026
16989
|
description: string;
|
|
17027
16990
|
contentSchema: unknown;
|
|
17028
16991
|
settingsSchema: unknown;
|
|
17029
|
-
defaultContent: unknown;
|
|
17030
|
-
defaultSettings: unknown;
|
|
17031
16992
|
layoutOnly: boolean | null;
|
|
17032
16993
|
synced: boolean;
|
|
17033
16994
|
schemaHash: string;
|
|
@@ -17042,8 +17003,6 @@ declare const router: {
|
|
|
17042
17003
|
description: string;
|
|
17043
17004
|
contentSchema: unknown;
|
|
17044
17005
|
settingsSchema: unknown;
|
|
17045
|
-
defaultContent: unknown;
|
|
17046
|
-
defaultSettings: unknown;
|
|
17047
17006
|
layoutOnly: boolean | null;
|
|
17048
17007
|
synced: boolean;
|
|
17049
17008
|
schemaHash: string;
|
|
@@ -17771,8 +17730,6 @@ declare const router: {
|
|
|
17771
17730
|
description: import("zod").ZodString;
|
|
17772
17731
|
contentSchema: import("zod").ZodUnknown;
|
|
17773
17732
|
settingsSchema: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17774
|
-
defaultContent: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17775
|
-
defaultSettings: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17776
17733
|
layoutOnly: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
17777
17734
|
synced: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
17778
17735
|
}, import("zod/v4/core").$strip>>;
|
|
@@ -17791,20 +17748,10 @@ declare const router: {
|
|
|
17791
17748
|
}, import("zod/v4/core").$strip>>;
|
|
17792
17749
|
blocks: import("zod").ZodArray<import("zod").ZodPreprocess<import("zod").ZodObject<{
|
|
17793
17750
|
type: import("zod").ZodString;
|
|
17794
|
-
content: import("zod").ZodUnknown;
|
|
17795
|
-
settings: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17796
17751
|
slot: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
17797
17752
|
after: "after";
|
|
17798
17753
|
before: "before";
|
|
17799
17754
|
}>>;
|
|
17800
|
-
repeatableItems: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
17801
|
-
tempId: import("zod").ZodString;
|
|
17802
|
-
parentTempId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
17803
|
-
fieldName: import("zod").ZodString;
|
|
17804
|
-
content: import("zod").ZodUnknown;
|
|
17805
|
-
settings: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17806
|
-
position: import("zod").ZodString;
|
|
17807
|
-
}, import("zod/v4/core").$strip>>>;
|
|
17808
17755
|
}, import("zod/v4/core").$strip>, unknown>>;
|
|
17809
17756
|
}, import("zod/v4/core").$strip>>;
|
|
17810
17757
|
collections: import("zod").ZodArray<import("zod").ZodPipe<import("zod").ZodObject<{
|
|
@@ -17937,19 +17884,6 @@ declare const router: {
|
|
|
17937
17884
|
}>>>;
|
|
17938
17885
|
homepage: import("zod").ZodNullable<import("zod").ZodObject<{
|
|
17939
17886
|
layoutId: import("zod").ZodString;
|
|
17940
|
-
blocks: import("zod").ZodArray<import("zod").ZodObject<{
|
|
17941
|
-
type: import("zod").ZodString;
|
|
17942
|
-
content: import("zod").ZodUnknown;
|
|
17943
|
-
settings: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17944
|
-
repeatableItems: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
17945
|
-
tempId: import("zod").ZodString;
|
|
17946
|
-
parentTempId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
17947
|
-
fieldName: import("zod").ZodString;
|
|
17948
|
-
content: import("zod").ZodUnknown;
|
|
17949
|
-
settings: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
17950
|
-
position: import("zod").ZodString;
|
|
17951
|
-
}, import("zod/v4/core").$strip>>>;
|
|
17952
|
-
}, import("zod/v4/core").$strip>>;
|
|
17953
17887
|
}, import("zod/v4/core").$strip>>;
|
|
17954
17888
|
}, import("zod/v4/core").$strip>;
|
|
17955
17889
|
}, import("zod/v4/core").$strip>, import("@orpc/server").Schema<{
|
|
@@ -17973,13 +17907,12 @@ declare const router: {
|
|
|
17973
17907
|
deletedDefinitionTypes: string[];
|
|
17974
17908
|
count: number;
|
|
17975
17909
|
} | null;
|
|
17976
|
-
homepage: {
|
|
17910
|
+
homepage: ({
|
|
17977
17911
|
created: false;
|
|
17978
17912
|
} | {
|
|
17979
17913
|
created: true;
|
|
17980
17914
|
pageId: string;
|
|
17981
|
-
|
|
17982
|
-
} | null;
|
|
17915
|
+
}) | null;
|
|
17983
17916
|
}, {
|
|
17984
17917
|
blocks: {
|
|
17985
17918
|
count: number;
|
|
@@ -18001,13 +17934,12 @@ declare const router: {
|
|
|
18001
17934
|
deletedDefinitionTypes: string[];
|
|
18002
17935
|
count: number;
|
|
18003
17936
|
} | null;
|
|
18004
|
-
homepage: {
|
|
17937
|
+
homepage: ({
|
|
18005
17938
|
created: false;
|
|
18006
17939
|
} | {
|
|
18007
17940
|
created: true;
|
|
18008
17941
|
pageId: string;
|
|
18009
|
-
|
|
18010
|
-
} | null;
|
|
17942
|
+
}) | null;
|
|
18011
17943
|
}>, Record<never, never>, Record<never, never>>;
|
|
18012
17944
|
};
|
|
18013
17945
|
drafts: {
|
|
@@ -18126,7 +18058,6 @@ declare const router: {
|
|
|
18126
18058
|
};
|
|
18127
18059
|
}>, import("zod").ZodObject<{
|
|
18128
18060
|
projectId: import("zod").ZodNumber;
|
|
18129
|
-
name: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
|
|
18130
18061
|
}, import("zod/v4/core").$strip>, import("@orpc/server").Schema<DraftSummary, DraftSummary>, Record<never, never>, Record<never, never>>;
|
|
18131
18062
|
get: import("@orpc/server").DecoratedProcedure<import("@orpc/server").MergedInitialContext<import("@orpc/server").MergedInitialContext<import("@orpc/server").MergedInitialContext<BaseContext & Record<never, never>, BaseContext, BaseContext>, import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>>, import("@orpc/server").MergedCurrentContext<import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, {
|
|
18132
18063
|
draft: DraftRequest | null;
|
|
@@ -18179,58 +18110,6 @@ declare const router: {
|
|
|
18179
18110
|
}>, import("zod").ZodObject<{
|
|
18180
18111
|
projectId: import("zod").ZodNumber;
|
|
18181
18112
|
}, import("zod/v4/core").$strip>, import("@orpc/server").Schema<DraftSummary, DraftSummary>, Record<never, never>, Record<never, never>>;
|
|
18182
|
-
rename: import("@orpc/server").DecoratedProcedure<import("@orpc/server").MergedInitialContext<import("@orpc/server").MergedInitialContext<import("@orpc/server").MergedInitialContext<BaseContext & Record<never, never>, BaseContext, BaseContext>, import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>>, import("@orpc/server").MergedCurrentContext<import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, {
|
|
18183
|
-
draft: DraftRequest | null;
|
|
18184
|
-
locale: string | undefined;
|
|
18185
|
-
publishingDraft: string | undefined;
|
|
18186
|
-
look: LookGrant | undefined;
|
|
18187
|
-
}>, import("@orpc/server").MergedCurrentContext<import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, {
|
|
18188
|
-
draft: DraftRequest | null;
|
|
18189
|
-
locale: string | undefined;
|
|
18190
|
-
publishingDraft: string | undefined;
|
|
18191
|
-
look: LookGrant | undefined;
|
|
18192
|
-
}>>, import("@orpc/server").MergedCurrentContext<import("@orpc/server").MergedCurrentContext<import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, {
|
|
18193
|
-
draft: DraftRequest | null;
|
|
18194
|
-
locale: string | undefined;
|
|
18195
|
-
publishingDraft: string | undefined;
|
|
18196
|
-
look: LookGrant | undefined;
|
|
18197
|
-
}>, {
|
|
18198
|
-
db: Database;
|
|
18199
|
-
env: Bindings;
|
|
18200
|
-
headers: Headers;
|
|
18201
|
-
client: string;
|
|
18202
|
-
telemetryDisabled: boolean;
|
|
18203
|
-
waitUntil: (promise: Promise<unknown>) => void;
|
|
18204
|
-
apiOrigin?: string;
|
|
18205
|
-
draft: DraftRequest | null;
|
|
18206
|
-
locale: string | undefined;
|
|
18207
|
-
publishingDraft: string | undefined;
|
|
18208
|
-
look: LookGrant | undefined;
|
|
18209
|
-
user: {
|
|
18210
|
-
id: string;
|
|
18211
|
-
createdAt: Date;
|
|
18212
|
-
updatedAt: Date;
|
|
18213
|
-
email: string;
|
|
18214
|
-
emailVerified: boolean;
|
|
18215
|
-
name: string;
|
|
18216
|
-
image?: string | null | undefined;
|
|
18217
|
-
};
|
|
18218
|
-
session: {
|
|
18219
|
-
id: string;
|
|
18220
|
-
createdAt: Date;
|
|
18221
|
-
updatedAt: Date;
|
|
18222
|
-
userId: string;
|
|
18223
|
-
expiresAt: Date;
|
|
18224
|
-
token: string;
|
|
18225
|
-
ipAddress?: string | null | undefined;
|
|
18226
|
-
userAgent?: string | null | undefined;
|
|
18227
|
-
activeOrganizationId?: string | null | undefined;
|
|
18228
|
-
studio?: boolean | null | undefined;
|
|
18229
|
-
};
|
|
18230
|
-
}>, import("zod").ZodObject<{
|
|
18231
|
-
projectId: import("zod").ZodNumber;
|
|
18232
|
-
name: import("zod").ZodNullable<import("zod").ZodString>;
|
|
18233
|
-
}, import("zod/v4/core").$strip>, import("@orpc/server").Schema<DraftSummary, DraftSummary>, Record<never, never>, Record<never, never>>;
|
|
18234
18113
|
previewPublish: import("@orpc/server").DecoratedProcedure<import("@orpc/server").MergedInitialContext<import("@orpc/server").MergedInitialContext<import("@orpc/server").MergedInitialContext<BaseContext & Record<never, never>, BaseContext, BaseContext>, import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>>, import("@orpc/server").MergedCurrentContext<import("@orpc/server").MergedCurrentContext<BaseContext, Record<never, never>>, {
|
|
18235
18114
|
draft: DraftRequest | null;
|
|
18236
18115
|
locale: string | undefined;
|
|
@@ -18314,7 +18193,6 @@ declare const router: {
|
|
|
18314
18193
|
status: "pending";
|
|
18315
18194
|
} | {
|
|
18316
18195
|
status: "ready";
|
|
18317
|
-
name: string | null;
|
|
18318
18196
|
headline: string;
|
|
18319
18197
|
bullets: string[];
|
|
18320
18198
|
stale: boolean;
|
|
@@ -18357,7 +18235,6 @@ declare const router: {
|
|
|
18357
18235
|
status: "pending";
|
|
18358
18236
|
} | {
|
|
18359
18237
|
status: "ready";
|
|
18360
|
-
name: string | null;
|
|
18361
18238
|
headline: string;
|
|
18362
18239
|
bullets: string[];
|
|
18363
18240
|
stale: boolean;
|
package/dist/threads.d.ts
CHANGED
|
@@ -34,8 +34,8 @@ export declare const BUILD_STATUS_ENTRY = "camox.build-status";
|
|
|
34
34
|
export declare const RECONCILE_ENTRY = "camox.reconcile";
|
|
35
35
|
/**
|
|
36
36
|
* The kind of the transcript entry opening a draft's thread a Live thread handed a request off
|
|
37
|
-
* to: the Brief, which the model reads
|
|
38
|
-
*
|
|
37
|
+
* to: the Brief, which the model reads ahead of the editor's messages, and editors see collapsed
|
|
38
|
+
* after them, so the request reads on as they sent it. In a draft Camox opened, such as its Patrol Draft, Camox's own messages are Briefs
|
|
39
39
|
* too, with their `operationId` as data, and start the agent's run, which acts for Camox.
|
|
40
40
|
*/
|
|
41
41
|
export declare const BRIEF_ENTRY = "camox.brief";
|
|
@@ -48,8 +48,8 @@ export declare const DRAFT_ENDED_ENTRY = "camox.draft-ended";
|
|
|
48
48
|
/**
|
|
49
49
|
* The kind of the transcript entry a Live thread starts afresh from once its agent handed a
|
|
50
50
|
* request off to a draft (ADR 0036): a reset of Pi's context, with a `startedDraftCardSchema` as
|
|
51
|
-
* data. Editors see
|
|
52
|
-
*
|
|
51
|
+
* data. Editors see an empty thread, and the model reads a note naming the draft. Everything
|
|
52
|
+
* before it is left out of both.
|
|
53
53
|
*/
|
|
54
54
|
export declare const DRAFT_CARD_ENTRY = "camox.draft-card";
|
|
55
55
|
/**
|
|
@@ -330,6 +330,15 @@ export type ThreadMessage = {
|
|
|
330
330
|
from: "camox";
|
|
331
331
|
text: string;
|
|
332
332
|
} |
|
|
333
|
+
/**
|
|
334
|
+
* The Brief the agent on Live wrote as it handed the request off to the draft, shown after the
|
|
335
|
+
* editor's messages it opened the thread with, though the model reads it before them.
|
|
336
|
+
*/
|
|
337
|
+
{
|
|
338
|
+
id: string;
|
|
339
|
+
from: "brief";
|
|
340
|
+
text: string;
|
|
341
|
+
} |
|
|
333
342
|
/** The agent's final message of a turn, in Markdown. */
|
|
334
343
|
{
|
|
335
344
|
id: string;
|
|
@@ -470,6 +479,11 @@ type ThreadStep = {
|
|
|
470
479
|
{
|
|
471
480
|
type: "camox";
|
|
472
481
|
text: string;
|
|
482
|
+
} |
|
|
483
|
+
/** The Brief opening a draft's thread a Live thread handed a request off to. */
|
|
484
|
+
{
|
|
485
|
+
type: "brief";
|
|
486
|
+
text: string;
|
|
473
487
|
} | {
|
|
474
488
|
type: "answer";
|
|
475
489
|
text: string;
|
package/dist/threads.js
CHANGED
|
@@ -32,8 +32,8 @@ const BUILD_STATUS_ENTRY = "camox.build-status";
|
|
|
32
32
|
const RECONCILE_ENTRY = "camox.reconcile";
|
|
33
33
|
/**
|
|
34
34
|
* The kind of the transcript entry opening a draft's thread a Live thread handed a request off
|
|
35
|
-
* to: the Brief, which the model reads
|
|
36
|
-
*
|
|
35
|
+
* to: the Brief, which the model reads ahead of the editor's messages, and editors see collapsed
|
|
36
|
+
* after them, so the request reads on as they sent it. In a draft Camox opened, such as its Patrol Draft, Camox's own messages are Briefs
|
|
37
37
|
* too, with their `operationId` as data, and start the agent's run, which acts for Camox.
|
|
38
38
|
*/
|
|
39
39
|
const BRIEF_ENTRY = "camox.brief";
|
|
@@ -46,8 +46,8 @@ const DRAFT_ENDED_ENTRY = "camox.draft-ended";
|
|
|
46
46
|
/**
|
|
47
47
|
* The kind of the transcript entry a Live thread starts afresh from once its agent handed a
|
|
48
48
|
* request off to a draft (ADR 0036): a reset of Pi's context, with a `startedDraftCardSchema` as
|
|
49
|
-
* data. Editors see
|
|
50
|
-
*
|
|
49
|
+
* data. Editors see an empty thread, and the model reads a note naming the draft. Everything
|
|
50
|
+
* before it is left out of both.
|
|
51
51
|
*/
|
|
52
52
|
const DRAFT_CARD_ENTRY = "camox.draft-card";
|
|
53
53
|
/**
|
|
@@ -375,14 +375,7 @@ function threadStepOf(entry) {
|
|
|
375
375
|
...push
|
|
376
376
|
};
|
|
377
377
|
}
|
|
378
|
-
if (entry.kind === "camox.draft-card")
|
|
379
|
-
const card = startedDraftCardSchema.safeParse(entry.data).data;
|
|
380
|
-
return card && {
|
|
381
|
-
id,
|
|
382
|
-
type: "draft",
|
|
383
|
-
...card
|
|
384
|
-
};
|
|
385
|
-
}
|
|
378
|
+
if (entry.kind === "camox.draft-card") return void 0;
|
|
386
379
|
const message = entry.model?.find((candidate) => candidate.role !== "system");
|
|
387
380
|
if (!message) return void 0;
|
|
388
381
|
if (message.role === "user") {
|
|
@@ -407,7 +400,7 @@ function threadStepOf(entry) {
|
|
|
407
400
|
}
|
|
408
401
|
if (entry.kind === "camox.brief") return {
|
|
409
402
|
id,
|
|
410
|
-
type: "camox",
|
|
403
|
+
type: z.object({ operationId: z.string() }).safeParse(entry.data).success ? "camox" : "brief",
|
|
411
404
|
text: textOf(message.content)
|
|
412
405
|
};
|
|
413
406
|
if (entry.kind === "camox.reconcile") {
|
|
@@ -474,101 +467,118 @@ function threadViewOf({ steps, running, toolCalls = [], callingTools = false, ch
|
|
|
474
467
|
});
|
|
475
468
|
endTurn();
|
|
476
469
|
};
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
id: step.id,
|
|
492
|
-
from: "connectedAgent",
|
|
493
|
-
member: step.member,
|
|
494
|
-
client: step.client,
|
|
495
|
-
text: step.text
|
|
496
|
-
});
|
|
497
|
-
waiting = step.id;
|
|
498
|
-
break;
|
|
499
|
-
case "camox":
|
|
500
|
-
if (unfinished) fail();
|
|
501
|
-
messages.push({
|
|
502
|
-
id: step.id,
|
|
503
|
-
from: "camox",
|
|
504
|
-
text: step.text
|
|
505
|
-
});
|
|
506
|
-
waiting = step.id;
|
|
507
|
-
break;
|
|
508
|
-
case "stopped":
|
|
509
|
-
if (waiting === void 0) break;
|
|
510
|
-
messages.push({
|
|
511
|
-
id: step.id,
|
|
512
|
-
from: "stopped",
|
|
513
|
-
sender: step.sender
|
|
514
|
-
});
|
|
515
|
-
endTurn();
|
|
516
|
-
break;
|
|
517
|
-
case "answer":
|
|
518
|
-
if (waiting === void 0 && messages.at(-1)?.from === "stopped") break;
|
|
519
|
-
messages.push({
|
|
520
|
-
id: step.id,
|
|
521
|
-
from: "agent",
|
|
522
|
-
text: step.text
|
|
523
|
-
});
|
|
524
|
-
{
|
|
525
|
-
const before = {
|
|
526
|
-
waiting,
|
|
527
|
-
status
|
|
470
|
+
/** A hand-off's Brief, shown once the editors' messages it opened the thread with are. */
|
|
471
|
+
let brief;
|
|
472
|
+
const showBrief = () => {
|
|
473
|
+
if (brief) messages.push(brief);
|
|
474
|
+
brief = void 0;
|
|
475
|
+
};
|
|
476
|
+
for (const step of steps) {
|
|
477
|
+
if (step.type !== "editor" && step.type !== "connectedAgent") showBrief();
|
|
478
|
+
switch (step.type) {
|
|
479
|
+
case "brief":
|
|
480
|
+
brief = {
|
|
481
|
+
id: step.id,
|
|
482
|
+
from: "brief",
|
|
483
|
+
text: step.text
|
|
528
484
|
};
|
|
485
|
+
break;
|
|
486
|
+
case "editor":
|
|
487
|
+
if (unfinished) fail();
|
|
488
|
+
messages.push({
|
|
489
|
+
id: step.id,
|
|
490
|
+
from: "editor",
|
|
491
|
+
sender: step.sender,
|
|
492
|
+
text: step.text
|
|
493
|
+
});
|
|
494
|
+
waiting = step.id;
|
|
495
|
+
break;
|
|
496
|
+
case "connectedAgent":
|
|
497
|
+
if (unfinished) fail();
|
|
498
|
+
messages.push({
|
|
499
|
+
id: step.id,
|
|
500
|
+
from: "connectedAgent",
|
|
501
|
+
member: step.member,
|
|
502
|
+
client: step.client,
|
|
503
|
+
text: step.text
|
|
504
|
+
});
|
|
505
|
+
waiting = step.id;
|
|
506
|
+
break;
|
|
507
|
+
case "camox":
|
|
508
|
+
if (unfinished) fail();
|
|
509
|
+
messages.push({
|
|
510
|
+
id: step.id,
|
|
511
|
+
from: "camox",
|
|
512
|
+
text: step.text
|
|
513
|
+
});
|
|
514
|
+
waiting = step.id;
|
|
515
|
+
break;
|
|
516
|
+
case "stopped":
|
|
517
|
+
if (waiting === void 0) break;
|
|
518
|
+
messages.push({
|
|
519
|
+
id: step.id,
|
|
520
|
+
from: "stopped",
|
|
521
|
+
sender: step.sender
|
|
522
|
+
});
|
|
523
|
+
endTurn();
|
|
524
|
+
break;
|
|
525
|
+
case "answer":
|
|
526
|
+
if (waiting === void 0 && messages.at(-1)?.from === "stopped") break;
|
|
527
|
+
messages.push({
|
|
528
|
+
id: step.id,
|
|
529
|
+
from: "agent",
|
|
530
|
+
text: step.text
|
|
531
|
+
});
|
|
532
|
+
{
|
|
533
|
+
const before = {
|
|
534
|
+
waiting,
|
|
535
|
+
status
|
|
536
|
+
};
|
|
537
|
+
endTurn();
|
|
538
|
+
answered = before;
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
541
|
+
case "draft":
|
|
542
|
+
if (waiting === void 0 && messages.at(-1)?.from === "stopped") break;
|
|
543
|
+
{
|
|
544
|
+
const draft = drafts[step.draftId];
|
|
545
|
+
messages.push({
|
|
546
|
+
id: step.id,
|
|
547
|
+
from: "draft",
|
|
548
|
+
draftId: step.draftId,
|
|
549
|
+
name: draft?.name ?? step.name,
|
|
550
|
+
...draft?.ended && { ended: draft.ended }
|
|
551
|
+
});
|
|
552
|
+
}
|
|
529
553
|
endTurn();
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
554
|
+
break;
|
|
555
|
+
case "continued":
|
|
556
|
+
if (!answered) break;
|
|
557
|
+
if (messages.at(-1)?.from === "agent") messages.pop();
|
|
558
|
+
waiting = answered.waiting;
|
|
559
|
+
status = answered.status === "fixing" ? "fixing" : void 0;
|
|
560
|
+
answered = void 0;
|
|
561
|
+
break;
|
|
562
|
+
case "build":
|
|
563
|
+
status = step.status;
|
|
564
|
+
break;
|
|
565
|
+
case "push":
|
|
537
566
|
messages.push({
|
|
538
567
|
id: step.id,
|
|
539
|
-
from: "
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
568
|
+
from: "push",
|
|
569
|
+
sender: step.pusher,
|
|
570
|
+
subjects: step.subjects,
|
|
571
|
+
outcome: step.outcome
|
|
543
572
|
});
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
status = answered.status === "fixing" ? "fixing" : void 0;
|
|
552
|
-
answered = void 0;
|
|
553
|
-
break;
|
|
554
|
-
case "build":
|
|
555
|
-
status = step.status;
|
|
556
|
-
break;
|
|
557
|
-
case "push":
|
|
558
|
-
messages.push({
|
|
559
|
-
id: step.id,
|
|
560
|
-
from: "push",
|
|
561
|
-
sender: step.pusher,
|
|
562
|
-
subjects: step.subjects,
|
|
563
|
-
outcome: step.outcome
|
|
564
|
-
});
|
|
565
|
-
break;
|
|
566
|
-
case "tools":
|
|
567
|
-
unfinished = false;
|
|
568
|
-
status = void 0;
|
|
569
|
-
break;
|
|
570
|
-
case "unfinished": unfinished = true;
|
|
573
|
+
break;
|
|
574
|
+
case "tools":
|
|
575
|
+
unfinished = false;
|
|
576
|
+
status = void 0;
|
|
577
|
+
break;
|
|
578
|
+
case "unfinished": unfinished = true;
|
|
579
|
+
}
|
|
571
580
|
}
|
|
581
|
+
showBrief();
|
|
572
582
|
if (!running) fail();
|
|
573
583
|
if (!running) return {
|
|
574
584
|
messages,
|
|
@@ -607,7 +617,7 @@ const callsChangingTool = (block) => block.type === "toolCall" && changes(block.
|
|
|
607
617
|
const callsLook = (block) => block.type === "toolCall" && block.name === "look";
|
|
608
618
|
/**
|
|
609
619
|
* Adds an entry to the thread's state as Pi places it. An entry heading a new context, such as
|
|
610
|
-
* the
|
|
620
|
+
* the one a Live thread starts afresh from, leaves out every step before its head, as Pi's
|
|
611
621
|
* snapshots do.
|
|
612
622
|
*/
|
|
613
623
|
const append = (state, entry) => {
|
package/package.json
CHANGED
package/src/drafts.ts
CHANGED
|
@@ -50,9 +50,9 @@ export const LOOK_LOCALE_PARAM = "locale";
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* The look document's Block Definition mode: instead of a page, the block of the Block Definition
|
|
53
|
-
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with
|
|
54
|
-
*
|
|
55
|
-
* the shape the content tools take.
|
|
53
|
+
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with empty fields and the
|
|
54
|
+
* content and Block Settings `LOOK_CONTENT_PARAM` and `LOOK_SETTINGS_PARAM` give as JSON merged
|
|
55
|
+
* on, in the shape the content tools take.
|
|
56
56
|
*/
|
|
57
57
|
export const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
58
58
|
export const LOOK_CONTENT_PARAM = "content";
|
|
@@ -60,8 +60,8 @@ export const LOOK_SETTINGS_PARAM = "settings";
|
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* The look document's Layout Definition mode: instead of a page, the curated Layout
|
|
63
|
-
* `LOOK_LAYOUT_DEFINITION_PARAM` names, alone in the site's shell, its blocks with
|
|
64
|
-
* content and Block Settings
|
|
63
|
+
* `LOOK_LAYOUT_DEFINITION_PARAM` names, alone in the site's shell, its blocks with empty fields
|
|
64
|
+
* and the content and Block Settings `LOOK_BLOCKS_PARAM` gives as JSON merged on, by Block
|
|
65
65
|
* Definition name (`{ navbar: { content, settings } }`), around a labelled placeholder where a
|
|
66
66
|
* page's content goes, as tall as `LOOK_PLACEHOLDER_PARAM` says: one of `LOOK_PLACEHOLDER_HEIGHTS`,
|
|
67
67
|
* the first without.
|
|
@@ -80,6 +80,64 @@ export type LookPlaceholderHeight = (typeof LOOK_PLACEHOLDER_HEIGHTS)[number];
|
|
|
80
80
|
*/
|
|
81
81
|
export const UNPLACED_BLOCK_ID = "unplaced";
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* The attributes the website's artifact frames carry: the artifact field's name, and the id of the
|
|
85
|
+
* Repeatable Item holding it, when an item's. With the block's `data-camox-viewport-block`, they
|
|
86
|
+
* find one artifact's frame (`lookArtifactSelector`).
|
|
87
|
+
*/
|
|
88
|
+
export const ARTIFACT_FIELD_ATTRIBUTE = "data-camox-artifact";
|
|
89
|
+
export const ARTIFACT_ITEM_ATTRIBUTE = "data-camox-item";
|
|
90
|
+
|
|
91
|
+
/** The CSS selector of the frame of an artifact field of a block, or of one of its items. */
|
|
92
|
+
export const lookArtifactSelector = ({
|
|
93
|
+
block,
|
|
94
|
+
item,
|
|
95
|
+
field,
|
|
96
|
+
}: {
|
|
97
|
+
block: string;
|
|
98
|
+
item?: string;
|
|
99
|
+
field: string;
|
|
100
|
+
}) =>
|
|
101
|
+
`[data-camox-viewport-block="${block}"] iframe[${ARTIFACT_FIELD_ATTRIBUTE}="${field}"]` +
|
|
102
|
+
(item ? `[${ARTIFACT_ITEM_ATTRIBUTE}="${item}"]` : `:not([${ARTIFACT_ITEM_ATTRIBUTE}])`);
|
|
103
|
+
|
|
104
|
+
/** An artifact's Timeline, as its runtime declares it: Marks by name, at times in ms. */
|
|
105
|
+
export type LookTimeline = {
|
|
106
|
+
duration: number;
|
|
107
|
+
loop: boolean;
|
|
108
|
+
marks: Record<string, number>;
|
|
109
|
+
/** The Mark whose frame stands for the artifact, or null. */
|
|
110
|
+
poster: string | null;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* One finding of an artifact's guardrail report, about motion that escapes its Timeline or will
|
|
115
|
+
* look broken: a Web Animation the runtime didn't make (a CSS animation, a CSS transition that no
|
|
116
|
+
* visitor triggered, one the source made itself), a live timer, a Track the runtime skipped
|
|
117
|
+
* because it can't play it, Tracks on one element and property that overlap, or a loop cut,
|
|
118
|
+
* where a looping Timeline's last frame differs from its first.
|
|
119
|
+
*/
|
|
120
|
+
export type LookGuardrailFinding = {
|
|
121
|
+
kind: "animation" | "timer" | "track" | "overlap" | "loop-cut";
|
|
122
|
+
/** What's wrong and what to do instead, for the Artifact Agent. */
|
|
123
|
+
text: string;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* What the look document's artifact frames hold under `LOOK_ARTIFACT_CAPTURE`, for the browser
|
|
128
|
+
* `look` drives: the artifact's Timeline, null when it declares none; seeking it to `t` ms,
|
|
129
|
+
* resolved once the frame at that time painted, with the error `render` threw, if it did; and its
|
|
130
|
+
* guardrail report, empty when nothing escapes its Timeline. Frames of an SDK older than
|
|
131
|
+
* Timelines hold nothing there.
|
|
132
|
+
*/
|
|
133
|
+
export type LookArtifactCapture = {
|
|
134
|
+
timeline(): Promise<LookTimeline | null>;
|
|
135
|
+
seek(t: number): Promise<{ error?: string }>;
|
|
136
|
+
guardrail(): Promise<LookGuardrailFinding[]>;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const LOOK_ARTIFACT_CAPTURE = "camoxCapture";
|
|
140
|
+
|
|
83
141
|
/**
|
|
84
142
|
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
85
143
|
* exist yet. Its value is `"1"`.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a field holds before anyone writes it: the empty value of its kind. Fields declare no
|
|
3
|
+
* default, so content missing a field, or holding a value of the wrong kind, reads as this.
|
|
4
|
+
* Shared by the SDK (rendering, new repeatable items, authoring forms) and the API (creating
|
|
5
|
+
* content, conforming it on read), so both agree on what an unset field is.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** A link that goes nowhere yet. */
|
|
9
|
+
export const EMPTY_LINK = { type: "external", text: "", href: "", newTab: false } as const;
|
|
10
|
+
|
|
11
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The empty value of a field, from its stored JSON Schema (`fieldType` and, for an enum, its
|
|
17
|
+
* options): `""` for text, a link to nowhere, `false`, an enum's first option, `null` for one
|
|
18
|
+
* asset or record, and `[]` for lists and repeaters. A fresh copy each call.
|
|
19
|
+
*/
|
|
20
|
+
export function emptyFieldValue(fieldSchema: unknown): unknown {
|
|
21
|
+
const schema = isObject(fieldSchema) ? fieldSchema : {};
|
|
22
|
+
switch (schema.fieldType) {
|
|
23
|
+
case "Link":
|
|
24
|
+
return { ...EMPTY_LINK };
|
|
25
|
+
case "Boolean":
|
|
26
|
+
return false;
|
|
27
|
+
case "Enum": {
|
|
28
|
+
const options = Array.isArray(schema.enum) ? schema.enum : [];
|
|
29
|
+
const first = options.find((option) => typeof option === "string");
|
|
30
|
+
return first ?? "";
|
|
31
|
+
}
|
|
32
|
+
case "Image":
|
|
33
|
+
case "File":
|
|
34
|
+
case "Reference":
|
|
35
|
+
return null;
|
|
36
|
+
case "ImageList":
|
|
37
|
+
case "FileList":
|
|
38
|
+
case "ReferenceList":
|
|
39
|
+
case "Repeater":
|
|
40
|
+
return [];
|
|
41
|
+
default:
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The empty value of every field of a content or settings schema, by name. */
|
|
47
|
+
export function emptyFieldValues(schema: unknown): Record<string, unknown> {
|
|
48
|
+
const properties = isObject(schema) && isObject(schema.properties) ? schema.properties : {};
|
|
49
|
+
return Object.fromEntries(
|
|
50
|
+
Object.entries(properties).map(([name, field]) => [name, emptyFieldValue(field)]),
|
|
51
|
+
);
|
|
52
|
+
}
|
package/src/index.ts
CHANGED
package/src/threads.ts
CHANGED
|
@@ -44,8 +44,8 @@ export const RECONCILE_ENTRY = "camox.reconcile";
|
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* The kind of the transcript entry opening a draft's thread a Live thread handed a request off
|
|
47
|
-
* to: the Brief, which the model reads
|
|
48
|
-
*
|
|
47
|
+
* to: the Brief, which the model reads ahead of the editor's messages, and editors see collapsed
|
|
48
|
+
* after them, so the request reads on as they sent it. In a draft Camox opened, such as its Patrol Draft, Camox's own messages are Briefs
|
|
49
49
|
* too, with their `operationId` as data, and start the agent's run, which acts for Camox.
|
|
50
50
|
*/
|
|
51
51
|
export const BRIEF_ENTRY = "camox.brief";
|
|
@@ -60,8 +60,8 @@ export const DRAFT_ENDED_ENTRY = "camox.draft-ended";
|
|
|
60
60
|
/**
|
|
61
61
|
* The kind of the transcript entry a Live thread starts afresh from once its agent handed a
|
|
62
62
|
* request off to a draft (ADR 0036): a reset of Pi's context, with a `startedDraftCardSchema` as
|
|
63
|
-
* data. Editors see
|
|
64
|
-
*
|
|
63
|
+
* data. Editors see an empty thread, and the model reads a note naming the draft. Everything
|
|
64
|
+
* before it is left out of both.
|
|
65
65
|
*/
|
|
66
66
|
export const DRAFT_CARD_ENTRY = "camox.draft-card";
|
|
67
67
|
|
|
@@ -302,6 +302,11 @@ export type ThreadMessage =
|
|
|
302
302
|
}
|
|
303
303
|
/** Camox's own message, starting a turn it began itself: why it did. */
|
|
304
304
|
| { id: string; from: "camox"; text: string }
|
|
305
|
+
/**
|
|
306
|
+
* The Brief the agent on Live wrote as it handed the request off to the draft, shown after the
|
|
307
|
+
* editor's messages it opened the thread with, though the model reads it before them.
|
|
308
|
+
*/
|
|
309
|
+
| { id: string; from: "brief"; text: string }
|
|
305
310
|
/** The agent's final message of a turn, in Markdown. */
|
|
306
311
|
| { id: string; from: "agent"; text: string }
|
|
307
312
|
/**
|
|
@@ -406,6 +411,8 @@ type ThreadStep = { id: string } & (
|
|
|
406
411
|
| { type: "connectedAgent"; member: ThreadSender; client: ConnectedAgentClient; text: string }
|
|
407
412
|
/** Camox starting a turn of its own, saying why. */
|
|
408
413
|
| { type: "camox"; text: string }
|
|
414
|
+
/** The Brief opening a draft's thread a Live thread handed a request off to. */
|
|
415
|
+
| { type: "brief"; text: string }
|
|
409
416
|
| { type: "answer"; text: string }
|
|
410
417
|
/** A round of tool calls, or their results: the run goes on after it. */
|
|
411
418
|
| { type: "tools" }
|
|
@@ -560,11 +567,8 @@ function threadStepOf(entry: EntryRecord): ThreadStep | undefined {
|
|
|
560
567
|
const push = pushDataSchema.safeParse(entry.data).data;
|
|
561
568
|
return push && { id, type: "push", ...push };
|
|
562
569
|
}
|
|
563
|
-
//
|
|
564
|
-
if (entry.kind === DRAFT_CARD_ENTRY)
|
|
565
|
-
const card = startedDraftCardSchema.safeParse(entry.data).data;
|
|
566
|
-
return card && { id, type: "draft", ...card };
|
|
567
|
-
}
|
|
570
|
+
// Only the model reads it, as a note naming the draft: editors see the Live thread start empty.
|
|
571
|
+
if (entry.kind === DRAFT_CARD_ENTRY) return undefined;
|
|
568
572
|
const message = entry.model?.find((candidate) => candidate.role !== "system");
|
|
569
573
|
if (!message) return undefined;
|
|
570
574
|
if (message.role === "user") {
|
|
@@ -583,7 +587,12 @@ function threadStepOf(entry: EntryRecord): ThreadStep | undefined {
|
|
|
583
587
|
}
|
|
584
588
|
);
|
|
585
589
|
}
|
|
586
|
-
if (entry.kind === BRIEF_ENTRY)
|
|
590
|
+
if (entry.kind === BRIEF_ENTRY) {
|
|
591
|
+
// Only Camox's own messages, in a draft it opened, carry an operation id: a hand-off's
|
|
592
|
+
// Brief is written ahead of the editor's messages, which start the run.
|
|
593
|
+
const own = z.object({ operationId: z.string() }).safeParse(entry.data).success;
|
|
594
|
+
return { id, type: own ? "camox" : "brief", text: textOf(message.content) };
|
|
595
|
+
}
|
|
587
596
|
if (entry.kind === RECONCILE_ENTRY) {
|
|
588
597
|
const reconcile = reconcileDataSchema.safeParse(entry.data).data;
|
|
589
598
|
return reconcile && { id, type: "camox", text: reconcile.message };
|
|
@@ -648,9 +657,19 @@ export function threadViewOf({
|
|
|
648
657
|
if (waiting !== undefined) messages.push({ id: `${waiting}:failed`, from: "failed" });
|
|
649
658
|
endTurn();
|
|
650
659
|
};
|
|
660
|
+
/** A hand-off's Brief, shown once the editors' messages it opened the thread with are. */
|
|
661
|
+
let brief: Extract<ThreadMessage, { from: "brief" }> | undefined;
|
|
662
|
+
const showBrief = () => {
|
|
663
|
+
if (brief) messages.push(brief);
|
|
664
|
+
brief = undefined;
|
|
665
|
+
};
|
|
651
666
|
|
|
652
667
|
for (const step of steps) {
|
|
668
|
+
if (step.type !== "editor" && step.type !== "connectedAgent") showBrief();
|
|
653
669
|
switch (step.type) {
|
|
670
|
+
case "brief":
|
|
671
|
+
brief = { id: step.id, from: "brief", text: step.text };
|
|
672
|
+
break;
|
|
654
673
|
case "editor":
|
|
655
674
|
// Pi places a steering message only once a model call is settled: after a round of tool
|
|
656
675
|
// calls, or with the answer ending the run. Never between a failed call and its retry, so
|
|
@@ -738,6 +757,7 @@ export function threadViewOf({
|
|
|
738
757
|
break;
|
|
739
758
|
}
|
|
740
759
|
}
|
|
760
|
+
showBrief();
|
|
741
761
|
if (!running) fail();
|
|
742
762
|
if (!running) return { messages, running };
|
|
743
763
|
return {
|
|
@@ -798,7 +818,7 @@ const callsLook = (block: AssistantMessage["content"][number]) =>
|
|
|
798
818
|
|
|
799
819
|
/**
|
|
800
820
|
* Adds an entry to the thread's state as Pi places it. An entry heading a new context, such as
|
|
801
|
-
* the
|
|
821
|
+
* the one a Live thread starts afresh from, leaves out every step before its head, as Pi's
|
|
802
822
|
* snapshots do.
|
|
803
823
|
*/
|
|
804
824
|
const append = (state: ThreadState, entry: EntryRecord | undefined): ThreadState => {
|