pilotswarm-sdk 0.5.64 → 0.5.65
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/dist/activity-routing.d.ts +21 -0
- package/dist/activity-routing.d.ts.map +1 -0
- package/dist/activity-routing.js +32 -0
- package/dist/activity-routing.js.map +1 -0
- package/dist/agent-discovery.d.ts +35 -0
- package/dist/agent-discovery.d.ts.map +1 -0
- package/dist/agent-discovery.js +107 -0
- package/dist/agent-discovery.js.map +1 -0
- package/dist/client.d.ts +9 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +94 -12
- package/dist/client.js.map +1 -1
- package/dist/managed-session.d.ts.map +1 -1
- package/dist/managed-session.js +21 -13
- package/dist/managed-session.js.map +1 -1
- package/dist/native-subagents.d.ts +1 -1
- package/dist/native-subagents.d.ts.map +1 -1
- package/dist/native-subagents.js +11 -6
- package/dist/native-subagents.js.map +1 -1
- package/dist/orchestration/agents.d.ts +8 -3
- package/dist/orchestration/agents.d.ts.map +1 -1
- package/dist/orchestration/agents.js +87 -36
- package/dist/orchestration/agents.js.map +1 -1
- package/dist/orchestration/index.d.ts +2 -2
- package/dist/orchestration/index.js +1 -1
- package/dist/orchestration/lifecycle.js +1 -1
- package/dist/orchestration/lifecycle.js.map +1 -1
- package/dist/orchestration/runtime.d.ts +1 -1
- package/dist/orchestration/runtime.d.ts.map +1 -1
- package/dist/orchestration/runtime.js +18 -4
- package/dist/orchestration/runtime.js.map +1 -1
- package/dist/orchestration/turn.d.ts.map +1 -1
- package/dist/orchestration/turn.js +3 -5
- package/dist/orchestration/turn.js.map +1 -1
- package/dist/orchestration-registry.d.ts.map +1 -1
- package/dist/orchestration-registry.js +12 -2
- package/dist/orchestration-registry.js.map +1 -1
- package/dist/orchestration-version.d.ts +1 -1
- package/dist/orchestration-version.js +1 -1
- package/dist/orchestration.d.ts +2 -2
- package/dist/orchestration.js +1 -1
- package/dist/orchestration_1_0_46.d.ts +1 -1
- package/dist/orchestration_1_0_47.d.ts +1 -1
- package/dist/orchestration_1_0_48.d.ts +1 -1
- package/dist/orchestration_1_0_49.d.ts +1 -1
- package/dist/orchestration_1_0_50.d.ts +1 -1
- package/dist/orchestration_1_0_73/agents.d.ts +61 -0
- package/dist/orchestration_1_0_73/agents.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/agents.js +843 -0
- package/dist/orchestration_1_0_73/agents.js.map +1 -0
- package/dist/orchestration_1_0_73/index.d.ts +24 -0
- package/dist/orchestration_1_0_73/index.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/index.js +13 -0
- package/dist/orchestration_1_0_73/index.js.map +1 -0
- package/dist/orchestration_1_0_73/lifecycle.d.ts +51 -0
- package/dist/orchestration_1_0_73/lifecycle.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/lifecycle.js +981 -0
- package/dist/orchestration_1_0_73/lifecycle.js.map +1 -0
- package/dist/orchestration_1_0_73/queue.d.ts +20 -0
- package/dist/orchestration_1_0_73/queue.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/queue.js +894 -0
- package/dist/orchestration_1_0_73/queue.js.map +1 -0
- package/dist/orchestration_1_0_73/runtime.d.ts +31 -0
- package/dist/orchestration_1_0_73/runtime.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/runtime.js +230 -0
- package/dist/orchestration_1_0_73/runtime.js.map +1 -0
- package/dist/orchestration_1_0_73/state.d.ts +214 -0
- package/dist/orchestration_1_0_73/state.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/state.js +178 -0
- package/dist/orchestration_1_0_73/state.js.map +1 -0
- package/dist/orchestration_1_0_73/turn.d.ts +34 -0
- package/dist/orchestration_1_0_73/turn.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/turn.js +1435 -0
- package/dist/orchestration_1_0_73/turn.js.map +1 -0
- package/dist/orchestration_1_0_73/utils.d.ts +39 -0
- package/dist/orchestration_1_0_73/utils.d.ts.map +1 -0
- package/dist/orchestration_1_0_73/utils.js +322 -0
- package/dist/orchestration_1_0_73/utils.js.map +1 -0
- package/dist/orchestration_1_0_74/agents.d.ts +61 -0
- package/dist/orchestration_1_0_74/agents.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/agents.js +889 -0
- package/dist/orchestration_1_0_74/agents.js.map +1 -0
- package/dist/orchestration_1_0_74/index.d.ts +24 -0
- package/dist/orchestration_1_0_74/index.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/index.js +13 -0
- package/dist/orchestration_1_0_74/index.js.map +1 -0
- package/dist/orchestration_1_0_74/lifecycle.d.ts +51 -0
- package/dist/orchestration_1_0_74/lifecycle.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/lifecycle.js +981 -0
- package/dist/orchestration_1_0_74/lifecycle.js.map +1 -0
- package/dist/orchestration_1_0_74/queue.d.ts +20 -0
- package/dist/orchestration_1_0_74/queue.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/queue.js +894 -0
- package/dist/orchestration_1_0_74/queue.js.map +1 -0
- package/dist/orchestration_1_0_74/runtime.d.ts +31 -0
- package/dist/orchestration_1_0_74/runtime.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/runtime.js +232 -0
- package/dist/orchestration_1_0_74/runtime.js.map +1 -0
- package/dist/orchestration_1_0_74/state.d.ts +214 -0
- package/dist/orchestration_1_0_74/state.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/state.js +178 -0
- package/dist/orchestration_1_0_74/state.js.map +1 -0
- package/dist/orchestration_1_0_74/turn.d.ts +34 -0
- package/dist/orchestration_1_0_74/turn.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/turn.js +1435 -0
- package/dist/orchestration_1_0_74/turn.js.map +1 -0
- package/dist/orchestration_1_0_74/utils.d.ts +39 -0
- package/dist/orchestration_1_0_74/utils.d.ts.map +1 -0
- package/dist/orchestration_1_0_74/utils.js +322 -0
- package/dist/orchestration_1_0_74/utils.js.map +1 -0
- package/dist/orchestration_1_0_75/agents.d.ts +61 -0
- package/dist/orchestration_1_0_75/agents.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/agents.js +887 -0
- package/dist/orchestration_1_0_75/agents.js.map +1 -0
- package/dist/orchestration_1_0_75/index.d.ts +24 -0
- package/dist/orchestration_1_0_75/index.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/index.js +13 -0
- package/dist/orchestration_1_0_75/index.js.map +1 -0
- package/dist/orchestration_1_0_75/lifecycle.d.ts +51 -0
- package/dist/orchestration_1_0_75/lifecycle.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/lifecycle.js +981 -0
- package/dist/orchestration_1_0_75/lifecycle.js.map +1 -0
- package/dist/orchestration_1_0_75/queue.d.ts +20 -0
- package/dist/orchestration_1_0_75/queue.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/queue.js +894 -0
- package/dist/orchestration_1_0_75/queue.js.map +1 -0
- package/dist/orchestration_1_0_75/runtime.d.ts +31 -0
- package/dist/orchestration_1_0_75/runtime.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/runtime.js +239 -0
- package/dist/orchestration_1_0_75/runtime.js.map +1 -0
- package/dist/orchestration_1_0_75/state.d.ts +214 -0
- package/dist/orchestration_1_0_75/state.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/state.js +178 -0
- package/dist/orchestration_1_0_75/state.js.map +1 -0
- package/dist/orchestration_1_0_75/turn.d.ts +34 -0
- package/dist/orchestration_1_0_75/turn.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/turn.js +1435 -0
- package/dist/orchestration_1_0_75/turn.js.map +1 -0
- package/dist/orchestration_1_0_75/utils.d.ts +39 -0
- package/dist/orchestration_1_0_75/utils.d.ts.map +1 -0
- package/dist/orchestration_1_0_75/utils.js +322 -0
- package/dist/orchestration_1_0_75/utils.js.map +1 -0
- package/dist/orchestration_1_0_76/agents.d.ts +61 -0
- package/dist/orchestration_1_0_76/agents.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/agents.js +865 -0
- package/dist/orchestration_1_0_76/agents.js.map +1 -0
- package/dist/orchestration_1_0_76/index.d.ts +24 -0
- package/dist/orchestration_1_0_76/index.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/index.js +13 -0
- package/dist/orchestration_1_0_76/index.js.map +1 -0
- package/dist/orchestration_1_0_76/lifecycle.d.ts +51 -0
- package/dist/orchestration_1_0_76/lifecycle.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/lifecycle.js +981 -0
- package/dist/orchestration_1_0_76/lifecycle.js.map +1 -0
- package/dist/orchestration_1_0_76/queue.d.ts +20 -0
- package/dist/orchestration_1_0_76/queue.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/queue.js +894 -0
- package/dist/orchestration_1_0_76/queue.js.map +1 -0
- package/dist/orchestration_1_0_76/runtime.d.ts +31 -0
- package/dist/orchestration_1_0_76/runtime.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/runtime.js +239 -0
- package/dist/orchestration_1_0_76/runtime.js.map +1 -0
- package/dist/orchestration_1_0_76/state.d.ts +214 -0
- package/dist/orchestration_1_0_76/state.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/state.js +178 -0
- package/dist/orchestration_1_0_76/state.js.map +1 -0
- package/dist/orchestration_1_0_76/turn.d.ts +34 -0
- package/dist/orchestration_1_0_76/turn.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/turn.js +1435 -0
- package/dist/orchestration_1_0_76/turn.js.map +1 -0
- package/dist/orchestration_1_0_76/utils.d.ts +39 -0
- package/dist/orchestration_1_0_76/utils.d.ts.map +1 -0
- package/dist/orchestration_1_0_76/utils.js +322 -0
- package/dist/orchestration_1_0_76/utils.js.map +1 -0
- package/dist/orchestration_1_0_77/agents.d.ts +66 -0
- package/dist/orchestration_1_0_77/agents.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/agents.js +895 -0
- package/dist/orchestration_1_0_77/agents.js.map +1 -0
- package/dist/orchestration_1_0_77/index.d.ts +24 -0
- package/dist/orchestration_1_0_77/index.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/index.js +13 -0
- package/dist/orchestration_1_0_77/index.js.map +1 -0
- package/dist/orchestration_1_0_77/lifecycle.d.ts +51 -0
- package/dist/orchestration_1_0_77/lifecycle.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/lifecycle.js +981 -0
- package/dist/orchestration_1_0_77/lifecycle.js.map +1 -0
- package/dist/orchestration_1_0_77/queue.d.ts +20 -0
- package/dist/orchestration_1_0_77/queue.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/queue.js +894 -0
- package/dist/orchestration_1_0_77/queue.js.map +1 -0
- package/dist/orchestration_1_0_77/runtime.d.ts +31 -0
- package/dist/orchestration_1_0_77/runtime.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/runtime.js +239 -0
- package/dist/orchestration_1_0_77/runtime.js.map +1 -0
- package/dist/orchestration_1_0_77/state.d.ts +214 -0
- package/dist/orchestration_1_0_77/state.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/state.js +178 -0
- package/dist/orchestration_1_0_77/state.js.map +1 -0
- package/dist/orchestration_1_0_77/turn.d.ts +34 -0
- package/dist/orchestration_1_0_77/turn.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/turn.js +1433 -0
- package/dist/orchestration_1_0_77/turn.js.map +1 -0
- package/dist/orchestration_1_0_77/utils.d.ts +39 -0
- package/dist/orchestration_1_0_77/utils.d.ts.map +1 -0
- package/dist/orchestration_1_0_77/utils.js +322 -0
- package/dist/orchestration_1_0_77/utils.js.map +1 -0
- package/dist/reserved-tool-names.d.ts +5 -0
- package/dist/reserved-tool-names.d.ts.map +1 -0
- package/dist/reserved-tool-names.js +102 -0
- package/dist/reserved-tool-names.js.map +1 -0
- package/dist/session-manager.d.ts +25 -1
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +275 -93
- package/dist/session-manager.js.map +1 -1
- package/dist/session-proxy.d.ts +28 -3
- package/dist/session-proxy.d.ts.map +1 -1
- package/dist/session-proxy.js +174 -70
- package/dist/session-proxy.js.map +1 -1
- package/dist/session-store.d.ts +2 -0
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +18 -2
- package/dist/session-store.js.map +1 -1
- package/dist/types.d.ts +17 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/worker.d.ts +9 -3
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +110 -99
- package/dist/worker.js.map +1 -1
- package/package.json +4 -3
- package/plugins/system/agents/default.agent.md +4 -3
package/dist/session-manager.js
CHANGED
|
@@ -38,6 +38,7 @@ const DEHYDRATE_STORE_MAX_RETRIES = 1;
|
|
|
38
38
|
const DEHYDRATE_STORE_RETRY_BASE_DELAY_MS = 0;
|
|
39
39
|
const SESSION_LOCK_BACKOFF_MS = [5_000, 10_000, 20_000];
|
|
40
40
|
const SESSION_LOCK_MAX_WAIT_MS = 120_000;
|
|
41
|
+
const COPILOT_CLIENT_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
41
42
|
export const SESSION_LOCK_ACQUIRE_TIMEOUT_CODE = "PILOTSWARM_SESSION_LOCK_ACQUIRE_TIMEOUT";
|
|
42
43
|
export class SessionLockAcquireTimeoutError extends Error {
|
|
43
44
|
code = SESSION_LOCK_ACQUIRE_TIMEOUT_CODE;
|
|
@@ -79,6 +80,24 @@ function isMissingDehydrateSnapshotError(error) {
|
|
|
79
80
|
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
80
81
|
return /Session state directory not ready during dehydrate/i.test(message);
|
|
81
82
|
}
|
|
83
|
+
export class PackageToolBindingError extends Error {
|
|
84
|
+
toolName;
|
|
85
|
+
code = "PACKAGE_TOOL_REQUIRES_BOUND_AGENT";
|
|
86
|
+
constructor(toolName) {
|
|
87
|
+
super(`Package tool "${toolName}" requires its owning named-agent definition. Use ps_list_agents to find its named agent, then call spawn_agent with the exact agent_name and your assignment in task.`);
|
|
88
|
+
this.toolName = toolName;
|
|
89
|
+
this.name = "PackageToolBindingError";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export class BoundAgentPackageUnavailableError extends Error {
|
|
93
|
+
packageId;
|
|
94
|
+
code = "BOUND_AGENT_PACKAGE_UNAVAILABLE";
|
|
95
|
+
constructor(packageId, message = `The bound agent package "${packageId}" is no longer available to this session.`) {
|
|
96
|
+
super(message);
|
|
97
|
+
this.packageId = packageId;
|
|
98
|
+
this.name = "BoundAgentPackageUnavailableError";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
82
101
|
/** Key under which a package copy's per-agent config (MCP) is registered. */
|
|
83
102
|
export function packageAgentKey(packageId, agentName) {
|
|
84
103
|
return `pkg\u0001${packageId}\u0001${agentName}`;
|
|
@@ -123,7 +142,58 @@ export function pickAgentCopyForOwner(entry, ownerKey) {
|
|
|
123
142
|
?? copies.find((copy) => copy.packageScope === "shared")
|
|
124
143
|
?? undefined;
|
|
125
144
|
}
|
|
126
|
-
|
|
145
|
+
/** Resolve an already-authorized exact package copy while rechecking owner visibility. */
|
|
146
|
+
export function pickAgentCopyByPackageIdForOwner(entry, packageId, ownerKey) {
|
|
147
|
+
if (!entry || !packageId)
|
|
148
|
+
return undefined;
|
|
149
|
+
const copies = entry.copies?.length ? entry.copies : [entry];
|
|
150
|
+
const copy = copies.find((candidate) => candidate.packageId === packageId);
|
|
151
|
+
if (!copy)
|
|
152
|
+
return undefined;
|
|
153
|
+
if (copy.packageScope !== "user")
|
|
154
|
+
return copy;
|
|
155
|
+
return agentOwnerKey(copy.packageOwner) === ownerKey && ownerKey !== null
|
|
156
|
+
? copy
|
|
157
|
+
: undefined;
|
|
158
|
+
}
|
|
159
|
+
/** Resolve every part of a bound agent using the same authorized package copy. */
|
|
160
|
+
function resolveBoundAgentCopy(workerDefaults, config, sessionOwnerKey) {
|
|
161
|
+
const entry = config.boundAgentName
|
|
162
|
+
? workerDefaults.agentPromptLookup?.[config.boundAgentName]
|
|
163
|
+
: undefined;
|
|
164
|
+
if (config.boundAgentSource === "deployment") {
|
|
165
|
+
const copies = entry?.copies?.length ? entry.copies : entry ? [entry] : [];
|
|
166
|
+
const deployment = copies.find(copy => !copy.packageId && copy.packageScope == null);
|
|
167
|
+
if (config.boundAgentPackageId || !deployment) {
|
|
168
|
+
throw new BoundAgentPackageUnavailableError(`deployment:${config.boundAgentName ?? ""}`, `The bound deployment agent "${config.boundAgentName ?? ""}" is no longer available or has a conflicting package binding.`);
|
|
169
|
+
}
|
|
170
|
+
return deployment;
|
|
171
|
+
}
|
|
172
|
+
const copy = config.boundAgentPackageId
|
|
173
|
+
? pickAgentCopyByPackageIdForOwner(entry, config.boundAgentPackageId, sessionOwnerKey)
|
|
174
|
+
: pickAgentCopyForOwner(entry, sessionOwnerKey);
|
|
175
|
+
if (config.boundAgentPackageId && !copy) {
|
|
176
|
+
throw new BoundAgentPackageUnavailableError(config.boundAgentPackageId);
|
|
177
|
+
}
|
|
178
|
+
return copy;
|
|
179
|
+
}
|
|
180
|
+
/** Match the SDK wire declaration, including schemas supplied through Zod. */
|
|
181
|
+
function toolDeclarationForFingerprint(tool) {
|
|
182
|
+
const parameters = tool.parameters;
|
|
183
|
+
return {
|
|
184
|
+
name: tool.name,
|
|
185
|
+
description: tool.description,
|
|
186
|
+
parameters: parameters != null && typeof parameters === "object" && typeof parameters.toJSONSchema === "function"
|
|
187
|
+
? parameters.toJSONSchema()
|
|
188
|
+
: parameters,
|
|
189
|
+
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
190
|
+
skipPermission: tool.skipPermission,
|
|
191
|
+
defer: tool.defer ?? "never",
|
|
192
|
+
metadata: tool.metadata,
|
|
193
|
+
isTerminal: tool.isTerminal,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function buildEffectivePromptLayers(workerDefaults, config, sessionOwnerKey = null, boundAgentCopy = resolveBoundAgentCopy(workerDefaults, config, sessionOwnerKey) ?? null) {
|
|
127
197
|
const boundAgentName = config.boundAgentName;
|
|
128
198
|
const layerKind = config.promptLayering?.kind ?? (boundAgentName ? "app-agent" : undefined);
|
|
129
199
|
const isPilotSwarmSystemAgent = layerKind === "pilotswarm-system-agent";
|
|
@@ -133,9 +203,8 @@ function buildEffectivePromptLayers(workerDefaults, config, sessionOwnerKey = nu
|
|
|
133
203
|
if (!isPilotSwarmSystemAgent && workerDefaults.appDefaultDescriptor)
|
|
134
204
|
layers.push(workerDefaults.appDefaultDescriptor);
|
|
135
205
|
if (boundAgentName) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
layers.push(copy.descriptor);
|
|
206
|
+
if (boundAgentCopy?.descriptor)
|
|
207
|
+
layers.push(boundAgentCopy.descriptor);
|
|
139
208
|
}
|
|
140
209
|
return layers;
|
|
141
210
|
}
|
|
@@ -309,10 +378,18 @@ export class SessionManager {
|
|
|
309
378
|
sessionStore = null;
|
|
310
379
|
/** In-memory configs with non-serializable fields (tools, hooks). */
|
|
311
380
|
sessionConfigs = new Map();
|
|
381
|
+
/** Only application-supplied tools; resolved registry/platform handlers are never cached as inputs. */
|
|
382
|
+
sessionApplicationTools = new Map();
|
|
383
|
+
/** One authorized agent snapshot per turn, also used by dynamic prompt callbacks. */
|
|
384
|
+
sessionAgentCopies = new Map();
|
|
385
|
+
/** CLI declarations and MCP grants require a new SDK handle when they change. */
|
|
386
|
+
sessionBindingFingerprints = new Map();
|
|
312
387
|
/** Worker-level tool registry — shared reference from PilotSwarmWorker. */
|
|
313
388
|
toolRegistry = new Map();
|
|
314
389
|
/** Per-package tool maps, so a session prefers ITS package's handler on a name collision. */
|
|
315
390
|
packageToolRegistry = null;
|
|
391
|
+
/** Package-owned names cannot be attached without the matching agent package binding. */
|
|
392
|
+
packageToolNames = new Set();
|
|
316
393
|
/** Names registered by deployment code — a package tool must never shadow these. */
|
|
317
394
|
staticToolNames = null;
|
|
318
395
|
/** Worker-level defaults for building blocks. */
|
|
@@ -368,6 +445,10 @@ export class SessionManager {
|
|
|
368
445
|
/** Store full config (with tools/hooks) for a session. Called by PilotSwarmClient. */
|
|
369
446
|
setConfig(sessionId, config) {
|
|
370
447
|
this.sessionConfigs.set(sessionId, config);
|
|
448
|
+
if (config.tools?.length)
|
|
449
|
+
this.sessionApplicationTools.set(sessionId, [...config.tools]);
|
|
450
|
+
else
|
|
451
|
+
this.sessionApplicationTools.delete(sessionId);
|
|
371
452
|
}
|
|
372
453
|
async _allowedModelProviderIds(sessionId) {
|
|
373
454
|
const registry = this.workerDefaults.modelProviders;
|
|
@@ -601,6 +682,12 @@ export class SessionManager {
|
|
|
601
682
|
this.toolRegistry = registry;
|
|
602
683
|
this.packageToolRegistry = opts?.byPackage ?? null;
|
|
603
684
|
this.staticToolNames = opts?.staticNames ?? null;
|
|
685
|
+
// Remember ownership after removal as well: a stale application-supplied
|
|
686
|
+
// handler must not become an ordinary tool when its package disappears.
|
|
687
|
+
for (const tools of this.packageToolRegistry?.values() ?? []) {
|
|
688
|
+
for (const name of tools.keys())
|
|
689
|
+
this.packageToolNames.add(name);
|
|
690
|
+
}
|
|
604
691
|
}
|
|
605
692
|
/** Set the cluster facts store for always-on facts tools. */
|
|
606
693
|
setFactStore(factStore) {
|
|
@@ -845,7 +932,7 @@ export class SessionManager {
|
|
|
845
932
|
await existing.destroy();
|
|
846
933
|
}
|
|
847
934
|
catch { }
|
|
848
|
-
this.
|
|
935
|
+
this._forgetWarmSession(sessionId);
|
|
849
936
|
}
|
|
850
937
|
try {
|
|
851
938
|
const client = await this._ensureClientForSession(sessionId);
|
|
@@ -881,7 +968,7 @@ export class SessionManager {
|
|
|
881
968
|
await existing.destroy();
|
|
882
969
|
}
|
|
883
970
|
catch { }
|
|
884
|
-
this.
|
|
971
|
+
this._forgetWarmSession(sessionId);
|
|
885
972
|
}
|
|
886
973
|
try {
|
|
887
974
|
const client = await this._ensureClientForSession(sessionId);
|
|
@@ -998,7 +1085,7 @@ export class SessionManager {
|
|
|
998
1085
|
await existing.destroy();
|
|
999
1086
|
}
|
|
1000
1087
|
catch { }
|
|
1001
|
-
this.
|
|
1088
|
+
this._forgetWarmSession(sessionId);
|
|
1002
1089
|
}
|
|
1003
1090
|
if (!dirExists) {
|
|
1004
1091
|
this.sessionLastTouchedAt.delete(sessionId);
|
|
@@ -1143,7 +1230,7 @@ export class SessionManager {
|
|
|
1143
1230
|
...(this.workerDefaults.appDefaultToolNames ?? []),
|
|
1144
1231
|
...(serializableConfig.toolNames ?? []),
|
|
1145
1232
|
]));
|
|
1146
|
-
|
|
1233
|
+
let effectiveSerializableConfig = inheritedToolNames.length > 0
|
|
1147
1234
|
? { ...serializableConfig, toolNames: inheritedToolNames }
|
|
1148
1235
|
: serializableConfig;
|
|
1149
1236
|
// Which copy of the bound agent does this session get? Owner-aware:
|
|
@@ -1151,20 +1238,69 @@ export class SessionManager {
|
|
|
1151
1238
|
// one, the same rule the registry resolver applies at create time.
|
|
1152
1239
|
// Resolved once here; prompt, descriptor, MCP, and tool-handler picks
|
|
1153
1240
|
// below all follow the same copy so a session can never mix copies.
|
|
1154
|
-
const boundAgentEntry = effectiveSerializableConfig.boundAgentName
|
|
1155
|
-
? this.workerDefaults.agentPromptLookup?.[effectiveSerializableConfig.boundAgentName]
|
|
1156
|
-
: undefined;
|
|
1157
|
-
// A PACKAGE agent (as opposed to a deployment/inline agent) carries a
|
|
1158
|
-
// packageId on its entry or on any of its copies. This is load-bearing
|
|
1159
|
-
// for MCP resolution: a package agent must never fall back to the
|
|
1160
|
-
// bare-name MCP key, which another copy of a shadowed name also wrote.
|
|
1161
1241
|
const sessionOwnerKey = effectiveSerializableConfig.boundAgentName
|
|
1162
1242
|
? await this._sessionAgentOwnerKey(sessionId)
|
|
1163
1243
|
: null;
|
|
1164
|
-
const boundAgentCopy = pickAgentCopyForOwner(boundAgentEntry, sessionOwnerKey);
|
|
1165
|
-
// Resolve tools: merge per-session (setConfig) + registry (toolNames)
|
|
1166
1244
|
const storedConfig = this.sessionConfigs.get(sessionId);
|
|
1167
|
-
|
|
1245
|
+
let boundAgentCopy;
|
|
1246
|
+
let resolvedTools;
|
|
1247
|
+
try {
|
|
1248
|
+
boundAgentCopy = resolveBoundAgentCopy(this.workerDefaults, effectiveSerializableConfig, sessionOwnerKey);
|
|
1249
|
+
// Snapshot the selected prompt and descriptor. A registry refresh in the
|
|
1250
|
+
// middle of a turn must not change instructions while handlers still
|
|
1251
|
+
// belong to the previously selected version.
|
|
1252
|
+
if (boundAgentCopy)
|
|
1253
|
+
boundAgentCopy = {
|
|
1254
|
+
...boundAgentCopy,
|
|
1255
|
+
...(boundAgentCopy.toolNames ? { toolNames: [...boundAgentCopy.toolNames] } : {}),
|
|
1256
|
+
...(boundAgentCopy.descriptor ? { descriptor: { ...boundAgentCopy.descriptor } } : {}),
|
|
1257
|
+
};
|
|
1258
|
+
if (boundAgentCopy?.toolNames && effectiveSerializableConfig.boundAgentName
|
|
1259
|
+
&& (effectiveSerializableConfig.boundAgentPackageId || effectiveSerializableConfig.detachedPackageToolPolicy
|
|
1260
|
+
|| effectiveSerializableConfig.namedAgentToolAdditions !== undefined)) {
|
|
1261
|
+
// Named definitions refresh as a unit. Roots may add ordinary
|
|
1262
|
+
// application tools; protected children receive only defaults and
|
|
1263
|
+
// their definition. Legacy package roots have no provenance, so
|
|
1264
|
+
// retain their ordinary names but never stale package capabilities.
|
|
1265
|
+
const additions = effectiveSerializableConfig.detachedPackageToolPolicy
|
|
1266
|
+
? []
|
|
1267
|
+
: (effectiveSerializableConfig.namedAgentToolAdditions ?? effectiveSerializableConfig.toolNames ?? [])
|
|
1268
|
+
.filter(name => this.staticToolNames?.has(name) || !this.packageToolNames.has(name));
|
|
1269
|
+
effectiveSerializableConfig = {
|
|
1270
|
+
...effectiveSerializableConfig,
|
|
1271
|
+
toolNames: [...new Set([
|
|
1272
|
+
...(this.workerDefaults.frameworkBaseToolNames ?? []),
|
|
1273
|
+
...(this.workerDefaults.appDefaultToolNames ?? []),
|
|
1274
|
+
...boundAgentCopy.toolNames,
|
|
1275
|
+
...additions,
|
|
1276
|
+
])],
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
if (effectiveSerializableConfig.boundAgentSource === "deployment") {
|
|
1280
|
+
// A deployment definition is bound, but owns no registry package.
|
|
1281
|
+
// It cannot borrow a shared/private package's exported handlers.
|
|
1282
|
+
effectiveSerializableConfig = { ...effectiveSerializableConfig, detachedPackageToolPolicy: "reject" };
|
|
1283
|
+
}
|
|
1284
|
+
resolvedTools = this._resolveTools({ tools: this.sessionApplicationTools.get(sessionId) }, effectiveSerializableConfig, boundAgentCopy?.packageId);
|
|
1285
|
+
}
|
|
1286
|
+
catch (error) {
|
|
1287
|
+
// Failed authorization/removal must not leave a reusable handle with
|
|
1288
|
+
// the previous package's handlers or MCP grants.
|
|
1289
|
+
await this.dropWarmSession(sessionId);
|
|
1290
|
+
this.sessionAgentCopies.delete(sessionId);
|
|
1291
|
+
throw error;
|
|
1292
|
+
}
|
|
1293
|
+
// Capture MCP grants with the same registry snapshot, before asynchronous
|
|
1294
|
+
// provider/catalog work below can allow a package reload to intervene.
|
|
1295
|
+
const boundAgentMcpServers = !effectiveSerializableConfig.boundAgentName || !boundAgentCopy
|
|
1296
|
+
? undefined
|
|
1297
|
+
: boundAgentCopy.packageId
|
|
1298
|
+
? this.workerDefaults.agentMcpServers?.[packageAgentKey(boundAgentCopy.packageId, effectiveSerializableConfig.boundAgentName)]
|
|
1299
|
+
: this.workerDefaults.agentMcpServers?.[effectiveSerializableConfig.boundAgentName];
|
|
1300
|
+
const effectiveMcpServers = {
|
|
1301
|
+
...(this.workerDefaults.baseMcpServers ?? {}),
|
|
1302
|
+
...(boundAgentMcpServers ?? {}),
|
|
1303
|
+
};
|
|
1168
1304
|
const config = {
|
|
1169
1305
|
...storedConfig,
|
|
1170
1306
|
...effectiveSerializableConfig,
|
|
@@ -1289,7 +1425,7 @@ export class SessionManager {
|
|
|
1289
1425
|
await existingWarm.destroy();
|
|
1290
1426
|
}
|
|
1291
1427
|
catch { }
|
|
1292
|
-
this.
|
|
1428
|
+
this._forgetWarmSession(sessionId);
|
|
1293
1429
|
}
|
|
1294
1430
|
}
|
|
1295
1431
|
const client = await this.ensureClient(userGithubToken, byokOpenAi);
|
|
@@ -1509,35 +1645,19 @@ export class SessionManager {
|
|
|
1509
1645
|
];
|
|
1510
1646
|
config.tools = persistentSessionTools;
|
|
1511
1647
|
// Build system message: worker base + client override
|
|
1512
|
-
const systemMessage = this._buildSystemMessage(sessionId, config, sessionOwnerKey);
|
|
1513
|
-
//
|
|
1514
|
-
//
|
|
1515
|
-
//
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
// • deployment/inline copy → the bare name (its own MCP);
|
|
1526
|
-
// • no copy resolved (a foreign-private-only name) → no grants.
|
|
1527
|
-
// Keying off `boundAgentCopy.packageId` rather than "is any copy a
|
|
1528
|
-
// package" is load-bearing: when a deployment agent and a package
|
|
1529
|
-
// share a name and this session resolved the DEPLOYMENT copy, it must
|
|
1530
|
-
// still get the deployment agent's bare-key MCP, not an empty
|
|
1531
|
-
// qualified lookup.
|
|
1532
|
-
const boundAgentMcpServers = !effectiveSerializableConfig.boundAgentName || !boundAgentCopy
|
|
1533
|
-
? undefined
|
|
1534
|
-
: boundAgentCopy.packageId
|
|
1535
|
-
? this.workerDefaults.agentMcpServers?.[packageAgentKey(boundAgentCopy.packageId, effectiveSerializableConfig.boundAgentName)]
|
|
1536
|
-
: this.workerDefaults.agentMcpServers?.[effectiveSerializableConfig.boundAgentName];
|
|
1537
|
-
const effectiveMcpServers = {
|
|
1538
|
-
...(this.workerDefaults.baseMcpServers ?? {}),
|
|
1539
|
-
...(boundAgentMcpServers ?? {}),
|
|
1540
|
-
};
|
|
1648
|
+
const systemMessage = this._buildSystemMessage(sessionId, config, sessionOwnerKey, boundAgentCopy ?? null);
|
|
1649
|
+
// Handler changes use updateConfig; declaration, MCP and authored prompt
|
|
1650
|
+
// changes need a fresh CLI handle at this turn boundary. Do not include
|
|
1651
|
+
// per-turn runtime context or newly allocated handler function identity.
|
|
1652
|
+
const bindingFingerprint = createHash("sha256").update(JSON.stringify({
|
|
1653
|
+
boundAgentName: config.boundAgentName,
|
|
1654
|
+
boundAgentSource: config.boundAgentSource,
|
|
1655
|
+
boundAgentCopy,
|
|
1656
|
+
mcpServers: effectiveMcpServers,
|
|
1657
|
+
tools: allTools.map(toolDeclarationForFingerprint),
|
|
1658
|
+
})).digest("hex");
|
|
1659
|
+
const bindingChanged = this.sessionBindingFingerprints.has(sessionId)
|
|
1660
|
+
&& this.sessionBindingFingerprints.get(sessionId) !== bindingFingerprint;
|
|
1541
1661
|
const sessionConfig = {
|
|
1542
1662
|
sessionId,
|
|
1543
1663
|
// Sole chokepoint where tool DECLARATIONS reach the CLI (create and
|
|
@@ -1621,15 +1741,16 @@ export class SessionManager {
|
|
|
1621
1741
|
console.warn(`[SessionManager] epoch-start for ${sessionId} (epoch ${transcriptEpoch}); ` +
|
|
1622
1742
|
`discarding the warm Copilot session of the previous epoch.`);
|
|
1623
1743
|
await existing.destroy();
|
|
1624
|
-
this.
|
|
1744
|
+
this._forgetWarmSession(sessionId);
|
|
1625
1745
|
}
|
|
1626
|
-
else if (existing.requiresModelRebind(config)) {
|
|
1627
|
-
console.warn(`[SessionManager] model
|
|
1628
|
-
`disconnecting warm Copilot session so it can resume with the
|
|
1746
|
+
else if (bindingChanged || existing.requiresModelRebind(config)) {
|
|
1747
|
+
console.warn(`[SessionManager] model or agent configuration changed for ${sessionId}; ` +
|
|
1748
|
+
`disconnecting warm Copilot session so it can resume with the updated configuration.`);
|
|
1629
1749
|
await existing.destroy();
|
|
1630
|
-
this.
|
|
1750
|
+
this._forgetWarmSession(sessionId);
|
|
1631
1751
|
}
|
|
1632
1752
|
else {
|
|
1753
|
+
this.sessionAgentCopies.set(sessionId, boundAgentCopy);
|
|
1633
1754
|
existing.updateConfig(config);
|
|
1634
1755
|
return existing;
|
|
1635
1756
|
}
|
|
@@ -1737,7 +1858,9 @@ export class SessionManager {
|
|
|
1737
1858
|
agentId: effectiveSerializableConfig.agentIdentity ?? null,
|
|
1738
1859
|
}));
|
|
1739
1860
|
this.sessions.set(sessionId, managed);
|
|
1740
|
-
|
|
1861
|
+
this.sessionAgentCopies.set(sessionId, boundAgentCopy);
|
|
1862
|
+
this.sessionBindingFingerprints.set(sessionId, bindingFingerprint);
|
|
1863
|
+
const promptLayers = buildEffectivePromptLayers(this.workerDefaults, config, sessionOwnerKey, boundAgentCopy ?? null);
|
|
1741
1864
|
if (promptLayers.length > 0 && this.sessionCatalog) {
|
|
1742
1865
|
void this.sessionCatalog.recordEvents(sessionId, [{
|
|
1743
1866
|
eventType: "session.prompt_layers",
|
|
@@ -1754,6 +1877,12 @@ export class SessionManager {
|
|
|
1754
1877
|
getSessionStateDir() {
|
|
1755
1878
|
return this.sessionStateDir;
|
|
1756
1879
|
}
|
|
1880
|
+
/** Release snapshots with their SDK handle; application tools survive ordinary hydration. */
|
|
1881
|
+
_forgetWarmSession(sessionId) {
|
|
1882
|
+
this.sessions.delete(sessionId);
|
|
1883
|
+
this.sessionAgentCopies.delete(sessionId);
|
|
1884
|
+
this.sessionBindingFingerprints.delete(sessionId);
|
|
1885
|
+
}
|
|
1757
1886
|
/**
|
|
1758
1887
|
* Destroy the in-memory ManagedSession only — disk state untouched.
|
|
1759
1888
|
* Used by the lifecycle preamble before overwriting local files with a
|
|
@@ -1762,13 +1891,13 @@ export class SessionManager {
|
|
|
1762
1891
|
*/
|
|
1763
1892
|
async dropWarmSession(sessionId) {
|
|
1764
1893
|
const existing = this.sessions.get(sessionId);
|
|
1765
|
-
if (
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1894
|
+
if (existing) {
|
|
1895
|
+
try {
|
|
1896
|
+
await existing.destroy();
|
|
1897
|
+
}
|
|
1898
|
+
catch { }
|
|
1769
1899
|
}
|
|
1770
|
-
|
|
1771
|
-
this.sessions.delete(sessionId);
|
|
1900
|
+
this._forgetWarmSession(sessionId);
|
|
1772
1901
|
}
|
|
1773
1902
|
/**
|
|
1774
1903
|
* Dehydrate a session: snapshot to the session store, release in-memory state.
|
|
@@ -1824,13 +1953,13 @@ export class SessionManager {
|
|
|
1824
1953
|
try {
|
|
1825
1954
|
emitSessionManagerTrace(sessionId, `destroy attempt ${attempt}/${DESTROY_MAX_RETRIES}`, { trace });
|
|
1826
1955
|
await session.destroy();
|
|
1827
|
-
this.
|
|
1956
|
+
this._forgetWarmSession(sessionId);
|
|
1828
1957
|
emitSessionManagerTrace(sessionId, `destroy complete on attempt ${attempt}/${DESTROY_MAX_RETRIES}`, { trace });
|
|
1829
1958
|
break; // Success
|
|
1830
1959
|
}
|
|
1831
1960
|
catch (err) {
|
|
1832
1961
|
lastDestroyError = normalizeError(err);
|
|
1833
|
-
this.
|
|
1962
|
+
this._forgetWarmSession(sessionId); // Remove broken session from map
|
|
1834
1963
|
emitSessionManagerTrace(sessionId, `destroy failed on attempt ${attempt}/${DESTROY_MAX_RETRIES} error=${lastDestroyError.message}`, { trace, level: "warn" });
|
|
1835
1964
|
if (attempt < DESTROY_MAX_RETRIES) {
|
|
1836
1965
|
// Re-create the session from local files so we can try destroy again.
|
|
@@ -1991,10 +2120,11 @@ export class SessionManager {
|
|
|
1991
2120
|
return this._withSessionLock(sessionId, "destroySession", () => this.destroySession(sessionId, { lockHeld: true }));
|
|
1992
2121
|
}
|
|
1993
2122
|
const session = this.sessions.get(sessionId);
|
|
1994
|
-
if (session)
|
|
2123
|
+
if (session)
|
|
1995
2124
|
await session.destroy();
|
|
1996
|
-
|
|
1997
|
-
|
|
2125
|
+
this._forgetWarmSession(sessionId);
|
|
2126
|
+
this.sessionApplicationTools.delete(sessionId);
|
|
2127
|
+
this.sessionConfigs.delete(sessionId);
|
|
1998
2128
|
}
|
|
1999
2129
|
/**
|
|
2000
2130
|
* Drop the warm in-memory session handle without deleting any persisted
|
|
@@ -2012,7 +2142,7 @@ export class SessionManager {
|
|
|
2012
2142
|
await session.destroy();
|
|
2013
2143
|
}
|
|
2014
2144
|
catch { }
|
|
2015
|
-
this.
|
|
2145
|
+
this._forgetWarmSession(sessionId);
|
|
2016
2146
|
}
|
|
2017
2147
|
/**
|
|
2018
2148
|
* Fully reset a session's live and persisted Copilot state.
|
|
@@ -2041,25 +2171,51 @@ export class SessionManager {
|
|
|
2041
2171
|
activeSessionIds() {
|
|
2042
2172
|
return [...this.sessions.keys()];
|
|
2043
2173
|
}
|
|
2044
|
-
/**
|
|
2174
|
+
/** Final worker cleanup, after the durable runtime has drained. */
|
|
2045
2175
|
async shutdown() {
|
|
2046
2176
|
this.unsubscribeFeatureFlags?.();
|
|
2047
2177
|
this.unsubscribeFeatureFlags = null;
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2178
|
+
// CopilotClient.stop owns session detachment. Detaching each session
|
|
2179
|
+
// first can hang forever in the SDK's unbounded session.detach RPC.
|
|
2180
|
+
// Snapshot and release this pool before awaiting: late SDK cleanup
|
|
2181
|
+
// must never clear clients/configuration installed by a later start.
|
|
2182
|
+
const clients = [...new Set(this.clients.values())];
|
|
2183
|
+
this.clients.clear();
|
|
2054
2184
|
this.sessions.clear();
|
|
2185
|
+
this.sessionAgentCopies.clear();
|
|
2186
|
+
this.sessionBindingFingerprints.clear();
|
|
2187
|
+
this.sessionApplicationTools.clear();
|
|
2188
|
+
this.sessionConfigs.clear();
|
|
2055
2189
|
this.sessionClientKeys.clear();
|
|
2056
|
-
|
|
2190
|
+
// Each process gets the same deadline concurrently; one stuck client
|
|
2191
|
+
// cannot block another or multiply the worker's termination budget.
|
|
2192
|
+
// This is final cleanup only, not the individual-session eviction path.
|
|
2193
|
+
await Promise.all(clients.map(async (client) => {
|
|
2194
|
+
let timer;
|
|
2057
2195
|
try {
|
|
2058
|
-
await
|
|
2196
|
+
const errors = await Promise.race([
|
|
2197
|
+
client.stop(),
|
|
2198
|
+
new Promise((_, reject) => {
|
|
2199
|
+
timer = setTimeout(() => reject(new Error("Copilot shutdown timed out")), COPILOT_CLIENT_SHUTDOWN_TIMEOUT_MS);
|
|
2200
|
+
}),
|
|
2201
|
+
]);
|
|
2202
|
+
if (errors?.length)
|
|
2203
|
+
throw errors[0];
|
|
2059
2204
|
}
|
|
2060
|
-
catch {
|
|
2061
|
-
|
|
2062
|
-
|
|
2205
|
+
catch {
|
|
2206
|
+
console.warn("[SessionManager] Copilot did not shut down cleanly; forcing its local process to stop.");
|
|
2207
|
+
try {
|
|
2208
|
+
await client.forceStop();
|
|
2209
|
+
}
|
|
2210
|
+
catch {
|
|
2211
|
+
console.warn("[SessionManager] Copilot force-stop failed.");
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
finally {
|
|
2215
|
+
if (timer)
|
|
2216
|
+
clearTimeout(timer);
|
|
2217
|
+
}
|
|
2218
|
+
}));
|
|
2063
2219
|
}
|
|
2064
2220
|
/**
|
|
2065
2221
|
* Resolve tools from per-session config + worker-level registry.
|
|
@@ -2078,15 +2234,42 @@ export class SessionManager {
|
|
|
2078
2234
|
: undefined;
|
|
2079
2235
|
if (serializableConfig.toolNames?.length) {
|
|
2080
2236
|
for (const name of serializableConfig.toolNames) {
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
|
|
2237
|
+
const staticTool = this.staticToolNames?.has(name)
|
|
2238
|
+
? this.toolRegistry.get(name)
|
|
2239
|
+
: undefined;
|
|
2240
|
+
const packageTool = packageTools?.get(name);
|
|
2241
|
+
if (!staticTool && !packageTool && this.packageToolNames.has(name)) {
|
|
2242
|
+
if (serializableConfig.detachedPackageToolPolicy === "drop")
|
|
2243
|
+
continue;
|
|
2244
|
+
if (serializableConfig.detachedPackageToolPolicy === "reject" || preferredPackageId) {
|
|
2245
|
+
throw new PackageToolBindingError(name);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
const tool = staticTool ?? packageTool ?? this.toolRegistry.get(name);
|
|
2084
2249
|
if (tool)
|
|
2085
2250
|
registryTools.push(tool);
|
|
2086
2251
|
}
|
|
2087
2252
|
}
|
|
2253
|
+
const storedTools = (storedConfig?.tools ?? []).filter((tool) => {
|
|
2254
|
+
const name = String(tool?.name || "");
|
|
2255
|
+
if (!name || this.staticToolNames?.has(name) || !this.packageToolNames.has(name))
|
|
2256
|
+
return true;
|
|
2257
|
+
// An explicitly supplied package handler follows the current package
|
|
2258
|
+
// copy, never a stale object retained by the caller across a reload.
|
|
2259
|
+
if (packageTools?.has(name) && serializableConfig.toolNames?.includes(name))
|
|
2260
|
+
return true;
|
|
2261
|
+
if (serializableConfig.detachedPackageToolPolicy === "drop")
|
|
2262
|
+
return false;
|
|
2263
|
+
if (serializableConfig.detachedPackageToolPolicy === "reject" || preferredPackageId) {
|
|
2264
|
+
throw new PackageToolBindingError(name);
|
|
2265
|
+
}
|
|
2266
|
+
return true;
|
|
2267
|
+
}).map((tool) => {
|
|
2268
|
+
const name = String(tool?.name || "");
|
|
2269
|
+
return this.staticToolNames?.has(name) ? tool : packageTools?.get(name) ?? tool;
|
|
2270
|
+
});
|
|
2088
2271
|
const combined = [
|
|
2089
|
-
...
|
|
2272
|
+
...storedTools,
|
|
2090
2273
|
...registryTools,
|
|
2091
2274
|
];
|
|
2092
2275
|
// Deduplicate by name — per-session tools take precedence
|
|
@@ -2218,18 +2401,17 @@ export class SessionManager {
|
|
|
2218
2401
|
},
|
|
2219
2402
|
};
|
|
2220
2403
|
}
|
|
2221
|
-
_buildLastInstructionsSection(sessionId, initialConfig) {
|
|
2404
|
+
_buildLastInstructionsSection(sessionId, initialConfig, initialAgentCopy) {
|
|
2222
2405
|
return {
|
|
2223
2406
|
action: async (currentContent) => {
|
|
2224
2407
|
const latest = this.sessionConfigs.get(sessionId) ?? initialConfig;
|
|
2225
2408
|
const runtimeContext = extractPromptContent(latest.systemMessage);
|
|
2226
|
-
//
|
|
2227
|
-
//
|
|
2228
|
-
//
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
: undefined;
|
|
2409
|
+
// Follow the same per-turn snapshot as tools/MCP/descriptor.
|
|
2410
|
+
// Re-selecting by bare name here could both defeat an explicit
|
|
2411
|
+
// shared-package pin and adopt refreshed instructions mid-turn.
|
|
2412
|
+
const activeAgentPrompt = (this.sessionAgentCopies.has(sessionId)
|
|
2413
|
+
? this.sessionAgentCopies.get(sessionId)
|
|
2414
|
+
: initialAgentCopy)?.prompt;
|
|
2233
2415
|
// Orchestration ≥1.0.71 delivers the per-turn note inside the
|
|
2234
2416
|
// user turn (see prompt-system-context.ts) and flags it. For
|
|
2235
2417
|
// those turns the note must NOT land here: this section is
|
|
@@ -2484,17 +2666,17 @@ export class SessionManager {
|
|
|
2484
2666
|
const names = new Set(own.map((s) => s.name));
|
|
2485
2667
|
return [...own, ...shared.filter((s) => !names.has(s.name))];
|
|
2486
2668
|
}
|
|
2487
|
-
_buildSystemMessage(sessionId, config, sessionOwnerKey = null) {
|
|
2669
|
+
_buildSystemMessage(sessionId, config, sessionOwnerKey = null, boundAgentCopy = resolveBoundAgentCopy(this.workerDefaults, config, sessionOwnerKey) ?? null) {
|
|
2488
2670
|
const frameworkBase = this.workerDefaults.frameworkBasePrompt ?? this.workerDefaults.systemMessage;
|
|
2489
2671
|
const boundAgentName = config.boundAgentName;
|
|
2490
2672
|
const layerKind = config.promptLayering?.kind ?? (boundAgentName ? "app-agent" : undefined);
|
|
2491
2673
|
const knowledgeToolInstructions = this._buildKnowledgeToolInstructionsSection(sessionId, config.agentIdentity);
|
|
2492
|
-
const lastInstructions = this._buildLastInstructionsSection(sessionId, config);
|
|
2674
|
+
const lastInstructions = this._buildLastInstructionsSection(sessionId, config, boundAgentCopy);
|
|
2493
2675
|
const additionalSections = knowledgeToolInstructions
|
|
2494
2676
|
? { tool_instructions: knowledgeToolInstructions, last_instructions: lastInstructions }
|
|
2495
2677
|
: { last_instructions: lastInstructions };
|
|
2496
2678
|
const isPilotSwarmSystemAgent = layerKind === "pilotswarm-system-agent";
|
|
2497
|
-
const layerManifest = buildEffectivePromptLayers(this.workerDefaults, config, sessionOwnerKey);
|
|
2679
|
+
const layerManifest = buildEffectivePromptLayers(this.workerDefaults, config, sessionOwnerKey, boundAgentCopy);
|
|
2498
2680
|
return composeStructuredSystemMessage({
|
|
2499
2681
|
frameworkBase,
|
|
2500
2682
|
appDefault: isPilotSwarmSystemAgent
|