@xfey/tutti 0.1.126 → 0.1.127

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 (48) hide show
  1. package/README.md +2 -0
  2. package/dist/chat-assistant/diagnostics.d.ts +4 -1
  3. package/dist/chat-assistant/index.js +15 -6
  4. package/dist/chat-assistant/language-context.d.ts +8 -0
  5. package/dist/chat-assistant/language-context.js +41 -0
  6. package/dist/collaboration-state/communication-language.d.ts +31 -0
  7. package/dist/collaboration-state/communication-language.js +36 -0
  8. package/dist/collaboration-state/task-compile-context.js +9 -0
  9. package/dist/communication-language/index.d.ts +75 -0
  10. package/dist/communication-language/index.js +122 -0
  11. package/dist/communication-language/live-smoke-cli.d.ts +2 -0
  12. package/dist/communication-language/live-smoke-cli.js +368 -0
  13. package/dist/communication-language/prompt.d.ts +22 -0
  14. package/dist/communication-language/prompt.js +73 -0
  15. package/dist/control-plane/communication-language.d.ts +33 -0
  16. package/dist/control-plane/communication-language.js +72 -0
  17. package/dist/control-plane/context-sync.js +7 -0
  18. package/dist/control-plane/follow-up-output.js +25 -4
  19. package/dist/control-plane/follow-up-start.js +17 -0
  20. package/dist/control-plane/project-brief-refresh.js +10 -1
  21. package/dist/control-plane/project-context-bootstrap.d.ts +2 -0
  22. package/dist/control-plane/project-context-bootstrap.js +8 -0
  23. package/dist/control-plane/reference-summary-refresh.js +7 -0
  24. package/dist/control-plane/run-start.js +14 -6
  25. package/dist/control-plane/scratchpad-refresh-start.d.ts +1 -0
  26. package/dist/control-plane/scratchpad-refresh-start.js +13 -0
  27. package/dist/control-plane/scratchpad-refresh.d.ts +2 -0
  28. package/dist/control-plane/scratchpad-refresh.js +40 -26
  29. package/dist/control-plane/task-compile-continuation.js +14 -1
  30. package/dist/control-plane/task-compile-output.js +38 -14
  31. package/dist/control-plane/task-compile-start.d.ts +1 -0
  32. package/dist/control-plane/task-compile-start.js +22 -1
  33. package/dist/control-plane/types.d.ts +2 -0
  34. package/dist/control-plane/workflows/openai.js +48 -28
  35. package/dist/control-plane/workflows/types.d.ts +18 -13
  36. package/dist/prompt-templates/index.d.ts +1 -1
  37. package/dist/prompt-templates/index.js +2 -0
  38. package/dist/run-pipeline/task-run-invocation.js +12 -9
  39. package/migrations/0023_communication_language.sql +14 -0
  40. package/package.json +1 -1
  41. package/prompts/README.md +1 -0
  42. package/prompts/chat-assistant.md +1 -1
  43. package/prompts/communication-language-result.md +27 -0
  44. package/prompts/communication-language.md +50 -0
  45. package/prompts/procedures/follow-up-check.md +1 -1
  46. package/prompts/procedures/scratchpad-refresh.md +2 -2
  47. package/prompts/procedures/task-compile.md +1 -1
  48. package/prompts/prompt-flow-map.md +2 -0
@@ -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",
@@ -6,6 +6,7 @@ import { readTaskCompileClarificationRounds } from "./task-compile-clarification
6
6
  import { materializePromptSourceMessages } from "./task-source-context.js";
7
7
  import { logProcedureExecutionError } from "./procedure-logging.js";
8
8
  import { materializeRecentReferences, readRecentReferenceSources } from "./recent-references.js";
