@sema-agent/server 1.310.0 → 1.311.0
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/dist/capabilities/center-prompts.d.ts +3 -28
- package/dist/capabilities/center-prompts.js +2 -107
- package/dist/config-lkg.js +1 -1
- package/dist/main.js +134 -143
- package/dist/plugins/pg-approval-store.js +1 -27
- package/dist/plugins/pg-checkpoint-store.js +1 -5
- package/dist/plugins/pg-image-bake.js +2 -54
- package/dist/plugins/pg-image-index.js +1 -44
- package/dist/plugins/pg-run-store.js +1 -15
- package/dist/plugins/pg-session-storage.js +1 -5
- package/dist/plugins/sql-row-helpers.d.ts +7 -0
- package/dist/plugins/sql-row-helpers.js +43 -0
- package/dist/plugins/tidb-approval-store.d.ts +1 -0
- package/dist/plugins/tidb-approval-store.js +2 -11
- package/dist/plugins/tidb-checkpoint-store.js +1 -5
- package/dist/plugins/tidb-image-bake.d.ts +31 -0
- package/dist/plugins/tidb-image-bake.js +3 -22
- package/dist/plugins/tidb-image-index.d.ts +24 -0
- package/dist/plugins/tidb-image-index.js +2 -19
- package/dist/plugins/tidb-run-store.js +1 -15
- package/dist/plugins/tidb-session-storage.js +1 -5
- package/dist/prompts-domain-validate.d.ts +29 -0
- package/dist/prompts-domain-validate.js +109 -0
- package/package.json +1 -1
|
@@ -1,31 +1,6 @@
|
|
|
1
|
-
import { type PromptProvider, type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
contentDigest: string;
|
|
5
|
-
sections: PromptTextDeclaration[];
|
|
6
|
-
scenarioOverrides?: Record<string, PromptTextDeclaration[]>;
|
|
7
|
-
}
|
|
8
|
-
export declare function validateCenterPrompts(raw: unknown): {
|
|
9
|
-
ok: true;
|
|
10
|
-
value: EffectiveCenterPrompts;
|
|
11
|
-
} | {
|
|
12
|
-
ok: false;
|
|
13
|
-
error: string;
|
|
14
|
-
};
|
|
15
|
-
export declare const CORE_ENGINE_VERSION: string;
|
|
16
|
-
export interface PromptsDomainFaces {
|
|
17
|
-
declarations?: EffectiveCenterPrompts;
|
|
18
|
-
catalog?: PublishedPromptArtifactEnvelope;
|
|
19
|
-
identity: string;
|
|
20
|
-
axes: Array<"declarations" | "catalog">;
|
|
21
|
-
}
|
|
22
|
-
export declare function validatePromptsDomain(raw: unknown): {
|
|
23
|
-
ok: true;
|
|
24
|
-
value: PromptsDomainFaces;
|
|
25
|
-
} | {
|
|
26
|
-
ok: false;
|
|
27
|
-
error: string;
|
|
28
|
-
};
|
|
1
|
+
import { type PromptProvider, type PublishedPromptArtifactEnvelope } from "@sema-agent/core";
|
|
2
|
+
import { type EffectiveCenterPrompts, type PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
3
|
+
export { validateCenterPrompts, validatePromptsDomain, CORE_ENGINE_VERSION, type EffectiveCenterPrompts, type PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
29
4
|
export declare function withPromptArtifactBackfill(inner: {
|
|
30
5
|
get(d: string, o: {
|
|
31
6
|
engineVersion: string;
|
|
@@ -1,111 +1,6 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
1
|
import { verifyPromptArtifact } from "@sema-agent/core";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const HASH_RE = /^sha256:[0-9a-f]{64}$/;
|
|
9
|
-
function declarationIssue(d, where) {
|
|
10
|
-
if (d === null || typeof d !== "object")
|
|
11
|
-
return `${where}: declaration is not an object`;
|
|
12
|
-
const o = d;
|
|
13
|
-
if (typeof o.id !== "string" || o.id.length === 0 || o.id.length > 128 || !ID_RE.test(o.id))
|
|
14
|
-
return `${where}: bad id`;
|
|
15
|
-
if (o.id.startsWith("core/"))
|
|
16
|
-
return `${where}: id in the reserved core/ namespace`;
|
|
17
|
-
if (typeof o.slot !== "string" || !SLOTS.has(o.slot))
|
|
18
|
-
return `${where}: bad slot`;
|
|
19
|
-
if (typeof o.text !== "string" || o.text.length === 0)
|
|
20
|
-
return `${where}: text must be a non-empty string`;
|
|
21
|
-
if (typeof o.contentHash !== "string" || !HASH_RE.test(o.contentHash))
|
|
22
|
-
return `${where}: contentHash is required (sha256:<64hex> — the epoch declaration axis needs it for byte-level change detection)`;
|
|
23
|
-
const expected = `sha256:${createHash("sha256").update(o.text).digest("hex")}`;
|
|
24
|
-
if (o.contentHash !== expected)
|
|
25
|
-
return `${where}: contentHash does not match sha256(text) — stale or tampered declaration`;
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
export function validateCenterPrompts(raw) {
|
|
29
|
-
if (raw === null || typeof raw !== "object")
|
|
30
|
-
return { ok: false, error: "prompts is not an object" };
|
|
31
|
-
const p = raw;
|
|
32
|
-
if (typeof p.packId !== "string" || !/^center:[0-9a-f]{12}$/.test(p.packId))
|
|
33
|
-
return { ok: false, error: "bad packId form (center:<digest12>)" };
|
|
34
|
-
if (typeof p.contentDigest !== "string" || !HASH_RE.test(p.contentDigest))
|
|
35
|
-
return { ok: false, error: "bad contentDigest form" };
|
|
36
|
-
const arrayIssue = (decls, where) => {
|
|
37
|
-
if (!Array.isArray(decls))
|
|
38
|
-
return `${where} is not an array`;
|
|
39
|
-
if (decls.length === 0)
|
|
40
|
-
return `${where} is empty (an empty replacement set is not a v1 semantic — omit the key instead)`;
|
|
41
|
-
const seen = new Set();
|
|
42
|
-
for (let i = 0; i < decls.length; i++) {
|
|
43
|
-
const issue = declarationIssue(decls[i], `${where}[${i}]`);
|
|
44
|
-
if (issue)
|
|
45
|
-
return issue;
|
|
46
|
-
const id = decls[i].id;
|
|
47
|
-
if (seen.has(id))
|
|
48
|
-
return `${where}[${i}]: duplicate id "${id}" (core composer throws on duplicates)`;
|
|
49
|
-
seen.add(id);
|
|
50
|
-
}
|
|
51
|
-
return undefined;
|
|
52
|
-
};
|
|
53
|
-
const sectionsIssue = arrayIssue(p.sections, "sections");
|
|
54
|
-
if (sectionsIssue)
|
|
55
|
-
return { ok: false, error: sectionsIssue };
|
|
56
|
-
if (p.scenarioOverrides !== undefined) {
|
|
57
|
-
if (p.scenarioOverrides === null || typeof p.scenarioOverrides !== "object" || Array.isArray(p.scenarioOverrides)) {
|
|
58
|
-
return { ok: false, error: "scenarioOverrides is not an object" };
|
|
59
|
-
}
|
|
60
|
-
for (const [name, decls] of Object.entries(p.scenarioOverrides)) {
|
|
61
|
-
const issue = arrayIssue(decls, `scenarioOverrides[${name}]`);
|
|
62
|
-
if (issue)
|
|
63
|
-
return { ok: false, error: issue };
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return { ok: true, value: raw };
|
|
67
|
-
}
|
|
68
|
-
export const CORE_ENGINE_VERSION = (() => {
|
|
69
|
-
try {
|
|
70
|
-
const entry = createRequire(import.meta.url).resolve("@sema-agent/core");
|
|
71
|
-
return JSON.parse(readFileSync(join(dirname(entry), "..", "package.json"), "utf8")).version ?? "0.0.0";
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return "0.0.0";
|
|
75
|
-
}
|
|
76
|
-
})();
|
|
77
|
-
export function validatePromptsDomain(raw) {
|
|
78
|
-
if (raw === null || typeof raw !== "object")
|
|
79
|
-
return { ok: false, error: "prompts is not an object" };
|
|
80
|
-
const w = raw;
|
|
81
|
-
if (w.schemaVersion === undefined) {
|
|
82
|
-
const legacy = validateCenterPrompts(raw);
|
|
83
|
-
if (!legacy.ok)
|
|
84
|
-
return legacy;
|
|
85
|
-
return { ok: true, value: { declarations: legacy.value, identity: `${legacy.value.contentDigest}+-`, axes: ["declarations"] } };
|
|
86
|
-
}
|
|
87
|
-
if (w.schemaVersion !== 1)
|
|
88
|
-
return { ok: false, error: `unsupported prompts schemaVersion ${String(w.schemaVersion)}` };
|
|
89
|
-
if (w.declarations === undefined && w.catalog === undefined)
|
|
90
|
-
return { ok: false, error: "dual-axis prompts carries neither axis (at least one of declarations|catalog required)" };
|
|
91
|
-
const value = { identity: "", axes: [] };
|
|
92
|
-
if (w.declarations !== undefined) {
|
|
93
|
-
const d = validateCenterPrompts(w.declarations);
|
|
94
|
-
if (!d.ok)
|
|
95
|
-
return { ok: false, error: `declarations axis: ${d.error}` };
|
|
96
|
-
value.declarations = d.value;
|
|
97
|
-
value.axes.push("declarations");
|
|
98
|
-
}
|
|
99
|
-
if (w.catalog !== undefined) {
|
|
100
|
-
const c = verifyPromptArtifact(w.catalog, { engineVersion: CORE_ENGINE_VERSION });
|
|
101
|
-
if (!c.ok)
|
|
102
|
-
return { ok: false, error: `catalog axis: ${c.code}: ${c.reason}` };
|
|
103
|
-
value.catalog = w.catalog;
|
|
104
|
-
value.axes.push("catalog");
|
|
105
|
-
}
|
|
106
|
-
value.identity = `${value.declarations?.contentDigest ?? "-"}+${value.catalog?.artifact.artifactDigest ?? "-"}`;
|
|
107
|
-
return { ok: true, value };
|
|
108
|
-
}
|
|
2
|
+
import { CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
3
|
+
export { validateCenterPrompts, validatePromptsDomain, CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
109
4
|
export function withPromptArtifactBackfill(inner, fetchRaw, log) {
|
|
110
5
|
const inFlight = new Map();
|
|
111
6
|
return {
|
package/dist/config-lkg.js
CHANGED
|
@@ -2,7 +2,7 @@ import { promises as fs } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, dirname } from "node:path";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
|
-
import { validatePromptsDomain } from "./
|
|
5
|
+
import { validatePromptsDomain } from "./prompts-domain-validate.js";
|
|
6
6
|
export function defaultSkillCacheDir() {
|
|
7
7
|
return join(process.env.SEMA_CONFIG_DIR ?? join(homedir(), ".sema"), "skill-cache");
|
|
8
8
|
}
|
package/dist/main.js
CHANGED
|
@@ -988,31 +988,80 @@ async function main() {
|
|
|
988
988
|
requirePrincipal: config.requirePrincipal,
|
|
989
989
|
warn: (msg, fields) => logger.warn(msg, fields),
|
|
990
990
|
});
|
|
991
|
+
const workflowModelAllowlist = workflowModelAllowlistFor(config);
|
|
992
|
+
const selfOrchestrationDeps = config.selfOrchestrationEnabled
|
|
993
|
+
? {
|
|
994
|
+
workflowScriptRunner: config.selfOrchestrationWorkerIsolation
|
|
995
|
+
? createWorkerHardenedVmRunner()
|
|
996
|
+
: createHardenedVmRunner(),
|
|
997
|
+
workflowRunStore: workflowRunStore ? workflowRunStore : undefined,
|
|
998
|
+
workflowJournalStore: workflowJournalStore ? workflowJournalStore : undefined,
|
|
999
|
+
workflowScriptStore: (() => {
|
|
1000
|
+
const fileStore = createFileWorkflowScriptStore(join(config.localDataRoot ?? localRoot, "workflow-scripts"));
|
|
1001
|
+
return {
|
|
1002
|
+
scopePartitioned: true,
|
|
1003
|
+
persist: fileStore.persist.bind(fileStore),
|
|
1004
|
+
load: fileStore.load.bind(fileStore),
|
|
1005
|
+
resolveName: (name) => resolveCollabWorkflow(name) ?? fileStore.resolveName?.(name),
|
|
1006
|
+
list: () => listCollabWorkflows(),
|
|
1007
|
+
};
|
|
1008
|
+
})(),
|
|
1009
|
+
onWorkflowAgentSpawn: workflowAgentRegistry
|
|
1010
|
+
? (handle) => {
|
|
1011
|
+
const unregister = workflowAgentRegistry.register(handle);
|
|
1012
|
+
void Promise.resolve(handle.result()).then(unregister, unregister);
|
|
1013
|
+
}
|
|
1014
|
+
: undefined,
|
|
1015
|
+
workflowLimits: config.workflowSizeGuideline ? { sizeGuideline: config.workflowSizeGuideline } : undefined,
|
|
1016
|
+
workflowGovernanceBaseline: {
|
|
1017
|
+
base: config.workflowAgentsReadOnly ? { handsReadOnly: true } : {},
|
|
1018
|
+
worktreeBase: config.workflowAgentsReadOnly ? { handsReadOnly: false } : undefined,
|
|
1019
|
+
workflowModelAllowlist: workflowModelAllowlist ? workflowModelAllowlist : undefined,
|
|
1020
|
+
},
|
|
1021
|
+
workflowCompletionNotifier: {
|
|
1022
|
+
...(workflowNotifyGate
|
|
1023
|
+
? workflowNotifyGate.buildNotifier()
|
|
1024
|
+
: { notify: (input) => deliverWorkflowCompletion(input) }),
|
|
1025
|
+
ackServed: async (input) => {
|
|
1026
|
+
if (!workflowCompletionInbox)
|
|
1027
|
+
return;
|
|
1028
|
+
try {
|
|
1029
|
+
const sid = await resolveServedSession(input, runStore ? (id) => runStore.getRun(id) : undefined);
|
|
1030
|
+
if (sid) {
|
|
1031
|
+
await workflowCompletionInbox.markTerminalServed(sid, input.runId);
|
|
1032
|
+
logger.info("workflow_complete_ack_served", { route: "poll-served", sessionId: sid, runId: input.runId });
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
catch (err) {
|
|
1036
|
+
logger.warn("workflow_ack_served_failed", { runId: input.runId, err: String(err) });
|
|
1037
|
+
}
|
|
1038
|
+
},
|
|
1039
|
+
},
|
|
1040
|
+
}
|
|
1041
|
+
: {};
|
|
991
1042
|
const runnerDeps = {
|
|
992
1043
|
promptSource,
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1044
|
+
rosterStore: rosterStore ? rosterStore : undefined,
|
|
1045
|
+
backgroundAgentStore: backgroundAgentStore ? backgroundAgentStore : undefined,
|
|
1046
|
+
mailboxStore: mailboxStore ? mailboxStore : undefined,
|
|
996
1047
|
brain,
|
|
997
1048
|
models: config.models,
|
|
998
1049
|
roles: config.roles,
|
|
999
1050
|
tiers: config.tiers,
|
|
1000
1051
|
pricing,
|
|
1001
1052
|
tracer,
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
? {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
? { onAsk: (req, signal) => toolApproval.ask(req, signal) }
|
|
1015
|
-
: {}),
|
|
1053
|
+
hands: config.configProvider === "local" ? { commitCoAuthor: "Sema <noreply@vivi-ai.com>" } : undefined,
|
|
1054
|
+
onTaskOutcome: outcomeSink
|
|
1055
|
+
? (o) => {
|
|
1056
|
+
metrics.inc("task_outcomes_total", { status: o.status, green: String(o.oracle?.green ?? "unknown") });
|
|
1057
|
+
void outcomeSink.recordCore(o).catch((err) => logger.warn("task_outcome_record_failed", { runId: o.runId, err: String(err) }));
|
|
1058
|
+
}
|
|
1059
|
+
: undefined,
|
|
1060
|
+
onElicit: elicitation ? elicitation.elicit : undefined,
|
|
1061
|
+
onQuestion: question ? question.question : undefined,
|
|
1062
|
+
onAsk: toolApproval
|
|
1063
|
+
? (req, signal) => toolApproval.ask(req, signal)
|
|
1064
|
+
: undefined,
|
|
1016
1065
|
autoMode: {
|
|
1017
1066
|
onBreakerOpen: (info) => {
|
|
1018
1067
|
metrics.inc("auto_mode_breaker_open_total");
|
|
@@ -1020,84 +1069,32 @@ async function main() {
|
|
|
1020
1069
|
},
|
|
1021
1070
|
},
|
|
1022
1071
|
sessionStore,
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
: {}),
|
|
1072
|
+
memoryBackend: memoryEngine ? memoryEngine.backend : undefined,
|
|
1073
|
+
memoryEngineDir: memoryEngine ? memoryEngine.root : undefined,
|
|
1074
|
+
onMemoryHarvestReport: memoryEngine
|
|
1075
|
+
? (report, info) => {
|
|
1076
|
+
metrics.inc("memory_harvest_total", { ok: String(report.ok), phase: info.phase, incident: report.incident?.kind ?? "none" });
|
|
1077
|
+
if (report.patches)
|
|
1078
|
+
metrics.inc("memory_harvest_patches_total", { phase: info.phase }, (report.patches.add ?? 0) + (report.patches.update ?? 0));
|
|
1079
|
+
if (report.incident)
|
|
1080
|
+
logger.warn("memory_harvest_incident", { kind: report.incident.kind, phase: info.phase });
|
|
1081
|
+
if (memorySyncRunner && report.ok && (report.patches?.add ?? 0) + (report.patches?.update ?? 0) > 0)
|
|
1082
|
+
memorySyncRunner.trigger("harvest");
|
|
1083
|
+
}
|
|
1084
|
+
: undefined,
|
|
1037
1085
|
toolResultStore,
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1086
|
+
sessionPolicyStore: sessionPolicyStore ? sessionPolicyStore : undefined,
|
|
1087
|
+
runtimeCapsResolver: runtimeCapsResolver ? runtimeCapsResolver : undefined,
|
|
1088
|
+
fileSnapshotStore: fileSnapshotStore ? fileSnapshotStore : undefined,
|
|
1089
|
+
executionEnvFactory: executionEnvFactory ? executionEnvFactory : undefined,
|
|
1090
|
+
lspManager: lspManager ? lspManager : undefined,
|
|
1043
1091
|
onBackgroundChildEvent: fleetBackgroundChildPublisher(fleetBus, (msg, fields) => logger.info(msg, fields)),
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
?
|
|
1047
|
-
:
|
|
1092
|
+
loadProjectMemory: config.requirePrincipal !== true && !config.projectMemoryDisabled ? makeLoadProjectMemory({ logger }) : undefined,
|
|
1093
|
+
probeInstructionSources: config.remoteExec?.provider === "host" && config.requirePrincipal !== true && !config.projectMemoryDisabled
|
|
1094
|
+
? makeProbeInstructionSources()
|
|
1095
|
+
: undefined,
|
|
1048
1096
|
hooks: deploymentHooks,
|
|
1049
|
-
...
|
|
1050
|
-
? {
|
|
1051
|
-
workflowScriptRunner: config.selfOrchestrationWorkerIsolation
|
|
1052
|
-
? createWorkerHardenedVmRunner()
|
|
1053
|
-
: createHardenedVmRunner(),
|
|
1054
|
-
...(workflowRunStore ? { workflowRunStore } : {}),
|
|
1055
|
-
...(workflowJournalStore ? { workflowJournalStore } : {}),
|
|
1056
|
-
workflowScriptStore: (() => {
|
|
1057
|
-
const fileStore = createFileWorkflowScriptStore(join(config.localDataRoot ?? localRoot, "workflow-scripts"));
|
|
1058
|
-
return {
|
|
1059
|
-
scopePartitioned: true,
|
|
1060
|
-
persist: fileStore.persist.bind(fileStore),
|
|
1061
|
-
load: fileStore.load.bind(fileStore),
|
|
1062
|
-
resolveName: (name) => resolveCollabWorkflow(name) ?? fileStore.resolveName?.(name),
|
|
1063
|
-
list: () => listCollabWorkflows(),
|
|
1064
|
-
};
|
|
1065
|
-
})(),
|
|
1066
|
-
...(workflowAgentRegistry
|
|
1067
|
-
? {
|
|
1068
|
-
onWorkflowAgentSpawn: (handle) => {
|
|
1069
|
-
const unregister = workflowAgentRegistry.register(handle);
|
|
1070
|
-
void Promise.resolve(handle.result()).then(unregister, unregister);
|
|
1071
|
-
},
|
|
1072
|
-
}
|
|
1073
|
-
: {}),
|
|
1074
|
-
...(config.workflowSizeGuideline ? { workflowLimits: { sizeGuideline: config.workflowSizeGuideline } } : {}),
|
|
1075
|
-
workflowGovernanceBaseline: {
|
|
1076
|
-
base: config.workflowAgentsReadOnly ? { handsReadOnly: true } : {},
|
|
1077
|
-
...(config.workflowAgentsReadOnly ? { worktreeBase: { handsReadOnly: false } } : {}),
|
|
1078
|
-
...((wl) => (wl ? { workflowModelAllowlist: wl } : {}))(workflowModelAllowlistFor(config)),
|
|
1079
|
-
},
|
|
1080
|
-
workflowCompletionNotifier: {
|
|
1081
|
-
...(workflowNotifyGate
|
|
1082
|
-
? workflowNotifyGate.buildNotifier()
|
|
1083
|
-
: { notify: (input) => deliverWorkflowCompletion(input) }),
|
|
1084
|
-
ackServed: async (input) => {
|
|
1085
|
-
if (!workflowCompletionInbox)
|
|
1086
|
-
return;
|
|
1087
|
-
try {
|
|
1088
|
-
const sid = await resolveServedSession(input, runStore ? (id) => runStore.getRun(id) : undefined);
|
|
1089
|
-
if (sid) {
|
|
1090
|
-
await workflowCompletionInbox.markTerminalServed(sid, input.runId);
|
|
1091
|
-
logger.info("workflow_complete_ack_served", { route: "poll-served", sessionId: sid, runId: input.runId });
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
catch (err) {
|
|
1095
|
-
logger.warn("workflow_ack_served_failed", { runId: input.runId, err: String(err) });
|
|
1096
|
-
}
|
|
1097
|
-
},
|
|
1098
|
-
},
|
|
1099
|
-
}
|
|
1100
|
-
: {}),
|
|
1097
|
+
...selfOrchestrationDeps,
|
|
1101
1098
|
onError: (err, ctx) => {
|
|
1102
1099
|
if (ctx.phase === "degraded") {
|
|
1103
1100
|
logger.warn("task_degraded", { sessionId: ctx.sessionId, info: String(err) });
|
|
@@ -1335,20 +1332,18 @@ async function main() {
|
|
|
1335
1332
|
};
|
|
1336
1333
|
const scenarioDeps = {
|
|
1337
1334
|
runner, subRunner, model: "default", skills, repoClient, requirePrincipal: config.requirePrincipal,
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1335
|
+
webSearch: webSearch ? webSearch : undefined, metrics, logger, webFetchSummarize,
|
|
1336
|
+
backgroundAgentStore: backgroundAgentStore ? backgroundAgentStore : undefined,
|
|
1337
|
+
checkpointStore: checkpointStore ? checkpointStore : undefined,
|
|
1338
|
+
ensureChildSessionDurable: ensureChildSessionDurable ? ensureChildSessionDurable : undefined,
|
|
1342
1339
|
oaApiBaseUrl: config.oaApiBaseUrl, oaServiceToken: config.oaServiceToken, oaIssue: config.oaIssue,
|
|
1343
1340
|
brandIdentity: config.configProvider === "local",
|
|
1344
|
-
|
|
1345
|
-
? {
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
}
|
|
1351
|
-
: {}),
|
|
1341
|
+
subagentExtraTools: sendUserFileToolSpec
|
|
1342
|
+
? subagentSendUserFileExtraTools({
|
|
1343
|
+
spec: sendUserFileToolSpec,
|
|
1344
|
+
approvalGate: () => ({ deny: config.approvalDeny, require: config.approvalRequire, neverAuto: config.approvalNeverAuto }),
|
|
1345
|
+
})
|
|
1346
|
+
: undefined,
|
|
1352
1347
|
};
|
|
1353
1348
|
const scenarios = buildScenarios(scenarioDeps);
|
|
1354
1349
|
const parkedReviveTool = checkpointStore && backgroundAgentStore ? scenarios.default?.({})?.tools.find((t) => t.name === "Agent") : undefined;
|
|
@@ -1844,72 +1839,68 @@ async function main() {
|
|
|
1844
1839
|
config,
|
|
1845
1840
|
authorize,
|
|
1846
1841
|
sessionStoreLabel: config.sessionBackend === "tidb" && backend ? `durable(${backend.kind})` : config.sessionBackend,
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
? (
|
|
1850
|
-
:
|
|
1842
|
+
taskAttachmentStore: taskAttachmentStore ? taskAttachmentStore : undefined,
|
|
1843
|
+
snapshotBlobSqlCapBytes: backend && backend.kind !== "local" && !config.snapshotBlobStore
|
|
1844
|
+
? (config.snapshotBlobSqlMaxBytes ?? (backend.kind === "mysql" ? SQL_BLOB_DEFAULT_MAX_BYTES : undefined))
|
|
1845
|
+
: undefined,
|
|
1851
1846
|
modelReady: () => modelReadyState.ready,
|
|
1852
1847
|
scenarioDetails,
|
|
1853
|
-
|
|
1848
|
+
registryJwtVerifier: registryJwtVerifier ? registryJwtVerifier : undefined,
|
|
1854
1849
|
hookWakeBus,
|
|
1855
1850
|
runStore,
|
|
1856
1851
|
fleetBus,
|
|
1857
1852
|
workflowsCapable,
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
?
|
|
1866
|
-
:
|
|
1853
|
+
resumeAnchorStore: resumeAnchorStore ? resumeAnchorStore : undefined,
|
|
1854
|
+
approvalExemptionStore: approvalExemptionStore ? approvalExemptionStore : undefined,
|
|
1855
|
+
sessionTitler: sessionTitler ? sessionTitler : undefined,
|
|
1856
|
+
sessionPolicyStore: sessionPolicyStore ? sessionPolicyStore : undefined,
|
|
1857
|
+
fileSnapshotStore: fileSnapshotStore ? fileSnapshotStore : undefined,
|
|
1858
|
+
backend: backend ? backend : undefined,
|
|
1859
|
+
sessionMirrorRuling: principalCaps
|
|
1860
|
+
? async (p) => (await principalCaps.executionRuling(p))?.sessionMirror
|
|
1861
|
+
: undefined,
|
|
1867
1862
|
approvalStore,
|
|
1868
1863
|
checkpointStore,
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1864
|
+
backgroundAgentStore: backgroundAgentStore ? backgroundAgentStore : undefined,
|
|
1865
|
+
parkedReviveTool: parkedReviveTool ? parkedReviveTool : undefined,
|
|
1866
|
+
parkedReviveInheritedGate: parkedReviveInheritedGate ? parkedReviveInheritedGate : undefined,
|
|
1872
1867
|
imageIndex,
|
|
1873
1868
|
imageBakes,
|
|
1874
1869
|
leaderEndpoint,
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1870
|
+
workflowRunStore: workflowRunStore ? workflowRunStore : undefined,
|
|
1871
|
+
workflowJournalStore: workflowJournalStore ? workflowJournalStore : undefined,
|
|
1872
|
+
workflowAgentRegistry: workflowAgentRegistry ? workflowAgentRegistry : undefined,
|
|
1878
1873
|
subagentSteerRegistry,
|
|
1879
1874
|
subagentTaskOutput: (handle, access) => backgroundAgentOutput(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1880
1875
|
taskHandleOutput: (handle, access) => taskHandleOutput(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1881
1876
|
taskHandleStop: (handle, access) => taskHandleStop(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1882
|
-
|
|
1877
|
+
workflowCompletionInbox: workflowCompletionInbox ? workflowCompletionInbox : undefined,
|
|
1883
1878
|
sessionAudit,
|
|
1884
1879
|
sessionStorage: ownerAware,
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
sessionEventsMaxConnections: posIntEnv(process.env.SESSION_EVENTS_MAX_CONNS, 256, 100_000),
|
|
1889
|
-
}
|
|
1890
|
-
: {}),
|
|
1891
|
-
...(purgeSession ? { purgeSession } : {}),
|
|
1880
|
+
sessionWatch: sessionWatchRegistry ? sessionWatchRegistry : undefined,
|
|
1881
|
+
sessionEventsMaxConnections: sessionWatchRegistry ? posIntEnv(process.env.SESSION_EVENTS_MAX_CONNS, 256, 100_000) : undefined,
|
|
1882
|
+
purgeSession: purgeSession ? purgeSession : undefined,
|
|
1892
1883
|
instrumentDegenerate,
|
|
1893
1884
|
planCacheProbe,
|
|
1894
1885
|
modelUsage: modelUsageTracker,
|
|
1895
1886
|
promptManifests: promptManifestTracker,
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1887
|
+
elicitation: elicitation ? elicitation : undefined,
|
|
1888
|
+
question: question ? question : undefined,
|
|
1889
|
+
toolApproval: toolApproval ? toolApproval : undefined,
|
|
1890
|
+
sendUserFile: sendUserFileEmitter ? sendUserFileEmitter : undefined,
|
|
1891
|
+
sendFileLedger: sendFileLedger ? sendFileLedger : undefined,
|
|
1901
1892
|
instanceId,
|
|
1902
1893
|
logger,
|
|
1903
1894
|
metrics,
|
|
1904
1895
|
rateLimiter,
|
|
1905
1896
|
costQuota,
|
|
1906
|
-
|
|
1897
|
+
fleetLease: fleetLease ? fleetLease : undefined,
|
|
1907
1898
|
sideQueryAccounting,
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
?
|
|
1912
|
-
:
|
|
1899
|
+
outcomeSink: outcomeSink ? outcomeSink : undefined,
|
|
1900
|
+
memoryExport: memoryExportBackend ? (scope) => exportMemoryScope(memoryExportBackend, scope) : undefined,
|
|
1901
|
+
memorySync: memoryExportBackend && memorySyncCursors
|
|
1902
|
+
? (scope, syncReq) => performMemorySync(memoryExportBackend, memorySyncCursors, scope, syncReq)
|
|
1903
|
+
: undefined,
|
|
1913
1904
|
capabilities: {
|
|
1914
1905
|
version: serviceVersion(),
|
|
1915
1906
|
scenarios: Object.keys(scenarios),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {} from "./tidb-approval-store.js";
|
|
1
|
+
import { mapRow } from "./tidb-approval-store.js";
|
|
2
2
|
import { pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
3
3
|
export const PG_APPROVAL_SCHEMA = [
|
|
4
4
|
`CREATE TABLE IF NOT EXISTS approval (
|
|
@@ -27,16 +27,6 @@ export async function ensureSchema(pool) {
|
|
|
27
27
|
for (const stmt of PG_APPROVAL_SCHEMA)
|
|
28
28
|
await pool.query(stmt);
|
|
29
29
|
}
|
|
30
|
-
function parseJson(v) {
|
|
31
|
-
if (v == null)
|
|
32
|
-
return null;
|
|
33
|
-
return (typeof v === "string" ? JSON.parse(v) : v);
|
|
34
|
-
}
|
|
35
|
-
function iso(v) {
|
|
36
|
-
if (v == null)
|
|
37
|
-
return null;
|
|
38
|
-
return v instanceof Date ? v.toISOString() : String(v);
|
|
39
|
-
}
|
|
40
30
|
export class PgApprovalStore {
|
|
41
31
|
pool;
|
|
42
32
|
constructor(pool) {
|
|
@@ -91,20 +81,4 @@ export class PgApprovalStore {
|
|
|
91
81
|
return res.rowCount ?? 0;
|
|
92
82
|
}
|
|
93
83
|
}
|
|
94
|
-
function mapRow(r) {
|
|
95
|
-
return {
|
|
96
|
-
id: String(r.id),
|
|
97
|
-
taskId: r.task_id ?? null,
|
|
98
|
-
sessionId: r.session_id ?? null,
|
|
99
|
-
owner: r.owner ?? null,
|
|
100
|
-
scope: r.scope ?? null,
|
|
101
|
-
toolName: String(r.tool_name),
|
|
102
|
-
args: parseJson(r.args),
|
|
103
|
-
status: r.status,
|
|
104
|
-
reason: r.reason ?? null,
|
|
105
|
-
decidedBy: r.decided_by ?? null,
|
|
106
|
-
createdAt: iso(r.created_at),
|
|
107
|
-
decidedAt: iso(r.decided_at),
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
84
|
//# sourceMappingURL=pg-approval-store.js.map
|
|
@@ -2,15 +2,11 @@ import { CheckpointError, validatePendingSteer, checkpointVersionOf, winnerFromO
|
|
|
2
2
|
import { redactDeep } from "../trace/redact.js";
|
|
3
3
|
import { tokenFingerprint } from "./tidb-checkpoint-store.js";
|
|
4
4
|
import { pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
5
|
+
import { parseJsonStrict as parseJson } from "./sql-row-helpers.js";
|
|
5
6
|
const MAX_TOOL_INPUT_CHARS = 8192;
|
|
6
7
|
const TERMINAL_BACKSTOP_MS = Math.max(60_000, Number(process.env.APPROVAL_TERMINAL_BACKSTOP_MS) || 30 * 86_400_000);
|
|
7
8
|
const TERMINAL_GRACE_MS = 3_600_000;
|
|
8
9
|
const PG_UNIQUE_VIOLATION = "23505";
|
|
9
|
-
function parseJson(v) {
|
|
10
|
-
if (v == null)
|
|
11
|
-
return null;
|
|
12
|
-
return (typeof v === "string" ? JSON.parse(v) : v);
|
|
13
|
-
}
|
|
14
10
|
function boundedToolInput(args) {
|
|
15
11
|
if (args === undefined)
|
|
16
12
|
return null;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { uuidv7 } from "@sema-agent/core";
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
import { pgSanitizeText, pgSafeJsonStringify, pgHasUnstorable } from "./pg-safe-json.js";
|
|
4
|
+
import { parseJsonOr as parseJson, toIso as iso } from "./sql-row-helpers.js";
|
|
5
|
+
import { mapRow, SELECT_COLS } from "./tidb-image-bake.js";
|
|
4
6
|
export const PG_IMAGE_BAKE_SCHEMA = [
|
|
5
7
|
`CREATE TABLE IF NOT EXISTS image_bake (
|
|
6
8
|
bake_id VARCHAR(64) NOT NULL,
|
|
@@ -74,60 +76,6 @@ function dupKeyName(err) {
|
|
|
74
76
|
return "primary";
|
|
75
77
|
return "other";
|
|
76
78
|
}
|
|
77
|
-
function iso(v) {
|
|
78
|
-
return v instanceof Date ? v.toISOString() : String(v);
|
|
79
|
-
}
|
|
80
|
-
function isoOrNull(v) {
|
|
81
|
-
if (v == null)
|
|
82
|
-
return null;
|
|
83
|
-
return v instanceof Date ? v.toISOString() : new Date(v).toISOString();
|
|
84
|
-
}
|
|
85
|
-
function parseJson(v, fallback) {
|
|
86
|
-
if (v == null)
|
|
87
|
-
return fallback;
|
|
88
|
-
if (typeof v !== "string")
|
|
89
|
-
return v;
|
|
90
|
-
try {
|
|
91
|
-
return JSON.parse(v);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return fallback;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function mapRow(r) {
|
|
98
|
-
return {
|
|
99
|
-
bakeId: r.bake_id,
|
|
100
|
-
profile: r.profile,
|
|
101
|
-
bands: r.bands == null ? null : parseJson(r.bands, []),
|
|
102
|
-
baseRef: r.base_ref,
|
|
103
|
-
push: !!r.push,
|
|
104
|
-
dryRun: !!r.dry_run,
|
|
105
|
-
logs: !!r.logs,
|
|
106
|
-
argv: parseJson(r.argv, []),
|
|
107
|
-
status: r.status,
|
|
108
|
-
state: r.state ?? null,
|
|
109
|
-
digest: r.digest,
|
|
110
|
-
repo: r.repo,
|
|
111
|
-
ref: r.ref,
|
|
112
|
-
indexId: r.index_id,
|
|
113
|
-
exitCode: r.exit_code === null ? null : Number(r.exit_code),
|
|
114
|
-
error: r.error,
|
|
115
|
-
errorCode: r.error_code ?? null,
|
|
116
|
-
manifestSha: r.manifest_sha,
|
|
117
|
-
tag: r.tag,
|
|
118
|
-
idemKey: r.idem_key,
|
|
119
|
-
ingestSecret: r.ingest_secret,
|
|
120
|
-
runnerId: r.runner_id,
|
|
121
|
-
leaseUntil: isoOrNull(r.lease_until),
|
|
122
|
-
cancelRequested: !!r.cancel_requested,
|
|
123
|
-
requestedBy: r.requested_by,
|
|
124
|
-
createdAt: iso(r.created_at),
|
|
125
|
-
updatedAt: iso(r.updated_at),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
const SELECT_COLS = "bake_id, profile, bands, base_ref, push, dry_run, logs, argv, status, state, digest, repo, ref, index_id, " +
|
|
129
|
-
"exit_code, error, error_code, manifest_sha, tag, idem_key, ingest_secret, runner_id, lease_until, " +
|
|
130
|
-
"cancel_requested, requested_by, created_at, updated_at";
|
|
131
79
|
export class PgImageBake {
|
|
132
80
|
pool;
|
|
133
81
|
poolName;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { pgSafeJsonStringify, pgSanitizeText, pgHasUnstorable, PgUnstorableError } from "./pg-safe-json.js";
|
|
3
|
-
import {} from "./tidb-image-index.js";
|
|
3
|
+
import { mapRow, } from "./tidb-image-index.js";
|
|
4
4
|
export const PG_IMAGE_INDEX_SCHEMA = [
|
|
5
5
|
`CREATE TABLE IF NOT EXISTS sandbox_image_index (
|
|
6
6
|
id VARCHAR(64) NOT NULL,
|
|
@@ -37,49 +37,6 @@ export async function ensureSchema(pool) {
|
|
|
37
37
|
}
|
|
38
38
|
const MAX_LIMIT = 200;
|
|
39
39
|
const DEFAULT_LIMIT = 50;
|
|
40
|
-
function asJson(v, fallback) {
|
|
41
|
-
if (v === null || v === undefined)
|
|
42
|
-
return fallback;
|
|
43
|
-
if (typeof v === "string") {
|
|
44
|
-
try {
|
|
45
|
-
return JSON.parse(v);
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return fallback;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return v;
|
|
52
|
-
}
|
|
53
|
-
function iso(v) {
|
|
54
|
-
if (v === null || v === undefined)
|
|
55
|
-
return null;
|
|
56
|
-
return v instanceof Date ? v.toISOString() : new Date(v).toISOString();
|
|
57
|
-
}
|
|
58
|
-
function mapRow(r) {
|
|
59
|
-
return {
|
|
60
|
-
id: r.id,
|
|
61
|
-
profile: r.profile,
|
|
62
|
-
bands: asJson(r.bands, []),
|
|
63
|
-
repo: r.repo,
|
|
64
|
-
tag: r.tag,
|
|
65
|
-
digest: r.digest,
|
|
66
|
-
toolchainVersions: asJson(r.toolchain_versions, {}),
|
|
67
|
-
capabilities: asJson(r.capabilities, {}),
|
|
68
|
-
podContract: asJson(r.pod_contract, {}),
|
|
69
|
-
sizeBytes: r.size_bytes === null ? null : Number(r.size_bytes),
|
|
70
|
-
status: r.status,
|
|
71
|
-
visibility: r.visibility,
|
|
72
|
-
tenantId: r.tenant_id,
|
|
73
|
-
manifestSha: r.manifest_sha,
|
|
74
|
-
recipeGitSha: r.recipe_git_sha,
|
|
75
|
-
generatorVersion: r.generator_version,
|
|
76
|
-
buildDate: iso(r.build_date),
|
|
77
|
-
supersedes: r.supersedes,
|
|
78
|
-
signed: !!r.signed,
|
|
79
|
-
createdAt: iso(r.created_at) ?? new Date(0).toISOString(),
|
|
80
|
-
updatedAt: iso(r.updated_at) ?? new Date(0).toISOString(),
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
40
|
function visibilityClause(viewer, startIdx) {
|
|
84
41
|
if (viewer.operator)
|
|
85
42
|
return { sql: "1=1", params: [], nextIdx: startIdx };
|
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
2
2
|
import { escapeLike } from "./tidb-tool-result-store.js";
|
|
3
3
|
import { pgSafeJsonStringify, pgSanitizeText } from "./pg-safe-json.js";
|
|
4
|
-
|
|
5
|
-
if (v == null)
|
|
6
|
-
return null;
|
|
7
|
-
if (typeof v !== "string")
|
|
8
|
-
return v;
|
|
9
|
-
try {
|
|
10
|
-
return JSON.parse(v);
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
4
|
+
import { parseJsonLenient as parseJson, toIso as iso } from "./sql-row-helpers.js";
|
|
16
5
|
function isDupKey(err) {
|
|
17
6
|
return Boolean(err) && err.code === "23505";
|
|
18
7
|
}
|
|
19
|
-
function iso(v) {
|
|
20
|
-
return v instanceof Date ? v.toISOString() : String(v);
|
|
21
|
-
}
|
|
22
8
|
export class PgRunStore {
|
|
23
9
|
pool;
|
|
24
10
|
constructor(pool) {
|
|
@@ -2,16 +2,12 @@ import { emitLeafAdvance } from "../session-leaf-bus.js";
|
|
|
2
2
|
import { BaseSessionStorage, StoredSession, SessionError, uuidv7, validateEntriesForImport, leafIdAfterEntry, normalizePromptEpoch, } from "@sema-agent/core";
|
|
3
3
|
import { escapeLike } from "./tidb-tool-result-store.js";
|
|
4
4
|
import { pgSafeJsonStringify } from "./pg-safe-json.js";
|
|
5
|
+
import { toIso } from "./sql-row-helpers.js";
|
|
5
6
|
import { classifySyncRelationshipByIds, SyncConflictError, stagingIdFor, STAGING_ID_MARKER, } from "../session-sync.js";
|
|
6
7
|
const STAGING_GC_GRACE_MS = 3_600_000;
|
|
7
8
|
function isDupKey(err) {
|
|
8
9
|
return Boolean(err) && err.code === "23505";
|
|
9
10
|
}
|
|
10
|
-
function toIso(v) {
|
|
11
|
-
if (v instanceof Date)
|
|
12
|
-
return v.toISOString();
|
|
13
|
-
return String(v);
|
|
14
|
-
}
|
|
15
11
|
function parseEntry(p) {
|
|
16
12
|
return (typeof p === "string" ? JSON.parse(p) : p);
|
|
17
13
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function parseJsonLenient<T>(v: unknown): T | null;
|
|
2
|
+
export declare function parseJsonStrict<T>(v: unknown): T | null;
|
|
3
|
+
export declare function parseJsonOr<T>(v: unknown, fallback: T): T;
|
|
4
|
+
export declare function toIso(v: unknown): string;
|
|
5
|
+
export declare function toIsoOrNull(v: unknown): string | null;
|
|
6
|
+
export declare function normalizeIsoOrNull(v: unknown): string | null;
|
|
7
|
+
//# sourceMappingURL=sql-row-helpers.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export function parseJsonLenient(v) {
|
|
2
|
+
if (v == null)
|
|
3
|
+
return null;
|
|
4
|
+
if (typeof v !== "string")
|
|
5
|
+
return v;
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(v);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function parseJsonStrict(v) {
|
|
14
|
+
if (v == null)
|
|
15
|
+
return null;
|
|
16
|
+
return (typeof v === "string" ? JSON.parse(v) : v);
|
|
17
|
+
}
|
|
18
|
+
export function parseJsonOr(v, fallback) {
|
|
19
|
+
if (v == null)
|
|
20
|
+
return fallback;
|
|
21
|
+
if (typeof v !== "string")
|
|
22
|
+
return v;
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(v);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return fallback;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function toIso(v) {
|
|
31
|
+
return v instanceof Date ? v.toISOString() : String(v);
|
|
32
|
+
}
|
|
33
|
+
export function toIsoOrNull(v) {
|
|
34
|
+
if (v == null)
|
|
35
|
+
return null;
|
|
36
|
+
return v instanceof Date ? v.toISOString() : String(v);
|
|
37
|
+
}
|
|
38
|
+
export function normalizeIsoOrNull(v) {
|
|
39
|
+
if (v == null)
|
|
40
|
+
return null;
|
|
41
|
+
return v instanceof Date ? v.toISOString() : new Date(v).toISOString();
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=sql-row-helpers.js.map
|
|
@@ -36,4 +36,5 @@ export declare class TiDBApprovalStore {
|
|
|
36
36
|
listPendingAll(): Promise<ApprovalRow[]>;
|
|
37
37
|
expireStale(olderThanMs: number): Promise<number>;
|
|
38
38
|
}
|
|
39
|
+
export declare function mapRow(r: Record<string, unknown>): ApprovalRow;
|
|
39
40
|
//# sourceMappingURL=tidb-approval-store.d.ts.map
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
if (v == null)
|
|
3
|
-
return null;
|
|
4
|
-
return (typeof v === "string" ? JSON.parse(v) : v);
|
|
5
|
-
}
|
|
6
|
-
function iso(v) {
|
|
7
|
-
if (v == null)
|
|
8
|
-
return null;
|
|
9
|
-
return v instanceof Date ? v.toISOString() : String(v);
|
|
10
|
-
}
|
|
1
|
+
import { parseJsonStrict as parseJson, toIsoOrNull as iso } from "./sql-row-helpers.js";
|
|
11
2
|
export class TiDBApprovalStore {
|
|
12
3
|
pool;
|
|
13
4
|
constructor(pool) {
|
|
@@ -62,7 +53,7 @@ export class TiDBApprovalStore {
|
|
|
62
53
|
return res.affectedRows;
|
|
63
54
|
}
|
|
64
55
|
}
|
|
65
|
-
function mapRow(r) {
|
|
56
|
+
export function mapRow(r) {
|
|
66
57
|
return {
|
|
67
58
|
id: String(r.id),
|
|
68
59
|
taskId: r.task_id ?? null,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { CheckpointError, validatePendingSteer, checkpointVersionOf, winnerFromOutcome, summarizeCheckpoint, MAX_SUPPORTED_CHECKPOINT_VERSION } from "@sema-agent/core";
|
|
3
3
|
import { redactDeep } from "../trace/redact.js";
|
|
4
|
+
import { parseJsonStrict as parseJson } from "./sql-row-helpers.js";
|
|
4
5
|
const MAX_TOOL_INPUT_CHARS = 8192;
|
|
5
6
|
export const TERMINAL_BACKSTOP_MS = Math.max(60_000, Number(process.env.APPROVAL_TERMINAL_BACKSTOP_MS) || 30 * 86_400_000);
|
|
6
7
|
export const TERMINAL_GRACE_MS = 3_600_000;
|
|
@@ -188,9 +189,4 @@ export class TiDBCheckpointStore {
|
|
|
188
189
|
return res.affectedRows;
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
|
-
function parseJson(v) {
|
|
192
|
-
if (v == null)
|
|
193
|
-
return null;
|
|
194
|
-
return (typeof v === "string" ? JSON.parse(v) : v);
|
|
195
|
-
}
|
|
196
192
|
//# sourceMappingURL=tidb-checkpoint-store.js.map
|
|
@@ -63,6 +63,37 @@ export interface BakeTerminal {
|
|
|
63
63
|
manifestSha?: string | null;
|
|
64
64
|
tag?: string | null;
|
|
65
65
|
}
|
|
66
|
+
export interface BakeRow {
|
|
67
|
+
bake_id: string;
|
|
68
|
+
profile: string;
|
|
69
|
+
bands: unknown;
|
|
70
|
+
base_ref: string | null;
|
|
71
|
+
push: number;
|
|
72
|
+
dry_run: number;
|
|
73
|
+
logs: number;
|
|
74
|
+
argv: unknown;
|
|
75
|
+
status: string;
|
|
76
|
+
state: string | null;
|
|
77
|
+
digest: string | null;
|
|
78
|
+
repo: string | null;
|
|
79
|
+
ref: string | null;
|
|
80
|
+
index_id: string | null;
|
|
81
|
+
exit_code: number | string | null;
|
|
82
|
+
error: string | null;
|
|
83
|
+
error_code: string | null;
|
|
84
|
+
manifest_sha: string | null;
|
|
85
|
+
tag: string | null;
|
|
86
|
+
idem_key: string | null;
|
|
87
|
+
ingest_secret: string | null;
|
|
88
|
+
runner_id: string | null;
|
|
89
|
+
lease_until: Date | string | null;
|
|
90
|
+
cancel_requested: number;
|
|
91
|
+
requested_by: string | null;
|
|
92
|
+
created_at: Date | string;
|
|
93
|
+
updated_at: Date | string;
|
|
94
|
+
}
|
|
95
|
+
export declare function mapRow(r: BakeRow): BakeRecord;
|
|
96
|
+
export declare const SELECT_COLS: string;
|
|
66
97
|
export declare class TiDBImageBake {
|
|
67
98
|
private readonly pool;
|
|
68
99
|
private readonly poolName;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { uuidv7 } from "@sema-agent/core";
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { parseJsonOr as parseJson, toIso as iso, normalizeIsoOrNull as isoOrNull } from "./sql-row-helpers.js";
|
|
3
4
|
function isDupKey(err) {
|
|
4
5
|
return Boolean(err) && err.code === "ER_DUP_ENTRY";
|
|
5
6
|
}
|
|
@@ -11,27 +12,7 @@ function dupKeyName(err) {
|
|
|
11
12
|
return "primary";
|
|
12
13
|
return "other";
|
|
13
14
|
}
|
|
14
|
-
function
|
|
15
|
-
return v instanceof Date ? v.toISOString() : String(v);
|
|
16
|
-
}
|
|
17
|
-
function isoOrNull(v) {
|
|
18
|
-
if (v == null)
|
|
19
|
-
return null;
|
|
20
|
-
return v instanceof Date ? v.toISOString() : new Date(v).toISOString();
|
|
21
|
-
}
|
|
22
|
-
function parseJson(v, fallback) {
|
|
23
|
-
if (v == null)
|
|
24
|
-
return fallback;
|
|
25
|
-
if (typeof v !== "string")
|
|
26
|
-
return v;
|
|
27
|
-
try {
|
|
28
|
-
return JSON.parse(v);
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return fallback;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function mapRow(r) {
|
|
15
|
+
export function mapRow(r) {
|
|
35
16
|
return {
|
|
36
17
|
bakeId: r.bake_id,
|
|
37
18
|
profile: r.profile,
|
|
@@ -62,7 +43,7 @@ function mapRow(r) {
|
|
|
62
43
|
updatedAt: iso(r.updated_at),
|
|
63
44
|
};
|
|
64
45
|
}
|
|
65
|
-
const SELECT_COLS = "bake_id, profile, bands, base_ref, push, dry_run, logs, argv, status, state, digest, repo, ref, index_id, " +
|
|
46
|
+
export const SELECT_COLS = "bake_id, profile, bands, base_ref, push, dry_run, logs, argv, status, state, digest, repo, ref, index_id, " +
|
|
66
47
|
"exit_code, error, error_code, manifest_sha, tag, idem_key, ingest_secret, runner_id, lease_until, " +
|
|
67
48
|
"cancel_requested, requested_by, created_at, updated_at";
|
|
68
49
|
export class TiDBImageBake {
|
|
@@ -51,6 +51,30 @@ export interface ImageListFilter extends ImageViewer {
|
|
|
51
51
|
limit?: number;
|
|
52
52
|
cursor?: string;
|
|
53
53
|
}
|
|
54
|
+
export interface ImageRow {
|
|
55
|
+
id: string;
|
|
56
|
+
profile: string;
|
|
57
|
+
bands: unknown;
|
|
58
|
+
repo: string;
|
|
59
|
+
tag: string;
|
|
60
|
+
digest: string;
|
|
61
|
+
toolchain_versions: unknown;
|
|
62
|
+
capabilities: unknown;
|
|
63
|
+
pod_contract: unknown;
|
|
64
|
+
size_bytes: number | string | null;
|
|
65
|
+
status: string;
|
|
66
|
+
visibility: string;
|
|
67
|
+
tenant_id: string | null;
|
|
68
|
+
manifest_sha: string | null;
|
|
69
|
+
recipe_git_sha: string | null;
|
|
70
|
+
generator_version: string | null;
|
|
71
|
+
build_date: Date | string | null;
|
|
72
|
+
supersedes: string | null;
|
|
73
|
+
signed: number;
|
|
74
|
+
created_at: Date | string;
|
|
75
|
+
updated_at: Date | string;
|
|
76
|
+
}
|
|
77
|
+
export declare function mapRow(r: ImageRow): ImageIndexEntry;
|
|
54
78
|
export declare class TiDBImageIndex {
|
|
55
79
|
private readonly pool;
|
|
56
80
|
constructor(pool: Pool);
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { parseJsonOr as asJson, normalizeIsoOrNull as iso } from "./sql-row-helpers.js";
|
|
2
3
|
const MAX_LIMIT = 200;
|
|
3
4
|
const DEFAULT_LIMIT = 50;
|
|
4
|
-
function
|
|
5
|
-
if (v === null || v === undefined)
|
|
6
|
-
return fallback;
|
|
7
|
-
if (typeof v === "string") {
|
|
8
|
-
try {
|
|
9
|
-
return JSON.parse(v);
|
|
10
|
-
}
|
|
11
|
-
catch {
|
|
12
|
-
return fallback;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return v;
|
|
16
|
-
}
|
|
17
|
-
function iso(v) {
|
|
18
|
-
if (v === null || v === undefined)
|
|
19
|
-
return null;
|
|
20
|
-
return v instanceof Date ? v.toISOString() : new Date(v).toISOString();
|
|
21
|
-
}
|
|
22
|
-
function mapRow(r) {
|
|
5
|
+
export function mapRow(r) {
|
|
23
6
|
return {
|
|
24
7
|
id: r.id,
|
|
25
8
|
profile: r.profile,
|
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
2
2
|
import { escapeLike } from "./tidb-tool-result-store.js";
|
|
3
|
-
|
|
4
|
-
if (v == null)
|
|
5
|
-
return null;
|
|
6
|
-
if (typeof v !== "string")
|
|
7
|
-
return v;
|
|
8
|
-
try {
|
|
9
|
-
return JSON.parse(v);
|
|
10
|
-
}
|
|
11
|
-
catch {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
3
|
+
import { parseJsonLenient as parseJson, toIso as iso } from "./sql-row-helpers.js";
|
|
15
4
|
function isDupKey(err) {
|
|
16
5
|
return Boolean(err) && err.code === "ER_DUP_ENTRY";
|
|
17
6
|
}
|
|
18
|
-
function iso(v) {
|
|
19
|
-
return v instanceof Date ? v.toISOString() : String(v);
|
|
20
|
-
}
|
|
21
7
|
export class TiDBRunStore {
|
|
22
8
|
pool;
|
|
23
9
|
constructor(pool) {
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { emitLeafAdvance } from "../session-leaf-bus.js";
|
|
2
2
|
import { BaseSessionStorage, SessionError, leafIdAfterEntry, normalizePromptEpoch, } from "@sema-agent/core";
|
|
3
|
+
import { toIso } from "./sql-row-helpers.js";
|
|
3
4
|
function isDupKey(err) {
|
|
4
5
|
return Boolean(err) && err.code === "ER_DUP_ENTRY";
|
|
5
6
|
}
|
|
6
|
-
function toIso(v) {
|
|
7
|
-
if (v instanceof Date)
|
|
8
|
-
return v.toISOString();
|
|
9
|
-
return String(v);
|
|
10
|
-
}
|
|
11
7
|
export class TiDBSessionStorage extends BaseSessionStorage {
|
|
12
8
|
pool;
|
|
13
9
|
sessionId;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type PromptTextDeclaration, type PublishedPromptArtifactEnvelope } from "@sema-agent/core";
|
|
2
|
+
export interface EffectiveCenterPrompts {
|
|
3
|
+
packId: string;
|
|
4
|
+
contentDigest: string;
|
|
5
|
+
sections: PromptTextDeclaration[];
|
|
6
|
+
scenarioOverrides?: Record<string, PromptTextDeclaration[]>;
|
|
7
|
+
}
|
|
8
|
+
export declare function validateCenterPrompts(raw: unknown): {
|
|
9
|
+
ok: true;
|
|
10
|
+
value: EffectiveCenterPrompts;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const CORE_ENGINE_VERSION: string;
|
|
16
|
+
export interface PromptsDomainFaces {
|
|
17
|
+
declarations?: EffectiveCenterPrompts;
|
|
18
|
+
catalog?: PublishedPromptArtifactEnvelope;
|
|
19
|
+
identity: string;
|
|
20
|
+
axes: Array<"declarations" | "catalog">;
|
|
21
|
+
}
|
|
22
|
+
export declare function validatePromptsDomain(raw: unknown): {
|
|
23
|
+
ok: true;
|
|
24
|
+
value: PromptsDomainFaces;
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
error: string;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=prompts-domain-validate.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { verifyPromptArtifact } from "@sema-agent/core";
|
|
6
|
+
const ID_RE = /^[a-z0-9][a-z0-9/._-]*$/;
|
|
7
|
+
const SLOTS = new Set(["identity", "scenario", "behavior"]);
|
|
8
|
+
const HASH_RE = /^sha256:[0-9a-f]{64}$/;
|
|
9
|
+
function declarationIssue(d, where) {
|
|
10
|
+
if (d === null || typeof d !== "object")
|
|
11
|
+
return `${where}: declaration is not an object`;
|
|
12
|
+
const o = d;
|
|
13
|
+
if (typeof o.id !== "string" || o.id.length === 0 || o.id.length > 128 || !ID_RE.test(o.id))
|
|
14
|
+
return `${where}: bad id`;
|
|
15
|
+
if (o.id.startsWith("core/"))
|
|
16
|
+
return `${where}: id in the reserved core/ namespace`;
|
|
17
|
+
if (typeof o.slot !== "string" || !SLOTS.has(o.slot))
|
|
18
|
+
return `${where}: bad slot`;
|
|
19
|
+
if (typeof o.text !== "string" || o.text.length === 0)
|
|
20
|
+
return `${where}: text must be a non-empty string`;
|
|
21
|
+
if (typeof o.contentHash !== "string" || !HASH_RE.test(o.contentHash))
|
|
22
|
+
return `${where}: contentHash is required (sha256:<64hex> — the epoch declaration axis needs it for byte-level change detection)`;
|
|
23
|
+
const expected = `sha256:${createHash("sha256").update(o.text).digest("hex")}`;
|
|
24
|
+
if (o.contentHash !== expected)
|
|
25
|
+
return `${where}: contentHash does not match sha256(text) — stale or tampered declaration`;
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
export function validateCenterPrompts(raw) {
|
|
29
|
+
if (raw === null || typeof raw !== "object")
|
|
30
|
+
return { ok: false, error: "prompts is not an object" };
|
|
31
|
+
const p = raw;
|
|
32
|
+
if (typeof p.packId !== "string" || !/^center:[0-9a-f]{12}$/.test(p.packId))
|
|
33
|
+
return { ok: false, error: "bad packId form (center:<digest12>)" };
|
|
34
|
+
if (typeof p.contentDigest !== "string" || !HASH_RE.test(p.contentDigest))
|
|
35
|
+
return { ok: false, error: "bad contentDigest form" };
|
|
36
|
+
const arrayIssue = (decls, where) => {
|
|
37
|
+
if (!Array.isArray(decls))
|
|
38
|
+
return `${where} is not an array`;
|
|
39
|
+
if (decls.length === 0)
|
|
40
|
+
return `${where} is empty (an empty replacement set is not a v1 semantic — omit the key instead)`;
|
|
41
|
+
const seen = new Set();
|
|
42
|
+
for (let i = 0; i < decls.length; i++) {
|
|
43
|
+
const issue = declarationIssue(decls[i], `${where}[${i}]`);
|
|
44
|
+
if (issue)
|
|
45
|
+
return issue;
|
|
46
|
+
const id = decls[i].id;
|
|
47
|
+
if (seen.has(id))
|
|
48
|
+
return `${where}[${i}]: duplicate id "${id}" (core composer throws on duplicates)`;
|
|
49
|
+
seen.add(id);
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
};
|
|
53
|
+
const sectionsIssue = arrayIssue(p.sections, "sections");
|
|
54
|
+
if (sectionsIssue)
|
|
55
|
+
return { ok: false, error: sectionsIssue };
|
|
56
|
+
if (p.scenarioOverrides !== undefined) {
|
|
57
|
+
if (p.scenarioOverrides === null || typeof p.scenarioOverrides !== "object" || Array.isArray(p.scenarioOverrides)) {
|
|
58
|
+
return { ok: false, error: "scenarioOverrides is not an object" };
|
|
59
|
+
}
|
|
60
|
+
for (const [name, decls] of Object.entries(p.scenarioOverrides)) {
|
|
61
|
+
const issue = arrayIssue(decls, `scenarioOverrides[${name}]`);
|
|
62
|
+
if (issue)
|
|
63
|
+
return { ok: false, error: issue };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, value: raw };
|
|
67
|
+
}
|
|
68
|
+
export const CORE_ENGINE_VERSION = (() => {
|
|
69
|
+
try {
|
|
70
|
+
const entry = createRequire(import.meta.url).resolve("@sema-agent/core");
|
|
71
|
+
return JSON.parse(readFileSync(join(dirname(entry), "..", "package.json"), "utf8")).version ?? "0.0.0";
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return "0.0.0";
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
export function validatePromptsDomain(raw) {
|
|
78
|
+
if (raw === null || typeof raw !== "object")
|
|
79
|
+
return { ok: false, error: "prompts is not an object" };
|
|
80
|
+
const w = raw;
|
|
81
|
+
if (w.schemaVersion === undefined) {
|
|
82
|
+
const legacy = validateCenterPrompts(raw);
|
|
83
|
+
if (!legacy.ok)
|
|
84
|
+
return legacy;
|
|
85
|
+
return { ok: true, value: { declarations: legacy.value, identity: `${legacy.value.contentDigest}+-`, axes: ["declarations"] } };
|
|
86
|
+
}
|
|
87
|
+
if (w.schemaVersion !== 1)
|
|
88
|
+
return { ok: false, error: `unsupported prompts schemaVersion ${String(w.schemaVersion)}` };
|
|
89
|
+
if (w.declarations === undefined && w.catalog === undefined)
|
|
90
|
+
return { ok: false, error: "dual-axis prompts carries neither axis (at least one of declarations|catalog required)" };
|
|
91
|
+
const value = { identity: "", axes: [] };
|
|
92
|
+
if (w.declarations !== undefined) {
|
|
93
|
+
const d = validateCenterPrompts(w.declarations);
|
|
94
|
+
if (!d.ok)
|
|
95
|
+
return { ok: false, error: `declarations axis: ${d.error}` };
|
|
96
|
+
value.declarations = d.value;
|
|
97
|
+
value.axes.push("declarations");
|
|
98
|
+
}
|
|
99
|
+
if (w.catalog !== undefined) {
|
|
100
|
+
const c = verifyPromptArtifact(w.catalog, { engineVersion: CORE_ENGINE_VERSION });
|
|
101
|
+
if (!c.ok)
|
|
102
|
+
return { ok: false, error: `catalog axis: ${c.code}: ${c.reason}` };
|
|
103
|
+
value.catalog = w.catalog;
|
|
104
|
+
value.axes.push("catalog");
|
|
105
|
+
}
|
|
106
|
+
value.identity = `${value.declarations?.contentDigest ?? "-"}+${value.catalog?.artifact.artifactDigest ?? "-"}`;
|
|
107
|
+
return { ok: true, value };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=prompts-domain-validate.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.311.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|