@sema-agent/server 7.122.0 → 7.124.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/MIGRATION.md +209 -0
- package/README.md +7 -2
- package/README.zh-CN.md +5 -2
- package/USAGE.md +76 -56
- package/dist/approval-ask-audit-store.d.ts +27 -32
- package/dist/approval-ask-audit-store.js +10 -9
- package/dist/approval-crash-convergence.d.ts +2 -2
- package/dist/approval-crash-convergence.js +5 -5
- package/dist/approval-deny-reasons.d.ts +163 -51
- package/dist/approval-deny-reasons.js +79 -8
- package/dist/approval-policy-settlement.d.ts +4 -1
- package/dist/approval-policy-settlement.js +3 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval-reconciler.js +10 -10
- package/dist/approval.d.ts +1 -1
- package/dist/approval.js +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +53 -23
- package/dist/auth-bridge.d.ts +8 -8
- package/dist/auth-bridge.js +6 -6
- package/dist/auth-keys.d.ts +2 -2
- package/dist/auto-mode-face.d.ts +13 -9
- package/dist/auto-mode-face.js +8 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/execution-env.js +1 -0
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +4 -4
- package/dist/boot/org-memory.d.ts +3 -3
- package/dist/boot/org-memory.js +5 -5
- package/dist/boot/resolve-spec.js +7 -7
- package/dist/boot/runner-deps.d.ts +1 -1
- package/dist/boot/runtime-caps.d.ts +1 -1
- package/dist/boot/runtime-caps.js +10 -10
- package/dist/boot/shutdown.d.ts +2 -2
- package/dist/boot/shutdown.js +2 -2
- package/dist/boot/side-query-lane.d.ts +3 -3
- package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
- package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
- package/dist/boot/stage-03-store-backend.d.ts +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +6 -6
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +6 -5
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -3
- package/dist/boot/stage-09-leader.js +7 -7
- package/dist/boot/stage-10-http-server.d.ts +3 -3
- package/dist/boot/stage-10-http-server.js +19 -19
- package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
- package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
- package/dist/boot/{config-center.js → web-admin.js} +39 -20
- package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
- package/dist/brain.d.ts +1 -1
- package/dist/brain.js +1 -1
- package/dist/budget.d.ts +3 -3
- package/dist/canonical-json.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +12 -5
- package/dist/capabilities/center-wiring.js +11 -2
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capabilities/team.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/center-credential-renewer.d.ts +1 -1
- package/dist/center-credential-renewer.js +7 -7
- package/dist/center-credential.d.ts +9 -9
- package/dist/center-credential.js +6 -6
- package/dist/config-catalog.d.ts +7 -10
- package/dist/config-catalog.js +16 -16
- package/dist/config-d-migration.d.ts +32 -0
- package/dist/config-d-migration.js +59 -0
- package/dist/config-invariants.d.ts +14 -4
- package/dist/config-invariants.js +31 -2
- package/dist/config-lkg.d.ts +34 -11
- package/dist/config-lkg.js +76 -48
- package/dist/config-provider.d.ts +26 -21
- package/dist/config-provider.js +25 -27
- package/dist/config-types.d.ts +59 -50
- package/dist/config.d.ts +17 -54
- package/dist/config.js +99 -181
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/drain-entry.d.ts +1 -1
- package/dist/fleet/engine-signal.d.ts +61 -30
- package/dist/fleet/engine-signal.js +29 -5
- package/dist/fleet/fleet-bus.d.ts +12 -3
- package/dist/fleet/fleet-bus.js +13 -9
- package/dist/fleet/serving-lease.d.ts +3 -3
- package/dist/fleet/serving-lease.js +1 -1
- package/dist/fleet-client.d.ts +15 -13
- package/dist/fleet-client.js +9 -7
- package/dist/fleet-lease.d.ts +3 -3
- package/dist/fleet-lease.js +2 -2
- package/dist/host-lsp-manager.d.ts +1 -1
- package/dist/hosted-posture.d.ts +4 -4
- package/dist/http/admission.js +4 -4
- package/dist/http/checkpoint-ctx.d.ts +20 -3
- package/dist/http/checkpoint-ctx.js +13 -5
- package/dist/http/dispatch.js +7 -16
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +7 -4
- package/dist/http/health-self-report.js +3 -3
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +31 -18
- package/dist/http/route-ctx.d.ts +8 -0
- package/dist/http/routes/admin-config-refresh.d.ts +1 -1
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.d.ts +1 -1
- package/dist/http/routes/admin-drain.js +5 -4
- package/dist/http/routes/approvals-assistant.js +4 -4
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/config-catalog.js +2 -3
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/runs.js +8 -4
- package/dist/http/routes/sessions-list.js +2 -1
- package/dist/http/routes/sessions.js +2 -5
- package/dist/http/routes/side-query.js +3 -3
- package/dist/http/routes/tasks.js +3 -2
- package/dist/http/run-meta.d.ts +1 -1
- package/dist/http/run-meta.js +2 -2
- package/dist/http/server.d.ts +7 -7
- package/dist/http/server.js +1 -1
- package/dist/http/stored-body-replay.d.ts +4 -3
- package/dist/http/stored-body-replay.js +5 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/leader.d.ts +7 -6
- package/dist/leader/leader.js +3 -1
- package/dist/leader/run-entry.d.ts +2 -2
- package/dist/leader/run-entry.js +3 -3
- package/dist/leader/wire.d.ts +4 -4
- package/dist/leader/wire.js +2 -1
- package/dist/main.js +1 -1
- package/dist/mcp-tool-faces.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +20 -11
- package/dist/model-entry-refusal.js +22 -17
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +22 -2
- package/dist/model-route-endpoint.js +9 -3
- package/dist/model-route-gap.d.ts +103 -0
- package/dist/model-route-gap.js +80 -0
- package/dist/model-route-url.d.ts +1 -1
- package/dist/model-route-url.js +2 -1
- package/dist/model-select.d.ts +24 -21
- package/dist/model-select.js +22 -17
- package/dist/namespaced-rule-name.d.ts +16 -30
- package/dist/namespaced-rule-name.js +2 -20
- package/dist/observability/fail-open.d.ts +0 -4
- package/dist/observability/fail-open.js +0 -4
- package/dist/observability/metrics.d.ts +1 -1
- package/dist/org-memory-admission.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -2
- package/dist/plugins/approval-ask-store-file.js +3 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
- package/dist/plugins/approval-ask-store-memory.js +10 -4
- package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
- package/dist/plugins/approval-ask-store-sql.js +20 -13
- package/dist/plugins/caching-session-store.d.ts +0 -10
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/file-run-store.js +9 -3
- package/dist/plugins/leader-run-store-sql.d.ts +3 -2
- package/dist/plugins/leader-run-store-sql.js +3 -2
- package/dist/plugins/local-session-store.d.ts +20 -27
- package/dist/plugins/local-session-store.js +19 -17
- package/dist/plugins/memory-run-store.js +9 -3
- package/dist/plugins/one-time-migrations.js +51 -0
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- package/dist/plugins/session-policy-store-sql.js +1 -2
- package/dist/plugins/store-backend.js +1 -1
- package/dist/plugins/store-contracts.d.ts +20 -4
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -1
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
- package/dist/posture-source.d.ts +1 -1
- package/dist/read-face-posture.d.ts +3 -3
- package/dist/read-face-posture.js +1 -1
- package/dist/rule-entry-list.d.ts +3 -13
- package/dist/rule-entry-list.js +1 -12
- package/dist/run-local.js +10 -7
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +36 -13
- package/dist/runtime-governance.js +7 -2
- package/dist/sealed-key.d.ts +4 -4
- package/dist/sealed-key.js +3 -2
- package/dist/security.d.ts +3 -3
- package/dist/service-version.d.ts +1 -1
- package/dist/service-version.js +5 -0
- package/dist/session-policy-wire.d.ts +47 -49
- package/dist/session-policy-wire.js +41 -36
- package/dist/session-sync.d.ts +5 -1
- package/dist/session-sync.js +2 -1
- package/dist/session-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/spec-fields.d.ts +4 -4
- package/dist/spec-fields.js +1 -4
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-settings.d.ts +4 -5
- package/dist/task-settings.js +5 -8
- package/dist/tool-approval.d.ts +43 -4
- package/dist/tool-approval.js +147 -98
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/project.d.ts +3 -3
- package/dist/trace/redact.d.ts +2 -23
- package/dist/trace/redact.js +1 -6
- package/dist/trace/self-minted-wire.d.ts +147 -3
- package/dist/trace/self-minted-wire.js +50 -9
- package/dist/unattended-permission-mode.d.ts +3 -3
- package/dist/unattended-permission-mode.js +2 -2
- package/dist/url-refusal.d.ts +35 -0
- package/dist/url-refusal.js +15 -0
- package/dist/user-authored-text.d.ts +31 -0
- package/dist/user-authored-text.js +18 -0
- package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
- package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
- package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
- package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
- package/dist/{config-center → web-admin-client}/center-request.js +5 -4
- package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
- package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
- package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
- package/dist/{config-center → web-admin-client}/facade.js +2 -2
- package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
- package/dist/{config-center → web-admin-client}/http-client.js +15 -15
- package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/read-face.js +4 -4
- package/dist/web-admin-client/read-warnings.d.ts +137 -0
- package/dist/web-admin-client/read-warnings.js +168 -0
- package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
- package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
- package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
- package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
- package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
- package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
- package/package.json +3 -3
- package/skills/find-skills.md +2 -2
- package/dist/config-center/read-warnings.d.ts +0 -109
- package/dist/config-center/read-warnings.js +0 -110
- package/dist/url-shape.d.ts +0 -31
- package/dist/url-shape.js +0 -41
- /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
- /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
- /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/types.js +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CC_MODEL_TIER_ALIASES, DEFAULT_TIER_ORDER, expandTiers } from "@sema-agent/core";
|
|
2
|
-
import { ModelEntry, isReportableRefusalName } from "@sema-agent/settings-schema";
|
|
2
|
+
import { ModelEntry, formatConfigPath, isReportableRefusalName } from "@sema-agent/settings-schema";
|
|
3
3
|
import { catalogBrainLane } from "./model-provider.js";
|
|
4
4
|
import { readCatalogEntryHeaders } from "./model-entry-headers.js";
|
|
5
|
-
import { describeSchemaIssueFields, describeSchemaIssues } from "./
|
|
5
|
+
import { DroppedCatalogEntryRow, describeSchemaIssueFields, describeSchemaIssues } from "./web-admin-client/read-warnings.js";
|
|
6
6
|
import { DEFAULT_MODEL_REF } from "./model-select.js";
|
|
7
7
|
export const ENTRY_REFUSAL_REASON_OF = {
|
|
8
8
|
"config.model_no_brain": "no_brain",
|
|
@@ -55,7 +55,7 @@ function entryInvalidRefusal(id, provider, fields, issues) {
|
|
|
55
55
|
"deployment's catalog on its own (the other entries keep serving) instead of being served with a value nothing validated; fix the entry to bring it back",
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
-
const MALFORMED_CARRIER_NOT_A_LIST = "(
|
|
58
|
+
const MALFORMED_CARRIER_NOT_A_LIST = "(droppedCatalogEntries is not a list)";
|
|
59
59
|
export function judgeCatalogEntries(enabled, ctx, dropped) {
|
|
60
60
|
const usable = [];
|
|
61
61
|
const refused = {};
|
|
@@ -71,20 +71,25 @@ export function judgeCatalogEntries(enabled, ctx, dropped) {
|
|
|
71
71
|
}
|
|
72
72
|
const rows = dropped === undefined ? [] : Array.isArray(dropped) ? dropped : undefined;
|
|
73
73
|
if (rows === undefined)
|
|
74
|
-
return { usable, refused, malformed: [MALFORMED_CARRIER_NOT_A_LIST] };
|
|
74
|
+
return { usable, refused, malformed: [MALFORMED_CARRIER_NOT_A_LIST], dropped: [] };
|
|
75
75
|
const malformed = [];
|
|
76
|
+
const carried = [];
|
|
76
77
|
for (const d of rows) {
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
79
|
-
|
|
78
|
+
const row = DroppedCatalogEntryRow.safeParse(d);
|
|
79
|
+
if (!row.success) {
|
|
80
|
+
const index = typeof d === "object" && d !== null ? d.index : undefined;
|
|
81
|
+
malformed.push(typeof index === "number" && Number.isSafeInteger(index) && index >= 0 ? formatConfigPath(["models", index]) : "(unknown coordinate)");
|
|
80
82
|
continue;
|
|
81
83
|
}
|
|
82
|
-
|
|
84
|
+
carried.push(row.data);
|
|
85
|
+
const { identity } = row.data;
|
|
86
|
+
if (identity?.name === undefined || identity.enabled === false)
|
|
83
87
|
continue;
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
if (Object.hasOwn(refused, identity.name))
|
|
89
|
+
continue;
|
|
90
|
+
mint(identity.name, entryInvalidRefusal(identity.id ?? "", "", row.data.fields, row.data.issues));
|
|
86
91
|
}
|
|
87
|
-
return { usable, refused, malformed };
|
|
92
|
+
return { usable, refused, malformed, dropped: carried };
|
|
88
93
|
}
|
|
89
94
|
export function buildModelRefusalsSignal(v) {
|
|
90
95
|
if (v === undefined)
|
|
@@ -113,9 +118,9 @@ function nameSlot(name) {
|
|
|
113
118
|
export function refusalEventOf(reason) {
|
|
114
119
|
switch (reason) {
|
|
115
120
|
case "no_brain":
|
|
116
|
-
return "
|
|
121
|
+
return "web_admin_model_no_brain";
|
|
117
122
|
case "entry_invalid":
|
|
118
|
-
return "
|
|
123
|
+
return "web_admin_model_entry_invalid";
|
|
119
124
|
}
|
|
120
125
|
}
|
|
121
126
|
export function refusalWarnFields(name, r) {
|
|
@@ -141,7 +146,7 @@ export function defaultModelRefusal(view, leg) {
|
|
|
141
146
|
return (`MODEL_ID is required when no catalog default resolves [${DEFAULT_MODEL_MISSING_CODE}] — this model table has no default model` +
|
|
142
147
|
unavailable +
|
|
143
148
|
". Set MODEL_ID=<model name your gateway serves>, or enable at least one model this host can serve in the catalog " +
|
|
144
|
-
"(config.d/models.json, or the
|
|
149
|
+
"(config.d/models.json, or the web-admin) — either one is enough (a web-admin that answers after the boot budget " +
|
|
145
150
|
"counts as absent at boot: raise CONFIG_BOOT_FETCH_BUDGET_MS to wait for it).");
|
|
146
151
|
case "catalog":
|
|
147
152
|
return (`this catalog candidate has no default model [${DEFAULT_MODEL_MISSING_CODE}]` +
|
|
@@ -185,8 +190,8 @@ export function refusedNameMintedRefusal(view) {
|
|
|
185
190
|
"rename the unavailable entry, fix it (see its own warn), or rebind / drop the tier binding that mints the name.");
|
|
186
191
|
}
|
|
187
192
|
export function malformedDroppedCarrierRefusal(entries) {
|
|
188
|
-
return (`the dropped
|
|
189
|
-
"every row the settings-schema read writes there
|
|
190
|
-
"the candidate cannot prove the tier/alias expansion does not re-mint the
|
|
193
|
+
return (`the dropped catalog entry carrier of this candidate is malformed [${REFUSED_NAME_MINTED_CODE}]: ${entries.join(", ")} — ` +
|
|
194
|
+
"every row the settings-schema read writes there has the carrier row shape (index, reasonCode, optional identity, fields, issues), so this carrier was edited outside the read legs (e.g. a hand-edited last-known-good file); " +
|
|
195
|
+
"the candidate cannot prove the tier/alias expansion does not re-mint the entries those rows stood for, so its model plane is refused — restore or delete that carrier (a fresh read of the source re-mints it).");
|
|
191
196
|
}
|
|
192
197
|
//# sourceMappingURL=model-entry-refusal.js.map
|
package/dist/model-provider.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export declare function modelBrainLane(provider: ModelProvider): ModelBrainLane;
|
|
|
60
60
|
*
|
|
61
61
|
* 🔴 为什么它与 {@link modelBrainLane} 不是同一只函数:两者的**输入保证不同**。
|
|
62
62
|
* · `MODEL_PROVIDER` 走 boot 闸(域外拒启)⇒ 到达 {@link modelBrainLane} 的恒是闭集词;
|
|
63
|
-
* · **目录条目**来自 settings-schema 的 `z.string()`,可以从
|
|
63
|
+
* · **目录条目**来自 settings-schema 的 `z.string()`,可以从 web-admin **热应用**进来 —— 那条路上
|
|
64
64
|
* 没有、也不该有「拒启」这回事(一次热发布不能让在跑的副本死),所以这里必然存在一条「认不出」的臂。
|
|
65
65
|
*
|
|
66
66
|
* 🔴 那条臂**就是今天的语义,本批一个字节都没改**([ref]「不可避免的运行期 miss 臂必须说出来」):
|
|
@@ -82,7 +82,7 @@ export declare function catalogBrainLane(provider: string | undefined): ModelBra
|
|
|
82
82
|
* `createBrain` 只在 anthropic 路由**装上**(`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 在场 ⇒
|
|
83
83
|
* `config.anthropic` 在场)时才铸 `createRoutingBrain({anthropic}, {fallback: gatewayStack})`;没装时整台机器
|
|
84
84
|
* 只有网关栈这一只 brain,**一切**条目(包括 `provider:"anthropic"` 的)都落 openai 兼容腿 ——
|
|
85
|
-
* `apply-effective.ts` 那条 `
|
|
85
|
+
* `apply-effective.ts` 那条 `web_admin_model_no_brain` warn 说的「mis-routes to the gateway brain」即此。
|
|
86
86
|
*
|
|
87
87
|
* 所以「这条路由要不要一个 openai 端点」的判据必须同时看词与装配:词判 {@link catalogBrainLane},
|
|
88
88
|
* 装配判路由在不在。本函数是这一合取的**唯一**写法 —— 端点判官(`model-route-endpoint.ts`)、降级腿与
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
* (`MODEL_GATEWAY_FALLBACK_URLS`)是主网关的镜像,没有主就没有镜像 ⇒ 拒。
|
|
16
16
|
*
|
|
17
17
|
* ## 执法点(判据只在这里,执法点在调用处 —— 与 S-475 `gateway-url-userinfo` 同形)
|
|
18
|
-
* · boot:`config.ts` 九域解析之后的跨域不变量区(锚 `CROSS-INVARIANT:model-route-endpoint`)⇒
|
|
18
|
+
* · boot:`config.ts` 九域解析之后的跨域不变量区(锚 `CROSS-INVARIANT:model-route-endpoint`)⇒ 拒启;经 `model-route-gap.ts`
|
|
19
|
+
* 的 {@link judgeModelRouteGap}(env 读成本文件判据要的切面,与包根导出的纯判官是**同一只**);严格名册
|
|
19
20
|
* 布防(`isRosterGateArmed`)时 env 腿是占位、从不被派发 ⇒ 不判它(备用网关那一条照判);
|
|
20
|
-
* · 热路径:`
|
|
21
|
+
* · 热路径:`web-admin-client/apply-effective.ts` 的模型面 stage ⇒ 模型面组拒(opus 腿 O3:同候选其余组照落)、上一代模型面继续服务;
|
|
21
22
|
* · run-local:配置源解析完之后按真要派发的表再判一次(`run-local.ts`,7.98.0 合并复审 F2)—— 本入口没有名册门,
|
|
22
23
|
* loadConfig 对严格名册布防的占位豁免在这里兑现不了;没布防时恒惰性;
|
|
23
24
|
* · 登记:`config-invariants.ts` 的 `model-route-endpoint` 条(表的「不许有表外不变量」职责);
|
|
@@ -37,6 +38,23 @@ import type { Model } from "@sema-agent/core";
|
|
|
37
38
|
export declare const MODEL_ROUTE_ENDPOINT_MISSING_CODE = "config.model_route_endpoint_missing";
|
|
38
39
|
/** 同族第二码:备用网关设了、主网关没设。与上一码分开是因为出路不同(补主网关 / 撤备用 vs 补主网关 / 给条目 baseUrl)。 */
|
|
39
40
|
export declare const GATEWAY_FALLBACK_WITHOUT_PRIMARY_CODE = "config.gateway_fallback_without_primary";
|
|
41
|
+
/**
|
|
42
|
+
* **路由缺口的出路轴**(闭集;{@link judgeModelRouteGap} 的 `gap` 词,包根导出 —— 壳 / 包在引擎起来之前问同一句)。
|
|
43
|
+
*
|
|
44
|
+
* 与上面的**码**是两根轴:码是组拒的机读词(`ModelPlaneRefusalCode`,settings-schema 属主),这里是**出路**:
|
|
45
|
+
* · `endpoint_missing` —— 缺的是网关端点:openai 兼容腿上的条目解析不到 base URL(或备用网关设了、主网关没设);
|
|
46
|
+
* 出路 = 设 `MODEL_GATEWAY_BASEURL`,或给条目自己的 `baseUrl`;
|
|
47
|
+
* · `lane_credential_missing` —— 缺的是**车道凭据**:条目的 provider 词是 `anthropic`(用户选的是 anthropic 车道),
|
|
48
|
+
* 却因 `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 都没有而没装上 anthropic 路由、落进了 openai 腿,那条腿又没有端点;
|
|
49
|
+
* 出路 = 补那两把钥匙之一(设网关是另一条出路,拒因句一并给);
|
|
50
|
+
* · `none` —— 这份配置能派发到的每一条 openai 兼容路由都解析得到端点。
|
|
51
|
+
*
|
|
52
|
+
* **声明序 = 语义序**(缺口两词在前,`none` 最后);加一词 ⇒ 所有穷举 switch 当场编译红。
|
|
53
|
+
*/
|
|
54
|
+
export declare const MODEL_ROUTE_GAP_WORDS: readonly ["endpoint_missing", "lane_credential_missing", "none"];
|
|
55
|
+
export type ModelRouteGap = (typeof MODEL_ROUTE_GAP_WORDS)[number];
|
|
56
|
+
/** 有缺口的那两词(判决的结构化形只在有缺口时存在,`none` = 判决为 `undefined`)。 */
|
|
57
|
+
export type ModelRouteGapBreach = Exclude<ModelRouteGap, "none">;
|
|
40
58
|
/**
|
|
41
59
|
* 拒因给出的**本机网关显式写法**。`src/` 里本机 8000 那个字面的**唯一**住处 —— 源码门钉在
|
|
42
60
|
* `test/config-gateway-endpoint-required.test.ts` ⑧(出现在别处 = 有人又在铸缺省)。
|
|
@@ -82,6 +100,8 @@ export declare function modelRouteEndpointRefusal(view: ModelRouteEndpointView):
|
|
|
82
100
|
/** S-768:部署级判决的结构化形 —— 码与拒因句由**同一次**判决给出(一个不变量 id 两个码,组拒码在判决那刻当数据带出,不从句子里抠)。 */
|
|
83
101
|
export interface ModelRouteEndpointVerdict {
|
|
84
102
|
readonly code: typeof GATEWAY_FALLBACK_WITHOUT_PRIMARY_CODE | typeof MODEL_ROUTE_ENDPOINT_MISSING_CODE;
|
|
103
|
+
/** 出路轴({@link MODEL_ROUTE_GAP_WORDS} 的缺口两词):同一次判决给出,不从句子或码里反推(`lane_credential_missing` 与 `endpoint_missing` 共用一个码)。 */
|
|
104
|
+
readonly gap: ModelRouteGapBreach;
|
|
85
105
|
readonly reason: string;
|
|
86
106
|
}
|
|
87
107
|
/**
|
|
@@ -2,6 +2,7 @@ import { dispatchBrainLane } from "./model-provider.js";
|
|
|
2
2
|
import { DEFAULT_MODEL_REF } from "./model-select.js";
|
|
3
3
|
export const MODEL_ROUTE_ENDPOINT_MISSING_CODE = "config.model_route_endpoint_missing";
|
|
4
4
|
export const GATEWAY_FALLBACK_WITHOUT_PRIMARY_CODE = "config.gateway_fallback_without_primary";
|
|
5
|
+
export const MODEL_ROUTE_GAP_WORDS = ["endpoint_missing", "lane_credential_missing", "none"];
|
|
5
6
|
export const LOCAL_GATEWAY_HINT = "MODEL_GATEWAY_BASEURL=http://127.0.0.1:8000/v1";
|
|
6
7
|
function declared(url) {
|
|
7
8
|
return url !== undefined && url.trim() !== "" ? url : undefined;
|
|
@@ -24,11 +25,12 @@ export function judgeModelRouteEndpoint(view) {
|
|
|
24
25
|
"after the primary fails; with no primary there is nothing to fail over from, and MODEL_GATEWAY_BASEURL has no " +
|
|
25
26
|
`factory default. Set MODEL_GATEWAY_BASEURL to the primary gateway (for one on this machine: ${LOCAL_GATEWAY_HINT}), ` +
|
|
26
27
|
"or unset MODEL_GATEWAY_FALLBACK_URLS.");
|
|
27
|
-
return { code: GATEWAY_FALLBACK_WITHOUT_PRIMARY_CODE, reason };
|
|
28
|
+
return { code: GATEWAY_FALLBACK_WITHOUT_PRIMARY_CODE, gap: "endpoint_missing", reason };
|
|
28
29
|
}
|
|
29
30
|
const anthropicMounted = view.anthropic !== undefined;
|
|
30
31
|
const entries = Object.entries(view.models ?? {});
|
|
31
32
|
const unresolved = [];
|
|
33
|
+
let laneCredentialMissing = false;
|
|
32
34
|
for (const [name, m] of entries) {
|
|
33
35
|
if (name === DEFAULT_MODEL_REF && entries.some(([k, other]) => k !== name && other === m))
|
|
34
36
|
continue;
|
|
@@ -36,11 +38,15 @@ export function judgeModelRouteEndpoint(view) {
|
|
|
36
38
|
continue;
|
|
37
39
|
if (openaiRouteBaseUrl(m.baseUrl, gateway) !== undefined)
|
|
38
40
|
continue;
|
|
39
|
-
|
|
41
|
+
const anthropicWordWithoutRoute = m.provider === "anthropic";
|
|
42
|
+
laneCredentialMissing ||= anthropicWordWithoutRoute;
|
|
43
|
+
unresolved.push(anthropicWordWithoutRoute
|
|
40
44
|
? `"${name}" (provider "anthropic", but no Anthropic route is mounted — ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN are unset — so it falls to the openai-compatible lane)`
|
|
41
45
|
: `"${name}"`);
|
|
42
46
|
}
|
|
43
|
-
|
|
47
|
+
if (unresolved.length === 0)
|
|
48
|
+
return undefined;
|
|
49
|
+
return { code: MODEL_ROUTE_ENDPOINT_MISSING_CODE, gap: laneCredentialMissing ? "lane_credential_missing" : "endpoint_missing", reason: routeEndpointMissingRefusal(unresolved) };
|
|
44
50
|
}
|
|
45
51
|
function routeEndpointMissingRefusal(quotedNames) {
|
|
46
52
|
const one = quotedNames.length === 1;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type ModelRouteEndpointVerdict, type ModelRouteGapBreach } from "./model-route-endpoint.js";
|
|
2
|
+
/**
|
|
3
|
+
* 路由读数读的八把 env 键(**闭表**;`judgeModelRouteGap` 只碰这几把,测试用代理钉「读集 ⊆ 本表」)。
|
|
4
|
+
* 配置目录的 D1 对账门把 {@link readModelRouteEnv} 的调用当作这八把键的读点(`test/config-catalog.test.ts` 的 `DELEGATED_ENV_READERS`,键集取本表,不手抄)。
|
|
5
|
+
*/
|
|
6
|
+
export declare const MODEL_ROUTE_ENV_KEYS: {
|
|
7
|
+
readonly gatewayBaseUrl: "MODEL_GATEWAY_BASEURL";
|
|
8
|
+
readonly gatewayFallbackUrls: "MODEL_GATEWAY_FALLBACK_URLS";
|
|
9
|
+
readonly provider: "MODEL_PROVIDER";
|
|
10
|
+
readonly mainId: "MODEL_ID";
|
|
11
|
+
readonly cheapId: "MODEL_CHEAP_ID";
|
|
12
|
+
readonly anthropicApiKey: "ANTHROPIC_API_KEY";
|
|
13
|
+
readonly anthropicAuthToken: "ANTHROPIC_AUTH_TOKEN";
|
|
14
|
+
readonly anthropicBaseUrl: "ANTHROPIC_BASE_URL";
|
|
15
|
+
};
|
|
16
|
+
/** 一份 env 快照(`process.env` 也满足这个形)。 */
|
|
17
|
+
export type ModelRouteEnv = Readonly<Record<string, string | undefined>>;
|
|
18
|
+
/**
|
|
19
|
+
* env 腿的 **cheap 槽**(`MODEL_CHEAP_ID`)铸不铸 —— 闭集四态,消费方用穷举 switch({@link mintedCheapId};`config.ts` 的启动通知):
|
|
20
|
+
* · `absent` —— 没设;
|
|
21
|
+
* · `without_main` —— 设了而主槽(`MODEL_ID`)没设:cheap 槽是主模型「同网关换个 id」的形,没有主槽就没有它要派生的东西 ⇒ 不铸(启动时说一句);
|
|
22
|
+
* · `same_as_main` —— 与主 id 相同:同一个 id 说的就是主模型本身 ⇒ 不铸(启动时说一句);
|
|
23
|
+
* · `minted` —— 铸(`id` = `MODEL_CHEAP_ID`)。
|
|
24
|
+
*/
|
|
25
|
+
export type EnvCheapSlot = {
|
|
26
|
+
readonly kind: "absent";
|
|
27
|
+
} | {
|
|
28
|
+
readonly kind: "without_main" | "same_as_main" | "minted";
|
|
29
|
+
readonly id: string;
|
|
30
|
+
};
|
|
31
|
+
/** cheap 槽铸出来的那个 id(不铸 ⇒ `undefined`)。**穷举 switch**:{@link EnvCheapSlot} 加一态不补臂 ⇒ 编译红。 */
|
|
32
|
+
export declare function mintedCheapId(slot: EnvCheapSlot): string | undefined;
|
|
33
|
+
/** {@link readModelRouteEnv} 的读数。 */
|
|
34
|
+
export interface ModelRouteEnvReading {
|
|
35
|
+
/** `MODEL_GATEWAY_BASEURL`;**空串 = 未设**(compose `${X:-}` 常态),缺席不铸。 */
|
|
36
|
+
readonly gatewayBaseUrl: string | undefined;
|
|
37
|
+
/** `MODEL_GATEWAY_FALLBACK_URLS` 逐项 trim、丢空项。 */
|
|
38
|
+
readonly gatewayFallbackUrls: string[];
|
|
39
|
+
/** `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL`:空串 = 未设,别名各自独立(一个空别名不遮蔽另一个)。 */
|
|
40
|
+
readonly anthropicApiKey: string | undefined;
|
|
41
|
+
readonly anthropicAuthToken: string | undefined;
|
|
42
|
+
readonly anthropicBaseUrl: string | undefined;
|
|
43
|
+
/** anthropic 路由装不装 = 两把凭据任一在场(`createBrain` 同判);只读在场性。 */
|
|
44
|
+
readonly anthropicRouteMounted: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* env 腿模型的 provider 词:显式 `MODEL_PROVIDER` 胜(原样,**不在此过闭集** —— 域外拒启是 `model-provider-word` 那条不变量的事);
|
|
47
|
+
* 缺席时「`ANTHROPIC_BASE_URL` + anthropic 凭据两样齐」⇒ `anthropic`(provider 推断),否则 `gateway`。
|
|
48
|
+
*/
|
|
49
|
+
readonly provider: string;
|
|
50
|
+
/** `provider` 的来路(推断那一臂启动时要说一句)。 */
|
|
51
|
+
readonly providerSource: "explicit" | "inferred" | "default";
|
|
52
|
+
/** `MODEL_ID`;空串 = 没有 env 主槽(env 腿不铸任何可派发条目)。 */
|
|
53
|
+
readonly mainId: string;
|
|
54
|
+
/** cheap 槽铸不铸(见 {@link EnvCheapSlot})。 */
|
|
55
|
+
readonly cheapSlot: EnvCheapSlot;
|
|
56
|
+
}
|
|
57
|
+
/** 逗号串读法的归一点:逐项 trim、丢空项(缺席 = 空串 = `[]`)。本文件的 CSV 路由键与 `config.ts` 的逗号串旋钮(按名薄壳 `csv(name)`)同读这一只;
|
|
58
|
+
* 目录模块的回显分词与 `SERVICE_AUTH_TOKENS` 的 `k=v` 对分词是同形的另两处,尚未改调(清账版收,本函数届时挪到中性模块)。 */
|
|
59
|
+
export declare const csvOf: (raw: string | undefined) => string[];
|
|
60
|
+
/**
|
|
61
|
+
* **env 模型路由读数的唯一读口**(纯:按 {@link MODEL_ROUTE_ENV_KEYS} 点名取值,不读 `process.env`,不枚举入参)。
|
|
62
|
+
* `parseModelDomain`(起服铸 `ServiceConfig`)与 {@link judgeModelRouteGap}(判官)吃同一份读数。
|
|
63
|
+
*/
|
|
64
|
+
export declare function readModelRouteEnv(env: ModelRouteEnv): ModelRouteEnvReading;
|
|
65
|
+
/**
|
|
66
|
+
* **env 腿的条目表** —— 主槽别名 `default` + 主槽 id(+ 铸出的 cheap 槽);没有 `MODEL_ID` ⇒ 空表(不铸占位条目:一个不存在的模型名
|
|
67
|
+
* 进可选目录 / 当缺省,正是 3.0.0 删掉的那种病)。`parseModelDomain` 铸真 `Model` 表与判官铸路由切面都经这一只,条目名与键序不会各写一份。
|
|
68
|
+
*/
|
|
69
|
+
export declare function envLaneTable<M extends {
|
|
70
|
+
readonly id: string;
|
|
71
|
+
}>(mainId: string, main: M, cheap: M | undefined): Record<string, M>;
|
|
72
|
+
/** {@link judgeModelRouteGap} 的旁路入参。 */
|
|
73
|
+
export interface ModelRouteGapOptions {
|
|
74
|
+
/**
|
|
75
|
+
* env 腿的模型会不会被派发(缺省 `true`)。起服期严格名册布防(`CONFIG_REQUIRE_ROSTER=true` 且接了远程中心、非 dryRun)= 运维声明 env
|
|
76
|
+
* `MODEL_ID` 是**占位**:名册落地前计费提交 503、落地后整表换装 ⇒ env 腿从不被派发,不在「配置能派发到的」射程里(备用网关那一条与派发
|
|
77
|
+
* 无关,照判)。布防与否是中心接入的事实(不是路由键),快照读不出 ⇒ 由调用方给;壳问「本机引擎、配置在本机」那一形不用传。
|
|
78
|
+
*/
|
|
79
|
+
readonly envLaneDispatchable?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 判官的读数(闭集三词,穷举 switch 消费):
|
|
83
|
+
* · `none` —— 无缺口,仅此一键;
|
|
84
|
+
* · 缺口两词 —— `code` = 起服拒启的机读码(与 `reason` 里的方括号码同一个词;`lane_credential_missing` 也带 `config.model_route_endpoint_missing`),
|
|
85
|
+
* `reason` = 起服拒启句原文(点名条目与出路)。
|
|
86
|
+
*/
|
|
87
|
+
export type ModelRouteGapReading = {
|
|
88
|
+
readonly gap: "none";
|
|
89
|
+
} | {
|
|
90
|
+
[G in ModelRouteGapBreach]: {
|
|
91
|
+
readonly gap: G;
|
|
92
|
+
readonly code: ModelRouteEndpointVerdict["code"];
|
|
93
|
+
readonly reason: string;
|
|
94
|
+
};
|
|
95
|
+
}[ModelRouteGapBreach];
|
|
96
|
+
/**
|
|
97
|
+
* **起服前可调的模型路由缺口纯判官**(与起服判官同一实现;包根导出)。
|
|
98
|
+
*
|
|
99
|
+
* @param env 一份 env 快照(只读 {@link MODEL_ROUTE_ENV_KEYS} 那八把键;`process.env` 也行 —— 起服段就是这样调的)。
|
|
100
|
+
* @returns 三词之一;有缺口时带 `code` 与 `reason`(见 {@link ModelRouteGapReading})。
|
|
101
|
+
*/
|
|
102
|
+
export declare function judgeModelRouteGap(env: ModelRouteEnv, opts?: ModelRouteGapOptions): ModelRouteGapReading;
|
|
103
|
+
//# sourceMappingURL=model-route-gap.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { DEFAULT_MODEL_REF } from "./model-select.js";
|
|
2
|
+
import { judgeModelRouteEndpoint } from "./model-route-endpoint.js";
|
|
3
|
+
export const MODEL_ROUTE_ENV_KEYS = {
|
|
4
|
+
gatewayBaseUrl: "MODEL_GATEWAY_BASEURL",
|
|
5
|
+
gatewayFallbackUrls: "MODEL_GATEWAY_FALLBACK_URLS",
|
|
6
|
+
provider: "MODEL_PROVIDER",
|
|
7
|
+
mainId: "MODEL_ID",
|
|
8
|
+
cheapId: "MODEL_CHEAP_ID",
|
|
9
|
+
anthropicApiKey: "ANTHROPIC_API_KEY",
|
|
10
|
+
anthropicAuthToken: "ANTHROPIC_AUTH_TOKEN",
|
|
11
|
+
anthropicBaseUrl: "ANTHROPIC_BASE_URL",
|
|
12
|
+
};
|
|
13
|
+
export function mintedCheapId(slot) {
|
|
14
|
+
switch (slot.kind) {
|
|
15
|
+
case "minted":
|
|
16
|
+
return slot.id;
|
|
17
|
+
case "absent":
|
|
18
|
+
case "without_main":
|
|
19
|
+
case "same_as_main":
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const declaredValue = (v) => (v !== undefined && v !== "" ? v : undefined);
|
|
24
|
+
export const csvOf = (raw) => (raw ?? "")
|
|
25
|
+
.split(",")
|
|
26
|
+
.map((s) => s.trim())
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
export function readModelRouteEnv(env) {
|
|
29
|
+
const K = MODEL_ROUTE_ENV_KEYS;
|
|
30
|
+
const anthropicApiKey = declaredValue(env[K.anthropicApiKey]);
|
|
31
|
+
const anthropicAuthToken = declaredValue(env[K.anthropicAuthToken]);
|
|
32
|
+
const anthropicBaseUrl = declaredValue(env[K.anthropicBaseUrl]);
|
|
33
|
+
const anthropicRouteMounted = anthropicApiKey !== undefined || anthropicAuthToken !== undefined;
|
|
34
|
+
const explicitProvider = declaredValue(env[K.provider]);
|
|
35
|
+
const inferAnthropic = anthropicBaseUrl !== undefined && anthropicRouteMounted;
|
|
36
|
+
const mainId = env[K.mainId] ?? "";
|
|
37
|
+
const rawCheapId = env[K.cheapId];
|
|
38
|
+
return {
|
|
39
|
+
gatewayBaseUrl: declaredValue(env[K.gatewayBaseUrl]),
|
|
40
|
+
gatewayFallbackUrls: csvOf(env[K.gatewayFallbackUrls]),
|
|
41
|
+
anthropicApiKey,
|
|
42
|
+
anthropicAuthToken,
|
|
43
|
+
anthropicBaseUrl,
|
|
44
|
+
anthropicRouteMounted,
|
|
45
|
+
provider: explicitProvider ?? (inferAnthropic ? "anthropic" : "gateway"),
|
|
46
|
+
providerSource: explicitProvider !== undefined ? "explicit" : inferAnthropic ? "inferred" : "default",
|
|
47
|
+
mainId,
|
|
48
|
+
cheapSlot: !rawCheapId
|
|
49
|
+
? { kind: "absent" }
|
|
50
|
+
: mainId === ""
|
|
51
|
+
? { kind: "without_main", id: rawCheapId }
|
|
52
|
+
: rawCheapId === mainId
|
|
53
|
+
? { kind: "same_as_main", id: rawCheapId }
|
|
54
|
+
: { kind: "minted", id: rawCheapId },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function envLaneTable(mainId, main, cheap) {
|
|
58
|
+
if (mainId === "")
|
|
59
|
+
return {};
|
|
60
|
+
const table = { [DEFAULT_MODEL_REF]: main, [main.id]: main };
|
|
61
|
+
if (cheap !== undefined)
|
|
62
|
+
table[cheap.id] = cheap;
|
|
63
|
+
return table;
|
|
64
|
+
}
|
|
65
|
+
export function judgeModelRouteGap(env, opts = {}) {
|
|
66
|
+
const r = readModelRouteEnv(env);
|
|
67
|
+
const slot = (id) => ({ id, baseUrl: "", provider: r.provider });
|
|
68
|
+
const cheapId = mintedCheapId(r.cheapSlot);
|
|
69
|
+
const models = opts.envLaneDispatchable === false ? {} : envLaneTable(r.mainId, slot(r.mainId), cheapId !== undefined ? slot(cheapId) : undefined);
|
|
70
|
+
const verdict = judgeModelRouteEndpoint({
|
|
71
|
+
gatewayBaseUrl: r.gatewayBaseUrl,
|
|
72
|
+
gatewayFallbackUrls: r.gatewayFallbackUrls,
|
|
73
|
+
anthropic: r.anthropicRouteMounted ? {} : undefined,
|
|
74
|
+
models,
|
|
75
|
+
});
|
|
76
|
+
if (verdict === undefined)
|
|
77
|
+
return { gap: "none" };
|
|
78
|
+
return { gap: verdict.gap, code: verdict.code, reason: verdict.reason };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=model-route-gap.js.map
|
|
@@ -12,7 +12,7 @@ export declare const MODEL_ROUTE_URL_INVALID_CODE = "config.model_route_url_inva
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const MODEL_ROUTE_URL_FRAGMENT_CODE = "config.model_route_url_fragment";
|
|
14
14
|
/**
|
|
15
|
-
* 模型路由 base URL 的拒因(`undefined` = 这一位合法)—— 判由
|
|
15
|
+
* 模型路由 base URL 的拒因(`undefined` = 这一位合法)—— 判由 settings-schema 的 `httpUrlFlaws`,本函数按**首个**拒因选码与出路句:
|
|
16
16
|
* ① 不是层级式 http(s) URL ⇒ `config.model_route_url_invalid`;
|
|
17
17
|
* ② 带 userinfo ⇒ `config.gateway_url_userinfo`;
|
|
18
18
|
* ③ 带 `#fragment` ⇒ `config.model_route_url_fragment`。
|
package/dist/model-route-url.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { httpUrlFlaws } from "@sema-agent/settings-schema";
|
|
2
|
+
import { buildHttpUrlRefusal } from "./url-refusal.js";
|
|
2
3
|
export const GATEWAY_URL_USERINFO_CODE = "config.gateway_url_userinfo";
|
|
3
4
|
export const MODEL_ROUTE_URL_INVALID_CODE = "config.model_route_url_invalid";
|
|
4
5
|
export const MODEL_ROUTE_URL_FRAGMENT_CODE = "config.model_route_url_fragment";
|
package/dist/model-select.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { type Model, type RunnerDeps } from "@sema-agent/core";
|
|
2
|
+
import { type AtMention } from "@sema-agent/settings-schema";
|
|
2
3
|
import type { ModelEntryRefusal } from "./model-entry-refusal.js";
|
|
4
|
+
/** 座位缺席时的读法 —— 契约 prefault 解出来的值(今天是 `{mode:"all"}`),env 车道(没有中心)的 `config.atMention` 也是它。 */
|
|
5
|
+
export declare const DEFAULT_AT_MENTION: AtMention;
|
|
6
|
+
/** 一个 `models.atMention` 值的读法:缺席 ⇒ {@link DEFAULT_AT_MENTION};在场 ⇒ 契约 schema 判形,判不过 ⇒ `undefined`(调用方 fail-closed 并响亮)。 */
|
|
7
|
+
export declare function readAtMention(raw: unknown): AtMention | undefined;
|
|
3
8
|
/**
|
|
4
9
|
* Resolve the model ref for a task spec from the request (CLI `/model` picker + `run --model`).
|
|
5
10
|
*
|
|
@@ -37,7 +42,7 @@ export declare const DEFAULT_MODEL_REF = "default";
|
|
|
37
42
|
* 起不再各抄一份「展开 + 解」。
|
|
38
43
|
*/
|
|
39
44
|
export declare function resolveMainModel(plane: Pick<RunnerDeps, "models" | "tiers">): Model;
|
|
40
|
-
export declare function resolveTaskModel(bodyModel: unknown, objective: string, catalog: Record<string, unknown>,
|
|
45
|
+
export declare function resolveTaskModel(bodyModel: unknown, objective: string, catalog: Record<string, unknown>, atMention: AtMention, refusals?: Readonly<Record<string, ModelEntryRefusal>>): {
|
|
41
46
|
model: string;
|
|
42
47
|
cleanedObjective: string;
|
|
43
48
|
unknownExplicit?: string;
|
|
@@ -84,7 +89,7 @@ export declare function refusedCatalogEntry(ref: string, refusals: Readonly<Reco
|
|
|
84
89
|
name: string;
|
|
85
90
|
refusal: ModelEntryRefusal;
|
|
86
91
|
} | undefined;
|
|
87
|
-
/** [ref]
|
|
92
|
+
/** [ref] 判别式拒因:这次**用户选择**不在 `atMention` 许可之内(`none`,或 `only` 而不在名里)。`resolved` 已是目录 name 形(归一后)。 */
|
|
88
93
|
export interface ModelNotAllowed {
|
|
89
94
|
/** 调用方发来的原始 ref(name / 档位词 / 别名 / id / `@name`),已做过日志安全的 repr 归一。 */
|
|
90
95
|
requested: string;
|
|
@@ -94,28 +99,26 @@ export interface ModelNotAllowed {
|
|
|
94
99
|
source: "explicit" | "mention";
|
|
95
100
|
}
|
|
96
101
|
/**
|
|
97
|
-
* [ref] / [ref] ——
|
|
102
|
+
* [ref] / [ref] —— 「这个 ref 此刻可不可以被用户 `@` / 显式点选」的**唯一**判据(`models.atMention`,三态闭集,穷举 switch)。
|
|
98
103
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
+
* 判序(一条规则):先把 ref 归一到**目录条目**({@link matchCatalogModel},name / 档位词 / 别名 / id 同一只);目录里根本没有的 ref ⇒ 恒 `true`
|
|
105
|
+
* —— 那是「未知模型」那道门的辖区(fresh 400 / resume 降级留声),本门只答「在目录里,但准不准点」,两道门同码同拒会让消费端分不清
|
|
106
|
+
* "没这模型"和"不让你点"。然后按 `mode`:
|
|
107
|
+
* · `all` ⇒ `true`;
|
|
108
|
+
* · `none` ⇒ `false`(一个都不许);
|
|
109
|
+
* · `only` ⇒ ref 归一到的那只条目**自己的目录名**在名单里 ⇒ `true`(名单按目录名直比)。
|
|
104
110
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
111
|
+
* 为什么 ref 侧要先归一、不拿 ref 串直比:`expandTiers` 的增广目录里,档位词(`pro`)与 CC 别名(`sonnet`)的值与 `config.models[<name>]`
|
|
112
|
+
* 是**同一个对象引用**——裸串比较会让 `@pro` 跳过一张按 name 写的名单(同一只模型,两个键)。名单侧不归一:`only` 的名在 stage 期已按本世代
|
|
113
|
+
* 可用目录收窄成目录名(settings-schema `narrowAtMention`),名单项是档位词 / 别名 / id 的形只可能来自绕过 stage 的写者 —— 它们准不了任何东西。
|
|
114
|
+
* 🔴 **刻意没有「id 相等」退路**(codex 复审 R1 [high]):目录**允许两条不同 name 的条目共享同一个上游 `Model.id`,却各自带不同的
|
|
115
|
+
* `baseUrl` / `apiKeyEnv` / `cost` / provider** —— 按 id 判同会把 `safe` 与 `premium` 合并,一张只含 `safe` 的名单会放行 `premium`。
|
|
116
|
+
* 🔴 S-704:名里写着一条**不可用**条目的名字 ⇒ 它准不了任何东西(不经 id 回退 / 别名改绑去准另一只模型 —— `matchCatalogModel` 的名字保留律)。
|
|
117
|
+
* `only` 的名在 stage 期已按本世代可用目录收窄过(settings-schema `narrowAtMention`,收窄到一个不剩 ⇒ `none`),所以这里的悬空名只来自绕过 stage 的写者(按名直比,悬空名不等于任何条目的名)。
|
|
110
118
|
*
|
|
111
|
-
*
|
|
112
|
-
* 目录里根本没有的 ref ⇒ 恒 `true`:那是「未知模型」那道门的辖区(fresh 400 / resume 降级留声),
|
|
113
|
-
* 本门只答「在目录里,但准不准点」——两道门同码同拒会让消费端分不清"没这模型"和"不让你点"。
|
|
114
|
-
*
|
|
115
|
-
* ⚠️ 射程:本门是**提交时**门。core 运行时路由(degrade 降级链 / cascade 梯 / roles 解析)按 operator
|
|
116
|
-
* 配置自己走,**不经本门**——那不是一次用户选择,如实声明,不假装是运行时执法。
|
|
119
|
+
* ⚠️ 射程:本门是**提交时**门。core 运行时路由(degrade 降级链 / cascade 梯 / roles 解析)按 operator 配置自己走,**不经本门**。
|
|
117
120
|
*/
|
|
118
|
-
export declare function
|
|
121
|
+
export declare function isAtMentionable(ref: string, catalog: Record<string, unknown>, atMention: AtMention, refusals?: Readonly<Record<string, ModelEntryRefusal>>): boolean;
|
|
119
122
|
/**
|
|
120
123
|
* [ref] —— ref → **终端 catalog name**(拒因/日志的可读形)。
|
|
121
124
|
*
|
|
@@ -144,7 +147,7 @@ export type ModelImageInput = (typeof MODEL_IMAGE_INPUTS)[number];
|
|
|
144
147
|
* · 目录行 `GET /v1/models` 的 `vision`:`yes` ⇒ `true`,`no` ⇒ `false`,`undeclared` ⇒ **键缺席**(不替没声明的模型答「收」也不答「不收」);
|
|
145
148
|
* · 运行期的带图预检 {@link modelSupportsImages}:只有明说 `no` 才出信号。
|
|
146
149
|
* 此前两处各判各的,且对「没声明」答法相反(目录行报 false、预检放行)——客户端只读得到目录那一位,于是在手写、没声明 `input` 的
|
|
147
|
-
* 条目上把用户的图拦在了本地,而引擎其实会把图交给模型。env
|
|
150
|
+
* 条目上把用户的图拦在了本地,而引擎其实会把图交给模型。env 车道与 web-admin 车道恒写 `input`,分叉只落在手写目录条目上。
|
|
148
151
|
* `input` 不是数组(手写错形)与条目不在,同归 `undeclared`:没有可信的声明。
|
|
149
152
|
*/
|
|
150
153
|
export declare function modelImageInput(model: {
|
package/dist/model-select.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { expandTiers, parseModelMention, resolveTaskModel as coreResolveTaskModel } from "@sema-agent/core";
|
|
2
|
+
import { DOMAIN_SCHEMAS } from "@sema-agent/settings-schema";
|
|
3
|
+
const AT_MENTION_SEAT = DOMAIN_SCHEMAS.models.shape.atMention;
|
|
4
|
+
export const DEFAULT_AT_MENTION = Object.freeze(AT_MENTION_SEAT.parse(undefined));
|
|
5
|
+
export function readAtMention(raw) {
|
|
6
|
+
const r = AT_MENTION_SEAT.safeParse(raw);
|
|
7
|
+
return r.success ? r.data : undefined;
|
|
8
|
+
}
|
|
2
9
|
export const DEFAULT_MODEL_REF = "default";
|
|
3
10
|
export function resolveMainModel(plane) {
|
|
4
11
|
const expanded = expandTiers(plane.models, plane.tiers ?? {}) ?? plane.models;
|
|
5
12
|
return coreResolveTaskModel({ model: DEFAULT_MODEL_REF }, { ...(expanded !== undefined ? { models: expanded } : {}) }).model;
|
|
6
13
|
}
|
|
7
|
-
export function resolveTaskModel(bodyModel, objective, catalog,
|
|
14
|
+
export function resolveTaskModel(bodyModel, objective, catalog, atMention, refusals) {
|
|
8
15
|
const mention = parseModelMention(objective, [...Object.keys(refusals ?? {}), ...Object.keys(catalog)]);
|
|
9
16
|
const mentionUsable = mention.model !== undefined && Object.hasOwn(catalog, mention.model) ? mention.model : undefined;
|
|
10
17
|
const explicit = typeof bodyModel === "string" ? matchCatalogModel(bodyModel, catalog, refusals) : undefined;
|
|
@@ -20,7 +27,7 @@ export function resolveTaskModel(bodyModel, objective, catalog, allowlist, refus
|
|
|
20
27
|
const unknown = present && explicit === undefined && refusedExplicit === undefined;
|
|
21
28
|
const model = explicit ?? mentionUsable ?? DEFAULT_MODEL_REF;
|
|
22
29
|
const picked = explicit !== undefined ? { ref: explicit, source: "explicit", requested: repr } : mentionUsable !== undefined ? { ref: mentionUsable, source: "mention", requested: mentionUsable } : undefined;
|
|
23
|
-
const notAllowed = picked !== undefined && !
|
|
30
|
+
const notAllowed = picked !== undefined && !isAtMentionable(picked.ref, catalog, atMention, refusals)
|
|
24
31
|
? { requested: picked.requested, resolved: terminalCatalogName(picked.ref, catalog, refusals) ?? picked.ref, source: picked.source }
|
|
25
32
|
: undefined;
|
|
26
33
|
return {
|
|
@@ -51,24 +58,22 @@ export function refusedCatalogEntry(ref, refusals) {
|
|
|
51
58
|
return { name, refusal: r };
|
|
52
59
|
return undefined;
|
|
53
60
|
}
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const entry = catalogEntryOf(ref, catalog, refusals);
|
|
58
|
-
if (entry === undefined)
|
|
61
|
+
export function isAtMentionable(ref, catalog, atMention, refusals) {
|
|
62
|
+
const name = terminalCatalogName(ref, catalog, refusals);
|
|
63
|
+
if (name === undefined)
|
|
59
64
|
return true;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (allowed === undefined)
|
|
63
|
-
continue;
|
|
64
|
-
if (allowed === entry)
|
|
65
|
+
switch (atMention.mode) {
|
|
66
|
+
case "all":
|
|
65
67
|
return true;
|
|
68
|
+
case "none":
|
|
69
|
+
return false;
|
|
70
|
+
case "only":
|
|
71
|
+
return atMention.models.includes(name);
|
|
72
|
+
default: {
|
|
73
|
+
const unhandled = atMention;
|
|
74
|
+
throw new Error(`atMention: unknown mode ${JSON.stringify(unhandled)}`);
|
|
75
|
+
}
|
|
66
76
|
}
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
function catalogEntryOf(ref, catalog, refusals) {
|
|
70
|
-
const name = matchCatalogModel(ref, catalog, refusals);
|
|
71
|
-
return name === undefined ? undefined : catalog[name];
|
|
72
77
|
}
|
|
73
78
|
export function terminalCatalogName(ref, catalog, refusals) {
|
|
74
79
|
const key = matchCatalogModel(ref, catalog, refusals);
|