diff --git a/command-snapshot.json b/command-snapshot.json index 754056f1..36cd2292 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -55,8 +55,8 @@ "alias": [], "command": "agent:preview", "flagAliases": [], - "flagChars": ["a", "d", "n", "o", "x"], - "flags": ["apex-debug", "api-name", "api-version", "connected-app-user", "flags-dir", "output-dir", "target-org"], + "flagChars": ["c", "d", "n", "o", "x"], + "flags": ["apex-debug", "api-name", "api-version", "client-app", "flags-dir", "output-dir", "target-org"], "plugin": "@salesforce/plugin-agent" }, { diff --git a/messages/agent.preview.md b/messages/agent.preview.md index 61d7767c..d23f5cf4 100644 --- a/messages/agent.preview.md +++ b/messages/agent.preview.md @@ -14,37 +14,35 @@ Find the agent's API name in its main details page in your org's Agent page in S Before you use this command, you must complete these steps: -1. Create a connected app in your org as described in the "Create a Connected App" section here: https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-get-started.html#create-a-connected-app. Do these four additional steps: +1. Using your org's Setup UI, create a connected app in your org as described in the "Create a Connected App" section here: https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-get-started.html#create-a-connected-app. Do these additional steps: a. When specifying the connected app's Callback URL, add this second callback URL on a new line: "http://localhost:1717/OauthRedirect". b. When adding the scopes to the connected app, add "Manage user data via Web browsers (web)". - c. Ensure that the "Require Secret for Web Server Flow" option is not selected. - - d. Make note of the user that you specified as the "Run As" user when updating the Client Credentials Flow section. - 2. Add the connected app to your agent as described in the "Add Connected App to Agent" section here: https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-get-started.html#add-connected-app-to-agent. 3. Copy the consumer key from your connected app as described in the "Obtain Credentials" section here: https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-get-started.html#obtain-credentials. -4. Set the "SFDX_AUTH_SCOPES" environment variable to "refresh_token sfap_api chatbot_api web api". This step ensures that you get the specific OAuth scopes required by this command. +4. If you haven't already, run the "org login web" CLI command as usual to authorize the development org that contains the agent you want to preview. + +5. Re-run the "org web login" command to link the new connected app to your already-authenticated user. Use the --client-app flag to give the link a name; you can specify any string, but make a note of it because you'll need it later. Use --username to specify the username that you used to log into the org in the previous step. Use --client-id to specify the consumer key you previously copied. Finally, use --scopes as indicated to specify the required API scopes. Here's an example: -5. Using the username of the user you specified as the "Run As" user above, authorize your org using the web server flow, as described in this document: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_web_flow.htm. +sf org login web --client-app agent-app --username --client-id --scopes "sfap_api chatbot_api refresh_token api web" - IMPORTANT: You must use the "--client-id " flag of "org login web", where CONNECTED-APP-CONSUMER-KEY is the consumer key you previously copied. This step ensures that the "org login web" command uses your custom connected app, and not the default CLI connected app. +IMPORTANT: You must use the "--client-id " flag of "org login web", where CONNECTED-APP-CONSUMER-KEY is the consumer key you previously copied. This step ensures that the "org login web" command uses your custom connected app, and not the default CLI connected app. - Press Enter to skip sharing the client secret. +6. Press Enter to skip sharing the client secret, then log in with your org username as usual and click Accept. -6. When you run this command to interact with an agent, specify the username you authorized in the preceding step with the --connected-app-user (-a) flag. +7. Run this command ("agent preview") to interact with an agent by using the --target-org flag to specify the org username or alias as usual and --client-app to specify the linked connected app ("agent-app" in the previous example). Use the "org display" command to get the list of client apps associated with an org. # flags.api-name.summary API name of the agent you want to interact with. -# flags.connected-app-user.summary +# flags.client-app.summary -Username or alias of the connected app user that's configured with web-based access tokens to the agent. +Name of the linked client app to use for the agent connection. You must have previously created this link with "org login web --client-app". Run "org display" to see the available linked client apps. # flags.output-dir.summary @@ -56,10 +54,10 @@ Enable Apex debug logging during the agent preview conversation. # examples -- Interact with an agent with API name "Resort_Manager" in the org with alias "my-org". Connect to your agent using the alias "my-agent-user"; this alias must point to the username who is authorized using the Web server flow: +- Interact with an agent with API name "Resort_Manager" in the org with alias "my-org" and the linked "agent-app" connected app: - <%= config.bin %> <%= command.id %> --api-name "Resort_Manager" --target-org my-org --connected-app-user my-agent-user + <%= config.bin %> <%= command.id %> --api-name "Resort_Manager" --target-org my-org --client-app agent-app - Same as the preceding example, but this time save the conversation transcripts to the "./transcripts/my-preview" directory rather than the default "./temp/agent-preview": - <%= config.bin %> <%= command.id %> --api-name "Resort_Manager" --target-org my-org --connected-app-user my-agent-user --output-dir "transcripts/my-preview" + <%= config.bin %> <%= command.id %> --api-name "Resort_Manager" --target-org my-org --client-app agent-app --output-dir "transcripts/my-preview" diff --git a/package.json b/package.json index 432240ec..eae616c1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@oclif/core": "^4", "@oclif/multi-stage-output": "^0.7.12", "@salesforce/agents": "0.15.0", - "@salesforce/core": "^8.10.2", + "@salesforce/core": "^8.13.0", "@salesforce/kit": "^3.2.3", "@salesforce/sf-plugins-core": "^12.2.0", "@salesforce/source-deploy-retrieve": "^12.19.3", diff --git a/src/commands/agent/preview.ts b/src/commands/agent/preview.ts index 92aabd1f..c260d1c3 100644 --- a/src/commands/agent/preview.ts +++ b/src/commands/agent/preview.ts @@ -7,7 +7,7 @@ import { resolve, join } from 'node:path'; import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; -import { Messages, SfError } from '@salesforce/core'; +import { AuthInfo, Connection, Messages, SfError } from '@salesforce/core'; import React from 'react'; import { render } from 'ink'; import { env } from '@salesforce/kit'; @@ -54,10 +54,11 @@ export default class AgentPreview extends SfCommand { public static readonly flags = { 'target-org': Flags.requiredOrg(), 'api-version': Flags.orgApiVersion(), - 'connected-app-user': Flags.requiredOrg({ - summary: messages.getMessage('flags.connected-app-user.summary'), - char: 'a', + 'client-app': Flags.string({ + char: 'c', + summary: messages.getMessage('flags.client-app.summary'), required: true, + dependsOn: ['target-org'], }), 'api-name': Flags.string({ summary: messages.getMessage('flags.api-name.summary'), @@ -78,7 +79,15 @@ export default class AgentPreview extends SfCommand { const { 'api-name': apiNameFlag } = flags; const conn = flags['target-org'].getConnection(flags['api-version']); - const apiConn = flags['connected-app-user'].getConnection(flags['api-version']); + + const authInfo = await AuthInfo.create({ + username: flags['target-org'].getUsername(), + }); + + const jwtConn = await Connection.create({ + authInfo, + clientApp: flags['client-app'], + }); const agentsQuery = await conn.query( 'SELECT Id, DeveloperName, (SELECT Status FROM BotVersions) FROM BotDefinition WHERE IsDeleted = false' @@ -102,7 +111,7 @@ export default class AgentPreview extends SfCommand { } const outputDir = await resolveOutputDir(flags['output-dir'], flags['apex-debug']); - const agentPreview = new Preview(apiConn, selectedAgent.Id); + const agentPreview = new Preview(jwtConn, selectedAgent.Id); agentPreview.toggleApexDebugMode(flags['apex-debug']); const instance = render( diff --git a/yarn.lock b/yarn.lock index 275c34da..8d3f25de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1271,10 +1271,10 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@jsforce/jsforce-node@^3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.8.1.tgz#482fcf2820b48a6b10930d33550eb4e4cbd1e480" - integrity sha512-+IZZC7VfNjhkTyeAspBc4Z35Y5eAP0RIWQnyfKahsbY/aLjiFRIM9ejl1YbWbrbabf5ODFSUgBGmOiEYLW3f7Q== +"@jsforce/jsforce-node@^3.8.2": + version "3.8.2" + resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.8.2.tgz#68b903f6733ae479086ab02ea4a2de87a7f208eb" + integrity sha512-ewaRr9JnZRW6I28C/TzUnv5p70zMrWsKCq2ovRW6X557/ikdfvA24F9k4cQXZnTG2lZLEfVn+WwdBGEtY7pPnQ== dependencies: "@sindresorhus/is" "^4" base64url "^3.0.1" @@ -1472,12 +1472,12 @@ strip-ansi "6.0.1" ts-retry-promise "^0.8.1" -"@salesforce/core@^8.10.0", "@salesforce/core@^8.10.2", "@salesforce/core@^8.10.3", "@salesforce/core@^8.5.1", "@salesforce/core@^8.8.0", "@salesforce/core@^8.8.5": - version "8.10.3" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.10.3.tgz#3cc2c99d097757cb4b08dab921254cfa3a00c7c1" - integrity sha512-juqbU304TBrrjb8sZGw+QkeAJISKu4+v2XIMTCxGJoEjs4LLhsyI7/drxCUY+7FNye+veAGeJdn/PCxkKhSgcA== +"@salesforce/core@^8.10.0", "@salesforce/core@^8.10.3", "@salesforce/core@^8.13.0", "@salesforce/core@^8.5.1", "@salesforce/core@^8.8.0", "@salesforce/core@^8.8.5": + version "8.13.0" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.13.0.tgz#ffc00a776c60a401d4385abfeb6cd7fee0d90f3b" + integrity sha512-FyAn0UGa93D0N++8poeJt7yEaWQH++qxrv/Wf4TjNaUCLoh19g57lrXuos3qDJPr8Ut4x6QjVxEc49XLy+vBkw== dependencies: - "@jsforce/jsforce-node" "^3.8.1" + "@jsforce/jsforce-node" "^3.8.2" "@salesforce/kit" "^3.2.2" "@salesforce/schemas" "^1.9.0" "@salesforce/ts-types" "^2.0.10" @@ -1489,9 +1489,9 @@ js2xmlparser "^4.0.1" jsonwebtoken "9.0.2" jszip "3.10.1" - pino "^9.4.0" + pino "^9.7.0" pino-abstract-transport "^1.2.0" - pino-pretty "^11.2.2" + pino-pretty "^11.3.0" proper-lockfile "^4.1.2" semver "^7.6.3" ts-retry-promise "^0.8.1" @@ -6985,7 +6985,7 @@ pino-abstract-transport@^2.0.0: dependencies: split2 "^4.0.0" -pino-pretty@^11.2.2: +pino-pretty@^11.3.0: version "11.3.0" resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-11.3.0.tgz#390b3be044cf3d2e9192c7d19d44f6b690468f2e" integrity sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA== @@ -7010,17 +7010,17 @@ pino-std-serializers@^7.0.0: resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b" integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== -pino@^9.4.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-9.6.0.tgz#6bc628159ba0cc81806d286718903b7fc6b13169" - integrity sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg== +pino@^9.7.0: + version "9.7.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-9.7.0.tgz#ff7cd86eb3103ee620204dbd5ca6ffda8b53f645" + integrity sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg== dependencies: atomic-sleep "^1.0.0" fast-redact "^3.1.1" on-exit-leak-free "^2.1.0" pino-abstract-transport "^2.0.0" pino-std-serializers "^7.0.0" - process-warning "^4.0.0" + process-warning "^5.0.0" quick-format-unescaped "^4.0.3" real-require "^0.2.0" safe-stable-stringify "^2.3.1" @@ -7079,10 +7079,10 @@ process-on-spawn@^1.0.0: dependencies: fromentries "^1.2.0" -process-warning@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.1.tgz#5c1db66007c67c756e4e09eb170cdece15da32fb" - integrity sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q== +process-warning@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7" + integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA== process@^0.11.10: version "0.11.10"