@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.
Files changed (81) hide show
  1. package/README.md +1 -1
  2. package/dist/approvals/decision-command.d.ts +2 -2
  3. package/dist/chat-assistant/index.d.ts +1 -1
  4. package/dist/chat-assistant/index.js +26 -6
  5. package/dist/collaboration-ingestion/clarification.d.ts +25 -0
  6. package/dist/collaboration-ingestion/clarification.js +63 -0
  7. package/dist/collaboration-ingestion/external-source.d.ts +2 -0
  8. package/dist/collaboration-ingestion/external-source.js +35 -0
  9. package/dist/collaboration-ingestion/index.d.ts +2 -0
  10. package/dist/collaboration-ingestion/index.js +2 -0
  11. package/dist/collaboration-ingestion/main-chat.js +9 -2
  12. package/dist/collaboration-ingestion/platform-clarification.d.ts +10 -0
  13. package/dist/collaboration-ingestion/platform-clarification.js +42 -0
  14. package/dist/collaboration-ingestion/types.d.ts +1 -0
  15. package/dist/collaboration-state/clarification-messages.js +3 -2
  16. package/dist/collaboration-state/clarification-records.d.ts +1 -1
  17. package/dist/collaboration-state/clarification-records.js +7 -5
  18. package/dist/collaboration-state/clarification-rounds.js +5 -5
  19. package/dist/collaboration-state/clarification-snapshot.d.ts +228 -0
  20. package/dist/collaboration-state/clarification-snapshot.js +29 -0
  21. package/dist/collaboration-state/clarification-successors.js +6 -6
  22. package/dist/collaboration-state/index.d.ts +1 -0
  23. package/dist/collaboration-state/index.js +1 -0
  24. package/dist/collaboration-state/run-recording.js +1 -1
  25. package/dist/collaboration-state/task-compile-context.d.ts +1 -1
  26. package/dist/collaboration-state/types.d.ts +1 -0
  27. package/dist/control-plane/clarification-commands.d.ts +3 -2
  28. package/dist/control-plane/clarification-commands.js +13 -4
  29. package/dist/control-plane/follow-up-context.js +8 -14
  30. package/dist/control-plane/index.d.ts +3 -2
  31. package/dist/control-plane/scratchpad-source-messages.js +9 -3
  32. package/dist/control-plane/task-compile-clarification-context.js +7 -2
  33. package/dist/control-plane/task-source-context-types.d.ts +1 -1
  34. package/dist/control-plane/task-source-context.js +4 -2
  35. package/dist/control-plane/types.d.ts +1 -0
  36. package/dist/control-plane/workflows/openai.js +5 -4
  37. package/dist/platform-outbound/repository.js +83 -4
  38. package/dist/server-shell/cli/host-lifecycle.js +1 -0
  39. package/dist/server-shell/cli/host-server-runtime.d.ts +2 -1
  40. package/dist/server-shell/cli/host-server-runtime.js +4 -2
  41. package/dist/server-shell/cli/relay-registration.js +2 -0
  42. package/dist/server-shell/http/host-tunnel.d.ts +2 -1
  43. package/dist/server-shell/http/host-tunnel.js +4 -1
  44. package/dist/server-shell/http/integration-clarification-dispatch.d.ts +6 -0
  45. package/dist/server-shell/http/integration-clarification-dispatch.js +43 -0
  46. package/dist/server-shell/http/routes/agent-context-reference-routes.js +1 -3
  47. package/dist/server-shell/http/routes/project-api/clarification-routes.js +16 -42
  48. package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +2 -0
  49. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +1 -0
  50. package/dist/server-shell/http/routes/project-api/openapi.d.ts +3 -0
  51. package/dist/server-shell/http/routes/project-api/schemas.d.ts +1 -0
  52. package/migrations/0022_clarification_projection_cursors.sql +7 -0
  53. package/node_modules/@tutti/relay-client/dist/host-control.d.ts +2 -0
  54. package/node_modules/@tutti/relay-client/dist/host-control.js +6 -0
  55. package/node_modules/@tutti/shared/dist/schemas/api/clarifications.d.ts +14 -1
  56. package/node_modules/@tutti/shared/dist/schemas/api/clarifications.js +9 -2
  57. package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +4 -0
  58. package/node_modules/@tutti/shared/dist/schemas/api/messages.js +1 -0
  59. package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +1 -0
  60. package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +2 -0
  61. package/node_modules/@tutti/shared/dist/schemas/internal/index.js +2 -0
  62. package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification-content.d.ts +15 -0
  63. package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification-content.js +24 -0
  64. package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification.d.ts +354 -0
  65. package/node_modules/@tutti/shared/dist/schemas/internal/platform-clarification.js +94 -0
  66. package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.d.ts +132 -5
  67. package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.js +29 -5
  68. package/node_modules/@tutti/shared/dist/utils/clarification-participants.d.ts +4 -0
  69. package/node_modules/@tutti/shared/dist/utils/clarification-participants.js +11 -0
  70. package/node_modules/@tutti/shared/dist/utils/index.d.ts +1 -0
  71. package/node_modules/@tutti/shared/dist/utils/index.js +1 -0
  72. package/package.json +1 -1
  73. package/prompts/chat-assistant.md +1 -0
  74. package/prompts/procedures/follow-up-check.md +4 -4
  75. package/prompts/procedures/scratchpad-refresh.md +22 -2
  76. package/prompts/procedures/task-compile.md +1 -0
  77. package/prompts/runs/task-execute.md +2 -0
  78. package/web/assets/{homepage-motion-scene-rxYjg-zc.js → homepage-motion-scene-BwdH6Iss.js} +1 -1
  79. package/web/assets/index-B29RuNsd.js +69 -0
  80. package/web/index.html +1 -1
  81. package/web/assets/index-BrKWdtKZ.js +0 -69
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  `apps/server` 是 Tutti 的项目 host service,也是机器级 Local Console 的进程入口。
6
6
 
