@salesforce/sfdx-agent-sdk 0.7.0 → 0.9.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 CHANGED
@@ -129,23 +129,24 @@ A configured AI agent. Factory for chat sessions. The optional `H` type paramete
129
129
  — harness-specific features are reached through `manager.extensions`, not `agent.extensions`. The default `AgentHarness`
130
130
  keeps unparameterized call sites working.
131
131
 
132
- | Method | Signature | Description |
133
- | ---------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
134
- | `getId` | `() => string` | Agent identifier. |
135
- | `getProjectRoot` | `() => string` | Absolute project path. |
136
- | `getOrgConnectionInfo` | `() => OrgConnectionInfo` | Org metadata (orgId, alias, instanceUrl, username, env). |
137
- | `getAgentConfig` | `() => AgentConfig` | Current configuration (shallow copy). |
138
- | `getMcpServerInfo` | `() => McpServerInfo[]` | MCP server status and discovered tools. |
139
- | `updateAgentConfig` | `(config?: AgentConfig, options?: { abortSignal?: AbortSignal }) => Promise<void>` | Merge new config into the live agent. |
140
- | `createChatSession` | `() => Promise<ChatSession>` | Open a new conversation thread. |
141
- | `getChatSession` | `(sessionId: string) => ChatSession` | Retrieve a session. Throws `AgentSDKError` (`CHAT_SESSION_NOT_FOUND`). |
142
- | `getChatSessionIds` | `() => string[]` | List active session IDs. |
143
- | `destroyChatSession` | `(sessionId: string) => Promise<void>` | Destroy a session and its history. |
144
- | `cloneChatSession` | `(sourceSessionId: string) => Promise<ChatSession>` | Clone a session with its message history. |
145
- | `compactChatSession` | `(sessionId: string) => Promise<ChatSession>` | Compact a session into a summarized new session. |
146
- | `destroy` | `() => Promise<void>` | Destroy the agent and all its sessions. |
147
- | `onTelemetry` | `(callback: TelemetryEventCallback) => Unsubscribe` | Subscribe to telemetry scoped to this agent (and its sessions). |
148
- | `onLog` | `(callback: (record: LogRecord) => void) => Unsubscribe` | Subscribe to logs scoped to this agent (and its sessions). |
132
+ | Method | Signature | Description |
133
+ | ---------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
134
+ | `getId` | `() => string` | Agent identifier. |
135
+ | `getProjectRoot` | `() => string` | Absolute project path. |
136
+ | `getOrgConnectionInfo` | `() => OrgConnectionInfo` | Org metadata (orgId, alias, instanceUrl, username, env). |
137
+ | `getAgentConfig` | `() => AgentConfig` | Current configuration (shallow copy). |
138
+ | `getMcpServerInfo` | `() => McpServerInfo[]` | MCP server status and discovered tools. |
139
+ | `reconnectMcpServer` | `(serverName: string) => Promise<void>` | Recover one MCP server without recycling the agent. Semantics vary by harness — observe via `getMcpServerInfo()` and discovery telemetry. |
140
+ | `updateAgentConfig` | `(config?: AgentConfig, options?: { abortSignal?: AbortSignal }) => Promise<void>` | Merge new config into the live agent. |
141
+ | `createChatSession` | `() => Promise<ChatSession>` | Open a new conversation thread. |
142
+ | `getChatSession` | `(sessionId: string) => ChatSession` | Retrieve a session. Throws `AgentSDKError` (`CHAT_SESSION_NOT_FOUND`). |
143
+ | `getChatSessionIds` | `() => string[]` | List active session IDs. |
144
+ | `destroyChatSession` | `(sessionId: string) => Promise<void>` | Destroy a session and its history. |
145
+ | `cloneChatSession` | `(sourceSessionId: string) => Promise<ChatSession>` | Clone a session with its message history. |
146
+ | `compactChatSession` | `(sessionId: string) => Promise<ChatSession>` | Compact a session into a summarized new session. |
147
+ | `destroy` | `() => Promise<void>` | Destroy the agent and all its sessions. |
148
+ | `onTelemetry` | `(callback: TelemetryEventCallback) => Unsubscribe` | Subscribe to telemetry scoped to this agent (and its sessions). |
149
+ | `onLog` | `(callback: (record: LogRecord) => void) => Unsubscribe` | Subscribe to logs scoped to this agent (and its sessions). |
149
150
 
