@salesforce/sfdx-agent-harness-openai 0.0.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 +37 -0
- package/LICENSE.txt +21 -0
- package/README.md +55 -0
- package/dist/gen-sink.d.ts +8 -0
- package/dist/gen-sink.js +13 -0
- package/dist/gen-sink.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-error-classifier.d.ts +36 -0
- package/dist/mcp-error-classifier.js +166 -0
- package/dist/mcp-error-classifier.js.map +1 -0
- package/dist/openai-agents-harness-factory.d.ts +36 -0
- package/dist/openai-agents-harness-factory.js +39 -0
- package/dist/openai-agents-harness-factory.js.map +1 -0
- package/dist/openai-agents-harness.d.ts +302 -0
- package/dist/openai-agents-harness.js +1014 -0
- package/dist/openai-agents-harness.js.map +1 -0
- package/dist/openai-approval-coordinator.d.ts +231 -0
- package/dist/openai-approval-coordinator.js +422 -0
- package/dist/openai-approval-coordinator.js.map +1 -0
- package/dist/openai-built-in-policies.d.ts +29 -0
- package/dist/openai-built-in-policies.js +33 -0
- package/dist/openai-built-in-policies.js.map +1 -0
- package/dist/openai-event-adapter.d.ts +119 -0
- package/dist/openai-event-adapter.js +322 -0
- package/dist/openai-event-adapter.js.map +1 -0
- package/dist/openai-mcp-config-mapper.d.ts +58 -0
- package/dist/openai-mcp-config-mapper.js +133 -0
- package/dist/openai-mcp-config-mapper.js.map +1 -0
- package/dist/openai-mcp-state.d.ts +67 -0
- package/dist/openai-mcp-state.js +6 -0
- package/dist/openai-mcp-state.js.map +1 -0
- package/dist/openai-message-mapper.d.ts +79 -0
- package/dist/openai-message-mapper.js +374 -0
- package/dist/openai-message-mapper.js.map +1 -0
- package/dist/openai-model-provider.d.ts +46 -0
- package/dist/openai-model-provider.js +144 -0
- package/dist/openai-model-provider.js.map +1 -0
- package/dist/openai-session-store.d.ts +149 -0
- package/dist/openai-session-store.js +328 -0
- package/dist/openai-session-store.js.map +1 -0
- package/dist/openai-tool-mapper.d.ts +121 -0
- package/dist/openai-tool-mapper.js +231 -0
- package/dist/openai-tool-mapper.js.map +1 -0
- package/dist/openai-tool-redaction.d.ts +55 -0
- package/dist/openai-tool-redaction.js +82 -0
- package/dist/openai-tool-redaction.js.map +1 -0
- package/dist/test/tsconfig.tsbuildinfo +1 -0
- package/dist/text-stream.d.ts +30 -0
- package/dist/text-stream.js +103 -0
- package/dist/text-stream.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { type Clock, type LogRecord, type Unsubscribe, type UniqueIDGenerator } from '@salesforce/agentic-common';
|
|
2
|
+
import { type MCPServer, type ModelProvider } from '@openai/agents';
|
|
3
|
+
import { type ChatStreamResult, type HarnessAgentConfig, type MCPConfiguration, type McpServerInfo, type Message, type MessagePart, type ModelConnectivityInfo, type StreamOptions, type TelemetryEventCallback, type ToolResultInfo, type WithAgentConfig, type WireCommunicationEventCallback } from '@salesforce/sfdx-agent-sdk';
|
|
4
|
+
import type { AgentHarness } from '@salesforce/sfdx-agent-sdk';
|
|
5
|
+
import type { AgentHooks } from '@salesforce/sfdx-agent-sdk';
|
|
6
|
+
/**
|
|
7
|
+
* The branded harness subtype consumers see when they pass
|
|
8
|
+
* `OpenAIAgentsHarnessFactory` to `createAgentManager`. The harness ships no
|
|
9
|
+
* config extensions, so the config type stays the base `HarnessAgentConfig`.
|
|
10
|
+
*/
|
|
11
|
+
export type OpenAIAgentsAgentHarness = WithAgentConfig<AgentHarness & {
|
|
12
|
+
readonly harnessId: 'openai-agents';
|
|
13
|
+
readonly extensions: Record<string, never>;
|
|
14
|
+
}, HarnessAgentConfig>;
|
|
15
|
+
/** Internal constructor options (test seam; not part of the public surface). */
|
|
16
|
+
export type OpenAIAgentsHarnessOptions = {
|
|
17
|
+
/** Proxy-aware inner fetch (honors HTTPS_PROXY / NO_PROXY). */
|
|
18
|
+
innerFetch?: typeof fetch;
|
|
19
|
+
/** ID generator for thread ids; defaults to `UUIDGenerator`. */
|
|
20
|
+
idGenerator?: UniqueIDGenerator;
|
|
21
|
+
/** Time source for `createdAt` stamping; defaults to `RealClock`. */
|
|
22
|
+
clock?: Clock;
|
|
23
|
+
/**
|
|
24
|
+
* Builds the `@openai/agents` model provider for an agent. Defaults to the
|
|
25
|
+
* gateway-bound {@link buildOpenAIModelProvider}. Unit tests pass a factory
|
|
26
|
+
* returning a scripted-`Model` provider so the real run loop executes with
|
|
27
|
+
* no network and no credentials.
|
|
28
|
+
*/
|
|
29
|
+
modelProviderFactory?: (getInfo: () => ModelConnectivityInfo) => ModelProvider;
|
|
30
|
+
/**
|
|
31
|
+
* Builds the live `@openai/agents` MCP server instances for a config.
|
|
32
|
+
* Defaults to {@link mapToOpenAIMcpServers}. Unit tests pass a factory
|
|
33
|
+
* returning fake `MCPServer`s so MCP discovery / lifecycle / preservation
|
|
34
|
+
* can be exercised with no subprocess and no network (mirrors
|
|
35
|
+
* {@link modelProviderFactory}).
|
|
36
|
+
*/
|
|
37
|
+
mcpServerFactory?: (config: MCPConfiguration, orgJwt?: HarnessAgentConfig['orgJwt']) => Map<string, MCPServer>;
|
|
38
|
+
/**
|
|
39
|
+
* Per-`toolCallId` tool-approval timeout, in milliseconds, forwarded to each
|
|
40
|
+
* turn's `OpenAIApprovalCoordinator`. Defaults to the coordinator's own
|
|
41
|
+
* 600_000 ms when unset. Threaded from `OpenAIAgentsHarnessFactoryConfig`.
|
|
42
|
+
*/
|
|
43
|
+
toolApprovalTimeoutMs?: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* OpenAI Agents SDK-backed implementation of the SDK's `AgentHarness` contract.
|
|
47
|
+
*
|
|
48
|
+
* Implements connectivity, streamed turns, disk-backed sessions, thread
|
|
49
|
+
* lifecycle, message history (with `createdAt`/`isError` persistence), tool
|
|
50
|
+
* approval (`approveToolCall` / `declineToolCall`), consumer-executed tools
|
|
51
|
+
* (`submitToolResult`), MCP server lifecycle (`getMcpServerInfo` /
|
|
52
|
+
* `reconnectMcpServer` / `updateAgent` preservation), and thread compaction
|
|
53
|
+
* (`compactThread`). A per-`(agentId, threadId)` {@link OpenAIApprovalCoordinator}
|
|
54
|
+
* owns each turn's run loop, the approval suspend/resume flow, the opt-in policy
|
|
55
|
+
* gate, the per-`toolCallId` timeout, and the consumer-tool parker.
|
|
56
|
+
*
|
|
57
|
+
* MCP tools attach via the SDK's native `Agent({ mcpServers })` path and are
|
|
58
|
+
* observable (`tool-call` / `tool-result`, enriched with `serverName` /
|
|
59
|
+
* `bareToolName`) but are NOT approval-gated this milestone — the native attach
|
|
60
|
+
* exposes no per-tool `needsApproval` hook, so gating is a deferred follow-up.
|
|
61
|
+
* MCP discovery/status telemetry and wire-communication events emit on their
|
|
62
|
+
* respective seams, and the `options.hooks.onToolResult` redaction hook fires
|
|
63
|
+
* per tool result (consumer tools at the parked `execute`; MCP tools via a
|
|
64
|
+
* `getAllMcpTools` materialize-and-wrap when a redactor is set). Every
|
|
65
|
+
* agent-scoped method throws `AGENT_NOT_FOUND` on an unregistered id first (SDK
|
|
66
|
+
* invariant).
|
|
67
|
+
*/
|
|
68
|
+
export declare class OpenAIAgentsHarness implements OpenAIAgentsAgentHarness {
|
|
69
|
+
private readonly storageRootFolder;
|
|
70
|
+
readonly harnessId: "openai-agents";
|
|
71
|
+
readonly protocolVersion: 1;
|
|
72
|
+
readonly extensions: Record<string, never>;
|
|
73
|
+
private readonly buses;
|
|
74
|
+
private readonly agents;
|
|
75
|
+
private readonly idGenerator;
|
|
76
|
+
private readonly clock;
|
|
77
|
+
private readonly innerFetch?;
|
|
78
|
+
private readonly modelProviderFactory;
|
|
79
|
+
private readonly mcpServerFactory;
|
|
80
|
+
private readonly sessions;
|
|
81
|
+
private readonly toolApprovalTimeoutMs?;
|
|
82
|
+
private shuttingDown;
|
|
83
|
+
constructor(storageRootFolder: string, options?: OpenAIAgentsHarnessOptions);
|
|
84
|
+
onTelemetry(callback: TelemetryEventCallback): Unsubscribe;
|
|
85
|
+
onLog(callback: (record: LogRecord) => void): Unsubscribe;
|
|
86
|
+
onWireCommunication(callback: WireCommunicationEventCallback): Unsubscribe;
|
|
87
|
+
shutdown(): Promise<void>;
|
|
88
|
+
createAgent(agentId: string, projectRoot: string, modelConnectivityInfo: ModelConnectivityInfo, config?: HarnessAgentConfig, options?: {
|
|
89
|
+
abortSignal?: AbortSignal;
|
|
90
|
+
hooks?: AgentHooks;
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
destroyAgent(agentId: string): Promise<boolean>;
|
|
93
|
+
getAgentIds(): Promise<string[]>;
|
|
94
|
+
createThread(agentId: string, threadId?: string): Promise<string>;
|
|
95
|
+
getThreadIds(agentId: string): Promise<string[]>;
|
|
96
|
+
destroyThread(agentId: string, threadId: string): Promise<void>;
|
|
97
|
+
cloneThread(agentId: string, sourceThreadId: string): Promise<string>;
|
|
98
|
+
stream(agentId: string, threadId: string, message: string | MessagePart[], options?: StreamOptions): Promise<ChatStreamResult>;
|
|
99
|
+
getMessages(agentId: string, threadId: string): Promise<Message[]>;
|
|
100
|
+
clearMessages(agentId: string, threadId: string): Promise<void>;
|
|
101
|
+
addContext(agentId: string, threadId: string, messages: Message[]): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Apply a new connectivity bag + config to a live agent, preserving any MCP
|
|
104
|
+
* client whose config is structurally unchanged (#541) and cycling only the
|
|
105
|
+
* changed/added/removed servers. No eager `Agent` rebuild is needed: this
|
|
106
|
+
* harness constructs a fresh `Agent` on every `stream()` (see
|
|
107
|
+
* {@link buildAgent}) reading `state.config` / `state.modelConnectivityInfo`
|
|
108
|
+
* / `state.mcpServers` live, so mutating state here is sufficient — the next
|
|
109
|
+
* turn picks up the change. Does NOT dispose in-flight coordinators, touch
|
|
110
|
+
* sessions, or persist (persistence is the SDK's responsibility).
|
|
111
|
+
*/
|
|
112
|
+
updateAgent(agentId: string, modelConnectivityInfo: ModelConnectivityInfo, config?: HarnessAgentConfig, options?: {
|
|
113
|
+
abortSignal?: AbortSignal;
|
|
114
|
+
hooks?: AgentHooks;
|
|
115
|
+
}): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Synchronous snapshot of the agent's MCP servers: connected servers with
|
|
118
|
+
* their discovered tools, errored servers with a sanitized message +
|
|
119
|
+
* structured `errorDetail`, in-flight servers as `Connecting` /
|
|
120
|
+
* `Reconnecting`, and configured-but-disabled servers (never constructed) as
|
|
121
|
+
* `Disabled`. Status is updated asynchronously by background discovery, so a
|
|
122
|
+
* caller polls this to observe a `createAgent` / `reconnectMcpServer` result.
|
|
123
|
+
*/
|
|
124
|
+
getMcpServerInfo(agentId: string): McpServerInfo[];
|
|
125
|
+
/**
|
|
126
|
+
* Cycle one MCP server's transport and re-discover its tools. Eager: awaits
|
|
127
|
+
* the close → connect → `invalidateToolsCache` → `listTools` round-trip, but
|
|
128
|
+
* a transient transport / discovery failure is recorded on per-server state
|
|
129
|
+
* (surfaced via `getMcpServerInfo`) rather than rejected — only the three
|
|
130
|
+
* programming errors throw. `getAgentOrThrow` runs first (AGENT_NOT_FOUND
|
|
131
|
+
* wins), then an unconfigured server throws `MCP_SERVER_NOT_FOUND` and a
|
|
132
|
+
* disabled one `MCP_SERVER_DISABLED`.
|
|
133
|
+
*/
|
|
134
|
+
reconnectMcpServer(agentId: string, serverName: string): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Compact a thread's history into a fresh thread seeded with an LLM-generated
|
|
137
|
+
* summary, then destroy the source (the `AgentHarness` contract). The OpenAI
|
|
138
|
+
* Agents SDK ships a server-side `OpenAIResponsesCompactionAwareSession.runCompaction`
|
|
139
|
+
* (via `responses.compact`), but it relies on `previous_response_id` /
|
|
140
|
+
* stored responses — unavailable against the stateless Salesforce gateway
|
|
141
|
+
* (`store: false`, the same reason the coordinator pins `reasoningItemIdPolicy: 'omit'`).
|
|
142
|
+
* So this hand-rolls summarize+seed+destroy, mirroring the Mastra/Claude harnesses.
|
|
143
|
+
*
|
|
144
|
+
* `getAgentOrThrow` runs first (AGENT_NOT_FOUND). An empty source is compacted
|
|
145
|
+
* to a fresh empty thread (leaving it attached would leak). A summarization or
|
|
146
|
+
* seed failure surfaces as `AgentSDKError(COMPACTION_FAILED)` with the source
|
|
147
|
+
* left intact; the source is destroyed best-effort only after the new thread
|
|
148
|
+
* is safely seeded.
|
|
149
|
+
*/
|
|
150
|
+
compactThread(agentId: string, threadId: string): Promise<string>;
|
|
151
|
+
/**
|
|
152
|
+
* Feed a consumer-executed tool's result back into the thread's in-flight
|
|
153
|
+
* turn. `getAgentOrThrow` runs FIRST (AGENT_NOT_FOUND wins over the
|
|
154
|
+
* coordinator lookup, per the SDK invariant); a thread with no in-flight
|
|
155
|
+
* coordinator throws `TOOL_CALL_NOT_FOUND`. The coordinator resolves the
|
|
156
|
+
* parked `execute` keyed by `toolCallId`, the run continues on the SAME
|
|
157
|
+
* eventStream the consumer is already iterating, and idempotency (#589) is
|
|
158
|
+
* owned downstream. `error` rides through as an error-shaped outcome so a
|
|
159
|
+
* consumer-reported failure reaches the tool call.
|
|
160
|
+
*/
|
|
161
|
+
submitToolResult(agentId: string, threadId: string, toolResult: ToolResultInfo): Promise<void>;
|
|
162
|
+
approveToolCall(agentId: string, threadId: string, toolCallId: string): Promise<void>;
|
|
163
|
+
declineToolCall(agentId: string, threadId: string, toolCallId: string): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Forward an approve / decline to the thread's in-flight coordinator.
|
|
166
|
+
* `getAgentOrThrow` runs FIRST so an unregistered agent surfaces
|
|
167
|
+
* `AGENT_NOT_FOUND` (the SDK invariant: agent-registry check before the
|
|
168
|
+
* per-`(agentId, threadId)` coordinator lookup) — distinguishable from a
|
|
169
|
+
* registered agent with no in-flight run, which throws `TOOL_CALL_NOT_FOUND`.
|
|
170
|
+
* The coordinator owns idempotency (#589): a repeat / post-teardown settle is
|
|
171
|
+
* a silent no-op there. Post-resume events flow through the SAME eventStream
|
|
172
|
+
* the consumer is already iterating from `stream()`.
|
|
173
|
+
*/
|
|
174
|
+
private settleToolApproval;
|
|
175
|
+
/**
|
|
176
|
+
* Build the `@openai/agents` `Agent` + `Runner` a turn runs against. One seam
|
|
177
|
+
* for the pair so a `stream()` constructs them identically each turn. The
|
|
178
|
+
* `Runner` binds the agent's live `modelProvider` (JWT rotation lands per
|
|
179
|
+
* request) with tracing off. `tools` carries the turn's consumer-executed
|
|
180
|
+
* tools (mapped from `config.tools`).
|
|
181
|
+
*
|
|
182
|
+
* **MCP attach, two paths.** Without a redaction hook (`redaction`
|
|
183
|
+
* undefined — the common case), the agent's live MCP server instances attach
|
|
184
|
+
* via the native `mcpServers` field; the SDK fetches their tools per run.
|
|
185
|
+
* Because each instance has `cacheToolsList: true` (cache keyed by
|
|
186
|
+
* `server.name`) and this harness reuses the SAME connected instances across
|
|
187
|
+
* turns, a rebuilt `Agent` here does not re-run `tools/list` for a preserved
|
|
188
|
+
* server — the #541 preservation mechanic. MCP tools are NOT approval-gated
|
|
189
|
+
* this milestone (the native attach exposes no per-tool `needsApproval`).
|
|
190
|
+
*
|
|
191
|
+
* **When a redaction hook is set,** the native attach exposes no per-result
|
|
192
|
+
* rewrite seam, so MCP tools are materialized via `getAllMcpTools(...)` and
|
|
193
|
+
* their `invoke` wrapped with the redactor (see {@link buildRedactedMcpTools});
|
|
194
|
+
* they attach as `tools` rather than `mcpServers`. #541 is preserved because
|
|
195
|
+
* `getAllMcpTools` reads each server's warm `cacheToolsList` cache with no
|
|
196
|
+
* network `tools/list`. This makes the method async (the materialize awaits
|
|
197
|
+
* `listTools()`), so `stream()` awaits it.
|
|
198
|
+
*/
|
|
199
|
+
private buildAgent;
|
|
200
|
+
/**
|
|
201
|
+
* One-shot, non-agentic summarization for `compactThread`. Builds a throwaway
|
|
202
|
+
* `Agent` (summarization-role instructions, NO tools, NO MCP servers) bound to
|
|
203
|
+
* the agent's live `modelProvider`, and runs it non-streaming with no
|
|
204
|
+
* `session` (the summary call must not leak into the thread's persisted
|
|
205
|
+
* history). Returns the model's final text; throws if it produced none.
|
|
206
|
+
*
|
|
207
|
+
* `reasoningItemIdPolicy: 'omit'` is load-bearing for the same reason the
|
|
208
|
+
* turn coordinator pins it — the stateless gateway (`store: false`) rejects
|
|
209
|
+
* reasoning items sent by id reference.
|
|
210
|
+
*/
|
|
211
|
+
private summarize;
|
|
212
|
+
/**
|
|
213
|
+
* Two-pass summarization for transcripts above {@link MAX_TRANSCRIPT_CHARS}.
|
|
214
|
+
* Splits on line boundaries, summarizes each chunk, then summarizes the
|
|
215
|
+
* concatenated chunk-summaries (recursing if the merge itself is still over
|
|
216
|
+
* budget). Mirrors the sibling harnesses' map/reduce so cross-harness
|
|
217
|
+
* compaction behavior matches.
|
|
218
|
+
*/
|
|
219
|
+
private summarizeInChunks;
|
|
220
|
+
/**
|
|
221
|
+
* Best-effort `destroyThread`: swallows the error so `compactThread`'s outer
|
|
222
|
+
* flow isn't aborted by a teardown blip, but logs it at `warn` so a future
|
|
223
|
+
* `destroyThread` regression stays observable. Used on both the empty-source
|
|
224
|
+
* and non-empty compaction paths.
|
|
225
|
+
*/
|
|
226
|
+
private destroyThreadBestEffort;
|
|
227
|
+
/**
|
|
228
|
+
* Construct the agent's enabled MCP servers and kick off background discovery
|
|
229
|
+
* for each. Synchronous: it inserts every server entry (status `Connecting`)
|
|
230
|
+
* then assigns its background discovery promise to `entry.ready`, so
|
|
231
|
+
* `createAgent` / `updateAgent` never block on `connect()` / `listTools()`.
|
|
232
|
+
* A no-op when the config declares no enabled servers.
|
|
233
|
+
*/
|
|
234
|
+
private startMcpServers;
|
|
235
|
+
/**
|
|
236
|
+
* Connect + list tools for one MCP server, recording the outcome on
|
|
237
|
+
* per-server state and emitting the discovery telemetry triple
|
|
238
|
+
* (`started` → `completed` | `failed`) plus the terminal `status-changed`.
|
|
239
|
+
* Guards against an orphaned write by re-checking the server instance
|
|
240
|
+
* identity after each await — a superseded cycle replaces the entry with a
|
|
241
|
+
* fresh instance, so a stale discovery must neither clobber state nor emit
|
|
242
|
+
* (every terminal emit sits behind the `isCurrent()` guard). Discovery
|
|
243
|
+
* failure is recorded on state (status `Error`, sanitized message +
|
|
244
|
+
* structured detail) and never rethrown — matching the "failed server ≠
|
|
245
|
+
* failed create/reconnect" contract; an aborted run records the state but
|
|
246
|
+
* emits no `failed` telemetry.
|
|
247
|
+
*/
|
|
248
|
+
private runMcpDiscovery;
|
|
249
|
+
/**
|
|
250
|
+
* Emit an MCP telemetry event, swallowing only the typed `DISPOSED` error a
|
|
251
|
+
* post-`shutdown()` background discovery callback would hit (the bus is gone).
|
|
252
|
+
* Any other emit failure rethrows so a real regression surfaces. Every MCP
|
|
253
|
+
* emit is background / racing shutdown, so all route through here.
|
|
254
|
+
*/
|
|
255
|
+
private emitMcpTelemetry;
|
|
256
|
+
/**
|
|
257
|
+
* Flip a server's status synchronously and return a closure that emits the
|
|
258
|
+
* matching `mcp-server-status-changed` telemetry — or `undefined` when the
|
|
259
|
+
* status is unchanged (same-status transitions are deduped here so callers
|
|
260
|
+
* don't have to). Splitting the flip from the emit lets callers order the
|
|
261
|
+
* emit AFTER the discovery-terminal event (#373), while a synchronous reader
|
|
262
|
+
* of `getMcpServerInfo()` already sees the post-flip status.
|
|
263
|
+
*/
|
|
264
|
+
private prepareMcpStatusChange;
|
|
265
|
+
/**
|
|
266
|
+
* Diff the next MCP config against the applied one and preserve / cycle / add
|
|
267
|
+
* / remove servers accordingly. `mcpServerConfigEqual` (SDK-exported, uniform
|
|
268
|
+
* across harnesses) is the preserve predicate: an equal server is left
|
|
269
|
+
* completely untouched (its live instance + warm tool-list cache survive — no
|
|
270
|
+
* `close`, no `tools/list`, the #541 checkpoint). A changed / removed server
|
|
271
|
+
* is closed and dropped; a changed / added enabled server is constructed
|
|
272
|
+
* fresh and discovered in the background.
|
|
273
|
+
*/
|
|
274
|
+
private diffMcpServers;
|
|
275
|
+
/** Close every MCP server on an agent, awaiting in-flight discovery first. */
|
|
276
|
+
private closeMcpServers;
|
|
277
|
+
/** Rebuild the catalog entries for one server from its freshly-discovered tools. */
|
|
278
|
+
private refreshCatalogForServer;
|
|
279
|
+
/** Drop every catalog entry that points at `serverName`. */
|
|
280
|
+
private removeCatalogForServer;
|
|
281
|
+
/**
|
|
282
|
+
* Decide whether the tool-approval gate engages this turn and, if so, return
|
|
283
|
+
* the per-tool policy decider the coordinator consults. `undefined` ⇒ gate
|
|
284
|
+
* inactive; the coordinator suspends nothing and tools run free (the SDK's
|
|
285
|
+
* "no policy ⇒ no gating" back-compat invariant), avoiding a suspend/resume
|
|
286
|
+
* round-trip per call.
|
|
287
|
+
*
|
|
288
|
+
* Gating is **opt-in**: it engages only when the consumer set
|
|
289
|
+
* `config.toolPolicies` (non-empty) or `config.defaultToolDecision`. Whether
|
|
290
|
+
* the gate engaged is frozen at stream start (the closure is built iff gating
|
|
291
|
+
* is active now), but the closure itself reads `state.config` **live on every
|
|
292
|
+
* call** rather than a snapshot — a mid-turn `updateAgentConfig` (notably the
|
|
293
|
+
* `source: 'remember'` rule an "Allow always" click appends) reassigns
|
|
294
|
+
* `state.config` in place on this same `state` without disposing the in-flight
|
|
295
|
+
* coordinator, so a snapshot would leave approvals 2..N in that turn
|
|
296
|
+
* re-prompting even though the rule is persisted (#638). Reading live makes
|
|
297
|
+
* the remembered decision auto-resolve subsequent matching calls.
|
|
298
|
+
* `OPENAI_BUILT_IN_TOOL_POLICIES` is the `tiers.harness` slice (empty today).
|
|
299
|
+
*/
|
|
300
|
+
private buildPolicyGate;
|
|
301
|
+
private getAgentOrThrow;
|
|
302
|
+
}
|