7
- `0.1.110` 发布候选加入每次 Chat invocation 的外部资料核验规则、本地/外部 provenance、从实际读取证据派生的回答来源线索,以及隔离多轮模型 smoke;配套 F.3 增量支持群资料确认与普通云盘文件。需要同步 Web/Relay/Integration 后再升级 Host;实际发布与真人验收状态见同一[按需资料计划](../../docs/roadmap/feishu-on-demand-reference-plan.md)。历史快照不删除,读取线索不继承新鲜度或权限。
7
+ `0.1.110` 已发布每次 Chat invocation 的外部资料核验规则、本地/外部 provenance、从实际读取证据派生的回答来源线索,以及隔离多轮模型 smoke;配套 F.3 增量支持群资料确认与普通云盘文件。Web/Relay/Integration 已先行同步,registry byte match 与本机 CLI/Console/原在线 Host 更新通过;实际发布与剩余真人验收状态见同一[按需资料计划](../../docs/roadmap/feishu-on-demand-reference-plan.md)。历史快照不删除,读取线索不继承新鲜度或权限。
8
8
 
9
9
  已发布的 `0.1.109` 统一验证 Codex `skills/extraRoots/set` / `skills/list` 与实际 `SKILL.md` 文件身份;Chat 的安全阶段日志可通过 invocation ref 关联外部 Reference 读取。候选安装/升级、registry byte match、本机 CLI/Console/测试 Host 更新及更新后 Docx 真人读取闭环已通过;连续更新/同次 pin/附件/失权 live 矩阵仍独立跟踪。证据见[按需资料计划](../../docs/roadmap/feishu-on-demand-reference-plan.md),不以安装版本代替实际读取证据。
10
10
 
