@xfey/tutti 0.1.126 → 0.1.128

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 (107) hide show
  1. package/README.md +2 -0
  2. package/dist/approvals/decision-command.d.ts +2 -2
  3. package/dist/chat-assistant/diagnostics.d.ts +11 -3
  4. package/dist/chat-assistant/diagnostics.js +5 -2
  5. package/dist/chat-assistant/failures.d.ts +27 -0
  6. package/dist/chat-assistant/failures.js +102 -0
  7. package/dist/chat-assistant/index.d.ts +14 -2
  8. package/dist/chat-assistant/index.js +241 -54
  9. package/dist/chat-assistant/language-context.d.ts +8 -0
  10. package/dist/chat-assistant/language-context.js +41 -0
  11. package/dist/chat-assistant/requests.d.ts +30 -0
  12. package/dist/chat-assistant/requests.js +58 -0
  13. package/dist/collaboration-ingestion/clarification.js +3 -1
  14. package/dist/collaboration-ingestion/main-chat.js +1 -0
  15. package/dist/collaboration-ingestion/types.d.ts +2 -0
  16. package/dist/collaboration-state/clarification-snapshot.d.ts +5 -5
  17. package/dist/collaboration-state/communication-language.d.ts +31 -0
  18. package/dist/collaboration-state/communication-language.js +36 -0
  19. package/dist/collaboration-state/task-compile-context.d.ts +1 -1
  20. package/dist/collaboration-state/task-compile-context.js +20 -1
  21. package/dist/collaboration-state/task-compile-requests.d.ts +6 -0
  22. package/dist/collaboration-state/task-compile-requests.js +16 -0
  23. package/dist/communication-language/index.d.ts +75 -0
  24. package/dist/communication-language/index.js +122 -0
  25. package/dist/communication-language/live-smoke-cli.d.ts +2 -0
  26. package/dist/communication-language/live-smoke-cli.js +368 -0
  27. package/dist/communication-language/prompt.d.ts +22 -0
  28. package/dist/communication-language/prompt.js +73 -0
  29. package/dist/control-plane/communication-language.d.ts +33 -0
  30. package/dist/control-plane/communication-language.js +72 -0
  31. package/dist/control-plane/context-sync.js +7 -0
  32. package/dist/control-plane/follow-up-output.js +25 -4
  33. package/dist/control-plane/follow-up-start.js +17 -0
  34. package/dist/control-plane/project-brief-refresh.js +10 -1
  35. package/dist/control-plane/project-context-bootstrap.d.ts +2 -0
  36. package/dist/control-plane/project-context-bootstrap.js +8 -0
  37. package/dist/control-plane/reference-summary-refresh.js +7 -0
  38. package/dist/control-plane/run-start.js +14 -6
  39. package/dist/control-plane/scratchpad-refresh-start.d.ts +1 -0
  40. package/dist/control-plane/scratchpad-refresh-start.js +13 -0
  41. package/dist/control-plane/scratchpad-refresh.d.ts +2 -0
  42. package/dist/control-plane/scratchpad-refresh.js +40 -26
  43. package/dist/control-plane/task-compile-continuation.js +16 -1
  44. package/dist/control-plane/task-compile-output.js +38 -14
  45. package/dist/control-plane/task-compile-request-status.d.ts +6 -0
  46. package/dist/control-plane/task-compile-request-status.js +70 -0
  47. package/dist/control-plane/task-compile-start.d.ts +1 -0
  48. package/dist/control-plane/task-compile-start.js +62 -3
  49. package/dist/control-plane/types.d.ts +2 -0
  50. package/dist/control-plane/workflows/openai.js +48 -28
  51. package/dist/control-plane/workflows/types.d.ts +18 -13
  52. package/dist/prompt-templates/index.d.ts +1 -1
  53. package/dist/prompt-templates/index.js +2 -0
  54. package/dist/providers/failure-classification.d.ts +23 -0
  55. package/dist/providers/failure-classification.js +43 -0
  56. package/dist/reference-access/read-evidence.d.ts +2 -0
  57. package/dist/reference-access/read-evidence.js +5 -0
  58. package/dist/reference-access/service.d.ts +2 -0
  59. package/dist/reference-access/service.js +2 -0
  60. package/dist/run-pipeline/task-run-invocation.js +12 -9
  61. package/dist/runtime-failures.js +15 -1
  62. package/dist/server-shell/cli/external-reference-runtime.js +6 -3
  63. package/dist/server-shell/cli/host-server-runtime.js +4 -1
  64. package/dist/server-shell/cli/relay-registration.js +1 -0
  65. package/dist/server-shell/http/routes/project-api/messages-routes.js +22 -1
  66. package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +140 -5
  67. package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.js +29 -2
  68. package/dist/server-shell/http/routes/project-api/openapi-skills-routes.d.ts +2 -0
  69. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +6 -0
  70. package/dist/server-shell/http/routes/project-api/openapi.d.ts +148 -5
  71. package/dist/server-shell/http/routes/project-api/schemas.d.ts +6 -0
  72. package/dist/server-shell/http/routes/project-api/schemas.js +1 -0
  73. package/dist/server-shell/http/routes/project-api/types.d.ts +1 -0
  74. package/dist/server-shell/http/routes/project-api/workflow-routes.js +39 -3
  75. package/dist/server-shell/http/routes/project-api/workspace-projections.js +1 -0
  76. package/dist/server-shell/http/validation.js +8 -2
  77. package/dist/server-shell/local-console/managed-project-service.d.ts +1 -1
  78. package/dist/server-shell/managed-access/transport.d.ts +1 -1
  79. package/migrations/0023_communication_language.sql +14 -0
  80. package/migrations/0024_chat_requests.sql +19 -0
  81. package/migrations/0025_task_compile_requests.sql +50 -0
  82. package/migrations/README.md +3 -1
  83. package/node_modules/@tutti/relay-client/dist/host-control.d.ts +1 -0
  84. package/node_modules/@tutti/relay-client/dist/host-control.js +1 -0
  85. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -0
  86. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -0
  87. package/node_modules/@tutti/shared/dist/schemas/api/operation-status.d.ts +174 -0
  88. package/node_modules/@tutti/shared/dist/schemas/api/operation-status.js +75 -0
  89. package/node_modules/@tutti/shared/dist/schemas/api/primitives.d.ts +1 -0
  90. package/node_modules/@tutti/shared/dist/schemas/api/primitives.js +1 -0
  91. package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +1 -0
  92. package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.js +2 -1
  93. package/package.json +1 -1
  94. package/prompts/README.md +1 -0
  95. package/prompts/chat-assistant.md +1 -1
  96. package/prompts/communication-language-result.md +27 -0
  97. package/prompts/communication-language.md +50 -0
  98. package/prompts/procedures/follow-up-check.md +1 -1
  99. package/prompts/procedures/scratchpad-refresh.md +2 -2
  100. package/prompts/procedures/task-compile.md +1 -1
  101. package/prompts/prompt-flow-map.md +2 -0
  102. package/web/assets/{homepage-motion-scene-DyEmWwvt.js → homepage-motion-scene-BcMt0AVW.js} +1 -1
  103. package/web/assets/index-2eX37Jx6.js +70 -0
  104. package/web/assets/index-BJvKuUiT.css +1 -0
  105. package/web/index.html +2 -2
  106. package/web/assets/index-By3idT4U.js +0 -70
  107. package/web/assets/index-DSBjOZmJ.css +0 -1