9
+ import { workflowLanguageContext, sourceLanguageEvidence, logLanguageContext, } from "./communication-language.js";
9
10
  export function startControlPlaneTaskCompileContinuation(options) {
10
11
  if (options.owner.kind !== "task_compile") {
11
12
  return { kind: "obsolete", errorCode: "owner_kind_mismatch" };
@@ -59,10 +60,21 @@ export function startControlPlaneTaskCompileContinuation(options) {
59
60
  sources: readRecentReferenceSources(options.store.db, taskCompileContext.sources),
60
61
  now: options.now,
61
62
  });
63
+ const sourceMessages = materializePromptSourceMessages(options.store.db, taskCompileContext.sources);
64
+ const language = workflowLanguageContext(options.store.db, {
65
+ workflowRef,
66
+ sources: sourceLanguageEvidence(options.store.db, taskCompileContext.sources),
67
+ answers: clarificationRounds.flatMap((entry) => entry.answer_messages),
68
+ });
69
+ logLanguageContext(options.logger, language, {
70
+ workflow_ref: workflowRef,
71
+ activity_ref: context.activity_ref,
72
+ });
62
73
  const output = await runnerResolution.runner.runTaskCompile({
74
+ communication_language: language,
63
75
  workflow_ref: workflowRef,
64
76
  scratchpad: taskCompileContext.scratchpad_snapshot,
65
- source_messages: materializePromptSourceMessages(options.store.db, taskCompileContext.sources),
77
+ source_messages: sourceMessages,
66
78
  worklist: readWorklistProjection(options.store.db),
67
79
  ...(recentReferences.length === 0 ? {} : { recent_references: recentReferences }),
68
80
  clarification_rounds: clarificationRounds,
@@ -71,6 +83,7 @@ export function startControlPlaneTaskCompileContinuation(options) {
71
83
  activity_ref: context.activity_ref,
72
84
  reportProgress: context.reportProgress,
73
85
  });
86
+ logLanguageContext(options.logger, language, { workflow_ref: workflowRef, activity_ref: context.activity_ref }, output.communication_language);
74
87
  return applyTaskCompileProcedureOutput({
75
88
  store: options.store,
76
89
  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,
@@ -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;
@@ -1,4 +1,5 @@
1
1
  import { createWorkflowInvocationRef, } from "@tutti/shared/ids";
2
+ import { workflowLanguageContext, sourceLanguageEvidence, logLanguageContext, } from "./communication-language.js";
2
3
  import { captureTaskCompileContext, readActiveTaskCompileContext, readCurrentScratchpadSourceRefs, readPendingTaskCompileSubmission, readScratchpadProjection, readScratchpadSourceState, readWorklistProjection, recordTaskCompileSubmission, rollbackTaskCompileContext, } from "../collaboration-state/index.js";
3
4
  import { withHostStoreTransaction } from "../store/index.js";
4
5
  import { initializeProjectDocs, readProjectDocsInitializationStatus, } from "../workspace-ops/index.js";
@@ -166,6 +167,7 @@ function startControlPlaneTaskCompileActivity(options) {
166
167
  error,
167
168
  }),
168
169
  execute: async (context) => runControlPlaneTaskCompileProcedure({
170
+ logger: options.logger,
169
171
  runner: options.runner,
170
172
  store: options.store,
171
173
  events: options.events,
@@ -242,6 +244,7 @@ function startScratchpadRefreshBeforeTaskCompileActivity(options) {
242
244
  error,
243
245
  }),
244
246
  execute: async (context) => runControlPlaneScratchpadRefreshProcedure({
247
+ logger: options.logger,
245
248
  runner: options.runner,
246
249
  store: options.store,
247
250
  events: options.events,
@@ -552,6 +555,13 @@ function startProjectContextBootstrapActivity(options) {
552
555
  try {
553
556
  const initializationContext = buildProjectDocsInitializationContext(taskCompileContext.scratchpad_snapshot);
554
557
  const modelDocuments = await tryProjectContextBootstrapDocuments({
558
+ communicationLanguage: {
559
+ ...workflowLanguageContext(options.store.db, {
560
+ workflowRef: options.taskCompileWorkflowRef,
561
+ sources: [],
562
+ }),
563
+ scope: "documents",
564
+ },
555
565
  runner: options.runner,
556
566
  projectContext: options.projectContext,
557
567
  scratchpad: taskCompileContext.scratchpad_snapshot,
@@ -639,10 +649,20 @@ export async function runControlPlaneTaskCompileProcedure(options) {
639
649
  sources: readRecentReferenceSources(options.store.db, context.sources),
640
650
  now: options.now,
641
651
  });
652
+ const sourceMessages = materializePromptSourceMessages(options.store.db, context.sources);
653
+ const language = workflowLanguageContext(options.store.db, {
654
+ workflowRef: options.workflowRef,
655
+ sources: sourceLanguageEvidence(options.store.db, context.sources),
656
+ });
657
+ logLanguageContext(options.logger, language, {
658
+ workflow_ref: options.workflowRef,
659
+ activity_ref: options.activityRef,
660
+ });
642
661
  const output = await options.runner.runTaskCompile({
662
+ communication_language: language,
643
663
  workflow_ref: options.workflowRef,
644
664
  scratchpad: context.scratchpad_snapshot,
645
- source_messages: materializePromptSourceMessages(options.store.db, context.sources),
665
+ source_messages: sourceMessages,
646
666
  worklist: readWorklistProjection(options.store.db),
647
667
  ...(recentReferences.length === 0 ? {} : { recent_references: recentReferences }),
648
668
  }, {
@@ -650,6 +670,7 @@ export async function runControlPlaneTaskCompileProcedure(options) {
650
670
  activity_ref: options.activityRef,
651
671
  ...(options.reportProgress === undefined ? {} : { reportProgress: options.reportProgress }),
652
672
  });
673
+ logLanguageContext(options.logger, language, { workflow_ref: options.workflowRef, activity_ref: options.activityRef }, output.communication_language);
653
674
  return applyTaskCompileProcedureOutput({
654
675
  store: options.store,
655
676
  events: options.events,
@@ -3,6 +3,7 @@ import type { RuntimeLogger } from "@tutti/shared/utils";
3
3
  import type { ActivityRef, ClarificationRoundRef, TaskId, TaskModuleId } from "@tutti/shared/ids";
4
4
  import type { ActiveApprovalProjection, ClarificationRequestPayload, ExecutionRuntimeSnapshot, MessageProjection, RecoverySummaryProjection, TaskDetailProjection, TaskProjection } from "@tutti/shared/schemas/api";
5
5
  import type { HostProjectStore } from "../store/index.js";
6
+ import type { CommunicationLanguageContext } from "../communication-language/index.js";
6
7
  import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js";
7
8
  import type { RecentReferenceContext } from "./reference-context-types.js";
8
9
  import type { PromptSourceMessage, TaskCompileClarificationContext } from "./task-source-context-types.js";
@@ -114,6 +115,7 @@ export type RunCorrectionContext = {
114
115
  } | null;
115
116
  };
116
117
  export type RunPipelineInput = {
118
+ communication_language?: CommunicationLanguageContext;
117
119
  activity_ref: ActivityRef;
118
120
  task: TaskProjection;
119
121
  task_detail: TaskDetailProjection;