@xfey/tutti 0.1.110 → 0.1.112
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/README.md +1 -1
- package/dist/approvals/decision-command.d.ts +2 -2
- package/dist/chat-assistant/index.d.ts +1 -1
- package/dist/chat-assistant/index.js +26 -6
- package/dist/collaboration-ingestion/clarification.d.ts +25 -0
- package/dist/collaboration-ingestion/clarification.js +63 -0
- package/dist/collaboration-ingestion/external-source.d.ts +2 -0
- package/dist/collaboration-ingestion/external-source.js +35 -0
- package/dist/collaboration-ingestion/index.d.ts +2 -0
- package/dist/collaboration-ingestion/index.js +2 -0
- package/dist/collaboration-ingestion/main-chat.js +9 -2
- package/dist/collaboration-ingestion/platform-clarification.d.ts +10 -0
- package/dist/collaboration-ingestion/platform-clarification.js +42 -0
- package/dist/collaboration-ingestion/types.d.ts +1 -0
- package/dist/collaboration-state/clarification-messages.js +3 -2
- package/dist/collaboration-state/clarification-records.d.ts +1 -1
- package/dist/collaboration-state/clarification-records.js +7 -5
- package/dist/collaboration-state/clarification-rounds.js +5 -5
- package/dist/collaboration-state/clarification-snapshot.d.ts +228 -0
- package/dist/collaboration-state/clarification-snapshot.js +29 -0
- package/dist/collaboration-state/clarification-successors.js +6 -6
- package/dist/collaboration-state/index.d.ts +1 -0
- package/dist/collaboration-state/index.js +1 -0
- package/dist/collaboration-state/run-recording.js +1 -1
- package/dist/collaboration-state/task-compile-context.d.ts +1 -1
- package/dist/collaboration-state/types.d.ts +1 -0
- package/dist/control-plane/clarification-commands.d.ts +3 -2
- package/dist/control-plane/clarification-commands.js +13 -4
- package/dist/control-plane/follow-up-context.js +8 -14
- package/dist/control-plane/index.d.ts +3 -2
- package/dist/control-plane/scratchpad-source-messages.js +9 -3
- package/dist/control-plane/task-compile-clarification-context.js +7 -2
- package/dist/control-plane/task-source-context-types.d.ts +1 -1
- package/dist/control-plane/task-source-context.js +4 -2
- package/dist/control-plane/types.d.ts +1 -0
- package/dist/control-plane/workflows/openai.js +5 -4
- package/dist/platform-outbound/repository.js +83 -4
- package/dist/server-shell/cli/host-lifecycle.js +1 -0
- package/dist/server-shell/cli/host-server-runtime.d.ts +2 -1
- package/dist/server-shell/cli/host-server-runtime.js +4 -2
- package/dist/server-shell/cli/relay-registration.js +2 -0
- package/dist/server-shell/http/host-tunnel.d.ts +2 -1
- package/dist/server-shell/http/host-tunnel.js +4 -1
- package/dist/server-shell/http/integration-clarification-dispatch.d.ts +6 -0
- package/dist/server-shell/http/integration-clarification-dispatch.js +43 -0
- package/dist/server-shell/http/routes/agent-context-reference-routes.js +1 -3
- package/dist/server-shell/http/routes/project-api/clarification-routes.js +16 -42
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +2 -0
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +1 -0
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +3 -0
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +1 -0
- package/migrations/0022_clarification_projection_cursors.sql +7 -0
- package/node_modules/@tutti/relay-client/dist/host-control.d.ts +2 -0
- package/node_modules/@tutti/relay-client/dist/host-control.js +6 -0
- package/node_modules/@tutti/shared/dist/schemas/api/clarifications.d.ts +14 -1
- package/node_modules/@tutti/shared/dist/schemas/api/clarifications.js +9 -2
- package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +4 -0
- package/node_modules/@tutti/shared/dist/schemas/api/messages.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +2 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.js +2 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification-content.d.ts +15 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification-content.js +24 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification.d.ts +354 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification.js +94 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.d.ts +132 -5
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.js +29 -5
- package/node_modules/@tutti/shared/dist/utils/clarification-participants.d.ts +4 -0
- package/node_modules/@tutti/shared/dist/utils/clarification-participants.js +11 -0
- package/node_modules/@tutti/shared/dist/utils/index.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/utils/index.js +1 -0
- package/package.json +1 -1
- package/prompts/chat-assistant.md +1 -0
- package/prompts/procedures/follow-up-check.md +4 -4
- package/prompts/procedures/scratchpad-refresh.md +22 -2
- package/prompts/procedures/task-compile.md +1 -0
- package/prompts/runs/task-execute.md +2 -0
- package/web/assets/{homepage-motion-scene-rxYjg-zc.js → homepage-motion-scene-BwdH6Iss.js} +1 -1
- package/web/assets/index-B29RuNsd.js +69 -0
- package/web/index.html +1 -1
- package/web/assets/index-BrKWdtKZ.js +0 -69
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import type { ClarificationRoundRef } from "@tutti/shared/ids";
|
|
2
|
+
import type { SqliteDatabase } from "../store/index.js";
|
|
3
|
+
/** Round messages are append-only; the eligible answer count is a stable CAS revision. */
|
|
4
|
+
export declare function readClarificationAnswerRevision(db: SqliteDatabase, roundId: ClarificationRoundRef): number;
|
|
5
|
+
/** Read the immutable submitted refs, not a first page or messages appended after sealing. */
|
|
6
|
+
export declare function readSubmittedClarificationMessages(db: SqliteDatabase, roundId: ClarificationRoundRef): {
|
|
7
|
+
clarification_card?: {
|
|
8
|
+
title?: string;
|
|
9
|
+
status: "writable" | "sealed";
|
|
10
|
+
round_id: string;
|
|
11
|
+
thread_id: string;
|
|
12
|
+
summary: string;
|
|
13
|
+
is_current_round: boolean;
|
|
14
|
+
};
|
|
15
|
+
refs?: {
|
|
16
|
+
task_id?: string;
|
|
17
|
+
activity_ref?: string;
|
|
18
|
+
artifact_feedback?: {
|
|
19
|
+
summary?: string;
|
|
20
|
+
kind: "artifact_feedback";
|
|
21
|
+
version: 1;
|
|
22
|
+
preview_generation: string;
|
|
23
|
+
annotations: {
|
|
24
|
+
document_url: string;
|
|
25
|
+
comment: string;
|
|
26
|
+
target: {
|
|
27
|
+
fallback_context?: {
|
|
28
|
+
snapshot: {
|
|
29
|
+
role?: string;
|
|
30
|
+
accessible_name?: string;
|
|
31
|
+
text_excerpt?: string;
|
|
32
|
+
state?: {
|
|
33
|
+
expanded?: boolean;
|
|
34
|
+
selected?: boolean;
|
|
35
|
+
checked?: boolean;
|
|
36
|
+
pressed?: boolean;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
};
|
|
39
|
+
tag_name: string;
|
|
40
|
+
element_kind: "content" | "control" | "container";
|
|
41
|
+
context: {
|
|
42
|
+
role?: string;
|
|
43
|
+
accessible_name?: string;
|
|
44
|
+
tag_name: string;
|
|
45
|
+
}[];
|
|
46
|
+
};
|
|
47
|
+
anchor: {
|
|
48
|
+
explicit_anchor?: string;
|
|
49
|
+
stable_attributes?: {
|
|
50
|
+
id?: string;
|
|
51
|
+
test_id?: string;
|
|
52
|
+
};
|
|
53
|
+
version: 1;
|
|
54
|
+
semantic_path: {
|
|
55
|
+
role?: string;
|
|
56
|
+
accessible_name?: string;
|
|
57
|
+
}[];
|
|
58
|
+
selector_path: {
|
|
59
|
+
root: "document" | "open_shadow_root";
|
|
60
|
+
selector: string;
|
|
61
|
+
}[];
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
snapshot: {
|
|
65
|
+
role?: string;
|
|
66
|
+
accessible_name?: string;
|
|
67
|
+
text_excerpt?: string;
|
|
68
|
+
state?: {
|
|
69
|
+
expanded?: boolean;
|
|
70
|
+
selected?: boolean;
|
|
71
|
+
checked?: boolean;
|
|
72
|
+
pressed?: boolean;
|
|
73
|
+
disabled?: boolean;
|
|
74
|
+
};
|
|
75
|
+
tag_name: string;
|
|
76
|
+
element_kind: "content" | "control" | "container";
|
|
77
|
+
context: {
|
|
78
|
+
role?: string;
|
|
79
|
+
accessible_name?: string;
|
|
80
|
+
tag_name: string;
|
|
81
|
+
}[];
|
|
82
|
+
};
|
|
83
|
+
anchor: {
|
|
84
|
+
explicit_anchor?: string;
|
|
85
|
+
stable_attributes?: {
|
|
86
|
+
id?: string;
|
|
87
|
+
test_id?: string;
|
|
88
|
+
};
|
|
89
|
+
version: 1;
|
|
90
|
+
semantic_path: {
|
|
91
|
+
role?: string;
|
|
92
|
+
accessible_name?: string;
|
|
93
|
+
}[];
|
|
94
|
+
selector_path: {
|
|
95
|
+
root: "document" | "open_shadow_root";
|
|
96
|
+
selector: string;
|
|
97
|
+
}[];
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
}[];
|
|
101
|
+
artifact_title: string;
|
|
102
|
+
inspector_version: 1;
|
|
103
|
+
};
|
|
104
|
+
reference_file?: {
|
|
105
|
+
media_type?: string;
|
|
106
|
+
blob_oid?: string;
|
|
107
|
+
path: string;
|
|
108
|
+
name: string;
|
|
109
|
+
source: "human_upload" | "tutti_output";
|
|
110
|
+
category: "file" | "image";
|
|
111
|
+
size_bytes: number;
|
|
112
|
+
text_read: {
|
|
113
|
+
blocked_reason?: "unknown" | "binary" | "too_large" | "unsupported_encoding" | "restricted_path" | "secret_like";
|
|
114
|
+
can_read: boolean;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
workflow_ref?: string;
|
|
118
|
+
clarification_round_ref?: string;
|
|
119
|
+
clarification_thread_ref?: string;
|
|
120
|
+
task_result?: {
|
|
121
|
+
error_code?: string;
|
|
122
|
+
activity_ref?: string;
|
|
123
|
+
generated_files?: {
|
|
124
|
+
media_type?: string;
|
|
125
|
+
group?: string;
|
|
126
|
+
path: string;
|
|
127
|
+
name: string;
|
|
128
|
+
size_bytes: number;
|
|
129
|
+
}[];
|
|
130
|
+
module_name?: string;
|
|
131
|
+
latest_run_result_id?: string;
|
|
132
|
+
retry_action?: "retryable" | "retried";
|
|
133
|
+
final_note?: string;
|
|
134
|
+
status: "completed" | "failed";
|
|
135
|
+
kind: "task_result";
|
|
136
|
+
task_id: string;
|
|
137
|
+
title: string;
|
|
138
|
+
summary: string;
|
|
139
|
+
task_title: string;
|
|
140
|
+
result_key: string;
|
|
141
|
+
};
|
|
142
|
+
worklist_compile?: {
|
|
143
|
+
kind: "worklist_compile";
|
|
144
|
+
title: string;
|
|
145
|
+
workflow_ref: string;
|
|
146
|
+
tasks: {
|
|
147
|
+
status: "failed" | "done" | "pending" | "todo" | "running";
|
|
148
|
+
task_id: string;
|
|
149
|
+
title: string;
|
|
150
|
+
summary: string;
|
|
151
|
+
module_id: string;
|
|
152
|
+
module_name: string;
|
|
153
|
+
}[];
|
|
154
|
+
task_count: number;
|
|
155
|
+
};
|
|
156
|
+
artifact_preview?: {
|
|
157
|
+
task_id?: string;
|
|
158
|
+
run_result_id?: string;
|
|
159
|
+
status: "available" | "updated";
|
|
160
|
+
kind: "artifact_preview";
|
|
161
|
+
title: string;
|
|
162
|
+
};
|
|
163
|
+
development_operator?: true;
|
|
164
|
+
external_reference_reads?: string[];
|
|
165
|
+
external_references?: {
|
|
166
|
+
name: string;
|
|
167
|
+
kind: "feishu_docx" | "feishu_drive_file" | "feishu_file" | "feishu_image";
|
|
168
|
+
created_at: string;
|
|
169
|
+
source_ref: string;
|
|
170
|
+
}[];
|
|
171
|
+
scratchpad_source?: "include" | "exclude";
|
|
172
|
+
worklist_feedback?: {
|
|
173
|
+
generated_files?: {
|
|
174
|
+
media_type?: string;
|
|
175
|
+
group?: string;
|
|
176
|
+
path: string;
|
|
177
|
+
name: string;
|
|
178
|
+
size_bytes: number;
|
|
179
|
+
}[];
|
|
180
|
+
final_note?: string;
|
|
181
|
+
primary_task_id?: string;
|
|
182
|
+
status: "completed" | "failed";
|
|
183
|
+
kind: "worklist_terminal";
|
|
184
|
+
items: {
|
|
185
|
+
module_name?: string;
|
|
186
|
+
latest_run_result_id?: string;
|
|
187
|
+
status: "failed" | "done";
|
|
188
|
+
task_id: string;
|
|
189
|
+
title: string;
|
|
190
|
+
summary: string;
|
|
191
|
+
}[];
|
|
192
|
+
title: string;
|
|
193
|
+
reason: "all_tasks_done" | "run_failed";
|
|
194
|
+
counters: {
|
|
195
|
+
completed: number;
|
|
196
|
+
failed: number;
|
|
197
|
+
remaining: number;
|
|
198
|
+
};
|
|
199
|
+
feedback_key: string;
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
scope: {
|
|
203
|
+
kind: "main_chat";
|
|
204
|
+
} | {
|
|
205
|
+
kind: "clarification_round";
|
|
206
|
+
clarification_round_ref: string;
|
|
207
|
+
};
|
|
208
|
+
id: string;
|
|
209
|
+
author: {
|
|
210
|
+
ref?: string;
|
|
211
|
+
display_name?: string;
|
|
212
|
+
avatar?: {
|
|
213
|
+
kind: "initials";
|
|
214
|
+
initials: string;
|
|
215
|
+
color: "neutral" | "green" | "blue" | "yellow";
|
|
216
|
+
} | {
|
|
217
|
+
kind: "image";
|
|
218
|
+
initials: string;
|
|
219
|
+
color: "neutral" | "green" | "blue" | "yellow";
|
|
220
|
+
image_url: string;
|
|
221
|
+
};
|
|
222
|
+
kind: "human" | "system" | "agent";
|
|
223
|
+
};
|
|
224
|
+
body: string;
|
|
225
|
+
created_at: string;
|
|
226
|
+
message_kind: "user_text" | "agent_text" | "system_notice" | "clarification_request" | "clarification_card";
|
|
227
|
+
}[];
|
|
228
|
+
//# sourceMappingURL=clarification-snapshot.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mapMessageRow } from "./messages.js";
|
|
2
|
+
/** Round messages are append-only; the eligible answer count is a stable CAS revision. */
|
|
3
|
+
export function readClarificationAnswerRevision(db, roundId) {
|
|
4
|
+
return db
|
|
5
|
+
.prepare(`
|
|
6
|
+
SELECT COUNT(*) AS count FROM messages
|
|
7
|
+
WHERE scope_kind = 'clarification_round' AND clarification_round_id = ?
|
|
8
|
+
AND message_kind = 'user_text'
|
|
9
|
+
AND (author_kind = 'human' OR
|
|
10
|
+
(author_kind = 'system' AND json_extract(refs_json, '$.development_operator') = 1))
|
|
11
|
+
`)
|
|
12
|
+
.get(roundId).count;
|
|
13
|
+
}
|
|
14
|
+
/** Read the immutable submitted refs, not a first page or messages appended after sealing. */
|
|
15
|
+
export function readSubmittedClarificationMessages(db, roundId) {
|
|
16
|
+
return db
|
|
17
|
+
.prepare(`
|
|
18
|
+
SELECT messages.* FROM clarification_rounds AS rounds
|
|
19
|
+
JOIN json_each(rounds.submitted_message_refs_json) AS submitted
|
|
20
|
+
JOIN messages ON messages.id = submitted.value
|
|
21
|
+
WHERE rounds.id = ? AND rounds.status = 'sealed'
|
|
22
|
+
AND messages.scope_kind = 'clarification_round'
|
|
23
|
+
AND messages.clarification_round_id = rounds.id
|
|
24
|
+
ORDER BY CAST(submitted.key AS INTEGER)
|
|
25
|
+
`)
|
|
26
|
+
.all(roundId)
|
|
27
|
+
.map((row) => mapMessageRow(row));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=clarification-snapshot.js.map
|
|
@@ -15,7 +15,7 @@ export function submitClarificationRound(db, input) {
|
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
if (row.status === "sealed") {
|
|
18
|
-
round = mapClarificationRoundRow(row);
|
|
18
|
+
round = mapClarificationRoundRow(row, db);
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const messageRows = db
|
|
@@ -64,7 +64,7 @@ export function materializeClarificationSuccessor(db, input) {
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
if (row.successor_status === "materialized") {
|
|
67
|
-
round = mapClarificationRoundRow(row);
|
|
67
|
+
round = mapClarificationRoundRow(row, db);
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
70
|
db.prepare(`
|
|
@@ -120,7 +120,7 @@ export function materializeTaskBoundRunSuccessor(db, input) {
|
|
|
120
120
|
result = {
|
|
121
121
|
kind: "already_materialized",
|
|
122
122
|
thread: mapClarificationThreadRow(thread),
|
|
123
|
-
round: mapClarificationRoundRow(row),
|
|
123
|
+
round: mapClarificationRoundRow(row, db),
|
|
124
124
|
task: readTaskProjection(db, thread.owner_task_id),
|
|
125
125
|
};
|
|
126
126
|
return;
|
|
@@ -182,7 +182,7 @@ export function materializeTaskBoundRunSuccessor(db, input) {
|
|
|
182
182
|
result = {
|
|
183
183
|
kind: "materialized",
|
|
184
184
|
thread: mapClarificationThreadRow(updatedThread),
|
|
185
|
-
round: mapClarificationRoundRow(updatedRound),
|
|
185
|
+
round: mapClarificationRoundRow(updatedRound, db),
|
|
186
186
|
task: updatedTask,
|
|
187
187
|
};
|
|
188
188
|
})();
|
|
@@ -210,7 +210,7 @@ export function closeTaskBoundClarificationAsRetaskingRequired(db, input) {
|
|
|
210
210
|
return {
|
|
211
211
|
kind: "already_materialized",
|
|
212
212
|
thread: mapClarificationThreadRow(thread),
|
|
213
|
-
round: mapClarificationRoundRow(row),
|
|
213
|
+
round: mapClarificationRoundRow(row, db),
|
|
214
214
|
task: readTaskProjection(tx, taskId),
|
|
215
215
|
task_detail: readTaskDetailProjection(tx, taskId),
|
|
216
216
|
};
|
|
@@ -308,7 +308,7 @@ export function closeTaskBoundClarificationAsRetaskingRequired(db, input) {
|
|
|
308
308
|
return {
|
|
309
309
|
kind: "closed",
|
|
310
310
|
thread: mapClarificationThreadRow(updatedThread),
|
|
311
|
-
round: mapClarificationRoundRow(updatedRound),
|
|
311
|
+
round: mapClarificationRoundRow(updatedRound, db),
|
|
312
312
|
task,
|
|
313
313
|
task_detail: taskDetail,
|
|
314
314
|
message,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { CollaborationStateCursorError } from "./serialization.js";
|
|
2
|
+
export { readClarificationAnswerRevision, readSubmittedClarificationMessages, } from "./clarification-snapshot.js";
|
|
2
3
|
export { createIdleExecutionStatusProjection } from "./execution-status.js";
|
|
3
4
|
export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, ensureInitialProjectWelcomeMessage, hasMainChatArtifactPreviewMessage, hasMainChatTaskResultMessage, hasMainChatWorklistCompileMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesBeforeCursor, readMainChatMessagesForScratchpadCycle, } from "./messages.js";
|
|
4
5
|
export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { CollaborationStateCursorError } from "./serialization.js";
|
|
2
|
+
export { readClarificationAnswerRevision, readSubmittedClarificationMessages, } from "./clarification-snapshot.js";
|
|
2
3
|
export { createIdleExecutionStatusProjection } from "./execution-status.js";
|
|
3
4
|
export { createMainChatAgentMessage, createMainChatMessage, createMainChatSystemMessage, ensureInitialProjectWelcomeMessage, hasMainChatArtifactPreviewMessage, hasMainChatTaskResultMessage, hasMainChatWorklistCompileMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readMessageProjectionById, readMainChatMessageWindow, readMainChatMessagesBeforeCursor, readMainChatMessagesForScratchpadCycle, } from "./messages.js";
|
|
4
5
|
export { createEmptyScratchpadProjection, readScratchpadReceiptSourceRefs, readScratchpadProjection, upsertScratchpadProjection, } from "./scratchpad.js";
|
|
@@ -227,7 +227,7 @@ export function recordRunNeedsHumanResult(db, input) {
|
|
|
227
227
|
task: updatedTask,
|
|
228
228
|
task_detail: taskDetail,
|
|
229
229
|
thread: mapClarificationThreadRow(thread),
|
|
230
|
-
round: mapClarificationRoundRow(round),
|
|
230
|
+
round: mapClarificationRoundRow(round, db),
|
|
231
231
|
card_message: mapMessageRow(cardMessage, tx),
|
|
232
232
|
opening_message: mapMessageRow(openingMessage),
|
|
233
233
|
};
|
|
@@ -15,8 +15,8 @@ export declare function completeTaskCompileContext(db: SqliteDatabase, input: Co
|
|
|
15
15
|
updated_by_activity_ref?: string;
|
|
16
16
|
submitted_by_activity_ref?: string;
|
|
17
17
|
submitted_by_workflow_ref?: string;
|
|
18
|
-
id: "current";
|
|
19
18
|
state: "ready" | "empty" | "submitted";
|
|
19
|
+
id: "current";
|
|
20
20
|
topic: string;
|
|
21
21
|
background_summary: string;
|
|
22
22
|
current_consensus: string[];
|
|
@@ -279,6 +279,7 @@ export type CreateClarificationRoundMessageInput = {
|
|
|
279
279
|
round_id: ClarificationRoundRef;
|
|
280
280
|
body: string;
|
|
281
281
|
author: MessageAuthorInput;
|
|
282
|
+
refs?: MessageProjection["refs"];
|
|
282
283
|
now?: () => Date;
|
|
283
284
|
};
|
|
284
285
|
export type CreateClarificationRoundAgentMessageInput = {
|
|
@@ -2,13 +2,14 @@ import type { ClarificationRoundRef, IdempotencyKey } from "@tutti/shared/ids";
|
|
|
2
2
|
import type { SendClarificationRoundMessageDisposition, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResult, SubmitClarificationRoundDisposition, SubmitClarificationRoundPayload, SubmitClarificationRoundResult } from "@tutti/shared/schemas/api";
|
|
3
3
|
import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
|
|
4
4
|
import { type HostProjectStore } from "../store/index.js";
|
|
5
|
-
import type { ControlPlaneCommandResult
|
|
5
|
+
import type { ControlPlaneCommandResult } from "./types.js";
|
|
6
|
+
import type { TrustedCollaborationAuthor } from "../collaboration-ingestion/types.js";
|
|
6
7
|
export declare function runSendClarificationRoundMessage(options: {
|
|
7
8
|
store: HostProjectStore;
|
|
8
9
|
events: WorkspaceEventBus;
|
|
9
10
|
roundId: ClarificationRoundRef;
|
|
10
11
|
payload: SendClarificationRoundMessagePayload;
|
|
11
|
-
author:
|
|
12
|
+
author: TrustedCollaborationAuthor;
|
|
12
13
|
now: () => Date;
|
|
13
14
|
}): ControlPlaneCommandResult<SendClarificationRoundMessageDisposition, SendClarificationRoundMessageResult>;
|
|
14
15
|
export declare function runSubmitClarificationRound(options: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createClarificationRoundMessage, readActiveClarificationProjection, submitClarificationRound, } from "../collaboration-state/index.js";
|
|
1
|
+
import { createClarificationRoundMessage, readActiveClarificationProjection, readClarificationAnswerRevision, submitClarificationRound, } from "../collaboration-state/index.js";
|
|
2
2
|
import { withHostStoreTransaction } from "../store/index.js";
|
|
3
3
|
import { enqueueControlPlaneIntent } from "./dispatch-intents.js";
|
|
4
4
|
import { clarificationInvalidates } from "./invalidations.js";
|
|
@@ -19,11 +19,14 @@ export function runSendClarificationRoundMessage(options) {
|
|
|
19
19
|
round_id: options.roundId,
|
|
20
20
|
body: options.payload.body,
|
|
21
21
|
author: {
|
|
22
|
-
kind: "human",
|
|
22
|
+
kind: options.author.kind === "development_operator" ? "system" : "human",
|
|
23
23
|
ref: options.author.account_ref,
|
|
24
24
|
display_name: options.author.display_name,
|
|
25
25
|
...(options.author.avatar === undefined ? {} : { avatar: options.author.avatar }),
|
|
26
26
|
},
|
|
27
|
+
...(options.author.kind === "development_operator"
|
|
28
|
+
? { refs: { development_operator: true } }
|
|
29
|
+
: {}),
|
|
27
30
|
now: options.now,
|
|
28
31
|
});
|
|
29
32
|
options.events.publish({
|
|
@@ -41,12 +44,11 @@ export function runSendClarificationRoundMessage(options) {
|
|
|
41
44
|
invalidates: clarificationInvalidates(options.roundId, active.thread.id),
|
|
42
45
|
});
|
|
43
46
|
return {
|
|
44
|
-
disposition: { kind: "created" },
|
|
47
|
+
disposition: { kind: "created", message_id: message.id },
|
|
45
48
|
result: { message },
|
|
46
49
|
};
|
|
47
50
|
}
|
|
48
51
|
export function runSubmitClarificationRound(options) {
|
|
49
|
-
void options.payload;
|
|
50
52
|
const active = readActiveClarificationProjection(options.store.db);
|
|
51
53
|
if (active.state === "none") {
|
|
52
54
|
return { disposition: { kind: "chain_closed" } };
|
|
@@ -71,6 +73,13 @@ export function runSubmitClarificationRound(options) {
|
|
|
71
73
|
result: { round: active.round },
|
|
72
74
|
};
|
|
73
75
|
}
|
|
76
|
+
const answerRevision = readClarificationAnswerRevision(options.store.db, options.roundId);
|
|
77
|
+
if (options.payload.expected_answer_revision !== undefined &&
|
|
78
|
+
options.payload.expected_answer_revision !== answerRevision) {
|
|
79
|
+
return { disposition: { kind: "answers_changed", current_answer_revision: answerRevision } };
|
|
80
|
+
}
|
|
81
|
+
if (answerRevision === 0)
|
|
82
|
+
return { disposition: { kind: "no_answers" } };
|
|
74
83
|
const sealed = withHostStoreTransaction(options.store.db, (tx) => {
|
|
75
84
|
const submitted = submitClarificationRound(tx, {
|
|
76
85
|
round_id: options.roundId,
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { clarificationAnswerRole } from "@tutti/shared/utils";
|
|
2
|
+
import { readSubmittedClarificationMessages, readClarificationRoundProjection, readClarificationRoundsForThread, readTaskDetailProjection, readTaskRunResultsPage, } from "../collaboration-state/index.js";
|
|
2
3
|
import { toDomainRunLineage } from "./run-lineage.js";
|
|
3
4
|
const CONTINUATION_CLARIFICATION_MESSAGE_LIMIT = 200;
|
|
4
5
|
export function readFollowUpCheckInputFromStore(input) {
|
|
5
6
|
const taskDetail = readTaskDetailProjection(input.db, input.task_id);
|
|
6
7
|
const round = readClarificationRoundProjection(input.db, input.round_id);
|
|
7
|
-
const messagesWindow = readClarificationRoundMessagesWindow(input.db, input.round_id, {
|
|
8
|
-
anchor: "start",
|
|
9
|
-
});
|
|
10
8
|
const latestRunResult = readTaskRunResultsPage(input.db, input.task_id, {
|
|
11
9
|
limit: 1,
|
|
12
10
|
})?.items[0];
|
|
@@ -29,7 +27,7 @@ export function readFollowUpCheckInputFromStore(input) {
|
|
|
29
27
|
clarification_round_ref: input.round_id,
|
|
30
28
|
clarification_request_payload: round.request_payload,
|
|
31
29
|
submitted_message_refs: (round.submitted_message_refs ?? []),
|
|
32
|
-
round_messages:
|
|
30
|
+
round_messages: readSubmittedClarificationMessages(input.db, input.round_id),
|
|
33
31
|
latest_run_result: latestRunResult,
|
|
34
32
|
run_lineage: toDomainRunLineage(latestRunResult.run_lineage),
|
|
35
33
|
},
|
|
@@ -51,18 +49,14 @@ export function readRunContinuationContextFromStore(input) {
|
|
|
51
49
|
}
|
|
52
50
|
let messagesTruncated = false;
|
|
53
51
|
const resolvedRounds = rounds.map((round) => {
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
56
|
-
messagesWindow.window.has_older ||
|
|
57
|
-
messagesWindow.window.has_newer) {
|
|
52
|
+
const submitted = readSubmittedClarificationMessages(input.db, round.id).filter((message) => clarificationAnswerRole(message) !== null);
|
|
53
|
+
if (submitted.length > CONTINUATION_CLARIFICATION_MESSAGE_LIMIT)
|
|
58
54
|
messagesTruncated = true;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const answerMessages = (messagesWindow?.items ?? [])
|
|
62
|
-
.filter((message) => message.author.kind === "human")
|
|
63
|
-
.filter((message) => submittedMessageRefs.size === 0 || submittedMessageRefs.has(message.id))
|
|
55
|
+
const answerMessages = submitted
|
|
56
|
+
.slice(0, CONTINUATION_CLARIFICATION_MESSAGE_LIMIT)
|
|
64
57
|
.map((message) => ({
|
|
65
58
|
author: message.author,
|
|
59
|
+
role: clarificationAnswerRole(message),
|
|
66
60
|
text: message.body,
|
|
67
61
|
created_at: message.created_at,
|
|
68
62
|
}));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ActivityRef, type ClarificationRoundRef, type IdempotencyKey, type TaskId, type WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
|
+
import type { TrustedCollaborationAuthor } from "../collaboration-ingestion/types.js";
|
|
2
3
|
import type { ExecutionStatusProjection, MessageProjection, ContextSyncDisposition, ContextSyncResult, RefreshScratchpadDisposition, RefreshScratchpadResult, RunSchedulerNowDisposition, RunSchedulerNowPayload, RetryTaskDisposition, RetryTaskPayload, RefreshReferenceSummariesDisposition, RefreshReferenceSummariesPayload, RefreshReferenceSummariesResult, SendClarificationRoundMessageDisposition, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResult, SubmitClarificationRoundDisposition, SubmitClarificationRoundPayload, SubmitClarificationRoundResult, SubmitWorklistDisposition, SubmitWorklistPayload, SubmitWorklistResult, ProcedureLane } from "@tutti/shared/schemas/api";
|
|
3
4
|
import type { ContextSyncWorkflowTrigger } from "./workflows/index.js";
|
|
4
|
-
import type { ControlPlaneCommandResult, Phase5ControlPlaneOptions, StartupRecoveryOptions, StartupRecoveryResult
|
|
5
|
+
import type { ControlPlaneCommandResult, Phase5ControlPlaneOptions, StartupRecoveryOptions, StartupRecoveryResult } from "./types.js";
|
|
5
6
|
import { type ProjectBriefRefreshReason, type RefreshProjectBriefProjectionResult } from "./project-brief-refresh.js";
|
|
6
7
|
export type { ControlPlaneCommandResult, ControlPlaneLogger, Phase5ControlPlaneOptions, RunCorrectionContext, RunContinuationContext, RunDispatchContext, RunDispatchTrigger, RunPipelineInput, RunPipelineResolution, RunPipelineResolver, RunPipelineResult, RunPipelineRunner, StartupRecoveryOptions, StartupRecoveryResult, TrustedHumanAuthor, } from "./types.js";
|
|
7
8
|
export declare class Phase5ControlPlane {
|
|
@@ -50,7 +51,7 @@ export declare class Phase5ControlPlane {
|
|
|
50
51
|
startContextSyncAnalysis(trigger?: ContextSyncWorkflowTrigger): ControlPlaneCommandResult<ContextSyncDisposition, ContextSyncResult>;
|
|
51
52
|
startReferenceSummaryRefresh(payload?: RefreshReferenceSummariesPayload): ControlPlaneCommandResult<RefreshReferenceSummariesDisposition, RefreshReferenceSummariesResult>;
|
|
52
53
|
private tryStartPendingReferenceSummaryRefresh;
|
|
53
|
-
sendClarificationRoundMessage(roundId: ClarificationRoundRef, payload: SendClarificationRoundMessagePayload, author:
|
|
54
|
+
sendClarificationRoundMessage(roundId: ClarificationRoundRef, payload: SendClarificationRoundMessagePayload, author: TrustedCollaborationAuthor): ControlPlaneCommandResult<SendClarificationRoundMessageDisposition, SendClarificationRoundMessageResult>;
|
|
54
55
|
submitClarificationRound(roundId: ClarificationRoundRef, payload: SubmitClarificationRoundPayload, commandId: IdempotencyKey): ControlPlaneCommandResult<SubmitClarificationRoundDisposition, SubmitClarificationRoundResult>;
|
|
55
56
|
waitForIdle(): Promise<void>;
|
|
56
57
|
private trackAsyncOwner;
|
|
@@ -19,7 +19,9 @@ export function shouldUseMessageAsScratchpadSource(message) {
|
|
|
19
19
|
if (message.scope.kind !== "main_chat") {
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
|
-
if (message.message_kind === "user_text" &&
|
|
22
|
+
if (message.message_kind === "user_text" &&
|
|
23
|
+
(message.author.kind === "human" ||
|
|
24
|
+
(message.author.kind === "system" && message.refs?.development_operator === true))) {
|
|
23
25
|
return true;
|
|
24
26
|
}
|
|
25
27
|
if (message.message_kind === "agent_text" && message.author.kind === "agent") {
|
|
@@ -31,7 +33,11 @@ export function filterScratchpadSourceMessages(messages) {
|
|
|
31
33
|
return messages.filter(shouldUseMessageAsScratchpadSource);
|
|
32
34
|
}
|
|
33
35
|
function compactRole(message) {
|
|
34
|
-
return message.
|
|
36
|
+
return message.refs?.development_operator === true
|
|
37
|
+
? "operator"
|
|
38
|
+
: message.author.kind === "agent"
|
|
39
|
+
? "tutti"
|
|
40
|
+
: "human";
|
|
35
41
|
}
|
|
36
42
|
export function truncateTextMiddle(text, maxChars) {
|
|
37
43
|
const trimmed = text.trim();
|
|
@@ -54,7 +60,7 @@ function sourceText(message) {
|
|
|
54
60
|
return `Reference file (${reference.category}:${reference.name})\n${message.body}`;
|
|
55
61
|
}
|
|
56
62
|
function sourceAuthorDisplayName(message) {
|
|
57
|
-
if (message.author.kind !== "human") {
|
|
63
|
+
if (message.author.kind !== "human" && message.refs?.development_operator !== true) {
|
|
58
64
|
return undefined;
|
|
59
65
|
}
|
|
60
66
|
const displayName = message.author.display_name?.trim();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { clarificationAnswerRole } from "@tutti/shared/utils";
|
|
1
2
|
import { readActiveClarificationProjection, readClarificationRoundProjection, readClarificationRoundsForThread, readMessageProjectionById, readTaskCompileClarificationRoundsByWorkflowRef, } from "../collaboration-state/index.js";
|
|
2
3
|
function answerMessage(store, messageId, roundId) {
|
|
3
4
|
const message = readMessageProjectionById(store.db, messageId);
|
|
@@ -7,11 +8,15 @@ function answerMessage(store, messageId, roundId) {
|
|
|
7
8
|
(message.message_kind !== "user_text" && message.message_kind !== "agent_text")) {
|
|
8
9
|
return null;
|
|
9
10
|
}
|
|
10
|
-
const role = message.author.kind === "agent"
|
|
11
|
+
const role = message.author.kind === "agent" && message.message_kind === "agent_text"
|
|
12
|
+
? "tutti"
|
|
13
|
+
: clarificationAnswerRole(message);
|
|
14
|
+
if (role === null)
|
|
15
|
+
return null;
|
|
11
16
|
const displayName = message.author.display_name?.trim();
|
|
12
17
|
return {
|
|
13
18
|
role,
|
|
14
|
-
...(role
|
|
19
|
+
...(role !== "tutti" && displayName !== undefined && displayName !== ""
|
|
15
20
|
? { author_display_name: displayName }
|
|
16
21
|
: {}),
|
|
17
22
|
text: message.body,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClarificationRequestPayload, ExternalReferenceDescriptor } from "@tutti/shared/schemas/api";
|
|
2
2
|
export type PromptSourceMessage = {
|
|
3
|
-
role: "human" | "tutti";
|
|
3
|
+
role: "human" | "tutti" | "operator";
|
|
4
4
|
author_display_name?: string;
|
|
5
5
|
text: string;
|
|
6
6
|
external_references?: ExternalReferenceDescriptor[];
|
|
@@ -8,10 +8,12 @@ function promptSourceMessage(db, source) {
|
|
|
8
8
|
if (message.scope.kind !== "main_chat") {
|
|
9
9
|
throw new Error("Task source message is outside main chat");
|
|
10
10
|
}
|
|
11
|
-
if (message.message_kind === "user_text" &&
|
|
11
|
+
if (message.message_kind === "user_text" &&
|
|
12
|
+
(message.author.kind === "human" ||
|
|
13
|
+
(message.author.kind === "system" && message.refs?.development_operator === true))) {
|
|
12
14
|
const displayName = message.author.display_name?.trim();
|
|
13
15
|
return {
|
|
14
|
-
role: "human",
|
|
16
|
+
role: message.refs?.development_operator === true ? "operator" : "human",
|
|
15
17
|
...(displayName === undefined || displayName === ""
|
|
16
18
|
? {}
|
|
17
19
|
: { author_display_name: displayName }),
|
|
@@ -2,6 +2,7 @@ import { copyFileSync, mkdtempSync } from "node:fs";
|
|
|
2
2
|
import { rm } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
|
+
import { clarificationAnswerRole } from "@tutti/shared/utils";
|
|
5
6
|
import { renderPromptTemplate } from "../../prompt-templates/index.js";
|
|
6
7
|
import { createOpenAiStructuredOutputClient, runOpenAiStructuredOutput, } from "../../providers/openai/sdk-procedure-runner.js";
|
|
7
8
|
import { readOpenAiApiKeyCredential } from "../../providers/openai/credential-store.js";
|
|
@@ -162,10 +163,10 @@ function referenceFileSummaryWorkflowOutput(output, originalPath) {
|
|
|
162
163
|
function followUpCheckPromptInput(input) {
|
|
163
164
|
const submittedMessageRefs = new Set(input.submitted_message_refs);
|
|
164
165
|
const answers = input.round_messages
|
|
165
|
-
.filter((message) => message
|
|
166
|
-
.filter((message) => submittedMessageRefs.
|
|
167
|
-
.
|
|
168
|
-
.
|
|
166
|
+
.filter((message) => clarificationAnswerRole(message) !== null)
|
|
167
|
+
.filter((message) => submittedMessageRefs.has(message.id))
|
|
168
|
+
.filter((message) => message.body.trim().length > 0)
|
|
169
|
+
.map((message) => ({ role: clarificationAnswerRole(message), text: message.body.trim() }));
|
|
169
170
|
return {
|
|
170
171
|
title: input.task_detail.task.title,
|
|
171
172
|
goal: input.task_detail.detail.contract.goal,
|