@@ -3,6 +3,8 @@ import { readFollowUpCheckInputFromStore } from "./follow-up-context.js";
3
3
  import { applyFollowUpCheckOutput, closeTaskBoundFollowUpAsRetaskingRequired, } from "./follow-up-output.js";
4
4
  import { startRunFromFollowUp as startRunFromFollowUpSuccessor } from "./follow-up-run.js";
5
5
  import { logProcedureExecutionError } from "./procedure-logging.js";
6
+ import { workflowLanguageContext, sourceLanguageEvidence, messageLanguageEvidence, logLanguageContext, } from "./communication-language.js";
7
+ import { readScratchpadReceiptSourceRefs } from "../collaboration-state/index.js";
6
8
  export function startControlPlaneTaskBoundFollowUpCheck(options) {
7
9
  const runnerResolution = options.resolveWorkflowRunner();
8
10
  if (runnerResolution.kind !== "ready" || runnerResolution.runner.runFollowUpCheck === undefined) {
@@ -79,6 +81,20 @@ export function startControlPlaneTaskBoundFollowUpCheck(options) {
79
81
  });
80
82
  }
81
83
  const input = inputResult.input;
84
+ const submitted = new Set(input.submitted_message_refs);
85
+ input.communication_language = workflowLanguageContext(options.store.db, {
86
+ workflowRef: input.task_detail.task.created_from_workflow_ref,
87
+ taskId: input.task_id,
88
+ sources: sourceLanguageEvidence(options.store.db, readScratchpadReceiptSourceRefs(options.store.db, input.task_detail.task.created_from_workflow_ref)),
89
+ answers: input.round_messages
90
+ .filter((message) => submitted.has(message.id))
91
+ .map(messageLanguageEvidence),
92
+ });
93
+ logLanguageContext(options.logger, input.communication_language, {
94
+ workflow_ref: workflowRef,
95
+ activity_ref: context.activity_ref,
96
+ task_id: input.task_id,
97
+ });
82
98
  output = await runnerResolution.runner.runFollowUpCheck?.(input, {
83
99
  workflow_ref: workflowRef,
84
100
  activity_ref: context.activity_ref,
@@ -90,6 +106,7 @@ export function startControlPlaneTaskBoundFollowUpCheck(options) {
90
106
  result_anchor: { kind: "workflow", workflow_ref: workflowRef },
91
107
  };
92
108
  }
109
+ logLanguageContext(options.logger, input.communication_language, { workflow_ref: workflowRef, activity_ref: context.activity_ref, task_id: input.task_id }, output.communication_language);
93
110
  return applyFollowUpCheckOutput({
94
111
  store: options.store,
95
112
  events: options.events,
@@ -1,5 +1,6 @@
1
1
  import { readProjectBriefProjection, readProjectBriefSourceDocuments, upsertProjectBriefProjection, } from "../project-brief/index.js";
2
2
  import { PROJECT_DOC_PATHS } from "../workspace-ops/index.js";
3
+ import { projectLanguageContext, logLanguageContext } from "./communication-language.js";
3
4
  export function projectBriefShouldRefreshForUpdatedPaths(paths) {
4
5
  return paths.some((path) => PROJECT_DOC_PATHS.includes(path));
5
6
  }
@@ -57,7 +58,15 @@ export async function refreshProjectBriefProjection(input) {
57
58
  }
58
59
  let output;
59
60
  try {
60
- output = await runner.runProjectBriefRefresh({ docs: sourceDocs }, input.workflowRef === undefined || input.activityRef === undefined
61
+ const language = projectLanguageContext(input.store.db, "summary");
62
+ logLanguageContext(input.logger, language, {
63
+ ...(input.workflowRef === undefined ? {} : { workflow_ref: input.workflowRef }),
64
+ ...(input.activityRef === undefined ? {} : { activity_ref: input.activityRef }),
65
+ });
66
+ output = await runner.runProjectBriefRefresh({
67
+ docs: sourceDocs,
68
+ communication_language: language,
69
+ }, input.workflowRef === undefined || input.activityRef === undefined
61
70
  ? undefined
62
71
  : {
63
72
  workflow_ref: input.workflowRef,
@@ -1,5 +1,6 @@
1
1
  import type { ActivityRef, WorkflowInvocationRef } from "@tutti/shared/ids";
2
2
  import type { ScratchpadContentSnapshot } from "../collaboration-state/index.js";
3
+ import type { CommunicationLanguageContext } from "../communication-language/index.js";
3
4
  import type { ProcedureProgressUpdate } from "../procedure-engine/index.js";
4
5
  import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
5
6
  import type { InitializeProjectDocsResult, ProjectDocsInitializationContext, ProjectDocsInitializationDocument } from "../workspace-ops/index.js";
@@ -14,6 +15,7 @@ export declare function buildProjectContextBootstrapWorkflowInput(options: {
14
15
  }): ProjectContextBootstrapWorkflowInput | undefined;
15
16
  export declare function projectContextBootstrapDocuments(output: ProjectContextBootstrapWorkflowOutput): ProjectDocsInitializationDocument[];
16
17
  export declare function tryProjectContextBootstrapDocuments(input: {
18
+ communicationLanguage?: CommunicationLanguageContext;
17
19
  runner: ProcedureWorkflowRunner;
18
20
  projectContext: Phase5ControlPlaneOptions["projectContext"];
19
21
  scratchpad: ScratchpadContentSnapshot;
@@ -1,5 +1,6 @@
1
1
  import { projectDocPath, readProjectDocsSummaries } from "../project-docs/context.js";
2
2
  import { projectContextBootstrapInvalidates } from "./invalidations.js";
3
+ import { logLanguageContext } from "./communication-language.js";
3
4
  export function buildProjectDocsInitializationContext(scratchpad) {
4
5
  return {
5
6
  source: "scratchpad_submit",
@@ -56,6 +57,13 @@ export async function tryProjectContextBootstrapDocuments(input) {
56
57
  if (workflowInput === undefined) {
57
58
  return undefined;
58
59
  }
60
+ if (input.communicationLanguage !== undefined) {
61
+ workflowInput.communication_language = input.communicationLanguage;
62
+ logLanguageContext(input.logger, input.communicationLanguage, {
63
+ workflow_ref: input.workflowRef,
64
+ activity_ref: input.activityRef,
65
+ });
66
+ }
59
67
  try {
60
68
  const output = await input.runner.runProjectContextBootstrap(workflowInput, {
61
69
  workflow_ref: input.workflowRef,
@@ -1,4 +1,5 @@
1
1
  import { createWorkflowInvocationRef } from "@tutti/shared/ids";
2
+ import { projectLanguageContext, logLanguageContext } from "./communication-language.js";
2
3
  import { recordProjectTimelineEvent } from "../project-timeline/index.js";
3
4
  import { withHostStoreTransaction } from "../store/index.js";
4
5
  import { WorkspaceOpsError, readReferenceSummaryTargets, updateReferenceSummaries, } from "../workspace-ops/index.js";
@@ -89,6 +90,7 @@ async function runReferenceSummaryRefresh(options) {
89
90
  let completedInBatch = 0;
90
91
  const batchResults = await mapWithConcurrency(batch, REFERENCE_SUMMARY_CONCURRENCY, async (target) => {
91
92
  const result = await summarizeReferenceTarget({
93
+ communicationLanguage: projectLanguageContext(options.store.db, "summary"),
92
94
  target,
93
95
  runner: options.runner,
94
96
  workflowRef: options.workflowRef,
@@ -211,7 +213,12 @@ async function mapWithConcurrency(items, concurrency, worker) {
211
213
  async function summarizeReferenceTarget(options) {
212
214
  for (let attempt = 1; attempt <= REFERENCE_SUMMARY_MAX_ATTEMPTS; attempt += 1) {
213
215
  try {
216
+ logLanguageContext(options.logger, options.communicationLanguage, {
217
+ workflow_ref: options.workflowRef,
218
+ activity_ref: options.activityRef,
219
+ });
214
220
  const output = await options.runner.runReferenceFileSummary?.({
221
+ communication_language: options.communicationLanguage,
215
222
  workflow_ref: options.workflowRef,
216
223
  activity_ref: options.activityRef,
217
224
  file: {
@@ -2,8 +2,9 @@ import { readScratchpadReceiptSourceRefs } from "../collaboration-state/index.js
2
2
  import { materializeWorkflowRecentReferences } from "./recent-references.js";
3
3
  import { readCompletedTaskCompileClarificationRounds } from "./task-compile-clarification-context.js";
4
4
  import { materializePromptSourceMessages } from "./task-source-context.js";
5
- import { recordRunPipelineFailure, recordRunPipelineResult, } from "./run-result-recording.js";
5
+ import { recordRunPipelineFailure, recordRunPipelineResult } from "./run-result-recording.js";
6
6
  import { projectBriefShouldRefreshForUpdatedPaths, refreshProjectBriefProjection, } from "./project-brief-refresh.js";
7
+ import { workflowLanguageContext, sourceLanguageEvidence, logLanguageContext, } from "./communication-language.js";
7
8
  function runLineageFields(lineage) {
8
9
  return {
9
10
  run_lineage_kind: lineage.kind,
@@ -83,8 +84,7 @@ export function startControlPlaneRunForTask(input) {
83
84
  const pipelineStartedAt = input.now();
84
85
  input.logger?.info(lifecycleFields, "Run pipeline started");
85
86
  try {
86
- const workflowRef = input.run.task
87
- .created_from_workflow_ref;
87
+ const workflowRef = input.run.task.created_from_workflow_ref;
88
88
  const sourceMessages = materializePromptSourceMessages(input.store.db, readScratchpadReceiptSourceRefs(input.store.db, workflowRef));
89
89
  const clarificationRounds = readCompletedTaskCompileClarificationRounds({
90
90
  store: input.store,
@@ -98,7 +98,17 @@ export function startControlPlaneRunForTask(input) {
98
98
  workflowRef,
99
99
  now: input.now,
100
100
  });
101
+ const language = workflowLanguageContext(input.store.db, {
102
+ workflowRef,
103
+ taskId: input.run.task.id,
104
+ sources: sourceLanguageEvidence(input.store.db, readScratchpadReceiptSourceRefs(input.store.db, workflowRef)),
105
+ });
106
+ logLanguageContext(input.logger, language, {
107
+ activity_ref: context.activity_ref,
108
+ task_id: input.run.task.id,
109
+ });
101
110
  const pipelineResult = await input.run.runner.runTask({
111
+ communication_language: language,
102
112
  activity_ref: context.activity_ref,
103
113
  task: input.run.task,
104
114
  task_detail: input.run.task_detail,
@@ -114,9 +124,7 @@ export function startControlPlaneRunForTask(input) {
114
124
  ...(clarificationRounds.length === 0
115
125
  ? {}
116
126
  : { clarification_rounds: clarificationRounds }),
117
- ...(recentReferences.length === 0
118
- ? {}
119
- : { recent_references: recentReferences }),
127
+ ...(recentReferences.length === 0 ? {} : { recent_references: recentReferences }),
120
128
  on_stage: (progress) => context.reportProgress({
121
129
  phase: progress.stage,
122
130
  summary: runStageSummary(input.run, progress),
@@ -30,6 +30,7 @@ export declare function runControlPlaneScratchpadRefreshProcedure(options: {
30
30
  events: WorkspaceEventBus;
31
31
  sourceBatch: ScratchpadSourceBatch;
32
32
  lane: ProcedureLane;
33
+ logger?: ControlPlaneLogger | undefined;
33
34
  recordRecoveryIntent?: boolean;
34
35
  recoveryIntentId?: ControlPlaneIntentId;
35
36
  now: () => Date;
@@ -1,5 +1,6 @@
1
1
  import { createWorkflowInvocationRef, } from "@tutti/shared/ids";
2
2
  import { readActiveTaskCompileContext, readMainChatMessagesForScratchpadCycle, readScratchpadSourceState, readWorklistProjection, markScratchpadRefreshFailed, markScratchpadRefreshStarted, } from "../collaboration-state/index.js";
3
+ import { projectLanguageContext, messageLanguageEvidence, logLanguageContext, } from "./communication-language.js";
3
4
  import { readProjectBriefProjection, readProjectBriefSourceDocuments, } from "../project-brief/index.js";
4
5
  import { withHostStoreTransaction } from "../store/index.js";
5
6
  import { logProcedureExecutionError } from "./procedure-logging.js";
@@ -37,6 +38,7 @@ function workflowInputSize(input) {
37
38
  }
38
39
  function fitScratchpadRefreshWorkflowInput(input) {
39
40
  const base = {
41
+ communication_language: input.language,
40
42
  ...(input.projectBrief === undefined ? {} : { project_brief: input.projectBrief }),
41
43
  ...(input.activeTaskCompile === undefined
42
44
  ? {}
@@ -107,6 +109,7 @@ export function readControlPlaneScratchpadSourceBatch(store, options = {}) {
107
109
  ...(activeContext === null ? {} : { activeTaskCompile: activeContext.scratchpad_snapshot }),
108
110
  worklist: readWorklistProjection(store.db),
109
111
  sourceMessages,
112
+ language: projectLanguageContext(store.db, "scratchpad", sourceMessages.map(messageLanguageEvidence)),
110
113
  });
111
114
  return {
112
115
  workflow_input: workflowInput,
@@ -146,6 +149,12 @@ export async function runControlPlaneScratchpadRefreshProcedure(options) {
146
149
  now: options.now,
147
150
  });
148
151
  });
152
+ const language = options.sourceBatch.workflow_input.communication_language;
153
+ if (language !== undefined)
154
+ logLanguageContext(options.logger, language, {
155
+ workflow_ref: options.workflowRef,
156
+ activity_ref: options.activityRef,
157
+ });
149
158
  let output;
150
159
  try {
151
160
  output = await options.runner.runScratchpadRefresh(options.sourceBatch.workflow_input, {
@@ -160,6 +169,8 @@ export async function runControlPlaneScratchpadRefreshProcedure(options) {
160
169
  });
161
170
  throw error;
162
171
  }
172
+ if (language !== undefined)
173
+ logLanguageContext(options.logger, language, { workflow_ref: options.workflowRef, activity_ref: options.activityRef }, output.communication_language);
163
174
  return applyScratchpadRefreshOutput({
164
175
  store: options.store,
165
176
  events: options.events,
@@ -169,6 +180,7 @@ export async function runControlPlaneScratchpadRefreshProcedure(options) {
169
180
  cursorUpdate: options.sourceBatch.cursor_update,
170
181
  sourceRefs: options.sourceBatch.source_refs,
171
182
  now: options.now,
183
+ ...(language === undefined ? {} : { languageContext: language }),
172
184
  });
173
185
  }
174
186
  export function readActiveScratchpadRefreshActivityRef(options) {
@@ -247,6 +259,7 @@ export function startControlPlaneScratchpadRefresh(options) {
247
259
  error,
248
260
  }),
249
261
  execute: async (context) => runControlPlaneScratchpadRefreshProcedure({
262
+ logger: options.logger,
250
263
  runner: runnerResolution.runner,
251
264
  workflowRef,
252
265
  activityRef: context.activity_ref,
@@ -3,6 +3,7 @@ import type { ScratchpadSourceCursorUpdate } from "../collaboration-state/scratc
3
3
  import type { ScratchpadSourceRefInput } from "../collaboration-state/types.js";
4
4
  import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
5
5
  import type { HostProjectStore } from "../store/index.js";
6
+ import type { CommunicationLanguageContext } from "../communication-language/index.js";
6
7
  import type { ScratchpadRefreshWorkflowOutput } from "./workflows/index.js";
7
8
  export declare function applyScratchpadRefreshOutput(input: {
8
9
  store: HostProjectStore;
@@ -13,6 +14,7 @@ export declare function applyScratchpadRefreshOutput(input: {
13
14
  cursorUpdate: ScratchpadSourceCursorUpdate;
14
15
  sourceRefs: ScratchpadSourceRefInput[];
15
16
  now: () => Date;
17
+ languageContext?: CommunicationLanguageContext;
16
18
  }): {
17
19
  kind: "needs_human";
18
20
  summary: string;
@@ -1,44 +1,58 @@
1
- import { createMainChatAgentMessage, markScratchpadRefreshSucceeded, upsertScratchpadProjection, } from "../collaboration-state/index.js";
1
+ import { createMainChatAgentMessage, markScratchpadRefreshSucceeded, upsertScratchpadProjection, readMessageProjectionById, } from "../collaboration-state/index.js";
2
+ import { withHostStoreTransaction } from "../store/index.js";
3
+ import { recordScratchpadLanguage } from "./communication-language.js";
2
4
  import { mainChatInvalidates, scratchpadRefreshInvalidates } from "./invalidations.js";
3
5
  export function applyScratchpadRefreshOutput(input) {
6
+ const persistLanguage = () => recordScratchpadLanguage(input.store.db, {
7
+ ...(input.output.communication_language === undefined
8
+ ? {}
9
+ : { language: input.output.communication_language }),
10
+ ...(input.languageContext === undefined ? {} : { context: input.languageContext }),
11
+ sourceMessages: input.sourceRefs.flatMap((source) => {
12
+ const message = readMessageProjectionById(input.store.db, source.message_id);
13
+ return message === null ? [] : [message];
14
+ }),
15
+ activityRef: input.activityRef,
16
+ snapshot: input.output.decision === "ready",
17
+ now: input.now,
18
+ });
4
19
  if (input.output.decision === "needs_human") {
5
- const message = createMainChatAgentMessage(input.store.db, {
6
- body: input.output.request_payload.request,
7
- refs: {
8
- workflow_ref: input.workflowRef,
9
- activity_ref: input.activityRef,
10
- scratchpad_source: "exclude",
11
- },
12
- now: input.now,
20
+ const request = input.output.request_payload.request;
21
+ const message = withHostStoreTransaction(input.store.db, () => {
22
+ persistLanguage();
23
+ markScratchpadRefreshSucceeded(input.store.db, { ...input.cursorUpdate, now: input.now });
24
+ return createMainChatAgentMessage(input.store.db, {
25
+ body: request,
26
+ refs: {
27
+ workflow_ref: input.workflowRef,
28
+ activity_ref: input.activityRef,
29
+ scratchpad_source: "exclude",
30
+ },
31
+ now: input.now,
32
+ });
13
33
  });
14
34
  input.events.publish({
15
35
  event_type: "message.created",
16
36
  payload: { message },
17
37
  invalidates: mainChatInvalidates(),
18
38
  });
19
- markScratchpadRefreshSucceeded(input.store.db, {
20
- ...input.cursorUpdate,
21
- now: input.now,
22
- });
23
39
  return {
24
40
  kind: "needs_human",
25
41
  summary: input.output.request_payload.summary,
26
42
  result_anchor: { kind: "workflow", workflow_ref: input.workflowRef },
27
43
  };
28
44
  }
29
- const scratchpad = upsertScratchpadProjection(input.store.db, {
30
- topic: input.output.scratchpad_snapshot.topic,
31
- background_summary: input.output.scratchpad_snapshot.background_summary,
32
- current_consensus: input.output.scratchpad_snapshot.current_consensus,
33
- open_questions: input.output.scratchpad_snapshot.open_questions,
34
- task_changes: input.output.scratchpad_snapshot.task_changes,
35
- source_refs: input.sourceRefs,
36
- updated_by_activity_ref: input.activityRef,
37
- now: input.now,
38
- });
39
- markScratchpadRefreshSucceeded(input.store.db, {
40
- ...input.cursorUpdate,
41
- now: input.now,
45
+ const snapshot = input.output.scratchpad_snapshot;
46
+ const scratchpad = withHostStoreTransaction(input.store.db, () => {
47
+ persistLanguage();
48
+ const projection = upsertScratchpadProjection(input.store.db, {
49
+ ...snapshot,
50
+ source_refs: input.sourceRefs,
51
+ updated_by_activity_ref: input.activityRef,
52
+ now: input.now,
53
+ });
54
+ markScratchpadRefreshSucceeded(input.store.db, { ...input.cursorUpdate, now: input.now });
55
+ return projection;
42
56
  });
43
57
  input.events.publish({
44
58
  event_type: "scratchpad.updated",
@@ -1,11 +1,13 @@
1
1
  import { materializeClarificationSuccessor, readActiveTaskCompileContext, readClarificationRoundProjection, readWorklistProjection, rollbackTaskCompileContext, } from "../collaboration-state/index.js";
2
2
  import { withHostStoreTransaction } from "../store/index.js";
3
+ import { linkTaskCompileActivity } from "../collaboration-state/task-compile-requests.js";
3
4
  import { clarificationInvalidates } from "./invalidations.js";
4
5
  import { applyTaskCompileProcedureOutput } from "./task-compile-output.js";
5
6
  import { readTaskCompileClarificationRounds } from "./task-compile-clarification-context.js";
6
7
  import { materializePromptSourceMessages } from "./task-source-context.js";
7
8
  import { logProcedureExecutionError } from "./procedure-logging.js";
8
9
  import { materializeRecentReferences, readRecentReferenceSources } from "./recent-references.js";
10
+ import { workflowLanguageContext, sourceLanguageEvidence, logLanguageContext, } from "./communication-language.js";
9
11
  export function startControlPlaneTaskCompileContinuation(options) {
10
12
  if (options.owner.kind !== "task_compile") {
11
13
  return { kind: "obsolete", errorCode: "owner_kind_mismatch" };
@@ -26,6 +28,7 @@ export function startControlPlaneTaskCompileContinuation(options) {
26
28
  summary: "Continuing task_compile from clarification input.",
27
29
  now: options.now,
28
30
  onTransition: (state) => {
31
+ linkTaskCompileActivity(options.store.db, workflowRef, state.activity.activity_ref);
29
32
  options.publishProcedureTransition(state);
30
33
  if (state.transition_kind === "terminal") {
31
34
  options.onTerminal?.(state.activity.status === "failed"
@@ -59,10 +62,21 @@ export function startControlPlaneTaskCompileContinuation(options) {
59
62
  sources: readRecentReferenceSources(options.store.db, taskCompileContext.sources),
60
63
  now: options.now,
61
64
  });
65
+ const sourceMessages = materializePromptSourceMessages(options.store.db, taskCompileContext.sources);
66
+ const language = workflowLanguageContext(options.store.db, {
67
+ workflowRef,
68
+ sources: sourceLanguageEvidence(options.store.db, taskCompileContext.sources),
69
+ answers: clarificationRounds.flatMap((entry) => entry.answer_messages),
70
+ });
71
+ logLanguageContext(options.logger, language, {
72
+ workflow_ref: workflowRef,
73
+ activity_ref: context.activity_ref,
74
+ });
62
75
  const output = await runnerResolution.runner.runTaskCompile({
76
+ communication_language: language,
63
77
  workflow_ref: workflowRef,
64
78
  scratchpad: taskCompileContext.scratchpad_snapshot,
65
- source_messages: materializePromptSourceMessages(options.store.db, taskCompileContext.sources),
79
+ source_messages: sourceMessages,
66
80
  worklist: readWorklistProjection(options.store.db),
67
81
  ...(recentReferences.length === 0 ? {} : { recent_references: recentReferences }),
68
82
  clarification_rounds: clarificationRounds,
@@ -71,6 +85,7 @@ export function startControlPlaneTaskCompileContinuation(options) {
71
85
  activity_ref: context.activity_ref,
72
86
  reportProgress: context.reportProgress,
73
87
  });
88
+ logLanguageContext(options.logger, language, { workflow_ref: workflowRef, activity_ref: context.activity_ref }, output.communication_language);
74
89
  return applyTaskCompileProcedureOutput({
75
90
  store: options.store,
76
91
  events: options.events,
@@ -1,7 +1,8 @@
1
1
  import { applyTaskCompileProposal, completeTaskCompileContext, materializeClarificationSuccessor, openNextTaskCompileClarificationRound, openTaskCompileClarificationRound, readClarificationRoundProjection, readWorklistProjection, } from "../collaboration-state/index.js";
2
2
  import { withHostStoreTransaction } from "../store/index.js";
3
- import { clarificationInvalidates, taskCompileInvalidates, } from "./invalidations.js";
3
+ import { clarificationInvalidates, taskCompileInvalidates } from "./invalidations.js";
4
4
  import { normalizeTaskCompileProposal } from "./task-proposal.js";
5
+ import { recordWorkflowLanguage } from "./communication-language.js";
5
6
  const EMPTY_INITIAL_WORKLIST_CLARIFICATION = {
6
7
  title: "Worklist scope needed",
7
8
  summary: "No existing Worklist task covers this Scratchpad, and no new task was produced.",
@@ -11,20 +12,28 @@ function countWorklistTasks(worklist) {
11
12
  return worklist.modules.reduce((count, module) => count + module.tasks.length, 0);
12
13
  }
13
14
  function openTaskCompileNeedsHuman(input) {
14
- const opened = input.continueFromRoundId === undefined
15
- ? openTaskCompileClarificationRound(input.store.db, {
16
- workflow_ref: input.workflowRef,
17
- activity_ref: input.activityRef,
18
- request_payload: input.requestPayload,
19
- now: input.now,
20
- })
21
- : openNextTaskCompileClarificationRound(input.store.db, {
22
- continue_from_round_id: input.continueFromRoundId,
23
- workflow_ref: input.workflowRef,
24
- activity_ref: input.activityRef,
25
- request_payload: input.requestPayload,
15
+ const opened = withHostStoreTransaction(input.store.db, (tx) => {
16
+ recordWorkflowLanguage(tx, {
17
+ owner: { kind: "workflow", ref: input.workflowRef },
18
+ ...(input.language === undefined ? {} : { language: input.language }),
19
+ activityRef: input.activityRef,
26
20
  now: input.now,
27
21
  });
22
+ return input.continueFromRoundId === undefined
23
+ ? openTaskCompileClarificationRound(input.store.db, {
24
+ workflow_ref: input.workflowRef,
25
+ activity_ref: input.activityRef,
26
+ request_payload: input.requestPayload,
27
+ now: input.now,
28
+ })
29
+ : openNextTaskCompileClarificationRound(input.store.db, {
30
+ continue_from_round_id: input.continueFromRoundId,
31
+ workflow_ref: input.workflowRef,
32
+ activity_ref: input.activityRef,
33
+ request_payload: input.requestPayload,
34
+ now: input.now,
35
+ });
36
+ });
28
37
  const roundId = opened.round.id;
29
38
  if (input.continueFromRoundId !== undefined) {
30
39
  input.events.publish({
@@ -66,9 +75,13 @@ function openTaskCompileNeedsHuman(input) {
66
75
  }
67
76
  export function applyTaskCompileProcedureOutput(input) {
68
77
  if (input.output.decision === "needs_human") {
78
+ const requestPayload = input.output.clarification_request_payload;
69
79
  return openTaskCompileNeedsHuman({
70
80
  ...input,
71
- requestPayload: input.output.clarification_request_payload,
81
+ requestPayload,
82
+ ...(input.output.communication_language === undefined
83
+ ? {}
84
+ : { language: input.output.communication_language }),
72
85
  });
73
86
  }
74
87
  const currentWorklist = readWorklistProjection(input.store.db);
@@ -79,12 +92,23 @@ export function applyTaskCompileProcedureOutput(input) {
79
92
  return openTaskCompileNeedsHuman({
80
93
  ...input,
81
94
  requestPayload: EMPTY_INITIAL_WORKLIST_CLARIFICATION,
95
+ ...(input.output.communication_language === undefined
96
+ ? {}
97
+ : { language: input.output.communication_language }),
82
98
  });
83
99
  }
84
100
  const continuationRound = input.continueFromRoundId === undefined
85
101
  ? null
86
102
  : readClarificationRoundProjection(input.store.db, input.continueFromRoundId);
87
103
  const committed = withHostStoreTransaction(input.store.db, (tx) => {
104
+ recordWorkflowLanguage(tx, {
105
+ owner: { kind: "workflow", ref: input.workflowRef },
106
+ ...(input.output.communication_language === undefined
107
+ ? {}
108
+ : { language: input.output.communication_language }),
109
+ activityRef: input.activityRef,
110
+ now: input.now,
111
+ });
88
112
  const applied = applyTaskCompileProposal(tx, {
89
113
  workflow_ref: input.workflowRef,
90
114
  proposal,
@@ -0,0 +1,6 @@
1
+ import type { ExecutionStatusProjection, WorklistSubmissionStatus } from "@tutti/shared/schemas/api";
2
+ import type { SqliteDatabase } from "../store/index.js";
3
+ /** Pure projection of owned records. A missing receipt is never proof of failure. */
4
+ export declare function readTaskCompileRequestStatus(db: SqliteDatabase, execution: ExecutionStatusProjection, workflowRef?: string): WorklistSubmissionStatus | null;
5
+ export declare function readTaskCompileCommandRef(db: SqliteDatabase, commandId: string): string | undefined;
6
+ //# sourceMappingURL=task-compile-request-status.d.ts.map
@@ -0,0 +1,70 @@
1
+ import { readActiveClarificationProjection, readActiveTaskCompileContext, readPendingTaskCompileSubmission, } from "../collaboration-state/index.js";
2
+ /** Pure projection of owned records. A missing receipt is never proof of failure. */
3
+ export function readTaskCompileRequestStatus(db, execution, workflowRef) {
4
+ const row = workflowRef === undefined
5
+ ? db
6
+ .prepare("SELECT * FROM task_compile_requests ORDER BY rowid DESC LIMIT 1")
7
+ .get()
8
+ : db
9
+ .prepare("SELECT * FROM task_compile_requests WHERE workflow_ref = ?")
10
+ .get(workflowRef);
11
+ if (row === undefined)
12
+ return null;
13
+ const common = {
14
+ operation: { kind: "worklist_submit", ref: row.workflow_ref },
15
+ created_at: row.created_at,
16
+ activity_ref: row.current_activity_ref,
17
+ };
18
+ if (db.prepare("SELECT 1 FROM scratchpad_receipts WHERE workflow_ref = ?").get(row.workflow_ref)) {
19
+ return { ...common, status: "succeeded", phase: "settled" };
20
+ }
21
+ if (row.failure_code !== null) {
22
+ return {
23
+ ...common,
24
+ status: "failed",
25
+ phase: "settled",
26
+ failure: {
27
+ code: row.failure_code,
28
+ category: "internal",
29
+ recovery: "none",
30
+ diagnostic_id: row.workflow_ref,
31
+ },
32
+ };
33
+ }
34
+ const clarification = readActiveClarificationProjection(db);
35
+ if (clarification.state === "active" &&
36
+ clarification.thread.owner.kind === "task_compile" &&
37
+ clarification.thread.owner.workflow_ref === row.workflow_ref &&
38
+ clarification.round.status === "writable") {
39
+ return {
40
+ ...common,
41
+ status: "waiting_input",
42
+ phase: "clarification",
43
+ round_id: clarification.round.id,
44
+ };
45
+ }
46
+ const activities = execution.active_activities ?? (execution.active_activity ? [execution.active_activity] : []);
47
+ const active = activities.find((entry) => entry.activity_ref === row.current_activity_ref || entry.workflow_ref === row.workflow_ref);
48
+ if (active !== undefined) {
49
+ const kind = active.workflow_kind;
50
+ const phase = kind === "scratchpad_refresh" ||
51
+ kind === "reference_summary_refresh" ||
52
+ kind === "project_context_bootstrap" ||
53
+ kind === "task_compile"
54
+ ? kind
55
+ : "preparing";
56
+ return { ...common, activity_ref: active.activity_ref, status: "running", phase };
57
+ }
58
+ const ref = row.workflow_ref;
59
+ if (readPendingTaskCompileSubmission(db, ref) !== null ||
60
+ readActiveTaskCompileContext(db, ref) !== null) {
61
+ return { ...common, status: "running", phase: "preparing" };
62
+ }
63
+ return { ...common, status: "unknown", phase: "unconfirmed" };
64
+ }
65
+ export function readTaskCompileCommandRef(db, commandId) {
66
+ return db
67
+ .prepare("SELECT workflow_ref FROM task_compile_request_commands WHERE command_id = ?")
68
+ .get(commandId)?.workflow_ref;
69
+ }
70
+ //# sourceMappingURL=task-compile-request-status.js.map
@@ -52,6 +52,7 @@ export declare function resumeControlPlaneTaskCompileChain(options: {
52
52
  onChainTerminal: (result?: IntentRuntimeTerminal) => void;
53
53
  }): IntentRuntimeStartResult;
54
54
  export declare function runControlPlaneTaskCompileProcedure(options: {
55
+ logger?: ControlPlaneLogger | undefined;
55
56
  runner: ProcedureWorkflowRunner;
56
57
  workflowRef: WorkflowInvocationRef;
57
58
  activityRef: ActivityRef;