@xfey/tutti 0.1.67 → 0.1.69
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/chat-assistant/index.d.ts +1 -1
- package/dist/chat-assistant/index.js +1 -1
- package/dist/collaboration-state/index.d.ts +1 -1
- package/dist/collaboration-state/index.js +1 -1
- package/dist/collaboration-state/task-compile-context.d.ts +2 -1
- package/dist/collaboration-state/task-compile-context.js +30 -8
- package/dist/control-plane/index.d.ts +9 -2
- package/dist/control-plane/index.js +82 -4
- package/dist/control-plane/recent-references.d.ts +26 -0
- package/dist/control-plane/recent-references.js +94 -0
- package/dist/control-plane/reference-context-types.d.ts +12 -0
- package/dist/control-plane/reference-context-types.js +2 -0
- package/dist/control-plane/reference-summary-refresh.d.ts +5 -1
- package/dist/control-plane/reference-summary-refresh.js +181 -113
- package/dist/control-plane/run-start.js +12 -0
- package/dist/control-plane/task-compile-continuation.d.ts +2 -0
- package/dist/control-plane/task-compile-continuation.js +11 -0
- package/dist/control-plane/task-compile-start.d.ts +2 -0
- package/dist/control-plane/task-compile-start.js +113 -16
- package/dist/control-plane/types.d.ts +2 -0
- package/dist/control-plane/workflows/openai.js +7 -0
- package/dist/control-plane/workflows/types.d.ts +3 -0
- package/dist/providers/openai/app-server/json-rpc.js +13 -1
- package/dist/providers/openai/app-server/linux-sandbox-readiness.js +6 -3
- package/dist/providers/openai/app-server/read-only-procedure.js +2 -2
- package/dist/providers/openai/app-server/smoke.js +2 -2
- package/dist/providers/openai/app-server/workspace-write-run.js +2 -2
- package/dist/providers/openai/codex-app-server.d.ts +10 -0
- package/dist/providers/openai/codex-app-server.js +22 -5
- package/dist/run-pipeline/task-run-invocation.js +3 -0
- package/dist/server-shell/cli/host-server-runtime.js +1 -1
- package/dist/server-shell/http/routes/project-api/messages-routes.js +1 -1
- package/dist/server-shell/http/routes/project-api/reference-files-routes.js +1 -1
- package/dist/server-shell/local-console/invocation-context.d.ts +2 -0
- package/dist/server-shell/local-console/invocation-context.js +10 -1
- package/dist/workspace-ops/index.d.ts +1 -1
- package/dist/workspace-ops/index.js +1 -1
- package/dist/workspace-ops/reference-files.js +98 -34
- package/dist/workspace-ops/reference-summaries.d.ts +5 -0
- package/dist/workspace-ops/reference-summaries.js +6 -5
- package/package.json +2 -2
- package/prompts/README.md +1 -1
- package/prompts/procedures/README.md +1 -1
- package/prompts/procedures/task-compile.md +2 -1
- package/prompts/prompt-flow-map.md +9 -2
- package/prompts/runs/README.md +1 -1
- package/prompts/runs/task-continuation.md +3 -0
- package/prompts/runs/task-retry.md +3 -0
- package/prompts/runs/task-run.md +3 -0
- package/web/assets/{homepage-motion-scene-CblEWSta.js → homepage-motion-scene-D2GZ8Nix.js} +1 -1
- package/web/assets/{index-CH2ZN4W4.js → index-NsxRK6_d.js} +2 -2
- package/web/index.html +1 -1
|
@@ -43,7 +43,7 @@ export type ReadOnlyChatAssistantOptions = {
|
|
|
43
43
|
workspaceRoot: string;
|
|
44
44
|
model: ReadOnlyChatAssistantModel;
|
|
45
45
|
promptsRoot?: string;
|
|
46
|
-
onScratchpadSourceChanged?: () => void;
|
|
46
|
+
onScratchpadSourceChanged?: (message: MessageProjection) => void;
|
|
47
47
|
now?: () => Date;
|
|
48
48
|
};
|
|
49
49
|
export declare function isChatAssistantOutput(value: unknown): value is ChatAssistantOutput;
|
|
@@ -206,7 +206,7 @@ export class ReadOnlyChatAssistant {
|
|
|
206
206
|
invalidates: mainChatMessageInvalidates(),
|
|
207
207
|
});
|
|
208
208
|
if (refs?.scratchpad_source !== "exclude") {
|
|
209
|
-
this.options.onScratchpadSourceChanged?.();
|
|
209
|
+
this.options.onScratchpadSourceChanged?.(message);
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
appendClarificationRoundAssistantMessage(input) {
|
|
@@ -3,7 +3,7 @@ export { createIdleExecutionStatusProjection } from "./execution-status.js";
|
|
|
3
3
|
export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, ensureInitialProjectWelcomeMessage, hasMainChatArtifactPreviewMessage, hasMainChatTaskResultMessage, hasMainChatWorklistCompileMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesBeforeCursor, readMainChatMessagesForScratchpadCycle, } from "./messages.js";
|
|
4
4
|
export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
5
5
|
export { markScratchpadRefreshFailed, markScratchpadRefreshStarted, markScratchpadRefreshSucceeded, markScratchpadSourceDirty, readScratchpadSourceState, } from "./scratchpad-source-state.js";
|
|
6
|
-
export { captureTaskCompileContext, completeTaskCompileContext, readActiveTaskCompileContext, rollbackTaskCompileContext, taskCompileContextSnapshot, } from "./task-compile-context.js";
|
|
6
|
+
export { captureTaskCompileContext, completeTaskCompileContext, readActiveTaskCompileContext, readCurrentScratchpadSourceRefs, rollbackTaskCompileContext, taskCompileContextSnapshot, } from "./task-compile-context.js";
|
|
7
7
|
export { deleteStaleClarificationSubmitReplayHints, readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readClarificationThreadResponse, readSealedClarificationRoundsWithoutSuccessor, } from "./clarification-records.js";
|
|
8
8
|
export { createClarificationRoundAgentMessage, createClarificationRoundMessage, readClarificationRoundMessagesWindow, } from "./clarification-messages.js";
|
|
9
9
|
export { openNextTaskBoundClarificationRound, openNextTaskCompileClarificationRound, openTaskCompileClarificationRound, } from "./clarification-rounds.js";
|
|
@@ -3,7 +3,7 @@ export { createIdleExecutionStatusProjection } from "./execution-status.js";
|
|
|
3
3
|
export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, ensureInitialProjectWelcomeMessage, hasMainChatArtifactPreviewMessage, hasMainChatTaskResultMessage, hasMainChatWorklistCompileMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesBeforeCursor, readMainChatMessagesForScratchpadCycle, } from "./messages.js";
|
|
4
4
|
export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
5
5
|
export { markScratchpadRefreshFailed, markScratchpadRefreshStarted, markScratchpadRefreshSucceeded, markScratchpadSourceDirty, readScratchpadSourceState, } from "./scratchpad-source-state.js";
|
|
6
|
-
export { captureTaskCompileContext, completeTaskCompileContext, readActiveTaskCompileContext, rollbackTaskCompileContext, taskCompileContextSnapshot, } from "./task-compile-context.js";
|
|
6
|
+
export { captureTaskCompileContext, completeTaskCompileContext, readActiveTaskCompileContext, readCurrentScratchpadSourceRefs, rollbackTaskCompileContext, taskCompileContextSnapshot, } from "./task-compile-context.js";
|
|
7
7
|
export { deleteStaleClarificationSubmitReplayHints, readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readClarificationThreadResponse, readSealedClarificationRoundsWithoutSuccessor, } from "./clarification-records.js";
|
|
8
8
|
export { createClarificationRoundAgentMessage, createClarificationRoundMessage, readClarificationRoundMessagesWindow, } from "./clarification-messages.js";
|
|
9
9
|
export { openNextTaskBoundClarificationRound, openNextTaskCompileClarificationRound, openTaskCompileClarificationRound, } from "./clarification-rounds.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
2
|
import { type SqliteDatabase } from "../store/index.js";
|
|
3
|
-
import type { CaptureTaskCompileContextInput, CompleteTaskCompileContextInput, RollbackTaskCompileContextInput, ScratchpadContentSnapshot, TaskCompileContextRecord } from "./types.js";
|
|
3
|
+
import type { CaptureTaskCompileContextInput, CompleteTaskCompileContextInput, RollbackTaskCompileContextInput, ScratchpadContentSnapshot, ScratchpadSourceRefInput, TaskCompileContextRecord } from "./types.js";
|
|
4
4
|
export declare function readActiveTaskCompileContext(db: SqliteDatabase, workflowRef?: WorkflowInvocationRef): TaskCompileContextRecord | null;
|
|
5
|
+
export declare function readCurrentScratchpadSourceRefs(db: SqliteDatabase): ScratchpadSourceRefInput[];
|
|
5
6
|
export declare function captureTaskCompileContext(db: SqliteDatabase, input: CaptureTaskCompileContextInput): TaskCompileContextRecord;
|
|
6
7
|
export declare function completeTaskCompileContext(db: SqliteDatabase, input: CompleteTaskCompileContextInput): {
|
|
7
8
|
updated_at?: string;
|
|
@@ -2,6 +2,16 @@ import { withHostStoreTransaction } from "../store/index.js";
|
|
|
2
2
|
import { readScratchpadProjection } from "./scratchpad.js";
|
|
3
3
|
import { readScratchpadSourceState } from "./scratchpad-source-state.js";
|
|
4
4
|
import { nowIso, stringifyJson } from "./serialization.js";
|
|
5
|
+
function cursorIsAfter(left, right) {
|
|
6
|
+
if (left === undefined) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (right === undefined) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const timeOrder = left.created_at.localeCompare(right.created_at);
|
|
13
|
+
return timeOrder > 0 || (timeOrder === 0 && left.message_id > right.message_id);
|
|
14
|
+
}
|
|
5
15
|
function parseStringArray(value, field) {
|
|
6
16
|
let parsed;
|
|
7
17
|
try {
|
|
@@ -89,7 +99,7 @@ export function readActiveTaskCompileContext(db, workflowRef) {
|
|
|
89
99
|
}
|
|
90
100
|
return mapContextRow(row, readContextSources(db, row.workflow_ref));
|
|
91
101
|
}
|
|
92
|
-
function
|
|
102
|
+
export function readCurrentScratchpadSourceRefs(db) {
|
|
93
103
|
return db
|
|
94
104
|
.prepare(`
|
|
95
105
|
SELECT message_id, created_at
|
|
@@ -98,7 +108,12 @@ function currentScratchpadSources(db) {
|
|
|
98
108
|
AND source_scope = 'main_chat'
|
|
99
109
|
ORDER BY created_at ASC, message_id ASC
|
|
100
110
|
`)
|
|
101
|
-
.all()
|
|
111
|
+
.all()
|
|
112
|
+
.map((source) => ({
|
|
113
|
+
message_id: source.message_id,
|
|
114
|
+
source_scope: "main_chat",
|
|
115
|
+
created_at: source.created_at,
|
|
116
|
+
}));
|
|
102
117
|
}
|
|
103
118
|
export function captureTaskCompileContext(db, input) {
|
|
104
119
|
return withHostStoreTransaction(db, (tx) => {
|
|
@@ -114,7 +129,7 @@ export function captureTaskCompileContext(db, input) {
|
|
|
114
129
|
throw new Error("A ready Scratchpad is required to capture Task Compile Context");
|
|
115
130
|
}
|
|
116
131
|
const sourceState = readScratchpadSourceState(tx);
|
|
117
|
-
const sources =
|
|
132
|
+
const sources = readCurrentScratchpadSourceRefs(tx);
|
|
118
133
|
const lastSource = sources.at(-1);
|
|
119
134
|
const through = sourceState.refreshed_through_cursor ??
|
|
120
135
|
(lastSource === undefined
|
|
@@ -233,11 +248,18 @@ export function rollbackTaskCompileContext(db, input) {
|
|
|
233
248
|
}
|
|
234
249
|
const rolledBackAt = nowIso(input.now);
|
|
235
250
|
const sourceState = readScratchpadSourceState(tx);
|
|
236
|
-
const dirtySince = sourceState.in_flight !== undefined &&
|
|
237
|
-
new Date(rolledBackAt).getTime() <= new Date(sourceState.in_flight.started_at).getTime()
|
|
238
|
-
? new Date(new Date(sourceState.in_flight.started_at).getTime() + 1).toISOString()
|
|
239
|
-
: rolledBackAt;
|
|
240
251
|
const after = context.source_window.after;
|
|
252
|
+
const through = context.source_window.through;
|
|
253
|
+
const hasBoundaryAfterSourceChanges = sourceState.dirty_since !== undefined ||
|
|
254
|
+
sourceState.in_flight !== undefined ||
|
|
255
|
+
cursorIsAfter(sourceState.refreshed_through_cursor, through);
|
|
256
|
+
const dirtySince = hasBoundaryAfterSourceChanges
|
|
257
|
+
? sourceState.in_flight !== undefined &&
|
|
258
|
+
new Date(rolledBackAt).getTime() <= new Date(sourceState.in_flight.started_at).getTime()
|
|
259
|
+
? new Date(new Date(sourceState.in_flight.started_at).getTime() + 1).toISOString()
|
|
260
|
+
: rolledBackAt
|
|
261
|
+
: null;
|
|
262
|
+
const restoredThrough = hasBoundaryAfterSourceChanges ? after : through;
|
|
241
263
|
tx.prepare(`
|
|
242
264
|
INSERT INTO scratchpad_source_state (
|
|
243
265
|
id,
|
|
@@ -256,7 +278,7 @@ export function rollbackTaskCompileContext(db, input) {
|
|
|
256
278
|
refreshed_through_cursor_message_id = excluded.refreshed_through_cursor_message_id,
|
|
257
279
|
dirty_since = excluded.dirty_since,
|
|
258
280
|
updated_at = excluded.updated_at
|
|
259
|
-
`).run(after?.created_at ?? null, after?.message_id ?? null,
|
|
281
|
+
`).run(after?.created_at ?? null, after?.message_id ?? null, restoredThrough?.created_at ?? null, restoredThrough?.message_id ?? null, dirtySince, rolledBackAt);
|
|
260
282
|
tx.prepare("DELETE FROM active_task_compile_context WHERE workflow_ref = ?").run(input.workflow_ref);
|
|
261
283
|
return true;
|
|
262
284
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ActivityRef, type ClarificationRoundRef, type IdempotencyKey, type WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
|
-
import type { ExecutionStatusProjection, ContextSyncDisposition, ContextSyncResult, RefreshScratchpadDisposition, RefreshScratchpadResult, RunSchedulerNowDisposition, RunSchedulerNowPayload, RefreshReferenceSummariesDisposition, RefreshReferenceSummariesPayload, RefreshReferenceSummariesResult, SendClarificationRoundMessageDisposition, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResult, SubmitClarificationRoundDisposition, SubmitClarificationRoundPayload, SubmitClarificationRoundResult, SubmitWorklistDisposition, SubmitWorklistPayload, SubmitWorklistResult, ProcedureLane } from "@tutti/shared/schemas/api";
|
|
2
|
+
import type { ExecutionStatusProjection, MessageProjection, ContextSyncDisposition, ContextSyncResult, RefreshScratchpadDisposition, RefreshScratchpadResult, RunSchedulerNowDisposition, RunSchedulerNowPayload, RefreshReferenceSummariesDisposition, RefreshReferenceSummariesPayload, RefreshReferenceSummariesResult, SendClarificationRoundMessageDisposition, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResult, SubmitClarificationRoundDisposition, SubmitClarificationRoundPayload, SubmitClarificationRoundResult, SubmitWorklistDisposition, SubmitWorklistPayload, SubmitWorklistResult, ProcedureLane } from "@tutti/shared/schemas/api";
|
|
3
3
|
import type { ContextSyncWorkflowTrigger } from "./workflows/index.js";
|
|
4
4
|
import type { ControlPlaneCommandResult, Phase5ControlPlaneOptions, StartupRecoveryOptions, StartupRecoveryResult, TrustedHumanAuthor } from "./types.js";
|
|
5
5
|
import { type ProjectBriefRefreshReason, type RefreshProjectBriefProjectionResult } from "./project-brief-refresh.js";
|
|
@@ -18,6 +18,10 @@ export declare class Phase5ControlPlane {
|
|
|
18
18
|
private readonly runLifecycle;
|
|
19
19
|
private readonly now;
|
|
20
20
|
private readonly scratchpadAutoRefreshScheduler;
|
|
21
|
+
private readonly pendingReferenceSummaryPaths;
|
|
22
|
+
private readonly referenceSummaryWaiters;
|
|
23
|
+
private pendingAllReferenceSummaries;
|
|
24
|
+
private referenceSummaryStartScheduled;
|
|
21
25
|
private lastRecoveryConclusion;
|
|
22
26
|
constructor(options: Phase5ControlPlaneOptions);
|
|
23
27
|
getExecutionStatus(): ExecutionStatusProjection;
|
|
@@ -26,7 +30,7 @@ export declare class Phase5ControlPlane {
|
|
|
26
30
|
startScratchpadRefresh(options?: {
|
|
27
31
|
lane?: ProcedureLane;
|
|
28
32
|
}): ControlPlaneCommandResult<RefreshScratchpadDisposition, RefreshScratchpadResult>;
|
|
29
|
-
notifyScratchpadSourceChanged(): void;
|
|
33
|
+
notifyScratchpadSourceChanged(message: MessageProjection): void;
|
|
30
34
|
refreshProjectBrief(options: {
|
|
31
35
|
reason: ProjectBriefRefreshReason;
|
|
32
36
|
workflowRef?: WorkflowInvocationRef;
|
|
@@ -36,9 +40,12 @@ export declare class Phase5ControlPlane {
|
|
|
36
40
|
startTaskCompile(payload: SubmitWorklistPayload): ControlPlaneCommandResult<SubmitWorklistDisposition, SubmitWorklistResult>;
|
|
37
41
|
startContextSyncAnalysis(trigger?: ContextSyncWorkflowTrigger): ControlPlaneCommandResult<ContextSyncDisposition, ContextSyncResult>;
|
|
38
42
|
startReferenceSummaryRefresh(payload?: RefreshReferenceSummariesPayload): ControlPlaneCommandResult<RefreshReferenceSummariesDisposition, RefreshReferenceSummariesResult>;
|
|
43
|
+
private tryStartPendingReferenceSummaryRefresh;
|
|
39
44
|
sendClarificationRoundMessage(roundId: ClarificationRoundRef, payload: SendClarificationRoundMessagePayload, author: TrustedHumanAuthor): ControlPlaneCommandResult<SendClarificationRoundMessageDisposition, SendClarificationRoundMessageResult>;
|
|
40
45
|
submitClarificationRound(roundId: ClarificationRoundRef, payload: SubmitClarificationRoundPayload, commandId: IdempotencyKey): ControlPlaneCommandResult<SubmitClarificationRoundDisposition, SubmitClarificationRoundResult>;
|
|
41
46
|
waitForIdle(): Promise<void>;
|
|
47
|
+
private hasPendingReferenceSummaryRefresh;
|
|
48
|
+
private schedulePendingReferenceSummaryRefresh;
|
|
42
49
|
private startRunForTask;
|
|
43
50
|
private readActiveRun;
|
|
44
51
|
private readActiveProcedures;
|
|
@@ -9,6 +9,7 @@ import { runControlPlaneStartupRecovery } from "./startup-recovery.js";
|
|
|
9
9
|
import { readControlPlaneExecutionStatus } from "./execution-status.js";
|
|
10
10
|
import { ScratchpadAutoRefreshScheduler } from "./scratchpad-auto-refresh.js";
|
|
11
11
|
import { startControlPlaneScratchpadRefresh } from "./scratchpad-refresh-start.js";
|
|
12
|
+
import { shouldUseMessageAsScratchpadSource } from "./scratchpad-source-messages.js";
|
|
12
13
|
import { startControlPlaneTaskCompile } from "./task-compile-start.js";
|
|
13
14
|
import { startControlPlaneTaskCompileContinuation } from "./task-compile-continuation.js";
|
|
14
15
|
import { startControlPlaneTaskBoundFollowUpCheck } from "./follow-up-start.js";
|
|
@@ -30,6 +31,10 @@ export class Phase5ControlPlane {
|
|
|
30
31
|
runLifecycle;
|
|
31
32
|
now;
|
|
32
33
|
scratchpadAutoRefreshScheduler;
|
|
34
|
+
pendingReferenceSummaryPaths = new Set();
|
|
35
|
+
referenceSummaryWaiters = new Map();
|
|
36
|
+
pendingAllReferenceSummaries = false;
|
|
37
|
+
referenceSummaryStartScheduled = false;
|
|
33
38
|
lastRecoveryConclusion = null;
|
|
34
39
|
constructor(options) {
|
|
35
40
|
this.store = options.store;
|
|
@@ -102,7 +107,10 @@ export class Phase5ControlPlane {
|
|
|
102
107
|
publishProcedureTransition: (state) => this.publishProcedureTransition(state),
|
|
103
108
|
});
|
|
104
109
|
}
|
|
105
|
-
notifyScratchpadSourceChanged() {
|
|
110
|
+
notifyScratchpadSourceChanged(message) {
|
|
111
|
+
if (!shouldUseMessageAsScratchpadSource(message)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
106
114
|
this.scratchpadAutoRefreshScheduler.notifySourceChanged();
|
|
107
115
|
}
|
|
108
116
|
refreshProjectBrief(options) {
|
|
@@ -139,6 +147,11 @@ export class Phase5ControlPlane {
|
|
|
139
147
|
this.tryRunTaskArrivalScheduler();
|
|
140
148
|
}
|
|
141
149
|
},
|
|
150
|
+
registerReferenceSummaryWaiter: (activityRef, waiter) => {
|
|
151
|
+
const existing = this.referenceSummaryWaiters.get(activityRef) ?? [];
|
|
152
|
+
existing.push(waiter);
|
|
153
|
+
this.referenceSummaryWaiters.set(activityRef, existing);
|
|
154
|
+
},
|
|
142
155
|
onTasksAdded: () => {
|
|
143
156
|
tasksAdded = true;
|
|
144
157
|
},
|
|
@@ -159,11 +172,25 @@ export class Phase5ControlPlane {
|
|
|
159
172
|
});
|
|
160
173
|
}
|
|
161
174
|
startReferenceSummaryRefresh(payload = {}) {
|
|
162
|
-
|
|
175
|
+
if (payload.paths === undefined) {
|
|
176
|
+
this.pendingAllReferenceSummaries = true;
|
|
177
|
+
this.pendingReferenceSummaryPaths.clear();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
for (const path of payload.paths) {
|
|
181
|
+
this.pendingReferenceSummaryPaths.add(path);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return this.tryStartPendingReferenceSummaryRefresh();
|
|
185
|
+
}
|
|
186
|
+
tryStartPendingReferenceSummaryRefresh() {
|
|
187
|
+
const refreshAll = this.pendingAllReferenceSummaries;
|
|
188
|
+
const paths = refreshAll ? undefined : [...this.pendingReferenceSummaryPaths];
|
|
189
|
+
const result = startReferenceSummaryRefreshProcedure({
|
|
163
190
|
engine: this.engine,
|
|
164
191
|
store: this.store,
|
|
165
192
|
events: this.events,
|
|
166
|
-
...(
|
|
193
|
+
...(paths === undefined ? {} : { paths }),
|
|
167
194
|
resolveWorkflowRunner: this.resolveWorkflowRunner,
|
|
168
195
|
readActiveActivity: () => this.readSchedulerBlocker(),
|
|
169
196
|
projectContext: this.projectContext,
|
|
@@ -171,6 +198,18 @@ export class Phase5ControlPlane {
|
|
|
171
198
|
now: this.now,
|
|
172
199
|
publishProcedureTransition: (state) => this.publishProcedureTransition(state),
|
|
173
200
|
});
|
|
201
|
+
if (result.disposition.kind !== "already_running") {
|
|
202
|
+
if (refreshAll) {
|
|
203
|
+
this.pendingAllReferenceSummaries = false;
|
|
204
|
+
this.pendingReferenceSummaryPaths.clear();
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
for (const path of paths ?? []) {
|
|
208
|
+
this.pendingReferenceSummaryPaths.delete(path);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
174
213
|
}
|
|
175
214
|
sendClarificationRoundMessage(roundId, payload, author) {
|
|
176
215
|
return runSendClarificationRoundMessage({
|
|
@@ -198,11 +237,29 @@ export class Phase5ControlPlane {
|
|
|
198
237
|
while (true) {
|
|
199
238
|
await this.engine.waitForIdle();
|
|
200
239
|
await this.runEngine.waitForIdle();
|
|
201
|
-
|
|
240
|
+
await Promise.resolve();
|
|
241
|
+
if (this.readAnyActiveActivity() === null &&
|
|
242
|
+
!this.hasPendingReferenceSummaryRefresh()) {
|
|
202
243
|
return;
|
|
203
244
|
}
|
|
245
|
+
this.schedulePendingReferenceSummaryRefresh();
|
|
204
246
|
}
|
|
205
247
|
}
|
|
248
|
+
hasPendingReferenceSummaryRefresh() {
|
|
249
|
+
return this.pendingAllReferenceSummaries || this.pendingReferenceSummaryPaths.size !== 0;
|
|
250
|
+
}
|
|
251
|
+
schedulePendingReferenceSummaryRefresh() {
|
|
252
|
+
if (!this.hasPendingReferenceSummaryRefresh() || this.referenceSummaryStartScheduled) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
this.referenceSummaryStartScheduled = true;
|
|
256
|
+
queueMicrotask(() => {
|
|
257
|
+
this.referenceSummaryStartScheduled = false;
|
|
258
|
+
if (this.hasPendingReferenceSummaryRefresh()) {
|
|
259
|
+
void this.tryStartPendingReferenceSummaryRefresh();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
206
263
|
startRunForTask(input) {
|
|
207
264
|
const result = startControlPlaneRunForTask({
|
|
208
265
|
runEngine: this.runEngine,
|
|
@@ -304,6 +361,9 @@ export class Phase5ControlPlane {
|
|
|
304
361
|
onTerminal: (terminalState) => this.handleRunTerminalTransition(terminalState),
|
|
305
362
|
});
|
|
306
363
|
this.scratchpadAutoRefreshScheduler.notifyActivityChanged();
|
|
364
|
+
if (state.transition_kind === "terminal") {
|
|
365
|
+
this.schedulePendingReferenceSummaryRefresh();
|
|
366
|
+
}
|
|
307
367
|
}
|
|
308
368
|
handleRunTerminalTransition(state) {
|
|
309
369
|
if (state.activity.status === "finished") {
|
|
@@ -377,6 +437,7 @@ export class Phase5ControlPlane {
|
|
|
377
437
|
owner,
|
|
378
438
|
roundId,
|
|
379
439
|
resolveWorkflowRunner: this.resolveWorkflowRunner,
|
|
440
|
+
projectContext: this.projectContext,
|
|
380
441
|
logger: this.logger,
|
|
381
442
|
now: this.now,
|
|
382
443
|
publishProcedureTransition: (state) => {
|
|
@@ -421,6 +482,23 @@ export class Phase5ControlPlane {
|
|
|
421
482
|
getExecutionStatus: () => this.getExecutionStatus(),
|
|
422
483
|
});
|
|
423
484
|
this.scratchpadAutoRefreshScheduler.notifyActivityChanged();
|
|
485
|
+
if (state.transition_kind === "terminal") {
|
|
486
|
+
const activityRef = state.activity.activity_ref;
|
|
487
|
+
const waiters = this.referenceSummaryWaiters.get(activityRef) ?? [];
|
|
488
|
+
this.referenceSummaryWaiters.delete(activityRef);
|
|
489
|
+
for (const waiter of waiters) {
|
|
490
|
+
try {
|
|
491
|
+
waiter(state);
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
this.logger?.info({
|
|
495
|
+
activity_ref: activityRef,
|
|
496
|
+
error_name: error instanceof Error ? error.name : "UnknownError",
|
|
497
|
+
}, "Reference summary continuation failed");
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
this.schedulePendingReferenceSummaryRefresh();
|
|
501
|
+
}
|
|
424
502
|
}
|
|
425
503
|
logProcedureTransition(state) {
|
|
426
504
|
const activity = state.activity;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MessageId } from "@tutti/shared/ids";
|
|
2
|
+
import type { MessageReferenceFileRef } from "@tutti/shared/schemas/api";
|
|
3
|
+
import type { ScratchpadSourceRefInput } from "../collaboration-state/types.js";
|
|
4
|
+
import type { SqliteDatabase } from "../store/index.js";
|
|
5
|
+
import type { RecentReferenceContext } from "./reference-context-types.js";
|
|
6
|
+
export type RecentReferenceSource = MessageReferenceFileRef & {
|
|
7
|
+
message_id: MessageId;
|
|
8
|
+
};
|
|
9
|
+
export declare function readRecentReferenceSources(db: SqliteDatabase, sourceRefs: Array<Pick<ScratchpadSourceRefInput, "message_id">>): RecentReferenceSource[];
|
|
10
|
+
export declare function readPendingRecentReferenceSummaryPaths(options: {
|
|
11
|
+
workspaceRoot: string;
|
|
12
|
+
sources: RecentReferenceSource[];
|
|
13
|
+
now: () => Date;
|
|
14
|
+
}): string[];
|
|
15
|
+
export declare function materializeRecentReferences(options: {
|
|
16
|
+
workspaceRoot: string;
|
|
17
|
+
sources: RecentReferenceSource[];
|
|
18
|
+
now: () => Date;
|
|
19
|
+
}): RecentReferenceContext[];
|
|
20
|
+
export declare function materializeWorkflowRecentReferences(options: {
|
|
21
|
+
db: SqliteDatabase;
|
|
22
|
+
workspaceRoot: string;
|
|
23
|
+
workflowRef: string;
|
|
24
|
+
now: () => Date;
|
|
25
|
+
}): RecentReferenceContext[];
|
|
26
|
+
//# sourceMappingURL=recent-references.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { readMessageProjectionById, readScratchpadReceiptSourceRefs, } from "../collaboration-state/index.js";
|
|
2
|
+
import { readReferenceSummaryEntries } from "../workspace-ops/index.js";
|
|
3
|
+
export function readRecentReferenceSources(db, sourceRefs) {
|
|
4
|
+
const sources = [];
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
for (const sourceRef of sourceRefs) {
|
|
7
|
+
const message = readMessageProjectionById(db, sourceRef.message_id);
|
|
8
|
+
const reference = message?.refs?.reference_file;
|
|
9
|
+
if (message?.author.kind !== "human" ||
|
|
10
|
+
reference === undefined ||
|
|
11
|
+
reference.source !== "human_upload") {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const identity = `${reference.path}\u0000${reference.blob_oid ?? ""}`;
|
|
15
|
+
if (seen.has(identity)) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
seen.add(identity);
|
|
19
|
+
sources.push({ message_id: sourceRef.message_id, ...reference });
|
|
20
|
+
}
|
|
21
|
+
return sources;
|
|
22
|
+
}
|
|
23
|
+
export function readPendingRecentReferenceSummaryPaths(options) {
|
|
24
|
+
const paths = [...new Set(options.sources.map((source) => source.path))];
|
|
25
|
+
if (paths.length === 0) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
const entries = new Map(readReferenceSummaryEntries({
|
|
29
|
+
workspaceRoot: options.workspaceRoot,
|
|
30
|
+
paths,
|
|
31
|
+
now: options.now,
|
|
32
|
+
}).map((entry) => [entry.path, entry]));
|
|
33
|
+
const pending = new Set();
|
|
34
|
+
for (const source of options.sources) {
|
|
35
|
+
const entry = entries.get(source.path);
|
|
36
|
+
if (source.blob_oid === undefined ||
|
|
37
|
+
entry === undefined ||
|
|
38
|
+
entry.blob_oid !== source.blob_oid) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (entry.summary.status === "missing" || entry.summary.status === "stale") {
|
|
42
|
+
pending.add(source.path);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [...pending];
|
|
46
|
+
}
|
|
47
|
+
export function materializeRecentReferences(options) {
|
|
48
|
+
const paths = [...new Set(options.sources.map((source) => source.path))];
|
|
49
|
+
const entries = new Map(paths.length === 0
|
|
50
|
+
? []
|
|
51
|
+
: readReferenceSummaryEntries({
|
|
52
|
+
workspaceRoot: options.workspaceRoot,
|
|
53
|
+
paths,
|
|
54
|
+
now: options.now,
|
|
55
|
+
}).map((entry) => [entry.path, entry]));
|
|
56
|
+
return options.sources.map((source) => {
|
|
57
|
+
const entry = entries.get(source.path);
|
|
58
|
+
if (source.blob_oid === undefined) {
|
|
59
|
+
return unavailableRecentReference(source, "source_blob_unavailable");
|
|
60
|
+
}
|
|
61
|
+
if (entry === undefined) {
|
|
62
|
+
return unavailableRecentReference(source, "reference_unavailable");
|
|
63
|
+
}
|
|
64
|
+
if (entry.blob_oid !== source.blob_oid) {
|
|
65
|
+
return unavailableRecentReference(source, "reference_source_changed");
|
|
66
|
+
}
|
|
67
|
+
if (entry.summary.status === "available" && entry.summary.text !== undefined) {
|
|
68
|
+
return {
|
|
69
|
+
path: source.path,
|
|
70
|
+
name: source.name,
|
|
71
|
+
summary: { status: "available", text: entry.summary.text },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (entry.summary.status === "unavailable") {
|
|
75
|
+
return unavailableRecentReference(source, entry.summary.unavailable_reason ?? "summary_unavailable");
|
|
76
|
+
}
|
|
77
|
+
return unavailableRecentReference(source, "summary_not_ready");
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export function materializeWorkflowRecentReferences(options) {
|
|
81
|
+
return materializeRecentReferences({
|
|
82
|
+
workspaceRoot: options.workspaceRoot,
|
|
83
|
+
sources: readRecentReferenceSources(options.db, readScratchpadReceiptSourceRefs(options.db, options.workflowRef)),
|
|
84
|
+
now: options.now,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function unavailableRecentReference(source, reason) {
|
|
88
|
+
return {
|
|
89
|
+
path: source.path,
|
|
90
|
+
name: source.name,
|
|
91
|
+
summary: { status: "unavailable", reason },
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=recent-references.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActivityRef } from "@tutti/shared/ids";
|
|
1
|
+
import type { ActivityRef, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
2
|
import type { RefreshReferenceSummariesDisposition, RefreshReferenceSummariesResult } from "@tutti/shared/schemas/api";
|
|
3
3
|
import type { ProcedureEngine, ProcedureEngineState } from "../procedure-engine/index.js";
|
|
4
4
|
import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
|
|
@@ -17,6 +17,10 @@ export declare function startReferenceSummaryRefreshProcedure(input: {
|
|
|
17
17
|
projectContext: Phase5ControlPlaneOptions["projectContext"];
|
|
18
18
|
logger?: ControlPlaneLogger | undefined;
|
|
19
19
|
now: () => Date;
|
|
20
|
+
onExecuteStart?: (input: {
|
|
21
|
+
activityRef: ActivityRef;
|
|
22
|
+
workflowRef: WorkflowInvocationRef;
|
|
23
|
+
}) => void;
|
|
20
24
|
publishProcedureTransition: (state: ProcedureEngineState) => void;
|
|
21
25
|
}): ControlPlaneCommandResult<RefreshReferenceSummariesDisposition, RefreshReferenceSummariesResult>;
|
|
22
26
|
//# sourceMappingURL=reference-summary-refresh.d.ts.map
|