@xfey/tutti 0.1.66 → 0.1.68
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/task-compile-context.d.ts +2 -1
- package/dist/collaboration-state/task-compile-context.js +8 -3
- package/dist/control-plane/index.d.ts +7 -0
- package/dist/control-plane/index.js +77 -3
- 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/run-pipeline/task-run-invocation.js +3 -0
- 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-Doj_Soje.js → homepage-motion-scene-D2GZ8Nix.js} +1 -1
- package/web/assets/{index-DuT1ti0p.js → index-NsxRK6_d.js} +2 -2
- package/web/index.html +1 -1
|
@@ -2,6 +2,8 @@ import { createWorkflowInvocationRef } from "@tutti/shared/ids";
|
|
|
2
2
|
import { recordProjectTimelineEvent } from "../project-timeline/index.js";
|
|
3
3
|
import { WorkspaceOpsError, readReferenceSummaryTargets, updateReferenceSummaries, } from "../workspace-ops/index.js";
|
|
4
4
|
import { logProcedureExecutionError } from "./procedure-logging.js";
|
|
5
|
+
const REFERENCE_SUMMARY_CONCURRENCY = 2;
|
|
6
|
+
const REFERENCE_SUMMARY_MAX_ATTEMPTS = 2;
|
|
5
7
|
function publishReferenceSummaryTimelineChanged(input) {
|
|
6
8
|
input.events.publish({
|
|
7
9
|
event_type: "query.invalidate",
|
|
@@ -62,111 +64,104 @@ function logNotStarted(input) {
|
|
|
62
64
|
}, "Reference summary refresh not started");
|
|
63
65
|
}
|
|
64
66
|
async function runReferenceSummaryRefresh(options) {
|
|
65
|
-
|
|
67
|
+
let targets = options.targets;
|
|
68
|
+
const processedTargets = new Set();
|
|
69
|
+
let targetCount = 0;
|
|
70
|
+
let updatedCount = 0;
|
|
66
71
|
let failedCount = 0;
|
|
67
72
|
let adapterUnavailableCount = 0;
|
|
68
|
-
|
|
73
|
+
let lastCommitOid;
|
|
74
|
+
while (targets.length !== 0) {
|
|
75
|
+
const batch = targets.filter((target) => !processedTargets.has(`${target.path}\u0000${target.blob_oid}`));
|
|
76
|
+
if (batch.length === 0) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
for (const target of batch) {
|
|
80
|
+
processedTargets.add(`${target.path}\u0000${target.blob_oid}`);
|
|
81
|
+
}
|
|
82
|
+
targetCount += batch.length;
|
|
83
|
+
options.reportProgress?.({
|
|
84
|
+
phase: "reference_summary_batch",
|
|
85
|
+
summary: `Summarizing ${batch.length} reference file${batch.length === 1 ? "" : "s"}.`,
|
|
86
|
+
});
|
|
87
|
+
let completedInBatch = 0;
|
|
88
|
+
const batchResults = await mapWithConcurrency(batch, REFERENCE_SUMMARY_CONCURRENCY, async (target) => {
|
|
89
|
+
const result = await summarizeReferenceTarget({
|
|
90
|
+
target,
|
|
91
|
+
runner: options.runner,
|
|
92
|
+
workflowRef: options.workflowRef,
|
|
93
|
+
activityRef: options.activityRef,
|
|
94
|
+
logger: options.logger,
|
|
95
|
+
now: options.now,
|
|
96
|
+
});
|
|
97
|
+
completedInBatch += 1;
|
|
98
|
+
options.reportProgress?.({
|
|
99
|
+
phase: "reference_summary_batch",
|
|
100
|
+
summary: `Processed ${completedInBatch} of ${batch.length} reference files.`,
|
|
101
|
+
});
|
|
102
|
+
return result;
|
|
103
|
+
});
|
|
104
|
+
const summaries = batchResults.map((entry) => entry.summary);
|
|
105
|
+
failedCount += batchResults.filter((entry) => entry.failed).length;
|
|
106
|
+
adapterUnavailableCount += batchResults.filter((entry) => entry.adapterUnavailable).length;
|
|
107
|
+
let result;
|
|
69
108
|
try {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
path: target.path,
|
|
75
|
-
name: target.name,
|
|
76
|
-
category: target.category,
|
|
77
|
-
size_bytes: target.size_bytes,
|
|
78
|
-
blob_oid: target.blob_oid,
|
|
79
|
-
...(target.media_type === undefined ? {} : { media_type: target.media_type }),
|
|
80
|
-
},
|
|
81
|
-
}, {
|
|
82
|
-
workflow_ref: options.workflowRef,
|
|
83
|
-
activity_ref: options.activityRef,
|
|
84
|
-
...(options.reportProgress === undefined
|
|
85
|
-
? {}
|
|
86
|
-
: { reportProgress: options.reportProgress }),
|
|
109
|
+
result = updateReferenceSummaries({
|
|
110
|
+
workspaceRoot: options.projectContext.workspaceRoot,
|
|
111
|
+
summaries,
|
|
112
|
+
now: options.now,
|
|
87
113
|
});
|
|
88
|
-
if (output === undefined) {
|
|
89
|
-
adapterUnavailableCount += 1;
|
|
90
|
-
summaries.push({
|
|
91
|
-
path: target.path,
|
|
92
|
-
status: "unavailable",
|
|
93
|
-
generated_at: options.now().toISOString(),
|
|
94
|
-
source_blob_oid: target.blob_oid,
|
|
95
|
-
unavailable_reason: "summary_adapter_unavailable",
|
|
96
|
-
});
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
summaries.push(summaryRecordFromOutput({
|
|
100
|
-
target,
|
|
101
|
-
output,
|
|
102
|
-
generatedAt: options.now().toISOString(),
|
|
103
|
-
}));
|
|
104
114
|
}
|
|
105
115
|
catch (error) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
recordProjectTimelineEvent(options.store.db, {
|
|
117
|
+
event_kind: "reference_summary",
|
|
118
|
+
status: "failed",
|
|
119
|
+
summary: "Reference summary write failed.",
|
|
109
120
|
activity_ref: options.activityRef,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
workflow_ref: options.workflowRef,
|
|
122
|
+
meta: [
|
|
123
|
+
`target count: ${targetCount}`,
|
|
124
|
+
`error: ${error instanceof Error ? error.name : "UnknownError"}`,
|
|
125
|
+
],
|
|
126
|
+
now: options.now,
|
|
127
|
+
});
|
|
128
|
+
publishReferenceSummaryTimelineChanged({
|
|
129
|
+
events: options.events,
|
|
130
|
+
message: "Reference summary timeline updated.",
|
|
119
131
|
});
|
|
132
|
+
throw error;
|
|
120
133
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
now: options.now,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
recordProjectTimelineEvent(options.store.db, {
|
|
132
|
-
event_kind: "reference_summary",
|
|
133
|
-
status: "failed",
|
|
134
|
-
summary: "Reference summary write failed.",
|
|
135
|
-
activity_ref: options.activityRef,
|
|
136
|
-
workflow_ref: options.workflowRef,
|
|
137
|
-
meta: [
|
|
138
|
-
`target count: ${options.targets.length}`,
|
|
139
|
-
`error: ${error instanceof Error ? error.name : "UnknownError"}`,
|
|
140
|
-
],
|
|
134
|
+
updatedCount += result.updated_paths.length;
|
|
135
|
+
if (result.commit_oid !== undefined) {
|
|
136
|
+
lastCommitOid = result.commit_oid;
|
|
137
|
+
}
|
|
138
|
+
targets = readTargets({
|
|
139
|
+
projectContext: options.projectContext,
|
|
141
140
|
now: options.now,
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
events: options.events,
|
|
145
|
-
message: "Reference summary timeline updated.",
|
|
146
|
-
});
|
|
147
|
-
throw error;
|
|
141
|
+
}).filter((target) => (target.summary.status === "missing" || target.summary.status === "stale") &&
|
|
142
|
+
!processedTargets.has(`${target.path}\u0000${target.blob_oid}`));
|
|
148
143
|
}
|
|
149
144
|
options.logger?.info({
|
|
150
145
|
workflow_ref: options.workflowRef,
|
|
151
146
|
activity_ref: options.activityRef,
|
|
152
|
-
target_count:
|
|
153
|
-
updated_count:
|
|
147
|
+
target_count: targetCount,
|
|
148
|
+
updated_count: updatedCount,
|
|
154
149
|
failed_count: failedCount,
|
|
155
150
|
adapter_unavailable_count: adapterUnavailableCount,
|
|
156
|
-
...(
|
|
151
|
+
...(lastCommitOid === undefined ? {} : { commit_oid: lastCommitOid }),
|
|
157
152
|
}, "Reference summaries refreshed");
|
|
158
153
|
recordProjectTimelineEvent(options.store.db, {
|
|
159
154
|
event_kind: "reference_summary",
|
|
160
155
|
status: "completed",
|
|
161
|
-
summary:
|
|
156
|
+
summary: updatedCount === 0
|
|
162
157
|
? "Reference summaries already up to date."
|
|
163
|
-
: `Updated ${
|
|
158
|
+
: `Updated ${updatedCount} reference summaries.`,
|
|
164
159
|
activity_ref: options.activityRef,
|
|
165
160
|
workflow_ref: options.workflowRef,
|
|
166
|
-
...(
|
|
161
|
+
...(lastCommitOid === undefined ? {} : { commit_oid: lastCommitOid }),
|
|
167
162
|
meta: [
|
|
168
|
-
`target count: ${
|
|
169
|
-
`updated paths: ${
|
|
163
|
+
`target count: ${targetCount}`,
|
|
164
|
+
`updated paths: ${updatedCount}`,
|
|
170
165
|
`failed targets: ${failedCount}`,
|
|
171
166
|
`adapter unavailable: ${adapterUnavailableCount}`,
|
|
172
167
|
],
|
|
@@ -175,7 +170,7 @@ async function runReferenceSummaryRefresh(options) {
|
|
|
175
170
|
publishReferenceSummaryTimelineChanged({
|
|
176
171
|
events: options.events,
|
|
177
172
|
message: "Reference summary timeline updated.",
|
|
178
|
-
...(
|
|
173
|
+
...(updatedCount !== 0
|
|
179
174
|
? {
|
|
180
175
|
invalidates: [
|
|
181
176
|
{ kind: "viewer", path: "docs/reference" },
|
|
@@ -188,12 +183,96 @@ async function runReferenceSummaryRefresh(options) {
|
|
|
188
183
|
});
|
|
189
184
|
return {
|
|
190
185
|
kind: "completed",
|
|
191
|
-
summary:
|
|
186
|
+
summary: updatedCount === 0
|
|
192
187
|
? "Reference summaries already up to date."
|
|
193
|
-
: `Updated ${
|
|
188
|
+
: `Updated ${updatedCount} reference summaries.`,
|
|
194
189
|
result_anchor: { kind: "workflow", workflow_ref: options.workflowRef },
|
|
195
190
|
};
|
|
196
191
|
}
|
|
192
|
+
async function mapWithConcurrency(items, concurrency, worker) {
|
|
193
|
+
const results = new Array(items.length);
|
|
194
|
+
let nextIndex = 0;
|
|
195
|
+
const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
|
|
196
|
+
while (nextIndex < items.length) {
|
|
197
|
+
const index = nextIndex;
|
|
198
|
+
nextIndex += 1;
|
|
199
|
+
const item = items[index];
|
|
200
|
+
if (item !== undefined) {
|
|
201
|
+
results[index] = await worker(item);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
await Promise.all(workers);
|
|
206
|
+
return results;
|
|
207
|
+
}
|
|
208
|
+
async function summarizeReferenceTarget(options) {
|
|
209
|
+
for (let attempt = 1; attempt <= REFERENCE_SUMMARY_MAX_ATTEMPTS; attempt += 1) {
|
|
210
|
+
try {
|
|
211
|
+
const output = await options.runner.runReferenceFileSummary?.({
|
|
212
|
+
workflow_ref: options.workflowRef,
|
|
213
|
+
activity_ref: options.activityRef,
|
|
214
|
+
file: {
|
|
215
|
+
path: options.target.path,
|
|
216
|
+
name: options.target.name,
|
|
217
|
+
category: options.target.category,
|
|
218
|
+
size_bytes: options.target.size_bytes,
|
|
219
|
+
blob_oid: options.target.blob_oid,
|
|
220
|
+
...(options.target.media_type === undefined
|
|
221
|
+
? {}
|
|
222
|
+
: { media_type: options.target.media_type }),
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
if (output === undefined) {
|
|
226
|
+
return {
|
|
227
|
+
summary: {
|
|
228
|
+
path: options.target.path,
|
|
229
|
+
status: "unavailable",
|
|
230
|
+
generated_at: options.now().toISOString(),
|
|
231
|
+
source_blob_oid: options.target.blob_oid,
|
|
232
|
+
unavailable_reason: "summary_adapter_unavailable",
|
|
233
|
+
},
|
|
234
|
+
failed: false,
|
|
235
|
+
adapterUnavailable: true,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
summary: summaryRecordFromOutput({
|
|
240
|
+
target: options.target,
|
|
241
|
+
output,
|
|
242
|
+
generatedAt: options.now().toISOString(),
|
|
243
|
+
}),
|
|
244
|
+
failed: false,
|
|
245
|
+
adapterUnavailable: false,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
options.logger?.info({
|
|
250
|
+
workflow_ref: options.workflowRef,
|
|
251
|
+
activity_ref: options.activityRef,
|
|
252
|
+
path: options.target.path,
|
|
253
|
+
attempt,
|
|
254
|
+
retrying: attempt < REFERENCE_SUMMARY_MAX_ATTEMPTS,
|
|
255
|
+
error_name: error instanceof Error ? error.name : "UnknownError",
|
|
256
|
+
}, attempt < REFERENCE_SUMMARY_MAX_ATTEMPTS
|
|
257
|
+
? "Reference summary target retrying"
|
|
258
|
+
: "Reference summary target failed");
|
|
259
|
+
if (attempt === REFERENCE_SUMMARY_MAX_ATTEMPTS) {
|
|
260
|
+
return {
|
|
261
|
+
summary: {
|
|
262
|
+
path: options.target.path,
|
|
263
|
+
status: "unavailable",
|
|
264
|
+
generated_at: options.now().toISOString(),
|
|
265
|
+
source_blob_oid: options.target.blob_oid,
|
|
266
|
+
unavailable_reason: "summary_failed",
|
|
267
|
+
},
|
|
268
|
+
failed: true,
|
|
269
|
+
adapterUnavailable: false,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
throw new Error("Reference summary retry loop ended unexpectedly");
|
|
275
|
+
}
|
|
197
276
|
export function startReferenceSummaryRefreshProcedure(input) {
|
|
198
277
|
const activeActivity = input.readActiveActivity();
|
|
199
278
|
const requestedPathCount = input.paths?.length ?? 0;
|
|
@@ -268,23 +347,6 @@ export function startReferenceSummaryRefreshProcedure(input) {
|
|
|
268
347
|
},
|
|
269
348
|
};
|
|
270
349
|
}
|
|
271
|
-
if (runnerResolution.runner.runReferenceFileSummary === undefined) {
|
|
272
|
-
logNotStarted({
|
|
273
|
-
logger: input.logger,
|
|
274
|
-
disposition: "provider_unavailable",
|
|
275
|
-
requestedPathCount,
|
|
276
|
-
targetCount: targets.length,
|
|
277
|
-
reason: "provider_model_unavailable",
|
|
278
|
-
retryable: false,
|
|
279
|
-
});
|
|
280
|
-
return {
|
|
281
|
-
disposition: {
|
|
282
|
-
kind: "provider_unavailable",
|
|
283
|
-
reason: "provider_model_unavailable",
|
|
284
|
-
retryable: false,
|
|
285
|
-
},
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
350
|
const workflowRef = createWorkflowInvocationRef();
|
|
289
351
|
const projectContext = input.projectContext;
|
|
290
352
|
const start = input.engine.startProcedure({
|
|
@@ -302,18 +364,24 @@ export function startReferenceSummaryRefreshProcedure(input) {
|
|
|
302
364
|
activityRef: context.activity_ref,
|
|
303
365
|
error,
|
|
304
366
|
}),
|
|
305
|
-
execute: async (context) =>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
367
|
+
execute: async (context) => {
|
|
368
|
+
input.onExecuteStart?.({
|
|
369
|
+
activityRef: context.activity_ref,
|
|
370
|
+
workflowRef,
|
|
371
|
+
});
|
|
372
|
+
return runReferenceSummaryRefresh({
|
|
373
|
+
store: input.store,
|
|
374
|
+
runner: runnerResolution.runner,
|
|
375
|
+
workflowRef,
|
|
376
|
+
activityRef: context.activity_ref,
|
|
377
|
+
targets,
|
|
378
|
+
projectContext,
|
|
379
|
+
events: input.events,
|
|
380
|
+
logger: input.logger,
|
|
381
|
+
reportProgress: context.reportProgress,
|
|
382
|
+
now: input.now,
|
|
383
|
+
});
|
|
384
|
+
},
|
|
317
385
|
});
|
|
318
386
|
if (start.kind === "already_running") {
|
|
319
387
|
logNotStarted({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { materializeWorkflowRecentReferences } from "./recent-references.js";
|
|
1
2
|
import { recordRunPipelineFailure, recordRunPipelineResult, } from "./run-result-recording.js";
|
|
2
3
|
import { projectBriefShouldRefreshForUpdatedPaths, refreshProjectBriefProjection, } from "./project-brief-refresh.js";
|
|
3
4
|
function runLineageFields(lineage) {
|
|
@@ -79,6 +80,14 @@ export function startControlPlaneRunForTask(input) {
|
|
|
79
80
|
const pipelineStartedAt = input.now();
|
|
80
81
|
input.logger?.info(lifecycleFields, "Run pipeline started");
|
|
81
82
|
try {
|
|
83
|
+
const recentReferences = input.projectContext === undefined
|
|
84
|
+
? []
|
|
85
|
+
: materializeWorkflowRecentReferences({
|
|
86
|
+
db: input.store.db,
|
|
87
|
+
workspaceRoot: input.projectContext.workspaceRoot,
|
|
88
|
+
workflowRef: input.run.task.created_from_workflow_ref,
|
|
89
|
+
now: input.now,
|
|
90
|
+
});
|
|
82
91
|
const pipelineResult = await input.run.runner.runTask({
|
|
83
92
|
activity_ref: context.activity_ref,
|
|
84
93
|
task: input.run.task,
|
|
@@ -88,6 +97,9 @@ export function startControlPlaneRunForTask(input) {
|
|
|
88
97
|
...(input.run.continuation_context === undefined
|
|
89
98
|
? {}
|
|
90
99
|
: { continuation_context: input.run.continuation_context }),
|
|
100
|
+
...(recentReferences.length === 0
|
|
101
|
+
? {}
|
|
102
|
+
: { recent_references: recentReferences }),
|
|
91
103
|
on_stage: (progress) => context.reportProgress({
|
|
92
104
|
phase: progress.stage,
|
|
93
105
|
summary: runStageSummary(input.run, progress),
|
|
@@ -3,6 +3,7 @@ import type { ProcedureEngine, ProcedureEngineState } from "../procedure-engine/
|
|
|
3
3
|
import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
|
|
4
4
|
import type { HostProjectStore } from "../store/index.js";
|
|
5
5
|
import type { ControlPlaneLogger } from "./types.js";
|
|
6
|
+
import type { Phase5ControlPlaneOptions } from "./types.js";
|
|
6
7
|
import type { ProcedureWorkflowRunnerResolver } from "./workflows/index.js";
|
|
7
8
|
export declare function startControlPlaneTaskCompileContinuation(options: {
|
|
8
9
|
engine: ProcedureEngine;
|
|
@@ -17,6 +18,7 @@ export declare function startControlPlaneTaskCompileContinuation(options: {
|
|
|
17
18
|
};
|
|
18
19
|
roundId: ClarificationRoundRef;
|
|
19
20
|
resolveWorkflowRunner: ProcedureWorkflowRunnerResolver;
|
|
21
|
+
projectContext: Phase5ControlPlaneOptions["projectContext"] | undefined;
|
|
20
22
|
logger?: ControlPlaneLogger | undefined;
|
|
21
23
|
now: () => Date;
|
|
22
24
|
publishProcedureTransition: (state: ProcedureEngineState) => void;
|
|
@@ -4,6 +4,7 @@ import { clarificationInvalidates } from "./invalidations.js";
|
|
|
4
4
|
import { applyTaskCompileProcedureOutput } from "./task-compile-output.js";
|
|
5
5
|
import { readTaskCompileClarificationRounds } from "./task-compile-clarification-context.js";
|
|
6
6
|
import { logProcedureExecutionError } from "./procedure-logging.js";
|
|
7
|
+
import { materializeRecentReferences, readRecentReferenceSources, } from "./recent-references.js";
|
|
7
8
|
export function startControlPlaneTaskCompileContinuation(options) {
|
|
8
9
|
if (options.owner.kind !== "task_compile") {
|
|
9
10
|
return false;
|
|
@@ -43,10 +44,20 @@ export function startControlPlaneTaskCompileContinuation(options) {
|
|
|
43
44
|
workflowRef,
|
|
44
45
|
throughRoundId: options.roundId,
|
|
45
46
|
});
|
|
47
|
+
const recentReferences = options.projectContext === undefined
|
|
48
|
+
? []
|
|
49
|
+
: materializeRecentReferences({
|
|
50
|
+
workspaceRoot: options.projectContext.workspaceRoot,
|
|
51
|
+
sources: readRecentReferenceSources(options.store.db, taskCompileContext.sources),
|
|
52
|
+
now: options.now,
|
|
53
|
+
});
|
|
46
54
|
const output = await runnerResolution.runner.runTaskCompile({
|
|
47
55
|
workflow_ref: workflowRef,
|
|
48
56
|
scratchpad: taskCompileContext.scratchpad_snapshot,
|
|
49
57
|
worklist: readWorklistProjection(options.store.db),
|
|
58
|
+
...(recentReferences.length === 0
|
|
59
|
+
? {}
|
|
60
|
+
: { recent_references: recentReferences }),
|
|
50
61
|
clarification_rounds: clarificationRounds,
|
|
51
62
|
}, {
|
|
52
63
|
workflow_ref: workflowRef,
|
|
@@ -15,6 +15,7 @@ export declare function startControlPlaneTaskCompile(options: {
|
|
|
15
15
|
logger: ControlPlaneLogger | undefined;
|
|
16
16
|
now: () => Date;
|
|
17
17
|
publishProcedureTransition: (state: ProcedureEngineState) => void;
|
|
18
|
+
registerReferenceSummaryWaiter: (activityRef: ActivityRef, waiter: (state: ProcedureEngineState) => void) => void;
|
|
18
19
|
onTasksAdded: () => void;
|
|
19
20
|
}): ControlPlaneCommandResult<SubmitWorklistDisposition, SubmitWorklistResult>;
|
|
20
21
|
export declare function runControlPlaneTaskCompileProcedure(options: {
|
|
@@ -23,6 +24,7 @@ export declare function runControlPlaneTaskCompileProcedure(options: {
|
|
|
23
24
|
activityRef: ActivityRef;
|
|
24
25
|
store: HostProjectStore;
|
|
25
26
|
events: WorkspaceEventBus;
|
|
27
|
+
projectContext: Phase5ControlPlaneOptions["projectContext"] | undefined;
|
|
26
28
|
now: () => Date;
|
|
27
29
|
onTasksAdded: () => void;
|
|
28
30
|
reportProgress?: (progress: ProcedureProgressUpdate) => void;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createWorkflowInvocationRef, } from "@tutti/shared/ids";
|
|
2
|
-
import { captureTaskCompileContext, readActiveTaskCompileContext, readScratchpadProjection, readWorklistProjection, rollbackTaskCompileContext, } from "../collaboration-state/index.js";
|
|
2
|
+
import { captureTaskCompileContext, readActiveTaskCompileContext, readCurrentScratchpadSourceRefs, readScratchpadProjection, readWorklistProjection, rollbackTaskCompileContext, } from "../collaboration-state/index.js";
|
|
3
3
|
import { initializeProjectDocs, readProjectDocsInitializationStatus, } from "../workspace-ops/index.js";
|
|
4
4
|
import { logProcedureExecutionError } from "./procedure-logging.js";
|
|
5
5
|
import { projectBriefShouldRefreshForUpdatedPaths, refreshProjectBriefProjection, } from "./project-brief-refresh.js";
|
|
6
6
|
import { applyProjectDocsInitializationResult, buildProjectDocsInitializationContext, tryProjectContextBootstrapDocuments, } from "./project-context-bootstrap.js";
|
|
7
7
|
import { readActiveScratchpadRefreshActivityRef, readControlPlaneScratchpadSourceBatch, runControlPlaneScratchpadRefreshProcedure, } from "./scratchpad-refresh-start.js";
|
|
8
8
|
import { applyTaskCompileProcedureOutput } from "./task-compile-output.js";
|
|
9
|
+
import { materializeRecentReferences, readPendingRecentReferenceSummaryPaths, readRecentReferenceSources, } from "./recent-references.js";
|
|
10
|
+
import { startReferenceSummaryRefreshProcedure } from "./reference-summary-refresh.js";
|
|
9
11
|
export function startControlPlaneTaskCompile(options) {
|
|
10
12
|
const activeContext = readActiveTaskCompileContext(options.store.db);
|
|
11
13
|
if (activeContext !== null) {
|
|
@@ -26,7 +28,6 @@ export function startControlPlaneTaskCompile(options) {
|
|
|
26
28
|
},
|
|
27
29
|
};
|
|
28
30
|
}
|
|
29
|
-
const shouldInitializeProjectContext = shouldInitializeControlPlaneProjectContext(options);
|
|
30
31
|
const runnerResolution = options.resolveWorkflowRunner();
|
|
31
32
|
if (runnerResolution.kind === "not_configured") {
|
|
32
33
|
return { disposition: { kind: "provider_not_configured" } };
|
|
@@ -65,14 +66,7 @@ export function startControlPlaneTaskCompile(options) {
|
|
|
65
66
|
if (!scratchpadHasSubmittableContent(scratchpad)) {
|
|
66
67
|
return { disposition: { kind: "scratchpad_empty" } };
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
-
return startProjectContextBootstrapActivity({
|
|
70
|
-
...options,
|
|
71
|
-
runner: runnerResolution.runner,
|
|
72
|
-
taskCompileWorkflowRef,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
return startControlPlaneTaskCompileActivity({
|
|
69
|
+
return startReferenceSummaryGateOrNextStage({
|
|
76
70
|
...options,
|
|
77
71
|
runner: runnerResolution.runner,
|
|
78
72
|
taskCompileWorkflowRef,
|
|
@@ -105,6 +99,7 @@ function startControlPlaneTaskCompileActivity(options) {
|
|
|
105
99
|
runner: options.runner,
|
|
106
100
|
store: options.store,
|
|
107
101
|
events: options.events,
|
|
102
|
+
projectContext: options.projectContext,
|
|
108
103
|
workflowRef,
|
|
109
104
|
activityRef: context.activity_ref,
|
|
110
105
|
reportProgress: context.reportProgress,
|
|
@@ -146,12 +141,7 @@ function startScratchpadRefreshBeforeTaskCompileActivity(options) {
|
|
|
146
141
|
if (!scratchpadHasSubmittableContent(scratchpad)) {
|
|
147
142
|
return;
|
|
148
143
|
}
|
|
149
|
-
|
|
150
|
-
void startProjectContextBootstrapActivity(options);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
void startControlPlaneTaskCompileActivity(options);
|
|
154
|
-
}
|
|
144
|
+
void startReferenceSummaryGateOrNextStage(options);
|
|
155
145
|
},
|
|
156
146
|
onError: ({ context, error }) => logProcedureExecutionError({
|
|
157
147
|
logger: options.logger,
|
|
@@ -186,6 +176,103 @@ function startScratchpadRefreshBeforeTaskCompileActivity(options) {
|
|
|
186
176
|
},
|
|
187
177
|
};
|
|
188
178
|
}
|
|
179
|
+
function startReferenceSummaryGateOrNextStage(options) {
|
|
180
|
+
const sourceRefs = readActiveTaskCompileContext(options.store.db, options.taskCompileWorkflowRef)?.sources ??
|
|
181
|
+
readCurrentScratchpadSourceRefs(options.store.db);
|
|
182
|
+
const referenceSources = readRecentReferenceSources(options.store.db, sourceRefs);
|
|
183
|
+
const pendingPaths = options.projectContext === undefined
|
|
184
|
+
? []
|
|
185
|
+
: readPendingRecentReferenceSummaryPaths({
|
|
186
|
+
workspaceRoot: options.projectContext.workspaceRoot,
|
|
187
|
+
sources: referenceSources,
|
|
188
|
+
now: options.now,
|
|
189
|
+
});
|
|
190
|
+
if (pendingPaths.length === 0) {
|
|
191
|
+
return startNextTaskCompileStage(options);
|
|
192
|
+
}
|
|
193
|
+
const activeReferenceSummary = options.engine.getActiveProcedures().find((activity) => activity.lane === "foreground" &&
|
|
194
|
+
activity.workflow_kind === "reference_summary_refresh");
|
|
195
|
+
if (activeReferenceSummary !== undefined) {
|
|
196
|
+
readOrCaptureTaskCompileContext({
|
|
197
|
+
store: options.store,
|
|
198
|
+
workflowRef: options.taskCompileWorkflowRef,
|
|
199
|
+
activityRef: activeReferenceSummary.activity_ref,
|
|
200
|
+
now: options.now,
|
|
201
|
+
});
|
|
202
|
+
registerReferenceSummaryGateWaiter(options, activeReferenceSummary.activity_ref);
|
|
203
|
+
return {
|
|
204
|
+
disposition: {
|
|
205
|
+
kind: "already_running",
|
|
206
|
+
activity_ref: activeReferenceSummary.activity_ref,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const started = startReferenceSummaryRefreshProcedure({
|
|
211
|
+
engine: options.engine,
|
|
212
|
+
store: options.store,
|
|
213
|
+
events: options.events,
|
|
214
|
+
paths: pendingPaths,
|
|
215
|
+
resolveWorkflowRunner: () => ({ kind: "ready", runner: options.runner }),
|
|
216
|
+
readActiveActivity: () => {
|
|
217
|
+
const active = options.engine.getActiveProcedures().find((activity) => activity.lane === "foreground");
|
|
218
|
+
return active === undefined
|
|
219
|
+
? null
|
|
220
|
+
: { activity_ref: active.activity_ref };
|
|
221
|
+
},
|
|
222
|
+
projectContext: options.projectContext,
|
|
223
|
+
logger: options.logger,
|
|
224
|
+
now: options.now,
|
|
225
|
+
onExecuteStart: ({ activityRef }) => {
|
|
226
|
+
readOrCaptureTaskCompileContext({
|
|
227
|
+
store: options.store,
|
|
228
|
+
workflowRef: options.taskCompileWorkflowRef,
|
|
229
|
+
activityRef,
|
|
230
|
+
now: options.now,
|
|
231
|
+
});
|
|
232
|
+
},
|
|
233
|
+
publishProcedureTransition: options.publishProcedureTransition,
|
|
234
|
+
});
|
|
235
|
+
if (started.disposition.kind === "accepted") {
|
|
236
|
+
const activityRef = started.result?.activity_ref;
|
|
237
|
+
const workflowRef = started.result?.workflow_ref;
|
|
238
|
+
if (activityRef === undefined || workflowRef === undefined) {
|
|
239
|
+
throw new Error("Accepted reference summary gate is missing activity identity");
|
|
240
|
+
}
|
|
241
|
+
registerReferenceSummaryGateWaiter(options, activityRef);
|
|
242
|
+
return {
|
|
243
|
+
disposition: { kind: "accepted" },
|
|
244
|
+
result: {
|
|
245
|
+
activity_ref: activityRef,
|
|
246
|
+
workflow_ref: workflowRef,
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (started.disposition.kind === "already_running") {
|
|
251
|
+
return { disposition: started.disposition };
|
|
252
|
+
}
|
|
253
|
+
if (started.disposition.kind === "no_targets") {
|
|
254
|
+
return startNextTaskCompileStage(options);
|
|
255
|
+
}
|
|
256
|
+
return { disposition: started.disposition };
|
|
257
|
+
}
|
|
258
|
+
function registerReferenceSummaryGateWaiter(options, activityRef) {
|
|
259
|
+
options.registerReferenceSummaryWaiter(activityRef, (state) => {
|
|
260
|
+
if (state.activity.status !== "finished") {
|
|
261
|
+
rollbackTaskCompileContext(options.store.db, {
|
|
262
|
+
workflow_ref: options.taskCompileWorkflowRef,
|
|
263
|
+
now: options.now,
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
void startReferenceSummaryGateOrNextStage(options);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function startNextTaskCompileStage(options) {
|
|
271
|
+
if (shouldInitializeControlPlaneProjectContext(options)) {
|
|
272
|
+
return startProjectContextBootstrapActivity(options);
|
|
273
|
+
}
|
|
274
|
+
return startControlPlaneTaskCompileActivity(options);
|
|
275
|
+
}
|
|
189
276
|
function shouldInitializeControlPlaneProjectContext(options) {
|
|
190
277
|
if (options.projectContext === undefined) {
|
|
191
278
|
return false;
|
|
@@ -324,10 +411,20 @@ export async function runControlPlaneTaskCompileProcedure(options) {
|
|
|
324
411
|
};
|
|
325
412
|
}
|
|
326
413
|
try {
|
|
414
|
+
const recentReferences = options.projectContext === undefined
|
|
415
|
+
? []
|
|
416
|
+
: materializeRecentReferences({
|
|
417
|
+
workspaceRoot: options.projectContext.workspaceRoot,
|
|
418
|
+
sources: readRecentReferenceSources(options.store.db, context.sources),
|
|
419
|
+
now: options.now,
|
|
420
|
+
});
|
|
327
421
|
const output = await options.runner.runTaskCompile({
|
|
328
422
|
workflow_ref: options.workflowRef,
|
|
329
423
|
scratchpad: context.scratchpad_snapshot,
|
|
330
424
|
worklist: readWorklistProjection(options.store.db),
|
|
425
|
+
...(recentReferences.length === 0
|
|
426
|
+
? {}
|
|
427
|
+
: { recent_references: recentReferences }),
|
|
331
428
|
}, {
|
|
332
429
|
workflow_ref: options.workflowRef,
|
|
333
430
|
activity_ref: options.activityRef,
|
|
@@ -4,6 +4,7 @@ import type { ActivityRef, ClarificationRoundRef, TaskId, TaskModuleId } from "@
|
|
|
4
4
|
import type { ActiveApprovalProjection, ClarificationRequestPayload, ExecutionRuntimeSnapshot, MessageProjection, RecoverySummaryProjection, TaskDetailProjection, TaskProjection } from "@tutti/shared/schemas/api";
|
|
5
5
|
import type { HostProjectStore } from "../store/index.js";
|
|
6
6
|
import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
|
|
7
|
+
import type { RecentReferenceContext } from "./reference-context-types.js";
|
|
7
8
|
import type { ProcedureWorkflowRunnerResolver } from "./workflows/index.js";
|
|
8
9
|
export type Phase5ControlPlaneOptions = {
|
|
9
10
|
store: HostProjectStore;
|
|
@@ -104,6 +105,7 @@ export type RunPipelineInput = {
|
|
|
104
105
|
dispatch_context: RunDispatchContext;
|
|
105
106
|
continuation_context?: RunContinuationContext;
|
|
106
107
|
correction_context?: RunCorrectionContext;
|
|
108
|
+
recent_references?: RecentReferenceContext[];
|
|
107
109
|
on_stage?: (progress: RunPipelineStageProgress) => void;
|
|
108
110
|
};
|
|
109
111
|
export type RunPipelineStageProgress = {
|
|
@@ -160,6 +160,13 @@ export function buildTaskCompilePromptInput(input) {
|
|
|
160
160
|
})),
|
|
161
161
|
},
|
|
162
162
|
};
|
|
163
|
+
if (input.recent_references !== undefined && input.recent_references.length !== 0) {
|
|
164
|
+
promptInput.recent_references = input.recent_references.map((reference) => ({
|
|
165
|
+
path: reference.path,
|
|
166
|
+
name: reference.name,
|
|
167
|
+
summary: { ...reference.summary },
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
163
170
|
if (input.clarification_rounds !== undefined) {
|
|
164
171
|
promptInput.clarification_rounds = input.clarification_rounds.map((round) => ({
|
|
165
172
|
request: {
|