@eddyskywalker/dsh-chatgpt-subscription 0.2.14 → 0.2.16
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/CHANGELOG.md +12 -1
- package/README.md +26 -4
- package/lib/client.js +0 -115
- package/lib/client.js.map +1 -1
- package/lib/index.js +248 -27
- package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +1 -15
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/host/preferences.d.ts.map +1 -1
- package/lib/types/host/subagent-model-authorization.d.ts +177 -0
- package/lib/types/host/subagent-model-authorization.d.ts.map +1 -0
- package/lib/types/index.d.ts +21 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/contracts.d.ts +0 -4
- package/lib/types/shared/contracts.d.ts.map +1 -1
- package/lib/types/shared/preferences.d.ts +0 -1
- package/lib/types/shared/preferences.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
3
|
import * as LlmModule from "@deepseek-ai/dsh-llm";
|
|
3
4
|
import { HarnessError, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, attributionHeaders, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
4
5
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
@@ -12,7 +13,6 @@ import path, { dirname, join } from "node:path";
|
|
|
12
13
|
import os, { homedir } from "node:os";
|
|
13
14
|
import { ProxyAgent, fetch as fetch$1 } from "undici";
|
|
14
15
|
import * as SettingsModule from "@deepseek-ai/dsh-settings";
|
|
15
|
-
import z from "@deepseek-ai/schemastery";
|
|
16
16
|
import fsPromises, { chmod, lstat, mkdir, open, rename, stat, unlink } from "node:fs/promises";
|
|
17
17
|
import { isDeepStrictEqual } from "node:util";
|
|
18
18
|
import { URL as URL$1, URLSearchParams as URLSearchParams$1 } from "node:url";
|
|
@@ -1361,8 +1361,6 @@ const DEFAULT_PREFERENCES = {
|
|
|
1361
1361
|
"gpt-5.6-terra": 272e3,
|
|
1362
1362
|
"gpt-5.6-luna": 272e3
|
|
1363
1363
|
},
|
|
1364
|
-
subagentContextWindow: null,
|
|
1365
|
-
subagentMaxDepth: null,
|
|
1366
1364
|
proxyMode: "auto",
|
|
1367
1365
|
customProxyUrl: null
|
|
1368
1366
|
};
|
|
@@ -1407,8 +1405,6 @@ function registerPreferenceStore(settings) {
|
|
|
1407
1405
|
"gpt-5.6-terra": z.number().step(1).min(1).max(GPT_56_MAX_CONTEXT_WINDOW).default(DEFAULT_PREFERENCES.contextWindowOverrides["gpt-5.6-terra"]),
|
|
1408
1406
|
"gpt-5.6-luna": z.number().step(1).min(1).max(GPT_56_MAX_CONTEXT_WINDOW).default(DEFAULT_PREFERENCES.contextWindowOverrides["gpt-5.6-luna"])
|
|
1409
1407
|
}).default(DEFAULT_PREFERENCES.contextWindowOverrides),
|
|
1410
|
-
subagentContextWindow: z.union([z.number().step(1).min(1), z.const(null)]).default(DEFAULT_PREFERENCES.subagentContextWindow),
|
|
1411
|
-
subagentMaxDepth: z.union([z.number().step(1).min(0).max(3), z.const(null)]).default(DEFAULT_PREFERENCES.subagentMaxDepth),
|
|
1412
1408
|
proxyMode: z.union([
|
|
1413
1409
|
z.const("auto"),
|
|
1414
1410
|
z.const("custom"),
|
|
@@ -1449,8 +1445,6 @@ var SettingsPreferenceStore = class {
|
|
|
1449
1445
|
...this.scope.get().contextWindowOverrides,
|
|
1450
1446
|
...patch.contextWindowOverrides
|
|
1451
1447
|
};
|
|
1452
|
-
if (patch.subagentContextWindow !== void 0) normalized.subagentContextWindow = patch.subagentContextWindow;
|
|
1453
|
-
if (patch.subagentMaxDepth !== void 0) normalized.subagentMaxDepth = patch.subagentMaxDepth;
|
|
1454
1448
|
if (patch.proxyMode !== void 0) {
|
|
1455
1449
|
if (!isProxyMode(patch.proxyMode)) throw new PreferenceError("Unsupported proxy mode preference.");
|
|
1456
1450
|
normalized.proxyMode = patch.proxyMode;
|
|
@@ -3145,14 +3139,6 @@ function readPreferencesUpdate(value, current) {
|
|
|
3145
3139
|
}
|
|
3146
3140
|
patch.contextWindowOverrides = overrides;
|
|
3147
3141
|
}
|
|
3148
|
-
if ("subagentContextWindow" in value) {
|
|
3149
|
-
if (value.subagentContextWindow !== null && (!Number.isSafeInteger(value.subagentContextWindow) || value.subagentContextWindow < 1)) throw new PreferenceError("subagentContextWindow must be null or a positive integer.");
|
|
3150
|
-
patch.subagentContextWindow = value.subagentContextWindow;
|
|
3151
|
-
}
|
|
3152
|
-
if ("subagentMaxDepth" in value) {
|
|
3153
|
-
if (value.subagentMaxDepth !== null && (!Number.isSafeInteger(value.subagentMaxDepth) || value.subagentMaxDepth < 0 || value.subagentMaxDepth > 3)) throw new PreferenceError(`subagentMaxDepth must be null or an integer from 0 to 3.`);
|
|
3154
|
-
patch.subagentMaxDepth = value.subagentMaxDepth;
|
|
3155
|
-
}
|
|
3156
3142
|
if ("proxyMode" in value) {
|
|
3157
3143
|
if (value.proxyMode !== "auto" && value.proxyMode !== "custom" && value.proxyMode !== "direct") throw new PreferenceError("proxyMode must be auto, custom, or direct.");
|
|
3158
3144
|
patch.proxyMode = value.proxyMode;
|
|
@@ -4926,7 +4912,7 @@ function sanitizeText(text) {
|
|
|
4926
4912
|
function isRecord(value) {
|
|
4927
4913
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4928
4914
|
}
|
|
4929
|
-
function asString(value) {
|
|
4915
|
+
function asString$1(value) {
|
|
4930
4916
|
return typeof value === "string" ? value : void 0;
|
|
4931
4917
|
}
|
|
4932
4918
|
function safeJsonParse(text) {
|
|
@@ -4949,10 +4935,10 @@ function parseArguments(raw) {
|
|
|
4949
4935
|
return isRecord(parsed) ? parsed : {};
|
|
4950
4936
|
}
|
|
4951
4937
|
function imageBlockToPart(block) {
|
|
4952
|
-
let data = asString(block.data) || asString(block.base64);
|
|
4938
|
+
let data = asString$1(block.data) || asString$1(block.base64);
|
|
4953
4939
|
const source = isRecord(block.source) ? block.source : void 0;
|
|
4954
|
-
if (!data && source) data = asString(source.data) || asString(source.base64);
|
|
4955
|
-
let mimeType = asString(block.mimeType) || asString(block.mediaType) || (source ? asString(source.mimeType) || asString(source.mediaType) : void 0) || "image/png";
|
|
4940
|
+
if (!data && source) data = asString$1(source.data) || asString$1(source.base64);
|
|
4941
|
+
let mimeType = asString$1(block.mimeType) || asString$1(block.mediaType) || (source ? asString$1(source.mimeType) || asString$1(source.mediaType) : void 0) || "image/png";
|
|
4956
4942
|
if (data?.startsWith("data:")) {
|
|
4957
4943
|
const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
|
|
4958
4944
|
if (match) {
|
|
@@ -4998,7 +4984,7 @@ function replayBlockFor(message, index) {
|
|
|
4998
4984
|
}
|
|
4999
4985
|
}
|
|
5000
4986
|
function thoughtSignature(part) {
|
|
5001
|
-
return asString(part?.thoughtSignature) || asString(part?.thought_signature) || asString(part?.thinkingSignature) || asString(part?.textSignature);
|
|
4987
|
+
return asString$1(part?.thoughtSignature) || asString$1(part?.thought_signature) || asString$1(part?.thinkingSignature) || asString$1(part?.textSignature);
|
|
5002
4988
|
}
|
|
5003
4989
|
function replayPart(part) {
|
|
5004
4990
|
const copy = { ...part };
|
|
@@ -5017,7 +5003,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
5017
5003
|
if (!isRecord(block)) continue;
|
|
5018
5004
|
const replay = replayBlockFor(message, index);
|
|
5019
5005
|
const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord) : [];
|
|
5020
|
-
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString(part.text) || "").join("") === sanitizeText(String(block.text || ""))) {
|
|
5006
|
+
if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$1(part.text) || "").join("") === sanitizeText(String(block.text || ""))) {
|
|
5021
5007
|
parts.push(...originalParts.map(replayPart));
|
|
5022
5008
|
continue;
|
|
5023
5009
|
}
|
|
@@ -5038,7 +5024,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
|
|
|
5038
5024
|
const toolId = String(block.id || "");
|
|
5039
5025
|
const toolName = String(block.name || "");
|
|
5040
5026
|
const originalCall = originalParts.find((part) => isRecord(part.functionCall));
|
|
5041
|
-
const wireId = asString((isRecord(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
|
|
5027
|
+
const wireId = asString$1((isRecord(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
|
|
5042
5028
|
toolCalls.set(toolId, {
|
|
5043
5029
|
name: toolName,
|
|
5044
5030
|
id: wireId
|
|
@@ -5315,8 +5301,8 @@ function processStreamLine(line, state) {
|
|
|
5315
5301
|
if (isRecord(part.functionCall)) {
|
|
5316
5302
|
out.push(...closeCurrentBlock(state));
|
|
5317
5303
|
const fc = part.functionCall;
|
|
5318
|
-
const toolName = asString(fc.name) || "";
|
|
5319
|
-
const toolId = asString(fc.id) || sanitizeToolCallId("", toolName);
|
|
5304
|
+
const toolName = asString$1(fc.name) || "";
|
|
5305
|
+
const toolId = asString$1(fc.id) || sanitizeToolCallId("", toolName);
|
|
5320
5306
|
const argsText = JSON.stringify(isRecord(fc.args) ? fc.args : {});
|
|
5321
5307
|
const index = state.blocks.length;
|
|
5322
5308
|
const block = {
|
|
@@ -5354,7 +5340,7 @@ function processStreamLine(line, state) {
|
|
|
5354
5340
|
}
|
|
5355
5341
|
collectUsage(chunk.usageMetadata, state);
|
|
5356
5342
|
if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
|
|
5357
|
-
const finishReason = asString(candidate?.finishReason) || asString(responseData.finishReason);
|
|
5343
|
+
const finishReason = asString$1(candidate?.finishReason) || asString$1(responseData.finishReason);
|
|
5358
5344
|
if (finishReason) {
|
|
5359
5345
|
state.finishReason = finishReason;
|
|
5360
5346
|
out.push(...closeCurrentBlock(state));
|
|
@@ -5699,7 +5685,230 @@ function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetch
|
|
|
5699
5685
|
});
|
|
5700
5686
|
}
|
|
5701
5687
|
//#endregion
|
|
5688
|
+
//#region src/host/subagent-model-authorization.ts
|
|
5689
|
+
/** DSH settings namespace owned by the Subagent settings card. */
|
|
5690
|
+
const SUBAGENT_MODEL_SELECTION_NAMESPACE = "subagent-model-selection";
|
|
5691
|
+
/** Durable Session event carrying one Session's authorized child routes. */
|
|
5692
|
+
const SUBAGENT_POLICY_EVENT = "subagent/model-selection-policy";
|
|
5693
|
+
/** Delegation tools whose child routes this guard authorizes. */
|
|
5694
|
+
const DEFAULT_DELEGATION_TOOLS = ["subagent"];
|
|
5695
|
+
/**
|
|
5696
|
+
* Read one deployment event field as a string.
|
|
5697
|
+
* @param value - Candidate field value from a durable event.
|
|
5698
|
+
* @returns the string value, or undefined for any other type.
|
|
5699
|
+
*/
|
|
5700
|
+
function asString(value) {
|
|
5701
|
+
return typeof value === "string" ? value : void 0;
|
|
5702
|
+
}
|
|
5703
|
+
/**
|
|
5704
|
+
* Read one deployment event field as a plain object.
|
|
5705
|
+
* @param value - Candidate field value from a durable event.
|
|
5706
|
+
* @returns the record value, or undefined for arrays, null, and primitives.
|
|
5707
|
+
*/
|
|
5708
|
+
function asRecord(value) {
|
|
5709
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
5710
|
+
}
|
|
5711
|
+
/**
|
|
5712
|
+
* Read one deployment event field as a boolean.
|
|
5713
|
+
* @param value - Candidate field value from a durable event.
|
|
5714
|
+
* @returns the boolean value, or undefined for any other type.
|
|
5715
|
+
*/
|
|
5716
|
+
function asBoolean(value) {
|
|
5717
|
+
return typeof value === "boolean" ? value : void 0;
|
|
5718
|
+
}
|
|
5719
|
+
/**
|
|
5720
|
+
* Parse the allowlist out of a durable route-policy event.
|
|
5721
|
+
* @param data - `subagent/model-selection-policy` event payload.
|
|
5722
|
+
* @returns every well-formed route, or undefined when the payload carries none.
|
|
5723
|
+
*/
|
|
5724
|
+
function parseAllowedRoutes(data) {
|
|
5725
|
+
const allowed = asRecord(data)?.["allowedModels"];
|
|
5726
|
+
if (!Array.isArray(allowed)) return void 0;
|
|
5727
|
+
const routes = [];
|
|
5728
|
+
for (const entry of allowed) {
|
|
5729
|
+
const record = asRecord(entry);
|
|
5730
|
+
const provider = asString(record?.["provider"]);
|
|
5731
|
+
const model = asString(record?.["model"]);
|
|
5732
|
+
if (provider === void 0 || model === void 0) continue;
|
|
5733
|
+
if (provider.length === 0 || model.length === 0) continue;
|
|
5734
|
+
routes.push({
|
|
5735
|
+
provider,
|
|
5736
|
+
model
|
|
5737
|
+
});
|
|
5738
|
+
}
|
|
5739
|
+
return routes.length === 0 ? void 0 : routes;
|
|
5740
|
+
}
|
|
5741
|
+
/**
|
|
5742
|
+
* Find one Session's recorded allowlist among its durable events.
|
|
5743
|
+
* @param session - Session whose log is scanned.
|
|
5744
|
+
* @returns the authorized routes, or undefined for a Session that recorded none.
|
|
5745
|
+
*/
|
|
5746
|
+
function policyRoutesOf(session) {
|
|
5747
|
+
if (session === void 0 || typeof session.eventAt !== "function") return void 0;
|
|
5748
|
+
for (let seq = 0; seq < 256; seq += 1) {
|
|
5749
|
+
let event;
|
|
5750
|
+
try {
|
|
5751
|
+
event = session.eventAt(seq);
|
|
5752
|
+
} catch {
|
|
5753
|
+
return;
|
|
5754
|
+
}
|
|
5755
|
+
if (event === void 0) return void 0;
|
|
5756
|
+
if (event.type !== "subagent/model-selection-policy") continue;
|
|
5757
|
+
const routes = parseAllowedRoutes(event.data);
|
|
5758
|
+
if (routes !== void 0) return routes;
|
|
5759
|
+
}
|
|
5760
|
+
}
|
|
5761
|
+
/**
|
|
5762
|
+
* Resolve the allowlist a delegation from this agent must respect: the agent's
|
|
5763
|
+
* own recorded policy, else the nearest ancestor Session that recorded one
|
|
5764
|
+
* (the inheritance the delegation tool applies to child Sessions).
|
|
5765
|
+
* @param agent - Calling agent.
|
|
5766
|
+
* @param sessions - Session registry used for ancestor lookup.
|
|
5767
|
+
* @returns the authorized routes, or undefined when no Session recorded any.
|
|
5768
|
+
*/
|
|
5769
|
+
function authorizedRoutesFor(agent, sessions) {
|
|
5770
|
+
let session = agent?.session;
|
|
5771
|
+
for (let depth = 0; depth < 8 && session !== void 0; depth += 1) {
|
|
5772
|
+
const recorded = policyRoutesOf(session);
|
|
5773
|
+
if (recorded !== void 0) return recorded;
|
|
5774
|
+
const header = session.header;
|
|
5775
|
+
if (header?.origin !== "subagent") return void 0;
|
|
5776
|
+
const parentId = asString(header.parentSession);
|
|
5777
|
+
if (parentId === void 0) return void 0;
|
|
5778
|
+
session = sessions.get(parentId);
|
|
5779
|
+
}
|
|
5780
|
+
}
|
|
5781
|
+
/**
|
|
5782
|
+
* Read the Host preference that owns the allowlist. Values in the stored
|
|
5783
|
+
* document are untrusted JSON, so every field is narrowed before use.
|
|
5784
|
+
* @param settings - Live settings service, when composed.
|
|
5785
|
+
* @returns the resolved preference, or undefined without a settings service.
|
|
5786
|
+
*/
|
|
5787
|
+
function subagentModelSelectionPreference(settings) {
|
|
5788
|
+
if (settings === void 0) return void 0;
|
|
5789
|
+
const register = settings["register"];
|
|
5790
|
+
if (typeof register !== "function") return void 0;
|
|
5791
|
+
try {
|
|
5792
|
+
const value = asRecord(register.call(settings, SUBAGENT_MODEL_SELECTION_NAMESPACE, z.object({
|
|
5793
|
+
enabled: z.boolean().default(false),
|
|
5794
|
+
allowedModels: z.array(z.object({
|
|
5795
|
+
provider: z.string().min(1).required(),
|
|
5796
|
+
model: z.string().min(1).required()
|
|
5797
|
+
})).default([])
|
|
5798
|
+
})).get());
|
|
5799
|
+
if (value === void 0) return void 0;
|
|
5800
|
+
return {
|
|
5801
|
+
enabled: asBoolean(value["enabled"]) === true,
|
|
5802
|
+
allowedModels: parseAllowedRoutes(value) ?? []
|
|
5803
|
+
};
|
|
5804
|
+
} catch {
|
|
5805
|
+
return;
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5808
|
+
/** Whether an exact route is authorized by a allowlist. */
|
|
5809
|
+
function routesInclude(allowed, provider, model) {
|
|
5810
|
+
return allowed.some((route) => route.provider === provider && route.model === model);
|
|
5811
|
+
}
|
|
5812
|
+
/**
|
|
5813
|
+
* Build the denial reason for a delegation that would run on an unauthorized
|
|
5814
|
+
* route. The reason names the authorized routes so the next call can select one.
|
|
5815
|
+
* @param provider - Effective child provider id, when one is known.
|
|
5816
|
+
* @param model - Effective child model id, when one is known.
|
|
5817
|
+
* @param allowed - Routes the calling Session authorizes.
|
|
5818
|
+
* @param explicit - Whether the model named the route in the tool arguments.
|
|
5819
|
+
* @returns the corrective reason handed back to the model.
|
|
5820
|
+
*/
|
|
5821
|
+
function unauthorizedRouteReason(provider, model, allowed, explicit) {
|
|
5822
|
+
const route = provider === void 0 || model === void 0 ? "the inherited route" : `route "${provider}/${model}"`;
|
|
5823
|
+
return `subagent model selection: ${explicit ? "the model this call selected is not on the Session allowlist" : "the route this call would inherit from the parent is not on the Session allowlist"} (${route}). Provide an authorized provider and model — ${allowed.map((entry) => `${entry.provider}/${entry.model}`).join(", ")} — using list_subagent_models to inspect their reasoning efforts.`;
|
|
5824
|
+
}
|
|
5825
|
+
/**
|
|
5826
|
+
* Decide whether one delegation call may start its child.
|
|
5827
|
+
* @param agent - Calling agent.
|
|
5828
|
+
* @param toolName - Tool being dispatched.
|
|
5829
|
+
* @param args - Parsed tool arguments.
|
|
5830
|
+
* @param preference - Current Host preference, when the settings service exists.
|
|
5831
|
+
* @param sessions - Session registry used for ancestor lookup.
|
|
5832
|
+
* @param toolNames - Delegation tool names this guard authorizes.
|
|
5833
|
+
* @param scope - Whether an unrecorded Session falls back to the preference.
|
|
5834
|
+
* @returns a denial reason, or undefined to leave the call untouched.
|
|
5835
|
+
*/
|
|
5836
|
+
function delegationDenialReason(agent, toolName, args, preference, sessions, toolNames = DEFAULT_DELEGATION_TOOLS, scope = "session") {
|
|
5837
|
+
if (!toolNames.includes(toolName)) return void 0;
|
|
5838
|
+
if (preference !== void 0 && !preference.enabled) return void 0;
|
|
5839
|
+
const allowed = authorizedRoutesFor(agent, sessions) ?? (scope === "preference" ? preference?.allowedModels ?? [] : []);
|
|
5840
|
+
if (allowed.length === 0) return void 0;
|
|
5841
|
+
const request = asRecord(args) ?? {};
|
|
5842
|
+
const requestedProvider = asString(request["provider"]);
|
|
5843
|
+
const requestedModel = asString(request["model"]);
|
|
5844
|
+
const explicit = requestedProvider !== void 0 || requestedModel !== void 0;
|
|
5845
|
+
const implicit = requestedProvider === void 0 && requestedModel === void 0;
|
|
5846
|
+
const provider = implicit ? asString(agent?.options?.provider) : requestedProvider;
|
|
5847
|
+
const model = implicit ? asString(agent?.options?.model) : requestedModel;
|
|
5848
|
+
if (provider === void 0 || model === void 0) return;
|
|
5849
|
+
if (routesInclude(allowed, provider, model)) return void 0;
|
|
5850
|
+
return unauthorizedRouteReason(provider, model, allowed, explicit);
|
|
5851
|
+
}
|
|
5852
|
+
/**
|
|
5853
|
+
* Build the monotonic tool guard for one deployment. The Host preference is
|
|
5854
|
+
* sampled from the live settings document on every call, because a settings
|
|
5855
|
+
* edit must not rebuild the guard the way it cannot rebuild a Session.
|
|
5856
|
+
* @param options - settings, session registry, and delegation tool names.
|
|
5857
|
+
* @returns a guard that denies delegations outside the Session allowlist.
|
|
5858
|
+
*/
|
|
5859
|
+
function createSubagentAuthorization(options) {
|
|
5860
|
+
return (agent, toolName, args) => delegationDenialReason(agent, toolName, args, subagentModelSelectionPreference(options.settings), options.sessions, options.toolNames, options.scope ?? "session");
|
|
5861
|
+
}
|
|
5862
|
+
/** Delegation names this guard recognizes when configuration omits them. */
|
|
5863
|
+
function normalizeDelegationToolNames(value) {
|
|
5864
|
+
const names = Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
|
|
5865
|
+
return [...new Set(names.length === 0 ? [...DEFAULT_DELEGATION_TOOLS] : names.map((name) => name.trim()))];
|
|
5866
|
+
}
|
|
5867
|
+
/**
|
|
5868
|
+
* Validate the plugin configuration that owns this guard.
|
|
5869
|
+
* @param toolNames - Candidate delegation tool names.
|
|
5870
|
+
* @returns the exact names this guard authorizes.
|
|
5871
|
+
*/
|
|
5872
|
+
function validateDelegationToolNames(toolNames) {
|
|
5873
|
+
if (toolNames.length === 0) throw new Error("dsh-chatgpt-subscription: subagentModelAuthorization.toolNames must name at least one delegation tool");
|
|
5874
|
+
for (const name of toolNames) if (name.length === 0 || name !== name.trim()) throw new Error(`dsh-chatgpt-subscription: subagentModelAuthorization.toolNames entry "${name}" must be a non-empty trimmed string`);
|
|
5875
|
+
return [...toolNames];
|
|
5876
|
+
}
|
|
5877
|
+
/**
|
|
5878
|
+
* Register the monotonic guard on the Host tool registry.
|
|
5879
|
+
* @param ctx - Host context carrying `tools` (and optionally `settings`).
|
|
5880
|
+
* @param sessions - Session registry used for ancestor lookup.
|
|
5881
|
+
* @param config - Enforcement toggle and delegation tool names.
|
|
5882
|
+
* @returns the exact disposer that unregisters the guard.
|
|
5883
|
+
*/
|
|
5884
|
+
function installSubagentModelAuthorization(ctx, sessions, config = {}) {
|
|
5885
|
+
const toolNames = validateDelegationToolNames(config.toolNames ?? [...DEFAULT_DELEGATION_TOOLS]);
|
|
5886
|
+
const scope = validateAuthorizationScope(config.scope ?? "session");
|
|
5887
|
+
const settings = ctx.get?.("settings");
|
|
5888
|
+
const authorize = createSubagentAuthorization({
|
|
5889
|
+
settings,
|
|
5890
|
+
sessions,
|
|
5891
|
+
toolNames,
|
|
5892
|
+
scope
|
|
5893
|
+
});
|
|
5894
|
+
return ctx.tools.guard((exec) => authorize(exec.agent, exec.name, exec.arguments));
|
|
5895
|
+
}
|
|
5896
|
+
/**
|
|
5897
|
+
* Validate the configured authorization scope.
|
|
5898
|
+
* @param scope - Candidate scope from deployment configuration.
|
|
5899
|
+
* @returns the exact scope this guard enforces.
|
|
5900
|
+
*/
|
|
5901
|
+
function validateAuthorizationScope(scope) {
|
|
5902
|
+
if (scope === "session" || scope === "preference") return scope;
|
|
5903
|
+
throw new Error(`dsh-chatgpt-subscription: subagentModelScope must be "session" or "preference", received ${JSON.stringify(scope)}`);
|
|
5904
|
+
}
|
|
5905
|
+
//#endregion
|
|
5702
5906
|
//#region src/index.ts
|
|
5907
|
+
const Config = z.object({
|
|
5908
|
+
subagentModelAuthorization: z.boolean().default(true),
|
|
5909
|
+
subagentModelTools: z.array(z.string()).default([]),
|
|
5910
|
+
subagentModelScope: z.union([z.const("session"), z.const("preference")]).default("session")
|
|
5911
|
+
});
|
|
5703
5912
|
const inject = [
|
|
5704
5913
|
"webServer",
|
|
5705
5914
|
"llm",
|
|
@@ -5708,12 +5917,24 @@ const inject = [
|
|
|
5708
5917
|
"settings",
|
|
5709
5918
|
"loader"
|
|
5710
5919
|
];
|
|
5711
|
-
function apply(ctx) {
|
|
5920
|
+
function apply(ctx, pluginConfig = {}) {
|
|
5712
5921
|
const store = createPlatformTokenStore();
|
|
5713
5922
|
const preferences = registerPreferenceStore(ctx.settings);
|
|
5714
5923
|
const antigravityStore = new FileCredentialStore();
|
|
5715
5924
|
const antigravityModelSettings = new FileModelSettingsStore();
|
|
5716
5925
|
const antigravityPreferences = registerAntigravityPreferenceStore(ctx.settings, antigravityModelSettings);
|
|
5926
|
+
const delegationToolNames = normalizeDelegationToolNames(pluginConfig.subagentModelTools);
|
|
5927
|
+
if (pluginConfig.subagentModelAuthorization !== false) ctx.inject(["sessions"], (scoped) => {
|
|
5928
|
+
const sessions = scoped.get("sessions");
|
|
5929
|
+
if (sessions === void 0) return;
|
|
5930
|
+
scoped.effect(() => {
|
|
5931
|
+
if (typeof scoped.tools?.guard !== "function") return () => void 0;
|
|
5932
|
+
return installSubagentModelAuthorization(scoped, sessions, {
|
|
5933
|
+
toolNames: delegationToolNames,
|
|
5934
|
+
scope: pluginConfig.subagentModelScope ?? "session"
|
|
5935
|
+
});
|
|
5936
|
+
}, "dsh-chatgpt-subscription: subagent model authorization");
|
|
5937
|
+
});
|
|
5717
5938
|
ctx.effect(() => {
|
|
5718
5939
|
const proxyManager = new ProxyManager({
|
|
5719
5940
|
getPreferences: () => preferences.status(),
|
|
@@ -5767,4 +5988,4 @@ function localWebServerBaseUrl(host, port) {
|
|
|
5767
5988
|
return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
|
|
5768
5989
|
}
|
|
5769
5990
|
//#endregion
|
|
5770
|
-
export { AntigravityAdapter, CodexChatGptAdapter, FileCredentialStore, FileModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, ResponsesClient, UsageService, WindowsDpapiTokenStore, apply, beginWebLogin, clearCachedQuota, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createPlatformTokenStore, credentialPath, detectSystemProxy, fetchAccountQuota, getCachedQuota, inject, loginAndSave, mapCodexUsage, modelSettingsPath, parseCodexUsage, parseResponsesStream, refreshAntigravityToken };
|
|
5991
|
+
export { AntigravityAdapter, CodexChatGptAdapter, Config, FileCredentialStore, FileModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, ResponsesClient, SUBAGENT_MODEL_SELECTION_NAMESPACE, SUBAGENT_POLICY_EVENT, UsageService, WindowsDpapiTokenStore, apply, authorizedRoutesFor, beginWebLogin, clearCachedQuota, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createPlatformTokenStore, createSubagentAuthorization, credentialPath, delegationDenialReason, detectSystemProxy, fetchAccountQuota, getCachedQuota, inject, installSubagentModelAuthorization, loginAndSave, mapCodexUsage, modelSettingsPath, normalizeDelegationToolNames, parseAllowedRoutes, parseCodexUsage, parseResponsesStream, policyRoutesOf, refreshAntigravityToken, subagentModelSelectionPreference, unauthorizedRouteReason, validateAuthorizationScope, validateDelegationToolNames };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodexSubscriptionSection.d.ts","sourceRoot":"","sources":["../../../src/client/CodexSubscriptionSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EAAyB,oBAAoB,EAAE,eAAe,EAAkB,cAAc,EAA8D,MAAM,wBAAwB,CAAA;AAGtM,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,KAAK,KAAK,GAAG,YAAY,CAAC,kBAAkB,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AACtE,KAAK,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAA;AACzG,KAAK,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;AAE3B,wBAAgB,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"CodexSubscriptionSection.d.ts","sourceRoot":"","sources":["../../../src/client/CodexSubscriptionSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EAAyB,oBAAoB,EAAE,eAAe,EAAkB,cAAc,EAA8D,MAAM,wBAAwB,CAAA;AAGtM,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,KAAK,KAAK,GAAG,YAAY,CAAC,kBAAkB,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AACtE,KAAK,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAA;AACzG,KAAK,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;AAE3B,wBAAgB,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAkbxE;AAiBD,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAO5F;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAO7F;AAcD,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAAE,YAAY,EAAE,WAAW,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAUzN;AAED,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAczH;AAMD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAYpF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOlE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,SAA4B,GAAG,MAAM,GAAG,IAAI,CAGxG;AAoCD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAgBtE"}
|
|
@@ -71,13 +71,6 @@ export declare const zh: {
|
|
|
71
71
|
readonly searchProviderDsh: "DSH 默认";
|
|
72
72
|
readonly searchProviderCodex: "ChatGPT(代理隧道)";
|
|
73
73
|
readonly providerDefault: "使用 Provider 默认值";
|
|
74
|
-
readonly subagentEnhancements: "子代理设置";
|
|
75
|
-
readonly subagentContextWindow: "子代理上下文预算";
|
|
76
|
-
readonly subagentContextWindowHint: "限制子代理运行时的最大上下文 Token 数(例如 128K、256K);留空跟随模型主设置。";
|
|
77
|
-
readonly subagentMaxDepth: "子代理最大嵌套深度";
|
|
78
|
-
readonly subagentMaxDepthHint: "限制子代理的递归层级(0–3);0 禁止创建子代理。";
|
|
79
|
-
readonly subagentDisabled: "已禁用";
|
|
80
|
-
readonly levels: "层";
|
|
81
74
|
readonly contextWindows: "模型上下文窗口";
|
|
82
75
|
readonly contextWindowsHint: "默认 272K;6 Astra 最高 872K,GPT-5.6 最高 1M。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。";
|
|
83
76
|
readonly contextWindow: "上下文窗口";
|
|
@@ -205,13 +198,6 @@ export declare const dictionaries: {
|
|
|
205
198
|
readonly searchProviderDsh: "DSH 默认";
|
|
206
199
|
readonly searchProviderCodex: "ChatGPT(代理隧道)";
|
|
207
200
|
readonly providerDefault: "使用 Provider 默认值";
|
|
208
|
-
readonly subagentEnhancements: "子代理设置";
|
|
209
|
-
readonly subagentContextWindow: "子代理上下文预算";
|
|
210
|
-
readonly subagentContextWindowHint: "限制子代理运行时的最大上下文 Token 数(例如 128K、256K);留空跟随模型主设置。";
|
|
211
|
-
readonly subagentMaxDepth: "子代理最大嵌套深度";
|
|
212
|
-
readonly subagentMaxDepthHint: "限制子代理的递归层级(0–3);0 禁止创建子代理。";
|
|
213
|
-
readonly subagentDisabled: "已禁用";
|
|
214
|
-
readonly levels: "层";
|
|
215
201
|
readonly contextWindows: "模型上下文窗口";
|
|
216
202
|
readonly contextWindowsHint: "默认 272K;6 Astra 最高 872K,GPT-5.6 最高 1M。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。";
|
|
217
203
|
readonly contextWindow: "上下文窗口";
|
|
@@ -264,6 +250,6 @@ export declare const dictionaries: {
|
|
|
264
250
|
readonly retry: "重试";
|
|
265
251
|
readonly unknown: "未知";
|
|
266
252
|
};
|
|
267
|
-
en: Record<"quota" | "account" | "storage" | "stale" | "pending" | "tokens" | "title" | "intro" | "signedOut" | "signedIn" | "plan" | "accountId" | "expires" | "storageWindows" | "storageMacKeychain" | "storageLinuxFile" | "storageMemory" | "storageUnavailable" | "securityWindows" | "securityMacKeychain" | "securityLinuxFile" | "securityMemory" | "securityUnavailable" | "signIn" | "signInAgain" | "cancel" | "signOut" | "refreshToken" | "popupBlocked" | "continueLogin" | "loading" | "connection" | "provider" | "connectionState" | "connected" | "untested" | "testConnection" | "testing" | "latency" | "models" | "modelsHint" | "proxySettings" | "proxyMode" | "proxyModeHint" | "proxyModeAuto" | "proxyModeCustom" | "proxyModeDirect" | "customProxyUrl" | "customProxyUrlHint" | "customProxyUrlPlaceholder" | "saveProxyUrl" | "proxyDetected" | "proxyDetectedEffective" | "proxyNoneDetected" | "proxyDirectHint" | "enhancements" | "fastMode" | "fastModeHint" | "outputVerbosity" | "outputVerbosityHint" | "verbosityLow" | "verbosityMedium" | "verbosityHigh" | "reasoningSummary" | "reasoningSummaryHint" | "summaryAuto" | "summaryConcise" | "summaryDetailed" | "summaryNone" | "searchProvider" | "searchProviderHint" | "searchProviderDsh" | "searchProviderCodex" | "providerDefault" | "
|
|
253
|
+
en: Record<"quota" | "account" | "storage" | "stale" | "pending" | "tokens" | "title" | "intro" | "signedOut" | "signedIn" | "plan" | "accountId" | "expires" | "storageWindows" | "storageMacKeychain" | "storageLinuxFile" | "storageMemory" | "storageUnavailable" | "securityWindows" | "securityMacKeychain" | "securityLinuxFile" | "securityMemory" | "securityUnavailable" | "signIn" | "signInAgain" | "cancel" | "signOut" | "refreshToken" | "popupBlocked" | "continueLogin" | "loading" | "connection" | "provider" | "connectionState" | "connected" | "untested" | "testConnection" | "testing" | "latency" | "models" | "modelsHint" | "proxySettings" | "proxyMode" | "proxyModeHint" | "proxyModeAuto" | "proxyModeCustom" | "proxyModeDirect" | "customProxyUrl" | "customProxyUrlHint" | "customProxyUrlPlaceholder" | "saveProxyUrl" | "proxyDetected" | "proxyDetectedEffective" | "proxyNoneDetected" | "proxyDirectHint" | "enhancements" | "fastMode" | "fastModeHint" | "outputVerbosity" | "outputVerbosityHint" | "verbosityLow" | "verbosityMedium" | "verbosityHigh" | "reasoningSummary" | "reasoningSummaryHint" | "summaryAuto" | "summaryConcise" | "summaryDetailed" | "summaryNone" | "searchProvider" | "searchProviderHint" | "searchProviderDsh" | "searchProviderCodex" | "providerDefault" | "contextWindows" | "contextWindowsHint" | "contextWindow" | "contextWindowInvalid" | "saveContextWindow" | "save" | "quickQuota" | "quickQuotaHint" | "quotaIntro" | "refreshQuota" | "refreshing" | "noQuota" | "quotaSignedOut" | "updated" | "primary" | "secondary" | "limitWindow" | "used" | "remaining" | "available" | "unavailable" | "unlimited" | "credits" | "monthlySpend" | "resetCredits" | "resetCreditExpires" | "useResetCredit" | "usingResetCredit" | "useResetCreditConfirm" | "resetCreditUsed" | "spendControlReached" | "limit" | "exhausted" | "resets" | "quickQuotaLabel" | "quickQuotaLoading" | "imageToolRunning" | "imageToolDone" | "imageToolFailed" | "image" | "openImage" | "openNamedImage" | "imageLoading" | "imageLoadFailed" | "imagePreviewClose" | "imagePreviewOpenOriginal" | "retry" | "unknown", string>;
|
|
268
254
|
};
|
|
269
255
|
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,EAAG,0BAAmC,CAAA;AAErD,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,EAAG,0BAAmC,CAAA;AAErD,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2HL,CAAA;AAEV,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,OAAO,EAAE,EAAE,MAAM,CA2H9C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AACvC,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAa,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../../src/host/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../../src/host/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,2BAA2B,CAAA;AAcrF,OAAO,KAAK,EACV,0BAA0B,EAC1B,gCAAgC,EACjC,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,2BAA2B;IAC1C,MAAM,IAAI,0BAA0B,CAAA;IACpC,MAAM,CAAC,KAAK,EAAE,gCAAgC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAA;IACpF,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,0BAA0B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAA;CAC1H;AAID,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,2BAA2B,CAwB/F;AA4DD,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAG5B"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-side authorization for the models a subagent may run.
|
|
3
|
+
*
|
|
4
|
+
* The `subagent-model-selection` preference is sampled into each Session as a
|
|
5
|
+
* durable route allowlist, but the built-in delegation tool only rejects an
|
|
6
|
+
* explicit route outside that list: a call that selects no route lets the child
|
|
7
|
+
* inherit the parent's model, so a DeepSeek parent could spawn DeepSeek
|
|
8
|
+
* children even though the allowlist authorizes only other models.
|
|
9
|
+
*
|
|
10
|
+
* This guard closes that gap from the plugin plane. Whenever the calling
|
|
11
|
+
* Session (or the nearest ancestor that recorded one) carries an allowlist,
|
|
12
|
+
* a delegation whose effective child route the list does not authorize is
|
|
13
|
+
* denied before the child starts, with the authorized routes in the reason so
|
|
14
|
+
* the model can retry and pick one of them.
|
|
15
|
+
* @module dsh-chatgpt-subscription/subagent-model-authorization
|
|
16
|
+
*/
|
|
17
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
18
|
+
import type { SettingsProvider } from '@deepseek-ai/dsh-settings';
|
|
19
|
+
/** DSH settings namespace owned by the Subagent settings card. */
|
|
20
|
+
export declare const SUBAGENT_MODEL_SELECTION_NAMESPACE = "subagent-model-selection";
|
|
21
|
+
/** Durable Session event carrying one Session's authorized child routes. */
|
|
22
|
+
export declare const SUBAGENT_POLICY_EVENT = "subagent/model-selection-policy";
|
|
23
|
+
/** Delegation tools whose child routes this guard authorizes. */
|
|
24
|
+
export declare const DEFAULT_DELEGATION_TOOLS: readonly string[];
|
|
25
|
+
/** One exact provider/model route the user authorized for children. */
|
|
26
|
+
export interface AllowedModelRoute {
|
|
27
|
+
readonly provider: string;
|
|
28
|
+
readonly model: string;
|
|
29
|
+
}
|
|
30
|
+
/** Resolved model-selection preference read from the Host settings document. */
|
|
31
|
+
export interface SubagentModelSelectionPreference {
|
|
32
|
+
readonly enabled: boolean;
|
|
33
|
+
readonly allowedModels: readonly AllowedModelRoute[];
|
|
34
|
+
}
|
|
35
|
+
/** One durable Session record this module reads: its events and its lineage. */
|
|
36
|
+
export interface PolicySession {
|
|
37
|
+
eventAt?(seq: number): {
|
|
38
|
+
type?: unknown;
|
|
39
|
+
data?: unknown;
|
|
40
|
+
} | undefined;
|
|
41
|
+
readonly header?: {
|
|
42
|
+
readonly origin?: unknown;
|
|
43
|
+
readonly parentSession?: unknown;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Session lookup the guard walks from the calling agent to its ancestors. */
|
|
47
|
+
export interface SessionsResolver {
|
|
48
|
+
get(id: string): PolicySession | undefined;
|
|
49
|
+
}
|
|
50
|
+
/** Calling agent fields the guard reads. */
|
|
51
|
+
export interface AuthorizationAgent {
|
|
52
|
+
readonly session?: PolicySession;
|
|
53
|
+
readonly options?: {
|
|
54
|
+
readonly provider?: unknown;
|
|
55
|
+
readonly model?: unknown;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** What the delegation tool received from the model. */
|
|
59
|
+
export interface DelegationArguments {
|
|
60
|
+
readonly provider?: unknown;
|
|
61
|
+
readonly model?: unknown;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parse the allowlist out of a durable route-policy event.
|
|
65
|
+
* @param data - `subagent/model-selection-policy` event payload.
|
|
66
|
+
* @returns every well-formed route, or undefined when the payload carries none.
|
|
67
|
+
*/
|
|
68
|
+
export declare function parseAllowedRoutes(data: unknown): AllowedModelRoute[] | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Find one Session's recorded allowlist among its durable events.
|
|
71
|
+
* @param session - Session whose log is scanned.
|
|
72
|
+
* @returns the authorized routes, or undefined for a Session that recorded none.
|
|
73
|
+
*/
|
|
74
|
+
export declare function policyRoutesOf(session: PolicySession | undefined): AllowedModelRoute[] | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Resolve the allowlist a delegation from this agent must respect: the agent's
|
|
77
|
+
* own recorded policy, else the nearest ancestor Session that recorded one
|
|
78
|
+
* (the inheritance the delegation tool applies to child Sessions).
|
|
79
|
+
* @param agent - Calling agent.
|
|
80
|
+
* @param sessions - Session registry used for ancestor lookup.
|
|
81
|
+
* @returns the authorized routes, or undefined when no Session recorded any.
|
|
82
|
+
*/
|
|
83
|
+
export declare function authorizedRoutesFor(agent: AuthorizationAgent | undefined, sessions: SessionsResolver): AllowedModelRoute[] | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Read the Host preference that owns the allowlist. Values in the stored
|
|
86
|
+
* document are untrusted JSON, so every field is narrowed before use.
|
|
87
|
+
* @param settings - Live settings service, when composed.
|
|
88
|
+
* @returns the resolved preference, or undefined without a settings service.
|
|
89
|
+
*/
|
|
90
|
+
export declare function subagentModelSelectionPreference(settings: SettingsProvider | undefined): SubagentModelSelectionPreference | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Build the denial reason for a delegation that would run on an unauthorized
|
|
93
|
+
* route. The reason names the authorized routes so the next call can select one.
|
|
94
|
+
* @param provider - Effective child provider id, when one is known.
|
|
95
|
+
* @param model - Effective child model id, when one is known.
|
|
96
|
+
* @param allowed - Routes the calling Session authorizes.
|
|
97
|
+
* @param explicit - Whether the model named the route in the tool arguments.
|
|
98
|
+
* @returns the corrective reason handed back to the model.
|
|
99
|
+
*/
|
|
100
|
+
export declare function unauthorizedRouteReason(provider: string | undefined, model: string | undefined, allowed: readonly AllowedModelRoute[], explicit: boolean): string;
|
|
101
|
+
/** Which Session's recorded allowlist a delegation must respect. */
|
|
102
|
+
export type AuthorizationScope =
|
|
103
|
+
/**
|
|
104
|
+
* `session` (default): a Session that recorded an allowlist governs itself
|
|
105
|
+
* and its descendants, matching the delegation tool's durable snapshot; a
|
|
106
|
+
* Session that recorded none keeps the built-in behavior.
|
|
107
|
+
*/
|
|
108
|
+
'session'
|
|
109
|
+
/**
|
|
110
|
+
* `preference`: the current Host preference also governs Sessions that never
|
|
111
|
+
* recorded an allowlist, so the Settings card applies without restarting the
|
|
112
|
+
* Session. A Session that recorded its own routes still outranks it.
|
|
113
|
+
*/
|
|
114
|
+
| 'preference';
|
|
115
|
+
/**
|
|
116
|
+
* Decide whether one delegation call may start its child.
|
|
117
|
+
* @param agent - Calling agent.
|
|
118
|
+
* @param toolName - Tool being dispatched.
|
|
119
|
+
* @param args - Parsed tool arguments.
|
|
120
|
+
* @param preference - Current Host preference, when the settings service exists.
|
|
121
|
+
* @param sessions - Session registry used for ancestor lookup.
|
|
122
|
+
* @param toolNames - Delegation tool names this guard authorizes.
|
|
123
|
+
* @param scope - Whether an unrecorded Session falls back to the preference.
|
|
124
|
+
* @returns a denial reason, or undefined to leave the call untouched.
|
|
125
|
+
*/
|
|
126
|
+
export declare function delegationDenialReason(agent: AuthorizationAgent | undefined, toolName: string, args: unknown, preference: SubagentModelSelectionPreference | undefined, sessions: SessionsResolver, toolNames?: readonly string[], scope?: AuthorizationScope): string | undefined;
|
|
127
|
+
/** Runtime inputs the guard closes over. */
|
|
128
|
+
export interface SubagentAuthorizationOptions {
|
|
129
|
+
/** Live settings service, when composed; absent leaves recorded policies in charge. */
|
|
130
|
+
readonly settings?: SettingsProvider;
|
|
131
|
+
/** Session registry used for ancestor lookup. */
|
|
132
|
+
readonly sessions: SessionsResolver;
|
|
133
|
+
/** Exact delegation tool names this guard authorizes. */
|
|
134
|
+
readonly toolNames: readonly string[];
|
|
135
|
+
/** Whether an unrecorded Session falls back to the current preference. */
|
|
136
|
+
readonly scope?: AuthorizationScope;
|
|
137
|
+
}
|
|
138
|
+
/** The exact guard signature the Host tool registry evaluates. */
|
|
139
|
+
export type DelegationGuard = (agent: AuthorizationAgent | undefined, toolName: string, args: unknown) => string | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* Build the monotonic tool guard for one deployment. The Host preference is
|
|
142
|
+
* sampled from the live settings document on every call, because a settings
|
|
143
|
+
* edit must not rebuild the guard the way it cannot rebuild a Session.
|
|
144
|
+
* @param options - settings, session registry, and delegation tool names.
|
|
145
|
+
* @returns a guard that denies delegations outside the Session allowlist.
|
|
146
|
+
*/
|
|
147
|
+
export declare function createSubagentAuthorization(options: SubagentAuthorizationOptions): DelegationGuard;
|
|
148
|
+
/** Delegation names this guard recognizes when configuration omits them. */
|
|
149
|
+
export declare function normalizeDelegationToolNames(value: unknown): string[];
|
|
150
|
+
/**
|
|
151
|
+
* Validate the plugin configuration that owns this guard.
|
|
152
|
+
* @param toolNames - Candidate delegation tool names.
|
|
153
|
+
* @returns the exact names this guard authorizes.
|
|
154
|
+
*/
|
|
155
|
+
export declare function validateDelegationToolNames(toolNames: readonly string[]): string[];
|
|
156
|
+
/** Configuration accepted by {@link installSubagentModelAuthorization}. */
|
|
157
|
+
export interface SubagentModelAuthorizationConfig {
|
|
158
|
+
/** Delegation tool names the guard authorizes. */
|
|
159
|
+
readonly toolNames?: readonly string[];
|
|
160
|
+
/** Whether an unrecorded Session falls back to the current preference. */
|
|
161
|
+
readonly scope?: AuthorizationScope;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Register the monotonic guard on the Host tool registry.
|
|
165
|
+
* @param ctx - Host context carrying `tools` (and optionally `settings`).
|
|
166
|
+
* @param sessions - Session registry used for ancestor lookup.
|
|
167
|
+
* @param config - Enforcement toggle and delegation tool names.
|
|
168
|
+
* @returns the exact disposer that unregisters the guard.
|
|
169
|
+
*/
|
|
170
|
+
export declare function installSubagentModelAuthorization(ctx: Context, sessions: SessionsResolver, config?: SubagentModelAuthorizationConfig): () => void;
|
|
171
|
+
/**
|
|
172
|
+
* Validate the configured authorization scope.
|
|
173
|
+
* @param scope - Candidate scope from deployment configuration.
|
|
174
|
+
* @returns the exact scope this guard enforces.
|
|
175
|
+
*/
|
|
176
|
+
export declare function validateAuthorizationScope(scope: unknown): AuthorizationScope;
|
|
177
|
+
//# sourceMappingURL=subagent-model-authorization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-model-authorization.d.ts","sourceRoot":"","sources":["../../../src/host/subagent-model-authorization.ts"],"names":[],"mappings":"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"}
|