@salesforce/sfdx-agent-sdk 0.52.0 → 0.53.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.
- package/CHANGELOG.md +5 -0
- package/README.md +61 -40
- package/dist/agent-manager.d.ts +7 -0
- package/dist/agent-manager.js +15 -3
- package/dist/agent.d.ts +55 -2
- package/dist/agent.js +72 -4
- package/dist/harness/harness-config.d.ts +37 -0
- package/dist/index.d.ts +1 -1
- package/dist/internal/agent-identity-store.d.ts +3 -1
- package/dist/internal/agent-identity-store.js +7 -3
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
All notable changes to `@salesforce/sfdx-agent-sdk` are documented in this file.
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
5
|
|
|
6
|
+
## [0.53.0] - 2026-08-24
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
- **agent-sdk**: persist per-agent consumer metadata for governed PATCH @W-23972709@ ([#760](https://github.com/forcedotcom/agentic-dx/pull/760))
|
|
10
|
+
|
|
6
11
|
## [0.52.0] - 2026-08-24
|
|
7
12
|
|
|
8
13
|
### Features
|
package/README.md
CHANGED
|
@@ -102,18 +102,18 @@ through a typed `manager.extensions` slot. `createAgentManager` infers `H` from
|
|
|
102
102
|
explicitly. The `createAgent` config parameter narrows automatically when the harness brands itself with
|
|
103
103
|
`WithAgentConfig` — see "Harness Extensibility" below.
|
|
104
104
|
|
|
105
|
-
| Property / Method | Signature
|
|
106
|
-
| --------------------- |
|
|
107
|
-
| `extensions` | `H['extensions']`
|
|
108
|
-
| `createAgent` | `(projectRoot: string, config?: ConfigOf<H> & { agentId?: string }, options?: { abortSignal?: AbortSignal }) => Promise<Agent<H>>` | Create and register a new agent and persist its identity triple. `projectRoot` must be an existing directory. If `agentId` is omitted a UUID is generated. The config type is inferred from the harness — see `ConfigOf<H>`.
|
|
109
|
-
| `getAgent` | `(agentId: string) => Agent<H>`
|
|
110
|
-
| `getAgentIds` | `() => string[]`
|
|
111
|
-
| `destroyAgent` | `(agentId: string) => Promise<void>`
|
|
112
|
-
| `shutdown` | `() => Promise<void>`
|
|
113
|
-
| `onTelemetry` | `(callback: TelemetryEventCallback) => Unsubscribe`
|
|
114
|
-
| `onLog` | `(callback: (record: LogRecord) => void) => Unsubscribe`
|
|
115
|
-
| `onWireCommunication` | `(callback: WireCommunicationEventCallback) => Unsubscribe`
|
|
116
|
-
| `getRestoreFailures` | `() => RestoreFailure[]`
|
|
105
|
+
| Property / Method | Signature | Description |
|
|
106
|
+
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
107
|
+
| `extensions` | `H['extensions']` | Harness-specific extensions namespace (read-only). Re-exposes the harness's `extensions` slot typed off `H`. Per-agent accessors take the agent id as their first argument. The SDK never reads or interprets this — see "Harness Extensibility" below. |
|
|
108
|
+
| `createAgent` | `(projectRoot: string, config?: ConfigOf<H> & { agentId?: string }, options?: { abortSignal?: AbortSignal; consumerMetadata?: JsonValue }) => Promise<Agent<H>>` | Create and register a new agent and persist its identity triple. `projectRoot` must be an existing directory. If `agentId` is omitted a UUID is generated. The config type is inferred from the harness — see `ConfigOf<H>`. `options.consumerMetadata` seeds the agent's opaque consumer metadata in the same persistence write as the config (create and initial metadata land together); it is never forwarded to the harness. |
|
|
109
|
+
| `getAgent` | `(agentId: string) => Agent<H>` | Retrieve a live agent by ID. Throws `AgentSDKError` (`AGENT_NOT_FOUND`) for unknown ids and for ids that are only present in `getRestoreFailures()`. |
|
|
110
|
+
| `getAgentIds` | `() => string[]` | List all live agent IDs (successful + successfully restored). Failed-restore agents are not included — query `getRestoreFailures()` separately. |
|
|
111
|
+
| `destroyAgent` | `(agentId: string) => Promise<void>` | Destroy an agent, remove its identity record from disk, and clear any matching `getRestoreFailures()` entry. Failed-restore-only ids are accepted (no harness call made). |
|
|
112
|
+
| `shutdown` | `() => Promise<void>` | Destroy all live agents and shut down the harness. Identity files survive (that's the whole point) — restart `createAgentManager` over the same root to bring them back. |
|
|
113
|
+
| `onTelemetry` | `(callback: TelemetryEventCallback) => Unsubscribe` | Subscribe to telemetry across all managed agents. |
|
|
114
|
+
| `onLog` | `(callback: (record: LogRecord) => void) => Unsubscribe` | Subscribe to structured logs across all managed agents. Bridge this into your host logger to observe restore-failure events + soft-skip warnings. |
|
|
115
|
+
| `onWireCommunication` | `(callback: WireCommunicationEventCallback) => Unsubscribe` | Subscribe to wire-level communication events from the harness. Opt-in diagnostic channel that surfaces outbound LLM requests, responses, and harness-specific monitoring metadata. Subscriber-gated end-to-end — harnesses pay no cost when nobody listens. See "Wire-Communication Events" below for the event-shape catalog and the harness-asymmetric coverage (Mastra emits per-call request/response pairs; Claude emits a per-stream pointer to a debug log file). |
|
|
116
|
+
| `getRestoreFailures` | `() => RestoreFailure[]` | Snapshot of agents the SDK could not restore on this boot. Each entry carries the persisted `{ agentId, projectRoot, config }` plus the underlying error. |
|
|
117
117
|
|
|
118
118
|
#### `RestoreFailure`
|
|
119
119
|
|
|
@@ -136,24 +136,26 @@ A configured AI agent. Factory for chat sessions. The optional `H` type paramete
|
|
|
136
136
|
— harness-specific features are reached through `manager.extensions`, not `agent.extensions`. The default `AgentHarness`
|
|
137
137
|
keeps unparameterized call sites working.
|
|
138
138
|
|
|
139
|
-
| Method
|
|
140
|
-
|
|
|
141
|
-
| `getId`
|
|
142
|
-
| `getProjectRoot`
|
|
143
|
-
| `getOrgConnection`
|
|
144
|
-
| `getAgentConfig`
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
139
|
+
| Method | Signature | Description |
|
|
140
|
+
| --------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
141
|
+
| `getId` | `() => string` | Agent identifier. |
|
|
142
|
+
| `getProjectRoot` | `() => string` | Absolute project path. |
|
|
143
|
+
| `getOrgConnection` | `() => OrgConnection \| undefined` | The Salesforce `OrgConnection` resolved for this agent (or `undefined` if the connectivity resolver omitted it — non-Salesforce hosts on the BYOK / api-key path return `undefined`). |
|
|
144
|
+
| `getAgentConfig` | `() => AgentConfig` | Current configuration (shallow copy). |
|
|
145
|
+
| `getConsumerMetadata` | `() => JsonValue \| undefined` | Deep copy of the agent's SDK-owned opaque consumer metadata, or `undefined` if unset. Persisted beside the config; never forwarded to the harness and never on the wire. Set it via `updateAgentState`. |
|
|
146
|
+
| `getMcpServerInfo` | `() => McpServerInfo[]` | MCP server status and discovered tools. |
|
|
147
|
+
| `reconnectMcpServer` | `(serverName: string) => Promise<void>` | Recover one MCP server without recycling the agent. Semantics vary by harness — observe via `getMcpServerInfo()` and discovery telemetry. |
|
|
148
|
+
| `updateAgentConfig` | `(config?: AgentConfig, options?: { abortSignal?: AbortSignal; forceResolve?: boolean }) => Promise<void>` | Merge new config into the live agent. Pass `forceResolve: true` to re-run the connectivity resolver even when the partial config doesn't include `orgAlias` or `modelId` — for consumer-side state changes (BYOK toggle, feature-id flip, rate-limit gate) the resolver reads but the SDK can't observe directly. A thin wrapper over `updateAgentState({ config }, options)`. |
|
|
149
|
+
| `updateAgentState` | `(update: AgentStateUpdate, options?: { abortSignal?: AbortSignal; forceResolve?: boolean }) => Promise<void>` | Atomically apply a config partial and/or a consumer-metadata mutation. When both are present they commit in one persistence write, so a failed update leaves config and metadata at their previous values together. A metadata-only update never calls the harness. See `AgentStateUpdate` / `ConsumerMetadataMutation` below. |
|
|
150
|
+
| `createChatSession` | `() => Promise<ChatSession>` | Open a new conversation thread. |
|
|
151
|
+
| `getChatSession` | `(sessionId: string) => ChatSession` | Retrieve a session. Throws `AgentSDKError` (`CHAT_SESSION_NOT_FOUND`). |
|
|
152
|
+
| `getChatSessionIds` | `() => string[]` | List active session IDs. |
|
|
153
|
+
| `destroyChatSession` | `(sessionId: string) => Promise<void>` | Destroy a session and its history. |
|
|
154
|
+
| `cloneChatSession` | `(sourceSessionId: string) => Promise<ChatSession>` | Clone a session with its message history. |
|
|
155
|
+
| `compactChatSession` | `(sessionId: string) => Promise<ChatSession>` | Compact a session into a summarized new session. |
|
|
156
|
+
| `destroy` | `() => Promise<void>` | Destroy the agent and all its sessions. |
|
|
157
|
+
| `onTelemetry` | `(callback: TelemetryEventCallback) => Unsubscribe` | Subscribe to telemetry scoped to this agent (and its sessions). |
|
|
158
|
+
| `onLog` | `(callback: (record: LogRecord) => void) => Unsubscribe` | Subscribe to logs scoped to this agent (and its sessions). |
|
|
157
159
|
|
|
158
160
|
### `ChatSession`
|
|
159
161
|
|
|
@@ -280,6 +282,25 @@ telemetry for a service of your own.
|
|
|
280
282
|
| `toolPolicies?` | `ToolPolicyRule[]` | Ordered per-tool approval rules resolved by `resolveToolApprovalPolicy` (cross-tier deny-wins / within-tier last-wins). Author directly or via `definePolicy(...)`. See "Tool Approval Policy" below. |
|
|
281
283
|
| `defaultToolDecision?` | `Decision` | Fallback decision when no rule matches. Defaults to `'allow'` (no policy ⇒ no gating). Set to `'require-approval'` for a fail-closed posture (recommended for catalogs with un-annotated MCP servers). |
|
|
282
284
|
|
|
285
|
+
#### `AgentStateUpdate` and `ConsumerMetadataMutation`
|
|
286
|
+
|
|
287
|
+
Inputs to `Agent.updateAgentState`. Consumer metadata is SDK-owned opaque JSON persisted beside the agent config — it
|
|
288
|
+
never sits on `AgentConfig`, never reaches the harness, and never appears on the REST wire.
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
type ConsumerMetadataMutation = { action: 'replace'; value: JsonValue } | { action: 'clear' };
|
|
292
|
+
|
|
293
|
+
type AgentStateUpdate = {
|
|
294
|
+
config?: AgentConfig;
|
|
295
|
+
consumerMetadata?: ConsumerMetadataMutation;
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`replace` stores a deep copy of `value`; `clear` removes the metadata; omitting `consumerMetadata` leaves it unchanged.
|
|
300
|
+
When `update.config` is present, `updateAgentState` applies it to the harness exactly as `updateAgentConfig` does and
|
|
301
|
+
persists config plus metadata in one write; when it is absent, the update is metadata-only and never calls the harness.
|
|
302
|
+
`getConsumerMetadata()` reads the current value back as a deep copy.
|
|
303
|
+
|
|
283
304
|
#### `StreamOptions`
|
|
284
305
|
|
|
285
306
|
| Field | Type | Description |
|
|
@@ -403,14 +424,14 @@ const manager = await createAgentManager(storageRoot, harnessFactory, {
|
|
|
403
424
|
The harness forwards the provider into the underlying HTTP transport (`@modelcontextprotocol/sdk`'s
|
|
404
425
|
`StreamableHTTPClientTransport` on Claude / OpenAI, `@mastra/mcp`'s `HttpServerDefinition` on Mastra). The transport
|
|
405
426
|
attaches existing tokens and silently refreshes them when possible. If user interaction is required, it invokes the
|
|
406
|
-
provider's `redirectToAuthorization` callback and surfaces `McpServerErrorDetail.category === 'oauth-required'`;
|
|
407
|
-
|
|
427
|
+
provider's `redirectToAuthorization` callback and surfaces `McpServerErrorDetail.category === 'oauth-required'`; ADX
|
|
428
|
+
does not open a browser or accept the authorization callback code. The static `headers` seam cannot provide this
|
|
408
429
|
recovery because headers are snapshotted at publish time.
|
|
409
430
|
|
|
410
431
|
- **`McpOAuthClientProvider`** (exported) is a harness-neutral interface that structurally mirrors the required core of
|
|
411
432
|
the MCP SDK's `OAuthClientProvider`, so a real provider assigns to it with no cast and the SDK stays free of a direct
|
|
412
|
-
`@modelcontextprotocol/sdk` dependency. **`McpAuthProviders`** (exported) is the
|
|
413
|
-
McpOAuthClientProvider>>` the resolver returns.
|
|
433
|
+
`@modelcontextprotocol/sdk` dependency. **`McpAuthProviders`** (exported) is the
|
|
434
|
+
`Readonly<Record<serverName, McpOAuthClientProvider>>` the resolver returns.
|
|
414
435
|
- **One provider instance per server**, and return the **same** instance across calls — the upstream contract forbids
|
|
415
436
|
tokens / codes / verifiers crossing sessions, and a harness cycles a server when its provider reference changes (so
|
|
416
437
|
returning a fresh instance each update reconnects that server every time).
|
|
@@ -422,8 +443,8 @@ recovery because headers are snapshotted at publish time.
|
|
|
422
443
|
(no Salesforce JWT injected, `HTTPS_PROXY` preserved) while the provider drives auth.
|
|
423
444
|
|
|
424
445
|
> **Interactive authorization stays with the consumer.** AFV's provider owns the Sign in UI, browser, VS Code callback,
|
|
425
|
-
> and code exchange. After it saves the new tokens, call `Agent.reconnectMcpServer` to connect. ADX owns runtime
|
|
426
|
-
> forwarding and silent refresh only; the transport's `finishAuth(code)` seam is not part of the public API.
|
|
446
|
+
> and code exchange. After it saves the new tokens, call `Agent.reconnectMcpServer` to connect. ADX owns runtime
|
|
447
|
+
> provider forwarding and silent refresh only; the transport's `finishAuth(code)` seam is not part of the public API.
|
|
427
448
|
|
|
428
449
|
**Tool-exposure policy** (which tools bypass the active runtime's tool-search deferral) is configured per-agent on the
|
|
429
450
|
harness extension surface, not per-server here. See `MastraAgentConfig.toolSearch.alwaysActive` and
|
|
@@ -450,8 +471,8 @@ only `MCPRemoteServerConfig` carries it.
|
|
|
450
471
|
|
|
451
472
|
#### `McpServerErrorDetail`
|
|
452
473
|
|
|
453
|
-
Structured projection of an MCP server failure. Route interactive authorization on `category === 'oauth-required'`;
|
|
454
|
-
|
|
474
|
+
Structured projection of an MCP server failure. Route interactive authorization on `category === 'oauth-required'`; an
|
|
475
|
+
ordinary missing or invalid bearer remains `http-401`. The same detail is attached to `mcp-server-discovery-failed`
|
|
455
476
|
telemetry so subscribers can route on it without pattern-matching `error.message`.
|
|
456
477
|
|
|
457
478
|
| Field | Type | Description |
|
|
@@ -460,8 +481,8 @@ telemetry so subscribers can route on it without pattern-matching `error.message
|
|
|
460
481
|
| `code?` | `number` | JSON-RPC error code from the underlying `McpError`, when the failure originated as a JSON-RPC error. Undefined for transport-level failures and for harnesses whose underlying SDK does not surface the code (e.g. Claude). |
|
|
461
482
|
| `retriable` | `boolean` | Whether the SDK considers the failure transient (worth `Agent.reconnectMcpServer`) versus fatal. |
|
|
462
483
|
|
|
463
|
-
`McpServerErrorCategory` values: `'connect-timeout'`, `'oauth-required'`, `'http-401'`, `'http-403'`, `'http-4xx'`,
|
|
464
|
-
`'transport-eof'`, `'protocol-error'`, `'config-error'`, `'aborted'`, `'unknown'`.
|
|
484
|
+
`McpServerErrorCategory` values: `'connect-timeout'`, `'oauth-required'`, `'http-401'`, `'http-403'`, `'http-4xx'`,
|
|
485
|
+
`'http-5xx'`, `'transport-eof'`, `'protocol-error'`, `'config-error'`, `'aborted'`, `'unknown'`.
|
|
465
486
|
|
|
466
487
|
#### `McpToolInfo`
|
|
467
488
|
|
package/dist/agent-manager.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type Clock, LogBus, type LogRecord, type Unsubscribe, type UniqueIDGene
|
|
|
2
2
|
import { type AgentHarness, type ConfigOf } from './harness/agent-harness.js';
|
|
3
3
|
import type { HarnessFactory } from './harness/harness-factory.js';
|
|
4
4
|
import { type AgentConfig, type McpAuthProviderResolver } from './harness/harness-config.js';
|
|
5
|
+
import type { JsonValue } from './types/session-context.js';
|
|
5
6
|
import { type Agent, type AgentRuntimeResolvers } from './agent.js';
|
|
6
7
|
import type { HooksForAgent } from './types/redaction.js';
|
|
7
8
|
import { type TelemetryEventCallback } from './types/telemetry-events.js';
|
|
@@ -50,6 +51,10 @@ export interface AgentManager<H extends AgentHarness = AgentHarness> {
|
|
|
50
51
|
* without an explicit generic at the call site. Extra fields thread
|
|
51
52
|
* through opaquely to the harness, which narrows what it cares about.
|
|
52
53
|
*
|
|
54
|
+
* `options.consumerMetadata` seeds the agent's SDK-owned opaque consumer
|
|
55
|
+
* metadata, persisted in the same identity write as the config so create
|
|
56
|
+
* and initial metadata land together. It is never forwarded to the harness.
|
|
57
|
+
*
|
|
53
58
|
* @throws If `projectRoot` does not exist or is not a directory.
|
|
54
59
|
* @throws If `config.agentId` is provided and an agent with that ID is
|
|
55
60
|
* already registered (live or in restore-failure state).
|
|
@@ -58,6 +63,7 @@ export interface AgentManager<H extends AgentHarness = AgentHarness> {
|
|
|
58
63
|
agentId?: string;
|
|
59
64
|
}, options?: {
|
|
60
65
|
abortSignal?: AbortSignal;
|
|
66
|
+
consumerMetadata?: JsonValue;
|
|
61
67
|
}): Promise<Agent>;
|
|
62
68
|
/**
|
|
63
69
|
* Returns the live {@link Agent} for the given id.
|
|
@@ -168,6 +174,7 @@ export declare class DefaultAgentManager<H extends AgentHarness = AgentHarness>
|
|
|
168
174
|
agentId?: string;
|
|
169
175
|
}, options?: {
|
|
170
176
|
abortSignal?: AbortSignal;
|
|
177
|
+
consumerMetadata?: JsonValue;
|
|
171
178
|
}): Promise<Agent>;
|
|
172
179
|
/**
|
|
173
180
|
* Shared install path for {@link createAgent} and the boot-time restore
|
package/dist/agent-manager.js
CHANGED
|
@@ -89,6 +89,7 @@ export class DefaultAgentManager {
|
|
|
89
89
|
try {
|
|
90
90
|
await this.installAgent(record.agentId, record.projectRoot, record.config, {
|
|
91
91
|
rehydrateThreads: true,
|
|
92
|
+
consumerMetadata: record.consumerMetadata,
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
catch (err) {
|
|
@@ -131,19 +132,26 @@ export class DefaultAgentManager {
|
|
|
131
132
|
const resolvedProjectRoot = resolve(projectRoot);
|
|
132
133
|
const { agentId: providedAgentId, ...agentConfig } = config;
|
|
133
134
|
const agentId = providedAgentId ?? this.agentIdGenerator.getUniqueId();
|
|
135
|
+
const consumerMetadata = options?.consumerMetadata;
|
|
134
136
|
if (this.agents.has(agentId)) {
|
|
135
137
|
throw new Error(`Agent with id "${agentId}" already exists`);
|
|
136
138
|
}
|
|
137
139
|
// installAgent validates projectRoot existence — same path as the restore loop.
|
|
138
140
|
const agent = await this.installAgent(agentId, resolvedProjectRoot, agentConfig, {
|
|
139
141
|
abortSignal: options?.abortSignal,
|
|
142
|
+
consumerMetadata,
|
|
140
143
|
});
|
|
141
144
|
// If the disk write fails (disk full, permissions, fs error), the in-memory install
|
|
142
145
|
// is now stale — the harness has the agent, the manager has it in `agents`, but no
|
|
143
146
|
// record on disk means a subsequent restart loses it. Roll back the install so the
|
|
144
147
|
// failure is observable and the id stays reusable, then rethrow.
|
|
145
148
|
try {
|
|
146
|
-
|
|
149
|
+
if (consumerMetadata === undefined) {
|
|
150
|
+
await this.identityStore.write(agentId, resolvedProjectRoot, agentConfig);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
await this.identityStore.write(agentId, resolvedProjectRoot, agentConfig, consumerMetadata);
|
|
154
|
+
}
|
|
147
155
|
}
|
|
148
156
|
catch (err) {
|
|
149
157
|
await this.rollbackInstall(agentId, agent);
|
|
@@ -186,7 +194,11 @@ export class DefaultAgentManager {
|
|
|
186
194
|
}
|
|
187
195
|
const hooks = this.resolvers.hooksForAgent?.(agentId, config) ?? {};
|
|
188
196
|
const mcpAuthProviders = normalizeMcpAuthProviders(config.mcpServers, this.resolvers.mcpAuthProviderResolver?.(agentId, config));
|
|
189
|
-
await this.harness.createAgent(agentId, projectRoot, runtime.modelConnectivityInfo, toHarnessConfig(config, runtime.orgJwt), {
|
|
197
|
+
await this.harness.createAgent(agentId, projectRoot, runtime.modelConnectivityInfo, toHarnessConfig(config, runtime.orgJwt), {
|
|
198
|
+
...(options.abortSignal !== undefined ? { abortSignal: options.abortSignal } : {}),
|
|
199
|
+
hooks,
|
|
200
|
+
mcpAuthProviders,
|
|
201
|
+
});
|
|
190
202
|
const agentSlice = this.router.registerAgent(agentId);
|
|
191
203
|
// Forward-compat: register the agent against the wire-communication router
|
|
192
204
|
// too. Today every WireCommunicationEvent lands on the unrouted slice (no
|
|
@@ -194,7 +206,7 @@ export class DefaultAgentManager {
|
|
|
194
206
|
// symmetrically with the telemetry router so the wiring is in place if/when
|
|
195
207
|
// the event shape grows an agentId field.
|
|
196
208
|
this.wireRouter.registerAgent(agentId);
|
|
197
|
-
const agent = new DefaultAgent(this.harness, agentId, projectRoot, config, runtime.modelConnectivityInfo, runtime.orgConnection, runtime.orgJwt, this.agentConnectivityResolver, this.harnessSupportedProviderHints, this.resolvers, this.identityStore, this.router, agentSlice, { telemetry: this.telemetryBus, log: this.logBus }, this.clock, this.agentIdGenerator);
|
|
209
|
+
const agent = new DefaultAgent(this.harness, agentId, projectRoot, config, options.consumerMetadata, runtime.modelConnectivityInfo, runtime.orgConnection, runtime.orgJwt, this.agentConnectivityResolver, this.harnessSupportedProviderHints, this.resolvers, this.identityStore, this.router, agentSlice, { telemetry: this.telemetryBus, log: this.logBus }, this.clock, this.agentIdGenerator);
|
|
198
210
|
this.agents.set(agentId, agent);
|
|
199
211
|
const agentCreatedAt = this.clock.now();
|
|
200
212
|
const modelName = runtime.modelConnectivityInfo.model.name;
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type Clock, type JSONWebToken, LogBus, type LogRecord, type OrgConnection, type UniqueIDGenerator, type Unsubscribe } from '@salesforce/agentic-common';
|
|
2
2
|
import type { AgentHarness } from './harness/agent-harness.js';
|
|
3
|
-
import { type AgentConfig, type McpAuthProviderResolver } from './harness/harness-config.js';
|
|
3
|
+
import { type AgentConfig, type AgentStateUpdate, type McpAuthProviderResolver } from './harness/harness-config.js';
|
|
4
4
|
import { type ChatSession } from './chat-session.js';
|
|
5
|
+
import type { JsonValue } from './types/session-context.js';
|
|
5
6
|
import type { McpServerInfo } from './mcp-config.js';
|
|
6
7
|
import type { AgentConnectivityResolver } from './agent-connectivity-resolver.js';
|
|
7
8
|
import type { ModelConnectivityInfo, ProviderHint } from './types/model-connectivity-info.js';
|
|
@@ -40,6 +41,13 @@ export interface Agent {
|
|
|
40
41
|
getOrgConnection(): OrgConnection | undefined;
|
|
41
42
|
/** Returns the current agent configuration. */
|
|
42
43
|
getAgentConfig(): AgentConfig;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a deep copy of the agent's persisted consumer metadata, or
|
|
46
|
+
* `undefined` if none has been set. This is SDK-owned opaque JSON: it is
|
|
47
|
+
* never placed on {@link AgentConfig}, never forwarded to the harness, and
|
|
48
|
+
* never appears on the REST wire. Set it via {@link updateAgentState}.
|
|
49
|
+
*/
|
|
50
|
+
getConsumerMetadata(): JsonValue | undefined;
|
|
43
51
|
/**
|
|
44
52
|
* Returns runtime information about MCP servers attached to this agent,
|
|
45
53
|
* including connection status and discovered tool names. This is a synchronous
|
|
@@ -97,6 +105,21 @@ export interface Agent {
|
|
|
97
105
|
abortSignal?: AbortSignal;
|
|
98
106
|
forceResolve?: boolean;
|
|
99
107
|
}): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Atomically update the agent's configuration and/or its persisted consumer
|
|
110
|
+
* metadata. `update.config` is merged and applied to the harness exactly as
|
|
111
|
+
* {@link updateAgentConfig} does; `update.consumerMetadata` mutates the
|
|
112
|
+
* SDK-owned opaque metadata. When both are present they commit in one
|
|
113
|
+
* persistence write, so a failed update leaves config and metadata at their
|
|
114
|
+
* previous values together. A metadata-only update never calls the harness.
|
|
115
|
+
*
|
|
116
|
+
* @param update - The config partial and/or consumer-metadata mutation to apply.
|
|
117
|
+
* @param options - Same execution options as {@link updateAgentConfig}.
|
|
118
|
+
*/
|
|
119
|
+
updateAgentState(update: AgentStateUpdate, options?: {
|
|
120
|
+
abortSignal?: AbortSignal;
|
|
121
|
+
forceResolve?: boolean;
|
|
122
|
+
}): Promise<void>;
|
|
100
123
|
/**
|
|
101
124
|
* Create a new chat session (conversation thread) for this agent.
|
|
102
125
|
* @returns A new {@link ChatSession} with a unique thread ID.
|
|
@@ -162,6 +185,7 @@ export declare class DefaultAgent implements Agent {
|
|
|
162
185
|
private readonly agentId;
|
|
163
186
|
private readonly projectRoot;
|
|
164
187
|
private config;
|
|
188
|
+
private consumerMetadata;
|
|
165
189
|
private modelConnectivityInfo;
|
|
166
190
|
private orgConnection;
|
|
167
191
|
private orgJwt;
|
|
@@ -184,6 +208,8 @@ export declare class DefaultAgent implements Agent {
|
|
|
184
208
|
* @param agentId - Unique identifier for this agent.
|
|
185
209
|
* @param projectRoot - Project folder this agent is allowed to operate within.
|
|
186
210
|
* @param config - Initial agent configuration (instructions, model, tools, etc.).
|
|
211
|
+
* @param consumerMetadata - Initial SDK-owned opaque consumer metadata (or `undefined`). Persisted beside
|
|
212
|
+
* `config`; never forwarded to the harness. Mutated via `updateAgentState`.
|
|
187
213
|
* @param modelConnectivityInfo - Connectivity bag (model, baseUrl, nativeModelId,
|
|
188
214
|
* providerHint, getHeaders) the harness uses to talk to the LLM. Replaced
|
|
189
215
|
* on every `updateAgentConfig` re-resolve.
|
|
@@ -201,7 +227,7 @@ export declare class DefaultAgent implements Agent {
|
|
|
201
227
|
* @param inbound - Router slice delivering harness events routed to this agent (non-session-scoped).
|
|
202
228
|
* @param parent - Manager's bus pair; this agent forwards its events upward into them.
|
|
203
229
|
*/
|
|
204
|
-
constructor(harness: AgentHarness, agentId: string, projectRoot: string, config: AgentConfig, modelConnectivityInfo: ModelConnectivityInfo, orgConnection: OrgConnection | undefined, orgJwt: JSONWebToken | undefined, agentConnectivityResolver: AgentConnectivityResolver, harnessSupportedProviderHints: readonly ProviderHint[], resolvers: AgentRuntimeResolvers, identityStore: AgentIdentityStore, router: TelemetryRouter, inbound: TelemetrySlice, parent: AgentParentBuses, clock?: Clock, idGenerator?: UniqueIDGenerator);
|
|
230
|
+
constructor(harness: AgentHarness, agentId: string, projectRoot: string, config: AgentConfig, consumerMetadata: JsonValue | undefined, modelConnectivityInfo: ModelConnectivityInfo, orgConnection: OrgConnection | undefined, orgJwt: JSONWebToken | undefined, agentConnectivityResolver: AgentConnectivityResolver, harnessSupportedProviderHints: readonly ProviderHint[], resolvers: AgentRuntimeResolvers, identityStore: AgentIdentityStore, router: TelemetryRouter, inbound: TelemetrySlice, parent: AgentParentBuses, clock?: Clock, idGenerator?: UniqueIDGenerator);
|
|
205
231
|
/**
|
|
206
232
|
* @requirements
|
|
207
233
|
* - MUST return the agent's ID.
|
|
@@ -215,6 +241,12 @@ export declare class DefaultAgent implements Agent {
|
|
|
215
241
|
* - MUST return a shallow copy of the internal `config` object to prevent external mutation of the agent's state.
|
|
216
242
|
*/
|
|
217
243
|
getAgentConfig(): AgentConfig;
|
|
244
|
+
/**
|
|
245
|
+
* @requirements
|
|
246
|
+
* - MUST return a deep copy so a caller cannot mutate the agent's persisted consumer metadata in place.
|
|
247
|
+
* - MUST return `undefined` when no metadata has been set.
|
|
248
|
+
*/
|
|
249
|
+
getConsumerMetadata(): JsonValue | undefined;
|
|
218
250
|
getMcpServerInfo(): McpServerInfo[];
|
|
219
251
|
reconnectMcpServer(serverName: string): Promise<void>;
|
|
220
252
|
/**
|
|
@@ -237,6 +269,27 @@ export declare class DefaultAgent implements Agent {
|
|
|
237
269
|
abortSignal?: AbortSignal;
|
|
238
270
|
forceResolve?: boolean;
|
|
239
271
|
}): Promise<void>;
|
|
272
|
+
/**
|
|
273
|
+
* @requirements
|
|
274
|
+
* - MUST merge `update.config` (when present) with the internal `config` object; `agentId` stays unchanged.
|
|
275
|
+
* - MUST apply the merged config to the harness via `this.harness.updateAgent(...)` ONLY when `update.config`
|
|
276
|
+
* is present. A metadata-only update MUST NOT call the harness at all (no server cycling, no resolver run).
|
|
277
|
+
* - MUST compute the next consumer metadata from `update.consumerMetadata`: `replace` stores a deep copy of the
|
|
278
|
+
* value; `clear` removes it; an absent mutation leaves it unchanged.
|
|
279
|
+
* - MUST persist config + metadata together in ONE `this.identityStore.write(...)` after any `harness.updateAgent`
|
|
280
|
+
* succeeds and before the in-memory swaps, so a write failure rolls back through the same catch path.
|
|
281
|
+
* - MUST preserve BOTH the previous config AND the previous metadata if `updateAgent` or persistence fails.
|
|
282
|
+
*/
|
|
283
|
+
updateAgentState(update: AgentStateUpdate, options?: {
|
|
284
|
+
abortSignal?: AbortSignal;
|
|
285
|
+
forceResolve?: boolean;
|
|
286
|
+
}): Promise<void>;
|
|
287
|
+
/**
|
|
288
|
+
* Writes the identity record, calling `identityStore.write` with a 4th argument only when consumer metadata is
|
|
289
|
+
* present. Omitting the argument (rather than passing `undefined`) keeps a config-only write byte-identical to the
|
|
290
|
+
* pre-metadata call shape and clears any previously-persisted metadata.
|
|
291
|
+
*/
|
|
292
|
+
private writeIdentity;
|
|
240
293
|
/**
|
|
241
294
|
* @requirements
|
|
242
295
|
* - MUST delegate to `this.harness.createThread(this.config.agentId)` to generate a new thread ID.
|
package/dist/agent.js
CHANGED
|
@@ -3,11 +3,22 @@
|
|
|
3
3
|
* See LICENSE.txt for license terms.
|
|
4
4
|
*/
|
|
5
5
|
import { LogBus, RealClock, UUIDGenerator, } from '@salesforce/agentic-common';
|
|
6
|
-
import { toHarnessConfig } from './harness/harness-config.js';
|
|
6
|
+
import { toHarnessConfig, } from './harness/harness-config.js';
|
|
7
7
|
import { normalizeMcpAuthProviders } from './mcp-auth.js';
|
|
8
8
|
import { DefaultChatSession } from './chat-session.js';
|
|
9
9
|
import { AgentSDKError, AgentSDKErrorType } from './errors.js';
|
|
10
10
|
import { createTelemetryBus } from './types/telemetry-events.js';
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the next consumer-metadata value from the current value and an optional mutation. `replace` deep-clones the
|
|
13
|
+
* incoming value so the stored copy is isolated from later caller mutation; `clear` yields `undefined`; an absent
|
|
14
|
+
* mutation leaves the current value untouched.
|
|
15
|
+
*/
|
|
16
|
+
function applyConsumerMetadataMutation(current, mutation) {
|
|
17
|
+
if (mutation === undefined) {
|
|
18
|
+
return current;
|
|
19
|
+
}
|
|
20
|
+
return mutation.action === 'replace' ? structuredClone(mutation.value) : undefined;
|
|
21
|
+
}
|
|
11
22
|
/**
|
|
12
23
|
* Default implementation of {@link Agent} that delegates
|
|
13
24
|
* agent and thread operations to an {@link AgentHarness}.
|
|
@@ -17,6 +28,7 @@ export class DefaultAgent {
|
|
|
17
28
|
agentId;
|
|
18
29
|
projectRoot;
|
|
19
30
|
config;
|
|
31
|
+
consumerMetadata;
|
|
20
32
|
modelConnectivityInfo;
|
|
21
33
|
orgConnection;
|
|
22
34
|
orgJwt;
|
|
@@ -41,6 +53,8 @@ export class DefaultAgent {
|
|
|
41
53
|
* @param agentId - Unique identifier for this agent.
|
|
42
54
|
* @param projectRoot - Project folder this agent is allowed to operate within.
|
|
43
55
|
* @param config - Initial agent configuration (instructions, model, tools, etc.).
|
|
56
|
+
* @param consumerMetadata - Initial SDK-owned opaque consumer metadata (or `undefined`). Persisted beside
|
|
57
|
+
* `config`; never forwarded to the harness. Mutated via `updateAgentState`.
|
|
44
58
|
* @param modelConnectivityInfo - Connectivity bag (model, baseUrl, nativeModelId,
|
|
45
59
|
* providerHint, getHeaders) the harness uses to talk to the LLM. Replaced
|
|
46
60
|
* on every `updateAgentConfig` re-resolve.
|
|
@@ -58,11 +72,12 @@ export class DefaultAgent {
|
|
|
58
72
|
* @param inbound - Router slice delivering harness events routed to this agent (non-session-scoped).
|
|
59
73
|
* @param parent - Manager's bus pair; this agent forwards its events upward into them.
|
|
60
74
|
*/
|
|
61
|
-
constructor(harness, agentId, projectRoot, config, modelConnectivityInfo, orgConnection, orgJwt, agentConnectivityResolver, harnessSupportedProviderHints, resolvers, identityStore, router, inbound, parent, clock = new RealClock(), idGenerator = new UUIDGenerator()) {
|
|
75
|
+
constructor(harness, agentId, projectRoot, config, consumerMetadata, modelConnectivityInfo, orgConnection, orgJwt, agentConnectivityResolver, harnessSupportedProviderHints, resolvers, identityStore, router, inbound, parent, clock = new RealClock(), idGenerator = new UUIDGenerator()) {
|
|
62
76
|
this.harness = harness;
|
|
63
77
|
this.agentId = agentId;
|
|
64
78
|
this.projectRoot = projectRoot;
|
|
65
79
|
this.config = config;
|
|
80
|
+
this.consumerMetadata = consumerMetadata;
|
|
66
81
|
this.modelConnectivityInfo = modelConnectivityInfo;
|
|
67
82
|
this.orgConnection = orgConnection;
|
|
68
83
|
this.orgJwt = orgJwt;
|
|
@@ -103,6 +118,15 @@ export class DefaultAgent {
|
|
|
103
118
|
this.assertNotDisposed();
|
|
104
119
|
return { ...this.config };
|
|
105
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* @requirements
|
|
123
|
+
* - MUST return a deep copy so a caller cannot mutate the agent's persisted consumer metadata in place.
|
|
124
|
+
* - MUST return `undefined` when no metadata has been set.
|
|
125
|
+
*/
|
|
126
|
+
getConsumerMetadata() {
|
|
127
|
+
this.assertNotDisposed();
|
|
128
|
+
return this.consumerMetadata === undefined ? undefined : structuredClone(this.consumerMetadata);
|
|
129
|
+
}
|
|
106
130
|
getMcpServerInfo() {
|
|
107
131
|
this.assertNotDisposed();
|
|
108
132
|
return this.harness.getMcpServerInfo(this.agentId);
|
|
@@ -128,11 +152,41 @@ export class DefaultAgent {
|
|
|
128
152
|
* against its current (possibly partially-updated) state and reverts only the actual deltas.
|
|
129
153
|
*/
|
|
130
154
|
async updateAgentConfig(config = {}, options) {
|
|
155
|
+
return this.updateAgentState({ config }, options);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @requirements
|
|
159
|
+
* - MUST merge `update.config` (when present) with the internal `config` object; `agentId` stays unchanged.
|
|
160
|
+
* - MUST apply the merged config to the harness via `this.harness.updateAgent(...)` ONLY when `update.config`
|
|
161
|
+
* is present. A metadata-only update MUST NOT call the harness at all (no server cycling, no resolver run).
|
|
162
|
+
* - MUST compute the next consumer metadata from `update.consumerMetadata`: `replace` stores a deep copy of the
|
|
163
|
+
* value; `clear` removes it; an absent mutation leaves it unchanged.
|
|
164
|
+
* - MUST persist config + metadata together in ONE `this.identityStore.write(...)` after any `harness.updateAgent`
|
|
165
|
+
* succeeds and before the in-memory swaps, so a write failure rolls back through the same catch path.
|
|
166
|
+
* - MUST preserve BOTH the previous config AND the previous metadata if `updateAgent` or persistence fails.
|
|
167
|
+
*/
|
|
168
|
+
async updateAgentState(update, options) {
|
|
131
169
|
this.assertNotDisposed();
|
|
170
|
+
const { config, consumerMetadata: metadataMutation } = update;
|
|
132
171
|
const previousConfig = { ...this.config };
|
|
172
|
+
const previousConsumerMetadata = this.consumerMetadata;
|
|
133
173
|
const previousModelConnectivityInfo = this.modelConnectivityInfo;
|
|
134
174
|
const previousOrgJwt = this.orgJwt;
|
|
135
|
-
const nextConfig = { ...this.config, ...config };
|
|
175
|
+
const nextConfig = config === undefined ? this.config : { ...this.config, ...config };
|
|
176
|
+
const nextConsumerMetadata = applyConsumerMetadataMutation(this.consumerMetadata, metadataMutation);
|
|
177
|
+
// A metadata-only update never touches the harness, the resolver, or the connectivity bag — it just
|
|
178
|
+
// rewrites the persisted record and swaps the in-memory metadata.
|
|
179
|
+
if (config === undefined) {
|
|
180
|
+
try {
|
|
181
|
+
await this.writeIdentity(nextConfig, nextConsumerMetadata);
|
|
182
|
+
this.consumerMetadata = nextConsumerMetadata;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
this.consumerMetadata = previousConsumerMetadata;
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
136
190
|
const orgAliasRequested = Object.prototype.hasOwnProperty.call(config, 'orgAlias');
|
|
137
191
|
const modelIdRequested = Object.prototype.hasOwnProperty.call(config, 'modelId');
|
|
138
192
|
let nextModelConnectivityInfo = previousModelConnectivityInfo;
|
|
@@ -169,8 +223,9 @@ export class DefaultAgent {
|
|
|
169
223
|
// Persist before the in-memory swaps so a write failure flows through the same
|
|
170
224
|
// catch block as an updateAgent failure: the rollback re-runs updateAgent against
|
|
171
225
|
// previousConfig and disk state remains the pre-update record.
|
|
172
|
-
await this.
|
|
226
|
+
await this.writeIdentity(nextConfig, nextConsumerMetadata);
|
|
173
227
|
this.config = nextConfig;
|
|
228
|
+
this.consumerMetadata = nextConsumerMetadata;
|
|
174
229
|
this.modelConnectivityInfo = nextModelConnectivityInfo;
|
|
175
230
|
this.orgConnection = nextConnection;
|
|
176
231
|
this.orgJwt = nextOrgJwt;
|
|
@@ -191,6 +246,19 @@ export class DefaultAgent {
|
|
|
191
246
|
throw error;
|
|
192
247
|
}
|
|
193
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Writes the identity record, calling `identityStore.write` with a 4th argument only when consumer metadata is
|
|
251
|
+
* present. Omitting the argument (rather than passing `undefined`) keeps a config-only write byte-identical to the
|
|
252
|
+
* pre-metadata call shape and clears any previously-persisted metadata.
|
|
253
|
+
*/
|
|
254
|
+
async writeIdentity(config, consumerMetadata) {
|
|
255
|
+
if (consumerMetadata === undefined) {
|
|
256
|
+
await this.identityStore.write(this.agentId, this.projectRoot, config);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
await this.identityStore.write(this.agentId, this.projectRoot, config, consumerMetadata);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
194
262
|
/**
|
|
195
263
|
* @requirements
|
|
196
264
|
* - MUST delegate to `this.harness.createThread(this.config.agentId)` to generate a new thread ID.
|
|
@@ -2,6 +2,7 @@ import type { Decision, ToolDefinition, ToolPolicyRule } from '../types/tools.js
|
|
|
2
2
|
import type { MCPConfiguration, McpAuthProviders } from '../mcp-config.js';
|
|
3
3
|
import type { JSONWebToken } from '@salesforce/agentic-common';
|
|
4
4
|
import type { Model, ModelName } from '../models/index.js';
|
|
5
|
+
import type { JsonValue } from '../types/session-context.js';
|
|
5
6
|
/**
|
|
6
7
|
* Configuration for an agent's behavior and capabilities.
|
|
7
8
|
* This excludes identity; `agentId` is handled separately.
|
|
@@ -140,6 +141,42 @@ export type HarnessAgentConfig = Omit<AgentConfig, 'orgAlias'> & {
|
|
|
140
141
|
* `test/harness/harness-config.test.ts` that asserts unknown fields survive.
|
|
141
142
|
*/
|
|
142
143
|
export declare function toHarnessConfig(config: AgentConfig, orgJwt?: JSONWebToken): HarnessAgentConfig;
|
|
144
|
+
/**
|
|
145
|
+
* A mutation applied to an agent's persisted consumer metadata by
|
|
146
|
+
* {@link AgentStateUpdate}. Two explicit actions rather than a bare value so
|
|
147
|
+
* "set it to this" is distinguishable from "delete it": `undefined` reads as
|
|
148
|
+
* "field omitted / leave unchanged" and `null` is a legal JSON value a
|
|
149
|
+
* consumer may legitimately want to store, so neither can double as a clear
|
|
150
|
+
* signal.
|
|
151
|
+
*
|
|
152
|
+
* - `replace` — set the metadata to `value` (stored as an opaque deep copy).
|
|
153
|
+
* - `clear` — remove the metadata entirely (a subsequent
|
|
154
|
+
* {@link Agent.getConsumerMetadata} returns `undefined`).
|
|
155
|
+
*/
|
|
156
|
+
export type ConsumerMetadataMutation = {
|
|
157
|
+
action: 'replace';
|
|
158
|
+
value: JsonValue;
|
|
159
|
+
} | {
|
|
160
|
+
action: 'clear';
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* A single atomic update to an agent's persisted state, applied by
|
|
164
|
+
* {@link Agent.updateAgentState}. Either or both members may be present:
|
|
165
|
+
*
|
|
166
|
+
* - `config` — a partial {@link AgentConfig} merged into the live config and
|
|
167
|
+
* applied to the harness (identical semantics to {@link Agent.updateAgentConfig}).
|
|
168
|
+
* - `consumerMetadata` — a {@link ConsumerMetadataMutation} on the agent's
|
|
169
|
+
* opaque consumer metadata. This metadata is SDK-owned persistence only: it
|
|
170
|
+
* is never placed on {@link AgentConfig}, never passed through
|
|
171
|
+
* {@link toHarnessConfig}, and never forwarded to the harness.
|
|
172
|
+
*
|
|
173
|
+
* When both are present the SDK commits them in one persistence write, so a
|
|
174
|
+
* failed update leaves config and metadata at their previous values together.
|
|
175
|
+
*/
|
|
176
|
+
export type AgentStateUpdate = {
|
|
177
|
+
config?: AgentConfig;
|
|
178
|
+
consumerMetadata?: ConsumerMetadataMutation;
|
|
179
|
+
};
|
|
143
180
|
/**
|
|
144
181
|
* Per-call options controlling streaming behavior.
|
|
145
182
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { BUILT_IN_TOOL_POLICIES, SKILL_BRIDGE_SERVER_ID, definePolicy, matcherMa
|
|
|
6
6
|
export type { ResolverResult, ResolverTiers, ToolInvocation } from './policy-resolver.js';
|
|
7
7
|
export type { ContextUsage, FinishReason, UsageMetadata } from './types/usage.js';
|
|
8
8
|
export type { AgentHooks, HooksForAgent, ToolResultRedactor, ToolResultRedactionInput, ToolResultRedactionResult, } from './types/redaction.js';
|
|
9
|
-
export type { AgentConfig, HarnessAgentConfig, McpAuthProviderResolver, StreamOptions, } from './harness/harness-config.js';
|
|
9
|
+
export type { AgentConfig, AgentStateUpdate, ConsumerMetadataMutation, HarnessAgentConfig, McpAuthProviderResolver, StreamOptions, } from './harness/harness-config.js';
|
|
10
10
|
export { DEFAULT_MAX_STEPS } from './harness/harness-config.js';
|
|
11
11
|
export type { MCPConfiguration, MCPServerConfig, MCPStdioServerConfig, MCPRemoteServerConfig, McpOAuthClientProvider, McpAuthProviders, McpServerInfo, McpServerErrorCategory, McpServerErrorDetail, McpToolInfo, McpToolAnnotations, } from './mcp-config.js';
|
|
12
12
|
export { McpServerStatus, mcpServerConfigEqual } from './mcp-config.js';
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type LogBus } from '@salesforce/agentic-common';
|
|
2
2
|
import type { AgentConfig } from '../harness/harness-config.js';
|
|
3
|
+
import type { JsonValue } from '../types/session-context.js';
|
|
3
4
|
export type AgentIdentityRecord = {
|
|
4
5
|
agentId: string;
|
|
5
6
|
projectRoot: string;
|
|
6
7
|
config: AgentConfig;
|
|
8
|
+
consumerMetadata?: JsonValue;
|
|
7
9
|
};
|
|
8
10
|
/**
|
|
9
11
|
* SDK-owned persistence for the agent-identity triple
|
|
@@ -33,7 +35,7 @@ export declare class AgentIdentityStore {
|
|
|
33
35
|
*/
|
|
34
36
|
private readonly inflightWrites;
|
|
35
37
|
constructor(storageRootFolder: string, harnessId: string, logBus: LogBus);
|
|
36
|
-
write(agentId: string, projectRoot: string, config: AgentConfig): Promise<void>;
|
|
38
|
+
write(agentId: string, projectRoot: string, config: AgentConfig, consumerMetadata?: JsonValue): Promise<void>;
|
|
37
39
|
private writeImmediate;
|
|
38
40
|
remove(agentId: string): Promise<void>;
|
|
39
41
|
list(): Promise<AgentIdentityRecord[]>;
|
|
@@ -39,11 +39,13 @@ export class AgentIdentityStore {
|
|
|
39
39
|
this.harnessId = harnessId;
|
|
40
40
|
this.logBus = logBus;
|
|
41
41
|
}
|
|
42
|
-
async write(agentId, projectRoot, config) {
|
|
42
|
+
async write(agentId, projectRoot, config, consumerMetadata) {
|
|
43
43
|
const previous = this.inflightWrites.get(agentId) ?? Promise.resolve();
|
|
44
44
|
// `.catch(() => undefined)` so a previous failure doesn't poison the next caller's await.
|
|
45
45
|
// Each caller still observes its own write's success or failure via the returned promise.
|
|
46
|
-
const next = previous
|
|
46
|
+
const next = previous
|
|
47
|
+
.catch(() => undefined)
|
|
48
|
+
.then(() => this.writeImmediate(agentId, projectRoot, config, consumerMetadata));
|
|
47
49
|
this.inflightWrites.set(agentId, next);
|
|
48
50
|
try {
|
|
49
51
|
await next;
|
|
@@ -56,7 +58,7 @@ export class AgentIdentityStore {
|
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
|
-
async writeImmediate(agentId, projectRoot, config) {
|
|
61
|
+
async writeImmediate(agentId, projectRoot, config, consumerMetadata) {
|
|
60
62
|
const dir = this.dir();
|
|
61
63
|
await mkdir(dir, { recursive: true });
|
|
62
64
|
const payload = {
|
|
@@ -65,6 +67,7 @@ export class AgentIdentityStore {
|
|
|
65
67
|
agentId,
|
|
66
68
|
projectRoot,
|
|
67
69
|
config,
|
|
70
|
+
...(consumerMetadata !== undefined ? { consumerMetadata } : {}),
|
|
68
71
|
};
|
|
69
72
|
const target = join(dir, `${agentId}.json`);
|
|
70
73
|
const tmp = `${target}.tmp`;
|
|
@@ -130,6 +133,7 @@ export class AgentIdentityStore {
|
|
|
130
133
|
agentId: parsed.agentId,
|
|
131
134
|
projectRoot: parsed.projectRoot,
|
|
132
135
|
config: parsed.config,
|
|
136
|
+
...(parsed.consumerMetadata !== undefined ? { consumerMetadata: parsed.consumerMetadata } : {}),
|
|
133
137
|
});
|
|
134
138
|
}
|
|
135
139
|
return records;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/sfdx-agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "Harness-agnostic agentic infrastructure for Salesforce developer experience tooling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@eslint/js": "^10.0.1",
|
|
50
|
-
"@salesforce/sfdx-agent-harness-claude": "0.
|
|
51
|
-
"@salesforce/sfdx-agent-harness-mastra": "0.
|
|
52
|
-
"@salesforce/sfdx-agent-harness-openai": "0.
|
|
50
|
+
"@salesforce/sfdx-agent-harness-claude": "0.49.0",
|
|
51
|
+
"@salesforce/sfdx-agent-harness-mastra": "0.52.0",
|
|
52
|
+
"@salesforce/sfdx-agent-harness-openai": "0.18.0",
|
|
53
53
|
"@types/node": "^22.20.1",
|
|
54
54
|
"@vitest/coverage-istanbul": "^4.1.10",
|
|
55
55
|
"@vitest/eslint-plugin": "^1.6.26",
|