150
151
  ### `ChatSession`
151
152
 
@@ -180,19 +181,19 @@ Returned by `chat()`, `submitToolResult()`, `approveToolCall()`, and `declineToo
180
181
 
181
182
  Discriminated union (`event.type`) of streaming events:
182
183
 
183
- | Type | Key Fields | Description |
184
- | ----------------------- | ---------------------------------------------- | -------------------------------------------------------- |
185
- | `start` | — | Stream has begun. |
186
- | `text-delta` | `text` | Incremental response text. |
187
- | `reasoning-delta` | `text` | Chain-of-thought fragment. |
188
- | `tool-call` | `toolCallId`, `toolName`, `args` | Tool invocation. |
189
- | `tool-approval-request` | `toolCall: ToolCallInfo` | Engine requests approval before executing a tool. |
190
- | `tool-result` | `toolCallId`, `toolName`, `result`, `isError?` | Tool execution completed. |
191
- | `step-start` | `stepIndex` | New LLM invocation step began. |
192
- | `step-finish` | `stepIndex`, `finishReason`, `usage?` | Step completed with per-step token usage. |
193
- | `error` | `error`, `code?` | Mid-stream error (yielded, not thrown). |
194
- | `finish` | `finishReason`, `usage?` | Stream completed with aggregate token usage. |
195
- | `unmapped-chunk` | `chunkType`, `rawChunk` | Unrecognized harness event, preserved for observability. |
184
+ | Type | Key Fields | Description |
185
+ | ----------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
186
+ | `start` | — | Stream has begun. |
187
+ | `text-delta` | `text` | Incremental response text. |
188
+ | `reasoning-delta` | `text` | Chain-of-thought fragment. |
189
+ | `tool-call` | `toolCallId`, `toolName`, `args`, `annotations?`, `serverName?` | Tool invocation. `annotations` is the MCP-spec hints (`readOnlyHint`, `destructiveHint`, …) when the source declared them; `serverName` is set when the tool came from an MCP server. |
190
+ | `tool-approval-request` | `toolCall: ToolCallInfo`, `annotations?`, `serverName?` | Engine requests approval before executing a tool. Same `annotations` / `serverName` semantics as `tool-call`. |
191
+ | `tool-result` | `toolCallId`, `toolName`, `result`, `isError?`, `annotations?`, `serverName?` | Tool execution completed. Same `annotations` / `serverName` semantics as `tool-call`. |
192
+ | `step-start` | `stepIndex` | New LLM invocation step began. |
193
+ | `step-finish` | `stepIndex`, `finishReason`, `usage?` | Step completed with per-step token usage. |
194
+ | `error` | `error`, `code?` | Mid-stream error (yielded, not thrown). |
195
+ | `finish` | `finishReason`, `usage?` | Stream completed with aggregate token usage. |
196
+ | `unmapped-chunk` | `chunkType`, `rawChunk` | Unrecognized harness event, preserved for observability. |
196
197
 
197
198
  ### Configuration Types
198
199
 
@@ -302,6 +303,10 @@ type ToolDefinition = {
302
303
  name: string;
303
304
  description?: string;
304
305
  inputSchema: Record<string, unknown>;
306
+ // Optional MCP-spec UI/behavioral hints. Consumer-declared tools can carry
307
+ // the same hints as MCP-discovered tools and receive matching UI treatment.
308
+ // Example: `{ name: 'read_doc', annotations: { readOnlyHint: true } }`.
309
+ annotations?: McpToolAnnotations;
305
310
  };
306
311
 
307
312
  type ToolCallInfo = {
@@ -357,6 +362,8 @@ from `AgentSDKErrorType`:
357
362
  | `COMPACTION_FAILED` | `Agent.compactChatSession()` when the harness's underlying summarization call rejects. The original error is attached as `cause`; the source session is left intact. |
358
363
  | `DISPOSED` | `Agent` and `ChatSession` methods called after the owner has been destroyed |
359
364
  | `INCOMPATIBLE_HARNESS` | `createAgentManager()` when the factory advertises an unsupported `protocolVersion`, or the constructed harness reports a `protocolVersion` that differs from the factory's |
365
+ | `MCP_SERVER_DISABLED` | `Agent.reconnectMcpServer()` when the named server is configured with `enabled: false` |
366
+ | `MCP_SERVER_NOT_FOUND` | `Agent.reconnectMcpServer()` when the server name is not in the agent's `mcpServers` config |
360
367
 
361
368
  ```typescript
