@salesforce/sfdx-agent-sdk 0.40.0 → 0.41.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 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.41.0] - 2026-08-03
7
+
8
+ ### Features
9
+ - **agent-sdk,harnesses**: emit Tier-1 logBus siblings for lifecycle telemetry @W-23547150@ ([#716](https://github.com/forcedotcom/agentic-dx/pull/716))
10
+
6
11
  ## [0.40.0] - 2026-08-03
7
12
 
8
13
  ### Features
package/README.md CHANGED
@@ -1546,6 +1546,13 @@ Abandoning the iterator mid-stream emits no terminal telemetry — the stream di
1546
1546
  Harness implementations may emit additional structured logs through their own `LogBus`. Those records surface to
1547
1547
  consumers via the same `onLog` channel.
1548
1548
 
1549
+ Selected lifecycle moments are reported on **both** channels: the typed telemetry event, plus a log record carrying the
1550
+ same facts for log sinks. On those records `message` is human-readable prose intended for display and may be reworded;
1551
+ `context.event_type` carries the matching `TelemetryEvent` type and is the stable field to filter, alert, and join on.
1552
+ Records paired this way today are `agent-created`, `agent-destroyed`, `session-created`, `session-destroyed`,
1553
+ `chat-stream-completed`, `chat-stream-error`, `tool-execution-completed` (only when `isError` is true), and the harness
1554
+ MCP events `mcp-server-discovery-completed`, `mcp-server-discovery-failed`, and `mcp-server-status-changed`.
1555
+
1549
1556
  ## Development
1550
1557
 
1551
1558
  See [DEVELOPING.md](DEVELOPING.md) for build-from-source setup, scripts, E2E testing, and packaging.
@@ -189,12 +189,20 @@ export class DefaultAgentManager {
189
189
  this.wireRouter.registerAgent(agentId);
190
190
  const agent = new DefaultAgent(this.harness, agentId, projectRoot, config, runtime.modelConnectivityInfo, runtime.orgConnection, runtime.orgJwt, this.agentConnectivityResolver, this.harnessSupportedProviderHints, this.hooksForAgent, this.identityStore, this.router, agentSlice, { telemetry: this.telemetryBus, log: this.logBus }, this.clock, this.agentIdGenerator);
191
191
  this.agents.set(agentId, agent);
192
+ const agentCreatedAt = this.clock.now();
193
+ const modelName = runtime.modelConnectivityInfo.model.name;
192
194
  this.telemetryBus.emit({
193
195
  type: 'agent-created',
194
- timestamp: this.clock.now(),
196
+ timestamp: agentCreatedAt,
195
197
  agentId,
196
198
  projectRoot,
197
- modelName: runtime.modelConnectivityInfo.model.name,
199
+ modelName,
200
+ });
201
+ this.logBus.emit({
202
+ level: 'info',
203
+ message: 'Agent created',
204
+ timestamp: agentCreatedAt,
205
+ context: { event_type: 'agent-created', agentId, projectRoot, modelName },
198
206
  });
199
207
  if (options.rehydrateThreads) {
200
208
  // If thread enumeration or session attachment fails, the restore is a full failure
package/dist/agent.js CHANGED
@@ -283,11 +283,18 @@ export class DefaultAgent {
283
283
  }
284
284
  this.sessions.clear();
285
285
  await this.harness.destroyAgent(this.agentId);
286
+ const agentDestroyedAt = this.clock.now();
286
287
  this.telemetryBus.emit({
287
288
  type: 'agent-destroyed',
288
- timestamp: this.clock.now(),
289
+ timestamp: agentDestroyedAt,
289
290
  agentId: this.agentId,
290
291
  });
292
+ this.logBus.emit({
293
+ level: 'info',
294
+ message: 'Agent destroyed',
295
+ timestamp: agentDestroyedAt,
296
+ context: { event_type: 'agent-destroyed', agentId: this.agentId },
297
+ });
291
298
  for (const unsub of this.inboundUnsubs)
292
299
  unsub();
293
300
  for (const unsub of this.parentUnsubs)
@@ -347,12 +354,19 @@ export class DefaultAgent {
347
354
  }, getContextWindow, { clock: this.clock, idGenerator: this.idGenerator, persistRememberedRule });
348
355
  this.sessions.set(threadId, session);
349
356
  this.sessionSliceUnregisters.set(threadId, () => this.router.unregisterSession(threadId));
357
+ const sessionCreatedAt = this.clock.now();
350
358
  this.telemetryBus.emit({
351
359
  type: 'session-created',
352
- timestamp: this.clock.now(),
360
+ timestamp: sessionCreatedAt,
353
361
  agentId: this.agentId,
354
362
  threadId,
355
363
  });
364
+ this.logBus.emit({
365
+ level: 'info',
366
+ message: 'Chat session created',
367
+ timestamp: sessionCreatedAt,
368
+ context: { event_type: 'session-created', agentId: this.agentId, threadId },
369
+ });
356
370
  return session;
357
371
  }
358
372
  detachSession(threadId, session) {
@@ -237,6 +237,18 @@ export class DefaultChatSession {
237
237
  durationMs,
238
238
  error: lastError,
239
239
  });
240
+ this.logBus.emit({
241
+ level: 'error',
242
+ message: 'Chat stream failed',
243
+ timestamp: finishedAt,
244
+ context: {
245
+ event_type: 'chat-stream-error',
246
+ agentId: this.agentId,
247
+ threadId: this.threadId,
248
+ durationMs,
249
+ },
250
+ error: lastError,
251
+ });
240
252
  }
241
253
  else {
242
254
  this.telemetryBus.emit({
@@ -247,6 +259,18 @@ export class DefaultChatSession {
247
259
  durationMs,
248
260
  usage: finishUsage,
249
261
  });
262
+ this.logBus.emit({
263
+ level: 'info',
264
+ message: 'Chat stream completed',
265
+ timestamp: finishedAt,
266
+ context: {
267
+ event_type: 'chat-stream-completed',
268
+ agentId: this.agentId,
269
+ threadId: this.threadId,
270
+ durationMs,
271
+ ...(finishUsage !== undefined ? { usage: finishUsage } : {}),
272
+ },
273
+ });
250
274
  }
251
275
  }
252
276
  /**
@@ -420,12 +444,23 @@ export class DefaultChatSession {
420
444
  if (this.disposed) {
421
445
  return;
422
446
  }
447
+ const sessionDestroyedAt = this.clock.now();
423
448
  this.telemetryBus.emit({
424
449
  type: 'session-destroyed',
425
- timestamp: this.clock.now(),
450
+ timestamp: sessionDestroyedAt,
426
451
  agentId: this.agentId,
427
452
  threadId: this.threadId,
428
453
  });
454
+ this.logBus.emit({
455
+ level: 'info',
456
+ message: 'Chat session destroyed',
457
+ timestamp: sessionDestroyedAt,
458
+ context: {
459
+ event_type: 'session-destroyed',
460
+ agentId: this.agentId,
461
+ threadId: this.threadId,
462
+ },
463
+ });
429
464
  for (const unsub of this.inboundUnsubs)
430
465
  unsub();
431
466
  for (const unsub of this.parentUnsubs)
@@ -436,6 +471,8 @@ export class DefaultChatSession {
436
471
  this.disposed = true;
437
472
  }
438
473
  emitToolApprovalResolved(toolCallId, approved, policyWritten) {
474
+ // No Tier-1 logBus sibling: tool-approval-resolved fires per gated
475
+ // tool call — interactive-UI signal, not on-call triage
439
476
  this.telemetryBus.emit({
440
477
  type: 'tool-approval-resolved',
441
478
  timestamp: this.clock.now(),
@@ -476,6 +513,8 @@ export class DefaultChatSession {
476
513
  deriveToolTelemetry(event) {
477
514
  if (event.type === 'tool-call') {
478
515
  this.toolStartMs.set(event.toolCallId, this.clock.now().getTime());
516
+ // No Tier-1 logBus sibling: tool-execution-started pairs 1:1 with
517
+ // tool-execution-completed; the completion (isError=true) is the triage signal
479
518
  this.telemetryBus.emit({
480
519
  type: 'tool-execution-started',
481
520
  timestamp: this.clock.now(),
@@ -492,19 +531,42 @@ export class DefaultChatSession {
492
531
  if (start === undefined)
493
532
  return;
494
533
  this.toolStartMs.delete(event.toolCallId);
534
+ const completedAt = this.clock.now();
535
+ const durationMs = completedAt.getTime() - start;
536
+ const isError = event.isError === true;
495
537
  this.telemetryBus.emit({
496
538
  type: 'tool-execution-completed',
497
- timestamp: this.clock.now(),
539
+ timestamp: completedAt,
498
540
  agentId: this.agentId,
499
541
  threadId: this.threadId,
500
542
  toolCallId: event.toolCallId,
501
543
  toolName: event.toolName,
502
- durationMs: this.clock.now().getTime() - start,
503
- isError: event.isError === true,
544
+ durationMs,
545
+ isError,
504
546
  ...(event.error ? { error: event.error } : {}),
505
547
  ...(event.annotations ? { annotations: event.annotations } : {}),
506
548
  ...(event.serverName ? { serverName: event.serverName } : {}),
507
549
  });
550
+ // Tier-1 logBus sibling only when isError=true.
551
+ if (isError) {
552
+ this.logBus.emit({
553
+ level: 'error',
554
+ message: 'Tool execution failed',
555
+ timestamp: completedAt,
556
+ context: {
557
+ event_type: 'tool-execution-completed',
558
+ agentId: this.agentId,
559
+ threadId: this.threadId,
560
+ toolCallId: event.toolCallId,
561
+ toolName: event.toolName,
562
+ durationMs,
563
+ isError: true,
564
+ ...(event.annotations ? { annotations: event.annotations } : {}),
565
+ ...(event.serverName ? { serverName: event.serverName } : {}),
566
+ },
567
+ ...(event.error ? { error: event.error } : {}),
568
+ });
569
+ }
508
570
  }
509
571
  else if (event.type === 'tool-approval-request') {
510
572
  // Record the (toolName, serverName?) so a later settle with
@@ -574,6 +636,7 @@ export class DefaultChatSession {
574
636
  */
575
637
  emitChatStreamStarted(trigger) {
576
638
  const startedAt = this.clock.now();
639
+ // chat-stream-started pairs 1:1 with chat-stream-completed, which already carries outcomes
577
640
  this.telemetryBus.emit({
578
641
  type: 'chat-stream-started',
579
642
  timestamp: startedAt,
@@ -597,12 +660,25 @@ export class DefaultChatSession {
597
660
  this.chatEventBus.emit({ type: 'error', error });
598
661
  this.chatEventBus.emit({ type: 'finish', finishReason: 'error' });
599
662
  const finishedAt = this.clock.now();
663
+ const durationMs = finishedAt.getTime() - startedAt.getTime();
600
664
  this.telemetryBus.emit({
601
665
  type: 'chat-stream-error',
602
666
  timestamp: finishedAt,
603
667
  agentId: this.agentId,
604
668
  threadId: this.threadId,
605
- durationMs: finishedAt.getTime() - startedAt.getTime(),
669
+ durationMs,
670
+ error,
671
+ });
672
+ this.logBus.emit({
673
+ level: 'error',
674
+ message: 'Chat stream failed',
675
+ timestamp: finishedAt,
676
+ context: {
677
+ event_type: 'chat-stream-error',
678
+ agentId: this.agentId,
679
+ threadId: this.threadId,
680
+ durationMs,
681
+ },
606
682
  error,
607
683
  });
608
684
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/sfdx-agent-sdk",
3
- "version": "0.40.0",
3
+ "version": "0.41.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.36.0",
51
- "@salesforce/sfdx-agent-harness-mastra": "0.39.0",
52
- "@salesforce/sfdx-agent-harness-openai": "0.5.0",
50
+ "@salesforce/sfdx-agent-harness-claude": "0.37.0",
51
+ "@salesforce/sfdx-agent-harness-mastra": "0.40.0",
52
+ "@salesforce/sfdx-agent-harness-openai": "0.6.0",
53
53
  "@types/node": "^22.20.0",
54
54
  "@vitest/coverage-istanbul": "^4.1.10",
55
55
  "@vitest/eslint-plugin": "^1.6.22",