@sema-agent/server 4.1.0 → 4.1.2
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/approval.d.ts +3 -2
- package/dist/approval.js +0 -6
- package/dist/bake-runner/main.js +1 -5
- package/dist/boot/config-center.js +2 -1
- package/dist/boot/execution-env.d.ts +2 -2
- package/dist/boot/execution-env.js +17 -12
- package/dist/boot/resolve-spec.js +3 -3
- package/dist/bounded-session-map.d.ts +25 -0
- package/dist/bounded-session-map.js +37 -0
- package/dist/capabilities/center-plugins.d.ts +6 -1
- package/dist/capabilities/center-plugins.js +32 -9
- package/dist/capabilities/center-prompts.js +2 -1
- package/dist/capabilities/sandbox-file-send.d.ts +2 -2
- package/dist/capabilities/sandbox-file-send.js +6 -4
- package/dist/capabilities/select-environment-tool.d.ts +1 -2
- package/dist/capabilities/select-environment-tool.js +7 -11
- package/dist/capabilities/skills.d.ts +4 -0
- package/dist/capabilities/skills.js +5 -4
- package/dist/config-center/skills-mcp.js +2 -1
- package/dist/config-provider.js +6 -0
- package/dist/digest-form.d.ts +15 -0
- package/dist/digest-form.js +15 -0
- package/dist/http/route-ctx.d.ts +3 -8
- package/dist/http/routes/approvals-assistant.js +3 -2
- package/dist/http/routes/runs.js +2 -2
- package/dist/http/routes/session-sync.js +11 -11
- package/dist/http/server.d.ts +2 -2
- package/dist/http/server.js +18 -40
- package/dist/http/verify-rounds.d.ts +24 -0
- package/dist/http/verify-rounds.js +18 -0
- package/dist/images/bake-validate.d.ts +5 -2
- package/dist/images/bake-validate.js +5 -2
- package/dist/index.d.ts +1 -0
- package/dist/leader/grader-env-factory.js +1 -2
- package/dist/leader/merge.js +1 -1
- package/dist/leader/repair-oracle.js +1 -2
- package/dist/per-task-image.d.ts +1 -16
- package/dist/per-task-image.js +21 -11
- package/dist/plugins/approval-store-sql.js +2 -3
- package/dist/plugins/checkpoint-store-sql.js +2 -3
- package/dist/plugins/image-bake-store-sql.js +3 -3
- package/dist/plugins/outcome-ledger-sql.js +2 -3
- package/dist/plugins/remote-env-e2b.js +1 -5
- package/dist/plugins/remote-shell.d.ts +2 -1
- package/dist/plugins/remote-shell.js +2 -1
- package/dist/plugins/run-store-sql.js +3 -3
- package/dist/plugins/sql-driver.d.ts +17 -1
- package/dist/plugins/sql-driver.js +12 -0
- package/dist/prompts-domain-validate.js +3 -3
- package/dist/runs.d.ts +2 -4
- package/dist/security.d.ts +11 -0
- package/dist/security.js +11 -0
- package/dist/session-sync.d.ts +12 -1
- package/dist/session-sync.js +15 -3
- package/package.json +1 -1
|
@@ -60,7 +60,12 @@
|
|
|
60
60
|
* $n::jsonb) · null-safe compare (<=> vs IS NOT DISTINCT FROM) AND its placeholder-arity fallout ·
|
|
61
61
|
* key-column byte semantics (VARBINARY vs COLLATE "C") · isolation/txn verbs · error classification
|
|
62
62
|
* (ER_DUP_ENTRY/errno vs SQLSTATE, sqlMessage vs err.constraint) · PG-only protocol-byte handling
|
|
63
|
-
* (pgSafeJsonStringify / pgProtocolJsonStringify / pgSanitizeText / pgHasUnstorable) · DDL.
|
|
63
|
+
* (pgSafeJsonStringify / pgProtocolJsonStringify / pgSanitizeText / pgHasUnstorable) · DDL. Each arm's
|
|
64
|
+
* BEHAVIOR (what pgSafeJsonStringify/pgProtocolJsonStringify actually do to the bytes) stays written out
|
|
65
|
+
* in `pg-safe-json.ts`, untouched — `dialectJsonEncoder`/`dialectProtocolJsonEncoder` below (design/158
|
|
66
|
+
* redesign①) only collect the identical `dialect === "tidb" ? JSON.stringify(v) : pgSafe…(v)` DISPATCH
|
|
67
|
+
* ternary that five call sites duplicated verbatim; they are not a new abstraction over the encodings
|
|
68
|
+
* themselves, so this does not violate the rule above.
|
|
64
69
|
*
|
|
65
70
|
* WHAT MAY BE PARAMETERIZED
|
|
66
71
|
* result unwrapping (rows/affected) · transaction plumbing · numeric coercion of BIGINT-as-string
|
|
@@ -99,4 +104,15 @@ export interface SqlDriver extends SqlExec {
|
|
|
99
104
|
export declare function mysqlDriver(pool: MySqlPool): SqlDriver;
|
|
100
105
|
/** PostgreSQL driver. Transaction control is issued as STATEMENTS (node-pg has no native verbs). */
|
|
101
106
|
export declare function pgDriver(pool: PgPool): SqlDriver;
|
|
107
|
+
/** design/158 redesign① — the "safe" JSON-column encoder DISPATCH (run-store/outcome-ledger's identical
|
|
108
|
+
* ternary, collected): TiDB stores `JSON.stringify` verbatim; PG goes through `pgSafeJsonStringify`'s
|
|
109
|
+
* protocol-byte defenses (a raw NUL/lone-surrogate would otherwise throw mid-write). Returns a 1-arg
|
|
110
|
+
* encoder; call sites invoke `dialectJsonEncoder(this.db.dialect)(value)` inline — the dispatch is the
|
|
111
|
+
* collected thing, not a cached field. */
|
|
112
|
+
export declare const dialectJsonEncoder: (dialect: SqlDialect) => ((v: unknown) => string);
|
|
113
|
+
/** design/158 redesign① — the "protocol" JSON-column encoder DISPATCH (approval-store/checkpoint-store's
|
|
114
|
+
* identical ternary, collected): TiDB stores `JSON.stringify` verbatim (the `label` arg is ignored on that
|
|
115
|
+
* arm — TiDB has no protocol-byte envelope to name); PG goes through `pgProtocolJsonStringify(v, label)`,
|
|
116
|
+
* whose `label` names the field in its error text on an unstorable-byte reject. */
|
|
117
|
+
export declare const dialectProtocolJsonEncoder: (dialect: SqlDialect) => ((v: unknown, label: string) => string);
|
|
102
118
|
//# sourceMappingURL=sql-driver.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { pgSafeJsonStringify, pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
1
2
|
/** mysql2 hands back `[rows]` for a SELECT and `[ResultSetHeader]` for a write. */
|
|
2
3
|
function mysqlResult(r) {
|
|
3
4
|
if (Array.isArray(r))
|
|
@@ -60,4 +61,15 @@ export function pgDriver(pool) {
|
|
|
60
61
|
},
|
|
61
62
|
};
|
|
62
63
|
}
|
|
64
|
+
/** design/158 redesign① — the "safe" JSON-column encoder DISPATCH (run-store/outcome-ledger's identical
|
|
65
|
+
* ternary, collected): TiDB stores `JSON.stringify` verbatim; PG goes through `pgSafeJsonStringify`'s
|
|
66
|
+
* protocol-byte defenses (a raw NUL/lone-surrogate would otherwise throw mid-write). Returns a 1-arg
|
|
67
|
+
* encoder; call sites invoke `dialectJsonEncoder(this.db.dialect)(value)` inline — the dispatch is the
|
|
68
|
+
* collected thing, not a cached field. */
|
|
69
|
+
export const dialectJsonEncoder = (dialect) => dialect === "tidb" ? JSON.stringify : pgSafeJsonStringify;
|
|
70
|
+
/** design/158 redesign① — the "protocol" JSON-column encoder DISPATCH (approval-store/checkpoint-store's
|
|
71
|
+
* identical ternary, collected): TiDB stores `JSON.stringify` verbatim (the `label` arg is ignored on that
|
|
72
|
+
* arm — TiDB has no protocol-byte envelope to name); PG goes through `pgProtocolJsonStringify(v, label)`,
|
|
73
|
+
* whose `label` names the field in its error text on an unstorable-byte reject. */
|
|
74
|
+
export const dialectProtocolJsonEncoder = (dialect) => dialect === "tidb" ? (v) => JSON.stringify(v) : pgProtocolJsonStringify;
|
|
63
75
|
//# sourceMappingURL=sql-driver.js.map
|
|
@@ -16,9 +16,9 @@ import { createRequire } from "node:module";
|
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
17
|
import { dirname, join } from "node:path";
|
|
18
18
|
import { verifyPromptArtifact } from "@sema-agent/core";
|
|
19
|
+
import { SHA256_DIGEST_RE } from "./digest-form.js";
|
|
19
20
|
const ID_RE = /^[a-z0-9][a-z0-9/._-]*$/; // core assemble 同形(≤128、非 core/ 前缀在下面单查)
|
|
20
21
|
const SLOTS = new Set(["identity", "scenario", "behavior"]);
|
|
21
|
-
const HASH_RE = /^sha256:[0-9a-f]{64}$/;
|
|
22
22
|
function declarationIssue(d, where) {
|
|
23
23
|
if (d === null || typeof d !== "object")
|
|
24
24
|
return `${where}: declaration is not an object`;
|
|
@@ -35,7 +35,7 @@ function declarationIssue(d, where) {
|
|
|
35
35
|
// contentHash?),hash 缺席/被 core 丢弃(错值)后**同长度文本编辑不改 artifactDigest=不重 pin**,
|
|
36
36
|
// 恰是撤 restart 臂所依赖的审计不变量被击穿。center 链路恒逐 section 铸([1065]),正常路径零影响;
|
|
37
37
|
// 这里拒的是坏发布/被改载荷(整拒候选,LKG/内置继续服务)。
|
|
38
|
-
if (typeof o.contentHash !== "string" || !
|
|
38
|
+
if (typeof o.contentHash !== "string" || !SHA256_DIGEST_RE.test(o.contentHash))
|
|
39
39
|
return `${where}: contentHash is required (sha256:<64hex> — the epoch declaration axis needs it for byte-level change detection)`;
|
|
40
40
|
const expected = `sha256:${createHash("sha256").update(o.text).digest("hex")}`;
|
|
41
41
|
if (o.contentHash !== expected)
|
|
@@ -53,7 +53,7 @@ export function validateCenterPrompts(raw) {
|
|
|
53
53
|
const p = raw;
|
|
54
54
|
if (typeof p.packId !== "string" || !/^center:[0-9a-f]{12}$/.test(p.packId))
|
|
55
55
|
return { ok: false, error: "bad packId form (center:<digest12>)" };
|
|
56
|
-
if (typeof p.contentDigest !== "string" || !
|
|
56
|
+
if (typeof p.contentDigest !== "string" || !SHA256_DIGEST_RE.test(p.contentDigest))
|
|
57
57
|
return { ok: false, error: "bad contentDigest form" };
|
|
58
58
|
// 发版复审 F2/F4 两条硬化:
|
|
59
59
|
// - 数组内 id 必须唯一(core composer 对 duplicate section id 是 THROW——独立判形查不出对撞,必须
|
package/dist/runs.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { ElicitationCoordinator } from "./elicitation.js";
|
|
|
7
7
|
import type { QuestionCoordinator } from "./question.js";
|
|
8
8
|
import { type FleetRunPublisher } from "./fleet/fleet-bus.js";
|
|
9
9
|
import { type WorkflowCompletionInbox } from "./orchestration/workflow-completion-inbox.js";
|
|
10
|
+
import type { VerifyRoundsSpec } from "./http/verify-rounds.js";
|
|
10
11
|
/**
|
|
11
12
|
* stoppedBy (core 1.252): a service cancel is a USER stop — mark the run's still-running background
|
|
12
13
|
* children BEFORE core's teardown reaps them (bare abort = attribution falls back to "system"; core's own
|
|
@@ -201,10 +202,7 @@ export declare function evictIfConflict(runner: Runner, sessionId: string | unde
|
|
|
201
202
|
* only — a suspended run is steered durably via the checkpoint's `setPendingSteer` instead, and only the
|
|
202
203
|
* plain-stream path holds a steerable stream (the verify/cascade branches return a result, not a stream).
|
|
203
204
|
*/
|
|
204
|
-
export declare function runInBackground(runner: Runner, spec: TaskSpec, runStore: RunStore, taskId: string, metrics?: Metrics, principal?: string, verify?:
|
|
205
|
-
maxRounds: number;
|
|
206
|
-
costCeilingMicroUsd?: number;
|
|
207
|
-
}, // 快审 F1:number 参升整对象——cost 顶随传
|
|
205
|
+
export declare function runInBackground(runner: Runner, spec: TaskSpec, runStore: RunStore, taskId: string, metrics?: Metrics, principal?: string, verify?: VerifyRoundsSpec, // 快审 F1:number 参升整对象——cost 顶随传
|
|
208
206
|
cascade?: CascadeConfig, instrumentDegenerate?: (result: TaskResult) => void, planCacheProbe?: {
|
|
209
207
|
record: (scope: string | undefined, objective: string, completed: boolean) => void;
|
|
210
208
|
}, persistThinking?: boolean, inflight?: Map<string, AbortController>, preemptable?: Map<string, AbortController>, steerable?: Map<string, TaskStream>, modelUsage?: ModelUsageTracker, elicitation?: ElicitationCoordinator,
|
package/dist/security.d.ts
CHANGED
|
@@ -194,6 +194,17 @@ export declare const PRINCIPAL_MAX_LENGTH = 190;
|
|
|
194
194
|
export declare const RESERVED_PRINCIPALS: readonly string[];
|
|
195
195
|
export declare const RESERVED_PRINCIPAL_PREFIXES: readonly string[];
|
|
196
196
|
export declare function assertPrincipalShape(principal: string): void;
|
|
197
|
+
/** The checkpoint `scope` column's single-user/anonymous sentinel — the same "_" documented above
|
|
198
|
+
* ({@link RESERVED_PRINCIPALS}) as the checkpoint/sendfile/resource-suspend scope family's shared value.
|
|
199
|
+
* Single attested constant + codec pair (naming precedent: {@link SENDFILE_SINGLE_USER_SCOPE} in
|
|
200
|
+
* ./plugins/send-file-ledger.js) so every checkpoint scope read/write goes through one place instead of
|
|
201
|
+
* each call site re-deriving the "_" ⇄ no-principal mapping inline. */
|
|
202
|
+
export declare const CHECKPOINT_PUBLIC_SCOPE: "_";
|
|
203
|
+
/** Encode a principal (or none) as the checkpoint `scope` column value. */
|
|
204
|
+
export declare const encodeCheckpointScope: (principal: string | null | undefined) => string;
|
|
205
|
+
/** Decode a checkpoint `scope` column value back to a principal — {@link CHECKPOINT_PUBLIC_SCOPE} maps to
|
|
206
|
+
* `undefined` (no principal), everything else passes through verbatim. */
|
|
207
|
+
export declare const decodeCheckpointScope: (scope: string) => string | undefined;
|
|
197
208
|
/** Read the authenticated principal from the trusted header. Never from the body. */
|
|
198
209
|
export declare function principalFrom(req: IncomingMessage, config: ServiceConfig): string | undefined;
|
|
199
210
|
/** Header carrying the crypto-verified principal JWT on a direct-door worker (the issuer signs it; the worker only
|
package/dist/security.js
CHANGED
|
@@ -256,6 +256,17 @@ export function assertPrincipalShape(principal) {
|
|
|
256
256
|
throw new HttpError(400, `principal exceeds ${PRINCIPAL_MAX_LENGTH} characters (the scope-column width every store pins, e.g. sendfile_link.scope VARCHAR(190)); got ${principal.length}`, { code: "principal_too_long" });
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
+
/** The checkpoint `scope` column's single-user/anonymous sentinel — the same "_" documented above
|
|
260
|
+
* ({@link RESERVED_PRINCIPALS}) as the checkpoint/sendfile/resource-suspend scope family's shared value.
|
|
261
|
+
* Single attested constant + codec pair (naming precedent: {@link SENDFILE_SINGLE_USER_SCOPE} in
|
|
262
|
+
* ./plugins/send-file-ledger.js) so every checkpoint scope read/write goes through one place instead of
|
|
263
|
+
* each call site re-deriving the "_" ⇄ no-principal mapping inline. */
|
|
264
|
+
export const CHECKPOINT_PUBLIC_SCOPE = "_";
|
|
265
|
+
/** Encode a principal (or none) as the checkpoint `scope` column value. */
|
|
266
|
+
export const encodeCheckpointScope = (principal) => principal ?? CHECKPOINT_PUBLIC_SCOPE;
|
|
267
|
+
/** Decode a checkpoint `scope` column value back to a principal — {@link CHECKPOINT_PUBLIC_SCOPE} maps to
|
|
268
|
+
* `undefined` (no principal), everything else passes through verbatim. */
|
|
269
|
+
export const decodeCheckpointScope = (scope) => (scope === CHECKPOINT_PUBLIC_SCOPE ? undefined : scope);
|
|
259
270
|
/** Read the authenticated principal from the trusted header. Never from the body. */
|
|
260
271
|
export function principalFrom(req, config) {
|
|
261
272
|
if (!config.principalHeader)
|
package/dist/session-sync.d.ts
CHANGED
|
@@ -15,10 +15,21 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import type { StoreBackend } from "./plugins/store-backend.js";
|
|
17
17
|
import { type SyncRelation } from "./session-sync-kernel.js";
|
|
18
|
-
import type { SessionTreeEntry, SessionRulesRecord } from "@sema-agent/core";
|
|
18
|
+
import type { SessionTreeEntry, SessionRulesRecord, FileSnapshotResult } from "@sema-agent/core";
|
|
19
19
|
/** A blob getter: content-addressed bytes for a sha256 hash, or `undefined` if the source can't supply them.
|
|
20
20
|
* Returned by {@link exportSession} (closes over the source store), consumed by {@link importSession}. */
|
|
21
21
|
export type BlobGetter = (hash: string) => Promise<Uint8Array | undefined>;
|
|
22
|
+
/** The snapshot-import capability face of a `FileSnapshotStore` — signature verbatim = the authoritative
|
|
23
|
+
* implementation, `FileSnapshotStoreSql.importManifest` (src/plugins/file-snapshot-store-sql.ts:201). */
|
|
24
|
+
export interface FileSnapshotImportFace {
|
|
25
|
+
importManifest(scope: string, key: string, manifest: Map<string, string>, srcGetBlob: BlobGetter): Promise<FileSnapshotResult>;
|
|
26
|
+
}
|
|
27
|
+
/** Single-point capability probe (design/158 R7): does `fs` carry the optional `importManifest` snapshot-import
|
|
28
|
+
* seam? Returns the bound method (never a naked function reference — `this` inside `importManifest` must resolve
|
|
29
|
+
* to `fs`, exactly like `asServiceDeps`'s other capability-probe-then-bind authorities) or `undefined` when the
|
|
30
|
+
* seam is absent (an older/in-memory dev store). Callers gate on the RETURN VALUE, not a separate `typeof` check,
|
|
31
|
+
* so there is exactly one place that knows the shape of the probe. */
|
|
32
|
+
export declare function fileSnapshotImportFace(fs: unknown): FileSnapshotImportFace | undefined;
|
|
22
33
|
export { stagingIdFor, STAGING_ID_MARKER, realIdOfStaging, classifySyncRelationship, classifySyncRelationshipByIds, SyncConflictError } from "./session-sync-kernel.js";
|
|
23
34
|
export type { StagingHandle, ImportStagingStore, SyncRelation } from "./session-sync-kernel.js";
|
|
24
35
|
/**
|
package/dist/session-sync.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { identicalIdsAlsoIdenticalContent } from "./session-sync-content.js";
|
|
2
2
|
import { classifySyncRelationship, SyncConflictError } from "./session-sync-kernel.js";
|
|
3
3
|
import { validateEntriesForImport, normalizeRules, stripRev } from "@sema-agent/core";
|
|
4
|
+
/** Single-point capability probe (design/158 R7): does `fs` carry the optional `importManifest` snapshot-import
|
|
5
|
+
* seam? Returns the bound method (never a naked function reference — `this` inside `importManifest` must resolve
|
|
6
|
+
* to `fs`, exactly like `asServiceDeps`'s other capability-probe-then-bind authorities) or `undefined` when the
|
|
7
|
+
* seam is absent (an older/in-memory dev store). Callers gate on the RETURN VALUE, not a separate `typeof` check,
|
|
8
|
+
* so there is exactly one place that knows the shape of the probe. */
|
|
9
|
+
export function fileSnapshotImportFace(fs) {
|
|
10
|
+
const candidate = fs?.importManifest;
|
|
11
|
+
if (typeof candidate !== "function")
|
|
12
|
+
return undefined;
|
|
13
|
+
return { importManifest: candidate.bind(fs) };
|
|
14
|
+
}
|
|
4
15
|
// ── PURE KERNEL moved to ./session-sync-kernel.ts (design/158 A2) ─────────────────────────────────────────────
|
|
5
16
|
// The §7 relation classifier (classifySyncRelationship[ByIds]), the staging-id scheme (stagingIdFor /
|
|
6
17
|
// STAGING_ID_MARKER / realIdOfStaging), the StagingHandle / ImportStagingStore contracts and SyncConflictError
|
|
@@ -196,7 +207,8 @@ export async function exportSessionManifest(sessionId, srcBackend) {
|
|
|
196
207
|
export async function importSession(bundle, getBlob, dstBackend, importingPrincipal, opts) {
|
|
197
208
|
const sessionId = bundle.sessionId;
|
|
198
209
|
const fs = dstBackend.fileSnapshot();
|
|
199
|
-
const
|
|
210
|
+
const importFace = fileSnapshotImportFace(fs);
|
|
211
|
+
const canImportSnapshots = importFace !== undefined;
|
|
200
212
|
// ── §7 classification gate, BEFORE any write ───────────────────────────────────────────────────────────────
|
|
201
213
|
// Read the destination's CURRENT entry log and classify the relationship (sound entry-id set comparison). A fork or
|
|
202
214
|
// a stale source would lose dst history → refuse with a typed 409 unless the caller explicitly resolved overwrite-dst.
|
|
@@ -290,8 +302,8 @@ export async function importSession(bundle, getBlob, dstBackend, importingPrinci
|
|
|
290
302
|
// written (the commit point is inside importEntries, step ②), so the dst stays clean (only collectable orphans).
|
|
291
303
|
let snapshotsImported = 0;
|
|
292
304
|
let snapshotsSkipped = 0;
|
|
293
|
-
if (
|
|
294
|
-
const importManifest =
|
|
305
|
+
if (importFace) {
|
|
306
|
+
const importManifest = importFace.importManifest;
|
|
295
307
|
for (const snap of bundle.snapshots) {
|
|
296
308
|
const r = await importManifest(sessionId, snap.key, new Map(snap.manifest), getBlob);
|
|
297
309
|
if (!r.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.2",
|
|
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",
|