362
369
  import { AgentSDKError, AgentSDKErrorType } from '@salesforce/sfdx-agent-sdk';
@@ -417,6 +424,11 @@ for (const s of servers) {
417
424
 
418
425
  ### Tool Approval Flow
419
426
 
427
+ `tool-call`, `tool-result`, and `tool-approval-request` events all carry optional `annotations` and `serverName` so
428
+ consumers can branch on tool hints (e.g. auto-approve `readOnlyHint`) or group by originating MCP server without
429
+ reparsing namespaced tool names. `annotations` is `undefined` when the source did not declare them (per the MCP spec);
430
+ `serverName` is `undefined` when the tool is not from an MCP server.
431
+
420
432
  ```typescript
421
433
  const { eventStream } = await session.chat('Run the deployment', {
422
434
  requireToolApproval: true,
@@ -424,9 +436,21 @@ const { eventStream } = await session.chat('Run the deployment', {
424
436
 
425
437
  for await (const event of eventStream) {
426
438
  if (event.type === 'tool-approval-request') {
427
- const continuation = await session.approveToolCall(event.toolCall.toolCallId);
428
- for await (const e of continuation.eventStream) {
429
- // process continuation
439
+ if (event.annotations?.readOnlyHint) {
440
+ // Safe read auto-approve.
441
+ const continuation = await session.approveToolCall(event.toolCall.toolCallId);
442
+ for await (const e of continuation.eventStream) {
443
+ // process continuation
444
+ }
445
+ } else {
446
+ // Route to the user; group/label by event.serverName when set.
447
+ const approved = await promptUser(event);
448
+ const continuation = approved
449
+ ? await session.approveToolCall(event.toolCall.toolCallId)
450
+ : await session.declineToolCall(event.toolCall.toolCallId);
451
+ for await (const e of continuation.eventStream) {
452
+ // process continuation
453
+ }
430
454
  }
431
455
  }
432
456
  }
@@ -670,13 +694,17 @@ All variants share `{ type: <discriminant>, timestamp: Date }` plus the fields b
670
694
  | `chat-stream-started` | `agentId`, `threadId`, `trigger` (`'chat' \| 'submit-tool-result' \| 'approve-tool-call' \| 'decline-tool-call'`) |
671
695
  | `chat-stream-completed` | `agentId`, `threadId`, `durationMs`, `usage?` |
672
696
  | `chat-stream-error` | `agentId`, `threadId`, `durationMs`, `error` |
673
- | `tool-execution-started` | `agentId`, `threadId`, `toolCallId`, `toolName` |
674
- | `tool-execution-completed` | `agentId`, `threadId`, `toolCallId`, `toolName`, `durationMs`, `isError` |
675
- | `tool-approval-requested` | `agentId`, `threadId`, `toolCallId`, `toolName` |
697
+ | `tool-execution-started` | `agentId`, `threadId`, `toolCallId`, `toolName`, `annotations?`, `serverName?` |
698
+ | `tool-execution-completed` | `agentId`, `threadId`, `toolCallId`, `toolName`, `durationMs`, `isError`, `annotations?`, `serverName?` |
699
+ | `tool-approval-requested` | `agentId`, `threadId`, `toolCallId`, `toolName`, `annotations?`, `serverName?` |
676
700
  | `tool-approval-resolved` | `agentId`, `threadId`, `toolCallId`, `approved` |
677
701
  | `mcp-server-discovery-started` | `agentId`, `serverName` |
678
702
  | `mcp-server-discovery-completed` | `agentId`, `serverName`, `toolCount`, `durationMs` |
679
703
  | `mcp-server-discovery-failed` | `agentId`, `serverName`, `durationMs`, `error` |
704
+ | `mcp-discovery-snapshot` | `agentId`, `servers` (`McpServerInfo[]`) |
705
+
706
+ `mcp-discovery-snapshot` is emitted by harnesses whose runtime exposes aggregate MCP server status (currently only the
707
+ Claude harness, once per `init` arrival). Its `servers` payload mirrors `agent.getMcpServerInfo()`.
680
708
 
681
709
  Every chat entry point (`chat`, `submitToolResult`, `approveToolCall`, `declineToolCall`) emits exactly one
682
710
  `chat-stream-started` followed by exactly one terminal event — either `chat-stream-completed` (natural completion) or
package/dist/agent.d.ts CHANGED
@@ -41,6 +41,27 @@ export interface Agent {
41
41
  * snapshot — status is updated asynchronously by background discovery promises.
42
42
  */
43
43
  getMcpServerInfo(): McpServerInfo[];
44
+ /**
45
+ * Request a reconnect of one MCP server on this agent without recycling
46
+ * any other server, custom tool, instruction, or skill. Useful for
47
+ * recovering a single failed MCP server without paying the full
48
+ * `updateAgentConfig` destroy/recreate cost.
49
+ *
50
+ * Throws if `serverName` is not configured on this agent or if the named
51
+ * server is disabled (`enabled: false`).
52
+ *
53
+ * **Semantics vary by harness.** Some harnesses await transport reconnect
54
+ * + discovery before this resolves (eager); others schedule the work and
55
+ * resolve as soon as the request is accepted (deferred — the actual
56
+ * reconnect happens on the next opportunity, typically the next stream).
57
+ * Consumers observe the result through {@link getMcpServerInfo} and the
58
+ * harness's MCP-discovery telemetry events, not the returned promise's
59
+ * resolution. Discovery / transport failures are reported on the
60
+ * per-server status, not by rejecting this promise.
61
+ *
62
+ * @param serverName - Name of the MCP server to reconnect.
63
+ */
64
+ reconnectMcpServer(serverName: string): Promise<void>;
44
65
  /**
45
66
  * Update the agent's configuration. The harness applies the changes
46
67
  * to the live agent (e.g., new instructions, tools, model).
@@ -152,6 +173,7 @@ export declare class DefaultAgent implements Agent {
152
173
  */
153
174
  getAgentConfig(): AgentConfig;
154
175
  getMcpServerInfo(): McpServerInfo[];
176
+ reconnectMcpServer(serverName: string): Promise<void>;
155
177
  /**
156
178
  * @requirements
157
179
  * - MUST merge the provided `config` with the internal `config` object.
package/dist/agent.js CHANGED
@@ -91,6 +91,10 @@ export class DefaultAgent {
91
91
  this.assertNotDisposed();
92
92
  return this.harness.getMcpServerInfo(this.agentId);
93
93
  }
94
+ async reconnectMcpServer(serverName) {
95
+ this.assertNotDisposed();
96
+ await this.harness.reconnectMcpServer(this.agentId, serverName);
97
+ }
94
98
  /**
95
99
  * @requirements
96
100
  * - MUST merge the provided `config` with the internal `config` object.
@@ -326,6 +326,8 @@ export class DefaultChatSession {
326
326
  threadId: this.threadId,
327
327
  toolCallId: event.toolCallId,
328
328
  toolName: event.toolName,
329
+ ...(event.annotations ? { annotations: event.annotations } : {}),
330
+ ...(event.serverName ? { serverName: event.serverName } : {}),
329
331
  });
330
332
  }
331
333
  else if (event.type === 'tool-result') {
@@ -342,6 +344,8 @@ export class DefaultChatSession {
342
344
  toolName: event.toolName,
343
345
  durationMs: this.clock.now().getTime() - start,
344
346
  isError: event.isError === true,
347
+ ...(event.annotations ? { annotations: event.annotations } : {}),
348
+ ...(event.serverName ? { serverName: event.serverName } : {}),
345
349
  });
346
350
  }
347
351
  else if (event.type === 'tool-approval-request') {
@@ -352,6 +356,8 @@ export class DefaultChatSession {
352
356
  threadId: this.threadId,
353
357
  toolCallId: event.toolCall.toolCallId,
354
358
  toolName: event.toolCall.toolName,
359
+ ...(event.annotations ? { annotations: event.annotations } : {}),
360
+ ...(event.serverName ? { serverName: event.serverName } : {}),
355
361
  });
356
362
  }
357
363
  }
package/dist/errors.d.ts CHANGED
@@ -4,6 +4,8 @@ export declare const AgentSDKErrorType: {
4
4
  readonly COMPACTION_FAILED: "COMPACTION_FAILED";
5
5
  readonly DISPOSED: "DISPOSED";
6
6
  readonly INCOMPATIBLE_HARNESS: "INCOMPATIBLE_HARNESS";
7
+ readonly MCP_SERVER_DISABLED: "MCP_SERVER_DISABLED";
8
+ readonly MCP_SERVER_NOT_FOUND: "MCP_SERVER_NOT_FOUND";
7
9
  readonly NOT_SUPPORTED: "NOT_SUPPORTED";
8
10
  };
9
11
  export type AgentSDKErrorType = (typeof AgentSDKErrorType)[keyof typeof AgentSDKErrorType];
package/dist/errors.js CHANGED
@@ -8,6 +8,8 @@ export const AgentSDKErrorType = {
8
8
  COMPACTION_FAILED: 'COMPACTION_FAILED',
9
9
  DISPOSED: 'DISPOSED',
10
10
  INCOMPATIBLE_HARNESS: 'INCOMPATIBLE_HARNESS',
11
+ MCP_SERVER_DISABLED: 'MCP_SERVER_DISABLED',
12
+ MCP_SERVER_NOT_FOUND: 'MCP_SERVER_NOT_FOUND',
11
13
  NOT_SUPPORTED: 'NOT_SUPPORTED',
12
14
  };
13
15
  export class AgentSDKError extends Error {
@@ -128,6 +128,34 @@ export interface AgentHarness {
128
128
  * @returns Info for each configured MCP server (empty array if none configured).
129
129
  */
130
130
  getMcpServerInfo(agentId: string): McpServerInfo[];
131
+ /**
132
+ * Request a reconnect of one MCP server attached to the agent without
133
+ * recycling any other server, custom tool, instruction, or skill.
134
+ *
135
+ * **Scheduled-minimum contract.** Implementors MUST validate the request
136
+ * (unknown agent id / unknown server name / disabled server reject) and
137
+ * MUST cause the named server to be reconnected. They MAY satisfy the
138
+ * reconnect eagerly (await transport reconnect + discovery before
139
+ * resolving) or schedule it (resolve once the request is accepted; carry
140
+ * out the work on the next opportunity, e.g. the next stream). Consumers
141
+ * observe the result via {@link getMcpServerInfo} and the harness's
142
+ * MCP-discovery telemetry events, not the returned promise's resolution.
143
+ *
144
+ * Implementors MUST:
145
+ * - throw if `agentId` is not registered.
146
+ * - throw if `serverName` is not configured on this agent.
147
+ * - throw if `serverName` is configured but disabled (`enabled: false`).
148
+ *
149
+ * Implementors MUST NOT:
150
+ * - reject on transient transport / discovery failure — record those on
151
+ * the per-server status (visible via {@link getMcpServerInfo}).
152
+ * - mutate `AgentConfig` or persist anything — reconnect is a runtime
153
+ * operation, not a config update.
154
+ *
155
+ * @param agentId - ID of the agent owning the server.
156
+ * @param serverName - Name of the MCP server to reconnect.
157
+ */
158
+ reconnectMcpServer(agentId: string, serverName: string): Promise<void>;
131
159
  /**
132
160
  * Create a new conversation thread for an agent.
133
161
  * @param agentId - ID of the owning agent.
package/dist/index.d.ts CHANGED
@@ -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, McpServerDiscoveryCompletedEvent, McpServerDiscoveryFailedEvent, McpServerDiscoveryStartedEvent, SessionCreatedEvent, SessionDestroyedEvent, TelemetryEvent, TelemetryEventCallback, ToolApprovalRequestedEvent, ToolApprovalResolvedEvent, ToolExecutionCompletedEvent, ToolExecutionStartedEvent, } from './types/telemetry-events.js';
19
+ export type { AgentCreatedEvent, AgentDestroyedEvent, ChatStreamCompletedEvent, ChatStreamErrorEvent, ChatStreamStartedEvent, ChatStreamTrigger, McpDiscoverySnapshotEvent, McpServerDiscoveryCompletedEvent, McpServerDiscoveryFailedEvent, McpServerDiscoveryStartedEvent, 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';
@@ -1,3 +1,4 @@
1
+ import type { McpToolAnnotations } from '../mcp-config.js';
1
2
  import type { ToolCallInfo, ToolResultInfo } from './tools.js';
2
3
  import type { FinishReason, UsageMetadata } from './usage.js';
3
4
  /**
@@ -47,9 +48,25 @@ export type ReasoningDeltaEvent = {
47
48
  *
48
49
  * Extends {@link ToolCallInfo} with a discriminator type for use in the
49
50
  * {@link ChatEvent} discriminated union.
51
+ *
52
+ * `annotations` and `serverName` are populated by the harness when the tool is
53
+ * in an MCP server's catalog, mirroring the enrichment on
54
+ * {@link ToolApprovalRequestEvent}. They are stream-event metadata — not part
55
+ * of {@link ToolCallInfo} — so persisted message history (`MessagePart`s) does
56
+ * not carry per-stream MCP enrichment.
50
57
  */
51
58
  export type ToolCallEvent = ToolCallInfo & {
52
59
  type: 'tool-call';
60
+ /**
61
+ * Behavioral / UI-presentation hints declared for the tool. See
62
+ * {@link ToolApprovalRequestEvent.annotations}.
63
+ */
64
+ annotations?: McpToolAnnotations;
65
+ /**
66
+ * Originating MCP server name when the tool was discovered through an MCP
67
+ * server. `undefined` for consumer-declared tools or workspace tools.
68
+ */
69
+ serverName?: string;
53
70
  };
54
71
  /**
55
72
  * The harness is requesting approval before executing a tool call.
@@ -65,15 +82,42 @@ export type ToolApprovalRequestEvent = {
65
82
  type: 'tool-approval-request';
66
83
  /** The tool call awaiting approval. */
67
84
  toolCall: ToolCallInfo;
85
+ /**
86
+ * Behavioral / UI-presentation hints declared for the tool. Populated by
87
+ * the harness when the tool is in an MCP server's tool catalog and the
88
+ * server declared annotations; `undefined` when the source did not declare
89
+ * them (per the MCP spec) or the tool is not from an MCP server.
90
+ */
91
+ annotations?: McpToolAnnotations;
92
+ /**
93
+ * Originating MCP server name when the tool was discovered through an MCP
94
+ * server. `undefined` for consumer-declared tools or workspace tools that
95
+ * have no MCP origin.
96
+ */
97
+ serverName?: string;
68
98
  };
69
99
  /**
70
100
  * A real-time stream event indicating a tool execution has completed.
71
101
  *
72
102
  * Extends {@link ToolResultInfo} with a discriminator type for use in the
73
103
  * {@link ChatEvent} discriminated union.
104
+ *
105
+ * `annotations` and `serverName` are populated by the harness when the tool is
106
+ * in an MCP server's catalog, mirroring the enrichment on
107
+ * {@link ToolApprovalRequestEvent} and {@link ToolCallEvent}.
74
108
  */
75
109
  export type ToolResultEvent = ToolResultInfo & {
76
110
  type: 'tool-result';
111
+ /**
112
+ * Behavioral / UI-presentation hints declared for the tool. See
113
+ * {@link ToolApprovalRequestEvent.annotations}.
114
+ */
115
+ annotations?: McpToolAnnotations;
116
+ /**
117
+ * Originating MCP server name when the tool was discovered through an MCP
118
+ * server. `undefined` for consumer-declared tools or workspace tools.
119
+ */
120
+ serverName?: string;
77
121
  };
78
122
  /**
79
123
  * Marks the beginning of a new LLM invocation within a multi-step agentic loop.
@@ -1,4 +1,5 @@
1
1
  import type { EventBus } from '@salesforce/agentic-common';
2
+ import type { McpServerInfo, McpToolAnnotations } from '../mcp-config.js';
2
3
  import type { UsageMetadata } from './usage.js';
3
4
  /**
4
5
  * Telemetry events emitted by the Agent SDK.
@@ -50,6 +51,10 @@ export type ToolExecutionStartedEvent = Base<'tool-execution-started'> & {
50
51
  threadId: string;
51
52
  toolCallId: string;
52
53
  toolName: string;
54
+ /** Annotations declared for the tool, when available. See {@link ToolApprovalRequestEvent.annotations}. */
55
+ annotations?: McpToolAnnotations;
56
+ /** Originating MCP server name, when the tool was discovered through MCP. */
57
+ serverName?: string;
53
58
  };
54
59
  export type ToolExecutionCompletedEvent = Base<'tool-execution-completed'> & {
55
60
  agentId: string;
@@ -58,12 +63,20 @@ export type ToolExecutionCompletedEvent = Base<'tool-execution-completed'> & {
58
63
  toolName: string;
59
64
  durationMs: number;
60
65
  isError: boolean;
66
+ /** Annotations declared for the tool, when available. See {@link ToolApprovalRequestEvent.annotations}. */
67
+ annotations?: McpToolAnnotations;
68
+ /** Originating MCP server name, when the tool was discovered through MCP. */
69
+ serverName?: string;
61
70
  };
62
71
  export type ToolApprovalRequestedEvent = Base<'tool-approval-requested'> & {
63
72
  agentId: string;
64
73
  threadId: string;
65
74
  toolCallId: string;
66
75
  toolName: string;
76
+ /** Annotations declared for the tool, when available. See {@link ToolApprovalRequestEvent.annotations}. */
77
+ annotations?: McpToolAnnotations;
78
+ /** Originating MCP server name, when the tool was discovered through MCP. */
79
+ serverName?: string;
67
80
  };
68
81
  export type ToolApprovalResolvedEvent = Base<'tool-approval-resolved'> & {
69
82
  agentId: string;
@@ -87,7 +100,21 @@ export type McpServerDiscoveryFailedEvent = Base<'mcp-server-discovery-failed'>
87
100
  durationMs: number;
88
101
  error: Error;
89
102
  };
90
- export type TelemetryEvent = AgentCreatedEvent | AgentDestroyedEvent | SessionCreatedEvent | SessionDestroyedEvent | ChatStreamStartedEvent | ChatStreamCompletedEvent | ChatStreamErrorEvent | ToolExecutionStartedEvent | ToolExecutionCompletedEvent | ToolApprovalRequestedEvent | ToolApprovalResolvedEvent | McpServerDiscoveryStartedEvent | McpServerDiscoveryCompletedEvent | McpServerDiscoveryFailedEvent;
103
+ /**
104
+ * Whole-snapshot MCP discovery event emitted by harnesses whose underlying SDK
105
+ * surfaces MCP status in a single aggregate message rather than as per-server
106
+ * lifecycle events. Currently emitted by the Claude harness on each
107
+ * `SDKSystemMessage init` arrival.
108
+ *
109
+ * The `servers` payload mirrors the result of `harness.getMcpServerInfo(agentId)`
110
+ * at the moment of the snapshot, so consumers can read status + tools without
111
+ * a follow-up call.
112
+ */
113
+ export type McpDiscoverySnapshotEvent = Base<'mcp-discovery-snapshot'> & {
114
+ agentId: string;
115
+ servers: McpServerInfo[];
116
+ };
117
+ export type TelemetryEvent = AgentCreatedEvent | AgentDestroyedEvent | SessionCreatedEvent | SessionDestroyedEvent | ChatStreamStartedEvent | ChatStreamCompletedEvent | ChatStreamErrorEvent | ToolExecutionStartedEvent | ToolExecutionCompletedEvent | ToolApprovalRequestedEvent | ToolApprovalResolvedEvent | McpServerDiscoveryStartedEvent | McpServerDiscoveryCompletedEvent | McpServerDiscoveryFailedEvent | McpDiscoverySnapshotEvent;
91
118
  export type TelemetryEventCallback = (event: TelemetryEvent) => void;
92
119
  export type TelemetryBus = EventBus<TelemetryEvent>;
93
120
  export {};
@@ -1,3 +1,4 @@
1
+ import type { McpToolAnnotations } from '../mcp-config.js';
1
2
  /**
2
3
  * Declares a consumer-executed tool that an agent can invoke.
3
4
  *
@@ -24,6 +25,15 @@ export type ToolDefinition = {
24
25
  * Harnesses use this to validate arguments before execution.
25
26
  */
26
27
  inputSchema: Record<string, unknown>;
28
+ /**
29
+ * Behavioral / UI-presentation hints for this tool. Mirrors the MCP
30
+ * protocol's `Tool.annotations` shape so consumer-declared tools can carry
31
+ * the same hints (`readOnlyHint`, `destructiveHint`, `idempotentHint`,
32
+ * `openWorldHint`, `title`) as MCP-discovered tools and receive matching
33
+ * UI treatment. Absence of a field means "the author did not declare this
34
+ * hint," not "false."
35
+ */
36
+ annotations?: McpToolAnnotations;
27
37
  };
28
38
  /**
29
39
  * Base shape for a tool call.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/sfdx-agent-sdk",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Harness-agnostic agentic infrastructure for Salesforce developer experience tooling",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,12 +35,13 @@
35
35
  "LICENSE.txt"
36
36
  ],
37
37
  "dependencies": {
38
- "@salesforce/agentic-common": "0.4.0",
39
- "@salesforce/llm-gateway-sdk": "0.4.0"
38
+ "@salesforce/agentic-common": "0.5.0",
39
+ "@salesforce/llm-gateway-sdk": "0.6.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@eslint/js": "^10.0.1",
43
- "@salesforce/sfdx-agent-harness-mastra": "0.6.0",
43
+ "@salesforce/sfdx-agent-harness-claude": "0.5.0",
44
+ "@salesforce/sfdx-agent-harness-mastra": "0.8.0",
44
45
  "@types/node": "^22.19.17",
45
46
  "@vitest/coverage-istanbul": "^4.1.7",
46
47
  "@vitest/eslint-plugin": "^1.6.17",