@salesforce/sfdx-agent-sdk 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -11
- package/dist/chat-session.d.ts +41 -9
- package/dist/chat-session.js +37 -11
- package/dist/harness/agent-harness.d.ts +12 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/mcp-config.d.ts +89 -2
- package/dist/mcp-config.js +7 -0
- package/dist/types/telemetry-events.d.ts +30 -11
- package/dist/types/tools.d.ts +29 -7
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -245,12 +245,27 @@ type MCPRemoteServerConfig = {
|
|
|
245
245
|
|
|
246
246
|
#### `McpServerInfo`
|
|
247
247
|
|
|
248
|
-
| Field
|
|
249
|
-
|
|
|
250
|
-
| `name`
|
|
251
|
-
| `status`
|
|
252
|
-
| `tools`
|
|
253
|
-
| `error?`
|
|
248
|
+
| Field | Type | Description |
|
|
249
|
+
| -------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
250
|
+
| `name` | `string` | Server identifier. |
|
|
251
|
+
| `status` | `'connected' \| 'connecting' \| 'disabled' \| 'error' \| 'reconnecting'` | Connection state. `'reconnecting'` is reported during an `Agent.reconnectMcpServer(name)` call against a previously-`'connected'` server. |
|
|
252
|
+
| `tools` | [`McpToolInfo[]`](#mcptoolinfo) | Discovered tools (name + metadata). |
|
|
253
|
+
| `error?` | `string` | Sanitized human-readable error message when status is `'error'`. Stack frames and file paths are stripped at the harness boundary. |
|
|
254
|
+
| `errorDetail?` | [`McpServerErrorDetail`](#mcpservererrordetail) | Structured failure projection for programmatic routing (category / code / retriable). Populated when status is `'error'`. |
|
|
255
|
+
|
|
256
|
+
#### `McpServerErrorDetail`
|
|
257
|
+
|
|
258
|
+
Structured projection of an MCP server failure. Mirror is also attached to the `mcp-server-discovery-failed` telemetry
|
|
259
|
+
event so subscribers can route on it without pattern-matching `error.message`.
|
|
260
|
+
|
|
261
|
+
| Field | Type | Description |
|
|
262
|
+
| ----------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
263
|
+
| `category` | `McpServerErrorCategory` | Stable category for routing logic. Set is additive across minor versions — values are added but never renamed or removed. |
|
|
264
|
+
| `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). |
|
|
265
|
+
| `retriable` | `boolean` | Whether the SDK considers the failure transient (worth `Agent.reconnectMcpServer` / `Agent.refreshMcpAuth`) versus fatal. |
|
|
266
|
+
|
|
267
|
+
`McpServerErrorCategory` values: `'connect-timeout'`, `'http-401'`, `'http-403'`, `'http-4xx'`, `'http-5xx'`,
|
|
268
|
+
`'transport-eof'`, `'protocol-error'`, `'config-error'`, `'aborted'`, `'unknown'`.
|
|
254
269
|
|
|
255
270
|
#### `McpToolInfo`
|
|
256
271
|
|
|
@@ -510,6 +525,12 @@ Returns `true` if the URL matches a Salesforce Hosted MCP Server endpoint (prod,
|
|
|
510
525
|
|
|
511
526
|
- `ModelName` — enum of supported model identifiers
|
|
512
527
|
- `SfApiEnv` — Salesforce API environment enum (`dev`, `perf`, `prod`, `stage`, `test`)
|
|
528
|
+
- `inferSfApiEnv(instanceUrl, options?)` — maps an instance URL to a `SfApiEnv`. Re-exported from
|
|
529
|
+
`@salesforce/agentic-common` for consumers that need the mapping without an `OrgConnection` (e.g. building a
|
|
530
|
+
Salesforce platform MCP URL). Defaults the unrecognized-`.pc-rnd.` fallback to `SfApiEnv.Test` (`.pc-rnd.` is an
|
|
531
|
+
internal-only OrgFarm domain — not Prod by definition); pass `{ pcRndFallback: SfApiEnv.Prod }` to override. See the
|
|
532
|
+
[`@salesforce/agentic-common` README](../agentic-common/README.md#infersfapienvinstanceurl-options-sfapienv) for the
|
|
533
|
+
full resolution order.
|
|
513
534
|
|
|
514
535
|
### Telemetry & structured logs
|
|
515
536
|
|
|
@@ -700,11 +721,14 @@ All variants share `{ type: <discriminant>, timestamp: Date }` plus the fields b
|
|
|
700
721
|
| `tool-approval-resolved` | `agentId`, `threadId`, `toolCallId`, `approved` |
|
|
701
722
|
| `mcp-server-discovery-started` | `agentId`, `serverName` |
|
|
702
723
|
| `mcp-server-discovery-completed` | `agentId`, `serverName`, `toolCount`, `durationMs` |
|
|
703
|
-
| `mcp-server-discovery-failed` | `agentId`, `serverName`, `durationMs`, `error`
|
|
704
|
-
| `mcp-
|
|
705
|
-
|
|
706
|
-
`mcp-
|
|
707
|
-
|
|
724
|
+
| `mcp-server-discovery-failed` | `agentId`, `serverName`, `durationMs`, `error`, `errorDetail?` ([`McpServerErrorDetail`](#mcpservererrordetail)) |
|
|
725
|
+
| `mcp-server-status-changed` | `agentId`, `serverName`, `previousStatus`, `nextStatus`, `error?` |
|
|
726
|
+
|
|
727
|
+
`mcp-server-status-changed` fires on every per-server status transition — emitted in addition to the discovery trio so
|
|
728
|
+
consumers can route on the `(previousStatus, nextStatus)` pair without polling `getMcpServerInfo()`. A reconnect on a
|
|
729
|
+
previously-`connected` server emits, in order: `connected → reconnecting`, then on success `reconnecting → connected`,
|
|
730
|
+
or on failure `reconnecting → error`. Emitted by the Mastra harness today; the Claude harness emits the discovery trio
|
|
731
|
+
on the same lifecycle moments and consumers can converge on the same `getMcpServerInfo()` snapshot from either side.
|
|
708
732
|
|
|
709
733
|
Every chat entry point (`chat`, `submitToolResult`, `approveToolCall`, `declineToolCall`) emits exactly one
|
|
710
734
|
`chat-stream-started` followed by exactly one terminal event — either `chat-stream-completed` (natural completion) or
|
package/dist/chat-session.d.ts
CHANGED
|
@@ -55,15 +55,28 @@ export interface ChatSession {
|
|
|
55
55
|
*/
|
|
56
56
|
chat(message: string, options?: ChatOptions): Promise<ChatStreamResult>;
|
|
57
57
|
/**
|
|
58
|
-
* Feed the result of a client-side tool
|
|
59
|
-
* and resume stream generation.
|
|
58
|
+
* Feed the result of a **consumer-executed (client-side) tool** back into the
|
|
59
|
+
* conversation and resume stream generation.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
61
|
+
* "Client-side tool" means a tool you declared in {@link AgentConfig.tools}
|
|
62
|
+
* without an `execute` function — the SDK registers its name + schema with the
|
|
63
|
+
* model but does not run it. When the model calls one, the chat eventStream
|
|
64
|
+
* emits a `tool-call` event and ends with `finishReason: 'tool-calls'`. Your
|
|
65
|
+
* application runs the tool however it likes (HTTP call, DB query, UI prompt,
|
|
66
|
+
* etc.) and calls this method with the result; the agent loop resumes and
|
|
67
|
+
* produces its next turn on the returned `ChatStreamResult.eventStream`.
|
|
68
|
+
*
|
|
69
|
+
* Use this method ONLY for client-side tools. Tools provided via
|
|
70
|
+
* {@link AgentConfig.mcpServers} are executed by the harness — their results
|
|
71
|
+
* flow naturally as `tool-result` events without consumer involvement.
|
|
72
|
+
* Human-in-the-loop approval of harness-executed tools uses
|
|
73
|
+
* {@link approveToolCall} / {@link declineToolCall}, not this method.
|
|
62
74
|
*
|
|
63
75
|
* On pre-stream failure, subscribers are notified with `ErrorEvent` + `FinishEvent` before
|
|
64
76
|
* the returned promise rejects. See the interface-level "Failure handling" notes for details.
|
|
65
77
|
*
|
|
66
|
-
* @param toolResult - The completed tool execution result.
|
|
78
|
+
* @param toolResult - The completed tool execution result. `toolCallId` and
|
|
79
|
+
* `toolName` MUST match the values from the originating `tool-call` event.
|
|
67
80
|
*/
|
|
68
81
|
submitToolResult(toolResult: ToolResultInfo): Promise<ChatStreamResult>;
|
|
69
82
|
/**
|
|
@@ -151,6 +164,17 @@ export declare class DefaultChatSession implements ChatSession {
|
|
|
151
164
|
private readonly parentUnsubs;
|
|
152
165
|
private readonly clock;
|
|
153
166
|
private readonly idGenerator;
|
|
167
|
+
/**
|
|
168
|
+
* Tracks the start timestamp of every in-flight `tool-call` keyed by `toolCallId`,
|
|
169
|
+
* used by `deriveToolTelemetry` to compute `tool-execution-completed.durationMs`.
|
|
170
|
+
*
|
|
171
|
+
* Lifetime is per-session (not per-stream) so a `tool-call` on the initial chat stream
|
|
172
|
+
* pairs with a `tool-result` on the approval-continuation / submit-tool-result
|
|
173
|
+
* continuation stream — those are continuations of the same logical chat turn. Cleared
|
|
174
|
+
* on every terminal `finish` ChatEvent (the turn closed cleanly; any unmatched entries
|
|
175
|
+
* are stale and should not bleed into the next turn).
|
|
176
|
+
*/
|
|
177
|
+
private readonly toolStartMs;
|
|
154
178
|
private disposed;
|
|
155
179
|
/**
|
|
156
180
|
* @param harness - The agent harness managing thread and message lifecycle.
|
|
@@ -195,8 +219,12 @@ export declare class DefaultChatSession implements ChatSession {
|
|
|
195
219
|
* - MUST derive `tool-execution-started`, `tool-execution-completed`, and
|
|
196
220
|
* `tool-approval-requested` telemetry from the corresponding `ChatEvent` types so harness
|
|
197
221
|
* implementations don't reimplement this. `tool-execution-completed.durationMs` is measured
|
|
198
|
-
* between the matching `tool-call` and `tool-result
|
|
199
|
-
*
|
|
222
|
+
* between the matching `tool-call` and `tool-result`, including across approval / resume
|
|
223
|
+
* continuations within the same chat turn — those are continuations of one logical turn
|
|
224
|
+
* and the tool start timestamp lives on the session, not the stream. The tracking map is
|
|
225
|
+
* cleared on every terminal `finish` ChatEvent so stale entries from one turn never bleed
|
|
226
|
+
* into the next. An unmatched `tool-result` (no recorded `tool-call` in the session) is
|
|
227
|
+
* still skipped.
|
|
200
228
|
*
|
|
201
229
|
* `chat-stream-started` is emitted by the entry-point method (chat / submitToolResult /
|
|
202
230
|
* approveToolCall / declineToolCall) before the harness call so that pre-stream rejections
|
|
@@ -269,9 +297,13 @@ export declare class DefaultChatSession implements ChatSession {
|
|
|
269
297
|
* implementation free of telemetry plumbing — they just yield the right `ChatEvent` shapes.
|
|
270
298
|
*
|
|
271
299
|
* `tool-execution-completed.durationMs` is measured between the matching `tool-call` and
|
|
272
|
-
* `tool-result` using `this.clock`.
|
|
273
|
-
*
|
|
274
|
-
*
|
|
300
|
+
* `tool-result` using `this.clock`. The tracking map (`this.toolStartMs`) lives on the
|
|
301
|
+
* session, so a `tool-call` on the initial stream pairs with a `tool-result` on the
|
|
302
|
+
* approval-continuation / submit-tool-result continuation stream — those are continuations
|
|
303
|
+
* of the same logical chat turn. The map is cleared on every terminal `finish` ChatEvent
|
|
304
|
+
* (handled by `wrapEventStream`). An unmatched `tool-result` (no recorded `tool-call`) is
|
|
305
|
+
* skipped — the consumer correlates by `toolCallId` against the earlier
|
|
306
|
+
* `tool-execution-started`.
|
|
275
307
|
*/
|
|
276
308
|
private deriveToolTelemetry;
|
|
277
309
|
/**
|
package/dist/chat-session.js
CHANGED
|
@@ -20,6 +20,17 @@ export class DefaultChatSession {
|
|
|
20
20
|
parentUnsubs;
|
|
21
21
|
clock;
|
|
22
22
|
idGenerator;
|
|
23
|
+
/**
|
|
24
|
+
* Tracks the start timestamp of every in-flight `tool-call` keyed by `toolCallId`,
|
|
25
|
+
* used by `deriveToolTelemetry` to compute `tool-execution-completed.durationMs`.
|
|
26
|
+
*
|
|
27
|
+
* Lifetime is per-session (not per-stream) so a `tool-call` on the initial chat stream
|
|
28
|
+
* pairs with a `tool-result` on the approval-continuation / submit-tool-result
|
|
29
|
+
* continuation stream — those are continuations of the same logical chat turn. Cleared
|
|
30
|
+
* on every terminal `finish` ChatEvent (the turn closed cleanly; any unmatched entries
|
|
31
|
+
* are stale and should not bleed into the next turn).
|
|
32
|
+
*/
|
|
33
|
+
toolStartMs = new Map();
|
|
23
34
|
disposed = false;
|
|
24
35
|
/**
|
|
25
36
|
* @param harness - The agent harness managing thread and message lifecycle.
|
|
@@ -103,8 +114,12 @@ export class DefaultChatSession {
|
|
|
103
114
|
* - MUST derive `tool-execution-started`, `tool-execution-completed`, and
|
|
104
115
|
* `tool-approval-requested` telemetry from the corresponding `ChatEvent` types so harness
|
|
105
116
|
* implementations don't reimplement this. `tool-execution-completed.durationMs` is measured
|
|
106
|
-
* between the matching `tool-call` and `tool-result
|
|
107
|
-
*
|
|
117
|
+
* between the matching `tool-call` and `tool-result`, including across approval / resume
|
|
118
|
+
* continuations within the same chat turn — those are continuations of one logical turn
|
|
119
|
+
* and the tool start timestamp lives on the session, not the stream. The tracking map is
|
|
120
|
+
* cleared on every terminal `finish` ChatEvent so stale entries from one turn never bleed
|
|
121
|
+
* into the next. An unmatched `tool-result` (no recorded `tool-call` in the session) is
|
|
122
|
+
* still skipped.
|
|
108
123
|
*
|
|
109
124
|
* `chat-stream-started` is emitted by the entry-point method (chat / submitToolResult /
|
|
110
125
|
* approveToolCall / declineToolCall) before the harness call so that pre-stream rejections
|
|
@@ -112,18 +127,21 @@ export class DefaultChatSession {
|
|
|
112
127
|
* `durationMs` measures real elapsed time on both terminal events.
|
|
113
128
|
*/
|
|
114
129
|
async *wrapEventStream(stream, startedAt) {
|
|
115
|
-
const toolStartMs = new Map();
|
|
116
130
|
let sawFinish = false;
|
|
117
131
|
let lastError;
|
|
118
132
|
let finishUsage;
|
|
119
133
|
try {
|
|
120
134
|
for await (const event of stream) {
|
|
121
135
|
this.chatEventBus.emit(event);
|
|
122
|
-
this.deriveToolTelemetry(event
|
|
136
|
+
this.deriveToolTelemetry(event);
|
|
123
137
|
yield event;
|
|
124
138
|
if (event.type === 'finish') {
|
|
125
139
|
sawFinish = true;
|
|
126
140
|
finishUsage = event.usage;
|
|
141
|
+
// Turn boundary — clear any unmatched in-flight tool starts so a stale
|
|
142
|
+
// entry from one turn cannot pair with an unrelated tool-result on the
|
|
143
|
+
// next turn. Matched pairs already removed their entry in `deriveToolTelemetry`.
|
|
144
|
+
this.toolStartMs.clear();
|
|
127
145
|
}
|
|
128
146
|
if (event.type === 'error')
|
|
129
147
|
lastError = event.error;
|
|
@@ -140,6 +158,10 @@ export class DefaultChatSession {
|
|
|
140
158
|
const finishEvent = { type: 'finish', finishReason: 'error' };
|
|
141
159
|
this.chatEventBus.emit(finishEvent);
|
|
142
160
|
yield finishEvent;
|
|
161
|
+
// Match the natural-finish branch: every terminal `finish` clears the
|
|
162
|
+
// tool-start tracking map so a stale entry can't pair with an unrelated
|
|
163
|
+
// tool-result on the next turn.
|
|
164
|
+
this.toolStartMs.clear();
|
|
143
165
|
}
|
|
144
166
|
const finishedAt = this.clock.now();
|
|
145
167
|
const durationMs = finishedAt.getTime() - startedAt.getTime();
|
|
@@ -312,13 +334,17 @@ export class DefaultChatSession {
|
|
|
312
334
|
* implementation free of telemetry plumbing — they just yield the right `ChatEvent` shapes.
|
|
313
335
|
*
|
|
314
336
|
* `tool-execution-completed.durationMs` is measured between the matching `tool-call` and
|
|
315
|
-
* `tool-result` using `this.clock`.
|
|
316
|
-
*
|
|
317
|
-
*
|
|
337
|
+
* `tool-result` using `this.clock`. The tracking map (`this.toolStartMs`) lives on the
|
|
338
|
+
* session, so a `tool-call` on the initial stream pairs with a `tool-result` on the
|
|
339
|
+
* approval-continuation / submit-tool-result continuation stream — those are continuations
|
|
340
|
+
* of the same logical chat turn. The map is cleared on every terminal `finish` ChatEvent
|
|
341
|
+
* (handled by `wrapEventStream`). An unmatched `tool-result` (no recorded `tool-call`) is
|
|
342
|
+
* skipped — the consumer correlates by `toolCallId` against the earlier
|
|
343
|
+
* `tool-execution-started`.
|
|
318
344
|
*/
|
|
319
|
-
deriveToolTelemetry(event
|
|
345
|
+
deriveToolTelemetry(event) {
|
|
320
346
|
if (event.type === 'tool-call') {
|
|
321
|
-
toolStartMs.set(event.toolCallId, this.clock.now().getTime());
|
|
347
|
+
this.toolStartMs.set(event.toolCallId, this.clock.now().getTime());
|
|
322
348
|
this.telemetryBus.emit({
|
|
323
349
|
type: 'tool-execution-started',
|
|
324
350
|
timestamp: this.clock.now(),
|
|
@@ -331,10 +357,10 @@ export class DefaultChatSession {
|
|
|
331
357
|
});
|
|
332
358
|
}
|
|
333
359
|
else if (event.type === 'tool-result') {
|
|
334
|
-
const start = toolStartMs.get(event.toolCallId);
|
|
360
|
+
const start = this.toolStartMs.get(event.toolCallId);
|
|
335
361
|
if (start === undefined)
|
|
336
362
|
return;
|
|
337
|
-
toolStartMs.delete(event.toolCallId);
|
|
363
|
+
this.toolStartMs.delete(event.toolCallId);
|
|
338
364
|
this.telemetryBus.emit({
|
|
339
365
|
type: 'tool-execution-completed',
|
|
340
366
|
timestamp: this.clock.now(),
|
|
@@ -208,16 +208,22 @@ export interface AgentHarness {
|
|
|
208
208
|
*/
|
|
209
209
|
stream(agentId: string, threadId: string, message: string, options?: StreamOptions): Promise<ChatStreamResult>;
|
|
210
210
|
/**
|
|
211
|
-
* Feed the result of a client-side tool
|
|
212
|
-
* and resume stream generation.
|
|
211
|
+
* Feed the result of a **consumer-executed (client-side) tool** back into the
|
|
212
|
+
* conversation and resume stream generation. Implements the consumer-facing
|
|
213
|
+
* {@link ChatSession.submitToolResult} contract: see that JSDoc for the
|
|
214
|
+
* full consumer-level semantics.
|
|
213
215
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
216
|
+
* Called only for tools declared in {@link HarnessAgentConfig.tools} (no
|
|
217
|
+
* `execute` function). Tools provided via `mcpServers` are executed by the
|
|
218
|
+
* harness directly and never reach this method. The harness resumes the
|
|
219
|
+
* suspended agentic loop from the most recent `stream()` call on the given
|
|
220
|
+
* thread, feeds `toolResult` into the loop, and returns a continuation
|
|
221
|
+
* stream the consumer iterates for the model's next turn.
|
|
217
222
|
*
|
|
218
223
|
* @param agentId - ID of the agent.
|
|
219
224
|
* @param threadId - ID of the conversation thread.
|
|
220
|
-
* @param toolResult - The completed tool execution result
|
|
225
|
+
* @param toolResult - The completed tool execution result; `toolCallId`
|
|
226
|
+
* matches the id from the originating `tool-call` event.
|
|
221
227
|
*/
|
|
222
228
|
submitToolResult(agentId: string, threadId: string, toolResult: ToolResultInfo): Promise<ChatStreamResult>;
|
|
223
229
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ export type { ToolDefinition, ToolCallInfo, ToolResultInfo } from './types/tools
|
|
|
4
4
|
export type { FinishReason, UsageMetadata } from './types/usage.js';
|
|
5
5
|
export type { AgentConfig, HarnessAgentConfig, StreamOptions } from './harness/harness-config.js';
|
|
6
6
|
export { DEFAULT_MAX_STEPS } from './harness/harness-config.js';
|
|
7
|
-
export type { MCPConfiguration, MCPServerConfig, MCPStdioServerConfig, MCPRemoteServerConfig, McpServerInfo, McpToolInfo, McpToolAnnotations, } from './mcp-config.js';
|
|
7
|
+
export type { MCPConfiguration, MCPServerConfig, MCPStdioServerConfig, MCPRemoteServerConfig, McpServerInfo, McpServerErrorCategory, McpServerErrorDetail, McpToolInfo, McpToolAnnotations, } from './mcp-config.js';
|
|
8
8
|
export { McpServerStatus } from './mcp-config.js';
|
|
9
9
|
export { ModelName } from '@salesforce/llm-gateway-sdk';
|
|
10
|
-
export { SfApiEnv } from '@salesforce/agentic-common';
|
|
10
|
+
export { inferSfApiEnv, SfApiEnv } from '@salesforce/agentic-common';
|
|
11
11
|
export { type AgentManager, type RestoreFailure, createAgentManager } from './agent-manager.js';
|
|
12
12
|
export { type Agent } from './agent.js';
|
|
13
13
|
export { type ChatSession, type ChatOptions } from './chat-session.js';
|
|
@@ -16,7 +16,7 @@ export type { AgentHarness, HarnessFactory, WithAgentConfig, ConfigOf } from './
|
|
|
16
16
|
export { SUPPORTED_PROTOCOL_VERSIONS } from './harness/agent-harness.js';
|
|
17
17
|
export { HarnessBusOwner } from './harness/harness-bus-owner.js';
|
|
18
18
|
export { AgentSDKError, AgentSDKErrorType } from './errors.js';
|
|
19
|
-
export type { AgentCreatedEvent, AgentDestroyedEvent, ChatStreamCompletedEvent, ChatStreamErrorEvent, ChatStreamStartedEvent, ChatStreamTrigger,
|
|
19
|
+
export type { AgentCreatedEvent, AgentDestroyedEvent, ChatStreamCompletedEvent, ChatStreamErrorEvent, ChatStreamStartedEvent, ChatStreamTrigger, McpServerDiscoveryCompletedEvent, McpServerDiscoveryFailedEvent, McpServerDiscoveryStartedEvent, McpServerStatusChangedEvent, SessionCreatedEvent, SessionDestroyedEvent, TelemetryEvent, TelemetryEventCallback, ToolApprovalRequestedEvent, ToolApprovalResolvedEvent, ToolExecutionCompletedEvent, ToolExecutionStartedEvent, } from './types/telemetry-events.js';
|
|
20
20
|
export type { LogLevel, LogRecord, Unsubscribe } from '@salesforce/agentic-common';
|
|
21
21
|
export { resolveMcpServerHeaders } from './mcp-auth.js';
|
|
22
22
|
export type { OrgConnection, OrgConnectionFactory } from '@salesforce/agentic-common';
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
export { DEFAULT_MAX_STEPS } from './harness/harness-config.js';
|
|
6
6
|
export { McpServerStatus } from './mcp-config.js';
|
|
7
7
|
export { ModelName } from '@salesforce/llm-gateway-sdk';
|
|
8
|
-
export { SfApiEnv } from '@salesforce/agentic-common';
|
|
8
|
+
export { inferSfApiEnv, SfApiEnv } from '@salesforce/agentic-common';
|
|
9
9
|
// ── Agent Layer ─────────────────────────────────────────────────────
|
|
10
10
|
export { createAgentManager } from './agent-manager.js';
|
|
11
11
|
export {} from './agent.js';
|
package/dist/mcp-config.d.ts
CHANGED
|
@@ -17,7 +17,18 @@ export type MCPStdioServerConfig = {
|
|
|
17
17
|
command: string;
|
|
18
18
|
/** Arguments passed to the command. */
|
|
19
19
|
args?: string[];
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Environment variables set when running the server process.
|
|
22
|
+
*
|
|
23
|
+
* **JWT rotation caveat.** These env vars are forwarded verbatim to the
|
|
24
|
+
* child process at spawn time. The MCP SDK's stdio transport has no
|
|
25
|
+
* per-request hook, so a JWT-bearing env var (e.g. `SF_ACCESS_TOKEN`)
|
|
26
|
+
* is frozen at spawn. After a JWT rotation, an stdio MCP server that
|
|
27
|
+
* depends on the env value will see a stale value until the child is
|
|
28
|
+
* respawned — call `Agent.reconnectMcpServer(name)` to refresh.
|
|
29
|
+
* Remote (HTTP) servers do not have this limitation; their auth headers
|
|
30
|
+
* are re-resolved per request through a host-side fetch hook.
|
|
31
|
+
*/
|
|
21
32
|
env?: Record<string, string>;
|
|
22
33
|
/** Whether this server is enabled. Defaults to `true`. */
|
|
23
34
|
enabled?: boolean;
|
|
@@ -41,7 +52,14 @@ export declare enum McpServerStatus {
|
|
|
41
52
|
Connected = "connected",
|
|
42
53
|
Connecting = "connecting",
|
|
43
54
|
Disabled = "disabled",
|
|
44
|
-
Error = "error"
|
|
55
|
+
Error = "error",
|
|
56
|
+
/**
|
|
57
|
+
* Transport is being cycled after the server was previously `Connected` —
|
|
58
|
+
* e.g. an explicit `Agent.reconnectMcpServer(name)` call. The server stays
|
|
59
|
+
* in this state until the new transport + discovery resolves to either
|
|
60
|
+
* `Connected` (success) or `Error` (failure).
|
|
61
|
+
*/
|
|
62
|
+
Reconnecting = "reconnecting"
|
|
45
63
|
}
|
|
46
64
|
/**
|
|
47
65
|
* Behavioral / UI-presentation hints for an MCP-discovered tool.
|
|
@@ -106,10 +124,79 @@ export type McpToolInfo = {
|
|
|
106
124
|
/** Behavioral / UI-presentation hints declared by the MCP server. */
|
|
107
125
|
annotations?: McpToolAnnotations;
|
|
108
126
|
};
|
|
127
|
+
/**
|
|
128
|
+
* Stable category for routing logic on an MCP server failure. Consumers writing
|
|
129
|
+
* reconnect / retry / UX flows match on this instead of regexing the
|
|
130
|
+
* free-form `error` string. The set is additive across minor versions — values
|
|
131
|
+
* may be added but never removed or renamed.
|
|
132
|
+
*/
|
|
133
|
+
export type McpServerErrorCategory =
|
|
134
|
+
/** 3s default or configured timeout exceeded. */
|
|
135
|
+
'connect-timeout'
|
|
136
|
+
/** Unauthorized — JWT missing/expired. */
|
|
137
|
+
| 'http-401'
|
|
138
|
+
/** Forbidden — JWT valid but the principal lacks permission. */
|
|
139
|
+
| 'http-403'
|
|
140
|
+
/** Other 4xx — likely a config issue. */
|
|
141
|
+
| 'http-4xx'
|
|
142
|
+
/** Server-side error — transient or fatal. */
|
|
143
|
+
| 'http-5xx'
|
|
144
|
+
/** Connection closed unexpectedly. */
|
|
145
|
+
| 'transport-eof'
|
|
146
|
+
/** MCP spec violation in response (JSON-RPC framing or schema). */
|
|
147
|
+
| 'protocol-error'
|
|
148
|
+
/** Bad URL, bad headers, bad config. */
|
|
149
|
+
| 'config-error'
|
|
150
|
+
/** Consumer-driven `AbortSignal`. */
|
|
151
|
+
| 'aborted'
|
|
152
|
+
/** Could not be classified. */
|
|
153
|
+
| 'unknown';
|
|
154
|
+
/**
|
|
155
|
+
* Structured projection of an MCP server failure attached to an
|
|
156
|
+
* {@link McpServerInfo} (post-discovery polling surface) or an
|
|
157
|
+
* {@link McpServerDiscoveryFailedEvent} (per-event telemetry).
|
|
158
|
+
*
|
|
159
|
+
* Replaces consumer pattern-matching against the free-form `error` string for
|
|
160
|
+
* routing decisions. The free-form string is still surfaced (sanitized — no V8
|
|
161
|
+
* stack frames or file paths) for human-readable display and logs.
|
|
162
|
+
*/
|
|
163
|
+
export type McpServerErrorDetail = {
|
|
164
|
+
/** Stable category for routing logic. */
|
|
165
|
+
category: McpServerErrorCategory;
|
|
166
|
+
/**
|
|
167
|
+
* JSON-RPC error code from the underlying `McpError`, when the failure
|
|
168
|
+
* originated as a JSON-RPC error. `undefined` for transport-level failures
|
|
169
|
+
* (DNS, TCP, TLS) and for harnesses whose underlying SDK does not surface
|
|
170
|
+
* the JSON-RPC code (e.g. the Claude harness).
|
|
171
|
+
*
|
|
172
|
+
* See [@modelcontextprotocol/sdk types](https://www.npmjs.com/package/@modelcontextprotocol/sdk)
|
|
173
|
+
* (`McpError`) and the JSON-RPC 2.0
|
|
174
|
+
* [error object](https://www.jsonrpc.org/specification#error_object).
|
|
175
|
+
*/
|
|
176
|
+
code?: number;
|
|
177
|
+
/**
|
|
178
|
+
* Whether the failure is transient (worth a retry via
|
|
179
|
+
* `Agent.reconnectMcpServer` / `Agent.refreshMcpAuth`) vs fatal (consumer
|
|
180
|
+
* must fix config). Harness implementations populate this with their best
|
|
181
|
+
* heuristic; consumers may override per-category.
|
|
182
|
+
*/
|
|
183
|
+
retriable: boolean;
|
|
184
|
+
};
|
|
109
185
|
/** Runtime status of a configured MCP server, including its discovered tools. */
|
|
110
186
|
export type McpServerInfo = {
|
|
111
187
|
name: string;
|
|
112
188
|
status: McpServerStatus;
|
|
113
189
|
tools: McpToolInfo[];
|
|
190
|
+
/**
|
|
191
|
+
* Human-readable error string. Sanitized at the harness boundary — no V8
|
|
192
|
+
* stack frames, no file paths, no internal class names. Safe for UI
|
|
193
|
+
* display and telemetry tags. For programmatic routing, prefer
|
|
194
|
+
* {@link errorDetail}.
|
|
195
|
+
*/
|
|
114
196
|
error?: string;
|
|
197
|
+
/**
|
|
198
|
+
* Structured failure projection. Populated by the harness when `status` is
|
|
199
|
+
* `Error`; absent otherwise. See {@link McpServerErrorDetail}.
|
|
200
|
+
*/
|
|
201
|
+
errorDetail?: McpServerErrorDetail;
|
|
115
202
|
};
|
package/dist/mcp-config.js
CHANGED
|
@@ -9,5 +9,12 @@ export var McpServerStatus;
|
|
|
9
9
|
McpServerStatus["Connecting"] = "connecting";
|
|
10
10
|
McpServerStatus["Disabled"] = "disabled";
|
|
11
11
|
McpServerStatus["Error"] = "error";
|
|
12
|
+
/**
|
|
13
|
+
* Transport is being cycled after the server was previously `Connected` —
|
|
14
|
+
* e.g. an explicit `Agent.reconnectMcpServer(name)` call. The server stays
|
|
15
|
+
* in this state until the new transport + discovery resolves to either
|
|
16
|
+
* `Connected` (success) or `Error` (failure).
|
|
17
|
+
*/
|
|
18
|
+
McpServerStatus["Reconnecting"] = "reconnecting";
|
|
12
19
|
})(McpServerStatus || (McpServerStatus = {}));
|
|
13
20
|
//# sourceMappingURL=mcp-config.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EventBus } from '@salesforce/agentic-common';
|
|
2
|
-
import type {
|
|
2
|
+
import type { McpServerErrorDetail, McpServerStatus, McpToolAnnotations } from '../mcp-config.js';
|
|
3
3
|
import type { UsageMetadata } from './usage.js';
|
|
4
4
|
/**
|
|
5
5
|
* Telemetry events emitted by the Agent SDK.
|
|
@@ -99,22 +99,41 @@ export type McpServerDiscoveryFailedEvent = Base<'mcp-server-discovery-failed'>
|
|
|
99
99
|
serverName: string;
|
|
100
100
|
durationMs: number;
|
|
101
101
|
error: Error;
|
|
102
|
+
/**
|
|
103
|
+
* Structured failure projection. Mirrors `McpServerInfo.errorDetail` so
|
|
104
|
+
* subscribers can route on category / code / retriable without
|
|
105
|
+
* pattern-matching `error.message`. Populated by harnesses that classify
|
|
106
|
+
* MCP failures.
|
|
107
|
+
*/
|
|
108
|
+
errorDetail?: McpServerErrorDetail;
|
|
102
109
|
};
|
|
103
110
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* `SDKSystemMessage init` arrival.
|
|
111
|
+
* Per-transition MCP transport-state event emitted whenever a server's
|
|
112
|
+
* `McpServerStatus` changes. Consumers that need to react to specific
|
|
113
|
+
* transitions filter on the `(previousStatus, nextStatus)` pair.
|
|
108
114
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
115
|
+
* Emitted in addition to `mcp-server-discovery-{started,completed,failed}` —
|
|
116
|
+
* the discovery trio reports work boundaries (start/end of a discovery run)
|
|
117
|
+
* while this event reports the status the server is now in. A reconnect on a
|
|
118
|
+
* `Connected` server emits, in order:
|
|
119
|
+
* `Connected → Reconnecting` (transport is being cycled),
|
|
120
|
+
* then on success `Reconnecting → Connected`, or on failure
|
|
121
|
+
* `Reconnecting → Error`.
|
|
122
|
+
*
|
|
123
|
+
* Emitted by the Mastra harness today. The Claude harness emits it through
|
|
124
|
+
* the per-server discovery telemetry triple (started → completed/failed) but
|
|
125
|
+
* not as a standalone transition event — both harnesses converge on the same
|
|
126
|
+
* `McpServerInfo[]` shape via `getMcpServerInfo()`.
|
|
112
127
|
*/
|
|
113
|
-
export type
|
|
128
|
+
export type McpServerStatusChangedEvent = Base<'mcp-server-status-changed'> & {
|
|
114
129
|
agentId: string;
|
|
115
|
-
|
|
130
|
+
serverName: string;
|
|
131
|
+
previousStatus: McpServerStatus;
|
|
132
|
+
nextStatus: McpServerStatus;
|
|
133
|
+
/** Populated when `nextStatus === 'error'`. */
|
|
134
|
+
error?: string;
|
|
116
135
|
};
|
|
117
|
-
export type TelemetryEvent = AgentCreatedEvent | AgentDestroyedEvent | SessionCreatedEvent | SessionDestroyedEvent | ChatStreamStartedEvent | ChatStreamCompletedEvent | ChatStreamErrorEvent | ToolExecutionStartedEvent | ToolExecutionCompletedEvent | ToolApprovalRequestedEvent | ToolApprovalResolvedEvent | McpServerDiscoveryStartedEvent | McpServerDiscoveryCompletedEvent | McpServerDiscoveryFailedEvent |
|
|
136
|
+
export type TelemetryEvent = AgentCreatedEvent | AgentDestroyedEvent | SessionCreatedEvent | SessionDestroyedEvent | ChatStreamStartedEvent | ChatStreamCompletedEvent | ChatStreamErrorEvent | ToolExecutionStartedEvent | ToolExecutionCompletedEvent | ToolApprovalRequestedEvent | ToolApprovalResolvedEvent | McpServerDiscoveryStartedEvent | McpServerDiscoveryCompletedEvent | McpServerDiscoveryFailedEvent | McpServerStatusChangedEvent;
|
|
118
137
|
export type TelemetryEventCallback = (event: TelemetryEvent) => void;
|
|
119
138
|
export type TelemetryBus = EventBus<TelemetryEvent>;
|
|
120
139
|
export {};
|
package/dist/types/tools.d.ts
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import type { McpToolAnnotations } from '../mcp-config.js';
|
|
2
2
|
/**
|
|
3
|
-
* Declares a consumer-executed tool that an agent can invoke.
|
|
3
|
+
* Declares a **consumer-executed (client-side) tool** that an agent can invoke.
|
|
4
4
|
*
|
|
5
5
|
* Tools declared here are schema-only: the harness registers the name,
|
|
6
6
|
* description, and input schema with the model so it can generate tool-call
|
|
7
7
|
* chunks, but the harness never executes these tools itself. When the model
|
|
8
8
|
* calls one, the stream ends with `finishReason: 'tool-calls'` and the
|
|
9
9
|
* consumer is responsible for running the tool locally and feeding the result
|
|
10
|
-
* back via
|
|
10
|
+
* back via {@link ChatSession.submitToolResult}.
|
|
11
|
+
*
|
|
12
|
+
* Typical flow:
|
|
13
|
+
* 1. Pass `{ tools: [{ name, description, inputSchema }] }` in `AgentConfig`.
|
|
14
|
+
* 2. Iterate `eventStream` from `session.chat(...)`; capture the `tool-call`
|
|
15
|
+
* event for one of your declared tools.
|
|
16
|
+
* 3. Run the tool locally (HTTP call, DB query, UI prompt — anything).
|
|
17
|
+
* 4. Call `session.submitToolResult({ toolCallId, toolName, result, isError })`
|
|
18
|
+
* with the same `toolCallId` from the event. Iterate the returned
|
|
19
|
+
* `ChatStreamResult.eventStream` for the model's next turn.
|
|
11
20
|
*
|
|
12
21
|
* For harness-executed (native) tools such as MCP tools, use
|
|
13
|
-
* `AgentConfig.mcpServers
|
|
14
|
-
*
|
|
22
|
+
* `AgentConfig.mcpServers` — those run in the harness and never need
|
|
23
|
+
* `submitToolResult`. To gate harness-executed tool calls with human approval,
|
|
24
|
+
* use `StreamOptions.requireToolApproval` plus `approveToolCall` /
|
|
25
|
+
* `declineToolCall`.
|
|
15
26
|
*
|
|
16
27
|
* Structurally compatible with AI SDK `LanguageModelV4FunctionTool`.
|
|
17
28
|
*/
|
|
@@ -53,15 +64,26 @@ export type ToolCallInfo = {
|
|
|
53
64
|
/**
|
|
54
65
|
* Base shape for a tool result.
|
|
55
66
|
*
|
|
56
|
-
*
|
|
67
|
+
* Used by {@link ChatSession.submitToolResult} to feed a consumer-executed tool's
|
|
68
|
+
* output back into the agent loop. Extended by {@link ToolResultPart} (message
|
|
69
|
+
* content) and {@link ToolResultEvent} (stream event).
|
|
70
|
+
*
|
|
71
|
+
* `toolCallId` and `toolName` MUST match the values from the originating
|
|
72
|
+
* `tool-call` event the consumer observed on the chat eventStream — that's how
|
|
73
|
+
* the harness pairs the result with the suspended call.
|
|
57
74
|
*/
|
|
58
75
|
export type ToolResultInfo = {
|
|
59
76
|
/** Identifier linking this result to the originating tool call. */
|
|
60
77
|
toolCallId: string;
|
|
61
78
|
/** Name of the tool that produced this result. */
|
|
62
79
|
toolName: string;
|
|
63
|
-
/** The tool's output value. */
|
|
80
|
+
/** The tool's output value. Pass through whatever your tool produced. */
|
|
64
81
|
result: unknown;
|
|
65
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Set to `true` to signal that the tool execution failed. The model
|
|
84
|
+
* receives a structured error and can recover (apologize, retry with
|
|
85
|
+
* different args, ask the user, etc.) rather than seeing the failure as
|
|
86
|
+
* the SDK or harness crashing.
|
|
87
|
+
*/
|
|
66
88
|
isError?: boolean;
|
|
67
89
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/sfdx-agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Harness-agnostic agentic infrastructure for Salesforce developer experience tooling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"LICENSE.txt"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@salesforce/agentic-common": "0.
|
|
39
|
-
"@salesforce/llm-gateway-sdk": "0.
|
|
38
|
+
"@salesforce/agentic-common": "0.6.0",
|
|
39
|
+
"@salesforce/llm-gateway-sdk": "0.7.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@eslint/js": "^10.0.1",
|
|
43
|
-
"@salesforce/sfdx-agent-harness-claude": "0.
|
|
44
|
-
"@salesforce/sfdx-agent-harness-mastra": "0.
|
|
43
|
+
"@salesforce/sfdx-agent-harness-claude": "0.6.0",
|
|
44
|
+
"@salesforce/sfdx-agent-harness-mastra": "0.9.0",
|
|
45
45
|
"@types/node": "^22.19.17",
|
|
46
46
|
"@vitest/coverage-istanbul": "^4.1.7",
|
|
47
47
|
"@vitest/eslint-plugin": "^1.6.17",
|