@xfey/tutti 0.1.20 → 0.1.22
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/collaboration-state/index.d.ts +1 -1
- package/dist/collaboration-state/index.js +1 -1
- package/dist/collaboration-state/messages.js +50 -1
- package/dist/collaboration-state/scratchpad.d.ts +2 -0
- package/dist/collaboration-state/scratchpad.js +63 -0
- package/dist/collaboration-state/storage-types.d.ts +5 -0
- package/dist/collaboration-state/types.d.ts +8 -1
- package/dist/control-plane/event-publishers.js +2 -2
- package/dist/control-plane/invalidations.d.ts +2 -1
- package/dist/control-plane/invalidations.js +25 -0
- package/dist/control-plane/scratchpad-refresh-start.d.ts +2 -0
- package/dist/control-plane/scratchpad-refresh-start.js +10 -0
- package/dist/control-plane/scratchpad-refresh.d.ts +2 -0
- package/dist/control-plane/scratchpad-refresh.js +1 -0
- package/dist/project-timeline/index.d.ts +17 -3
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +1 -0
- package/dist/server-shell/http/routes/project-api/openapi-timeline-routes.d.ts +94 -5
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +95 -5
- package/dist/server-shell/http/routes/project-api/payload-validation.d.ts +6 -2
- package/dist/server-shell/http/routes/project-api/payload-validation.js +3 -0
- package/dist/server-shell/http/routes/project-api/project-timeline-projection.js +694 -502
- package/migrations/0013_scratchpad_receipt_sources.sql +24 -0
- package/migrations/README.md +3 -2
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
- package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/messages.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/project-timeline.d.ts +313 -12
- package/node_modules/@tutti/shared/dist/schemas/api/project-timeline.js +131 -14
- package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +5 -1
- package/package.json +1 -1
- package/prompts/procedures/README.md +1 -1
- package/prompts/procedures/task-compile.md +9 -2
- package/prompts/runs/README.md +2 -2
- package/prompts/runs/task-continuation.md +11 -4
- package/prompts/runs/task-retry.md +11 -4
- package/prompts/runs/task-run.md +11 -4
- package/web/assets/index-BfFYfzeO.js +29 -0
- package/web/assets/index-De6mK5Q2.css +1 -0
- package/web/index.html +2 -2
- package/web/assets/index-BtneECwp.js +0 -29
- package/web/assets/index-CM9mbbeW.css +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { CollaborationStateCursorError } from "./serialization.js";
|
|
2
2
|
export { createIdleExecutionStatusProjection } from "./execution-status.js";
|
|
3
3
|
export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesAfter, readMainChatMessagesAfterCursor, readMainChatMessagesBeforeCursor, } from "./messages.js";
|
|
4
|
-
export { createEmptyScratchpadProjection, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
4
|
+
export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
5
5
|
export { advanceScratchpadTaskCompileSourceCursor, markScratchpadRefreshFailed, markScratchpadRefreshStarted, markScratchpadRefreshSucceeded, markScratchpadSourceDirty, readScratchpadSourceState, } from "./scratchpad-source-state.js";
|
|
6
6
|
export { deleteStaleClarificationSubmitReplayHints, readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readClarificationThreadResponse, readSealedClarificationRoundsWithoutSuccessor, readSubmittedTaskCompileClarificationRounds, readSubmittedTaskCompileClarificationRoundsAfterCursor, } from "./clarification-records.js";
|
|
7
7
|
export { createClarificationRoundAgentMessage, createClarificationRoundMessage, readClarificationRoundMessagesWindow, } from "./clarification-messages.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { CollaborationStateCursorError } from "./serialization.js";
|
|
2
2
|
export { createIdleExecutionStatusProjection } from "./execution-status.js";
|
|
3
3
|
export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesAfter, readMainChatMessagesAfterCursor, readMainChatMessagesBeforeCursor, } from "./messages.js";
|
|
4
|
-
export { createEmptyScratchpadProjection, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
4
|
+
export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, submitScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
5
5
|
export { advanceScratchpadTaskCompileSourceCursor, markScratchpadRefreshFailed, markScratchpadRefreshStarted, markScratchpadRefreshSucceeded, markScratchpadSourceDirty, readScratchpadSourceState, } from "./scratchpad-source-state.js";
|
|
6
6
|
export { deleteStaleClarificationSubmitReplayHints, readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readClarificationThreadResponse, readSealedClarificationRoundsWithoutSuccessor, readSubmittedTaskCompileClarificationRounds, readSubmittedTaskCompileClarificationRoundsAfterCursor, } from "./clarification-records.js";
|
|
7
7
|
export { createClarificationRoundAgentMessage, createClarificationRoundMessage, readClarificationRoundMessagesWindow, } from "./clarification-messages.js";
|
|
@@ -245,10 +245,59 @@ export function readMainChatMessageWindow(db, options = {}) {
|
|
|
245
245
|
if (before !== null && after !== null) {
|
|
246
246
|
throw new Error("before and after cursors cannot be used together");
|
|
247
247
|
}
|
|
248
|
+
if (options.around !== undefined && (before !== null || after !== null)) {
|
|
249
|
+
throw new Error("around cannot be used with before or after cursors");
|
|
250
|
+
}
|
|
248
251
|
let rows;
|
|
249
252
|
let hasOlder = false;
|
|
250
253
|
let hasNewer = false;
|
|
251
|
-
if (
|
|
254
|
+
if (options.around !== undefined) {
|
|
255
|
+
const target = db
|
|
256
|
+
.prepare(`
|
|
257
|
+
SELECT *
|
|
258
|
+
FROM messages
|
|
259
|
+
WHERE scope_kind = 'main_chat'
|
|
260
|
+
AND id = ?
|
|
261
|
+
`)
|
|
262
|
+
.get(options.around);
|
|
263
|
+
if (target === undefined) {
|
|
264
|
+
rows = [];
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
const beforeLimit = Math.floor((limit - 1) / 2);
|
|
268
|
+
const afterLimit = Math.max(0, limit - beforeLimit - 1);
|
|
269
|
+
const olderRows = db
|
|
270
|
+
.prepare(`
|
|
271
|
+
SELECT *
|
|
272
|
+
FROM messages
|
|
273
|
+
WHERE scope_kind = 'main_chat'
|
|
274
|
+
AND (
|
|
275
|
+
created_at < ?
|
|
276
|
+
OR (created_at = ? AND id < ?)
|
|
277
|
+
)
|
|
278
|
+
ORDER BY created_at DESC, id DESC
|
|
279
|
+
LIMIT ?
|
|
280
|
+
`)
|
|
281
|
+
.all(target.created_at, target.created_at, target.id, beforeLimit + 1);
|
|
282
|
+
const newerRows = db
|
|
283
|
+
.prepare(`
|
|
284
|
+
SELECT *
|
|
285
|
+
FROM messages
|
|
286
|
+
WHERE scope_kind = 'main_chat'
|
|
287
|
+
AND (
|
|
288
|
+
created_at > ?
|
|
289
|
+
OR (created_at = ? AND id > ?)
|
|
290
|
+
)
|
|
291
|
+
ORDER BY created_at ASC, id ASC
|
|
292
|
+
LIMIT ?
|
|
293
|
+
`)
|
|
294
|
+
.all(target.created_at, target.created_at, target.id, afterLimit + 1);
|
|
295
|
+
hasOlder = olderRows.length > beforeLimit;
|
|
296
|
+
hasNewer = newerRows.length > afterLimit;
|
|
297
|
+
rows = [...olderRows.slice(0, beforeLimit).reverse(), target, ...newerRows.slice(0, afterLimit)];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else if (before !== null) {
|
|
252
301
|
rows = db
|
|
253
302
|
.prepare(`
|
|
254
303
|
SELECT *
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { ScratchpadProjection } from "@tutti/shared/schemas/api";
|
|
2
2
|
import type { SqliteDatabase } from "../store/index.js";
|
|
3
|
+
import type { ScratchpadSourceRefRow } from "./storage-types.js";
|
|
3
4
|
import type { ScratchpadSnapshotInput, SubmitScratchpadInput } from "./types.js";
|
|
4
5
|
export declare function createEmptyScratchpadProjection(): ScratchpadProjection;
|
|
5
6
|
export declare function upsertScratchpadProjection(db: SqliteDatabase, input: ScratchpadSnapshotInput): ScratchpadProjection;
|
|
6
7
|
export declare function submitScratchpadProjection(db: SqliteDatabase, input: SubmitScratchpadInput): ScratchpadProjection;
|
|
7
8
|
export declare function readScratchpadProjection(db: SqliteDatabase): ScratchpadProjection;
|
|
9
|
+
export declare function readScratchpadReceiptSourceRefs(db: SqliteDatabase, workflowRef: string): ScratchpadSourceRefRow[];
|
|
8
10
|
//# sourceMappingURL=scratchpad.d.ts.map
|
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
import { nowIso, parseJson, stringifyJson } from "./serialization.js";
|
|
2
2
|
const SCRATCHPAD_RECEIPT_LIMIT = 100;
|
|
3
|
+
function normalizeSourceRefs(sourceRefs = []) {
|
|
4
|
+
const byMessageId = new Map();
|
|
5
|
+
for (const sourceRef of sourceRefs) {
|
|
6
|
+
if (sourceRef.message_id.trim() === "" || sourceRef.created_at.trim() === "") {
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
byMessageId.set(sourceRef.message_id, sourceRef);
|
|
10
|
+
}
|
|
11
|
+
return [...byMessageId.values()].sort((left, right) => {
|
|
12
|
+
const timeOrder = left.created_at.localeCompare(right.created_at);
|
|
13
|
+
return timeOrder === 0 ? left.message_id.localeCompare(right.message_id) : timeOrder;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function replaceCurrentScratchpadSourceRefs(db, sourceRefs) {
|
|
17
|
+
db.prepare("DELETE FROM scratchpad_source_refs WHERE scratchpad_id = 'current'").run();
|
|
18
|
+
const normalized = normalizeSourceRefs(sourceRefs);
|
|
19
|
+
if (normalized.length === 0) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const insert = db.prepare(`
|
|
23
|
+
INSERT INTO scratchpad_source_refs (
|
|
24
|
+
scratchpad_id,
|
|
25
|
+
message_id,
|
|
26
|
+
source_scope,
|
|
27
|
+
created_at
|
|
28
|
+
)
|
|
29
|
+
VALUES ('current', ?, ?, ?)
|
|
30
|
+
`);
|
|
31
|
+
for (const sourceRef of normalized) {
|
|
32
|
+
insert.run(sourceRef.message_id, sourceRef.source_scope, sourceRef.created_at);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function copyCurrentScratchpadSourcesToReceipt(db, workflowRef) {
|
|
36
|
+
db.prepare("DELETE FROM scratchpad_receipt_sources WHERE workflow_ref = ?").run(workflowRef);
|
|
37
|
+
db.prepare(`
|
|
38
|
+
INSERT INTO scratchpad_receipt_sources (
|
|
39
|
+
workflow_ref,
|
|
40
|
+
message_id,
|
|
41
|
+
source_scope,
|
|
42
|
+
created_at
|
|
43
|
+
)
|
|
44
|
+
SELECT
|
|
45
|
+
?,
|
|
46
|
+
message_id,
|
|
47
|
+
source_scope,
|
|
48
|
+
created_at
|
|
49
|
+
FROM scratchpad_source_refs
|
|
50
|
+
WHERE scratchpad_id = 'current'
|
|
51
|
+
ORDER BY created_at ASC, message_id ASC
|
|
52
|
+
`).run(workflowRef);
|
|
53
|
+
}
|
|
3
54
|
export function createEmptyScratchpadProjection() {
|
|
4
55
|
return {
|
|
5
56
|
id: "current",
|
|
@@ -76,6 +127,7 @@ export function upsertScratchpadProjection(db, input) {
|
|
|
76
127
|
submitted_by_workflow_ref = NULL,
|
|
77
128
|
submitted_at = NULL
|
|
78
129
|
`).run(input.topic, input.background_summary, stringifyJson(input.current_consensus), stringifyJson(input.open_questions), stringifyJson(input.task_changes), input.updated_by_activity_ref ?? null, updatedAt);
|
|
130
|
+
replaceCurrentScratchpadSourceRefs(db, input.source_refs);
|
|
79
131
|
return readScratchpadProjection(db);
|
|
80
132
|
}
|
|
81
133
|
export function submitScratchpadProjection(db, input) {
|
|
@@ -105,6 +157,7 @@ export function submitScratchpadProjection(db, input) {
|
|
|
105
157
|
task_changes_json = excluded.task_changes_json,
|
|
106
158
|
submitted_at = excluded.submitted_at
|
|
107
159
|
`).run(input.workflow_ref, input.activity_ref, scratchpad.topic, scratchpad.background_summary, stringifyJson(scratchpad.current_consensus), stringifyJson(scratchpad.open_questions), stringifyJson(scratchpad.task_changes), submittedAt);
|
|
160
|
+
copyCurrentScratchpadSourcesToReceipt(db, input.workflow_ref);
|
|
108
161
|
db.prepare(`
|
|
109
162
|
UPDATE scratchpad
|
|
110
163
|
SET
|
|
@@ -168,4 +221,14 @@ export function readScratchpadProjection(db) {
|
|
|
168
221
|
}
|
|
169
222
|
return scratchpad;
|
|
170
223
|
}
|
|
224
|
+
export function readScratchpadReceiptSourceRefs(db, workflowRef) {
|
|
225
|
+
return db
|
|
226
|
+
.prepare(`
|
|
227
|
+
SELECT message_id, source_scope, created_at
|
|
228
|
+
FROM scratchpad_receipt_sources
|
|
229
|
+
WHERE workflow_ref = ?
|
|
230
|
+
ORDER BY created_at ASC, message_id ASC
|
|
231
|
+
`)
|
|
232
|
+
.all(workflowRef);
|
|
233
|
+
}
|
|
171
234
|
//# sourceMappingURL=scratchpad.js.map
|
|
@@ -35,6 +35,11 @@ export type ScratchpadReceiptRow = {
|
|
|
35
35
|
task_changes_json: string;
|
|
36
36
|
submitted_at: string;
|
|
37
37
|
};
|
|
38
|
+
export type ScratchpadSourceRefRow = {
|
|
39
|
+
message_id: MessageId;
|
|
40
|
+
source_scope: "main_chat" | "clarification_round";
|
|
41
|
+
created_at: string;
|
|
42
|
+
};
|
|
38
43
|
export type ScratchpadSourceStateRow = {
|
|
39
44
|
main_chat_cursor_created_at: string | null;
|
|
40
45
|
main_chat_cursor_message_id: string | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RunLineage } from "@tutti/shared/domain";
|
|
2
2
|
import type { AccountAvatarProjection } from "@tutti/shared/domain";
|
|
3
|
-
import type { ActivityRef, ClarificationRoundRef, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
3
|
+
import type { ActivityRef, ClarificationRoundRef, MessageId, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
4
4
|
import type { ClarificationRequestPayload, ClarificationRoundProjection, ClarificationSuccessorRef, ClarificationThreadProjection, MessageProjection, ReadStateScope, ReadStateSummaryProjection, RecoverySummaryProjection, RunResultProjection, ScratchpadProjection, TaskContractProjection, TaskDetailProjection, TaskDetailResultProjection, TaskProjection, WorklistProjection } from "@tutti/shared/schemas/api";
|
|
5
5
|
export type MessageAuthorInput = {
|
|
6
6
|
kind: "human" | "system" | "agent";
|
|
@@ -53,9 +53,15 @@ export type ScratchpadSnapshotInput = {
|
|
|
53
53
|
current_consensus: string[];
|
|
54
54
|
open_questions: string[];
|
|
55
55
|
task_changes: string[];
|
|
56
|
+
source_refs?: ScratchpadSourceRefInput[];
|
|
56
57
|
updated_by_activity_ref?: ActivityRef;
|
|
57
58
|
now?: () => Date;
|
|
58
59
|
};
|
|
60
|
+
export type ScratchpadSourceRefInput = {
|
|
61
|
+
message_id: MessageId;
|
|
62
|
+
source_scope: "main_chat" | "clarification_round";
|
|
63
|
+
created_at: string;
|
|
64
|
+
};
|
|
59
65
|
export type SubmitScratchpadInput = {
|
|
60
66
|
workflow_ref: WorkflowInvocationRef;
|
|
61
67
|
activity_ref: ActivityRef;
|
|
@@ -286,6 +292,7 @@ export type ReadMessageWindowOptions = {
|
|
|
286
292
|
anchor?: "latest" | "start";
|
|
287
293
|
before?: string;
|
|
288
294
|
after?: string;
|
|
295
|
+
around?: string;
|
|
289
296
|
};
|
|
290
297
|
export type ReadMainChatMessagesAfterOptions = {
|
|
291
298
|
after_created_at: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createEventRef, } from "@tutti/shared/ids";
|
|
2
2
|
import { createMainChatSystemMessage, } from "../collaboration-state/index.js";
|
|
3
|
-
import { EXECUTION_STATUS_INVALIDATES, clarificationInvalidates, procedureFailureInvalidates, taskRunInvalidates, } from "./invalidations.js";
|
|
3
|
+
import { EXECUTION_STATUS_INVALIDATES, clarificationInvalidates, procedureFailureInvalidates, taskRunResultInvalidates, taskRunInvalidates, } from "./invalidations.js";
|
|
4
4
|
import { defaultProcedureFailureSystemMessage } from "./formatters.js";
|
|
5
5
|
function activityEventKind(activity, transitionKind) {
|
|
6
6
|
if (transitionKind === "progress") {
|
|
@@ -37,7 +37,7 @@ export function publishTaskRunStarted(events, task, activityRef) {
|
|
|
37
37
|
}
|
|
38
38
|
export function publishRunResultRecorded(events, recorded) {
|
|
39
39
|
const taskId = recorded.task.id;
|
|
40
|
-
const invalidates =
|
|
40
|
+
const invalidates = taskRunResultInvalidates(taskId, recorded.task_detail.detail.result);
|
|
41
41
|
if ("card_message" in recorded) {
|
|
42
42
|
const threadId = recorded.thread.id;
|
|
43
43
|
const roundId = recorded.round.id;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ClarificationRoundRef, TaskId } from "@tutti/shared/ids";
|
|
2
|
-
import type { QueryInvalidationHint } from "@tutti/shared/schemas/api";
|
|
2
|
+
import type { QueryInvalidationHint, TaskDetailResultProjection } from "@tutti/shared/schemas/api";
|
|
3
3
|
export declare const EXECUTION_STATUS_INVALIDATES: QueryInvalidationHint[];
|
|
4
4
|
export declare const STARTUP_RECOVERY_INVALIDATES: QueryInvalidationHint[];
|
|
5
5
|
export declare function mainChatInvalidates(): QueryInvalidationHint[];
|
|
@@ -8,5 +8,6 @@ export declare function taskCompileInvalidates(): QueryInvalidationHint[];
|
|
|
8
8
|
export declare function projectContextBootstrapInvalidates(): QueryInvalidationHint[];
|
|
9
9
|
export declare function clarificationInvalidates(roundId: ClarificationRoundRef, threadId?: string): QueryInvalidationHint[];
|
|
10
10
|
export declare function taskRunInvalidates(taskId: TaskId): QueryInvalidationHint[];
|
|
11
|
+
export declare function taskRunResultInvalidates(taskId: TaskId, result: TaskDetailResultProjection | undefined): QueryInvalidationHint[];
|
|
11
12
|
export declare function procedureFailureInvalidates(): QueryInvalidationHint[];
|
|
12
13
|
//# sourceMappingURL=invalidations.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const REFERENCE_DIRECTORY_PATH = "docs/reference";
|
|
1
2
|
export const EXECUTION_STATUS_INVALIDATES = [
|
|
2
3
|
{ kind: "execution_status" },
|
|
3
4
|
{ kind: "bootstrap" },
|
|
@@ -57,6 +58,30 @@ export function taskRunInvalidates(taskId) {
|
|
|
57
58
|
{ kind: "bootstrap" },
|
|
58
59
|
];
|
|
59
60
|
}
|
|
61
|
+
function pathTouchesReferenceFiles(path) {
|
|
62
|
+
return path === REFERENCE_DIRECTORY_PATH || path.startsWith(`${REFERENCE_DIRECTORY_PATH}/`);
|
|
63
|
+
}
|
|
64
|
+
function hasArtifactRelevantPromotedChange(paths) {
|
|
65
|
+
// The active artifact root can only be resolved from committed repo state.
|
|
66
|
+
// At this event-publishing layer, conservatively refresh Artifacts for any
|
|
67
|
+
// promoted repo change.
|
|
68
|
+
return paths.length > 0;
|
|
69
|
+
}
|
|
70
|
+
export function taskRunResultInvalidates(taskId, result) {
|
|
71
|
+
const invalidates = taskRunInvalidates(taskId);
|
|
72
|
+
if (result?.promotion?.status !== "promoted" ||
|
|
73
|
+
result.changed_paths === undefined ||
|
|
74
|
+
result.changed_paths.length === 0) {
|
|
75
|
+
return invalidates;
|
|
76
|
+
}
|
|
77
|
+
if (result.changed_paths.some(pathTouchesReferenceFiles)) {
|
|
78
|
+
invalidates.push({ kind: "viewer", path: REFERENCE_DIRECTORY_PATH });
|
|
79
|
+
}
|
|
80
|
+
if (hasArtifactRelevantPromotedChange(result.changed_paths)) {
|
|
81
|
+
invalidates.push({ kind: "artifacts" });
|
|
82
|
+
}
|
|
83
|
+
return invalidates;
|
|
84
|
+
}
|
|
60
85
|
export function procedureFailureInvalidates() {
|
|
61
86
|
return [
|
|
62
87
|
{ kind: "messages", scope: "main_chat" },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createWorkflowInvocationRef, type ActivityRef } from "@tutti/shared/ids";
|
|
2
2
|
import type { RefreshScratchpadDisposition, RefreshScratchpadResult, ProcedureLane } from "@tutti/shared/schemas/api";
|
|
3
3
|
import type { ScratchpadSourceCursorUpdate } from "../collaboration-state/scratchpad-source-state.js";
|
|
4
|
+
import type { ScratchpadSourceRefInput } from "../collaboration-state/types.js";
|
|
4
5
|
import type { ProcedureEngine, ProcedureEngineState } from "../procedure-engine/index.js";
|
|
5
6
|
import type { HostProjectStore } from "../store/index.js";
|
|
6
7
|
import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
|
|
@@ -12,6 +13,7 @@ type ScratchpadProjectContext = {
|
|
|
12
13
|
export type ScratchpadSourceBatch = {
|
|
13
14
|
workflow_input: Parameters<ProcedureWorkflowRunner["runScratchpadRefresh"]>[0];
|
|
14
15
|
cursor_update: ScratchpadSourceCursorUpdate;
|
|
16
|
+
source_refs: ScratchpadSourceRefInput[];
|
|
15
17
|
source_message_count: number;
|
|
16
18
|
};
|
|
17
19
|
export declare function readControlPlaneScratchpadSourceBatch(store: HostProjectStore, options?: {
|
|
@@ -96,6 +96,10 @@ export function readControlPlaneScratchpadSourceBatch(store, options = {}) {
|
|
|
96
96
|
...newMainChatSourceMessages,
|
|
97
97
|
...clarificationSourceMessages,
|
|
98
98
|
]);
|
|
99
|
+
const sourceRefMessages = sortScratchpadSourceMessages([
|
|
100
|
+
...(isInitialMainChatRefresh ? recentMessages : []),
|
|
101
|
+
...sourceMessages,
|
|
102
|
+
]);
|
|
99
103
|
const latestMainChatSource = mainChatSourceMessages.at(-1);
|
|
100
104
|
const latestClarificationRound = clarificationRounds.at(-1);
|
|
101
105
|
const cursorUpdate = {};
|
|
@@ -124,6 +128,11 @@ export function readControlPlaneScratchpadSourceBatch(store, options = {}) {
|
|
|
124
128
|
new_messages: compactScratchpadSourceMessages(sourceMessages),
|
|
125
129
|
},
|
|
126
130
|
cursor_update: cursorUpdate,
|
|
131
|
+
source_refs: sourceRefMessages.map((message) => ({
|
|
132
|
+
message_id: message.id,
|
|
133
|
+
source_scope: message.scope.kind,
|
|
134
|
+
created_at: message.created_at,
|
|
135
|
+
})),
|
|
127
136
|
source_message_count: sourceMessages.length + (isInitialMainChatRefresh ? recentMessages.length : 0),
|
|
128
137
|
};
|
|
129
138
|
}
|
|
@@ -153,6 +162,7 @@ export async function runControlPlaneScratchpadRefreshProcedure(options) {
|
|
|
153
162
|
workflowRef: options.workflowRef,
|
|
154
163
|
activityRef: options.activityRef,
|
|
155
164
|
cursorUpdate: options.sourceBatch.cursor_update,
|
|
165
|
+
sourceRefs: options.sourceBatch.source_refs,
|
|
156
166
|
now: options.now,
|
|
157
167
|
});
|
|
158
168
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ActivityRef, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
2
|
import type { ScratchpadSourceCursorUpdate } from "../collaboration-state/scratchpad-source-state.js";
|
|
3
|
+
import type { ScratchpadSourceRefInput } from "../collaboration-state/types.js";
|
|
3
4
|
import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
|
|
4
5
|
import type { HostProjectStore } from "../store/index.js";
|
|
5
6
|
import type { ScratchpadRefreshWorkflowOutput } from "./workflows/index.js";
|
|
@@ -10,6 +11,7 @@ export declare function applyScratchpadRefreshOutput(input: {
|
|
|
10
11
|
workflowRef: WorkflowInvocationRef;
|
|
11
12
|
activityRef: ActivityRef;
|
|
12
13
|
cursorUpdate: ScratchpadSourceCursorUpdate;
|
|
14
|
+
sourceRefs: ScratchpadSourceRefInput[];
|
|
13
15
|
now: () => Date;
|
|
14
16
|
}): {
|
|
15
17
|
kind: "needs_human";
|
|
@@ -31,6 +31,7 @@ export function applyScratchpadRefreshOutput(input) {
|
|
|
31
31
|
current_consensus: input.output.scratchpad_snapshot.current_consensus,
|
|
32
32
|
open_questions: input.output.scratchpad_snapshot.open_questions,
|
|
33
33
|
task_changes: input.output.scratchpad_snapshot.task_changes,
|
|
34
|
+
source_refs: input.sourceRefs,
|
|
34
35
|
updated_by_activity_ref: input.activityRef,
|
|
35
36
|
now: input.now,
|
|
36
37
|
});
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { type ActivityRef, type EventRef, type TaskId, type WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
|
-
import type { ProjectTimelineItem } from "@tutti/shared/schemas/api";
|
|
3
2
|
import type { SqliteDatabase } from "../store/index.js";
|
|
4
3
|
export type ProjectTimelineEventKind = "context_sync" | "reference_summary" | "promotion_reconcile";
|
|
4
|
+
export type ProjectTimelineEventStatus = "completed" | "failed";
|
|
5
|
+
export type ProjectTimelineEventItem = {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: "procedure" | "promotion";
|
|
8
|
+
occurred_at: string;
|
|
9
|
+
title: string;
|
|
10
|
+
status: ProjectTimelineEventStatus;
|
|
11
|
+
summary?: string;
|
|
12
|
+
activity_ref?: ActivityRef;
|
|
13
|
+
workflow_ref?: WorkflowInvocationRef;
|
|
14
|
+
task_id?: TaskId;
|
|
15
|
+
commit_oid?: string;
|
|
16
|
+
commit_short_oid?: string;
|
|
17
|
+
meta?: string[];
|
|
18
|
+
};
|
|
5
19
|
export type ProjectTimelineEventInput = {
|
|
6
20
|
event_kind: ProjectTimelineEventKind;
|
|
7
|
-
status:
|
|
21
|
+
status: ProjectTimelineEventStatus;
|
|
8
22
|
summary?: string;
|
|
9
23
|
activity_ref?: ActivityRef;
|
|
10
24
|
workflow_ref?: WorkflowInvocationRef;
|
|
@@ -16,5 +30,5 @@ export type ProjectTimelineEventInput = {
|
|
|
16
30
|
export declare function recordProjectTimelineEvent(db: SqliteDatabase, input: ProjectTimelineEventInput): EventRef;
|
|
17
31
|
export declare function readProjectTimelineEventItems(db: SqliteDatabase, options?: {
|
|
18
32
|
limit?: number;
|
|
19
|
-
}):
|
|
33
|
+
}): ProjectTimelineEventItem[];
|
|
20
34
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -8,6 +8,7 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
|
|
|
8
8
|
anchor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"latest">, import("@sinclair/typebox").TLiteral<"start">]>>;
|
|
9
9
|
before: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
10
|
after: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
11
|
+
around: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
11
12
|
}>;
|
|
12
13
|
responses: {
|
|
13
14
|
200: {
|
|
@@ -67,7 +67,7 @@ export declare const HOST_PROJECT_TIMELINE_OPENAPI_ROUTES: {
|
|
|
67
67
|
}>;
|
|
68
68
|
items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
69
69
|
id: import("@sinclair/typebox").TString;
|
|
70
|
-
kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"
|
|
70
|
+
kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"task_accepted">, import("@sinclair/typebox").TLiteral<"task_update">, import("@sinclair/typebox").TLiteral<"checkpoint">]>;
|
|
71
71
|
occurred_at: import("@sinclair/typebox").TString;
|
|
72
72
|
title: import("@sinclair/typebox").TString;
|
|
73
73
|
summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -75,9 +75,10 @@ export declare const HOST_PROJECT_TIMELINE_OPENAPI_ROUTES: {
|
|
|
75
75
|
task_title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
76
76
|
activity_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
77
77
|
workflow_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"
|
|
78
|
+
run_result_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
79
|
+
message_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
80
|
+
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"failed">, import("@sinclair/typebox").TLiteral<"needs_human">]>>;
|
|
81
|
+
update_state: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"needs_input">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"failed">]>>;
|
|
81
82
|
token_usage: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
82
83
|
input_tokens: import("@sinclair/typebox").TInteger;
|
|
83
84
|
cached_input_tokens: import("@sinclair/typebox").TInteger;
|
|
@@ -106,7 +107,95 @@ export declare const HOST_PROJECT_TIMELINE_OPENAPI_ROUTES: {
|
|
|
106
107
|
total_tokens: import("@sinclair/typebox").TInteger;
|
|
107
108
|
event_count: import("@sinclair/typebox").TInteger;
|
|
108
109
|
}>>>;
|
|
109
|
-
|
|
110
|
+
trace_card: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
111
|
+
tone: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"neutral">, import("@sinclair/typebox").TLiteral<"success">, import("@sinclair/typebox").TLiteral<"warning">, import("@sinclair/typebox").TLiteral<"error">]>;
|
|
112
|
+
summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
113
|
+
origin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
114
|
+
title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
115
|
+
summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
116
|
+
snippets: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
117
|
+
message_id: import("@sinclair/typebox").TString;
|
|
118
|
+
author: import("@sinclair/typebox").TString;
|
|
119
|
+
body: import("@sinclair/typebox").TString;
|
|
120
|
+
created_at: import("@sinclair/typebox").TString;
|
|
121
|
+
}>>>;
|
|
122
|
+
source_count: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
123
|
+
unavailable_reason: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
124
|
+
}>>;
|
|
125
|
+
decisions: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
126
|
+
title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
127
|
+
summary: import("@sinclair/typebox").TString;
|
|
128
|
+
source: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"scratchpad">, import("@sinclair/typebox").TLiteral<"clarification">, import("@sinclair/typebox").TLiteral<"contract">]>>;
|
|
129
|
+
}>>>;
|
|
130
|
+
clarification: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
131
|
+
title: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
132
|
+
summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
133
|
+
request: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
134
|
+
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"resolved">]>>;
|
|
135
|
+
answer_count: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
136
|
+
answers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
137
|
+
message_id: import("@sinclair/typebox").TString;
|
|
138
|
+
author: import("@sinclair/typebox").TString;
|
|
139
|
+
body: import("@sinclair/typebox").TString;
|
|
140
|
+
created_at: import("@sinclair/typebox").TString;
|
|
141
|
+
}>>>;
|
|
142
|
+
}>>;
|
|
143
|
+
contract: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
144
|
+
goal: import("@sinclair/typebox").TString;
|
|
145
|
+
scope: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
146
|
+
truncated: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
147
|
+
}>>;
|
|
148
|
+
result: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
149
|
+
summary: import("@sinclair/typebox").TString;
|
|
150
|
+
error_code: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
151
|
+
}>>;
|
|
152
|
+
changes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
153
|
+
items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
154
|
+
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"added">, import("@sinclair/typebox").TLiteral<"modified">, import("@sinclair/typebox").TLiteral<"deleted">, import("@sinclair/typebox").TLiteral<"renamed">, import("@sinclair/typebox").TLiteral<"unknown">]>;
|
|
155
|
+
path: import("@sinclair/typebox").TString;
|
|
156
|
+
previous_path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
157
|
+
}>>;
|
|
158
|
+
total_count: import("@sinclair/typebox").TInteger;
|
|
159
|
+
truncated: import("@sinclair/typebox").TBoolean;
|
|
160
|
+
}>>;
|
|
161
|
+
verification: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
162
|
+
checks: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"passed">, import("@sinclair/typebox").TLiteral<"failed">, import("@sinclair/typebox").TLiteral<"skipped">]>;
|
|
163
|
+
skip_reason_code: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
164
|
+
skip_reason_summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
165
|
+
}>>;
|
|
166
|
+
promotion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
167
|
+
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"promoted">, import("@sinclair/typebox").TLiteral<"not_promoted">, import("@sinclair/typebox").TLiteral<"not_attempted">]>;
|
|
168
|
+
commit_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
169
|
+
commit_short_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
170
|
+
summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
171
|
+
reason_code: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
172
|
+
}>>;
|
|
173
|
+
checkpoint: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
174
|
+
counters: import("@sinclair/typebox").TObject<{
|
|
175
|
+
completed: import("@sinclair/typebox").TInteger;
|
|
176
|
+
failed: import("@sinclair/typebox").TInteger;
|
|
177
|
+
remaining: import("@sinclair/typebox").TInteger;
|
|
178
|
+
}>;
|
|
179
|
+
items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
180
|
+
task_id: import("@sinclair/typebox").TString;
|
|
181
|
+
title: import("@sinclair/typebox").TString;
|
|
182
|
+
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"done">, import("@sinclair/typebox").TLiteral<"failed">]>;
|
|
183
|
+
summary: import("@sinclair/typebox").TString;
|
|
184
|
+
}>>;
|
|
185
|
+
generated_files: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
186
|
+
path: import("@sinclair/typebox").TString;
|
|
187
|
+
name: import("@sinclair/typebox").TString;
|
|
188
|
+
}>>>;
|
|
189
|
+
truncated: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
190
|
+
}>>;
|
|
191
|
+
links: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
192
|
+
kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"worklist_task">, import("@sinclair/typebox").TLiteral<"chat_message">, import("@sinclair/typebox").TLiteral<"reference_file">, import("@sinclair/typebox").TLiteral<"repo_path">]>;
|
|
193
|
+
label: import("@sinclair/typebox").TString;
|
|
194
|
+
task_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
195
|
+
message_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
196
|
+
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
197
|
+
}>>;
|
|
198
|
+
}>>;
|
|
110
199
|
}>>;
|
|
111
200
|
}>;
|
|
112
201
|
};
|