@@ -22,6 +22,7 @@ export declare function executeApprovalDecisionCommand(input: {
22
22
  approval?: {
23
23
  state: "none";
24
24
  } | {
25
+ state: "pending";
25
26
  request: {
26
27
  task_id?: string;
27
28
  activity_ref?: string;
@@ -64,8 +65,8 @@ export declare function executeApprovalDecisionCommand(input: {
64
65
  request_kind: "command_execution" | "file_change" | "permissions" | "legacy_exec_command" | "legacy_apply_patch";
65
66
  requested_at: string;
66
67
  };
67
- state: "pending";
68
68
  } | {
69
+ state: "resolved";
69
70
  request: {
70
71
  task_id?: string;
71
72
  activity_ref?: string;
@@ -108,7 +109,6 @@ export declare function executeApprovalDecisionCommand(input: {
108
109
  request_kind: "command_execution" | "file_change" | "permissions" | "legacy_exec_command" | "legacy_apply_patch";
109
110
  requested_at: string;
110
111
  };
111
- state: "resolved";
112
112
  resolution: {
113
113
  decided_by?: {
114
114
  display_name: string;
@@ -49,7 +49,7 @@ export type ReadOnlyChatAssistantOptions = {
49
49
  model: ReadOnlyChatAssistantModel;
50
50
  promptsRoot?: string;
51
51
  onScratchpadSourceChanged?: (message: MessageProjection) => void;
52
- onMainChatAgentMessageCreated?: (input: {
52
+ onAgentMessageCreated?: (input: {
53
53
  tx: SqliteDatabase;
54
54
  triggerMessage: MessageProjection;
55
55
  responseMessage: MessageProjection;
@@ -49,6 +49,7 @@ function assistantFailureMessage() {
49
49
  function messageToContext(message) {
50
50
  const authorDisplayName = message.author.display_name?.trim();
51
51
  return {
52
+ ...(message.refs?.development_operator === true ? { source_role: "operator" } : {}),
52
53
  ...(authorDisplayName === undefined || authorDisplayName === ""
53
54
  ? {}
54
55
  : { author_display_name: authorDisplayName }),
@@ -57,6 +58,8 @@ function messageToContext(message) {
57
58
  };
58
59
  }
59
60
  function messageRole(message) {
61
+ if (message.author.kind === "system" && message.refs?.development_operator === true)
62
+ return "operator";
60
63
  if (message.author.kind === "agent") {
61
64
  return "tutti";
62
65
  }
@@ -110,6 +113,10 @@ export class ReadOnlyChatAssistant {
110
113
  this.maxQueuedMentions = options.maxQueuedMentions ?? 8;
111
114
  }
112
115
  enqueue(input) {
116
+ if (input.message.author.kind !== "human" &&
117
+ !(input.message.author.kind === "system" && input.message.refs?.development_operator === true)) {
118
+ return { triggered: false };
119
+ }
113
120
  if (!containsTuttiMention(messageTextForTuttiMention(input.message))) {
114
121
  return { triggered: false };
115
122
  }
@@ -255,7 +262,7 @@ export class ReadOnlyChatAssistant {
255
262
  ...(refs === undefined ? {} : { refs }),
256
263
  ...(this.options.now === undefined ? {} : { now: this.options.now }),
257
264
  });
258
- const callback = this.options.onMainChatAgentMessageCreated?.({
265
+ const callback = this.options.onAgentMessageCreated?.({
259
266
  tx,
260
267
  triggerMessage,
261
268
  responseMessage,
@@ -279,12 +286,24 @@ export class ReadOnlyChatAssistant {
279
286
  }
280
287
  appendClarificationRoundAssistantMessage(input) {
281
288
  const round = readClarificationRoundProjection(this.options.store.db, input.roundId);
282
- const message = createClarificationRoundAgentMessage(this.options.store.db, {
283
- round_id: input.roundId,
284
- body: input.body,
285
- ...(input.refs === undefined ? {} : { refs: input.refs }),
286
- ...(this.options.now === undefined ? {} : { now: this.options.now }),
289
+ let afterCommit;
290
+ const message = withHostStoreTransaction(this.options.store.db, (tx) => {
291
+ const responseMessage = createClarificationRoundAgentMessage(tx, {
292
+ round_id: input.roundId,
293
+ body: input.body,
294
+ ...(input.refs === undefined ? {} : { refs: input.refs }),
295
+ ...(this.options.now === undefined ? {} : { now: this.options.now }),
296
+ });
297
+ const callback = this.options.onAgentMessageCreated?.({
298
+ tx,
299
+ triggerMessage: input.triggerMessage,
300
+ responseMessage,
301
+ });
302
+ if (typeof callback === "function")
303
+ afterCommit = callback;
304
+ return responseMessage;
287
305
  });
306
+ afterCommit?.();
288
307
  const invalidates = [
289
308
  {
290
309
  kind: "clarification",
@@ -307,6 +326,7 @@ export class ReadOnlyChatAssistant {
307
326
  appendAssistantMessageForTrigger(triggerMessage, body, refs) {
308
327
  if (triggerMessage.scope.kind === "clarification_round") {
309
328
  this.appendClarificationRoundAssistantMessage({
329
+ triggerMessage,
310
330
  roundId: triggerMessage.scope.clarification_round_ref,
311
331
  body,
312
332
  ...(refs === undefined ? {} : { refs }),
@@ -0,0 +1,25 @@
1
+ import type { ClarificationRoundRef, IdempotencyKey } from "@tutti/shared/ids";
2
+ import type { MessageProjection, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResponse, SubmitClarificationRoundPayload, SubmitClarificationRoundResponse } from "@tutti/shared/schemas/api";
3
+ import type { Phase5ControlPlane } from "../control-plane/index.js";
4
+ import type { HostProjectStore, SqliteDatabase } from "../store/index.js";
5
+ import type { ChatAssistantEnqueuer, TrustedCollaborationAuthor } from "./types.js";
6
+ type RoundCommandOptions = {
7
+ store: HostProjectStore;
8
+ controlPlane: Pick<Phase5ControlPlane, "sendClarificationRoundMessage" | "submitClarificationRound">;
9
+ roundId: ClarificationRoundRef;
10
+ commandId: IdempotencyKey;
11
+ now?: () => Date;
12
+ };
13
+ /** Browser and trusted platform input share command identity, mutation and write-once effects. */
14
+ export declare function ingestClarificationMessage(options: RoundCommandOptions & {
15
+ payload: SendClarificationRoundMessagePayload;
16
+ author: TrustedCollaborationAuthor;
17
+ chatAssistant?: ChatAssistantEnqueuer;
18
+ idempotencyContext?: unknown;
19
+ afterCreate?: (tx: SqliteDatabase, message: MessageProjection) => void;
20
+ }): SendClarificationRoundMessageResponse;
21
+ export declare function submitClarificationAnswers(options: RoundCommandOptions & {
22
+ payload: SubmitClarificationRoundPayload;
23
+ }): SubmitClarificationRoundResponse;
24
+ export {};
25
+ //# sourceMappingURL=clarification.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { readClarificationRoundProjection, readMessageProjectionById, } from "../collaboration-state/index.js";
2
+ import { clarificationInvalidates } from "../control-plane/invalidations.js";
3
+ import { executeIdempotentCommand } from "../server-shell/command-idempotency/index.js";
4
+ /** Browser and trusted platform input share command identity, mutation and write-once effects. */
5
+ export function ingestClarificationMessage(options) {
6
+ const execution = executeIdempotentCommand({
7
+ db: options.store.db,
8
+ command_id: options.commandId,
9
+ command_name: "clarification.message.create",
10
+ target_ref: options.roundId,
11
+ payload: {
12
+ body: options.payload.body,
13
+ author_ref: options.author.account_ref,
14
+ ...(options.author.kind === "development_operator"
15
+ ? { author_kind: "development_operator" }
16
+ : {}),
17
+ ...(options.idempotencyContext === undefined
18
+ ? {}
19
+ : { ingestion_context: options.idempotencyContext }),
20
+ },
21
+ ...(options.now === undefined ? {} : { now: options.now }),
22
+ execute: (tx) => {
23
+ const result = options.controlPlane.sendClarificationRoundMessage(options.roundId, options.payload, options.author);
24
+ if (result.result?.message !== undefined)
25
+ options.afterCreate?.(tx, result.result.message);
26
+ return result;
27
+ },
28
+ });
29
+ const replayedMessage = execution.disposition.kind === "created" && execution.disposition.message_id !== undefined
30
+ ? readMessageProjectionById(options.store.db, execution.disposition.message_id)
31
+ : null;
32
+ const result = execution.result ?? (replayedMessage === null ? undefined : { message: replayedMessage });
33
+ if (!execution.replayed && result?.message !== undefined)
34
+ options.chatAssistant?.enqueue({ message: result.message });
35
+ return {
36
+ command_id: execution.command_id,
37
+ disposition: execution.disposition,
38
+ invalidates: clarificationInvalidates(options.roundId),
39
+ ...(result === undefined ? {} : { result }),
40
+ };
41
+ }
42
+ export function submitClarificationAnswers(options) {
43
+ const execution = executeIdempotentCommand({
44
+ db: options.store.db,
45
+ command_id: options.commandId,
46
+ command_name: "clarification.round.submit",
47
+ target_ref: options.roundId,
48
+ payload: options.payload,
49
+ ...(options.now === undefined ? {} : { now: options.now }),
50
+ execute: () => options.controlPlane.submitClarificationRound(options.roundId, options.payload, options.commandId),
51
+ });
52
+ const round = execution.disposition.kind === "accepted" || execution.disposition.kind === "already_submitted"
53
+ ? readClarificationRoundProjection(options.store.db, options.roundId)
54
+ : null;
55
+ const result = execution.result ?? (round === null ? undefined : { round });
56
+ return {
57
+ command_id: execution.command_id,
58
+ disposition: execution.disposition,
59
+ invalidates: clarificationInvalidates(options.roundId),
60
+ ...(result === undefined ? {} : { result }),
61
+ };
62
+ }
63
+ //# sourceMappingURL=clarification.js.map
@@ -1,12 +1,14 @@
1
1
  import type { IntegrationDeliveryDisposition, TrustedConversationSourceIngestionCommand } from "@tutti/shared/schemas/internal";
2
2
  import type { HostProjectStore } from "../store/index.js";
3
3
  import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
4
+ import type { Phase5ControlPlane } from "../control-plane/index.js";
4
5
  import type { ChatAssistantEnqueuer, ScratchpadSourceNotifier } from "./types.js";
5
6
  export declare const TRUSTED_INTEGRATION_INGESTION_PATH = "/internal/integration/v1/conversation-sources";
6
7
  export type IngestTrustedConversationSourceOptions = {
7
8
  store: HostProjectStore;
8
9
  events: WorkspaceEventBus;
9
10
  command: TrustedConversationSourceIngestionCommand;
11
+ controlPlane?: Pick<Phase5ControlPlane, "sendClarificationRoundMessage" | "submitClarificationRound">;
10
12
  scratchpadSource?: ScratchpadSourceNotifier;
11
13
  chatAssistant?: ChatAssistantEnqueuer;
12
14
  now?: () => Date;
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { INTEGRATION_CONVERSATION_SOURCE_TUNNEL_PATH, isTrustedConversationSourceIngestionCommand, } from "@tutti/shared/schemas/internal";
3
3
  import { ingestMainChatMessage } from "./main-chat.js";
4
+ import { ingestClarificationMessage } from "./clarification.js";
4
5
  export const TRUSTED_INTEGRATION_INGESTION_PATH = INTEGRATION_CONVERSATION_SOURCE_TUNNEL_PATH;
5
6
  function sha256Text(value) {
6
7
  return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
@@ -77,12 +78,45 @@ export function ingestTrustedConversationSource(options) {
77
78
  if (source.content.text.length > 8_000) {
78
79
  return { kind: "unsupported", reason_code: "message_too_long" };
79
80
  }
81
+ if (options.command.clarification_round_ref !== undefined) {
82
+ if (options.controlPlane === undefined)
83
+ return {
84
+ kind: "host_incompatible",
85
+ retryable: true,
86
+ reason_code: "integration_clarification_unsupported",
87
+ };
88
+ const response = ingestClarificationMessage({
89
+ store: options.store,
90
+ controlPlane: options.controlPlane,
91
+ commandId: options.command.command_id,
92
+ roundId: options.command.clarification_round_ref,
93
+ payload: { body: source.content.text },
94
+ author: {
95
+ ...(options.command.actor.kind === "bot" ? { kind: "development_operator" } : {}),
96
+ account_ref: options.command.actor.account_ref,
97
+ display_name: options.command.actor.display_name,
98
+ },
99
+ idempotencyContext: {
100
+ binding_ref: options.command.binding_ref,
101
+ external_message_ref: source.locator.message_ref,
102
+ },
103
+ afterCreate: (tx, message) => insertExternalSourceEvidence(tx, options.command, message),
104
+ ...(options.chatAssistant === undefined ? {} : { chatAssistant: options.chatAssistant }),
105
+ ...(options.now === undefined ? {} : { now: options.now }),
106
+ });
107
+ if (response.disposition.kind === "created" && response.result?.message !== undefined)
108
+ return { kind: "created", message_id: response.result.message.id };
109
+ if (response.disposition.kind === "interrupted")
110
+ return { kind: "host_unavailable", retryable: true, reason_code: "command_interrupted" };
111
+ return { kind: "invalid", reason_code: `clarification_${response.disposition.kind}` };
112
+ }
80
113
  const response = ingestMainChatMessage({
81
114
  store: options.store,
82
115
  events: options.events,
83
116
  commandId: options.command.command_id,
84
117
  payload: { body: source.content.text },
85
118
  author: {
119
+ ...(options.command.actor.kind === "bot" ? { kind: "development_operator" } : {}),
86
120
  account_ref: options.command.actor.account_ref,
87
121
  display_name: options.command.actor.display_name,
88
122
  },
@@ -100,6 +134,7 @@ export function ingestTrustedConversationSource(options) {
100
134
  external_message_ref: source.locator.message_ref,
101
135
  binding_ref: options.command.binding_ref,
102
136
  receipt_key: options.command.receipt.receipt_key,
137
+ ...(options.command.actor.kind === "bot" ? { actor_kind: "bot" } : {}),
103
138
  ...(source.external_references === undefined
104
139
  ? {}
105
140
  : { external_references: source.external_references }),
@@ -5,4 +5,6 @@ export { ingestTrustedManagedReference, readManagedReferenceSourcePaths, type In
5
5
  export { ingestReferenceFile, REFERENCE_FILE_INGESTION_COMMAND_NAME, REFERENCE_FILE_INGESTION_TARGET_REF, toReferenceFileProjection, type IngestReferenceFileOptions, } from "./reference-files.js";
6
6
  export { ingestTrustedReferenceAttachment, TRUSTED_INTEGRATION_REFERENCE_ATTACHMENT_PATH, type IngestTrustedReferenceAttachmentOptions, type ResolvedReferenceAttachmentContent, } from "./reference-attachments.js";
7
7
  export type { ChatAssistantEnqueuer, ReferenceSummaryStarter, ScratchpadSourceNotifier, TrustedCollaborationAuthor, } from "./types.js";
8
+ export { ingestClarificationMessage, submitClarificationAnswers } from "./clarification.js";
9
+ export { executeTrustedClarification } from "./platform-clarification.js";
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,6 @@ export { ingestManagedReferenceSnapshot, publishManagedReferenceSnapshotChanged,
4
4
  export { ingestTrustedManagedReference, readManagedReferenceSourcePaths, } from "./managed-reference-sources.js";
5
5
  export { ingestReferenceFile, REFERENCE_FILE_INGESTION_COMMAND_NAME, REFERENCE_FILE_INGESTION_TARGET_REF, toReferenceFileProjection, } from "./reference-files.js";
6
6
  export { ingestTrustedReferenceAttachment, TRUSTED_INTEGRATION_REFERENCE_ATTACHMENT_PATH, } from "./reference-attachments.js";
7
+ export { ingestClarificationMessage, submitClarificationAnswers } from "./clarification.js";
8
+ export { executeTrustedClarification } from "./platform-clarification.js";
7
9
  //# sourceMappingURL=index.js.map
@@ -10,6 +10,9 @@ export function ingestMainChatMessage(options) {
10
10
  payload: {
11
11
  ...options.payload,
12
12
  author_ref: options.author.account_ref,
13
+ ...(options.author.kind === "development_operator"
14
+ ? { author_kind: "development_operator" }
15
+ : {}),
13
16
  ...(options.idempotencyContext === undefined
14
17
  ? {}
15
18
  : { ingestion_context: options.idempotencyContext }),
@@ -23,12 +26,16 @@ export function ingestMainChatMessage(options) {
23
26
  const message = createMainChatMessage(tx, {
24
27
  body: materialized.body,
25
28
  author: {
26
- kind: "human",
29
+ kind: options.author.kind === "development_operator" ? "system" : "human",
27
30
  ref: options.author.account_ref,
28
31
  display_name: options.author.display_name,
29
32
  ...(options.author.avatar === undefined ? {} : { avatar: options.author.avatar }),
30
33
  },
31
- ...(materialized.refs === undefined ? {} : { refs: materialized.refs }),
34
+ ...(options.author.kind === "development_operator"
35
+ ? { refs: { ...materialized.refs, development_operator: true } }
36
+ : materialized.refs === undefined
37
+ ? {}
38
+ : { refs: materialized.refs }),
32
39
  ...(options.now === undefined ? {} : { now: options.now }),
33
40
  });
34
41
  options.afterCreate?.(tx, message);
@@ -0,0 +1,10 @@
1
+ import { type TrustedClarificationCommand, type IntegrationClarificationResponse } from "@tutti/shared/schemas/internal";
2
+ import type { Phase5ControlPlane } from "../control-plane/index.js";
3
+ import type { HostProjectStore } from "../store/index.js";
4
+ export declare function executeTrustedClarification(options: {
5
+ store: HostProjectStore;
6
+ controlPlane: Phase5ControlPlane;
7
+ command: TrustedClarificationCommand;
8
+ now?: () => Date;
9
+ }): IntegrationClarificationResponse;
10
+ //# sourceMappingURL=platform-clarification.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { isTrustedClarificationCommand, } from "@tutti/shared/schemas/internal";
2
+ import { readActiveClarificationProjection, readClarificationRoundProjection, readClarificationThreadResponse, } from "../collaboration-state/index.js";
3
+ import { submitClarificationAnswers } from "./clarification.js";
4
+ export function executeTrustedClarification(options) {
5
+ const { command, store } = options;
6
+ if (!isTrustedClarificationCommand(command))
7
+ return {
8
+ protocol_version: 1,
9
+ disposition: { kind: "invalid", reason_code: "trusted_clarification_invalid" },
10
+ };
11
+ if (command.operation.kind === "submit")
12
+ return {
13
+ protocol_version: 1,
14
+ disposition: {
15
+ kind: "submitted",
16
+ response: submitClarificationAnswers({
17
+ store,
18
+ controlPlane: options.controlPlane,
19
+ commandId: command.command_id,
20
+ roundId: command.operation.round_id,
21
+ payload: { expected_answer_revision: command.operation.expected_answer_revision },
22
+ ...(options.now === undefined ? {} : { now: options.now }),
23
+ }),
24
+ },
25
+ };
26
+ const round = command.operation.round_id === undefined
27
+ ? null
28
+ : readClarificationRoundProjection(store.db, command.operation.round_id);
29
+ const thread = round === null
30
+ ? null
31
+ : readClarificationThreadResponse(store.db, round.thread_id)
32
+ ?.thread;
33
+ return {
34
+ protocol_version: 1,
35
+ disposition: {
36
+ kind: "queried",
37
+ active: readActiveClarificationProjection(store.db),
38
+ ...(round === null || thread == null ? {} : { selected: { round, thread } }),
39
+ },
40
+ };
41
+ }
42
+ //# sourceMappingURL=platform-clarification.js.map
@@ -1,6 +1,7 @@
1
1
  import type { AccountAvatarProjection } from "@tutti/shared/domain";
2
2
  import type { MessageProjection } from "@tutti/shared/schemas/api";
3
3
  export type TrustedCollaborationAuthor = {
4
+ kind?: "human" | "development_operator";
4
5
  account_ref: string;
5
6
  display_name: string;
6
7
  avatar?: AccountAvatarProjection;
@@ -1,5 +1,5 @@
1
- import { createMessageId, } from "@tutti/shared/ids";
2
- import { clampLimit, decodeCursor, messageCursor, nowIso, stringifyJson, } from "./serialization.js";
1
+ import { createMessageId } from "@tutti/shared/ids";
2
+ import { clampLimit, decodeCursor, messageCursor, nowIso, stringifyJson } from "./serialization.js";
3
3
  import { readClarificationRoundRow } from "./clarification-records.js";
4
4
  import { mapMessageRow } from "./messages.js";
5
5
  import { recordReadNotificationEvent } from "./read-state.js";
@@ -7,6 +7,7 @@ export function createClarificationRoundMessage(db, input) {
7
7
  const createdAt = nowIso(input.now);
8
8
  const id = createMessageId();
9
9
  const refs = {
10
+ ...(input.refs ?? {}),
10
11
  clarification_round_ref: input.round_id,
11
12
  };
12
13
  db.prepare(`
@@ -4,7 +4,7 @@ import type { SqliteDatabase } from "../store/index.js";
4
4
  import type { SealedClarificationRoundWithoutSuccessor } from "./types.js";
5
5
  import type { ClarificationRoundRow, ClarificationThreadRow } from "./storage-types.js";
6
6
  export declare function mapClarificationThreadRow(row: ClarificationThreadRow): ClarificationThreadProjection;
7
- export declare function mapClarificationRoundRow(row: ClarificationRoundRow): ClarificationRoundProjection;
7
+ export declare function mapClarificationRoundRow(row: ClarificationRoundRow, db: SqliteDatabase): ClarificationRoundProjection;
8
8
  export declare function readClarificationThreadRow(db: SqliteDatabase, threadId: ClarificationThreadRef): ClarificationThreadRow | null;
9
9
  export declare function readClarificationRoundRow(db: SqliteDatabase, roundId: ClarificationRoundRef): ClarificationRoundRow | null;
10
10
  export declare function readActiveClarificationProjection(db: SqliteDatabase): ActiveClarificationProjection;
@@ -1,4 +1,5 @@
1
1
  import { parseJson } from "./serialization.js";
2
+ import { readClarificationAnswerRevision } from "./clarification-snapshot.js";
2
3
  export function mapClarificationThreadRow(row) {
3
4
  const thread = {
4
5
  id: row.id,
@@ -26,7 +27,7 @@ export function mapClarificationThreadRow(row) {
26
27
  }
27
28
  return thread;
28
29
  }
29
- export function mapClarificationRoundRow(row) {
30
+ export function mapClarificationRoundRow(row, db) {
30
31
  const round = {
31
32
  id: row.id,
32
33
  thread_id: row.clarification_thread_id,
@@ -38,6 +39,7 @@ export function mapClarificationRoundRow(row) {
38
39
  }),
39
40
  card_message_id: row.card_message_id,
40
41
  opening_message_id: row.opening_message_id,
42
+ answer_revision: readClarificationAnswerRevision(db, row.id),
41
43
  successor_status: row.successor_status,
42
44
  capabilities: {
43
45
  send_message: row.status === "writable",
@@ -99,7 +101,7 @@ export function readActiveClarificationProjection(db) {
99
101
  return {
100
102
  state: "active",
101
103
  thread: mapClarificationThreadRow(row),
102
- round: mapClarificationRoundRow(round),
104
+ round: mapClarificationRoundRow(round, db),
103
105
  };
104
106
  }
105
107
  export function readSealedClarificationRoundsWithoutSuccessor(db) {
@@ -120,7 +122,7 @@ export function readSealedClarificationRoundsWithoutSuccessor(db) {
120
122
  return [
121
123
  {
122
124
  thread: mapClarificationThreadRow(thread),
123
- round: mapClarificationRoundRow(roundRow),
125
+ round: mapClarificationRoundRow(roundRow, db),
124
126
  },
125
127
  ];
126
128
  });
@@ -142,7 +144,7 @@ export function deleteStaleClarificationSubmitReplayHints(db) {
142
144
  }
143
145
  export function readClarificationRoundProjection(db, roundId) {
144
146
  const row = readClarificationRoundRow(db, roundId);
145
- return row === null ? null : mapClarificationRoundRow(row);
147
+ return row === null ? null : mapClarificationRoundRow(row, db);
146
148
  }
147
149
  export function readClarificationRoundsForThread(db, threadId, options = {}) {
148
150
  const rows = options.throughRoundIndex === undefined
@@ -163,7 +165,7 @@ export function readClarificationRoundsForThread(db, threadId, options = {}) {
163
165
  ORDER BY round_index ASC
164
166
  `)
165
167
  .all(threadId, options.throughRoundIndex);
166
- return rows.map((row) => mapClarificationRoundRow(row));
168
+ return rows.map((row) => mapClarificationRoundRow(row, db));
167
169
  }
168
170
  export function readTaskCompileClarificationRoundsByWorkflowRef(db, workflowRef) {
169
171
  const threads = db
@@ -114,7 +114,7 @@ export function openTaskCompileClarificationRound(db, input) {
114
114
  }
115
115
  return {
116
116
  thread: mapClarificationThreadRow(thread),
117
- round: mapClarificationRoundRow(round),
117
+ round: mapClarificationRoundRow(round, db),
118
118
  card_message: mapMessageRow(cardMessage, db),
119
119
  opening_message: mapMessageRow(openingMessage),
120
120
  };
@@ -219,8 +219,8 @@ export function openNextTaskCompileClarificationRound(db, input) {
219
219
  }
220
220
  return {
221
221
  thread: mapClarificationThreadRow(thread),
222
- previous_round: mapClarificationRoundRow(previousRound),
223
- round: mapClarificationRoundRow(round),
222
+ previous_round: mapClarificationRoundRow(previousRound, db),
223
+ round: mapClarificationRoundRow(round, db),
224
224
  card_message: mapMessageRow(cardMessage, db),
225
225
  opening_message: mapMessageRow(openingMessage),
226
226
  };
@@ -337,8 +337,8 @@ export function openNextTaskBoundClarificationRound(db, input) {
337
337
  }
338
338
  return {
339
339
  thread: mapClarificationThreadRow(thread),
340
- previous_round: mapClarificationRoundRow(previousRound),
341
- round: mapClarificationRoundRow(round),
340
+ previous_round: mapClarificationRoundRow(previousRound, db),
341
+ round: mapClarificationRoundRow(round, db),
342
342
  task,
343
343
  card_message: mapMessageRow(cardMessage, db),
344
344
  opening_message: mapMessageRow(openingMessage),