From 095e81c1cb211886d58a5c04c2f26916adbcbe1e Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Fri, 27 Mar 2026 14:15:05 -0600 Subject: [PATCH 1/7] fix: make agent preview start require preview mode flag --- command-snapshot.json | 11 ++++++++++- messages/agent.preview.start.md | 24 ++++++++++++++--------- src/commands/agent/preview/start.ts | 12 +++++++++--- test/commands/agent/preview/start.test.ts | 10 ++++++++-- test/nuts/z3.agent.preview.nut.ts | 15 ++++++++++---- 5 files changed, 53 insertions(+), 19 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index e27f0217..050e1343 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -141,7 +141,16 @@ "command": "agent:preview:start", "flagAliases": [], "flagChars": ["n", "o"], - "flags": ["api-name", "api-version", "authoring-bundle", "flags-dir", "json", "target-org", "use-live-actions"], + "flags": [ + "api-name", + "api-version", + "authoring-bundle", + "flags-dir", + "json", + "simulate-actions", + "target-org", + "use-live-actions" + ], "plugin": "@salesforce/plugin-agent" }, { diff --git a/messages/agent.preview.start.md b/messages/agent.preview.start.md index 3d840163..037509c4 100644 --- a/messages/agent.preview.start.md +++ b/messages/agent.preview.start.md @@ -1,14 +1,16 @@ # summary -Start a programmatic agent preview session. +Start a programmatic agent preview session. # description -This command outputs a session ID that you then use with the "agent preview send" command to send an utterance to the agent. Use the "agent preview sessions" command to list all active sessions and the "agent preview end" command to end a specific session. +This command outputs a session ID that you then use with the "agent preview send" command to send an utterance to the agent. Use the "agent preview sessions" command to list all active sessions and the "agent preview end" command to end a specific session. -Identify the agent you want to start previewing with either the --authoring-bundle flag to specify a local authoring bundle's API name or --api-name to specify an activated published agent's API name. To find either API name, navigate to your package directory in your DX project. The API name of an authoring bundle is the same as its directory name under the "aiAuthoringBundles" metadata directory. Similarly, the published agent's API name is the same as its directory name under the "Bots" metadata directory. +Identify the agent you want to start previewing with either the --authoring-bundle flag to specify a local authoring bundle's API name or --api-name to specify an activated published agent's API name. To find either API name, navigate to your package directory in your DX project. The API name of an authoring bundle is the same as its directory name under the "aiAuthoringBundles" metadata directory. Similarly, the published agent's API name is the same as its directory name under the "Bots" metadata directory. -When starting a preview session using the authoring bundle, which contains the agent's Agent Script file, the preview uses mocked actions by default. Specify --use-live-actions for live mode, which uses the real Apex classes, flows, etc, in the org for the actions. +You must explicitly specify the preview execution mode using one of these flags: --use-live-actions: Executes real Apex classes, flows, and other actions in the org. --simulate-actions: Uses AI to simulate action execution without calling real implementations. + +Published agents always use live actions regardless of which flag is specified. # flags.api-name.summary @@ -20,7 +22,11 @@ API name of the authoring bundle metadata component that contains the agent's Ag # flags.use-live-actions.summary -Use real actions in the org; if not specified, preview uses AI to simulate (mock) actions. +Execute real actions in the org (Apex classes, flows, etc.). + +# flags.simulate-actions.summary + +Use AI to simulate action execution instead of calling real actions. # output.sessionId @@ -28,14 +34,14 @@ Session ID: %s # examples -- Start a programmatic agent preview session by specifying an authoring bundle; uses mocked actions by default. Use the org with alias "my-dev-org": +- Start a programmatic agent preview session by specifying an authoring bundle. Use the org with alias "my-dev-org": - <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --target-org my-dev-org + <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --target-org my-dev-org --simulate-actions - Similar to previous example but use live actions and the default org: - <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --use-live-actions + <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --use-live-actions - Start a preview session with an activated published agent: - <%= config.bin %> <%= command.id %> --api-name My_Published_Agent + <%= config.bin %> <%= command.id %> --api-name My_Published_Agent diff --git a/src/commands/agent/preview/start.ts b/src/commands/agent/preview/start.ts index 2e7d0bf4..3b0ec6ab 100644 --- a/src/commands/agent/preview/start.ts +++ b/src/commands/agent/preview/start.ts @@ -46,7 +46,11 @@ export default class AgentPreviewStart extends SfCommand { }); describe('setMockMode', () => { - it('should call setMockMode with "Mock" when --use-live-actions is not set', async () => { - await AgentPreviewStart.run(['--authoring-bundle', 'MyAgent', '--target-org', 'test@org.com']); + it('should call setMockMode with "Mock" when --simulate-actions is set', async () => { + await AgentPreviewStart.run([ + '--authoring-bundle', + 'MyAgent', + '--simulate-actions', + '--target-org', + 'test@org.com', + ]); expect(setMockModeStub.calledOnce).to.be.true; expect(setMockModeStub.firstCall.args[0]).to.equal('Mock'); diff --git a/test/nuts/z3.agent.preview.nut.ts b/test/nuts/z3.agent.preview.nut.ts index 6e7ab7e6..8077517b 100644 --- a/test/nuts/z3.agent.preview.nut.ts +++ b/test/nuts/z3.agent.preview.nut.ts @@ -37,12 +37,17 @@ describe('agent preview', function () { it('should fail when authoring bundle does not exist', async () => { const invalidBundle = 'NonExistent_Bundle'; - execCmd(`agent preview --authoring-bundle ${invalidBundle} --target-org ${getUsername()}`, { ensureExitCode: 1 }); + execCmd( + `agent preview start --authoring-bundle ${invalidBundle} --simulate-actions --target-org ${getUsername()}`, + { ensureExitCode: 1 } + ); }); it('should fail when api-name does not exist in org', async () => { const invalidApiName = 'NonExistent_Agent_12345'; - execCmd(`agent preview --api-name ${invalidApiName} --target-org ${getUsername()}`, { ensureExitCode: 1 }); + execCmd(`agent preview start --api-name ${invalidApiName} --use-live-actions --target-org ${getUsername()}`, { + ensureExitCode: 1, + }); }); describe('using preview start/send/end commands', () => { @@ -53,7 +58,7 @@ describe('agent preview', function () { const targetOrg = getUsername(); const startResult = execCmd( - `agent preview start --authoring-bundle ${bundleApiName} --target-org ${targetOrg} --json` + `agent preview start --authoring-bundle ${bundleApiName} --simulate-actions --target-org ${targetOrg} --json` ).jsonOutput?.result; expect(startResult?.sessionId).to.be.a('string'); const sessionId = startResult!.sessionId; @@ -122,7 +127,9 @@ describe('agent preview', function () { const targetOrg = getUsername(); const startResult = execCmd( - `agent preview start --api-name ${publishedAgent!.DeveloperName} --target-org ${targetOrg} --json` + `agent preview start --api-name ${ + publishedAgent!.DeveloperName + } --use-live-actions --target-org ${targetOrg} --json` ).jsonOutput?.result; expect(startResult?.sessionId).to.be.a('string'); const sessionId = startResult!.sessionId; From ca5364bf333ee9e19814b3905d0d666c486f1fde Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Mon, 30 Mar 2026 13:47:45 -0700 Subject: [PATCH 2/7] fix: edit help --- messages/agent.preview.start.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/messages/agent.preview.start.md b/messages/agent.preview.start.md index 037509c4..b5b62fa4 100644 --- a/messages/agent.preview.start.md +++ b/messages/agent.preview.start.md @@ -8,9 +8,12 @@ This command outputs a session ID that you then use with the "agent preview send Identify the agent you want to start previewing with either the --authoring-bundle flag to specify a local authoring bundle's API name or --api-name to specify an activated published agent's API name. To find either API name, navigate to your package directory in your DX project. The API name of an authoring bundle is the same as its directory name under the "aiAuthoringBundles" metadata directory. Similarly, the published agent's API name is the same as its directory name under the "Bots" metadata directory. -You must explicitly specify the preview execution mode using one of these flags: --use-live-actions: Executes real Apex classes, flows, and other actions in the org. --simulate-actions: Uses AI to simulate action execution without calling real implementations. +You must explicitly specify the preview execution mode using one of these flags: -Published agents always use live actions regardless of which flag is specified. +--use-live-actions: Executes real Apex classes, flows, and other actions in the org. +--simulate-actions: Uses AI to simulate action execution without calling real implementations. + +Published agents always use live actions regardless of which flag you specify. # flags.api-name.summary @@ -22,11 +25,11 @@ API name of the authoring bundle metadata component that contains the agent's Ag # flags.use-live-actions.summary -Execute real actions in the org (Apex classes, flows, etc.). +Execute real actions in the org, such as Apex classes and flows. You must specify either this flag or --simulate-actions # flags.simulate-actions.summary -Use AI to simulate action execution instead of calling real actions. +Use AI to simulate action execution instead of calling real actions. You must specify either this flag or --use-live-actions. # output.sessionId @@ -34,7 +37,7 @@ Session ID: %s # examples -- Start a programmatic agent preview session by specifying an authoring bundle. Use the org with alias "my-dev-org": +- Start a programmatic agent preview session by specifying an authoring bundle; use simulated actions. Use the org with alias "my-dev-org": <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --target-org my-dev-org --simulate-actions @@ -44,4 +47,4 @@ Session ID: %s - Start a preview session with an activated published agent: - <%= config.bin %> <%= command.id %> --api-name My_Published_Agent + <%= config.bin %> <%= command.id %> --api-name My_Published_Agent --use-live-actions From d7061b9ba286934b994b932be491b9e7ab4d1472 Mon Sep 17 00:00:00 2001 From: Juliet Shackell <63259011+jshackell-sfdc@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:49:50 -0700 Subject: [PATCH 3/7] Fix formatting in agent.preview.start.md --- messages/agent.preview.start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messages/agent.preview.start.md b/messages/agent.preview.start.md index b5b62fa4..d6cc451a 100644 --- a/messages/agent.preview.start.md +++ b/messages/agent.preview.start.md @@ -25,7 +25,7 @@ API name of the authoring bundle metadata component that contains the agent's Ag # flags.use-live-actions.summary -Execute real actions in the org, such as Apex classes and flows. You must specify either this flag or --simulate-actions +Execute real actions in the org, such as Apex classes and flows. You must specify either this flag or --simulate-actions. # flags.simulate-actions.summary From 378fd56d139683788cf626c696ba4ca0ac911d4b Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Mon, 30 Mar 2026 14:59:14 -0600 Subject: [PATCH 4/7] chore: flag exclusivity at work --- messages/agent.preview.start.md | 20 +++++++++++----- src/commands/agent/preview/start.ts | 28 ++++++++++++++++++----- test/commands/agent/preview/start.test.ts | 9 ++++++++ test/nuts/z3.agent.preview.nut.ts | 6 ++--- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/messages/agent.preview.start.md b/messages/agent.preview.start.md index d6cc451a..495b11bf 100644 --- a/messages/agent.preview.start.md +++ b/messages/agent.preview.start.md @@ -8,12 +8,12 @@ This command outputs a session ID that you then use with the "agent preview send Identify the agent you want to start previewing with either the --authoring-bundle flag to specify a local authoring bundle's API name or --api-name to specify an activated published agent's API name. To find either API name, navigate to your package directory in your DX project. The API name of an authoring bundle is the same as its directory name under the "aiAuthoringBundles" metadata directory. Similarly, the published agent's API name is the same as its directory name under the "Bots" metadata directory. -You must explicitly specify the preview execution mode using one of these flags: +When starting a preview session with --authoring-bundle, you must explicitly specify the execution mode using one of these flags: ---use-live-actions: Executes real Apex classes, flows, and other actions in the org. ---simulate-actions: Uses AI to simulate action execution without calling real implementations. +- --use-live-actions: Executes real Apex classes, flows, and other actions in the org. This surfaces compile and validation errors during preview. +- --simulate-actions: Uses AI to simulate action execution without calling real implementations. -Published agents always use live actions regardless of which flag you specify. +Published agents (--api-name) always use live actions. # flags.api-name.summary @@ -35,6 +35,14 @@ Use AI to simulate action execution instead of calling real actions. You must sp Session ID: %s +# output.mode.script + +Preview mode: %s actions (authoring bundle) + +# output.mode.production + +Preview mode: %s actions (published agent always uses live actions) + # examples - Start a programmatic agent preview session by specifying an authoring bundle; use simulated actions. Use the org with alias "my-dev-org": @@ -45,6 +53,6 @@ Session ID: %s <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --use-live-actions -- Start a preview session with an activated published agent: +- Start a preview session with an activated published agent (always uses live actions): - <%= config.bin %> <%= command.id %> --api-name My_Published_Agent --use-live-actions + <%= config.bin %> <%= command.id %> --api-name My_Published_Agent diff --git a/src/commands/agent/preview/start.ts b/src/commands/agent/preview/start.ts index 3b0ec6ab..11c81910 100644 --- a/src/commands/agent/preview/start.ts +++ b/src/commands/agent/preview/start.ts @@ -15,7 +15,7 @@ */ import { Flags, SfCommand } from '@salesforce/sf-plugins-core'; -import { Lifecycle, Messages } from '@salesforce/core'; +import { Lifecycle, Messages, SfError } from '@salesforce/core'; import { Agent, ProductionAgent, ScriptAgent } from '@salesforce/agents'; import { createCache } from '../../../previewSessionStore.js'; @@ -46,11 +46,9 @@ export default class AgentPreviewStart extends SfCommand { expect(setMockModeStub.calledOnce).to.be.true; expect(setMockModeStub.firstCall.args[0]).to.equal('Live Test'); }); + + it('should throw error when using --authoring-bundle without mode flag', async () => { + try { + await AgentPreviewStart.run(['--authoring-bundle', 'MyAgent', '--target-org', 'test@org.com']); + expect.fail('Should have thrown an error'); + } catch (error: unknown) { + expect((error as Error).message).to.include('must specify either --use-live-actions or --simulate-actions'); + } + }); }); }); diff --git a/test/nuts/z3.agent.preview.nut.ts b/test/nuts/z3.agent.preview.nut.ts index 8077517b..d6317977 100644 --- a/test/nuts/z3.agent.preview.nut.ts +++ b/test/nuts/z3.agent.preview.nut.ts @@ -45,7 +45,7 @@ describe('agent preview', function () { it('should fail when api-name does not exist in org', async () => { const invalidApiName = 'NonExistent_Agent_12345'; - execCmd(`agent preview start --api-name ${invalidApiName} --use-live-actions --target-org ${getUsername()}`, { + execCmd(`agent preview start --api-name ${invalidApiName} --target-org ${getUsername()}`, { ensureExitCode: 1, }); }); @@ -127,9 +127,7 @@ describe('agent preview', function () { const targetOrg = getUsername(); const startResult = execCmd( - `agent preview start --api-name ${ - publishedAgent!.DeveloperName - } --use-live-actions --target-org ${targetOrg} --json` + `agent preview start --api-name ${publishedAgent!.DeveloperName} --target-org ${targetOrg} --json` ).jsonOutput?.result; expect(startResult?.sessionId).to.be.a('string'); const sessionId = startResult!.sessionId; From 20b405c8321a81cc602127c92b98d89ad8f236b2 Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Mon, 30 Mar 2026 15:07:32 -0600 Subject: [PATCH 5/7] chore: use oclif flag defs --- messages/agent.preview.start.md | 8 ------- src/commands/agent/preview/start.ts | 26 ++++++----------------- test/commands/agent/preview/start.test.ts | 9 -------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/messages/agent.preview.start.md b/messages/agent.preview.start.md index 495b11bf..b902f509 100644 --- a/messages/agent.preview.start.md +++ b/messages/agent.preview.start.md @@ -35,14 +35,6 @@ Use AI to simulate action execution instead of calling real actions. You must sp Session ID: %s -# output.mode.script - -Preview mode: %s actions (authoring bundle) - -# output.mode.production - -Preview mode: %s actions (published agent always uses live actions) - # examples - Start a programmatic agent preview session by specifying an authoring bundle; use simulated actions. Use the org with alias "my-dev-org": diff --git a/src/commands/agent/preview/start.ts b/src/commands/agent/preview/start.ts index 11c81910..8c7380b6 100644 --- a/src/commands/agent/preview/start.ts +++ b/src/commands/agent/preview/start.ts @@ -15,7 +15,7 @@ */ import { Flags, SfCommand } from '@salesforce/sf-plugins-core'; -import { Lifecycle, Messages, SfError } from '@salesforce/core'; +import { Lifecycle, Messages } from '@salesforce/core'; import { Agent, ProductionAgent, ScriptAgent } from '@salesforce/agents'; import { createCache } from '../../../previewSessionStore.js'; @@ -38,17 +38,21 @@ export default class AgentPreviewStart extends SfCommand { expect(setMockModeStub.calledOnce).to.be.true; expect(setMockModeStub.firstCall.args[0]).to.equal('Live Test'); }); - - it('should throw error when using --authoring-bundle without mode flag', async () => { - try { - await AgentPreviewStart.run(['--authoring-bundle', 'MyAgent', '--target-org', 'test@org.com']); - expect.fail('Should have thrown an error'); - } catch (error: unknown) { - expect((error as Error).message).to.include('must specify either --use-live-actions or --simulate-actions'); - } - }); }); }); From c941d5e76793b08575b145fca6647696a5bb5837 Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Mon, 30 Mar 2026 14:23:35 -0700 Subject: [PATCH 6/7] fix: tweak help after Willie changed functionality a bit --- messages/agent.preview.start.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/messages/agent.preview.start.md b/messages/agent.preview.start.md index b902f509..5cfb7c74 100644 --- a/messages/agent.preview.start.md +++ b/messages/agent.preview.start.md @@ -13,7 +13,7 @@ When starting a preview session with --authoring-bundle, you must explicitly spe - --use-live-actions: Executes real Apex classes, flows, and other actions in the org. This surfaces compile and validation errors during preview. - --simulate-actions: Uses AI to simulate action execution without calling real implementations. -Published agents (--api-name) always use live actions. +Published agents, which you specify with the --api-name, always use live actions. # flags.api-name.summary @@ -25,11 +25,11 @@ API name of the authoring bundle metadata component that contains the agent's Ag # flags.use-live-actions.summary -Execute real actions in the org, such as Apex classes and flows. You must specify either this flag or --simulate-actions. +Execute real actions in the org, such as Apex classes and flows. When previewing using an authoring bundle, you must specify either this flag or --simulate-actions. # flags.simulate-actions.summary -Use AI to simulate action execution instead of calling real actions. You must specify either this flag or --use-live-actions. +Use AI to simulate action execution instead of calling real actions. When previewing using an authoring bundle, you must specify either this flag or --use-live-actions. # output.sessionId @@ -45,6 +45,6 @@ Session ID: %s <%= config.bin %> <%= command.id %> --authoring-bundle My_Agent_Bundle --use-live-actions -- Start a preview session with an activated published agent (always uses live actions): +- Start a preview session with an activated published agent in your default org (always uses live actions): <%= config.bin %> <%= command.id %> --api-name My_Published_Agent From d8cb6a67bf73b3ac0ffcb9a32b89d1b42f094b66 Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Tue, 31 Mar 2026 11:10:49 -0600 Subject: [PATCH 7/7] fix: correct no flag behavior --- src/commands/agent/preview/start.ts | 20 +++++++++---- test/commands/agent/preview/start.test.ts | 34 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/commands/agent/preview/start.ts b/src/commands/agent/preview/start.ts index 8c7380b6..5c933944 100644 --- a/src/commands/agent/preview/start.ts +++ b/src/commands/agent/preview/start.ts @@ -15,7 +15,7 @@ */ import { Flags, SfCommand } from '@salesforce/sf-plugins-core'; -import { Lifecycle, Messages } from '@salesforce/core'; +import { Lifecycle, Messages, SfError } from '@salesforce/core'; import { Agent, ProductionAgent, ScriptAgent } from '@salesforce/agents'; import { createCache } from '../../../previewSessionStore.js'; @@ -38,26 +38,34 @@ export default class AgentPreviewStart extends SfCommand { const { flags } = await this.parse(AgentPreviewStart); + + // Validate: authoring-bundle requires exactly one mode flag + // (mutual exclusion of mode flags handled by 'exclusive' in flag definitions) + if (flags['authoring-bundle'] && !flags['use-live-actions'] && !flags['simulate-actions']) { + throw new SfError( + 'When using --authoring-bundle, you must specify either --use-live-actions or --simulate-actions.', + 'MissingModeFlag' + ); + } + const conn = flags['target-org'].getConnection(flags['api-version']); const useLiveActions = flags['use-live-actions']; const simulateActions = flags['simulate-actions']; @@ -68,7 +76,7 @@ export default class AgentPreviewStart extends SfCommand { expect(setMockModeStub.calledOnce).to.be.true; expect(setMockModeStub.firstCall.args[0]).to.equal('Live Test'); }); + + it('should throw error when using --authoring-bundle without mode flag', async () => { + try { + await AgentPreviewStart.run(['--authoring-bundle', 'MyAgent', '--target-org', 'test@org.com']); + expect.fail('Should have thrown an error'); + } catch (error: unknown) { + expect((error as Error).message).to.include('must specify either --use-live-actions or --simulate-actions'); + } + }); + + it('should throw error when using both mode flags together', async () => { + try { + await AgentPreviewStart.run([ + '--authoring-bundle', + 'MyAgent', + '--use-live-actions', + '--simulate-actions', + '--target-org', + 'test@org.com', + ]); + expect.fail('Should have thrown an error'); + } catch (error: unknown) { + expect((error as Error).message).to.match(/cannot also be provided when using/i); + } + }); + + it('should throw error when neither --api-name nor --authoring-bundle is provided', async () => { + try { + await AgentPreviewStart.run(['--use-live-actions', '--target-org', 'test@org.com']); + expect.fail('Should have thrown an error'); + } catch (error: unknown) { + expect((error as Error).message).to.match(/exactly one|api-name|authoring-bundle/i); + } + }); }); });