@sema-agent/server 7.68.0 → 7.69.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/USAGE.md +19 -2
- package/dist/adoption/plan.js +11 -0
- package/dist/approval-card.d.ts +26 -0
- package/dist/approval-card.js +11 -0
- package/dist/approval.js +5 -4
- package/dist/boot/config-center.d.ts +6 -7
- package/dist/boot/config-center.js +31 -8
- package/dist/boot/leader.js +1 -1
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +10 -2
- package/dist/budget.js +1 -1
- package/dist/config-catalog.js +20 -1
- package/dist/config-center/apply-effective.d.ts +8 -1
- package/dist/config-center/apply-effective.js +23 -9
- package/dist/config-center/facade.d.ts +1 -1
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/read-face.d.ts +30 -1
- package/dist/config-center/read-face.js +33 -15
- package/dist/config-center/restart-signal.js +2 -1
- package/dist/config-center/types.d.ts +20 -5
- package/dist/config-provider.js +1 -0
- package/dist/config-types.d.ts +17 -2
- package/dist/config.d.ts +0 -21
- package/dist/config.js +19 -6
- package/dist/http/route-ctx.d.ts +39 -1
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/capabilities.js +1 -0
- package/dist/http/routes/workflows.js +15 -7
- package/dist/http/server.d.ts +10 -2
- package/dist/http/server.js +70 -24
- package/dist/leader/wire.d.ts +9 -2
- package/dist/leader/wire.js +6 -6
- package/dist/main.js +6 -5
- package/dist/model-compat.d.ts +81 -0
- package/dist/model-compat.js +52 -0
- package/dist/observability/fail-open.d.ts +4 -0
- package/dist/observability/fail-open.js +4 -0
- package/dist/operator-ask.d.ts +46 -0
- package/dist/operator-ask.js +4 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +96 -0
- package/dist/orchestration/workflow-agent-session-index.js +146 -0
- package/dist/orchestration/workflow-journal-entry.d.ts +78 -0
- package/dist/orchestration/workflow-journal-entry.js +20 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +43 -1
- package/dist/orchestration/workflow-notify-journal.js +43 -3
- package/dist/parked-decide.d.ts +115 -5
- package/dist/parked-decide.js +94 -26
- package/dist/plugins/pg-pool.js +8 -0
- package/dist/plugins/store-backend.d.ts +5 -0
- package/dist/plugins/store-backend.js +3 -1
- package/dist/plugins/tidb-pool.js +8 -0
- package/dist/plugins/workflow-journal-store-sql.js +10 -3
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -0
- package/dist/plugins/workflow-run-store-sql.js +40 -0
- package/dist/router/route-orchestration.js +2 -1
- package/dist/run-local.js +1 -1
- package/dist/runs.js +2 -0
- package/dist/runtime-governance.js +5 -4
- package/dist/tool-approval.d.ts +20 -0
- package/dist/tool-approval.js +2 -1
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +1 -0
- package/package.json +3 -3
package/dist/parked-decide.js
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
import { defaultSubagentTailBus } from "./fleet/subagent-tail-bus.js";
|
|
2
2
|
import { backgroundScopesForCheckpointScope, decodeCheckpointScope } from "./security.js";
|
|
3
|
+
export async function findParkOrigin(sources, cp) {
|
|
4
|
+
if (sources.agentStore !== undefined) {
|
|
5
|
+
let match;
|
|
6
|
+
try {
|
|
7
|
+
match = await findParkedAgentForCheckpoint(sources.agentStore, cp);
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
quiet(sources.warn, "parked_decide_probe_failed", { error: e instanceof Error ? e.message : String(e) });
|
|
11
|
+
}
|
|
12
|
+
if (match !== undefined)
|
|
13
|
+
return { kind: "background", handle: match.handle, row: match.row };
|
|
14
|
+
}
|
|
15
|
+
const index = sources.workflowIndex;
|
|
16
|
+
const runStore = sources.workflowRunStore;
|
|
17
|
+
if (index === undefined || runStore === undefined)
|
|
18
|
+
return undefined;
|
|
19
|
+
try {
|
|
20
|
+
const row = await index.findByAgentSession(cp.sessionId);
|
|
21
|
+
if (row === null)
|
|
22
|
+
return undefined;
|
|
23
|
+
const run = await runStore.get(row.runId);
|
|
24
|
+
if (run === null)
|
|
25
|
+
return undefined;
|
|
26
|
+
const agent = (run.agents ?? []).find((a) => a.sessionId === cp.sessionId && a.status === "parked");
|
|
27
|
+
if (agent === undefined || agent.parkedCheckpointToken !== cp.token)
|
|
28
|
+
return undefined;
|
|
29
|
+
return { kind: "workflow", runId: row.runId, run, agent };
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
quiet(sources.warn, "workflow_park_probe_failed", { error: e instanceof Error ? e.message : String(e) });
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function quiet(warn, event, fields) {
|
|
37
|
+
try {
|
|
38
|
+
warn?.(event, fields);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
}
|
|
42
|
+
}
|
|
3
43
|
export async function findParkedAgentForCheckpoint(agentStore, cp) {
|
|
4
44
|
for (const scope of backgroundScopesForCheckpointScope(cp.scope)) {
|
|
5
45
|
const parked = await agentStore.listByScope(scope, { status: "parked" });
|
|
@@ -25,21 +65,61 @@ function mintReviveArgs(row, knownAgentTypes) {
|
|
|
25
65
|
...(row.agentType !== undefined && knownAgentTypes.has(row.agentType) ? { subagent_type: row.agentType } : {}),
|
|
26
66
|
};
|
|
27
67
|
}
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
68
|
+
export function buildParkedResumeOutcome(req) {
|
|
69
|
+
const pa = req.pendingAction;
|
|
70
|
+
const persistedCallId = pa?.kind === "tool_approval" ? (pa.toolCallId ?? "") : "";
|
|
71
|
+
const persistedHash = pa?.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
|
|
72
|
+
return {
|
|
73
|
+
gate: "policy_ask",
|
|
74
|
+
boundCallId: req.binding?.boundCallId ?? persistedCallId,
|
|
75
|
+
boundInputHash: req.binding?.boundInputHash ?? persistedHash,
|
|
76
|
+
decision: req.decision === "approve" ? "allow" : "deny",
|
|
77
|
+
...(req.decision === "approve" && req.binding?.updatedInput !== undefined ? { updatedInput: req.binding.updatedInput } : {}),
|
|
78
|
+
...(req.answer !== undefined ? { answer: req.answer } : {}),
|
|
79
|
+
...(req.reason !== undefined ? { reason: req.reason } : {}),
|
|
80
|
+
hostDecision: req.hostDecision,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function planWorkflowParkedDecide(origin, req) {
|
|
84
|
+
if (req.grantRemember !== undefined) {
|
|
85
|
+
return {
|
|
86
|
+
ok: false,
|
|
87
|
+
deny: {
|
|
88
|
+
status: 400,
|
|
89
|
+
body: {
|
|
90
|
+
error: "remember:\"session\" is not supported for a parked WORKFLOW agent: this lane's 200 means the decision was handed to the host's next turn, not that the engine committed it — an exemption granted here could outlive a decision the engine later rejects. Re-issue the decide without `remember`.",
|
|
91
|
+
errorCode: "decide.workflow_remember_unsupported",
|
|
92
|
+
runId: origin.runId,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
32
96
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
97
|
+
const hostSessionId = origin.run.originatingSessionId;
|
|
98
|
+
if (hostSessionId === undefined || hostSessionId === "") {
|
|
99
|
+
return {
|
|
100
|
+
ok: false,
|
|
101
|
+
deny: {
|
|
102
|
+
status: 409,
|
|
103
|
+
body: {
|
|
104
|
+
error: "this parked workflow agent's run carries no originating session — the deployment has nowhere to deliver the decision (a directly-started workflow, not a Workflow tool call)",
|
|
105
|
+
errorCode: "decide.workflow_host_unknown",
|
|
106
|
+
runId: origin.runId,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
40
110
|
}
|
|
41
|
-
|
|
42
|
-
|
|
111
|
+
const verdict = req.decision === "approve" ? "APPROVED" : "DENIED";
|
|
112
|
+
return {
|
|
113
|
+
ok: true,
|
|
114
|
+
hostSessionId,
|
|
115
|
+
runId: origin.runId,
|
|
116
|
+
outcome: buildParkedResumeOutcome(req),
|
|
117
|
+
message: `The human approval that workflow run "${origin.runId}" parked on (agent callKey "${origin.agent.callKey}") has been ${verdict}. ` +
|
|
118
|
+
`Resume that run now by calling Workflow with resumeFromRunId: "${origin.runId}" — the decision is already held by the deployment ` +
|
|
119
|
+
`and will be applied to the parked agent; completed steps replay from the journal. Do not re-issue the original call.`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
export async function decideParkedAgent(deps, req, match) {
|
|
43
123
|
const row = match.row;
|
|
44
124
|
const rememberRoot = req.grantRemember !== undefined ? (row.rootSessionId ?? row.parentSessionId) : undefined;
|
|
45
125
|
if (req.grantRemember !== undefined && rememberRoot === undefined) {
|
|
@@ -81,19 +161,7 @@ export async function decideParkedAgent(deps, req) {
|
|
|
81
161
|
catch {
|
|
82
162
|
}
|
|
83
163
|
}
|
|
84
|
-
const
|
|
85
|
-
const persistedCallId = pa?.kind === "tool_approval" ? (pa.toolCallId ?? "") : "";
|
|
86
|
-
const persistedHash = pa?.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
|
|
87
|
-
const outcome = {
|
|
88
|
-
gate: "policy_ask",
|
|
89
|
-
boundCallId: req.binding?.boundCallId ?? persistedCallId,
|
|
90
|
-
boundInputHash: req.binding?.boundInputHash ?? persistedHash,
|
|
91
|
-
decision: req.decision === "approve" ? "allow" : "deny",
|
|
92
|
-
...(req.decision === "approve" && req.binding?.updatedInput !== undefined ? { updatedInput: req.binding.updatedInput } : {}),
|
|
93
|
-
...(req.answer !== undefined ? { answer: req.answer } : {}),
|
|
94
|
-
...(req.reason !== undefined ? { reason: req.reason } : {}),
|
|
95
|
-
hostDecision: req.hostDecision,
|
|
96
|
-
};
|
|
164
|
+
const outcome = buildParkedResumeOutcome(req);
|
|
97
165
|
const ctx = {
|
|
98
166
|
toolCallId: `drv-${ticket.claimId}`,
|
|
99
167
|
reviveClaim: {
|
package/dist/plugins/pg-pool.js
CHANGED
|
@@ -266,6 +266,14 @@ export const PG_SCHEMA_STATEMENTS = [
|
|
|
266
266
|
)`,
|
|
267
267
|
`CREATE INDEX IF NOT EXISTS idx_wfrun_scope_created ON workflow_run (scope, created_at_ms)`,
|
|
268
268
|
`CREATE INDEX IF NOT EXISTS idx_wfrun_scope_status ON workflow_run (scope, status)`,
|
|
269
|
+
`CREATE TABLE IF NOT EXISTS workflow_agent_session (
|
|
270
|
+
session_id VARCHAR(190) COLLATE "C" NOT NULL,
|
|
271
|
+
run_id VARCHAR(191) COLLATE "C" NOT NULL,
|
|
272
|
+
agent_key VARCHAR(191) COLLATE "C" NOT NULL,
|
|
273
|
+
scope VARCHAR(190) COLLATE "C" NOT NULL,
|
|
274
|
+
PRIMARY KEY (session_id)
|
|
275
|
+
)`,
|
|
276
|
+
`CREATE INDEX IF NOT EXISTS idx_wfagentsess_run ON workflow_agent_session (run_id)`,
|
|
269
277
|
`CREATE TABLE IF NOT EXISTS workflow_completion_inbox (
|
|
270
278
|
seq BIGSERIAL,
|
|
271
279
|
session_id VARCHAR(190) COLLATE "C" NOT NULL,
|
|
@@ -238,6 +238,11 @@ export interface StoreBackend {
|
|
|
238
238
|
/** 1.108 review fix (lens③ HIGH): the notify-JOURNAL twin — third leg of the same axis (a SQL run store +
|
|
239
239
|
* inbox with a replica-LOCAL File journal stranded a dead replica's un-acked notify forever). */
|
|
240
240
|
notifyJournal?(): import("../orchestration/workflow-notify-journal.js").WorkflowNotifyJournalStore;
|
|
241
|
+
/** S-185 车CM:workflow 出身 park 的**有界 join** 索引(子会话 id → 它所属的 workflow run)。
|
|
242
|
+
* 与 `workflowRun`/`completionInbox`/`notifyJournal` 同一条轴 —— SQL 后端 = 跨副本双生;`local` 车道
|
|
243
|
+
* 缺席**是一个真答案**:那里的索引家在 run 店同一间屋子里(`LocalWorkflowAgentSessionIndex`,文件账本
|
|
244
|
+
* 或纯内存),不需要经过 backend。契约与单写者纪律的属主 = orchestration/workflow-agent-session-index.ts。 */
|
|
245
|
+
workflowAgentSessionIndex?(): import("../orchestration/workflow-agent-session-index.js").WorkflowAgentSessionIndex;
|
|
241
246
|
/** Cloud-only stores below are OPTIONAL: the `local` (in-memory/file) backend omits them (it has no core
|
|
242
247
|
* in-memory twin carrying the service extras, and these are fleet/multi-replica concepts), so a local HTTP
|
|
243
248
|
* service degrades EXACTLY like today's no-DB env (the consumers gate on `backend?.X?.()`). TiDB/PG provide all. */
|
|
@@ -4,7 +4,7 @@ import { AdoptionError, FileStorageBackend, FileSessionRepo } from "@sema-agent/
|
|
|
4
4
|
import { FileWorkflowJournalStore } from "@sema-agent/core";
|
|
5
5
|
import { TiDBOutcomeLedger, PgOutcomeLedger } from "./outcome-ledger-sql.js";
|
|
6
6
|
import { FileOutcomeSink } from "./file-outcome-sink.js";
|
|
7
|
-
import { TiDBWorkflowRunStore, TiDBWorkflowCompletionInbox, TiDBWorkflowNotifyJournalStore, PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore } from "./workflow-run-store-sql.js";
|
|
7
|
+
import { TiDBWorkflowRunStore, TiDBWorkflowCompletionInbox, TiDBWorkflowNotifyJournalStore, TiDBWorkflowAgentSessionIndex, PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore, PgWorkflowAgentSessionIndex } from "./workflow-run-store-sql.js";
|
|
8
8
|
import { FileRunStore, RunStoreStrictHydrateError } from "./file-run-store.js";
|
|
9
9
|
import { LocalSessionStore } from "./local-session-store.js";
|
|
10
10
|
import { LocalCheckpointStore } from "./local-checkpoint-store.js";
|
|
@@ -145,6 +145,7 @@ class TiDBBackend {
|
|
|
145
145
|
workflowRun(onWarn) { return new TiDBWorkflowRunStore(this.pool, onWarn); }
|
|
146
146
|
completionInbox(onWarn) { return new TiDBWorkflowCompletionInbox(this.pool, onWarn); }
|
|
147
147
|
notifyJournal() { return new TiDBWorkflowNotifyJournalStore(this.pool); }
|
|
148
|
+
workflowAgentSessionIndex() { return new TiDBWorkflowAgentSessionIndex(this.pool); }
|
|
148
149
|
sharedMemoryStore(authorizer) { return new TiDBSharedMemoryStore(this.pool, authorizer); }
|
|
149
150
|
checkpoint(logger) { return new TiDBCheckpointStore(this.pool, logger); }
|
|
150
151
|
toolResult() { return new TiDBToolResultStore(this.pool); }
|
|
@@ -191,6 +192,7 @@ class PgBackend {
|
|
|
191
192
|
workflowRun(onWarn) { return new PgWorkflowRunStore(this.pool, onWarn); }
|
|
192
193
|
completionInbox(onWarn) { return new PgWorkflowCompletionInbox(this.pool, onWarn); }
|
|
193
194
|
notifyJournal() { return new PgWorkflowNotifyJournalStore(this.pool); }
|
|
195
|
+
workflowAgentSessionIndex() { return new PgWorkflowAgentSessionIndex(this.pool); }
|
|
194
196
|
sharedMemoryStore(authorizer) { return new PgSharedMemoryStore(this.pool, authorizer); }
|
|
195
197
|
checkpoint(logger) { return new PgCheckpointStore(this.pool, logger); }
|
|
196
198
|
toolResult() { return new PgToolResultStore(this.pool); }
|
|
@@ -446,6 +446,14 @@ export const SCHEMA_STATEMENTS = [
|
|
|
446
446
|
PRIMARY KEY (id),
|
|
447
447
|
KEY idx_wfrun_scope_created (scope, created_at_ms),
|
|
448
448
|
KEY idx_wfrun_scope_status (scope, status)
|
|
449
|
+
) COLLATE utf8mb4_bin`,
|
|
450
|
+
`CREATE TABLE IF NOT EXISTS workflow_agent_session (
|
|
451
|
+
session_id VARCHAR(190) NOT NULL,
|
|
452
|
+
run_id VARCHAR(191) NOT NULL,
|
|
453
|
+
agent_key VARCHAR(191) NOT NULL,
|
|
454
|
+
scope VARCHAR(190) NOT NULL,
|
|
455
|
+
PRIMARY KEY (session_id),
|
|
456
|
+
KEY idx_wfagentsess_run (run_id)
|
|
449
457
|
) COLLATE utf8mb4_bin`,
|
|
450
458
|
`CREATE TABLE IF NOT EXISTS workflow_completion_inbox (
|
|
451
459
|
seq BIGINT NOT NULL AUTO_INCREMENT,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { callKeyOrdinal } from "@sema-agent/core";
|
|
2
2
|
import { oversizeJournalResult } from "@sema-agent/core";
|
|
3
|
+
import { journalEntryOfRow, journalEntryPayload, journalRowPayloadOf } from "../orchestration/workflow-journal-entry.js";
|
|
3
4
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
4
5
|
const DEFAULT_RESUME_CLAIM_TTL_MS = 60 * 60 * 1000;
|
|
5
6
|
export class SqlWorkflowJournalStore {
|
|
@@ -13,16 +14,22 @@ export class SqlWorkflowJournalStore {
|
|
|
13
14
|
return this.db.dialect === "tidb" ? tidb : pg;
|
|
14
15
|
}
|
|
15
16
|
async append(runId, scope, entry) {
|
|
16
|
-
const serialized =
|
|
17
|
-
if (oversizeJournalResult(serialized))
|
|
17
|
+
const serialized = journalRowPayloadOf(entry);
|
|
18
|
+
if (oversizeJournalResult(serialized)) {
|
|
19
|
+
if (journalEntryPayload(entry).parked) {
|
|
20
|
+
throw new Error(`workflow journal: PARKED entry ${entry.callKey} is ${serialized.length} bytes, over the journal result cap — refusing to skip it. ` +
|
|
21
|
+
"Skipping a parked entry would make a resume start a SECOND live agent beside the session already pinned by the pending checkpoint (duplicating pre-approval side effects); " +
|
|
22
|
+
"a completed result may be skipped (resume just re-runs that agent), a park may not.");
|
|
23
|
+
}
|
|
18
24
|
return;
|
|
25
|
+
}
|
|
19
26
|
await this.db.query(this.q("INSERT INTO workflow_journal (run_id, ordinal, scope, call_key, result, created_at_ms) VALUES (?,?,?,?,?,?) " +
|
|
20
27
|
"ON DUPLICATE KEY UPDATE call_key = VALUES(call_key), result = VALUES(result)", "INSERT INTO workflow_journal (run_id, ordinal, scope, call_key, result, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6) " +
|
|
21
28
|
"ON CONFLICT (run_id, ordinal) DO UPDATE SET call_key = EXCLUDED.call_key, result = EXCLUDED.result"), [runId, callKeyOrdinal(entry.callKey), scope, entry.callKey, serialized, Date.now()]);
|
|
22
29
|
}
|
|
23
30
|
async load(runId, scope) {
|
|
24
31
|
const { rows } = await this.db.query(this.q("SELECT call_key, result FROM workflow_journal WHERE run_id = ? AND scope = ? ORDER BY ordinal ASC", "SELECT call_key, result FROM workflow_journal WHERE run_id = $1 AND scope = $2 ORDER BY ordinal ASC"), [runId, scope]);
|
|
25
|
-
return rows.map((r) => (
|
|
32
|
+
return rows.map((r) => journalEntryOfRow(String(r.call_key), String(r.result)));
|
|
26
33
|
}
|
|
27
34
|
locator(runId, _scope) {
|
|
28
35
|
return `/v1/workflows/${runId}/journal`;
|
|
@@ -59,6 +59,7 @@ import type { Pool as PgPool } from "pg";
|
|
|
59
59
|
import { summarizeWorkflowRun, type WorkflowRunStore } from "@sema-agent/core";
|
|
60
60
|
import { type WorkflowCompletionInbox, type WorkflowCompletionInboxEntry } from "../orchestration/workflow-completion-inbox.js";
|
|
61
61
|
import type { WorkflowNotifyJournalStore, WorkflowNotifyJournalEntry } from "../orchestration/workflow-notify-journal.js";
|
|
62
|
+
import type { WorkflowAgentSessionIndex, WorkflowAgentSessionRow } from "../orchestration/workflow-agent-session-index.js";
|
|
62
63
|
import { type SqlDriver } from "./sql-driver.js";
|
|
63
64
|
type WorkflowRun = Parameters<WorkflowRunStore["put"]>[1];
|
|
64
65
|
/** Row cap guard: a run blob beyond this is NOT stored on update (the prior revision stays) — TiDB's
|
|
@@ -153,6 +154,29 @@ export declare class SqlWorkflowNotifyJournalStore implements WorkflowNotifyJour
|
|
|
153
154
|
reapAcked(before: number): Promise<number>;
|
|
154
155
|
get(runId: string): Promise<WorkflowNotifyJournalEntry | null>;
|
|
155
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* S-185 车CM —— **workflow 出身 park 的有界 join 索引** SQL 双生(契约与纪律的唯一属主 =
|
|
159
|
+
* {@link import("../orchestration/workflow-agent-session-index.js").WorkflowAgentSessionIndex} 的文件头,
|
|
160
|
+
* 这里只记方言差)。行是 `WorkflowRun` 的派生投影,写者只有一个(Journaling 装饰器的写观察点)。
|
|
161
|
+
*
|
|
162
|
+
* ── 方言差,保持显式 ──────────────────────────────────────────────────────────────────────────
|
|
163
|
+
* - `?` 占位 vs `$n`,且 `syncRun` 的删除腿在 PG 上要按 `params.length` 记位(与 `listByScope` 同因)。
|
|
164
|
+
* - 「删掉这条 run 里已不在 rows 里的旧行」:TiDB `session_id NOT IN (?,?,…)`(动态占位数)vs
|
|
165
|
+
* PG `session_id <> ALL($n::text[])`(数组绑定)—— 两边同一件事,语句结构不同(reap 的批删同先例)。
|
|
166
|
+
* - upsert:TiDB `REPLACE INTO`(整行替换)vs PG `INSERT … ON CONFLICT (session_id) DO UPDATE`。
|
|
167
|
+
* - schema 属主同店内其余表:TiDB DDL 在 tidb-pool.ts,PG DDL 在 pg-pool.ts(店不建表)。
|
|
168
|
+
*
|
|
169
|
+
* 🔴 **写序**:先 upsert 再删。反过来(先删后 upsert)会在两条语句之间留出一个**索引行不存在**的窗口,
|
|
170
|
+
* 而这期间进来的 `/decide` 会诚实 miss ⇒ 一次本可受理的批准被退回。先 upsert 的最坏形是窗口内多一条
|
|
171
|
+
* 旧行(读口按 session_id 精确查,取 run 后还要逐字比对赎回键 ⇒ 多余的行只会 miss,不会错配)。
|
|
172
|
+
*/
|
|
173
|
+
export declare class SqlWorkflowAgentSessionIndex implements WorkflowAgentSessionIndex {
|
|
174
|
+
private readonly db;
|
|
175
|
+
constructor(db: SqlDriver);
|
|
176
|
+
private q;
|
|
177
|
+
syncRun(runId: string, rows: readonly WorkflowAgentSessionRow[]): Promise<void>;
|
|
178
|
+
findByAgentSession(sessionId: string): Promise<WorkflowAgentSessionRow | null>;
|
|
179
|
+
}
|
|
156
180
|
/** MySQL-protocol (TiDB) bindings — historical class names preserved; `onWarn` is an ADDITIVE optional 2nd
|
|
157
181
|
* ctor arg (existing 1-arg call sites are unaffected — see {@link SqlWorkflowRunStore}'s C5 trace channel). */
|
|
158
182
|
export declare class TiDBWorkflowRunStore extends SqlWorkflowRunStore {
|
|
@@ -175,5 +199,11 @@ export declare class PgWorkflowCompletionInbox extends SqlWorkflowCompletionInbo
|
|
|
175
199
|
export declare class PgWorkflowNotifyJournalStore extends SqlWorkflowNotifyJournalStore {
|
|
176
200
|
constructor(pool: PgPool);
|
|
177
201
|
}
|
|
202
|
+
export declare class TiDBWorkflowAgentSessionIndex extends SqlWorkflowAgentSessionIndex {
|
|
203
|
+
constructor(pool: MySqlPool);
|
|
204
|
+
}
|
|
205
|
+
export declare class PgWorkflowAgentSessionIndex extends SqlWorkflowAgentSessionIndex {
|
|
206
|
+
constructor(pool: PgPool);
|
|
207
|
+
}
|
|
178
208
|
export {};
|
|
179
209
|
//# sourceMappingURL=workflow-run-store-sql.d.ts.map
|
|
@@ -277,6 +277,36 @@ export class SqlWorkflowNotifyJournalStore {
|
|
|
277
277
|
};
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
|
+
export class SqlWorkflowAgentSessionIndex {
|
|
281
|
+
db;
|
|
282
|
+
constructor(db) {
|
|
283
|
+
this.db = db;
|
|
284
|
+
}
|
|
285
|
+
q(tidb, pg) {
|
|
286
|
+
return this.db.dialect === "tidb" ? tidb : pg;
|
|
287
|
+
}
|
|
288
|
+
async syncRun(runId, rows) {
|
|
289
|
+
for (const r of rows) {
|
|
290
|
+
await this.db.query(this.q("REPLACE INTO workflow_agent_session (session_id, run_id, agent_key, scope) VALUES (?,?,?,?)", `INSERT INTO workflow_agent_session (session_id, run_id, agent_key, scope) VALUES ($1,$2,$3,$4)
|
|
291
|
+
ON CONFLICT (session_id) DO UPDATE SET run_id = EXCLUDED.run_id, agent_key = EXCLUDED.agent_key, scope = EXCLUDED.scope`), [r.sessionId, r.runId, r.agentKey, r.scope]);
|
|
292
|
+
}
|
|
293
|
+
const keep = rows.map((r) => r.sessionId);
|
|
294
|
+
if (this.db.dialect === "tidb") {
|
|
295
|
+
const holes = keep.map(() => "?").join(",");
|
|
296
|
+
await this.db.query(`DELETE FROM workflow_agent_session WHERE run_id = ?${keep.length > 0 ? ` AND session_id NOT IN (${holes})` : ""}`, [runId, ...keep]);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
await this.db.query(`DELETE FROM workflow_agent_session WHERE run_id = $1${keep.length > 0 ? " AND session_id <> ALL($2::text[])" : ""}`, keep.length > 0 ? [runId, keep] : [runId]);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async findByAgentSession(sessionId) {
|
|
303
|
+
const { rows } = await this.db.query(this.q("SELECT session_id, run_id, agent_key, scope FROM workflow_agent_session WHERE session_id = ?", "SELECT session_id, run_id, agent_key, scope FROM workflow_agent_session WHERE session_id = $1"), [sessionId]);
|
|
304
|
+
const r = rows[0];
|
|
305
|
+
if (!r)
|
|
306
|
+
return null;
|
|
307
|
+
return { sessionId: String(r.session_id), runId: String(r.run_id), agentKey: String(r.agent_key), scope: String(r.scope) };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
280
310
|
export class TiDBWorkflowRunStore extends SqlWorkflowRunStore {
|
|
281
311
|
constructor(pool, onWarn) {
|
|
282
312
|
super(mysqlDriver(pool), onWarn);
|
|
@@ -307,4 +337,14 @@ export class PgWorkflowNotifyJournalStore extends SqlWorkflowNotifyJournalStore
|
|
|
307
337
|
super(pgDriver(pool));
|
|
308
338
|
}
|
|
309
339
|
}
|
|
340
|
+
export class TiDBWorkflowAgentSessionIndex extends SqlWorkflowAgentSessionIndex {
|
|
341
|
+
constructor(pool) {
|
|
342
|
+
super(mysqlDriver(pool));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
export class PgWorkflowAgentSessionIndex extends SqlWorkflowAgentSessionIndex {
|
|
346
|
+
constructor(pool) {
|
|
347
|
+
super(pgDriver(pool));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
310
350
|
//# sourceMappingURL=workflow-run-store-sql.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {} from "@sema-agent/core";
|
|
2
|
+
import { operatorAsk } from "../operator-ask.js";
|
|
2
3
|
export function routeOrchestration(s) {
|
|
3
4
|
if (s.explicitMode)
|
|
4
5
|
return { mode: s.explicitMode, reason: `explicit:${s.explicitMode}` };
|
|
@@ -40,7 +41,7 @@ export function isIsolatedExecEnv(provider, runtimeClass) {
|
|
|
40
41
|
}
|
|
41
42
|
const WRITE_HAND_TOOLS = new Set(["Edit", "Write", "NotebookEdit"]);
|
|
42
43
|
export function supPostureOverrides() {
|
|
43
|
-
const ask = (toolName) => ({
|
|
44
|
+
const ask = (toolName) => operatorAsk(`supervisor routing(capability-danger:${toolName})`, `${toolName} gated by supervisor routing (capability-danger task)`);
|
|
44
45
|
const writeGate = {
|
|
45
46
|
check: (req) => (WRITE_HAND_TOOLS.has(req.toolName) ? ask(req.toolName) : { action: "allow" }),
|
|
46
47
|
};
|
package/dist/run-local.js
CHANGED
|
@@ -190,7 +190,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
190
190
|
config.mcpServers = resolveMcpServers(effective.mcp, logger);
|
|
191
191
|
if (effective?.a2a)
|
|
192
192
|
config.a2aPeers = resolveA2aPeers(effective.a2a, logger);
|
|
193
|
-
applyCenterReadFace(config, r.effective, logger);
|
|
193
|
+
applyCenterReadFace(config, r.effective, logger, { phase: "boot" });
|
|
194
194
|
logger.info("config_loaded", { source: configProvider.kind, version: r.effective.version });
|
|
195
195
|
}
|
|
196
196
|
}
|
package/dist/runs.js
CHANGED
|
@@ -88,6 +88,8 @@ export function resumeAtHttpStatus(result) {
|
|
|
88
88
|
return 400;
|
|
89
89
|
if (code === "config.invalid_checkpoint_store")
|
|
90
90
|
return 400;
|
|
91
|
+
if (code === "config.tool_mount_denied")
|
|
92
|
+
return 400;
|
|
91
93
|
if (code === "config.memory_capture_unsupported")
|
|
92
94
|
return 409;
|
|
93
95
|
if (!code.startsWith("resume_at."))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { combinePolicies, COARSE_SHELL_TOOLS as CORE_COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, DEFAULT_SUBAGENT_TOOL_NAME, parseLeadingCommandName, tightenTaskSpec, } from "@sema-agent/core";
|
|
2
2
|
import { SAFETY_MERGE_SPEC } from "@sema-agent/settings-schema";
|
|
3
3
|
import { currentGovernanceAskMarks } from "./governance-ask-marks.js";
|
|
4
|
+
import { operatorAsk } from "./operator-ask.js";
|
|
4
5
|
export function isDelegationToolName(name) {
|
|
5
6
|
return name === DEFAULT_SUBAGENT_TOOL_NAME;
|
|
6
7
|
}
|
|
@@ -13,18 +14,18 @@ export const COARSE_SHELL_TOOLS_MIRROR = COARSE_SHELL_TOOLS;
|
|
|
13
14
|
function createCommandAskListPolicy(askCommands, tools = COARSE_SHELL_TOOLS) {
|
|
14
15
|
const askSet = new Set(askCommands);
|
|
15
16
|
const shellTools = new Set(tools);
|
|
16
|
-
const ask = (message) => (
|
|
17
|
+
const ask = (message, rule) => operatorAsk(rule, message);
|
|
17
18
|
return {
|
|
18
19
|
check(req) {
|
|
19
20
|
if (!shellTools.has(req.toolName))
|
|
20
21
|
return { action: "allow" };
|
|
21
22
|
const command = req.args?.command;
|
|
22
23
|
if (typeof command !== "string")
|
|
23
|
-
return ask(`tool "${req.toolName}" call has no parseable command string
|
|
24
|
+
return ask(`tool "${req.toolName}" call has no parseable command string`, "commandPolicy(unparseable command)");
|
|
24
25
|
const parsed = parseLeadingCommandName(command);
|
|
25
26
|
if ("reject" in parsed)
|
|
26
|
-
return ask(`command is not a single simple command (${parsed.reject})
|
|
27
|
-
return askSet.has(parsed.name) ? ask(`command "${parsed.name}" requires approval by policy`) : { action: "allow" };
|
|
27
|
+
return ask(`command is not a single simple command (${parsed.reject})`, "commandPolicy(argv[0] unparseable)");
|
|
28
|
+
return askSet.has(parsed.name) ? ask(`command "${parsed.name}" requires approval by policy`, `commandPolicy(${parsed.name}=ask)`) : { action: "allow" };
|
|
28
29
|
},
|
|
29
30
|
};
|
|
30
31
|
}
|
package/dist/tool-approval.d.ts
CHANGED
|
@@ -143,6 +143,26 @@ export interface ToolApprovalFrame {
|
|
|
143
143
|
* ask」,治理策略产的与普通策略产的在这一个词上同形 ⇒ 顶替不了(逐字论证见 `governance-ask-marks.ts` 顶注)。
|
|
144
144
|
*/
|
|
145
145
|
origin?: string;
|
|
146
|
+
/**
|
|
147
|
+
* **S-185 / [ref]**(core 7.10.0;**ADDITIVE**,`"tool_approval"` only)—— 这一问**为什么**到了人手上:
|
|
148
|
+
* auto 档的分类器被咨询过、而它**跑不了**。`cause` = core 的闭三词
|
|
149
|
+
* (`AUTO_MODE_UNAVAILABLE_CAUSES` = `error` / `timeout` / `breaker_open`),`AskRequest.classifierUnavailable`
|
|
150
|
+
* 逐字透传。
|
|
151
|
+
*
|
|
152
|
+
* 🔴 **缺席 ≠「分类器好着呢」**:缺席同时覆盖三形 —— 分类器答上了 / 这只 ask 没资格走分类器
|
|
153
|
+
* (`classifierMayAnswer` 的闭表)/ 本部署压根没接分类器。消费端**禁**把缺席读成对分类器健康的断言。
|
|
154
|
+
* 另注:`parse_error`(分类器跑了但答得出格)**不盖这一位** —— 那是另一句话,core 顶注逐字。
|
|
155
|
+
*
|
|
156
|
+
* 🔴 **不枚举词表**(值形是 `{cause: string}` 而不是本仓自铸的联合):词表单一属主在 core,抄一份会把
|
|
157
|
+
* core 加的新词吞成缺席。窄读只判「对象 ∧ `cause` 非空串 ∧ 无多余成员」(`readClassifierUnavailable`,
|
|
158
|
+
* 帧与卡的**唯一**铸造点 ⇒ 两面结构性同值)。
|
|
159
|
+
*
|
|
160
|
+
* 🔴 **echo-only,零消费**:熔断/超时的处置全在 core 的分类器站,server 不许据本键自铸第二套回落判据
|
|
161
|
+
* —— 同 `origin` / `denialLimitFallback` 两条顶注的同一条禁令(同一语义面两个写者)。
|
|
162
|
+
*/
|
|
163
|
+
classifierUnavailable?: {
|
|
164
|
+
cause: string;
|
|
165
|
+
};
|
|
146
166
|
/**
|
|
147
167
|
* **E-14**([ref]② Trojan Source 族;**ADDITIVE**,`"tool_approval"` only)—— 这只 ask 的**工具输入**
|
|
148
168
|
* (`AskRequest.args`)里含 bidi 控制符(LRM/RLM、嵌入/覆写、隔离符;字符类属主 `text-bidi.ts`)。
|
package/dist/tool-approval.js
CHANGED
|
@@ -8,7 +8,7 @@ import { approvalPayloadFingerprint } from "./plugins/approval-payload-fingerpri
|
|
|
8
8
|
import { createLogger } from "./observability/logger.js";
|
|
9
9
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
10
10
|
import { deriveAskId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
|
|
11
|
-
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
11
|
+
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readClassifierUnavailable, readProbeCause, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
12
12
|
import { projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
13
13
|
import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
|
|
14
14
|
const defaultLogger = createLogger();
|
|
@@ -844,6 +844,7 @@ export class ToolApprovalCoordinator {
|
|
|
844
844
|
...(ruleLaneMaterial !== undefined ? { ruleOffers: ruleLaneMaterial.offers } : {}),
|
|
845
845
|
...((a) => (a !== undefined ? { ruleOffersAbsence: a } : {}))(readRuleOffersAbsence(req)),
|
|
846
846
|
...((f) => (f !== undefined ? { denialLimitFallback: f } : {}))(readDenialLimitFallback(req)),
|
|
847
|
+
...((c) => (c !== undefined ? { classifierUnavailable: c } : {}))(readClassifierUnavailable(req)),
|
|
847
848
|
...((c) => (c !== undefined ? { probeCause: c } : {}))(readProbeCause(req)),
|
|
848
849
|
...((c) => (c !== undefined ? { ruleEvidence: c } : {}))(readRuleEvidence(req)),
|
|
849
850
|
...(bounded.omitted ? { argsOmitted: true } : { args: bounded.args }),
|
|
@@ -28,7 +28,7 @@ type BgNotifExcluded = "kind" | "sessionScoped" | "owner" | "scope" | "descripti
|
|
|
28
28
|
type _GuardBgNotif = AssertAllKeysHandled<Exclude<keyof BackgroundChildEvent, BgNotifProjected | BgNotifExcluded>>;
|
|
29
29
|
type RosterProjected = "name" | "agentId" | "sessionId" | "toolUseId" | "owner" | "scope" | "sessionScoped" | "rootSessionId" | "model" | "modelFallback" | "createdAt";
|
|
30
30
|
type _GuardRoster = AssertAllKeysHandled<Exclude<keyof RosterEntry, RosterProjected>>;
|
|
31
|
-
type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin";
|
|
31
|
+
type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "classifierUnavailable";
|
|
32
32
|
type AskExcluded = "preview" | "principal" | "riskAxes" | "boundInputHash" | "isDelegatedChild" | "probeReason" | "hasBidiControls" | "previewWithheld" | "execCwd";
|
|
33
33
|
type _GuardAsk = AssertAllKeysHandled<Exclude<keyof AskRequest, AskProjected | AskExcluded>>;
|
|
34
34
|
type TaskEventHandled = "text_delta" | "reasoning_delta" | "tool_start" | "tool_end" | "turn_end" | "compacted" | "diagnostics" | "message_committed" | "status" | "task_notification" | "task_progress" | "steering_injected" | "workspace_changed" | "done" | "context_usage" | "compaction_outcome" | "human_input" | "wiring_manifest" | "text_end" | "tool_roster_delta";
|
|
@@ -38,14 +38,14 @@ type _GuardMailbox = AssertAllKeysHandled<Exclude<keyof MailboxMessage, MailboxP
|
|
|
38
38
|
type MailboxAppendProjected = "from" | "content" | "sentAt" | "hopChain" | "peerMeta";
|
|
39
39
|
type _GuardMailboxAppend = AssertAllKeysHandled<Exclude<keyof MailboxAppendMessage, MailboxAppendProjected>>;
|
|
40
40
|
type PermissionTraceKind = Extract<TraceEvent["kind"], `permission.${string}`>;
|
|
41
|
-
type PermissionTraceProjected = "permission.persisted_rule_allowed" | "permission.rule_store_unreadable";
|
|
41
|
+
type PermissionTraceProjected = "permission.persisted_rule_allowed" | "permission.rule_store_unreadable" | "permission.read_only_allowed";
|
|
42
42
|
type PermissionTraceDropped = "permission.sandbox_admitted" | "permission.rule_sync_resurrected" | "permission.rule_sync_dropped" | "permission.org_snapshot_unavailable";
|
|
43
43
|
type _GuardPermissionTrace = AssertAllKeysHandled<Exclude<PermissionTraceKind, PermissionTraceProjected | PermissionTraceDropped>>;
|
|
44
44
|
type _GuardPermissionTraceReverse = AssertAllKeysHandled<Exclude<PermissionTraceProjected | PermissionTraceDropped, PermissionTraceKind>>;
|
|
45
45
|
/** `T` 非 `never` 时收敛到 `never`(空集 ⇒ 残留 `"EMPTY"` ⇒ tsc 红)。 */
|
|
46
46
|
type AssertNonEmpty<T> = [T] extends [never] ? "EMPTY" : never;
|
|
47
47
|
type _GuardPermissionTraceNonEmpty = AssertAllKeysHandled<AssertNonEmpty<PermissionTraceKind>>;
|
|
48
|
-
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin";
|
|
48
|
+
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "classifierUnavailable";
|
|
49
49
|
type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
|
|
50
50
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
51
51
|
type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested";
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* 同文件 G1 e2e 的全码扇出夹具、以及契约文档附录 D.3 那张表(含**小节标题里的码数** —— 那道门本批
|
|
17
17
|
* 刚立,立完就在下一次加码时自己咬住了)。
|
|
18
18
|
*/
|
|
19
|
-
export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped"];
|
|
19
|
+
export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable"];
|
|
20
20
|
export type EngineNoticeWireCode = (typeof ENGINE_NOTICE_WIRE_CODES)[number];
|
|
21
21
|
/** 白名单谓词(单点):路由与门都读这一个,不许第二处手抄码串。 */
|
|
22
22
|
export declare function isEngineNoticeWireCode(code: string): code is EngineNoticeWireCode;
|
|
@@ -21,6 +21,7 @@ export const ENGINE_NOTICE_WIRE_CODES = [
|
|
|
21
21
|
"peer.idle_subscription",
|
|
22
22
|
"classifier.denial_limit",
|
|
23
23
|
"mcp.injection_dropped",
|
|
24
|
+
"delegation.ask_unresolvable",
|
|
24
25
|
];
|
|
25
26
|
const WIRE_CODES = new Set(ENGINE_NOTICE_WIRE_CODES);
|
|
26
27
|
export function isEngineNoticeWireCode(code) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.69.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",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@sema-agent/core": "7.
|
|
58
|
-
"@sema-agent/settings-schema": "1.
|
|
57
|
+
"@sema-agent/core": "7.11.2",
|
|
58
|
+
"@sema-agent/settings-schema": "1.10.0",
|
|
59
59
|
"e2b": "^2.28.0",
|
|
60
60
|
"libsodium-wrappers": "^0.8.4",
|
|
61
61
|
"mysql2": "^3.22.4",
|