@indexnetwork/protocol 11.1.0-rc.457.1 → 11.2.1-rc.459.1
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 +38 -1
- package/dist/mcp/mcp.authorization-policy.d.ts +10 -4
- package/dist/mcp/mcp.authorization-policy.js +64 -5
- package/dist/shared/agent/model.config.d.ts +6 -4
- package/dist/shared/agent/model.config.js +11 -60
- package/dist/shared/agent/model.resolver.d.ts +48 -0
- package/dist/shared/agent/model.resolver.js +78 -0
- package/dist/shared/schemas/mcp-auth.schema.d.ts +6 -0
- package/dist/shared/schemas/mcp-auth.schema.js +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -20,6 +20,30 @@ went 6.7.1 → 8.0.2 with no 7.x in between because the whole 7.x line shipped a
|
|
|
20
20
|
prereleases between the two promotions. To track every change, read `rc`; to
|
|
21
21
|
pin a supported release, use `latest`.
|
|
22
22
|
|
|
23
|
+
## 11.2.1 - 2026-08-11
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Added the guarded historical-quality runtime for single-configuration,
|
|
28
|
+
dual-trigger shared-pool evaluation.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Hardened historical-quality readiness with attested database credentials,
|
|
33
|
+
frozen embedding requests, and fail-closed protected-base refresh gating.
|
|
34
|
+
|
|
35
|
+
## 10.2.0 - 2026-08-10
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Refined the canonical V2 historical-quality artifact contract so execution
|
|
40
|
+
completeness is independent of verdict availability: complete filtered
|
|
41
|
+
case/trigger selections are valid descriptive evidence with
|
|
42
|
+
`completeness.complete: true` and
|
|
43
|
+
`measurement.qualityVerdictAvailable: false`; only complete full-corpus,
|
|
44
|
+
full-trigger selections may publish a quality verdict. Legacy and canonical
|
|
45
|
+
parser selection remain unchanged.
|
|
46
|
+
|
|
23
47
|
## 10.1.0 - 2026-08-07
|
|
24
48
|
|
|
25
49
|
### Added
|
|
@@ -28,6 +52,12 @@ pin a supported release, use `latest`.
|
|
|
28
52
|
|
|
29
53
|
## [Unreleased]
|
|
30
54
|
|
|
55
|
+
### Added
|
|
56
|
+
- Full standalone Hermes capability policy (11.2.0): the `hermes-agent` principal has an explicit six-action MCP/REST policy while the existing `hermes-negotiator` principal remains restricted to its four scheduled negotiation handlers. Both policies default deny and preserve one-shot, generation-fenced negotiation authority.
|
|
57
|
+
|
|
58
|
+
### Security
|
|
59
|
+
- The Hermes policy never exposes owner credentials, account-security, credential/permission/agent administration, billing, or unclassified tools; connector and owner-native callers receive only nonsecret response projections.
|
|
60
|
+
|
|
31
61
|
### Removed
|
|
32
62
|
- Remove six unsupported shared interface/schema forwarding shims after migrating repository consumers to capability-owned domain and port modules; stable package-root exports remain unchanged.
|
|
33
63
|
- Remove six unsupported tool-port forwarding shims and the deprecated unused discovery-question mapper; stable package-root exports remain unchanged.
|
|
@@ -75,12 +105,19 @@ pin a supported release, use `latest`.
|
|
|
75
105
|
- Remove unsupported deprecated source/deep forwarding shims after migrating repository consumers to canonical modules; stable package-root exports are unchanged.
|
|
76
106
|
- Add a fail-closed isolated provider-free test gate (10.1.1). Tooling-only
|
|
77
107
|
safety foundation; no runtime or public API behavior changes.
|
|
108
|
+
- For the planned 10.2.0 release, refine the canonical V2 historical-quality
|
|
109
|
+
artifact contract so execution completeness is independent of verdict
|
|
110
|
+
availability: complete filtered case/trigger selections are valid descriptive
|
|
111
|
+
evidence with `completeness.complete: true` and
|
|
112
|
+
`measurement.qualityVerdictAvailable: false`; only complete full-corpus,
|
|
113
|
+
full-trigger selections may publish a quality verdict. Legacy and canonical
|
|
114
|
+
parser selection remain unchanged.
|
|
78
115
|
- Share capability classification metadata between the existing architecture
|
|
79
116
|
boundary gate and the protocol atlas generator; allowed dependency directions
|
|
80
117
|
are unchanged.
|
|
81
118
|
|
|
82
119
|
### Security
|
|
83
|
-
- The Hermes skill contract is restricted to the four negotiator tools, never treats model prose as authority, never forwards secrets or owner-private context, and relies on Index's validated action/consultation and bounded fallback paths. **This branch targets dev/private testing only. Production distribution remains blocked until the Mac owner credential is migrated to Keychain and the plaintext file/directory is removed, hardened
|
|
120
|
+
- The Hermes skill contract is restricted to the four negotiator tools, never treats model prose as authority, never forwards secrets or owner-private context, and relies on Index's validated action/consultation and bounded fallback paths. **This branch targets dev/private testing only. Production distribution remains blocked until the Mac owner credential is migrated to Keychain and the plaintext file/directory is removed, Developer ID hardened-runtime signing and notarization are complete, and the credential TTL/revocation checklist is verified.**
|
|
84
121
|
|
|
85
122
|
### Fixed
|
|
86
123
|
- Add an independent complete-payload golden digest and stronger audit/report leak
|
|
@@ -25,6 +25,12 @@ export type McpToolPermissionMap = ReadonlyMap<string, McpToolPermissionRequirem
|
|
|
25
25
|
* Runtime-validates a capability-owned tool-to-permission mapping.
|
|
26
26
|
*/
|
|
27
27
|
export declare function defineMcpToolPermissionMap(mapping: Readonly<Record<string, McpToolPermissionRequirement>>): McpToolPermissionMap;
|
|
28
|
+
/**
|
|
29
|
+
* Exact full-standalone Hermes MCP surface. Every admitted tool maps to one
|
|
30
|
+
* canonical action; absence is denial, including human-only, deletion,
|
|
31
|
+
* permission-management, agent-administration, and retired aliases.
|
|
32
|
+
*/
|
|
33
|
+
export declare const HERMES_AGENT_MCP_TOOL_PERMISSIONS: McpToolPermissionMap;
|
|
28
34
|
export declare const McpToolAccessRuleSchema: z.ZodEffects<z.ZodObject<{
|
|
29
35
|
access: z.ZodEnum<["permission", "authenticated", "human_only", "agent_admin", "informational", "delivery_only", "removed"]>;
|
|
30
36
|
actions: z.ZodOptional<z.ZodArray<z.ZodEnum<["manage:identity", "manage:premises", "manage:intents", "manage:networks", "manage:opportunities", "manage:negotiations"]>, "many">>;
|
|
@@ -113,10 +119,10 @@ export declare const McpPolicyAgentSnapshotSchema: z.ZodObject<{
|
|
|
113
119
|
}[];
|
|
114
120
|
}>;
|
|
115
121
|
export type McpPolicyAgentSnapshot = z.infer<typeof McpPolicyAgentSnapshotSchema>;
|
|
116
|
-
export declare const McpPrincipalProfileSchema: z.ZodEnum<["session_human", "onboarding_human", "enrollment_key", "unregistered_key", "registered_global_agent", "registered_network_agent", "delivery_agent", "invalid_agent"]>;
|
|
122
|
+
export declare const McpPrincipalProfileSchema: z.ZodEnum<["session_human", "onboarding_human", "enrollment_key", "unregistered_key", "registered_global_agent", "registered_network_agent", "hermes_agent", "delivery_agent", "invalid_agent"]>;
|
|
117
123
|
export type McpPrincipalProfile = z.infer<typeof McpPrincipalProfileSchema>;
|
|
118
124
|
export declare const McpCapabilitySubjectSchema: z.ZodObject<{
|
|
119
|
-
profile: z.ZodEnum<["session_human", "onboarding_human", "enrollment_key", "unregistered_key", "registered_global_agent", "registered_network_agent", "delivery_agent", "invalid_agent"]>;
|
|
125
|
+
profile: z.ZodEnum<["session_human", "onboarding_human", "enrollment_key", "unregistered_key", "registered_global_agent", "registered_network_agent", "hermes_agent", "delivery_agent", "invalid_agent"]>;
|
|
120
126
|
userId: z.ZodString;
|
|
121
127
|
agentId: z.ZodOptional<z.ZodString>;
|
|
122
128
|
agentType: z.ZodOptional<z.ZodEnum<["personal", "external", "system"]>>;
|
|
@@ -125,7 +131,7 @@ export declare const McpCapabilitySubjectSchema: z.ZodObject<{
|
|
|
125
131
|
permissions: z.ZodArray<z.ZodEnum<["manage:identity", "manage:premises", "manage:intents", "manage:networks", "manage:opportunities", "manage:negotiations"]>, "many">;
|
|
126
132
|
}, "strict", z.ZodTypeAny, {
|
|
127
133
|
userId: string;
|
|
128
|
-
profile: "session_human" | "onboarding_human" | "enrollment_key" | "unregistered_key" | "registered_global_agent" | "registered_network_agent" | "delivery_agent" | "invalid_agent";
|
|
134
|
+
profile: "session_human" | "onboarding_human" | "enrollment_key" | "unregistered_key" | "registered_global_agent" | "registered_network_agent" | "hermes_agent" | "delivery_agent" | "invalid_agent";
|
|
129
135
|
permissions: ("manage:negotiations" | "manage:intents" | "manage:opportunities" | "manage:identity" | "manage:premises" | "manage:networks")[];
|
|
130
136
|
networkScopeId: string | null;
|
|
131
137
|
isOnboarding: boolean;
|
|
@@ -133,7 +139,7 @@ export declare const McpCapabilitySubjectSchema: z.ZodObject<{
|
|
|
133
139
|
agentType?: "system" | "personal" | "external" | undefined;
|
|
134
140
|
}, {
|
|
135
141
|
userId: string;
|
|
136
|
-
profile: "session_human" | "onboarding_human" | "enrollment_key" | "unregistered_key" | "registered_global_agent" | "registered_network_agent" | "delivery_agent" | "invalid_agent";
|
|
142
|
+
profile: "session_human" | "onboarding_human" | "enrollment_key" | "unregistered_key" | "registered_global_agent" | "registered_network_agent" | "hermes_agent" | "delivery_agent" | "invalid_agent";
|
|
137
143
|
permissions: ("manage:negotiations" | "manage:intents" | "manage:opportunities" | "manage:identity" | "manage:premises" | "manage:networks")[];
|
|
138
144
|
networkScopeId: string | null;
|
|
139
145
|
isOnboarding: boolean;
|
|
@@ -26,6 +26,44 @@ export function defineMcpToolPermissionMap(mapping) {
|
|
|
26
26
|
const parsed = McpToolPermissionMapSchema.parse(mapping);
|
|
27
27
|
return new Map(Object.entries(parsed));
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Exact full-standalone Hermes MCP surface. Every admitted tool maps to one
|
|
31
|
+
* canonical action; absence is denial, including human-only, deletion,
|
|
32
|
+
* permission-management, agent-administration, and retired aliases.
|
|
33
|
+
*/
|
|
34
|
+
export const HERMES_AGENT_MCP_TOOL_PERMISSIONS = defineMcpToolPermissionMap({
|
|
35
|
+
read_user_contexts: { action: 'manage:identity', reach: 'principal' },
|
|
36
|
+
preview_user_context: { action: 'manage:identity', reach: 'principal' },
|
|
37
|
+
confirm_user_context: { action: 'manage:identity', reach: 'principal' },
|
|
38
|
+
create_user_context: { action: 'manage:identity', reach: 'principal' },
|
|
39
|
+
update_user_context: { action: 'manage:identity', reach: 'principal' },
|
|
40
|
+
get_enrichment_run: { action: 'manage:identity', reach: 'principal' },
|
|
41
|
+
cancel_enrichment_run: { action: 'manage:identity', reach: 'principal' },
|
|
42
|
+
read_intents: { action: 'manage:intents', reach: 'network' },
|
|
43
|
+
search_intents: { action: 'manage:intents', reach: 'network' },
|
|
44
|
+
create_intent: { action: 'manage:intents', reach: 'network' },
|
|
45
|
+
update_intent: { action: 'manage:intents', reach: 'network' },
|
|
46
|
+
read_intent_indexes: { action: 'manage:intents', reach: 'network' },
|
|
47
|
+
create_intent_index: { action: 'manage:intents', reach: 'network' },
|
|
48
|
+
list_negotiations: { action: 'manage:negotiations', reach: 'network' },
|
|
49
|
+
get_negotiation: { action: 'manage:negotiations', reach: 'network' },
|
|
50
|
+
respond_to_negotiation: { action: 'manage:negotiations', reach: 'network' },
|
|
51
|
+
read_networks: { action: 'manage:networks', reach: 'network' },
|
|
52
|
+
read_network_memberships: { action: 'manage:networks', reach: 'network' },
|
|
53
|
+
create_network: { action: 'manage:networks', reach: 'network' },
|
|
54
|
+
update_network: { action: 'manage:networks', reach: 'network' },
|
|
55
|
+
create_network_membership: { action: 'manage:networks', reach: 'network' },
|
|
56
|
+
list_opportunities: { action: 'manage:opportunities', reach: 'network' },
|
|
57
|
+
update_opportunity: { action: 'manage:opportunities', reach: 'network' },
|
|
58
|
+
confirm_opportunity_delivery: { action: 'manage:opportunities', reach: 'network' },
|
|
59
|
+
read_premises: { action: 'manage:premises', reach: 'principal' },
|
|
60
|
+
create_premise: { action: 'manage:premises', reach: 'principal' },
|
|
61
|
+
update_premise: { action: 'manage:premises', reach: 'principal' },
|
|
62
|
+
retract_premise: { action: 'manage:premises', reach: 'principal' },
|
|
63
|
+
read_pending_questions: { action: 'manage:identity', reach: 'principal' },
|
|
64
|
+
read_activity_summary: { action: 'manage:identity', reach: 'principal' },
|
|
65
|
+
read_docs: { action: 'manage:identity', reach: 'principal' },
|
|
66
|
+
});
|
|
29
67
|
export const McpToolAccessRuleSchema = z.object({
|
|
30
68
|
access: z.enum([
|
|
31
69
|
'permission',
|
|
@@ -216,6 +254,7 @@ export const McpPrincipalProfileSchema = z.enum([
|
|
|
216
254
|
'unregistered_key',
|
|
217
255
|
'registered_global_agent',
|
|
218
256
|
'registered_network_agent',
|
|
257
|
+
'hermes_agent',
|
|
219
258
|
'delivery_agent',
|
|
220
259
|
'invalid_agent',
|
|
221
260
|
]);
|
|
@@ -331,11 +370,13 @@ export function resolveMcpCapabilitySubject(input) {
|
|
|
331
370
|
});
|
|
332
371
|
}
|
|
333
372
|
const agent = parsedAgent.data;
|
|
334
|
-
const profile = identity.
|
|
335
|
-
? '
|
|
336
|
-
: identity.
|
|
337
|
-
? '
|
|
338
|
-
:
|
|
373
|
+
const profile = identity.isHermesAgent === true
|
|
374
|
+
? 'hermes_agent'
|
|
375
|
+
: identity.isDeliveryAgent === true
|
|
376
|
+
? 'delivery_agent'
|
|
377
|
+
: identity.networkScopeId
|
|
378
|
+
? 'registered_network_agent'
|
|
379
|
+
: 'registered_global_agent';
|
|
339
380
|
return McpCapabilitySubjectSchema.parse({
|
|
340
381
|
profile,
|
|
341
382
|
userId: identity.userId,
|
|
@@ -437,6 +478,24 @@ export class McpCapabilityPolicy {
|
|
|
437
478
|
if (subject.isOnboarding && !ONBOARDING_ALLOWED.has(toolName)) {
|
|
438
479
|
return { allowed: false, reason: 'onboarding_required', reach: rule.reach };
|
|
439
480
|
}
|
|
481
|
+
if (subject.profile === 'hermes_agent') {
|
|
482
|
+
const requirement = HERMES_AGENT_MCP_TOOL_PERMISSIONS.get(toolName);
|
|
483
|
+
if (!requirement)
|
|
484
|
+
return { allowed: false, reason: 'tool_unclassified' };
|
|
485
|
+
return subject.permissions.includes(requirement.action)
|
|
486
|
+
? {
|
|
487
|
+
allowed: true,
|
|
488
|
+
reason: 'permission_granted',
|
|
489
|
+
reach: requirement.reach,
|
|
490
|
+
requiredPermissions: [requirement.action],
|
|
491
|
+
}
|
|
492
|
+
: {
|
|
493
|
+
allowed: false,
|
|
494
|
+
reason: 'permission_missing',
|
|
495
|
+
reach: requirement.reach,
|
|
496
|
+
requiredPermissions: [requirement.action],
|
|
497
|
+
};
|
|
498
|
+
}
|
|
440
499
|
if (rule.access === 'delivery_only') {
|
|
441
500
|
return subject.profile === 'delivery_agent'
|
|
442
501
|
? { allowed: true, reason: 'delivery', reach: rule.reach }
|
|
@@ -31,8 +31,8 @@ export interface ModelConfig {
|
|
|
31
31
|
/** Override the chat reasoning effort. Falls back to CHAT_REASONING_EFFORT env var. */
|
|
32
32
|
chatReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
33
33
|
}
|
|
34
|
-
/** Per-agent model settings before
|
|
35
|
-
declare function getBaseModelConfig(config?: ModelConfig): {
|
|
34
|
+
/** Per-agent model settings before canonical assignments are applied. */
|
|
35
|
+
declare function getBaseModelConfig(config?: ModelConfig): { [Agent in "intentInferrer" | "intentIndexer" | "intentVerifier" | "intentReconciler" | "intentClarifier" | "profileGenerator" | "hydeGenerator" | "hydeValidator" | "lensInferrer" | "opportunityEvaluator" | "opportunityPresenter" | "negotiator" | "negotiationScreener" | "negotiationReflector" | "homeCategorizer" | "suggestionGenerator" | "chatTitleGenerator" | "negotiationInsights" | "chatContextSummarizer" | "questioner" | "signalIntakePack" | "negotiationSummarizer" | "poolDiscriminatorMiner" | "poolDiscriminatorAssigner" | "negotiationEvidenceMiner" | "inviteGenerator" | "premiseAnalyzer" | "premiseDecomposer" | "premiseIndexer" | "userContextGenerator" | "networkRecommender" | "interruptClassifier" | "chat"]: Omit<{
|
|
36
36
|
readonly intentInferrer: {
|
|
37
37
|
readonly model: "google/gemini-2.5-flash";
|
|
38
38
|
};
|
|
@@ -164,14 +164,16 @@ declare function getBaseModelConfig(config?: ModelConfig): {
|
|
|
164
164
|
readonly maxTokens: 16;
|
|
165
165
|
};
|
|
166
166
|
readonly chat: {
|
|
167
|
-
readonly model:
|
|
167
|
+
readonly model: "google/gemini-3-pro-preview";
|
|
168
168
|
readonly maxTokens: 8192;
|
|
169
169
|
readonly reasoning: {
|
|
170
170
|
readonly effort: NonNullable<ModelSettings["reasoning"]>["effort"];
|
|
171
171
|
readonly exclude: true;
|
|
172
172
|
};
|
|
173
173
|
};
|
|
174
|
-
}
|
|
174
|
+
}[Agent], "model"> & {
|
|
175
|
+
model: string;
|
|
176
|
+
}; };
|
|
175
177
|
/** Key identifying one of the per-agent model configurations. */
|
|
176
178
|
export type ModelAgent = keyof ReturnType<typeof getBaseModelConfig>;
|
|
177
179
|
/**
|
|
@@ -1,50 +1,8 @@
|
|
|
1
1
|
import { ChatOpenAI } from "@langchain/openai";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* `EVAL_MODEL_OVERRIDES={"opportunityEvaluator":"anthropic/claude-sonnet-4"}`.
|
|
5
|
-
*
|
|
6
|
-
* Read on every call (no caching) to match the surrounding env convention, and
|
|
7
|
-
* ignored entirely in production so a deployed process can never be repointed at
|
|
8
|
-
* another model by an environment variable. A malformed value or an unknown agent
|
|
9
|
-
* key throws: a typo must not silently produce a run that measured the default.
|
|
10
|
-
*/
|
|
11
|
-
function readModelOverrides(agentKeys) {
|
|
12
|
-
if (process.env.NODE_ENV === "production")
|
|
13
|
-
return {};
|
|
14
|
-
const raw = process.env.EVAL_MODEL_OVERRIDES?.trim();
|
|
15
|
-
if (!raw)
|
|
16
|
-
return {};
|
|
17
|
-
let parsed;
|
|
18
|
-
try {
|
|
19
|
-
parsed = JSON.parse(raw);
|
|
20
|
-
}
|
|
21
|
-
catch (err) {
|
|
22
|
-
// `new Error(msg, { cause })` needs lib ES2022; this package targets ES2020,
|
|
23
|
-
// so the cause is attached after construction (same pattern as elsewhere in src).
|
|
24
|
-
const wrapped = new Error(`EVAL_MODEL_OVERRIDES is not valid JSON: ${raw}`);
|
|
25
|
-
wrapped.cause = err;
|
|
26
|
-
throw wrapped;
|
|
27
|
-
}
|
|
28
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
29
|
-
throw new Error("EVAL_MODEL_OVERRIDES must be a JSON object of agent -> model id");
|
|
30
|
-
}
|
|
31
|
-
const overrides = {};
|
|
32
|
-
for (const [agent, model] of Object.entries(parsed)) {
|
|
33
|
-
if (!agentKeys.includes(agent)) {
|
|
34
|
-
throw new Error(`EVAL_MODEL_OVERRIDES names an unknown agent "${agent}". Known agents: ${agentKeys.join(", ")}`);
|
|
35
|
-
}
|
|
36
|
-
if (typeof model !== "string" || model.trim() === "") {
|
|
37
|
-
throw new Error(`EVAL_MODEL_OVERRIDES value for "${agent}" must be a non-empty model id string`);
|
|
38
|
-
}
|
|
39
|
-
// Store trimmed: surrounding whitespace in the JSON value would otherwise be
|
|
40
|
-
// sent verbatim to OpenRouter as part of the model id.
|
|
41
|
-
overrides[agent] = model.trim();
|
|
42
|
-
}
|
|
43
|
-
return overrides;
|
|
44
|
-
}
|
|
45
|
-
/** Per-agent model settings before any eval-only override is applied. */
|
|
2
|
+
import { resolveCanonicalAllAgentModels } from "./model.resolver.js";
|
|
3
|
+
/** Per-agent model settings before canonical assignments are applied. */
|
|
46
4
|
function getBaseModelConfig(config) {
|
|
47
|
-
|
|
5
|
+
const settings = {
|
|
48
6
|
intentInferrer: { model: "google/gemini-2.5-flash" },
|
|
49
7
|
intentIndexer: { model: "google/gemini-2.5-flash" },
|
|
50
8
|
intentVerifier: { model: "google/gemini-2.5-flash" },
|
|
@@ -78,7 +36,7 @@ function getBaseModelConfig(config) {
|
|
|
78
36
|
networkRecommender: { model: "google/gemini-2.5-flash", temperature: 0.2, maxTokens: 512 },
|
|
79
37
|
interruptClassifier: { model: "google/gemini-2.5-flash", temperature: 0.0, maxTokens: 16 },
|
|
80
38
|
chat: {
|
|
81
|
-
model:
|
|
39
|
+
model: "google/gemini-3-pro-preview",
|
|
82
40
|
maxTokens: 8192,
|
|
83
41
|
reasoning: {
|
|
84
42
|
effort: (config?.chatReasoningEffort ?? process.env.CHAT_REASONING_EFFORT ?? "low"),
|
|
@@ -86,22 +44,15 @@ function getBaseModelConfig(config) {
|
|
|
86
44
|
},
|
|
87
45
|
},
|
|
88
46
|
};
|
|
47
|
+
const assignments = resolveCanonicalAllAgentModels({
|
|
48
|
+
CHAT_MODEL: config?.chatModel ?? process.env.CHAT_MODEL,
|
|
49
|
+
EVAL_MODEL_OVERRIDES: process.env.EVAL_MODEL_OVERRIDES,
|
|
50
|
+
}, { applyEvalOverrides: process.env.NODE_ENV !== "production" });
|
|
51
|
+
return Object.fromEntries(Object.entries(settings).map(([agent, value]) => [agent, { ...value, model: assignments[agent] }]));
|
|
89
52
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Per-agent model settings, with `EVAL_MODEL_OVERRIDES` applied when present.
|
|
92
|
-
* Only the model id is overridable: temperature, token limits and reasoning
|
|
93
|
-
* effort stay fixed so an eval measures a model swap and nothing else.
|
|
94
|
-
*/
|
|
53
|
+
/** Canonical assignments preserve sampling, token, and reasoning settings. */
|
|
95
54
|
function getModelConfig(config) {
|
|
96
|
-
|
|
97
|
-
const overrides = readModelOverrides(Object.keys(base));
|
|
98
|
-
if (Object.keys(overrides).length === 0)
|
|
99
|
-
return base;
|
|
100
|
-
const merged = Object.fromEntries(Object.entries(base).map(([agent, settings]) => {
|
|
101
|
-
const model = overrides[agent];
|
|
102
|
-
return [agent, model ? { ...settings, model } : settings];
|
|
103
|
-
}));
|
|
104
|
-
return merged;
|
|
55
|
+
return getBaseModelConfig(config);
|
|
105
56
|
}
|
|
106
57
|
/**
|
|
107
58
|
* Returns the model name string for the given agent key.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical model-assignment authority for every protocol agent.
|
|
3
|
+
*
|
|
4
|
+
* The resolver is pure: callers provide the complete environment projection it
|
|
5
|
+
* may read. Historical eval planning uses the returned all-agent map so an
|
|
6
|
+
* unmentioned agent cannot drift behind an implicit runtime default.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CANONICAL_AGENT_MODEL_DEFAULTS: Readonly<{
|
|
9
|
+
readonly intentInferrer: "google/gemini-2.5-flash";
|
|
10
|
+
readonly intentIndexer: "google/gemini-2.5-flash";
|
|
11
|
+
readonly intentVerifier: "google/gemini-2.5-flash";
|
|
12
|
+
readonly intentReconciler: "google/gemini-2.5-flash";
|
|
13
|
+
readonly intentClarifier: "google/gemini-2.5-flash";
|
|
14
|
+
readonly profileGenerator: "google/gemini-2.5-flash";
|
|
15
|
+
readonly hydeGenerator: "google/gemini-2.5-flash";
|
|
16
|
+
readonly hydeValidator: "google/gemini-2.5-flash";
|
|
17
|
+
readonly lensInferrer: "google/gemini-2.5-flash";
|
|
18
|
+
readonly opportunityEvaluator: "google/gemini-2.5-flash";
|
|
19
|
+
readonly opportunityPresenter: "google/gemini-2.5-flash";
|
|
20
|
+
readonly negotiator: "google/gemini-2.5-flash";
|
|
21
|
+
readonly negotiationScreener: "google/gemini-2.5-flash";
|
|
22
|
+
readonly negotiationReflector: "google/gemini-2.5-flash";
|
|
23
|
+
readonly homeCategorizer: "google/gemini-2.5-flash";
|
|
24
|
+
readonly suggestionGenerator: "google/gemini-2.5-flash";
|
|
25
|
+
readonly chatTitleGenerator: "google/gemini-2.5-flash";
|
|
26
|
+
readonly negotiationInsights: "google/gemini-2.5-flash";
|
|
27
|
+
readonly chatContextSummarizer: "google/gemini-2.5-flash";
|
|
28
|
+
readonly questioner: "google/gemini-2.5-flash";
|
|
29
|
+
readonly signalIntakePack: "google/gemini-2.5-flash";
|
|
30
|
+
readonly negotiationSummarizer: "google/gemini-2.5-flash";
|
|
31
|
+
readonly poolDiscriminatorMiner: "google/gemini-2.5-flash";
|
|
32
|
+
readonly poolDiscriminatorAssigner: "google/gemini-2.5-flash";
|
|
33
|
+
readonly negotiationEvidenceMiner: "google/gemini-2.5-flash";
|
|
34
|
+
readonly inviteGenerator: "google/gemini-2.5-flash";
|
|
35
|
+
readonly premiseAnalyzer: "google/gemini-2.5-flash";
|
|
36
|
+
readonly premiseDecomposer: "google/gemini-2.5-flash";
|
|
37
|
+
readonly premiseIndexer: "google/gemini-2.5-flash";
|
|
38
|
+
readonly userContextGenerator: "google/gemini-2.5-flash";
|
|
39
|
+
readonly networkRecommender: "google/gemini-2.5-flash";
|
|
40
|
+
readonly interruptClassifier: "google/gemini-2.5-flash";
|
|
41
|
+
readonly chat: "google/gemini-3-pro-preview";
|
|
42
|
+
}>;
|
|
43
|
+
export type CanonicalModelAgent = keyof typeof CANONICAL_AGENT_MODEL_DEFAULTS;
|
|
44
|
+
export type CanonicalAllAgentModels = Readonly<Record<CanonicalModelAgent, string>>;
|
|
45
|
+
export declare const CANONICAL_MODEL_AGENTS: readonly ("intentInferrer" | "intentIndexer" | "intentVerifier" | "intentReconciler" | "intentClarifier" | "profileGenerator" | "hydeGenerator" | "hydeValidator" | "lensInferrer" | "opportunityEvaluator" | "opportunityPresenter" | "negotiator" | "negotiationScreener" | "negotiationReflector" | "homeCategorizer" | "suggestionGenerator" | "chatTitleGenerator" | "negotiationInsights" | "chatContextSummarizer" | "questioner" | "signalIntakePack" | "negotiationSummarizer" | "poolDiscriminatorMiner" | "poolDiscriminatorAssigner" | "negotiationEvidenceMiner" | "inviteGenerator" | "premiseAnalyzer" | "premiseDecomposer" | "premiseIndexer" | "userContextGenerator" | "networkRecommender" | "interruptClassifier" | "chat")[];
|
|
46
|
+
export declare function resolveCanonicalAllAgentModels(environment: Readonly<Record<string, string | undefined>>, options?: {
|
|
47
|
+
applyEvalOverrides?: boolean;
|
|
48
|
+
}): CanonicalAllAgentModels;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical model-assignment authority for every protocol agent.
|
|
3
|
+
*
|
|
4
|
+
* The resolver is pure: callers provide the complete environment projection it
|
|
5
|
+
* may read. Historical eval planning uses the returned all-agent map so an
|
|
6
|
+
* unmentioned agent cannot drift behind an implicit runtime default.
|
|
7
|
+
*/
|
|
8
|
+
export const CANONICAL_AGENT_MODEL_DEFAULTS = Object.freeze({
|
|
9
|
+
intentInferrer: "google/gemini-2.5-flash",
|
|
10
|
+
intentIndexer: "google/gemini-2.5-flash",
|
|
11
|
+
intentVerifier: "google/gemini-2.5-flash",
|
|
12
|
+
intentReconciler: "google/gemini-2.5-flash",
|
|
13
|
+
intentClarifier: "google/gemini-2.5-flash",
|
|
14
|
+
profileGenerator: "google/gemini-2.5-flash",
|
|
15
|
+
hydeGenerator: "google/gemini-2.5-flash",
|
|
16
|
+
hydeValidator: "google/gemini-2.5-flash",
|
|
17
|
+
lensInferrer: "google/gemini-2.5-flash",
|
|
18
|
+
opportunityEvaluator: "google/gemini-2.5-flash",
|
|
19
|
+
opportunityPresenter: "google/gemini-2.5-flash",
|
|
20
|
+
negotiator: "google/gemini-2.5-flash",
|
|
21
|
+
negotiationScreener: "google/gemini-2.5-flash",
|
|
22
|
+
negotiationReflector: "google/gemini-2.5-flash",
|
|
23
|
+
homeCategorizer: "google/gemini-2.5-flash",
|
|
24
|
+
suggestionGenerator: "google/gemini-2.5-flash",
|
|
25
|
+
chatTitleGenerator: "google/gemini-2.5-flash",
|
|
26
|
+
negotiationInsights: "google/gemini-2.5-flash",
|
|
27
|
+
chatContextSummarizer: "google/gemini-2.5-flash",
|
|
28
|
+
questioner: "google/gemini-2.5-flash",
|
|
29
|
+
signalIntakePack: "google/gemini-2.5-flash",
|
|
30
|
+
negotiationSummarizer: "google/gemini-2.5-flash",
|
|
31
|
+
poolDiscriminatorMiner: "google/gemini-2.5-flash",
|
|
32
|
+
poolDiscriminatorAssigner: "google/gemini-2.5-flash",
|
|
33
|
+
negotiationEvidenceMiner: "google/gemini-2.5-flash",
|
|
34
|
+
inviteGenerator: "google/gemini-2.5-flash",
|
|
35
|
+
premiseAnalyzer: "google/gemini-2.5-flash",
|
|
36
|
+
premiseDecomposer: "google/gemini-2.5-flash",
|
|
37
|
+
premiseIndexer: "google/gemini-2.5-flash",
|
|
38
|
+
userContextGenerator: "google/gemini-2.5-flash",
|
|
39
|
+
networkRecommender: "google/gemini-2.5-flash",
|
|
40
|
+
interruptClassifier: "google/gemini-2.5-flash",
|
|
41
|
+
chat: "google/gemini-3-pro-preview",
|
|
42
|
+
});
|
|
43
|
+
export const CANONICAL_MODEL_AGENTS = Object.freeze(Object.keys(CANONICAL_AGENT_MODEL_DEFAULTS));
|
|
44
|
+
function parseOverrides(raw) {
|
|
45
|
+
if (raw?.trim() === undefined || raw.trim() === "")
|
|
46
|
+
return {};
|
|
47
|
+
let parsed;
|
|
48
|
+
try {
|
|
49
|
+
parsed = JSON.parse(raw);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
throw new Error("EVAL_MODEL_OVERRIDES is not valid JSON");
|
|
53
|
+
}
|
|
54
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
55
|
+
throw new Error("EVAL_MODEL_OVERRIDES must be a JSON object of agent -> model id");
|
|
56
|
+
}
|
|
57
|
+
const overrides = {};
|
|
58
|
+
for (const [agent, model] of Object.entries(parsed)) {
|
|
59
|
+
if (!CANONICAL_MODEL_AGENTS.includes(agent)) {
|
|
60
|
+
throw new Error(`EVAL_MODEL_OVERRIDES names an unknown agent "${agent}". Known agents: ${CANONICAL_MODEL_AGENTS.join(", ")}`);
|
|
61
|
+
}
|
|
62
|
+
if (typeof model !== "string" || model.trim() === "") {
|
|
63
|
+
throw new Error(`EVAL_MODEL_OVERRIDES value for "${agent}" must be a non-empty model id string`);
|
|
64
|
+
}
|
|
65
|
+
overrides[agent] = model.trim();
|
|
66
|
+
}
|
|
67
|
+
return overrides;
|
|
68
|
+
}
|
|
69
|
+
export function resolveCanonicalAllAgentModels(environment, options = {}) {
|
|
70
|
+
const models = { ...CANONICAL_AGENT_MODEL_DEFAULTS };
|
|
71
|
+
const chatModel = environment.CHAT_MODEL?.trim();
|
|
72
|
+
if (chatModel)
|
|
73
|
+
models.chat = chatModel;
|
|
74
|
+
if (options.applyEvalOverrides !== false) {
|
|
75
|
+
Object.assign(models, parseOverrides(environment.EVAL_MODEL_OVERRIDES));
|
|
76
|
+
}
|
|
77
|
+
return Object.freeze(models);
|
|
78
|
+
}
|
|
@@ -48,6 +48,8 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
48
48
|
isSessionAuth: z.ZodOptional<z.ZodBoolean>;
|
|
49
49
|
enrollmentCapable: z.ZodOptional<z.ZodBoolean>;
|
|
50
50
|
isDeliveryAgent: z.ZodOptional<z.ZodBoolean>;
|
|
51
|
+
/** Host-authenticated marker for the dedicated full standalone Hermes audience. */
|
|
52
|
+
isHermesAgent: z.ZodOptional<z.ZodBoolean>;
|
|
51
53
|
networkScopeId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
52
54
|
}, "strict", z.ZodTypeAny, {
|
|
53
55
|
userId: string;
|
|
@@ -56,6 +58,7 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
56
58
|
enrollmentCapable?: boolean | undefined;
|
|
57
59
|
isDeliveryAgent?: boolean | undefined;
|
|
58
60
|
isSessionAuth?: boolean | undefined;
|
|
61
|
+
isHermesAgent?: boolean | undefined;
|
|
59
62
|
}, {
|
|
60
63
|
userId: string;
|
|
61
64
|
agentId?: string | undefined;
|
|
@@ -63,6 +66,7 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
63
66
|
enrollmentCapable?: boolean | undefined;
|
|
64
67
|
isDeliveryAgent?: boolean | undefined;
|
|
65
68
|
isSessionAuth?: boolean | undefined;
|
|
69
|
+
isHermesAgent?: boolean | undefined;
|
|
66
70
|
}>, {
|
|
67
71
|
userId: string;
|
|
68
72
|
agentId?: string | undefined;
|
|
@@ -70,6 +74,7 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
70
74
|
enrollmentCapable?: boolean | undefined;
|
|
71
75
|
isDeliveryAgent?: boolean | undefined;
|
|
72
76
|
isSessionAuth?: boolean | undefined;
|
|
77
|
+
isHermesAgent?: boolean | undefined;
|
|
73
78
|
}, {
|
|
74
79
|
userId: string;
|
|
75
80
|
agentId?: string | undefined;
|
|
@@ -77,5 +82,6 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
77
82
|
enrollmentCapable?: boolean | undefined;
|
|
78
83
|
isDeliveryAgent?: boolean | undefined;
|
|
79
84
|
isSessionAuth?: boolean | undefined;
|
|
85
|
+
isHermesAgent?: boolean | undefined;
|
|
80
86
|
}>;
|
|
81
87
|
export type McpResolvedIdentity = z.infer<typeof McpResolvedIdentitySchema>;
|
|
@@ -28,6 +28,8 @@ export const McpResolvedIdentitySchema = z.object({
|
|
|
28
28
|
isSessionAuth: z.boolean().optional(),
|
|
29
29
|
enrollmentCapable: z.boolean().optional(),
|
|
30
30
|
isDeliveryAgent: z.boolean().optional(),
|
|
31
|
+
/** Host-authenticated marker for the dedicated full standalone Hermes audience. */
|
|
32
|
+
isHermesAgent: z.boolean().optional(),
|
|
31
33
|
networkScopeId: z.string().min(1).nullable().optional(),
|
|
32
34
|
}).strict().superRefine((identity, ctx) => {
|
|
33
35
|
if (identity.isSessionAuth === true && identity.agentId) {
|
|
@@ -44,4 +46,11 @@ export const McpResolvedIdentitySchema = z.object({
|
|
|
44
46
|
message: 'Delivery-agent designation requires an agent ID.',
|
|
45
47
|
});
|
|
46
48
|
}
|
|
49
|
+
if (identity.isHermesAgent === true && !identity.agentId) {
|
|
50
|
+
ctx.addIssue({
|
|
51
|
+
code: z.ZodIssueCode.custom,
|
|
52
|
+
path: ['isHermesAgent'],
|
|
53
|
+
message: 'Hermes-agent designation requires an agent ID.',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
47
56
|
});
|