@opengeni/core 0.4.10 → 0.10.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.
@@ -0,0 +1,211 @@
1
+ import type { Settings } from "@opengeni/config";
2
+ import {
3
+ SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT,
4
+ SESSION_EFFECTIVE_TOOL_POLICY_ID_MAX_LENGTH,
5
+ mergeToolRefs,
6
+ type Session,
7
+ type SessionEffectiveToolPolicy,
8
+ type SessionToolPolicy,
9
+ type ToolRef,
10
+ } from "@opengeni/contracts";
11
+ import type { Database } from "@opengeni/db";
12
+ import { settingsWithEnabledCapabilityMcpServers } from "./capabilities";
13
+ import { enabledCapabilityMcpToolRefs } from "./resources";
14
+
15
+ const MANDATORY_SESSION_MCP_SERVER_IDS = ["opengeni"] as const;
16
+ const PROJECTABLE_REGISTRY_ID = /^[A-Za-z0-9_-]+$/;
17
+
18
+ export type ResolvedSessionToolPolicy = {
19
+ toolRefs: ToolRef[];
20
+ effectivePolicy: SessionEffectiveToolPolicy;
21
+ };
22
+
23
+ export type SessionToolPolicyInput = {
24
+ toolPolicy?: SessionToolPolicy | null;
25
+ sessionTools: ToolRef[];
26
+ turnTools?: ToolRef[];
27
+ /** Undefined preserves the legacy merge path for pre-provenance callers. */
28
+ turnToolsProvided?: boolean;
29
+ availableMcpServerIds: Iterable<string>;
30
+ /** Current omitted-tools defaults, intentionally narrower than all servers. */
31
+ defaultMcpServerIds?: Iterable<string>;
32
+ };
33
+
34
+ function sortedIds(ids: Iterable<string>): string[] {
35
+ return [...new Set(ids)].sort();
36
+ }
37
+
38
+ function projectIds(ids: readonly string[]): { ids: string[]; truncated: boolean } {
39
+ const projectable = ids.filter(
40
+ (id) =>
41
+ id.length <= SESSION_EFFECTIVE_TOOL_POLICY_ID_MAX_LENGTH && PROJECTABLE_REGISTRY_ID.test(id),
42
+ );
43
+ return {
44
+ ids: projectable.slice(0, SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT),
45
+ truncated:
46
+ projectable.length !== ids.length ||
47
+ projectable.length > SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Resolve the same ID-only policy used by API projections and worker turns.
53
+ * This function never receives endpoint URLs, credentials, schemas, or live
54
+ * probe results. `availableMcpServerIds` is the resolved runtime registry;
55
+ * `defaultMcpServerIds` is the capability-only omitted-tools set.
56
+ */
57
+ export function resolveSessionToolPolicy(input: SessionToolPolicyInput): ResolvedSessionToolPolicy {
58
+ const policy = input.toolPolicy ?? { mode: "legacy" as const, inheritedFromSessionId: null };
59
+ const availableIds = new Set(input.availableMcpServerIds);
60
+ // Never infer omitted-tools defaults from the full runtime registry: static
61
+ // MCPs are explicit-only unless they are capability-derived defaults.
62
+ const defaultIds = new Set(input.defaultMcpServerIds ?? []);
63
+ const mandatoryIds: string[] = MANDATORY_SESSION_MCP_SERVER_IDS.filter((id) =>
64
+ availableIds.has(id),
65
+ );
66
+ const mandatoryIdSet = new Set<string>(mandatoryIds);
67
+ const selectedRefs =
68
+ input.turnToolsProvided === true
69
+ ? mergeToolRefs([], input.turnTools ?? [])
70
+ : input.turnToolsProvided === false
71
+ ? mergeToolRefs([], input.sessionTools)
72
+ : mergeToolRefs(input.sessionTools, input.turnTools ?? []);
73
+ const tracksWorkspaceDefaults =
74
+ policy.mode === "workspace_default" && input.turnToolsProvided !== true;
75
+
76
+ // Optional capability refs are a historical materialization of a
77
+ // workspace-default selection. They may outlive an installation or its
78
+ // credentials; do not hand an unavailable optional ref to runtime, where it
79
+ // would otherwise be an unknown MCP id. Strict historical refs intentionally
80
+ // remain so their fail-loud compatibility contract is preserved.
81
+ let toolRefs = selectedRefs.filter((tool) => tool.optional !== true || availableIds.has(tool.id));
82
+ if (tracksWorkspaceDefaults) {
83
+ toolRefs = mergeToolRefs(
84
+ toolRefs,
85
+ sortedIds(defaultIds)
86
+ .filter((id) => availableIds.has(id))
87
+ .map((id) => ({ kind: "mcp" as const, id, optional: true as const })),
88
+ );
89
+ }
90
+ toolRefs = mergeToolRefs(
91
+ toolRefs,
92
+ mandatoryIds.map((id) => ({ kind: "mcp" as const, id })),
93
+ );
94
+
95
+ // `effectiveIds` is the requested policy truth, including unavailable
96
+ // optional refs retained in the persisted selection. `toolRefs` above is
97
+ // the runtime-safe materialization, so projections can distinguish dropped
98
+ // history from what is actually handed to the MCP router.
99
+ const requestedEffectiveRefs = mergeToolRefs(
100
+ selectedRefs,
101
+ tracksWorkspaceDefaults
102
+ ? sortedIds(defaultIds)
103
+ .filter((id) => availableIds.has(id))
104
+ .map((id) => ({ kind: "mcp" as const, id, optional: true as const }))
105
+ : [],
106
+ );
107
+ const effectiveIds = sortedIds(
108
+ mergeToolRefs(
109
+ requestedEffectiveRefs,
110
+ mandatoryIds.map((id) => ({ kind: "mcp" as const, id })),
111
+ ).map((tool) => tool.id),
112
+ );
113
+ const configuredIds = effectiveIds.filter((id) => availableIds.has(id));
114
+ const configuredIdSet = new Set(configuredIds);
115
+ const droppedIds = effectiveIds.filter((id) => !configuredIdSet.has(id));
116
+ const deferredIds = tracksWorkspaceDefaults
117
+ ? sortedIds(
118
+ toolRefs
119
+ .filter(
120
+ (tool) =>
121
+ tool.optional === true &&
122
+ configuredIdSet.has(tool.id) &&
123
+ !mandatoryIdSet.has(tool.id),
124
+ )
125
+ .map((tool) => tool.id),
126
+ )
127
+ : [];
128
+ const selectedIds = sortedIds(
129
+ selectedRefs
130
+ .filter(
131
+ (tool) =>
132
+ !mandatoryIdSet.has(tool.id) && !(tracksWorkspaceDefaults && tool.optional === true),
133
+ )
134
+ .map((tool) => tool.id),
135
+ );
136
+ const projections = {
137
+ selected: projectIds(selectedIds),
138
+ effective: projectIds(effectiveIds),
139
+ mandatory: projectIds(sortedIds(mandatoryIds)),
140
+ deferred: projectIds(deferredIds),
141
+ configured: projectIds(configuredIds),
142
+ dropped: projectIds(droppedIds),
143
+ };
144
+
145
+ return {
146
+ toolRefs,
147
+ effectivePolicy: {
148
+ mode: policy.mode,
149
+ inheritedFromSessionId: policy.inheritedFromSessionId,
150
+ selectedIds: projections.selected.ids,
151
+ effectiveIds: projections.effective.ids,
152
+ mandatoryIds: projections.mandatory.ids,
153
+ lazyRouter: {
154
+ state: tracksWorkspaceDefaults ? "required" : "disabled",
155
+ deferredIds: projections.deferred.ids,
156
+ },
157
+ configuredIds: projections.configured.ids,
158
+ droppedIds: projections.dropped.ids,
159
+ counts: {
160
+ selected: selectedIds.length,
161
+ effective: effectiveIds.length,
162
+ mandatory: mandatoryIds.length,
163
+ deferred: deferredIds.length,
164
+ configured: configuredIds.length,
165
+ dropped: droppedIds.length,
166
+ },
167
+ idsTruncated: Object.values(projections).some((projection) => projection.truncated),
168
+ },
169
+ };
170
+ }
171
+
172
+ /** Current full runtime registry IDs, including configured static servers. */
173
+ export async function workspaceSessionToolPolicyServerIds(
174
+ db: Database,
175
+ workspaceId: string,
176
+ settings: Settings,
177
+ ): Promise<string[]> {
178
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
179
+ return sortedIds(runtimeSettings.mcpServers.map((server) => server.id));
180
+ }
181
+
182
+ /** Current omitted-tools defaults; this preserves capability-first behavior. */
183
+ export async function workspaceSessionToolPolicyDefaultServerIds(
184
+ db: Database,
185
+ workspaceId: string,
186
+ settings: Settings,
187
+ ): Promise<string[]> {
188
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
189
+ return sortedIds(enabledCapabilityMcpToolRefs(settings, runtimeSettings).map((tool) => tool.id));
190
+ }
191
+
192
+ /** Add a bounded, secret-safe effective projection to a session response. */
193
+ export function sessionWithEffectiveToolPolicy(
194
+ session: Session,
195
+ workspaceServerIds: Iterable<string>,
196
+ workspaceDefaultServerIds: Iterable<string> = [],
197
+ ): Session {
198
+ const availableIds = new Set(workspaceServerIds);
199
+ for (const server of session.mcpServers) {
200
+ availableIds.add(server.id);
201
+ }
202
+ return {
203
+ ...session,
204
+ effectiveToolPolicy: resolveSessionToolPolicy({
205
+ ...(session.toolPolicy ? { toolPolicy: session.toolPolicy } : {}),
206
+ sessionTools: session.tools,
207
+ availableMcpServerIds: availableIds,
208
+ defaultMcpServerIds: workspaceDefaultServerIds,
209
+ }).effectivePolicy,
210
+ };
211
+ }