diff --git a/command-snapshot.json b/command-snapshot.json index 138b240..3ee4e8f 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -3,26 +3,27 @@ "alias": [], "command": "agent:create", "flagAliases": [], - "flagChars": ["f", "o", "p"], - "flags": ["api-version", "flags-dir", "json", "planner", "spec", "target-org"], + "flagChars": ["f", "o"], + "flags": ["api-version", "flags-dir", "json", "spec", "target-org"], "plugin": "@salesforce/plugin-agent" }, { "alias": [], "command": "agent:create:spec", "flagAliases": [], - "flagChars": ["d", "o"], + "flagChars": ["d", "n", "o", "t"], "flags": [ - "agent-type", "api-version", "company-description", "company-name", "company-website", "flags-dir", "json", + "name", "output-dir", "role", - "target-org" + "target-org", + "type" ], "plugin": "@salesforce/plugin-agent" }, diff --git a/messages/agent.create.md b/messages/agent.create.md index c90d729..6597802 100644 --- a/messages/agent.create.md +++ b/messages/agent.create.md @@ -6,20 +6,16 @@ Create an Agent from an agent spec. Create an Agent from an agent spec. Agent metadata is created in the target org and retrieved to the local project. -# flags.planner.summary - -The agent planner API name. - # flags.spec.summary The path to an agent spec file. # flags.spec.description -The agent spec file defines job descriptions for the agent and can be created using the `sf agent create spec` command. +The agent spec file defines job titles and descriptions for the agent and can be created using the `sf agent create spec` command. # examples - Create an Agent: - <%= config.bin %> <%= command.id %> --planner MyAgentPlanner --spec ./agent-spec.json + <%= config.bin %> <%= command.id %> --spec ./agent-spec.json diff --git a/messages/agent.create.spec.md b/messages/agent.create.spec.md index fe9d392..17b5eb6 100644 --- a/messages/agent.create.spec.md +++ b/messages/agent.create.spec.md @@ -4,9 +4,13 @@ Create an Agent spec. # description -Create an Agent spec, which is a list of job descriptions for the agent. +Create an Agent spec, which is a list of job titles and descriptions that the agent performs. -# flags.agent-type.summary +# flags.name.summary + +The name of the agent to create. + +# flags.type.summary The type of agent to create. @@ -34,4 +38,4 @@ The location within the project where the agent spec will be written. - Create an Agent spec in the default location: - <%= config.bin %> <%= command.id %> --agent-type customer-facing --role Support --company-name "Coral Cloud" --company-description "A meaningful description" + <%= config.bin %> <%= command.id %> --type customer_facing --role Support --company-name "Coral Cloud" --company-description "A meaningful description" diff --git a/src/commands/agent/create.ts b/src/commands/agent/create.ts index 740e98e..b90d51f 100644 --- a/src/commands/agent/create.ts +++ b/src/commands/agent/create.ts @@ -7,6 +7,7 @@ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; +import { Duration, sleep } from '@salesforce/kit'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.create'); @@ -16,7 +17,9 @@ export type AgentCreateResult = { errorMessage?: string; }; -// This is a POST to /services/data/{api-version}/connect/attach-agent-topics +// There is no API for this yet. It's being planned/built by the Agent Creator team. +// However, we could possibly use: +// /services/data/{api-version}/connect/attach-agent-topics export default class AgentCreate extends SfCommand { public static readonly summary = messages.getMessage('summary'); @@ -32,11 +35,6 @@ export default class AgentCreate extends SfCommand { summary: messages.getMessage('flags.spec.summary'), description: messages.getMessage('flags.spec.description'), }), - planner: Flags.string({ - char: 'p', - required: true, - summary: messages.getMessage('flags.spec.summary'), - }), }; public async run(): Promise { @@ -46,6 +44,9 @@ export default class AgentCreate extends SfCommand { // POST to /services/data/{api-version}/connect/attach-agent-topics + // To simulate time spent on the server generating the spec. + await sleep(Duration.seconds(5)); + return { isSuccess: true }; } } diff --git a/src/commands/agent/create/spec.ts b/src/commands/agent/create/spec.ts index 5a77048..838c530 100644 --- a/src/commands/agent/create/spec.ts +++ b/src/commands/agent/create/spec.ts @@ -4,9 +4,11 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ - +import { join } from 'node:path'; +import { writeFileSync } from 'node:fs'; import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; +import { Duration, sleep } from '@salesforce/kit'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.create.spec'); @@ -14,11 +16,29 @@ const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.create export type AgentCreateSpecResult = { isSuccess: boolean; errorMessage?: string; - jobSpec?: string; + jobSpec?: string; // the location of the job spec file + // We probably need more than this in the returned JSON like + // all the parameters used to generate the spec and the spec contents }; // This is a GET of '/services/data/v62.0/connect/agent-job-spec?agentType... +// Mocked job spec, which is a list of AI generated jobs to be done +const jobSpecContent = [ + { + jobTitle: 'My first job title', + jobDescription: 'This is what the first job does', + }, + { + jobTitle: 'My second job title', + jobDescription: 'This is what the second job does', + }, + { + jobTitle: 'My third job title', + jobDescription: 'This is what the third job does', + }, +]; + export default class AgentCreateSpec extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); @@ -27,9 +47,15 @@ export default class AgentCreateSpec extends SfCommand { public static readonly flags = { 'target-org': Flags.requiredOrg(), 'api-version': Flags.orgApiVersion(), - 'agent-type': Flags.string({ + name: Flags.string({ + char: 'n', required: true, - summary: messages.getMessage('flags.agent-type.summary'), + summary: messages.getMessage('flags.name.summary'), + }), + type: Flags.string({ + char: 't', + required: true, + summary: messages.getMessage('flags.type.summary'), options: ['customer_facing', 'employee_facing'], }), role: Flags.string({ @@ -58,14 +84,40 @@ export default class AgentCreateSpec extends SfCommand { public async run(): Promise { const { flags } = await this.parse(AgentCreateSpec); - this.log(`Creating agent spec in: ${flags['output-dir']}`); + // We'll need to generate a GenAiPlanner using the name flag and deploy it + // as part of this, at least for now. We won't have to do this with the + // new API being created for us. + + this.log(); + this.styledHeader('Agent Details'); + this.log('Name:', flags.name); + this.log('Type:', flags.type); + this.log('Role:', flags.role); + this.log('Company Name:', flags['company-name']); + this.log('Company Description:', flags['company-description']); + if (flags['company-website']) { + this.log('Company Website:', flags['company-website']); + } + + this.log(); + this.spinner.start('Creating agent spec'); + + // To simulate time spent on the server generating the spec. + await sleep(Duration.seconds(2)); // GET to /services/data/{api-version}/connect/agent-job-spec // Write a file with the returned job specs + const filePath = join(flags['output-dir'], 'agentSpec.json'); + writeFileSync(filePath, JSON.stringify(jobSpecContent, null, 4)); + + this.spinner.stop(); + + this.log(`\nSaved agent spec: ${filePath}`); return { isSuccess: true, + jobSpec: filePath, }; } }