@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.
- package/README.md +2 -0
- package/dist/approvals/decision-command.d.ts +2 -2
- package/dist/chat-assistant/diagnostics.d.ts +11 -3
- package/dist/chat-assistant/diagnostics.js +5 -2
- package/dist/chat-assistant/failures.d.ts +27 -0
- package/dist/chat-assistant/failures.js +102 -0
- package/dist/chat-assistant/index.d.ts +14 -2
- package/dist/chat-assistant/index.js +241 -54
- package/dist/chat-assistant/language-context.d.ts +8 -0
- package/dist/chat-assistant/language-context.js +41 -0
- package/dist/chat-assistant/requests.d.ts +30 -0
- package/dist/chat-assistant/requests.js +58 -0
- package/dist/collaboration-ingestion/clarification.js +3 -1
- package/dist/collaboration-ingestion/main-chat.js +1 -0
- package/dist/collaboration-ingestion/types.d.ts +2 -0
- package/dist/collaboration-state/clarification-snapshot.d.ts +5 -5
- package/dist/collaboration-state/communication-language.d.ts +31 -0
- package/dist/collaboration-state/communication-language.js +36 -0
- package/dist/collaboration-state/task-compile-context.d.ts +1 -1
- package/dist/collaboration-state/task-compile-context.js +20 -1
- package/dist/collaboration-state/task-compile-requests.d.ts +6 -0
- package/dist/collaboration-state/task-compile-requests.js +16 -0
- package/dist/communication-language/index.d.ts +75 -0
- package/dist/communication-language/index.js +122 -0
- package/dist/communication-language/live-smoke-cli.d.ts +2 -0
- package/dist/communication-language/live-smoke-cli.js +368 -0
- package/dist/communication-language/prompt.d.ts +22 -0
- package/dist/communication-language/prompt.js +73 -0
- package/dist/control-plane/communication-language.d.ts +33 -0
- package/dist/control-plane/communication-language.js +72 -0
- package/dist/control-plane/context-sync.js +7 -0
- package/dist/control-plane/follow-up-output.js +25 -4
- package/dist/control-plane/follow-up-start.js +17 -0
- package/dist/control-plane/project-brief-refresh.js +10 -1
- package/dist/control-plane/project-context-bootstrap.d.ts +2 -0
- package/dist/control-plane/project-context-bootstrap.js +8 -0
- package/dist/control-plane/reference-summary-refresh.js +7 -0
- package/dist/control-plane/run-start.js +14 -6
- package/dist/control-plane/scratchpad-refresh-start.d.ts +1 -0
- package/dist/control-plane/scratchpad-refresh-start.js +13 -0
- package/dist/control-plane/scratchpad-refresh.d.ts +2 -0
- package/dist/control-plane/scratchpad-refresh.js +40 -26
- package/dist/control-plane/task-compile-continuation.js +16 -1
- package/dist/control-plane/task-compile-output.js +38 -14
- package/dist/control-plane/task-compile-request-status.d.ts +6 -0
- package/dist/control-plane/task-compile-request-status.js +70 -0
- package/dist/control-plane/task-compile-start.d.ts +1 -0
- package/dist/control-plane/task-compile-start.js +62 -3
- package/dist/control-plane/types.d.ts +2 -0
- package/dist/control-plane/workflows/openai.js +48 -28
- package/dist/control-plane/workflows/types.d.ts +18 -13
- package/dist/prompt-templates/index.d.ts +1 -1
- package/dist/prompt-templates/index.js +2 -0
- package/dist/providers/failure-classification.d.ts +23 -0
- package/dist/providers/failure-classification.js +43 -0
- package/dist/reference-access/read-evidence.d.ts +2 -0
- package/dist/reference-access/read-evidence.js +5 -0
- package/dist/reference-access/service.d.ts +2 -0
- package/dist/reference-access/service.js +2 -0
- package/dist/run-pipeline/task-run-invocation.js +12 -9
- package/dist/runtime-failures.js +15 -1
- package/dist/server-shell/cli/external-reference-runtime.js +6 -3
- package/dist/server-shell/cli/host-server-runtime.js +4 -1
- package/dist/server-shell/cli/relay-registration.js +1 -0
- package/dist/server-shell/http/routes/project-api/messages-routes.js +22 -1
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +140 -5
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.js +29 -2
- package/dist/server-shell/http/routes/project-api/openapi-skills-routes.d.ts +2 -0
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +6 -0
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +148 -5
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +6 -0
- package/dist/server-shell/http/routes/project-api/schemas.js +1 -0
- package/dist/server-shell/http/routes/project-api/types.d.ts +1 -0
- package/dist/server-shell/http/routes/project-api/workflow-routes.js +39 -3
- package/dist/server-shell/http/routes/project-api/workspace-projections.js +1 -0
- package/dist/server-shell/http/validation.js +8 -2
- package/dist/server-shell/local-console/managed-project-service.d.ts +1 -1
- package/dist/server-shell/managed-access/transport.d.ts +1 -1
- package/migrations/0023_communication_language.sql +14 -0
- package/migrations/0024_chat_requests.sql +19 -0
- package/migrations/0025_task_compile_requests.sql +50 -0
- package/migrations/README.md +3 -1
- package/node_modules/@tutti/relay-client/dist/host-control.d.ts +1 -0
- package/node_modules/@tutti/relay-client/dist/host-control.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/operation-status.d.ts +174 -0
- package/node_modules/@tutti/shared/dist/schemas/api/operation-status.js +75 -0
- package/node_modules/@tutti/shared/dist/schemas/api/primitives.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/primitives.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.js +2 -1
- package/package.json +1 -1
- package/prompts/README.md +1 -0
- package/prompts/chat-assistant.md +1 -1
- package/prompts/communication-language-result.md +27 -0
- package/prompts/communication-language.md +50 -0
- package/prompts/procedures/follow-up-check.md +1 -1
- package/prompts/procedures/scratchpad-refresh.md +2 -2
- package/prompts/procedures/task-compile.md +1 -1
- package/prompts/prompt-flow-map.md +2 -0
- package/web/assets/{homepage-motion-scene-DyEmWwvt.js → homepage-motion-scene-BcMt0AVW.js} +1 -1
- package/web/assets/index-2eX37Jx6.js +70 -0
- package/web/assets/index-BJvKuUiT.css +1 -0
- package/web/index.html +2 -2
- package/web/assets/index-By3idT4U.js +0 -70
- package/web/assets/index-DSBjOZmJ.css +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SqliteDatabase } from "../store/index.js";
|
|
2
|
+
import { type LanguageDecision, type LanguagePreference } from "../communication-language/index.js";
|
|
3
|
+
export type LanguageOwner = {
|
|
4
|
+
kind: "project" | "scratchpad" | "workflow" | "task";
|
|
5
|
+
ref: string;
|
|
6
|
+
};
|
|
7
|
+
export type StoredCommunicationLanguage = LanguagePreference & {
|
|
8
|
+
basis: LanguageDecision["basis"];
|
|
9
|
+
activity_ref: string | null;
|
|
10
|
+
source_message_id: string | null;
|
|
11
|
+
source_created_at: string | null;
|
|
12
|
+
};
|
|
13
|
+
export declare function readCommunicationLanguage(db: SqliteDatabase, owner?: LanguageOwner): StoredCommunicationLanguage | null;
|
|
14
|
+
export declare function writeCommunicationLanguage(db: SqliteDatabase, input: {
|
|
15
|
+
owner: LanguageOwner;
|
|
16
|
+
language: LanguagePreference & {
|
|
17
|
+
basis: LanguageDecision["basis"];
|
|
18
|
+
};
|
|
19
|
+
activityRef?: string;
|
|
20
|
+
sourceCursor?: {
|
|
21
|
+
message_id: string;
|
|
22
|
+
created_at: string;
|
|
23
|
+
};
|
|
24
|
+
now: () => Date;
|
|
25
|
+
}): void;
|
|
26
|
+
export declare function copyCommunicationLanguage(db: SqliteDatabase, input: {
|
|
27
|
+
from: LanguageOwner;
|
|
28
|
+
to: LanguageOwner;
|
|
29
|
+
now: () => Date;
|
|
30
|
+
}): void;
|
|
31
|
+
//# sourceMappingURL=communication-language.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { COMMUNICATION_LANGUAGE_POLICY_VERSION, isLanguagePreference, } from "../communication-language/index.js";
|
|
2
|
+
export function readCommunicationLanguage(db, owner = { kind: "project", ref: "current" }) {
|
|
3
|
+
const row = db
|
|
4
|
+
.prepare(`SELECT locale, preference, basis, activity_ref, source_message_id, source_created_at
|
|
5
|
+
FROM communication_language_state WHERE owner_kind = ? AND owner_ref = ?`)
|
|
6
|
+
.get(owner.kind, owner.ref);
|
|
7
|
+
if (row === undefined)
|
|
8
|
+
return null;
|
|
9
|
+
if (!isLanguagePreference(row))
|
|
10
|
+
throw new Error("communication_language_state_invalid");
|
|
11
|
+
return row;
|
|
12
|
+
}
|
|
13
|
+
export function writeCommunicationLanguage(db, input) {
|
|
14
|
+
if (!isLanguagePreference(input.language))
|
|
15
|
+
throw new Error("communication_language_state_invalid");
|
|
16
|
+
db.prepare(`INSERT INTO communication_language_state
|
|
17
|
+
(owner_kind, owner_ref, locale, preference, basis, policy_version, activity_ref,
|
|
18
|
+
source_message_id, source_created_at, updated_at)
|
|
19
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
20
|
+
ON CONFLICT(owner_kind, owner_ref) DO UPDATE SET
|
|
21
|
+
locale = excluded.locale, preference = excluded.preference, basis = excluded.basis,
|
|
22
|
+
policy_version = excluded.policy_version, activity_ref = excluded.activity_ref,
|
|
23
|
+
source_message_id = excluded.source_message_id, source_created_at = excluded.source_created_at,
|
|
24
|
+
updated_at = excluded.updated_at
|
|
25
|
+
WHERE excluded.owner_kind != 'project' OR
|
|
26
|
+
communication_language_state.source_created_at IS NULL OR
|
|
27
|
+
(excluded.source_created_at, excluded.source_message_id) >
|
|
28
|
+
(communication_language_state.source_created_at, communication_language_state.source_message_id)`).run(input.owner.kind, input.owner.ref, input.language.locale, input.language.preference, input.language.basis, COMMUNICATION_LANGUAGE_POLICY_VERSION, input.activityRef ?? null, input.sourceCursor?.message_id ?? null, input.sourceCursor?.created_at ?? null, input.now().toISOString());
|
|
29
|
+
}
|
|
30
|
+
export function copyCommunicationLanguage(db, input) {
|
|
31
|
+
const language = readCommunicationLanguage(db, input.from);
|
|
32
|
+
if (language === null)
|
|
33
|
+
return;
|
|
34
|
+
writeCommunicationLanguage(db, { owner: input.to, language, now: input.now });
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=communication-language.js.map
|
|
@@ -24,7 +24,7 @@ export declare function completeTaskCompileContext(db: SqliteDatabase, input: Co
|
|
|
24
24
|
task_changes: string[];
|
|
25
25
|
receipts: {
|
|
26
26
|
compiled_tasks?: {
|
|
27
|
-
status: "failed" | "pending" | "
|
|
27
|
+
status: "failed" | "pending" | "running" | "done" | "todo";
|
|
28
28
|
task_id: string;
|
|
29
29
|
title: string;
|
|
30
30
|
summary: string;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { withHostStoreTransaction } from "../store/index.js";
|
|
2
2
|
import { readScratchpadProjection } from "./scratchpad.js";
|
|
3
|
+
import { readCommunicationLanguage, copyCommunicationLanguage } from "./communication-language.js";
|
|
3
4
|
import { readScratchpadSourceState } from "./scratchpad-source-state.js";
|
|
4
5
|
import { nowIso, stringifyJson } from "./serialization.js";
|
|
6
|
+
import { registerTaskCompileRequest, closeFailedTaskCompileRequest, } from "./task-compile-requests.js";
|
|
5
7
|
function cursorIsAfter(left, right) {
|
|
6
8
|
if (left === undefined) {
|
|
7
9
|
return false;
|
|
@@ -144,6 +146,7 @@ export function recordTaskCompileSubmission(db, input) {
|
|
|
144
146
|
if (readActiveTaskCompileContext(db) !== null) {
|
|
145
147
|
throw new Error("An active Task Compile Context already exists");
|
|
146
148
|
}
|
|
149
|
+
registerTaskCompileRequest(db, input.workflow_ref, input.accepted_activity_ref, nowIso(input.now));
|
|
147
150
|
db.prepare(`
|
|
148
151
|
INSERT INTO pending_task_compile_submissions (
|
|
149
152
|
id,
|
|
@@ -206,6 +209,14 @@ export function captureTaskCompileContext(db, input) {
|
|
|
206
209
|
if (scratchpad.state !== "ready" || scratchpad.updated_at === undefined) {
|
|
207
210
|
throw new Error("A ready Scratchpad is required to capture Task Compile Context");
|
|
208
211
|
}
|
|
212
|
+
const language = readCommunicationLanguage(tx, { kind: "scratchpad", ref: "current" });
|
|
213
|
+
if (language !== null && language.activity_ref === scratchpad.updated_by_activity_ref) {
|
|
214
|
+
copyCommunicationLanguage(tx, {
|
|
215
|
+
from: { kind: "scratchpad", ref: "current" },
|
|
216
|
+
to: { kind: "workflow", ref: input.workflow_ref },
|
|
217
|
+
now: input.now ?? (() => new Date()),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
209
220
|
const sourceState = readScratchpadSourceState(tx);
|
|
210
221
|
const submission = readPendingTaskCompileSubmission(tx, input.workflow_ref);
|
|
211
222
|
const sources = readCurrentScratchpadSourceRefs(tx, submission?.source_window.through);
|
|
@@ -217,6 +228,7 @@ export function captureTaskCompileContext(db, input) {
|
|
|
217
228
|
: { created_at: lastSource.created_at, message_id: lastSource.message_id });
|
|
218
229
|
const after = submission?.source_window.after ?? sourceState.cycle_start_cursor;
|
|
219
230
|
const submittedAt = nowIso(input.now);
|
|
231
|
+
registerTaskCompileRequest(tx, input.workflow_ref, input.captured_by_activity_ref, submittedAt);
|
|
220
232
|
tx.prepare(`
|
|
221
233
|
INSERT INTO active_task_compile_context (
|
|
222
234
|
id,
|
|
@@ -328,9 +340,16 @@ export function rollbackTaskCompileContext(db, input) {
|
|
|
328
340
|
return withHostStoreTransaction(db, (tx) => {
|
|
329
341
|
const context = readActiveTaskCompileContext(tx, input.workflow_ref);
|
|
330
342
|
if (context === null) {
|
|
331
|
-
|
|
343
|
+
const pending = readPendingTaskCompileSubmission(tx, input.workflow_ref);
|
|
344
|
+
if (pending === null)
|
|
345
|
+
return false;
|
|
346
|
+
// Before capture the source cursor has not moved: release only this admission.
|
|
347
|
+
closeFailedTaskCompileRequest(tx, input.workflow_ref, nowIso(input.now));
|
|
348
|
+
tx.prepare("DELETE FROM pending_task_compile_submissions WHERE workflow_ref = ?").run(input.workflow_ref);
|
|
349
|
+
return true;
|
|
332
350
|
}
|
|
333
351
|
const rolledBackAt = nowIso(input.now);
|
|
352
|
+
closeFailedTaskCompileRequest(tx, input.workflow_ref, rolledBackAt);
|
|
334
353
|
const sourceState = readScratchpadSourceState(tx);
|
|
335
354
|
const after = context.source_window.after;
|
|
336
355
|
const through = context.source_window.through;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SqliteDatabase } from "../store/index.js";
|
|
2
|
+
/** Persistence only: callers own acceptance, stage selection and rollback. */
|
|
3
|
+
export declare function registerTaskCompileRequest(db: SqliteDatabase, workflowRef: string, activityRef: string, createdAt: string): void;
|
|
4
|
+
export declare function linkTaskCompileActivity(db: SqliteDatabase, workflowRef: string, activityRef: string): void;
|
|
5
|
+
export declare function closeFailedTaskCompileRequest(db: SqliteDatabase, workflowRef: string, now: string, code?: "task_compile_failed" | "scratchpad_empty_after_refresh"): void;
|
|
6
|
+
//# sourceMappingURL=task-compile-requests.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Persistence only: callers own acceptance, stage selection and rollback. */
|
|
2
|
+
export function registerTaskCompileRequest(db, workflowRef, activityRef, createdAt) {
|
|
3
|
+
db.prepare(`INSERT OR IGNORE INTO task_compile_requests
|
|
4
|
+
(workflow_ref, accepted_activity_ref, current_activity_ref, created_at)
|
|
5
|
+
VALUES (?, ?, ?, ?)`).run(workflowRef, activityRef, activityRef, createdAt);
|
|
6
|
+
}
|
|
7
|
+
export function linkTaskCompileActivity(db, workflowRef, activityRef) {
|
|
8
|
+
db.prepare(`UPDATE task_compile_requests SET current_activity_ref = ?
|
|
9
|
+
WHERE workflow_ref = ? AND closed_at IS NULL`).run(activityRef, workflowRef);
|
|
10
|
+
}
|
|
11
|
+
export function closeFailedTaskCompileRequest(db, workflowRef, now, code = "task_compile_failed") {
|
|
12
|
+
db.prepare(`UPDATE task_compile_requests SET failure_code = ?, closed_at = ?
|
|
13
|
+
WHERE workflow_ref = ? AND closed_at IS NULL
|
|
14
|
+
AND NOT EXISTS (SELECT 1 FROM scratchpad_receipts WHERE workflow_ref = ?)`).run(code, now, workflowRef, workflowRef);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=task-compile-requests.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { MessageProjection } from "@tutti/shared/schemas/api";
|
|
2
|
+
export declare const COMMUNICATION_LANGUAGE_POLICY_VERSION = 1;
|
|
3
|
+
export type LanguagePreference = {
|
|
4
|
+
locale: string;
|
|
5
|
+
preference: "auto" | "fixed";
|
|
6
|
+
};
|
|
7
|
+
export type LanguageDecision = LanguagePreference & {
|
|
8
|
+
basis: "discussion" | "explicit" | "inherited" | "default";
|
|
9
|
+
evidence_index: number | null;
|
|
10
|
+
};
|
|
11
|
+
export type LanguageEvidenceMessage = {
|
|
12
|
+
role: "human" | "tutti" | "operator" | "system";
|
|
13
|
+
text: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function messageLanguageEvidence(message: MessageProjection): LanguageEvidenceMessage;
|
|
16
|
+
export type CommunicationLanguageContext = {
|
|
17
|
+
policy_version: 1;
|
|
18
|
+
scope: "scratchpad" | "reply" | "workflow" | "summary" | "documents";
|
|
19
|
+
inherited: LanguagePreference | null;
|
|
20
|
+
pinned: boolean;
|
|
21
|
+
evidence: Array<{
|
|
22
|
+
role: "human" | "operator";
|
|
23
|
+
text: string;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
export declare function isLanguagePreference(value: unknown): value is LanguagePreference;
|
|
27
|
+
export declare function isLanguageDecision(value: unknown): value is LanguageDecision;
|
|
28
|
+
/** A language sample, not task context. The original message is never rewritten. */
|
|
29
|
+
export declare function authoredLanguageSample(text: string): string;
|
|
30
|
+
export declare function createLanguageContext(input: {
|
|
31
|
+
scope: CommunicationLanguageContext["scope"];
|
|
32
|
+
inherited?: LanguagePreference | null;
|
|
33
|
+
pinned?: boolean;
|
|
34
|
+
messages?: readonly LanguageEvidenceMessage[];
|
|
35
|
+
}): CommunicationLanguageContext;
|
|
36
|
+
export declare function languageDecisionMatchesContext(decision: unknown, context: CommunicationLanguageContext): decision is LanguageDecision;
|
|
37
|
+
export declare function languageDiagnosticFields(context: CommunicationLanguageContext): {
|
|
38
|
+
language_policy_version: 1;
|
|
39
|
+
language_scope: "scratchpad" | "summary" | "workflow" | "reply" | "documents";
|
|
40
|
+
language_locale: string;
|
|
41
|
+
language_pinned: boolean;
|
|
42
|
+
language_evidence_count: number;
|
|
43
|
+
};
|
|
44
|
+
export type LanguageAwareOutput = {
|
|
45
|
+
communication_language?: LanguageDecision;
|
|
46
|
+
};
|
|
47
|
+
export declare const LANGUAGE_DECISION_SCHEMA: {
|
|
48
|
+
readonly type: "object";
|
|
49
|
+
readonly additionalProperties: false;
|
|
50
|
+
readonly required: readonly ["locale", "preference", "basis", "evidence_index"];
|
|
51
|
+
readonly properties: {
|
|
52
|
+
readonly locale: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
readonly pattern: string;
|
|
55
|
+
};
|
|
56
|
+
readonly preference: {
|
|
57
|
+
readonly type: "string";
|
|
58
|
+
readonly enum: readonly ["auto", "fixed"];
|
|
59
|
+
};
|
|
60
|
+
readonly basis: {
|
|
61
|
+
readonly type: "string";
|
|
62
|
+
readonly enum: readonly ["discussion", "explicit", "inherited", "default"];
|
|
63
|
+
};
|
|
64
|
+
readonly evidence_index: {
|
|
65
|
+
readonly anyOf: readonly [{
|
|
66
|
+
readonly type: "integer";
|
|
67
|
+
readonly minimum: 0;
|
|
68
|
+
readonly maximum: 11;
|
|
69
|
+
}, {
|
|
70
|
+
readonly type: "null";
|
|
71
|
+
}];
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export const COMMUNICATION_LANGUAGE_POLICY_VERSION = 1;
|
|
2
|
+
export function messageLanguageEvidence(message) {
|
|
3
|
+
const feedback = message.refs?.artifact_feedback;
|
|
4
|
+
return {
|
|
5
|
+
role: message.author.kind === "human"
|
|
6
|
+
? "human"
|
|
7
|
+
: message.refs?.development_operator === true
|
|
8
|
+
? "operator"
|
|
9
|
+
: "system",
|
|
10
|
+
text: message.refs?.reference_file !== undefined
|
|
11
|
+
? ""
|
|
12
|
+
: feedback === undefined
|
|
13
|
+
? message.body
|
|
14
|
+
: [feedback.summary, ...feedback.annotations.map((entry) => entry.comment)]
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.join("\n"),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const BASES = new Set(["discussion", "explicit", "inherited", "default"]);
|
|
20
|
+
const LOCALE_PATTERN = /^[a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-[A-Z]{2}|-\d{3})?$/u;
|
|
21
|
+
export function isLanguagePreference(value) {
|
|
22
|
+
if (typeof value !== "object" || value === null)
|
|
23
|
+
return false;
|
|
24
|
+
const entry = value;
|
|
25
|
+
if (entry.preference !== "auto" && entry.preference !== "fixed")
|
|
26
|
+
return false;
|
|
27
|
+
if (typeof entry.locale !== "string" || !LOCALE_PATTERN.test(entry.locale))
|
|
28
|
+
return false;
|
|
29
|
+
try {
|
|
30
|
+
return Intl.getCanonicalLocales(entry.locale)[0] === entry.locale && entry.locale !== "und";
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function isLanguageDecision(value) {
|
|
37
|
+
if (!isLanguagePreference(value))
|
|
38
|
+
return false;
|
|
39
|
+
const entry = value;
|
|
40
|
+
return (BASES.has(entry.basis ?? "") &&
|
|
41
|
+
(entry.evidence_index === null ||
|
|
42
|
+
(Number.isSafeInteger(entry.evidence_index) && (entry.evidence_index ?? -1) >= 0)) &&
|
|
43
|
+
Object.keys(value).every((key) => ["locale", "preference", "basis", "evidence_index"].includes(key)));
|
|
44
|
+
}
|
|
45
|
+
/** A language sample, not task context. The original message is never rewritten. */
|
|
46
|
+
export function authoredLanguageSample(text) {
|
|
47
|
+
const sample = text
|
|
48
|
+
.replace(/```[^]*?```|~~~[^]*?~~~/gu, " ")
|
|
49
|
+
.replace(/^(?: {0,3}>| {4}|\t).*$/gmu, " ")
|
|
50
|
+
.replace(/`[^`]*`/gu, " ")
|
|
51
|
+
.replace(/!\[[^\]]*\]\([^)]*\)/gu, " ")
|
|
52
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/gu, "$1")
|
|
53
|
+
.replace(/https?:\/\/\S+|@tutti\b/giu, " ")
|
|
54
|
+
.replace(/\s+/gu, " ")
|
|
55
|
+
.trim();
|
|
56
|
+
return sample.length <= 800 ? sample : `${sample.slice(0, 398)} … ${sample.slice(-399)}`;
|
|
57
|
+
}
|
|
58
|
+
export function createLanguageContext(input) {
|
|
59
|
+
const evidence = (input.messages ?? []).flatMap((message) => {
|
|
60
|
+
if (message.role !== "human" && message.role !== "operator")
|
|
61
|
+
return [];
|
|
62
|
+
const text = authoredLanguageSample(message.text);
|
|
63
|
+
return /\p{L}/u.test(text) ? [{ role: message.role, text }] : [];
|
|
64
|
+
});
|
|
65
|
+
// Prefer humans. Operator-only tests can infer locally but cannot update project memory.
|
|
66
|
+
const selected = input.scope !== "reply" && evidence.some((entry) => entry.role === "human")
|
|
67
|
+
? evidence.filter((entry) => entry.role === "human")
|
|
68
|
+
: evidence;
|
|
69
|
+
return {
|
|
70
|
+
policy_version: COMMUNICATION_LANGUAGE_POLICY_VERSION,
|
|
71
|
+
scope: input.scope,
|
|
72
|
+
inherited: input.inherited == null
|
|
73
|
+
? null
|
|
74
|
+
: { locale: input.inherited.locale, preference: input.inherited.preference },
|
|
75
|
+
pinned: input.pinned ?? false,
|
|
76
|
+
evidence: selected.slice(-12),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function languageDecisionMatchesContext(decision, context) {
|
|
80
|
+
if (!isLanguageDecision(decision))
|
|
81
|
+
return false;
|
|
82
|
+
if (decision.basis === "inherited") {
|
|
83
|
+
return (decision.evidence_index === null &&
|
|
84
|
+
decision.locale === context.inherited?.locale &&
|
|
85
|
+
decision.preference === context.inherited.preference);
|
|
86
|
+
}
|
|
87
|
+
if (decision.basis === "default") {
|
|
88
|
+
return (decision.evidence_index === null &&
|
|
89
|
+
context.inherited === null &&
|
|
90
|
+
decision.locale === "en" &&
|
|
91
|
+
decision.preference === "auto");
|
|
92
|
+
}
|
|
93
|
+
if (decision.evidence_index === null || !context.evidence[decision.evidence_index])
|
|
94
|
+
return false;
|
|
95
|
+
if (context.scope === "summary" || context.scope === "documents")
|
|
96
|
+
return false;
|
|
97
|
+
if (decision.basis === "discussion") {
|
|
98
|
+
return (!context.pinned && context.inherited?.preference !== "fixed" && decision.preference === "auto");
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
export function languageDiagnosticFields(context) {
|
|
103
|
+
return {
|
|
104
|
+
language_policy_version: context.policy_version,
|
|
105
|
+
language_scope: context.scope,
|
|
106
|
+
language_locale: context.inherited?.locale ?? "undetermined",
|
|
107
|
+
language_pinned: context.pinned,
|
|
108
|
+
language_evidence_count: context.evidence.length,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export const LANGUAGE_DECISION_SCHEMA = {
|
|
112
|
+
type: "object",
|
|
113
|
+
additionalProperties: false,
|
|
114
|
+
required: ["locale", "preference", "basis", "evidence_index"],
|
|
115
|
+
properties: {
|
|
116
|
+
locale: { type: "string", pattern: LOCALE_PATTERN.source },
|
|
117
|
+
preference: { type: "string", enum: ["auto", "fixed"] },
|
|
118
|
+
basis: { type: "string", enum: ["discussion", "explicit", "inherited", "default"] },
|
|
119
|
+
evidence_index: { anyOf: [{ type: "integer", minimum: 0, maximum: 11 }, { type: "null" }] },
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=index.js.map
|