@sema-agent/server 3.0.0 → 3.2.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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +13 -9
- package/dist/approval-hmac.js +1 -2
- package/dist/bench/s1/live-deps.js +1 -1
- package/dist/boot/config-center.d.ts +3 -2
- package/dist/boot/config-center.js +33 -19
- package/dist/boot/resolve-spec.js +5 -5
- package/dist/brain.js +42 -9
- package/dist/config-center/apply-effective.d.ts +1 -1
- package/dist/config-center/apply-effective.js +4 -4
- package/dist/config-center/facade.d.ts +47 -0
- package/dist/config-center/facade.js +46 -0
- package/dist/config-center/http-client.d.ts +1 -1
- package/dist/config-center/http-client.js +6 -6
- package/dist/config-center/restart-signal.d.ts +11 -3
- package/dist/config-center/restart-signal.js +51 -7
- package/dist/config-center/skills-mcp.js +1 -1
- package/dist/config-center/types.d.ts +2 -2
- package/dist/config-provider.d.ts +7 -7
- package/dist/config-provider.js +9 -9
- package/dist/config.d.ts +1 -1
- package/dist/config.js +5 -5
- package/dist/http/routes/approvals-assistant.js +3 -3
- package/dist/http/routes/runs.js +7 -7
- package/dist/http/routes/sessions.js +1 -1
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/server.d.ts +1 -1
- package/dist/http/server.js +3 -3
- package/dist/key-resolver.d.ts +14 -0
- package/dist/key-resolver.js +27 -11
- package/dist/plugins/remote-env-host.d.ts +32 -14
- package/dist/plugins/remote-env-host.js +30 -10
- package/dist/plugins/remote-env-local-docker.d.ts +14 -0
- package/dist/plugins/remote-env-local-docker.js +10 -3
- package/dist/plugins/run-store-sql.d.ts +8 -3
- package/dist/plugins/run-store-sql.js +8 -3
- package/dist/run-local.js +2 -2
- package/dist/runtime-caps-resolver.d.ts +1 -1
- package/dist/runtime-caps-resolver.js +1 -1
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/runtime-governance.js +1 -1
- package/dist/sema-registry.d.ts +18 -4
- package/dist/sema-registry.js +17 -3
- package/package.json +2 -2
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
* (`{ ok:true, exitCode }`), never an error.
|
|
29
29
|
*
|
|
30
30
|
* Platforms: macOS + Linux (POSIX shell). Forward-compatible with the `remoteExec` superset: this file also
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* hosts the `local-docker` / `remote-docker` providers' factory entry points — both now IMPLEMENTED by the
|
|
32
|
+
* container adapter in remote-env-local-docker.ts (the two providers differ only in whether the `-H` daemon
|
|
33
|
+
* endpoint is off-box and required), re-exported/wrapped here so the discriminator has one canonical site.
|
|
33
34
|
*/
|
|
34
35
|
import { spawn } from "node:child_process";
|
|
35
36
|
import os from "node:os";
|
|
@@ -1647,19 +1648,38 @@ export function hostExecutionEnvFactory(config = {}) {
|
|
|
1647
1648
|
// ─────────────────────────────── remoteExec superset: docker providers ───────────────────────────────
|
|
1648
1649
|
//
|
|
1649
1650
|
// DUAL-MODE-DESIGN §5 defines a `remoteExec.provider` superset. `host` (above) is implemented; `local-docker`
|
|
1650
|
-
//
|
|
1651
|
-
// re-exported here so the discriminator entry
|
|
1652
|
-
//
|
|
1653
|
-
// implemented" so selecting it fails loud at wiring time instead of silently degrading isolation. NOT faked green.
|
|
1651
|
+
// (the isolation lane) and `remote-docker` (that same container lane aimed at a REMOTE daemon) are BOTH
|
|
1652
|
+
// implemented by remote-env-local-docker.ts and re-exported / wrapped here so the discriminator entry points +
|
|
1653
|
+
// the historical import sites stay stable.
|
|
1654
1654
|
// `local-docker` (the isolation lane): real implementation moved to remote-env-local-docker.ts. Re-export the
|
|
1655
1655
|
// factory + config from here so existing wiring (`import { localDockerExecutionEnvFactory } from "./remote-env-host"`)
|
|
1656
1656
|
// keeps working and the provider discriminator has one canonical entry point.
|
|
1657
1657
|
export { localDockerExecutionEnvFactory, RemoteLocalDockerExecutionEnv } from "./remote-env-local-docker.js";
|
|
1658
|
+
import { localDockerExecutionEnvFactory } from "./remote-env-local-docker.js";
|
|
1658
1659
|
/**
|
|
1659
|
-
* `
|
|
1660
|
-
*
|
|
1660
|
+
* `ExecutionEnvFactory` for the TOC `remote-docker` backend (DUAL-MODE-DESIGN §5): a per-task container on
|
|
1661
|
+
* SOMEONE ELSE'S docker daemon (offload — the operator's box stays free; isolation:true, suspendable:false).
|
|
1662
|
+
* Same lifetime contract as local-docker: unconnected/lazy, one container per task, `destroy()` = `docker rm -f`.
|
|
1663
|
+
*
|
|
1664
|
+
* 🔴 **Endpoint credentials are the docker CLI's own** — this adapter deliberately carries none. The docker CLI
|
|
1665
|
+
* reads `DOCKER_CERT_PATH` + `DOCKER_TLS_VERIFY` from the worker's environment (inherited by every spawn) for a
|
|
1666
|
+
* `tcp://` + TLS daemon, and uses `ssh-agent` / `~/.ssh/config` for an `ssh://` one. That keeps key material out
|
|
1667
|
+
* of this process's config objects entirely. Consequence to know: `tcp://…:2376` WITHOUT those env vars fails
|
|
1668
|
+
* loud at connect (the daemon refuses plaintext) — it does not silently downgrade; a plaintext `tcp://…:2375`
|
|
1669
|
+
* daemon is unauthenticated and remains the operator's decision, exactly as in the registry-core schema.
|
|
1670
|
+
* (The registry-core `remote-docker` arm additionally models `tlsCertEnv`/`tlsKeyEnv`/`tlsCaEnv`/`sshKeyEnv` =
|
|
1671
|
+
* env-NAMEs the control plane resolves to PEM BYTES. Materializing those bytes to short-lived 0600 files and
|
|
1672
|
+
* passing `--tlsverify --tlscert/--tlskey/--tlscacert` is the remaining config-surface follow-up, together with
|
|
1673
|
+
* the `provider:"remote-docker"` arm on `AppConfig.remoteExec` — see the note on that union in config-types.ts.)
|
|
1674
|
+
*
|
|
1675
|
+
* Throws at factory-BUILD time on a missing/blank endpoint: a "remote" lane with no endpoint would otherwise
|
|
1676
|
+
* quietly become the LOCAL daemon — an isolation-topology surprise, so it fails loud instead.
|
|
1661
1677
|
*/
|
|
1662
|
-
export function remoteDockerExecutionEnvFactory(
|
|
1663
|
-
|
|
1678
|
+
export function remoteDockerExecutionEnvFactory(config, deps = {}) {
|
|
1679
|
+
const dockerHost = config.dockerHost?.trim();
|
|
1680
|
+
if (!dockerHost) {
|
|
1681
|
+
throw new RemoteExecutionError("connect_failed", "remoteExec provider 'remote-docker' requires a non-empty dockerHost (the remote daemon endpoint, e.g. tcp://host:2376 or ssh://user@host) — use provider 'local-docker' for THIS machine's daemon");
|
|
1682
|
+
}
|
|
1683
|
+
return localDockerExecutionEnvFactory({ ...config, dockerHost, providerLabel: "remote-docker" }, deps);
|
|
1664
1684
|
}
|
|
1665
1685
|
//# sourceMappingURL=remote-env-host.js.map
|
|
@@ -17,8 +17,20 @@ export interface LocalDockerEnvConfig {
|
|
|
17
17
|
/**
|
|
18
18
|
* DOCKER_HOST override for the docker CLI (e.g. a non-default socket). Passed as `-H <value>` on EVERY docker
|
|
19
19
|
* invocation (not the process env) so it can't leak / drift. Absent = the daemon DOCKER_HOST points at.
|
|
20
|
+
*
|
|
21
|
+
* Pointing this OFF-BOX (`tcp://host:2376`, `ssh://user@host`) is exactly the DUAL-MODE-DESIGN §5
|
|
22
|
+
* **`remote-docker`** provider — see {@link remoteDockerExecutionEnvFactory} (remote-env-host.ts), which is
|
|
23
|
+
* this adapter with the endpoint required. Nothing else about the class is host-local: the workspace is
|
|
24
|
+
* `mkdir`'d INSIDE the container (never a bind-mount of a host path) and bytes move by `docker cp` /
|
|
25
|
+
* `docker exec cat`, which stream over the daemon API.
|
|
20
26
|
*/
|
|
21
27
|
dockerHost?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Provider NAME reported on the {@link WorkspaceHandle}. Default `"local-docker"`; the `remote-docker` arm
|
|
30
|
+
* passes `"remote-docker"` so a handle never mislabels which lane it is (the CLASS is shared — `remote-docker`
|
|
31
|
+
* IS this adapter aimed at a remote daemon). Cosmetic/observability only: it selects no behavior.
|
|
32
|
+
*/
|
|
33
|
+
providerLabel?: string;
|
|
22
34
|
/** Container memory limit (docker `--memory`, e.g. "2g"). Absent = no limit. */
|
|
23
35
|
memory?: string;
|
|
24
36
|
/** Container CPU limit (docker `--cpus`, e.g. 1.5). Absent = no limit. */
|
|
@@ -65,6 +77,8 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
65
77
|
private readonly spawnFn;
|
|
66
78
|
/** Stable container NAME (also our handle id). Created on connect; targeted by every docker exec/cp/rm. */
|
|
67
79
|
private readonly containerName;
|
|
80
|
+
/** Provider name put on the WorkspaceHandle ("local-docker" | "remote-docker"). Observability only. */
|
|
81
|
+
private readonly providerName;
|
|
68
82
|
/** Set once the container is up + the workspace dir created. */
|
|
69
83
|
private containerId?;
|
|
70
84
|
private handle?;
|
|
@@ -66,6 +66,8 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
66
66
|
spawnFn;
|
|
67
67
|
/** Stable container NAME (also our handle id). Created on connect; targeted by every docker exec/cp/rm. */
|
|
68
68
|
containerName;
|
|
69
|
+
/** Provider name put on the WorkspaceHandle ("local-docker" | "remote-docker"). Observability only. */
|
|
70
|
+
providerName;
|
|
69
71
|
/** Set once the container is up + the workspace dir created. */
|
|
70
72
|
containerId;
|
|
71
73
|
handle;
|
|
@@ -92,6 +94,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
92
94
|
const id = config.id ?? randomBytes(6).toString("hex");
|
|
93
95
|
const suffix = randomBytes(4).toString("hex"); // always-unique tail so a reused id never collides
|
|
94
96
|
this.containerName = `sema-docker-${sanitizeId(id)}-${suffix}`;
|
|
97
|
+
this.providerName = config.providerLabel?.trim() || PROVIDER;
|
|
95
98
|
}
|
|
96
99
|
resolve(p) {
|
|
97
100
|
return path.posix.isAbsolute(p) ? path.posix.normalize(p) : path.posix.normalize(path.posix.join(this.cwd, p));
|
|
@@ -165,7 +168,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
165
168
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
166
169
|
}
|
|
167
170
|
this.containerId = run.value.stdout.trim() || this.containerName;
|
|
168
|
-
this.handle = { sandboxId: this.containerName, provider:
|
|
171
|
+
this.handle = { sandboxId: this.containerName, provider: this.providerName, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
|
|
169
172
|
if (config?.secrets?.length) {
|
|
170
173
|
// Secrets are injected per-command via cfg.env (resolved by the control plane), not at connect — record only.
|
|
171
174
|
}
|
|
@@ -197,7 +200,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
197
200
|
// re-run `docker run --name <same>` → name conflict → the failure path rm -f's the very container we just
|
|
198
201
|
// re-attached to (destroying the running workspace). The name IS our exec/handle target.
|
|
199
202
|
this.containerId = this.containerName;
|
|
200
|
-
this.handle ??= { sandboxId: this.containerName, provider:
|
|
203
|
+
this.handle ??= { sandboxId: this.containerName, provider: this.providerName, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
|
|
201
204
|
return ok(this.handle);
|
|
202
205
|
}
|
|
203
206
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `container '${this.containerName}' is not running (gone or stopped) — no managed snapshot to resume`) };
|
|
@@ -609,7 +612,11 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
609
612
|
return;
|
|
610
613
|
this.containerShellProbed = true;
|
|
611
614
|
try {
|
|
612
|
-
|
|
615
|
+
// 🔴 NO withHostFlag here — `docker()` already prepends it. A second `-H` is not a harmless repeat: the
|
|
616
|
+
// docker CLI rejects the whole command (`invalid argument … specify only one -H`), so on every
|
|
617
|
+
// REMOTE-daemon container (`dockerHost` set — always, on the `remote-docker` arm) the probe used to fail
|
|
618
|
+
// and silently degrade the user shell to /bin/sh for a reason unrelated to the image.
|
|
619
|
+
const r = await this.docker(["exec", this.containerName, "/bin/sh", "-c", "command -v bash"], { timeoutMs: this.cfg.controlTimeoutMs });
|
|
613
620
|
if (r.ok && r.value.exitCode === 0 && r.value.stdout.trim().length > 0)
|
|
614
621
|
this.containerShell = "bash";
|
|
615
622
|
}
|
|
@@ -126,9 +126,14 @@ export declare class SqlRunStore {
|
|
|
126
126
|
* suspend, an INTENTIONAL durable pause" (design/76 §2.5) — the service MUST park it the same way, else the run is
|
|
127
127
|
* terminalized + its lock released and the plan_review/dry_run_review resume can never run (it gets
|
|
128
128
|
* taskId=undefined and drives the model unprotected on an unlocked session). CAS on `running`/`needs_review`
|
|
129
|
-
* (reaper-revert guard, mirrors setSuspended).
|
|
130
|
-
*
|
|
131
|
-
*
|
|
129
|
+
* (reaper-revert guard, mirrors setSuspended). The park→resume→claim invariant is pinned on BOTH REAL engines by
|
|
130
|
+
* `test/run-store-reaper-integration.test.ts` (`inv#1` row ownership across park→resume→handover, `inv#2` two
|
|
131
|
+
* replicas racing one session ⇒ exactly one claim wins, `inv#3`/`inv#3'` stale-claim takeover vs fresh/parked
|
|
132
|
+
* claims), closing the former required-before-GA gap. Keep it that way: the P2 lease-SQL bug and this
|
|
133
|
+
* needs_review-park bug were both born from store SQL that mocked unit tests pass — measured, not asserted, when
|
|
134
|
+
* the invariant set was built: an upserting (non-exclusive) claim reddened all four real-DB cases while all 111
|
|
135
|
+
* mocked run-store unit tests stayed green. A mock cannot observe a unique-key claim race, a rolled-back loser,
|
|
136
|
+
* or a multi-table reaper DELETE.
|
|
132
137
|
*/
|
|
133
138
|
setNeedsReview(taskId: string): Promise<void>;
|
|
134
139
|
/**
|
|
@@ -206,9 +206,14 @@ export class SqlRunStore {
|
|
|
206
206
|
* suspend, an INTENTIONAL durable pause" (design/76 §2.5) — the service MUST park it the same way, else the run is
|
|
207
207
|
* terminalized + its lock released and the plan_review/dry_run_review resume can never run (it gets
|
|
208
208
|
* taskId=undefined and drives the model unprotected on an unlocked session). CAS on `running`/`needs_review`
|
|
209
|
-
* (reaper-revert guard, mirrors setSuspended).
|
|
210
|
-
*
|
|
211
|
-
*
|
|
209
|
+
* (reaper-revert guard, mirrors setSuspended). The park→resume→claim invariant is pinned on BOTH REAL engines by
|
|
210
|
+
* `test/run-store-reaper-integration.test.ts` (`inv#1` row ownership across park→resume→handover, `inv#2` two
|
|
211
|
+
* replicas racing one session ⇒ exactly one claim wins, `inv#3`/`inv#3'` stale-claim takeover vs fresh/parked
|
|
212
|
+
* claims), closing the former required-before-GA gap. Keep it that way: the P2 lease-SQL bug and this
|
|
213
|
+
* needs_review-park bug were both born from store SQL that mocked unit tests pass — measured, not asserted, when
|
|
214
|
+
* the invariant set was built: an upserting (non-exclusive) claim reddened all four real-DB cases while all 111
|
|
215
|
+
* mocked run-store unit tests stayed green. A mock cannot observe a unique-key claim race, a rolled-back loser,
|
|
216
|
+
* or a multi-table reaper DELETE.
|
|
212
217
|
*/
|
|
213
218
|
async setNeedsReview(taskId) {
|
|
214
219
|
await this.db.query(this.q("UPDATE task_run SET status = 'needs_review', updated_at = ? WHERE task_id = ? AND status IN ('running','needs_review')", "UPDATE task_run SET status = 'needs_review', updated_at = $1 WHERE task_id = $2 AND status IN ('running','needs_review')"), [new Date(), taskId]);
|
package/dist/run-local.js
CHANGED
|
@@ -33,7 +33,7 @@ import { taskWallClockSec } from "./task-workflow.js";
|
|
|
33
33
|
import { validatePromptsDomain, applyCatalogToSource, CORE_ENGINE_VERSION } from "./capabilities/center-prompts.js";
|
|
34
34
|
import { loadConfig, logConfigDiagnostics } from "./config.js";
|
|
35
35
|
import { createConfigProvider } from "./config-provider.js";
|
|
36
|
-
import { applyEffective, resolveMcpServers, mcpForScenario } from "./
|
|
36
|
+
import { applyEffective, resolveMcpServers, mcpForScenario } from "./config-center/facade.js";
|
|
37
37
|
import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
|
|
38
38
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "./project-memory.js";
|
|
39
39
|
import { loadSkills } from "./capabilities/skills.js";
|
|
@@ -272,7 +272,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
272
272
|
return 2;
|
|
273
273
|
}
|
|
274
274
|
const sessionStore = fileBackend.sessionStore;
|
|
275
|
-
const keyResolver = createKeyResolver(config.modelApiKeyEnv);
|
|
275
|
+
const keyResolver = createKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys); // [2006] 后续:三参全链(sealed→env→undefined),与 boot 正形同源——二参形曾让 sealed 模型静默落网关 key
|
|
276
276
|
// Host exec lane: run on THIS machine, in a FIXED workspace (CC-like) — the cwd by default (or --workspace /
|
|
277
277
|
// a config.d workdir). The agent's file edits PERSIST there + are user-visible; the dir is the user's OWN and
|
|
278
278
|
// is NEVER deleted (workspaceDir mode). One env per task; the Runner owns its lifetime.
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
import type { RuntimeCaps } from "@sema-agent/core";
|
|
30
30
|
import type { EntitlementRuntimeCaps } from "@sema-agent/registry-core";
|
|
31
|
-
import { fetchPrincipalCaps, type ExecutionRuling } from "./
|
|
31
|
+
import { fetchPrincipalCaps, type ExecutionRuling } from "./config-center/facade.js";
|
|
32
32
|
import type { ScenarioRuling } from "./capabilities/scenarios.js";
|
|
33
33
|
export interface EntitlementsResolverOpts {
|
|
34
34
|
baseUrl: string;
|
|
@@ -51,7 +51,7 @@ export type Autonomy = "read-only" | "ask" | "plan" | "auto";
|
|
|
51
51
|
export declare const COARSE_SHELL_TOOLS_MIRROR: readonly string[];
|
|
52
52
|
/** Validate `commandPolicy` rules — the shape (array of {command, decision}), the `command` (a bare argv[0] name,
|
|
53
53
|
* see {@link VALID_COMMAND_NAME}), AND the `decision` enum. Returns the list of human-readable errors (empty =
|
|
54
|
-
* OK). Called at config-apply (
|
|
54
|
+
* OK). Called at config-apply (config-center/facade.ts `applyRuntimeHot`) so a malformed rule that BYPASSED the
|
|
55
55
|
* registry schema (a hand-edited config.d / a non-conformant publish) is rejected LOUDLY rather than
|
|
56
56
|
* silently mis-compiling — review MEDIUM: an out-of-enum `decision` (e.g. "DENY") would otherwise fall through
|
|
57
57
|
* {@link compileCommandPolicy}'s `decision==="deny"?…:"ask"` to ASK, silently WEAKENING an intended deny. */
|
|
@@ -108,7 +108,7 @@ const VALID_COMMAND_NAME = /^[A-Za-z0-9._+-]+$/;
|
|
|
108
108
|
const VALID_DECISIONS = new Set(["allow", "ask", "deny"]);
|
|
109
109
|
/** Validate `commandPolicy` rules — the shape (array of {command, decision}), the `command` (a bare argv[0] name,
|
|
110
110
|
* see {@link VALID_COMMAND_NAME}), AND the `decision` enum. Returns the list of human-readable errors (empty =
|
|
111
|
-
* OK). Called at config-apply (
|
|
111
|
+
* OK). Called at config-apply (config-center/facade.ts `applyRuntimeHot`) so a malformed rule that BYPASSED the
|
|
112
112
|
* registry schema (a hand-edited config.d / a non-conformant publish) is rejected LOUDLY rather than
|
|
113
113
|
* silently mis-compiling — review MEDIUM: an out-of-enum `decision` (e.g. "DENY") would otherwise fall through
|
|
114
114
|
* {@link compileCommandPolicy}'s `decision==="deny"?…:"ask"` to ASK, silently WEAKENING an intended deny. */
|
package/dist/sema-registry.d.ts
CHANGED
|
@@ -10,9 +10,23 @@
|
|
|
10
10
|
* (core 1.45), so each model/cascade-rung authenticates with its own upstream key.
|
|
11
11
|
*
|
|
12
12
|
* Per-model `baseUrl` IS transported (a catalog model may live on a different gateway;
|
|
13
|
-
* core brain honors model.baseUrl, absent = "" = boot-env endpoint).
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* core brain honors model.baseUrl, absent = "" = boot-env endpoint).
|
|
14
|
+
*
|
|
15
|
+
* Hot-reload status (复审 2026-07-29 P1-11 — 亲读判定,取代此处旧的 "models/roles are restart-to-apply"
|
|
16
|
+
* TODO, which went stale when `mutateInPlace` landed):
|
|
17
|
+
* - models/roles/roster/teams/projects/autonomy — **HOT**. `applyEffective` mutates `config.models`/
|
|
18
|
+
* `config.roles` IN PLACE, and core's Runner reads `this.deps.models/roles` per task off that very
|
|
19
|
+
* reference. Both brains re-resolve `model.baseUrl || config.baseUrl` inside `buildRequest()` on every
|
|
20
|
+
* call (core 2.1.0 `brain/openai.js` + `brain/anthropic.js`), so a moved gateway takes effect on the
|
|
21
|
+
* next task with no restart.
|
|
22
|
+
* - the same plane under a **tier-frozen** Runner — deferred, not hot: core expands a PRIVATE catalog copy
|
|
23
|
+
* at construction, so `main` defers the whole plane and the `models-tiers` restart slice signals.
|
|
24
|
+
* - **`degrade-route`** — the one genuinely boot-frozen catalog consumer left: reactive degrade
|
|
25
|
+
* (`MODEL_DEGRADE_REACTIVE`) bakes the target Model + its gateway + its key into the brain composition
|
|
26
|
+
* at boot. It cannot be hot-applied without rebuilding the brain, so it is registered on the existing
|
|
27
|
+
* restartRequired /health contract instead (see `restart-signal.ts`). Fail-loud beats serving a stale
|
|
28
|
+
* gateway silently on the rate-limit path.
|
|
29
|
+
* - skills/mcp/scenarios/runtime-gates — restart-to-apply by construction (baked into the boot wiring).
|
|
16
30
|
*
|
|
17
31
|
* (design/158 A13, internal-lossless) This module is now a FACADE: the implementation lives in
|
|
18
32
|
* `src/config-center/` split by responsibility group (HTTP client / EffectiveConfig application /
|
|
@@ -21,7 +35,7 @@
|
|
|
21
35
|
*/
|
|
22
36
|
export { fetchEffective, fetchPrincipalCaps, ConfigCenterHttpError, fetchSkillContent, fetchPromptArtifact, fetchPromptBlob, } from "./config-center/http-client.js";
|
|
23
37
|
export { mutateInPlace, applyEffective, applyRuntimeGates, applyRuntimeHot, resolveDefaultModelName, logEffectiveDiff, runtimeHasActiveGate, } from "./config-center/apply-effective.js";
|
|
24
|
-
export { restartReasons, planeHasActiveTiers, modelPlaneChanged, type RestartSlice, type RestartSignal, } from "./config-center/restart-signal.js";
|
|
38
|
+
export { restartReasons, planeHasActiveTiers, modelPlaneChanged, type RestartSlice, type RestartSliceCtx, type RestartSignal, } from "./config-center/restart-signal.js";
|
|
25
39
|
export { applyCenterSkills, resolveMcpServers, mcpForScenario } from "./config-center/skills-mcp.js";
|
|
26
40
|
export type { CenterSkillManifest, CenterMcpServer, EffectiveConfig, ExecutionRuling, SessionMirrorRuling, } from "./config-center/types.js";
|
|
27
41
|
//# sourceMappingURL=sema-registry.d.ts.map
|
package/dist/sema-registry.js
CHANGED
|
@@ -10,9 +10,23 @@
|
|
|
10
10
|
* (core 1.45), so each model/cascade-rung authenticates with its own upstream key.
|
|
11
11
|
*
|
|
12
12
|
* Per-model `baseUrl` IS transported (a catalog model may live on a different gateway;
|
|
13
|
-
* core brain honors model.baseUrl, absent = "" = boot-env endpoint).
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* core brain honors model.baseUrl, absent = "" = boot-env endpoint).
|
|
14
|
+
*
|
|
15
|
+
* Hot-reload status (复审 2026-07-29 P1-11 — 亲读判定,取代此处旧的 "models/roles are restart-to-apply"
|
|
16
|
+
* TODO, which went stale when `mutateInPlace` landed):
|
|
17
|
+
* - models/roles/roster/teams/projects/autonomy — **HOT**. `applyEffective` mutates `config.models`/
|
|
18
|
+
* `config.roles` IN PLACE, and core's Runner reads `this.deps.models/roles` per task off that very
|
|
19
|
+
* reference. Both brains re-resolve `model.baseUrl || config.baseUrl` inside `buildRequest()` on every
|
|
20
|
+
* call (core 2.1.0 `brain/openai.js` + `brain/anthropic.js`), so a moved gateway takes effect on the
|
|
21
|
+
* next task with no restart.
|
|
22
|
+
* - the same plane under a **tier-frozen** Runner — deferred, not hot: core expands a PRIVATE catalog copy
|
|
23
|
+
* at construction, so `main` defers the whole plane and the `models-tiers` restart slice signals.
|
|
24
|
+
* - **`degrade-route`** — the one genuinely boot-frozen catalog consumer left: reactive degrade
|
|
25
|
+
* (`MODEL_DEGRADE_REACTIVE`) bakes the target Model + its gateway + its key into the brain composition
|
|
26
|
+
* at boot. It cannot be hot-applied without rebuilding the brain, so it is registered on the existing
|
|
27
|
+
* restartRequired /health contract instead (see `restart-signal.ts`). Fail-loud beats serving a stale
|
|
28
|
+
* gateway silently on the rate-limit path.
|
|
29
|
+
* - skills/mcp/scenarios/runtime-gates — restart-to-apply by construction (baked into the boot wiring).
|
|
16
30
|
*
|
|
17
31
|
* (design/158 A13, internal-lossless) This module is now a FACADE: the implementation lives in
|
|
18
32
|
* `src/config-center/` split by responsibility group (HTTP client / EffectiveConfig application /
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.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",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"sharp": "^0.35.3"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@sema-agent/sdk": "^0.0
|
|
70
|
+
"@sema-agent/sdk": "^1.0.0",
|
|
71
71
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
72
72
|
"@types/node": "22.10.2",
|
|
73
73
|
"@types/pg": "^8.20.0",
|