@salesforce/sfdx-agent-harness-mastra 0.27.0 → 0.28.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-harness-mastra` are documented in this file.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## [0.28.0] - 2026-07-02
7
+
8
+ ### Fixes
9
+ - **harness-mastra,harness-claude**: honor mid-turn remembered tool-policy rules @W-23294201 ([#639](https://github.com/forcedotcom/agentic-dx/pull/639))
10
+
6
11
  ## [0.27.0] - 2026-06-30
7
12
 
8
13
  ### Features
@@ -450,6 +450,29 @@ export declare class MastraHarness implements MastraAgentHarness {
450
450
  * cross-tier deny-wins, so the capability-discovery meta-tools stay
451
451
  * auto-approved even under legacy gating.
452
452
  *
453
+ * **Live config read (#638).** `lookupPolicy` reads `agentState.config` on
454
+ * every call rather than closing over a snapshot taken at stream start. A
455
+ * mid-turn `updateAgentConfig` — notably the `source: 'remember'` rule an
456
+ * "Allow always" / "Deny always" click appends — reassigns `state.config`
457
+ * (in place, on this same `agentState`; the in-flight coordinator is not
458
+ * disposed), so a snapshot would be stale for approvals 2..N in the turn
459
+ * that persisted the rule. Reading live makes the remembered decision
460
+ * auto-resolve subsequent matching tool calls within the same turn.
461
+ *
462
+ * Two decisions stay **frozen at stream start** and MUST NOT be recomputed
463
+ * live:
464
+ * - `gatingActive` — the turn either told Mastra to suspend tools
465
+ * (`requireToolApproval: true`) or it didn't; gating cannot begin
466
+ * mid-turn. The closure is built (and returned) iff gating engaged now.
467
+ * - `applyLegacyBridge` (`!hasPolicy && legacyGating`) — whether the
468
+ * deprecation bridge injects `defaultToolDecision: 'require-approval'`.
469
+ * If this were recomputed live, the FIRST remembered rule would flip
470
+ * `hasPolicy` false→true, turn the bridge OFF mid-turn, and silently drop
471
+ * the effective default back to the resolver's `'allow'` — auto-approving
472
+ * every remaining legacy-gated tool. Freezing the boolean and applying it
473
+ * to the live config preserves legacy all-or-none semantics while still
474
+ * honoring any rule the turn appends.
475
+ *
453
476
  * `batchApprovals` is the serial-vs-batch emission axis: the explicit
454
477
  * `StreamOptions.batchApprovals` OR the legacy `requireToolApproval: 'batch'`.
455
478
  */
@@ -1365,6 +1365,29 @@ export class MastraHarness {
1365
1365
  * cross-tier deny-wins, so the capability-discovery meta-tools stay
1366
1366
  * auto-approved even under legacy gating.
1367
1367
  *
1368
+ * **Live config read (#638).** `lookupPolicy` reads `agentState.config` on
1369
+ * every call rather than closing over a snapshot taken at stream start. A
1370
+ * mid-turn `updateAgentConfig` — notably the `source: 'remember'` rule an
1371
+ * "Allow always" / "Deny always" click appends — reassigns `state.config`
1372
+ * (in place, on this same `agentState`; the in-flight coordinator is not
1373
+ * disposed), so a snapshot would be stale for approvals 2..N in the turn
1374
+ * that persisted the rule. Reading live makes the remembered decision
1375
+ * auto-resolve subsequent matching tool calls within the same turn.
1376
+ *
1377
+ * Two decisions stay **frozen at stream start** and MUST NOT be recomputed
1378
+ * live:
1379
+ * - `gatingActive` — the turn either told Mastra to suspend tools
1380
+ * (`requireToolApproval: true`) or it didn't; gating cannot begin
1381
+ * mid-turn. The closure is built (and returned) iff gating engaged now.
1382
+ * - `applyLegacyBridge` (`!hasPolicy && legacyGating`) — whether the
1383
+ * deprecation bridge injects `defaultToolDecision: 'require-approval'`.
1384
+ * If this were recomputed live, the FIRST remembered rule would flip
1385
+ * `hasPolicy` false→true, turn the bridge OFF mid-turn, and silently drop
1386
+ * the effective default back to the resolver's `'allow'` — auto-approving
1387
+ * every remaining legacy-gated tool. Freezing the boolean and applying it
1388
+ * to the live config preserves legacy all-or-none semantics while still
1389
+ * honoring any rule the turn appends.
1390
+ *
1368
1391
  * `batchApprovals` is the serial-vs-batch emission axis: the explicit
1369
1392
  * `StreamOptions.batchApprovals` OR the legacy `requireToolApproval: 'batch'`.
1370
1393
  */
@@ -1377,10 +1400,20 @@ export class MastraHarness {
1377
1400
  if (!gatingActive) {
1378
1401
  return { batchApprovals: false };
1379
1402
  }
1380
- // Apply the deprecation bridge only when the gate engages purely from
1381
- // the legacy flag (no explicit policy of any kind).
1382
- const resolverConfig = !hasPolicy && legacyGating ? { ...config, defaultToolDecision: 'require-approval' } : config;
1383
- const lookupPolicy = (invocation) => resolveToolApprovalPolicy(invocation, resolverConfig, { harness: MASTRA_BUILT_IN_TOOL_POLICIES }).decision;
1403
+ // Freeze the deprecation-bridge decision at stream start (see JSDoc) —
1404
+ // whether to inject `defaultToolDecision: 'require-approval'` must not
1405
+ // change when a mid-turn remember rule flips `hasPolicy`.
1406
+ const applyLegacyBridge = !hasPolicy && legacyGating;
1407
+ const lookupPolicy = (invocation) => {
1408
+ // Read the config live so a mid-turn `updateAgentConfig` (e.g. a
1409
+ // remembered rule) is honored for the rest of this turn.
1410
+ const liveConfig = agentState.config;
1411
+ const resolverConfig = applyLegacyBridge
1412
+ ? { ...liveConfig, defaultToolDecision: 'require-approval' }
1413
+ : liveConfig;
1414
+ return resolveToolApprovalPolicy(invocation, resolverConfig, { harness: MASTRA_BUILT_IN_TOOL_POLICIES })
1415
+ .decision;
1416
+ };
1384
1417
  return { lookupPolicy, batchApprovals };
1385
1418
  }
1386
1419
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/sfdx-agent-harness-mastra",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "Mastra-backed AgentHarness implementation for @salesforce/sfdx-agent-sdk",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -40,11 +40,11 @@
40
40
  "openai": "^6.0.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "@salesforce/sfdx-agent-sdk": "0.28.0"
43
+ "@salesforce/sfdx-agent-sdk": "0.29.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@eslint/js": "^10.0.1",
47
- "@salesforce/sfdx-agent-sdk": "0.28.0",
47
+ "@salesforce/sfdx-agent-sdk": "0.29.0",
48
48
  "@types/node": "^22.20.0",
49
49
  "@vitest/coverage-istanbul": "^4.1.8",
50
50
  "@vitest/eslint-plugin": "^1.6.20",