@camox/api-contract 0.66.0 → 0.67.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 +14 -0
- package/dist/drafts.js +14 -1
- package/dist/patrol.d.ts +10 -14
- package/dist/patrol.js +9 -5
- package/dist/router.d.ts +180 -7
- package/dist/threads.d.ts +31 -8
- package/dist/threads.js +40 -19
- package/package.json +1 -1
- package/src/drafts.ts +15 -0
- package/src/patrol.ts +15 -15
- package/src/threads.ts +67 -27
package/dist/drafts.d.ts
CHANGED
|
@@ -49,6 +49,20 @@ export declare const LOOK_LOCALE_PARAM = "locale";
|
|
|
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
|
+
/**
|
|
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 their default
|
|
55
|
+
* content and Block Settings and the overrides `LOOK_BLOCKS_PARAM` gives as JSON, by Block
|
|
56
|
+
* Definition name (`{ navbar: { content, settings } }`), around a labelled placeholder where a
|
|
57
|
+
* page's content goes, as tall as `LOOK_PLACEHOLDER_PARAM` says: one of `LOOK_PLACEHOLDER_HEIGHTS`,
|
|
58
|
+
* the first without.
|
|
59
|
+
*/
|
|
60
|
+
export declare const LOOK_LAYOUT_DEFINITION_PARAM = "layoutDefinition";
|
|
61
|
+
export declare const LOOK_BLOCKS_PARAM = "blocks";
|
|
62
|
+
export declare const LOOK_PLACEHOLDER_PARAM = "placeholder";
|
|
63
|
+
/** A short placeholder shows whether the footer rises up the screen; a tall one, scrolling. */
|
|
64
|
+
export declare const LOOK_PLACEHOLDER_HEIGHTS: readonly ["short", "tall"];
|
|
65
|
+
export type LookPlaceholderHeight = (typeof LOOK_PLACEHOLDER_HEIGHTS)[number];
|
|
52
66
|
/**
|
|
53
67
|
* The id of a block shown without being placed, as the look document's Block Definition mode
|
|
54
68
|
* shows it: never a stored block's, which are UUIDs. Its element is
|
package/dist/drafts.js
CHANGED
|
@@ -50,6 +50,19 @@ const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
|
50
50
|
const LOOK_CONTENT_PARAM = "content";
|
|
51
51
|
const LOOK_SETTINGS_PARAM = "settings";
|
|
52
52
|
/**
|
|
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 their default
|
|
55
|
+
* content and Block Settings and the overrides `LOOK_BLOCKS_PARAM` gives as JSON, by Block
|
|
56
|
+
* Definition name (`{ navbar: { content, settings } }`), around a labelled placeholder where a
|
|
57
|
+
* page's content goes, as tall as `LOOK_PLACEHOLDER_PARAM` says: one of `LOOK_PLACEHOLDER_HEIGHTS`,
|
|
58
|
+
* the first without.
|
|
59
|
+
*/
|
|
60
|
+
const LOOK_LAYOUT_DEFINITION_PARAM = "layoutDefinition";
|
|
61
|
+
const LOOK_BLOCKS_PARAM = "blocks";
|
|
62
|
+
const LOOK_PLACEHOLDER_PARAM = "placeholder";
|
|
63
|
+
/** A short placeholder shows whether the footer rises up the screen; a tall one, scrolling. */
|
|
64
|
+
const LOOK_PLACEHOLDER_HEIGHTS = ["short", "tall"];
|
|
65
|
+
/**
|
|
53
66
|
* The id of a block shown without being placed, as the look document's Block Definition mode
|
|
54
67
|
* shows it: never a stored block's, which are UUIDs. Its element is
|
|
55
68
|
* `[data-camox-viewport-block="unplaced"]`.
|
|
@@ -223,4 +236,4 @@ function isContentWrite(path) {
|
|
|
223
236
|
}
|
|
224
237
|
|
|
225
238
|
//#endregion
|
|
226
|
-
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_BLOCK_DEFINITION_PARAM, LOOK_CONTENT_PARAM, LOOK_DOCUMENT_PATH, LOOK_LOCALE_PARAM, LOOK_PATH_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 };
|
|
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 };
|
package/dist/patrol.d.ts
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* Live, and names each report's subject, so the studio needs no entity loaded to show it.
|
|
6
6
|
*/
|
|
7
7
|
/** Every patroller's stable id. The registry in the API lists them all. */
|
|
8
|
-
export declare const PATROLLER_IDS: readonly ["translator", "seoManager", "linkChecker"
|
|
8
|
+
export declare const PATROLLER_IDS: readonly ["translator", "seoManager", "linkChecker"];
|
|
9
9
|
/** A patroller's stable id. */
|
|
10
10
|
export type PatrollerId = (typeof PATROLLER_IDS)[number];
|
|
11
11
|
/**
|
|
12
12
|
* What a structured report says was done. Each has a failed form, by the report's outcome. A
|
|
13
13
|
* merge with Live's localization reads as a translation.
|
|
14
14
|
*/
|
|
15
|
-
export type ReportVerb = "translated" | "mergedWithLive" | "wroteSeo" | "describedFile" | "publishedCatchUp" | "removedLink" | "fixedLink"
|
|
15
|
+
export type ReportVerb = "translated" | "mergedWithLive" | "wroteSeo" | "describedFile" | "publishedCatchUp" | "removedLink" | "fixedLink";
|
|
16
16
|
/** What a report can be about. */
|
|
17
17
|
export type ReportEntity = "page" | "block" | "sharedContent" | "repeatableItem" | "record" | "file";
|
|
18
18
|
/** A report's subject, named as the Canvas names it, read when the Patrol is. */
|
|
@@ -84,7 +84,6 @@ export type ReportView = {
|
|
|
84
84
|
* What a finding is about (ADR 0034), by its kind:
|
|
85
85
|
* - `missingPage`: a link to a page that doesn't exist, the page's name as it was last known.
|
|
86
86
|
* - `brokenLink`: an external link that failed, and how.
|
|
87
|
-
* - `misspelling`, `grammar`: the flagged text, in the sentence it's in.
|
|
88
87
|
* A link's `url` is as content stores it: a page link's is `camox:page:<id>`, and `text` is what
|
|
89
88
|
* the link reads.
|
|
90
89
|
*/
|
|
@@ -98,10 +97,6 @@ export type FindingAbout = {
|
|
|
98
97
|
url: string;
|
|
99
98
|
text: string;
|
|
100
99
|
failure: LinkFailure;
|
|
101
|
-
} | {
|
|
102
|
-
kind: "misspelling" | "grammar";
|
|
103
|
-
text: string;
|
|
104
|
-
sentence: string;
|
|
105
100
|
};
|
|
106
101
|
/** How a link failed: an HTTP error status, no connection (DNS included), or no answer in time. */
|
|
107
102
|
export type LinkFailure = {
|
|
@@ -113,15 +108,9 @@ export type LinkFailure = {
|
|
|
113
108
|
kind: "timeout";
|
|
114
109
|
};
|
|
115
110
|
export type FindingKind = FindingAbout["kind"];
|
|
116
|
-
/**
|
|
117
|
-
* The fix a finding suggests, which applying makes: removing the link, keeping its text, or
|
|
118
|
-
* replacing the flagged text with `replacement` in its sentence, keeping its formatting.
|
|
119
|
-
*/
|
|
111
|
+
/** The fix a finding suggests, which applying makes: removing the link, keeping its text. */
|
|
120
112
|
export type FindingFix = {
|
|
121
113
|
kind: "removeLink";
|
|
122
|
-
} | {
|
|
123
|
-
kind: "replaceText";
|
|
124
|
-
replacement: string;
|
|
125
114
|
};
|
|
126
115
|
/** A finding, open, in the scope viewed. */
|
|
127
116
|
export type FindingView = {
|
|
@@ -136,6 +125,8 @@ export type FindingView = {
|
|
|
136
125
|
locale: string;
|
|
137
126
|
/** The content field it's in, by name. */
|
|
138
127
|
field: string;
|
|
128
|
+
/** That field's kind, such as "String" or "Link", or null when unknown. */
|
|
129
|
+
fieldKind: string | null;
|
|
139
130
|
/** When it was first raised, in milliseconds since the epoch. */
|
|
140
131
|
raisedAt: number;
|
|
141
132
|
/** Whether it's Live's. Live's are fixed in the Patrol Draft. */
|
|
@@ -148,6 +139,11 @@ export type FindingView = {
|
|
|
148
139
|
* Footer links to About, a page that no longer exists".
|
|
149
140
|
*/
|
|
150
141
|
export declare function findingSentence(finding: Pick<FindingView, "about" | "subject">): string;
|
|
142
|
+
/**
|
|
143
|
+
* A finding as one sentence where its content is already shown, as the studio's sidebar shows it
|
|
144
|
+
* by its field: "“About us” links to About, a page that no longer exists".
|
|
145
|
+
*/
|
|
146
|
+
export declare function findingSentenceInPlace(finding: Pick<FindingView, "about">): string;
|
|
151
147
|
/** A member's dismissal of what a finding was about: no finding like it is raised again. */
|
|
152
148
|
export type DismissalView = {
|
|
153
149
|
id: number;
|
package/dist/patrol.js
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
const PATROLLER_IDS = [
|
|
9
9
|
"translator",
|
|
10
10
|
"seoManager",
|
|
11
|
-
"linkChecker"
|
|
12
|
-
"proofreader"
|
|
11
|
+
"linkChecker"
|
|
13
12
|
];
|
|
14
13
|
/** The locale a summary's work was in: a structured summary's, if any. A text summary has none. */
|
|
15
14
|
const reportLocale = (summary) => summary.kind === "structured" ? summary.locale : null;
|
|
@@ -22,8 +21,6 @@ function aboutSentence(about) {
|
|
|
22
21
|
const how = failure.kind === "status" ? `answers with an error (${failure.status})` : failure.kind === "timeout" ? "doesn't answer in time" : "can't be reached";
|
|
23
22
|
return `links to ${about.url}, which ${how}`;
|
|
24
23
|
}
|
|
25
|
-
case "misspelling": return "may be misspelled";
|
|
26
|
-
case "grammar": return "may be a grammar mistake";
|
|
27
24
|
}
|
|
28
25
|
}
|
|
29
26
|
/**
|
|
@@ -33,8 +30,15 @@ function aboutSentence(about) {
|
|
|
33
30
|
function findingSentence(finding) {
|
|
34
31
|
return `“${finding.about.text}” in ${finding.subject.name} ${aboutSentence(finding.about)}`;
|
|
35
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* A finding as one sentence where its content is already shown, as the studio's sidebar shows it
|
|
35
|
+
* by its field: "“About us” links to About, a page that no longer exists".
|
|
36
|
+
*/
|
|
37
|
+
function findingSentenceInPlace(finding) {
|
|
38
|
+
return `“${finding.about.text}” ${aboutSentence(finding.about)}`;
|
|
39
|
+
}
|
|
36
40
|
/** How many reports the Patrol shows of each patroller; the rest are counted. */
|
|
37
41
|
const REPORTS_SHOWN = 5;
|
|
38
42
|
|
|
39
43
|
//#endregion
|
|
40
|
-
export { PATROLLER_IDS, REPORTS_SHOWN, findingSentence, reportLocale };
|
|
44
|
+
export { PATROLLER_IDS, REPORTS_SHOWN, findingSentence, findingSentenceInPlace, reportLocale };
|
package/dist/router.d.ts
CHANGED
|
@@ -9967,9 +9967,9 @@ type CheckJob = {
|
|
|
9967
9967
|
};
|
|
9968
9968
|
/**
|
|
9969
9969
|
* A run of patrollers' patrols of a project's Live content (ADR 0034), keyed by project: the cron
|
|
9970
|
-
* trigger requests one of every patroller patrolling Live for every project every 6 hours
|
|
9971
|
-
*
|
|
9972
|
-
*
|
|
9970
|
+
* trigger requests one of every patroller patrolling Live for every project every 6 hours.
|
|
9971
|
+
* Requesting one while another is pending joins it: one run patrols for both, so its new findings
|
|
9972
|
+
* are told of once.
|
|
9973
9973
|
*/
|
|
9974
9974
|
type PatrolJob = {
|
|
9975
9975
|
kind: "patrol";
|
|
@@ -14514,6 +14514,177 @@ declare const router: {
|
|
|
14514
14514
|
structuredData: BlockStructuredData;
|
|
14515
14515
|
recordStructuredData: import("@camox/api-contract").RecordStructuredData;
|
|
14516
14516
|
}>, Record<never, never>, Record<never, never>>;
|
|
14517
|
+
getUnplaced: import("@orpc/server").DecoratedProcedure<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>>, {
|
|
14518
|
+
draft: DraftRequest | null;
|
|
14519
|
+
locale: string | undefined;
|
|
14520
|
+
publishingDraft: string | undefined;
|
|
14521
|
+
look: LookGrant | undefined;
|
|
14522
|
+
}>, import("zod").ZodObject<{
|
|
14523
|
+
projectUuid: import("zod").ZodUUID;
|
|
14524
|
+
layoutId: import("zod").ZodString;
|
|
14525
|
+
blocks: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
|
|
14526
|
+
content: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
14527
|
+
settings: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
14528
|
+
}, import("zod/v4/core").$strip>>>;
|
|
14529
|
+
}, import("zod/v4/core").$strip>, import("@orpc/server").Schema<{
|
|
14530
|
+
projectName: string;
|
|
14531
|
+
project: {
|
|
14532
|
+
id: number;
|
|
14533
|
+
updatedAt: number;
|
|
14534
|
+
analytics: AnalyticsProviders;
|
|
14535
|
+
socialProfiles: string[];
|
|
14536
|
+
};
|
|
14537
|
+
layout: {
|
|
14538
|
+
layoutId: string;
|
|
14539
|
+
contentUpdatedAt: number;
|
|
14540
|
+
updatedAt: number;
|
|
14541
|
+
beforeBlockIds: string[];
|
|
14542
|
+
afterBlockIds: string[];
|
|
14543
|
+
};
|
|
14544
|
+
blocks: (Omit<{
|
|
14545
|
+
baseVersion: number | null;
|
|
14546
|
+
content: unknown;
|
|
14547
|
+
createdAt: number;
|
|
14548
|
+
deleted: boolean;
|
|
14549
|
+
draftId: string | null;
|
|
14550
|
+
firstPublishedAt: number | null;
|
|
14551
|
+
id: string;
|
|
14552
|
+
layoutId: string | null;
|
|
14553
|
+
locale: string;
|
|
14554
|
+
pageId: string | null;
|
|
14555
|
+
position: string;
|
|
14556
|
+
projectId: number;
|
|
14557
|
+
publishedAt: number | null;
|
|
14558
|
+
publishedBy: string | null;
|
|
14559
|
+
rowId: number;
|
|
14560
|
+
settings: unknown;
|
|
14561
|
+
slot: "after" | "before" | null;
|
|
14562
|
+
type: string;
|
|
14563
|
+
updatedAt: number;
|
|
14564
|
+
version: number;
|
|
14565
|
+
}, "content"> & {
|
|
14566
|
+
content: Record<string, unknown>;
|
|
14567
|
+
} & {
|
|
14568
|
+
summary: string;
|
|
14569
|
+
title: string;
|
|
14570
|
+
artifactHashes: Record<string, string>;
|
|
14571
|
+
} & {
|
|
14572
|
+
references: ResolvedReferences;
|
|
14573
|
+
})[];
|
|
14574
|
+
repeatableItems: (Omit<{
|
|
14575
|
+
baseVersion: number | null;
|
|
14576
|
+
blockId: string | null;
|
|
14577
|
+
content: unknown;
|
|
14578
|
+
createdAt: number;
|
|
14579
|
+
deleted: boolean;
|
|
14580
|
+
draftId: string | null;
|
|
14581
|
+
fieldName: string;
|
|
14582
|
+
firstPublishedAt: number | null;
|
|
14583
|
+
id: string;
|
|
14584
|
+
locale: string;
|
|
14585
|
+
parentItemId: string | null;
|
|
14586
|
+
position: string;
|
|
14587
|
+
projectId: number | null;
|
|
14588
|
+
publishedAt: number | null;
|
|
14589
|
+
publishedBy: string | null;
|
|
14590
|
+
rowId: number;
|
|
14591
|
+
settings: unknown;
|
|
14592
|
+
sharedContentType: string | null;
|
|
14593
|
+
updatedAt: number;
|
|
14594
|
+
version: number;
|
|
14595
|
+
}, "content"> & {
|
|
14596
|
+
content: Record<string, unknown>;
|
|
14597
|
+
} & {
|
|
14598
|
+
blockId: string;
|
|
14599
|
+
summary: string;
|
|
14600
|
+
title: string;
|
|
14601
|
+
artifactHashes: Record<string, string>;
|
|
14602
|
+
} & {
|
|
14603
|
+
references: ResolvedReferences;
|
|
14604
|
+
})[];
|
|
14605
|
+
files: FileView[];
|
|
14606
|
+
structuredData: BlockStructuredData;
|
|
14607
|
+
recordStructuredData: import("@camox/api-contract").RecordStructuredData;
|
|
14608
|
+
}, {
|
|
14609
|
+
projectName: string;
|
|
14610
|
+
project: {
|
|
14611
|
+
id: number;
|
|
14612
|
+
updatedAt: number;
|
|
14613
|
+
analytics: AnalyticsProviders;
|
|
14614
|
+
socialProfiles: string[];
|
|
14615
|
+
};
|
|
14616
|
+
layout: {
|
|
14617
|
+
layoutId: string;
|
|
14618
|
+
contentUpdatedAt: number;
|
|
14619
|
+
updatedAt: number;
|
|
14620
|
+
beforeBlockIds: string[];
|
|
14621
|
+
afterBlockIds: string[];
|
|
14622
|
+
};
|
|
14623
|
+
blocks: (Omit<{
|
|
14624
|
+
baseVersion: number | null;
|
|
14625
|
+
content: unknown;
|
|
14626
|
+
createdAt: number;
|
|
14627
|
+
deleted: boolean;
|
|
14628
|
+
draftId: string | null;
|
|
14629
|
+
firstPublishedAt: number | null;
|
|
14630
|
+
id: string;
|
|
14631
|
+
layoutId: string | null;
|
|
14632
|
+
locale: string;
|
|
14633
|
+
pageId: string | null;
|
|
14634
|
+
position: string;
|
|
14635
|
+
projectId: number;
|
|
14636
|
+
publishedAt: number | null;
|
|
14637
|
+
publishedBy: string | null;
|
|
14638
|
+
rowId: number;
|
|
14639
|
+
settings: unknown;
|
|
14640
|
+
slot: "after" | "before" | null;
|
|
14641
|
+
type: string;
|
|
14642
|
+
updatedAt: number;
|
|
14643
|
+
version: number;
|
|
14644
|
+
}, "content"> & {
|
|
14645
|
+
content: Record<string, unknown>;
|
|
14646
|
+
} & {
|
|
14647
|
+
summary: string;
|
|
14648
|
+
title: string;
|
|
14649
|
+
artifactHashes: Record<string, string>;
|
|
14650
|
+
} & {
|
|
14651
|
+
references: ResolvedReferences;
|
|
14652
|
+
})[];
|
|
14653
|
+
repeatableItems: (Omit<{
|
|
14654
|
+
baseVersion: number | null;
|
|
14655
|
+
blockId: string | null;
|
|
14656
|
+
content: unknown;
|
|
14657
|
+
createdAt: number;
|
|
14658
|
+
deleted: boolean;
|
|
14659
|
+
draftId: string | null;
|
|
14660
|
+
fieldName: string;
|
|
14661
|
+
firstPublishedAt: number | null;
|
|
14662
|
+
id: string;
|
|
14663
|
+
locale: string;
|
|
14664
|
+
parentItemId: string | null;
|
|
14665
|
+
position: string;
|
|
14666
|
+
projectId: number | null;
|
|
14667
|
+
publishedAt: number | null;
|
|
14668
|
+
publishedBy: string | null;
|
|
14669
|
+
rowId: number;
|
|
14670
|
+
settings: unknown;
|
|
14671
|
+
sharedContentType: string | null;
|
|
14672
|
+
updatedAt: number;
|
|
14673
|
+
version: number;
|
|
14674
|
+
}, "content"> & {
|
|
14675
|
+
content: Record<string, unknown>;
|
|
14676
|
+
} & {
|
|
14677
|
+
blockId: string;
|
|
14678
|
+
summary: string;
|
|
14679
|
+
title: string;
|
|
14680
|
+
artifactHashes: Record<string, string>;
|
|
14681
|
+
} & {
|
|
14682
|
+
references: ResolvedReferences;
|
|
14683
|
+
})[];
|
|
14684
|
+
files: FileView[];
|
|
14685
|
+
structuredData: BlockStructuredData;
|
|
14686
|
+
recordStructuredData: import("@camox/api-contract").RecordStructuredData;
|
|
14687
|
+
}>, Record<never, never>, Record<never, never>>;
|
|
14517
14688
|
list: import("@orpc/server").DecoratedProcedure<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>>, {
|
|
14518
14689
|
draft: DraftRequest | null;
|
|
14519
14690
|
locale: string | undefined;
|
|
@@ -18124,16 +18295,17 @@ declare const router: {
|
|
|
18124
18295
|
subject: import("@camox/api-contract/patrol").ReportSubject;
|
|
18125
18296
|
locale: string;
|
|
18126
18297
|
field: string;
|
|
18298
|
+
fieldKind: string | null;
|
|
18127
18299
|
raisedAt: number;
|
|
18128
18300
|
live: boolean;
|
|
18129
18301
|
place: import("@camox/api-contract/patrol").ReportPlace | null;
|
|
18130
18302
|
patroller: {
|
|
18131
|
-
id: "linkChecker" | "
|
|
18303
|
+
id: "linkChecker" | "seoManager" | "translator";
|
|
18132
18304
|
role: string;
|
|
18133
18305
|
};
|
|
18134
18306
|
}[];
|
|
18135
18307
|
checking: {
|
|
18136
|
-
id: "linkChecker" | "
|
|
18308
|
+
id: "linkChecker" | "seoManager" | "translator";
|
|
18137
18309
|
role: string;
|
|
18138
18310
|
}[];
|
|
18139
18311
|
defaultLocale: string | null;
|
|
@@ -18166,16 +18338,17 @@ declare const router: {
|
|
|
18166
18338
|
subject: import("@camox/api-contract/patrol").ReportSubject;
|
|
18167
18339
|
locale: string;
|
|
18168
18340
|
field: string;
|
|
18341
|
+
fieldKind: string | null;
|
|
18169
18342
|
raisedAt: number;
|
|
18170
18343
|
live: boolean;
|
|
18171
18344
|
place: import("@camox/api-contract/patrol").ReportPlace | null;
|
|
18172
18345
|
patroller: {
|
|
18173
|
-
id: "linkChecker" | "
|
|
18346
|
+
id: "linkChecker" | "seoManager" | "translator";
|
|
18174
18347
|
role: string;
|
|
18175
18348
|
};
|
|
18176
18349
|
}[];
|
|
18177
18350
|
checking: {
|
|
18178
|
-
id: "linkChecker" | "
|
|
18351
|
+
id: "linkChecker" | "seoManager" | "translator";
|
|
18179
18352
|
role: string;
|
|
18180
18353
|
}[];
|
|
18181
18354
|
defaultLocale: string | null;
|
package/dist/threads.d.ts
CHANGED
|
@@ -91,6 +91,26 @@ export declare const artifactRequestDataSchema: z.ZodObject<{
|
|
|
91
91
|
operationIds: z.ZodArray<z.ZodString>;
|
|
92
92
|
}, z.core.$strip>;
|
|
93
93
|
export type ArtifactRequestData = z.infer<typeof artifactRequestDataSchema>;
|
|
94
|
+
/**
|
|
95
|
+
* The agent's tool handing code work to the draft thread's Code Agent, which reads and writes the
|
|
96
|
+
* website's code in a conversation of its own and answers the agent.
|
|
97
|
+
*/
|
|
98
|
+
export declare const CODE_TOOL = "code";
|
|
99
|
+
/**
|
|
100
|
+
* The kind of the entry recording a request the agent sent the Code Agent, in the Code Agent's
|
|
101
|
+
* own conversation, which editors never see: who the run acts for, the operation ids of its
|
|
102
|
+
* messages, and whether it's Camox's reconcile turn, as data (`codeRequestDataSchema`).
|
|
103
|
+
*/
|
|
104
|
+
export declare const CODE_REQUEST_ENTRY = "camox.code-request";
|
|
105
|
+
/** What a Code Agent's request records: as an Artifact Agent's, and whether Camox reconciles. */
|
|
106
|
+
export declare const codeRequestDataSchema: z.ZodObject<{
|
|
107
|
+
member: z.ZodString;
|
|
108
|
+
operationIds: z.ZodArray<z.ZodString>;
|
|
109
|
+
reconciling: z.ZodOptional<z.ZodBoolean>;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
export type CodeRequestData = z.infer<typeof codeRequestDataSchema>;
|
|
112
|
+
/** Whether `name` is a tool handing work to an agent of its own (`HANDING_OFF_TOOLS`). */
|
|
113
|
+
export declare const handsOff: (name: string) => boolean;
|
|
94
114
|
/**
|
|
95
115
|
* The tools whose calls change a draft: the content tools that write, and the code tools that
|
|
96
116
|
* write files. The model calls the code tools, and code mode scripts call both. A test in the API
|
|
@@ -375,11 +395,11 @@ export declare const agentActivitySchema: z.ZodEnum<{
|
|
|
375
395
|
}>;
|
|
376
396
|
export type AgentActivity = z.infer<typeof agentActivitySchema>;
|
|
377
397
|
/**
|
|
378
|
-
* What
|
|
379
|
-
* it's the agent's answer to the turn too,
|
|
380
|
-
*
|
|
398
|
+
* What the result of a call handing work off (`handsOff`), such as `artifact` or `code`, carries
|
|
399
|
+
* for the studio: the other agent's answer, whether it's the agent's answer to the turn too,
|
|
400
|
+
* which then ends on it, and while it works, what the other agent is doing.
|
|
381
401
|
*/
|
|
382
|
-
export declare const
|
|
402
|
+
export declare const handOffDetailsSchema: z.ZodObject<{
|
|
383
403
|
answer: z.ZodOptional<z.ZodString>;
|
|
384
404
|
final: z.ZodOptional<z.ZodBoolean>;
|
|
385
405
|
activity: z.ZodOptional<z.ZodEnum<{
|
|
@@ -392,7 +412,7 @@ export declare const artifactDetailsSchema: z.ZodObject<{
|
|
|
392
412
|
thinking: "thinking";
|
|
393
413
|
}>>;
|
|
394
414
|
}, z.core.$strip>;
|
|
395
|
-
export type
|
|
415
|
+
export type HandOffDetails = z.infer<typeof handOffDetailsSchema>;
|
|
396
416
|
/** Everything the studio shows for a thread. */
|
|
397
417
|
export type ThreadView = {
|
|
398
418
|
messages: readonly ThreadMessage[];
|
|
@@ -424,8 +444,11 @@ export type ThreadState = {
|
|
|
424
444
|
changing?: boolean;
|
|
425
445
|
/** Whether the model's latest round calls `look`: from writing the call until it's called again. */
|
|
426
446
|
checking?: boolean;
|
|
427
|
-
/**
|
|
428
|
-
|
|
447
|
+
/**
|
|
448
|
+
* What the agent a running call handing work off (`handsOff`) waits for is doing, as it last
|
|
449
|
+
* said.
|
|
450
|
+
*/
|
|
451
|
+
handedOffActivity?: AgentActivity;
|
|
429
452
|
/** The drafts the thread's cards name, as the thread last looked them up. */
|
|
430
453
|
drafts?: DraftCardStates;
|
|
431
454
|
};
|
|
@@ -614,7 +637,7 @@ export declare const editorTextOf: (content: Message["content"]) => string;
|
|
|
614
637
|
* run is over, or a later message started another run after its last model call came back
|
|
615
638
|
* unfinished. While Pi retries a failed call, the run goes on, so the turn shows as working.
|
|
616
639
|
*/
|
|
617
|
-
export declare function threadViewOf({ steps, running, toolCalls, callingTools, changing, checking,
|
|
640
|
+
export declare function threadViewOf({ steps, running, toolCalls, callingTools, changing, checking, handedOffActivity, drafts }: ThreadState): ThreadView;
|
|
618
641
|
/** Folds one of Pi's agent events into the thread's state. */
|
|
619
642
|
export declare function reduceThreadState(state: ThreadState, event: AgentEvent): ThreadState;
|
|
620
643
|
/** Folds a batch of Pi's agent events into the thread's state. */
|
package/dist/threads.js
CHANGED
|
@@ -88,6 +88,26 @@ const artifactRequestDataSchema = z.object({
|
|
|
88
88
|
operationIds: z.array(z.string())
|
|
89
89
|
});
|
|
90
90
|
/**
|
|
91
|
+
* The agent's tool handing code work to the draft thread's Code Agent, which reads and writes the
|
|
92
|
+
* website's code in a conversation of its own and answers the agent.
|
|
93
|
+
*/
|
|
94
|
+
const CODE_TOOL = "code";
|
|
95
|
+
/**
|
|
96
|
+
* The kind of the entry recording a request the agent sent the Code Agent, in the Code Agent's
|
|
97
|
+
* own conversation, which editors never see: who the run acts for, the operation ids of its
|
|
98
|
+
* messages, and whether it's Camox's reconcile turn, as data (`codeRequestDataSchema`).
|
|
99
|
+
*/
|
|
100
|
+
const CODE_REQUEST_ENTRY = "camox.code-request";
|
|
101
|
+
/** What a Code Agent's request records: as an Artifact Agent's, and whether Camox reconciles. */
|
|
102
|
+
const codeRequestDataSchema = artifactRequestDataSchema.extend({ reconciling: z.boolean().optional() });
|
|
103
|
+
/**
|
|
104
|
+
* The agent's tools handing work to an agent of its own, in a conversation beside the thread's,
|
|
105
|
+
* whose answer they return: editors see what that agent does as the agent's.
|
|
106
|
+
*/
|
|
107
|
+
const HANDING_OFF_TOOLS = /* @__PURE__ */ new Set([ARTIFACT_TOOL, CODE_TOOL]);
|
|
108
|
+
/** Whether `name` is a tool handing work to an agent of its own (`HANDING_OFF_TOOLS`). */
|
|
109
|
+
const handsOff = (name) => HANDING_OFF_TOOLS.has(name);
|
|
110
|
+
/**
|
|
91
111
|
* The tools whose calls change a draft: the content tools that write, and the code tools that
|
|
92
112
|
* write files. The model calls the code tools, and code mode scripts call both. A test in the API
|
|
93
113
|
* keeps this in step with the tools themselves.
|
|
@@ -232,11 +252,11 @@ const agentActivitySchema = z.enum([
|
|
|
232
252
|
"startingDraft"
|
|
233
253
|
]);
|
|
234
254
|
/**
|
|
235
|
-
* What
|
|
236
|
-
* it's the agent's answer to the turn too,
|
|
237
|
-
*
|
|
255
|
+
* What the result of a call handing work off (`handsOff`), such as `artifact` or `code`, carries
|
|
256
|
+
* for the studio: the other agent's answer, whether it's the agent's answer to the turn too,
|
|
257
|
+
* which then ends on it, and while it works, what the other agent is doing.
|
|
238
258
|
*/
|
|
239
|
-
const
|
|
259
|
+
const handOffDetailsSchema = z.object({
|
|
240
260
|
answer: z.string().optional(),
|
|
241
261
|
final: z.boolean().optional(),
|
|
242
262
|
activity: agentActivitySchema.optional()
|
|
@@ -405,8 +425,8 @@ function threadStepOf(entry) {
|
|
|
405
425
|
}
|
|
406
426
|
if (message.role === "assistant") return assistantStep(id, message);
|
|
407
427
|
if (message.role === "toolResult") {
|
|
408
|
-
if (message.toolName
|
|
409
|
-
const details =
|
|
428
|
+
if (handsOff(message.toolName) && !message.isError) {
|
|
429
|
+
const details = handOffDetailsSchema.safeParse(message.details).data;
|
|
410
430
|
if (details?.final && details.answer) return {
|
|
411
431
|
id,
|
|
412
432
|
type: "answer",
|
|
@@ -433,7 +453,7 @@ function threadStepOf(entry) {
|
|
|
433
453
|
* run is over, or a later message started another run after its last model call came back
|
|
434
454
|
* unfinished. While Pi retries a failed call, the run goes on, so the turn shows as working.
|
|
435
455
|
*/
|
|
436
|
-
function threadViewOf({ steps, running, toolCalls = [], callingTools = false, changing = false, checking = false,
|
|
456
|
+
function threadViewOf({ steps, running, toolCalls = [], callingTools = false, changing = false, checking = false, handedOffActivity, drafts = {} }) {
|
|
437
457
|
const messages = [];
|
|
438
458
|
let waiting;
|
|
439
459
|
let unfinished = false;
|
|
@@ -545,6 +565,7 @@ function threadViewOf({ steps, running, toolCalls = [], callingTools = false, ch
|
|
|
545
565
|
break;
|
|
546
566
|
case "tools":
|
|
547
567
|
unfinished = false;
|
|
568
|
+
status = void 0;
|
|
548
569
|
break;
|
|
549
570
|
case "unfinished": unfinished = true;
|
|
550
571
|
}
|
|
@@ -562,17 +583,17 @@ function threadViewOf({ steps, running, toolCalls = [], callingTools = false, ch
|
|
|
562
583
|
callingTools,
|
|
563
584
|
changing,
|
|
564
585
|
checking,
|
|
565
|
-
|
|
586
|
+
handedOffActivity
|
|
566
587
|
})
|
|
567
588
|
};
|
|
568
589
|
}
|
|
569
590
|
/** What the agent is doing during a run, from where the turn's build stands and its tool calls. */
|
|
570
|
-
function activityOf({ status, toolCalls, callingTools, changing, checking,
|
|
591
|
+
function activityOf({ status, toolCalls, callingTools, changing, checking, handedOffActivity }) {
|
|
571
592
|
const calling = (name) => toolCalls.some((call) => call.name === name);
|
|
572
593
|
if (status === "building" || calling("build")) return "building";
|
|
573
|
-
if (calling("artifact")) return artifactActivity ?? "changing";
|
|
574
|
-
if (checking) return "checking";
|
|
575
594
|
if (status === "fixing") return "fixing";
|
|
595
|
+
if (toolCalls.some((call) => handsOff(call.name))) return handedOffActivity ?? "changing";
|
|
596
|
+
if (checking) return "checking";
|
|
576
597
|
if (calling("startDraft")) return "startingDraft";
|
|
577
598
|
if (changing) return "changing";
|
|
578
599
|
if (callingTools || toolCalls.length > 0) return "exploring";
|
|
@@ -615,11 +636,11 @@ function reduceThreadState(state, event) {
|
|
|
615
636
|
name: tool.name
|
|
616
637
|
}]);
|
|
617
638
|
const generated = event.generation?.message?.content ?? [];
|
|
618
|
-
const
|
|
639
|
+
const handingOff = event.tools.find((tool) => handsOff(tool.name) && tool.status !== "done");
|
|
619
640
|
return {
|
|
620
641
|
...state,
|
|
621
642
|
steps: event.entries.flatMap((entry) => threadStepOf(entry) ?? []),
|
|
622
|
-
|
|
643
|
+
handedOffActivity: handOffDetailsSchema.safeParse(handingOff?.details).data?.activity,
|
|
623
644
|
running: event.run !== void 0,
|
|
624
645
|
toolCalls,
|
|
625
646
|
callingTools: generated.some((part) => part.type === "toolCall"),
|
|
@@ -638,7 +659,7 @@ function reduceThreadState(state, event) {
|
|
|
638
659
|
callingTools: false,
|
|
639
660
|
changing: false,
|
|
640
661
|
checking: false,
|
|
641
|
-
|
|
662
|
+
handedOffActivity: void 0
|
|
642
663
|
};
|
|
643
664
|
case "message_start": return event.message.role === "assistant" ? {
|
|
644
665
|
...state,
|
|
@@ -673,17 +694,17 @@ function reduceThreadState(state, event) {
|
|
|
673
694
|
};
|
|
674
695
|
}
|
|
675
696
|
case "tool_execution_update": {
|
|
676
|
-
if (event.toolName
|
|
677
|
-
const activity =
|
|
697
|
+
if (!handsOff(event.toolName) || event.parentToolCallId !== void 0) return state;
|
|
698
|
+
const activity = handOffDetailsSchema.safeParse(event.details).data?.activity;
|
|
678
699
|
return activity ? {
|
|
679
700
|
...state,
|
|
680
|
-
|
|
701
|
+
handedOffActivity: activity
|
|
681
702
|
} : state;
|
|
682
703
|
}
|
|
683
704
|
case "tool_execution_end": return append({
|
|
684
705
|
...state,
|
|
685
706
|
toolCalls: state.toolCalls?.filter((call) => call.callId !== event.toolCallId),
|
|
686
|
-
...event.toolName
|
|
707
|
+
...handsOff(event.toolName) && event.parentToolCallId === void 0 && { handedOffActivity: void 0 }
|
|
687
708
|
}, event.entry);
|
|
688
709
|
case "message_end":
|
|
689
710
|
case "entry_appended": return append(state, event.entry);
|
|
@@ -705,4 +726,4 @@ function reduceThreadFrame(state, frame) {
|
|
|
705
726
|
}
|
|
706
727
|
|
|
707
728
|
//#endregion
|
|
708
|
-
export { ARTIFACT_REQUEST_ENTRY, ARTIFACT_TOOL, BRIEF_ENTRY, BUILD_STATUS_ENTRY, BUILD_TOOL, CHANGING_TOOLS, CONNECTED_AGENT_MESSAGE_ENTRY, DRAFT_CARD_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, LOOK_TOOL, PUSH_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, agentActivitySchema,
|
|
729
|
+
export { ARTIFACT_REQUEST_ENTRY, ARTIFACT_TOOL, BRIEF_ENTRY, BUILD_STATUS_ENTRY, BUILD_TOOL, CHANGING_TOOLS, CODE_REQUEST_ENTRY, CODE_TOOL, CONNECTED_AGENT_MESSAGE_ENTRY, DRAFT_CARD_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, LOOK_TOOL, PUSH_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, agentActivitySchema, artifactRequestDataSchema, buildStatusDataSchema, buildStatusSchema, codeRequestDataSchema, connectedAgentClientSchema, connectedAgentMessageDataSchema, editorMessageDataSchema, editorSelectionSchema, editorTextOf, editorWhereSchema, handOffDetailsSchema, handsOff, isSender, pushDataSchema, pushOutcomeSchema, reconcileDataSchema, reduceThreadEvents, reduceThreadFrame, reduceThreadState, startedDraftCardSchema, startedDraftSchema, textOf, threadClientMessageSchema, threadSenderSchema, threadViewOf, touchKindSchema, touchSchema, touchedBatchSchema };
|
package/package.json
CHANGED
package/src/drafts.ts
CHANGED
|
@@ -58,6 +58,21 @@ export const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
|
58
58
|
export const LOOK_CONTENT_PARAM = "content";
|
|
59
59
|
export const LOOK_SETTINGS_PARAM = "settings";
|
|
60
60
|
|
|
61
|
+
/**
|
|
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 their default
|
|
64
|
+
* content and Block Settings and the overrides `LOOK_BLOCKS_PARAM` gives as JSON, by Block
|
|
65
|
+
* Definition name (`{ navbar: { content, settings } }`), around a labelled placeholder where a
|
|
66
|
+
* page's content goes, as tall as `LOOK_PLACEHOLDER_PARAM` says: one of `LOOK_PLACEHOLDER_HEIGHTS`,
|
|
67
|
+
* the first without.
|
|
68
|
+
*/
|
|
69
|
+
export const LOOK_LAYOUT_DEFINITION_PARAM = "layoutDefinition";
|
|
70
|
+
export const LOOK_BLOCKS_PARAM = "blocks";
|
|
71
|
+
export const LOOK_PLACEHOLDER_PARAM = "placeholder";
|
|
72
|
+
/** A short placeholder shows whether the footer rises up the screen; a tall one, scrolling. */
|
|
73
|
+
export const LOOK_PLACEHOLDER_HEIGHTS = ["short", "tall"] as const;
|
|
74
|
+
export type LookPlaceholderHeight = (typeof LOOK_PLACEHOLDER_HEIGHTS)[number];
|
|
75
|
+
|
|
61
76
|
/**
|
|
62
77
|
* The id of a block shown without being placed, as the look document's Block Definition mode
|
|
63
78
|
* shows it: never a stored block's, which are UUIDs. Its element is
|
package/src/patrol.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/** Every patroller's stable id. The registry in the API lists them all. */
|
|
8
|
-
export const PATROLLER_IDS = ["translator", "seoManager", "linkChecker"
|
|
8
|
+
export const PATROLLER_IDS = ["translator", "seoManager", "linkChecker"] as const;
|
|
9
9
|
|
|
10
10
|
/** A patroller's stable id. */
|
|
11
11
|
export type PatrollerId = (typeof PATROLLER_IDS)[number];
|
|
@@ -21,8 +21,7 @@ export type ReportVerb =
|
|
|
21
21
|
| "describedFile"
|
|
22
22
|
| "publishedCatchUp"
|
|
23
23
|
| "removedLink"
|
|
24
|
-
| "fixedLink"
|
|
25
|
-
| "fixedMistake";
|
|
24
|
+
| "fixedLink";
|
|
26
25
|
|
|
27
26
|
/** What a report can be about. */
|
|
28
27
|
export type ReportEntity =
|
|
@@ -92,14 +91,12 @@ export type ReportView = {
|
|
|
92
91
|
* What a finding is about (ADR 0034), by its kind:
|
|
93
92
|
* - `missingPage`: a link to a page that doesn't exist, the page's name as it was last known.
|
|
94
93
|
* - `brokenLink`: an external link that failed, and how.
|
|
95
|
-
* - `misspelling`, `grammar`: the flagged text, in the sentence it's in.
|
|
96
94
|
* A link's `url` is as content stores it: a page link's is `camox:page:<id>`, and `text` is what
|
|
97
95
|
* the link reads.
|
|
98
96
|
*/
|
|
99
97
|
export type FindingAbout =
|
|
100
98
|
| { kind: "missingPage"; url: string; text: string; page: string | null }
|
|
101
|
-
| { kind: "brokenLink"; url: string; text: string; failure: LinkFailure }
|
|
102
|
-
| { kind: "misspelling" | "grammar"; text: string; sentence: string };
|
|
99
|
+
| { kind: "brokenLink"; url: string; text: string; failure: LinkFailure };
|
|
103
100
|
|
|
104
101
|
/** How a link failed: an HTTP error status, no connection (DNS included), or no answer in time. */
|
|
105
102
|
export type LinkFailure =
|
|
@@ -109,11 +106,8 @@ export type LinkFailure =
|
|
|
109
106
|
|
|
110
107
|
export type FindingKind = FindingAbout["kind"];
|
|
111
108
|
|
|
112
|
-
/**
|
|
113
|
-
|
|
114
|
-
* replacing the flagged text with `replacement` in its sentence, keeping its formatting.
|
|
115
|
-
*/
|
|
116
|
-
export type FindingFix = { kind: "removeLink" } | { kind: "replaceText"; replacement: string };
|
|
109
|
+
/** The fix a finding suggests, which applying makes: removing the link, keeping its text. */
|
|
110
|
+
export type FindingFix = { kind: "removeLink" };
|
|
117
111
|
|
|
118
112
|
/** A finding, open, in the scope viewed. */
|
|
119
113
|
export type FindingView = {
|
|
@@ -128,6 +122,8 @@ export type FindingView = {
|
|
|
128
122
|
locale: string;
|
|
129
123
|
/** The content field it's in, by name. */
|
|
130
124
|
field: string;
|
|
125
|
+
/** That field's kind, such as "String" or "Link", or null when unknown. */
|
|
126
|
+
fieldKind: string | null;
|
|
131
127
|
/** When it was first raised, in milliseconds since the epoch. */
|
|
132
128
|
raisedAt: number;
|
|
133
129
|
/** Whether it's Live's. Live's are fixed in the Patrol Draft. */
|
|
@@ -153,10 +149,6 @@ function aboutSentence(about: FindingAbout): string {
|
|
|
153
149
|
: "can't be reached";
|
|
154
150
|
return `links to ${about.url}, which ${how}`;
|
|
155
151
|
}
|
|
156
|
-
case "misspelling":
|
|
157
|
-
return "may be misspelled";
|
|
158
|
-
case "grammar":
|
|
159
|
-
return "may be a grammar mistake";
|
|
160
152
|
}
|
|
161
153
|
}
|
|
162
154
|
|
|
@@ -168,6 +160,14 @@ export function findingSentence(finding: Pick<FindingView, "about" | "subject">)
|
|
|
168
160
|
return `“${finding.about.text}” in ${finding.subject.name} ${aboutSentence(finding.about)}`;
|
|
169
161
|
}
|
|
170
162
|
|
|
163
|
+
/**
|
|
164
|
+
* A finding as one sentence where its content is already shown, as the studio's sidebar shows it
|
|
165
|
+
* by its field: "“About us” links to About, a page that no longer exists".
|
|
166
|
+
*/
|
|
167
|
+
export function findingSentenceInPlace(finding: Pick<FindingView, "about">): string {
|
|
168
|
+
return `“${finding.about.text}” ${aboutSentence(finding.about)}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
171
|
/** A member's dismissal of what a finding was about: no finding like it is raised again. */
|
|
172
172
|
export type DismissalView = {
|
|
173
173
|
id: number;
|
package/src/threads.ts
CHANGED
|
@@ -108,6 +108,34 @@ export const artifactRequestDataSchema = z.object({
|
|
|
108
108
|
});
|
|
109
109
|
export type ArtifactRequestData = z.infer<typeof artifactRequestDataSchema>;
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* The agent's tool handing code work to the draft thread's Code Agent, which reads and writes the
|
|
113
|
+
* website's code in a conversation of its own and answers the agent.
|
|
114
|
+
*/
|
|
115
|
+
export const CODE_TOOL = "code";
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The kind of the entry recording a request the agent sent the Code Agent, in the Code Agent's
|
|
119
|
+
* own conversation, which editors never see: who the run acts for, the operation ids of its
|
|
120
|
+
* messages, and whether it's Camox's reconcile turn, as data (`codeRequestDataSchema`).
|
|
121
|
+
*/
|
|
122
|
+
export const CODE_REQUEST_ENTRY = "camox.code-request";
|
|
123
|
+
|
|
124
|
+
/** What a Code Agent's request records: as an Artifact Agent's, and whether Camox reconciles. */
|
|
125
|
+
export const codeRequestDataSchema = artifactRequestDataSchema.extend({
|
|
126
|
+
reconciling: z.boolean().optional(),
|
|
127
|
+
});
|
|
128
|
+
export type CodeRequestData = z.infer<typeof codeRequestDataSchema>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The agent's tools handing work to an agent of its own, in a conversation beside the thread's,
|
|
132
|
+
* whose answer they return: editors see what that agent does as the agent's.
|
|
133
|
+
*/
|
|
134
|
+
const HANDING_OFF_TOOLS: ReadonlySet<string> = new Set([ARTIFACT_TOOL, CODE_TOOL]);
|
|
135
|
+
|
|
136
|
+
/** Whether `name` is a tool handing work to an agent of its own (`HANDING_OFF_TOOLS`). */
|
|
137
|
+
export const handsOff = (name: string) => HANDING_OFF_TOOLS.has(name);
|
|
138
|
+
|
|
111
139
|
/**
|
|
112
140
|
* The tools whose calls change a draft: the content tools that write, and the code tools that
|
|
113
141
|
* write files. The model calls the code tools, and code mode scripts call both. A test in the API
|
|
@@ -320,16 +348,16 @@ export const agentActivitySchema = z.enum([
|
|
|
320
348
|
export type AgentActivity = z.infer<typeof agentActivitySchema>;
|
|
321
349
|
|
|
322
350
|
/**
|
|
323
|
-
* What
|
|
324
|
-
* it's the agent's answer to the turn too,
|
|
325
|
-
*
|
|
351
|
+
* What the result of a call handing work off (`handsOff`), such as `artifact` or `code`, carries
|
|
352
|
+
* for the studio: the other agent's answer, whether it's the agent's answer to the turn too,
|
|
353
|
+
* which then ends on it, and while it works, what the other agent is doing.
|
|
326
354
|
*/
|
|
327
|
-
export const
|
|
355
|
+
export const handOffDetailsSchema = z.object({
|
|
328
356
|
answer: z.string().optional(),
|
|
329
357
|
final: z.boolean().optional(),
|
|
330
358
|
activity: agentActivitySchema.optional(),
|
|
331
359
|
});
|
|
332
|
-
export type
|
|
360
|
+
export type HandOffDetails = z.infer<typeof handOffDetailsSchema>;
|
|
333
361
|
|
|
334
362
|
/** Everything the studio shows for a thread. */
|
|
335
363
|
export type ThreadView = {
|
|
@@ -361,8 +389,11 @@ export type ThreadState = {
|
|
|
361
389
|
changing?: boolean;
|
|
362
390
|
/** Whether the model's latest round calls `look`: from writing the call until it's called again. */
|
|
363
391
|
checking?: boolean;
|
|
364
|
-
/**
|
|
365
|
-
|
|
392
|
+
/**
|
|
393
|
+
* What the agent a running call handing work off (`handsOff`) waits for is doing, as it last
|
|
394
|
+
* said.
|
|
395
|
+
*/
|
|
396
|
+
handedOffActivity?: AgentActivity;
|
|
366
397
|
/** The drafts the thread's cards name, as the thread last looked them up. */
|
|
367
398
|
drafts?: DraftCardStates;
|
|
368
399
|
};
|
|
@@ -563,9 +594,10 @@ function threadStepOf(entry: EntryRecord): ThreadStep | undefined {
|
|
|
563
594
|
}
|
|
564
595
|
if (message.role === "assistant") return assistantStep(id, message);
|
|
565
596
|
if (message.role === "toolResult") {
|
|
566
|
-
// An Artifact Agent's answer that ends the turn is the agent's: editors
|
|
567
|
-
|
|
568
|
-
|
|
597
|
+
// An Artifact Agent's or the Code Agent's answer that ends the turn is the agent's: editors
|
|
598
|
+
// never see it apart.
|
|
599
|
+
if (handsOff(message.toolName) && !message.isError) {
|
|
600
|
+
const details = handOffDetailsSchema.safeParse(message.details).data;
|
|
569
601
|
if (details?.final && details.answer) return { id, type: "answer", text: details.answer };
|
|
570
602
|
}
|
|
571
603
|
const card =
|
|
@@ -593,7 +625,7 @@ export function threadViewOf({
|
|
|
593
625
|
callingTools = false,
|
|
594
626
|
changing = false,
|
|
595
627
|
checking = false,
|
|
596
|
-
|
|
628
|
+
handedOffActivity,
|
|
597
629
|
drafts = {},
|
|
598
630
|
}: ThreadState): ThreadView {
|
|
599
631
|
const messages: ThreadMessage[] = [];
|
|
@@ -698,6 +730,8 @@ export function threadViewOf({
|
|
|
698
730
|
break;
|
|
699
731
|
case "tools":
|
|
700
732
|
unfinished = false;
|
|
733
|
+
// The Code Agent's build status ends with its request, whose answer is a tool result.
|
|
734
|
+
status = undefined;
|
|
701
735
|
break;
|
|
702
736
|
case "unfinished":
|
|
703
737
|
unfinished = true;
|
|
@@ -709,7 +743,14 @@ export function threadViewOf({
|
|
|
709
743
|
return {
|
|
710
744
|
messages,
|
|
711
745
|
running,
|
|
712
|
-
activity: activityOf({
|
|
746
|
+
activity: activityOf({
|
|
747
|
+
status,
|
|
748
|
+
toolCalls,
|
|
749
|
+
callingTools,
|
|
750
|
+
changing,
|
|
751
|
+
checking,
|
|
752
|
+
handedOffActivity,
|
|
753
|
+
}),
|
|
713
754
|
};
|
|
714
755
|
}
|
|
715
756
|
|
|
@@ -720,23 +761,24 @@ function activityOf({
|
|
|
720
761
|
callingTools,
|
|
721
762
|
changing,
|
|
722
763
|
checking,
|
|
723
|
-
|
|
764
|
+
handedOffActivity,
|
|
724
765
|
}: {
|
|
725
766
|
status: BuildStatus | undefined;
|
|
726
767
|
toolCalls: NonNullable<ThreadState["toolCalls"]>;
|
|
727
768
|
callingTools: boolean;
|
|
728
769
|
changing: boolean;
|
|
729
770
|
checking: boolean;
|
|
730
|
-
|
|
771
|
+
handedOffActivity: AgentActivity | undefined;
|
|
731
772
|
}): AgentActivity {
|
|
732
773
|
const calling = (name: string) => toolCalls.some((call) => call.name === name);
|
|
733
774
|
// Fixing a build error takes thinking, reading and writing, which all read as fixing, but its
|
|
734
775
|
// builds show as building.
|
|
735
776
|
if (status === "building" || calling(BUILD_TOOL)) return "building";
|
|
736
|
-
// An Artifact Agent works on the agent's behalf: editors see what it does as the agent's.
|
|
737
|
-
if (calling(ARTIFACT_TOOL)) return artifactActivity ?? "changing";
|
|
738
|
-
if (checking) return "checking";
|
|
739
777
|
if (status === "fixing") return "fixing";
|
|
778
|
+
// An Artifact Agent or the Code Agent works on the agent's behalf: editors see what it does as
|
|
779
|
+
// the agent's.
|
|
780
|
+
if (toolCalls.some((call) => handsOff(call.name))) return handedOffActivity ?? "changing";
|
|
781
|
+
if (checking) return "checking";
|
|
740
782
|
if (calling(START_DRAFT_TOOL)) return "startingDraft";
|
|
741
783
|
if (changing) return "changing";
|
|
742
784
|
if (callingTools || toolCalls.length > 0) return "exploring";
|
|
@@ -781,13 +823,11 @@ export function reduceThreadState(state: ThreadState, event: AgentEvent): Thread
|
|
|
781
823
|
tool.status === "done" ? [] : [{ callId: tool.callId, name: tool.name }],
|
|
782
824
|
);
|
|
783
825
|
const generated = event.generation?.message?.content ?? [];
|
|
784
|
-
const
|
|
785
|
-
(tool) => tool.name === ARTIFACT_TOOL && tool.status !== "done",
|
|
786
|
-
);
|
|
826
|
+
const handingOff = event.tools.find((tool) => handsOff(tool.name) && tool.status !== "done");
|
|
787
827
|
return {
|
|
788
828
|
...state,
|
|
789
829
|
steps: event.entries.flatMap((entry) => threadStepOf(entry) ?? []),
|
|
790
|
-
|
|
830
|
+
handedOffActivity: handOffDetailsSchema.safeParse(handingOff?.details).data?.activity,
|
|
791
831
|
running: event.run !== undefined,
|
|
792
832
|
toolCalls,
|
|
793
833
|
callingTools: generated.some((part) => part.type === "toolCall"),
|
|
@@ -817,7 +857,7 @@ export function reduceThreadState(state: ThreadState, event: AgentEvent): Thread
|
|
|
817
857
|
callingTools: false,
|
|
818
858
|
changing: false,
|
|
819
859
|
checking: false,
|
|
820
|
-
|
|
860
|
+
handedOffActivity: undefined,
|
|
821
861
|
};
|
|
822
862
|
case "message_start":
|
|
823
863
|
// The model is called again: it thinks until it writes a tool call.
|
|
@@ -852,17 +892,17 @@ export function reduceThreadState(state: ThreadState, event: AgentEvent): Thread
|
|
|
852
892
|
};
|
|
853
893
|
}
|
|
854
894
|
case "tool_execution_update": {
|
|
855
|
-
if (event.toolName
|
|
856
|
-
const activity =
|
|
857
|
-
return activity ? { ...state,
|
|
895
|
+
if (!handsOff(event.toolName) || event.parentToolCallId !== undefined) return state;
|
|
896
|
+
const activity = handOffDetailsSchema.safeParse(event.details).data?.activity;
|
|
897
|
+
return activity ? { ...state, handedOffActivity: activity } : state;
|
|
858
898
|
}
|
|
859
899
|
case "tool_execution_end":
|
|
860
900
|
return append(
|
|
861
901
|
{
|
|
862
902
|
...state,
|
|
863
903
|
toolCalls: state.toolCalls?.filter((call) => call.callId !== event.toolCallId),
|
|
864
|
-
...(event.toolName
|
|
865
|
-
event.parentToolCallId === undefined && {
|
|
904
|
+
...(handsOff(event.toolName) &&
|
|
905
|
+
event.parentToolCallId === undefined && { handedOffActivity: undefined }),
|
|
866
906
|
},
|
|
867
907
|
event.entry,
|
|
868
908
|
);
|