@sprucelabs/spruce-cli 28.1.3 → 28.2.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 +19 -0
- package/build/.spruce/errors/errors.types.d.ts +22 -0
- package/build/.spruce/errors/options.types.d.ts +4 -1
- package/build/.spruce/errors/spruceCli/agentAlreadyRegistered.schema.d.ts +3 -0
- package/build/.spruce/errors/spruceCli/agentAlreadyRegistered.schema.js +21 -0
- package/build/.spruce/errors/spruceCli/agentAlreadyRegistered.schema.js.map +1 -0
- package/build/__tests__/behavioral/agents/RegisteringAnAgentAtBoot.test.d.ts +15 -0
- package/build/__tests__/behavioral/agents/RegisteringAnAgentAtBoot.test.js +94 -0
- package/build/__tests__/behavioral/agents/RegisteringAnAgentAtBoot.test.js.map +1 -0
- package/build/__tests__/behavioral/onboard/StartingOnboarding.test.js +0 -7
- package/build/__tests__/behavioral/onboard/StartingOnboarding.test.js.map +1 -1
- package/build/__tests__/behavioral/{SettingRemote.test.d.ts → remote/SettingRemote.test.d.ts} +2 -2
- package/build/__tests__/behavioral/{SettingRemote.test.js → remote/SettingRemote.test.js} +2 -2
- package/build/__tests__/behavioral/remote/SettingRemote.test.js.map +1 -0
- package/build/__tests__/behavioral/remote/SettingRemoteDoesNotAskTwice.test.d.ts +10 -0
- package/build/__tests__/behavioral/remote/SettingRemoteDoesNotAskTwice.test.js +67 -0
- package/build/__tests__/behavioral/remote/SettingRemoteDoesNotAskTwice.test.js.map +1 -0
- package/build/__tests__/behavioral/skill/SettingUpASkill.test.d.ts +1 -1
- package/build/__tests__/behavioral/skill/SettingUpASkill.test.js +5 -5
- package/build/__tests__/behavioral/skill/SettingUpASkill.test.js.map +1 -1
- package/build/errors/SpruceError.js +3 -0
- package/build/errors/SpruceError.js.map +1 -1
- package/build/errors/agentAlreadyRegistered.builder.d.ts +13 -0
- package/build/errors/agentAlreadyRegistered.builder.js +16 -0
- package/build/errors/agentAlreadyRegistered.builder.js.map +1 -0
- package/build/features/ActionExecuter.js.map +1 -1
- package/build/features/FeatureInstaller.d.ts +1 -1
- package/build/features/FeatureInstallerFactory.js +3 -0
- package/build/features/FeatureInstallerFactory.js.map +1 -1
- package/build/features/agent/AgentFeature.d.ts +22 -0
- package/build/features/agent/AgentFeature.js +24 -0
- package/build/features/agent/AgentFeature.js.map +1 -0
- package/build/features/agent/actions/RegisterAction.d.ts +54 -0
- package/build/features/agent/actions/RegisterAction.js +76 -0
- package/build/features/agent/actions/RegisterAction.js.map +1 -0
- package/build/features/agent/stores/AgentStore.d.ts +5 -0
- package/build/features/agent/stores/AgentStore.js +18 -0
- package/build/features/agent/stores/AgentStore.js.map +1 -0
- package/build/features/agent/writers/AgentWriter.d.ts +8 -0
- package/build/features/agent/writers/AgentWriter.js +31 -0
- package/build/features/agent/writers/AgentWriter.js.map +1 -0
- package/build/features/event/EventFeature.js +1 -0
- package/build/features/event/EventFeature.js.map +1 -1
- package/build/stores/StoreFactory.d.ts +2 -0
- package/build/stores/StoreFactory.js +2 -0
- package/build/stores/StoreFactory.js.map +1 -1
- package/build/tests/buildTestCache.js +7 -1
- package/build/tests/buildTestCache.js.map +1 -1
- package/build/tests/utilities/test.utility.js +3 -3
- package/build/writers/WriterFactory.d.ts +2 -0
- package/build/writers/WriterFactory.js +2 -0
- package/build/writers/WriterFactory.js.map +1 -1
- package/package.json +24 -24
- package/src/.spruce/errors/errors.types.ts +40 -9
- package/src/.spruce/errors/options.types.ts +4 -1
- package/src/.spruce/errors/spruceCli/agentAlreadyRegistered.schema.ts +24 -0
- package/src/__tests__/behavioral/agents/RegisteringAnAgentAtBoot.test.ts +99 -0
- package/src/__tests__/behavioral/onboard/StartingOnboarding.test.ts +2 -7
- package/src/__tests__/behavioral/{SettingRemote.test.ts → remote/SettingRemote.test.ts} +3 -3
- package/src/__tests__/behavioral/remote/SettingRemoteDoesNotAskTwice.test.ts +68 -0
- package/src/__tests__/behavioral/skill/SettingUpASkill.test.ts +6 -6
- package/src/errors/SpruceError.ts +4 -0
- package/src/errors/agentAlreadyRegistered.builder.ts +14 -0
- package/src/features/ActionExecuter.ts +5 -4
- package/src/features/FeatureInstallerFactory.ts +3 -0
- package/src/features/agent/AgentFeature.ts +31 -0
- package/src/features/agent/actions/RegisterAction.ts +79 -0
- package/src/features/agent/stores/AgentStore.ts +16 -0
- package/src/features/agent/writers/AgentWriter.ts +54 -0
- package/src/features/event/EventFeature.ts +1 -0
- package/src/stores/StoreFactory.ts +3 -0
- package/src/tests/buildTestCache.ts +9 -2
- package/src/tests/utilities/test.utility.ts +3 -3
- package/src/writers/WriterFactory.ts +3 -0
- package/build/__tests__/behavioral/SettingRemote.test.js.map +0 -1
|
@@ -127,10 +127,13 @@ export interface BootErrorErrorOptions extends SpruceErrors.SpruceCli.BootError,
|
|
|
127
127
|
export interface AppControllerAlreadyExistsErrorOptions extends SpruceErrors.SpruceCli.AppControllerAlreadyExists, ISpruceErrorOptions {
|
|
128
128
|
code: 'APP_CONTROLLER_ALREADY_EXISTS'
|
|
129
129
|
}
|
|
130
|
+
export interface AgentAlreadyRegisteredErrorOptions extends SpruceErrors.SpruceCli.AgentAlreadyRegistered, ISpruceErrorOptions {
|
|
131
|
+
code: 'AGENT_ALREADY_REGISTERED'
|
|
132
|
+
}
|
|
130
133
|
export interface ActionCancelledErrorOptions extends SpruceErrors.SpruceCli.ActionCancelled, ISpruceErrorOptions {
|
|
131
134
|
code: 'ACTION_CANCELLED'
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
type ErrorOptions = | VscodeNotInstalledErrorOptions | ViewPluginAlreadyExistsErrorOptions | TransportAlreadyExistsErrorOptions | ThemeExistsErrorOptions | TestFailedErrorOptions | StoreExistsErrorOptions | SkillViewExistsErrorOptions | SkillNotRegisteredErrorOptions | SkillNotFoundErrorOptions | SchemaTemplateItemBuildingFailedErrorOptions | SchemaFailedToImportErrorOptions | SchemaExistsErrorOptions | NotLoggedInErrorOptions | NotImplementedErrorOptions | NoSkillsRegisteredErrorOptions | NoOrganizationsFoundErrorOptions | MissingDependenciesErrorOptions | MercuryResponseErrorErrorOptions | LintFailedErrorOptions | InvalidTestDirectoryErrorOptions | InvalidFeatureCodeErrorOptions | InvalidEventContractErrorOptions | InvalidCommandErrorOptions | GenericErrorOptions | FileExistsErrorOptions | FeatureNotInstalledErrorOptions | FailedToImportErrorOptions | ExecutingCommandFailedErrorOptions | DockerNotStartedErrorOptions | DirectoryNotSkillErrorOptions | DirectoryEmptyErrorOptions | DeployFailedErrorOptions | DependencyExistsErrorOptions | CreateAutoloaderFailedErrorOptions | CommandNotImplementedErrorOptions | CommandBlockedErrorOptions | CommandAbortedErrorOptions | CannotPromptInCiErrorOptions | CacheNotEnabledErrorOptions | BuildFailedErrorOptions | BootErrorErrorOptions | AppControllerAlreadyExistsErrorOptions | ActionCancelledErrorOptions
|
|
137
|
+
type ErrorOptions = | VscodeNotInstalledErrorOptions | ViewPluginAlreadyExistsErrorOptions | TransportAlreadyExistsErrorOptions | ThemeExistsErrorOptions | TestFailedErrorOptions | StoreExistsErrorOptions | SkillViewExistsErrorOptions | SkillNotRegisteredErrorOptions | SkillNotFoundErrorOptions | SchemaTemplateItemBuildingFailedErrorOptions | SchemaFailedToImportErrorOptions | SchemaExistsErrorOptions | NotLoggedInErrorOptions | NotImplementedErrorOptions | NoSkillsRegisteredErrorOptions | NoOrganizationsFoundErrorOptions | MissingDependenciesErrorOptions | MercuryResponseErrorErrorOptions | LintFailedErrorOptions | InvalidTestDirectoryErrorOptions | InvalidFeatureCodeErrorOptions | InvalidEventContractErrorOptions | InvalidCommandErrorOptions | GenericErrorOptions | FileExistsErrorOptions | FeatureNotInstalledErrorOptions | FailedToImportErrorOptions | ExecutingCommandFailedErrorOptions | DockerNotStartedErrorOptions | DirectoryNotSkillErrorOptions | DirectoryEmptyErrorOptions | DeployFailedErrorOptions | DependencyExistsErrorOptions | CreateAutoloaderFailedErrorOptions | CommandNotImplementedErrorOptions | CommandBlockedErrorOptions | CommandAbortedErrorOptions | CannotPromptInCiErrorOptions | CacheNotEnabledErrorOptions | BuildFailedErrorOptions | BootErrorErrorOptions | AppControllerAlreadyExistsErrorOptions | AgentAlreadyRegisteredErrorOptions | ActionCancelledErrorOptions
|
|
135
138
|
|
|
136
139
|
export default ErrorOptions
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SchemaRegistry } from '@sprucelabs/schema'
|
|
2
|
+
import { SpruceErrors } from '../errors.types'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const agentAlreadyRegisteredSchema: SpruceErrors.SpruceCli.AgentAlreadyRegisteredSchema = {
|
|
7
|
+
id: 'agentAlreadyRegistered',
|
|
8
|
+
namespace: 'SpruceCli',
|
|
9
|
+
name: 'agent already registered',
|
|
10
|
+
fields: {
|
|
11
|
+
/** Prompt Path. The path to the existing agent prompt file. */
|
|
12
|
+
'promptPath': {
|
|
13
|
+
label: 'Prompt Path',
|
|
14
|
+
type: 'text',
|
|
15
|
+
isRequired: true,
|
|
16
|
+
hint: 'The path to the existing agent prompt file.',
|
|
17
|
+
options: undefined
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
SchemaRegistry.getInstance().trackSchema(agentAlreadyRegisteredSchema)
|
|
23
|
+
|
|
24
|
+
export default agentAlreadyRegisteredSchema
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { assert, generateId, test } from '@sprucelabs/test-utils'
|
|
2
|
+
import AgentStore from '../../../features/agent/stores/AgentStore'
|
|
3
|
+
import { SkillStore } from '../../../features/skill/stores/SkillStore'
|
|
4
|
+
import AbstractSkillTest from '../../../tests/AbstractSkillTest'
|
|
5
|
+
|
|
6
|
+
export default class RegisteringAnAgentAtBootTest extends AbstractSkillTest {
|
|
7
|
+
protected static skillCacheKey = 'events'
|
|
8
|
+
private static agentName = generateId()
|
|
9
|
+
private static agents: AgentStore
|
|
10
|
+
private static skills: SkillStore
|
|
11
|
+
|
|
12
|
+
protected static async beforeEach() {
|
|
13
|
+
await super.beforeEach()
|
|
14
|
+
this.agents = this.Store('agent')
|
|
15
|
+
this.skills = this.Store('skill')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@test()
|
|
19
|
+
protected static async canCreateRegisteringAnAgentAtBoot() {
|
|
20
|
+
const results = await this.register()
|
|
21
|
+
|
|
22
|
+
const expectedPlugin = this.resolvePath(
|
|
23
|
+
'src',
|
|
24
|
+
'.spruce',
|
|
25
|
+
'features',
|
|
26
|
+
'agent.plugin.ts'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const expectedPrompt = this.resolvePath('agents/SYSTEM_PROMPT.md')
|
|
30
|
+
assert.isEqualDeep(results.files, [
|
|
31
|
+
{
|
|
32
|
+
path: expectedPlugin,
|
|
33
|
+
name: 'agent.plugin.ts',
|
|
34
|
+
action: 'generated',
|
|
35
|
+
description: 'Supports your skill with registering ai agents.',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
path: expectedPrompt,
|
|
39
|
+
name: 'SYSTEM_PROMPT.md',
|
|
40
|
+
action: 'generated',
|
|
41
|
+
description: `The prompt file that defines how your AI Platform Agent behaves.`,
|
|
42
|
+
},
|
|
43
|
+
])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@test()
|
|
47
|
+
protected static async bootingRegistersTheAgent() {
|
|
48
|
+
await this.loginAndRegisterSkill()
|
|
49
|
+
await this.boot()
|
|
50
|
+
|
|
51
|
+
const agent = await this.getPlatformAgent()
|
|
52
|
+
|
|
53
|
+
assert.isTruthy(agent, 'Did not register an agent at boot.')
|
|
54
|
+
assert.isEqual(
|
|
55
|
+
agent.name,
|
|
56
|
+
this.agentName,
|
|
57
|
+
'Did not set name correctly.'
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@test()
|
|
62
|
+
protected static async returnsAnErrorIfAlreadyRegistered() {
|
|
63
|
+
const results = await this.register()
|
|
64
|
+
assert.isFalsy(results.files, 'Should not have created files.')
|
|
65
|
+
assert.isTruthy(results.errors, 'Should have errors.')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private static async register() {
|
|
69
|
+
return await this.Action('agent', 'register', {
|
|
70
|
+
shouldAutoHandleDependencies: true,
|
|
71
|
+
}).execute({
|
|
72
|
+
type: 'system',
|
|
73
|
+
name: this.agentName,
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private static async loginAndRegisterSkill() {
|
|
78
|
+
await this.people.loginAsDemoPerson()
|
|
79
|
+
await this.skills.register({
|
|
80
|
+
name: 'Agent skill',
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private static async boot() {
|
|
85
|
+
await this.Action('skill', 'boot').execute({
|
|
86
|
+
local: true,
|
|
87
|
+
onData: (data: string) => {
|
|
88
|
+
this.log(`Boot Log: ${data}`)
|
|
89
|
+
},
|
|
90
|
+
onError: (data: string) => {
|
|
91
|
+
this.log(`Boot Error: ${data}`)
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private static async getPlatformAgent() {
|
|
97
|
+
return await this.agents.getPlatformAgent()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -39,23 +39,18 @@ export default class StartingOnboardingTest extends AbstractCliTest {
|
|
|
39
39
|
|
|
40
40
|
// get through first onboarding script and select short onboarding
|
|
41
41
|
await this.waitForInput()
|
|
42
|
-
debugger
|
|
43
42
|
|
|
44
43
|
await this.ui.sendInput('\n')
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
await this.waitForInput()
|
|
47
|
-
debugger
|
|
48
46
|
|
|
49
47
|
await this.ui.sendInput('immersive')
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
await this.waitForInput()
|
|
52
|
-
debugger
|
|
53
50
|
|
|
54
51
|
await this.ui.sendInput('\n')
|
|
55
|
-
debugger
|
|
56
52
|
|
|
57
53
|
await onboardPromise
|
|
58
|
-
debugger
|
|
59
54
|
|
|
60
55
|
const onboardingStore = this.Store('onboarding')
|
|
61
56
|
assert.isEqual(onboardingStore.getMode(), 'immersive')
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
REMOTE_SANDBOX,
|
|
6
6
|
} from '@sprucelabs/spruce-event-utils'
|
|
7
7
|
import { test, assert } from '@sprucelabs/test-utils'
|
|
8
|
-
import { FeatureCode } from '
|
|
9
|
-
import TerminalInterface from '
|
|
10
|
-
import AbstractSkillTest from '
|
|
8
|
+
import { FeatureCode } from '../../../features/features.types'
|
|
9
|
+
import TerminalInterface from '../../../interfaces/TerminalInterface'
|
|
10
|
+
import AbstractSkillTest from '../../../tests/AbstractSkillTest'
|
|
11
11
|
|
|
12
12
|
export default class SettingRemoteTest extends AbstractSkillTest {
|
|
13
13
|
protected static skillCacheKey = 'events'
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Remote } from '@sprucelabs/spruce-event-utils'
|
|
2
|
+
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
|
|
3
|
+
import { test } from '@sprucelabs/test-utils'
|
|
4
|
+
import RemoteService from '../../../features/event/services/RemoteService'
|
|
5
|
+
import ServiceFactory from '../../../services/ServiceFactory'
|
|
6
|
+
import AbstractSkillTest from '../../../tests/AbstractSkillTest'
|
|
7
|
+
|
|
8
|
+
export default class SettingRemoteDoesNotAskTwiceTest extends AbstractSkillTest {
|
|
9
|
+
protected static skillCacheKey = 'tests'
|
|
10
|
+
@test()
|
|
11
|
+
protected static async canSetRemoteWithoutOneAndOnlyBeAskedOnce() {
|
|
12
|
+
ServiceFactory.setServiceClass('remote', CountingRemoteService)
|
|
13
|
+
|
|
14
|
+
this.cleanEnv()
|
|
15
|
+
|
|
16
|
+
const promise = this.Action('event', 'setRemote', {
|
|
17
|
+
shouldAutoHandleDependencies: true,
|
|
18
|
+
}).execute({})
|
|
19
|
+
|
|
20
|
+
await this.confirmInstallSchemaFeature()
|
|
21
|
+
await this.confirmInstallPermissionFeature()
|
|
22
|
+
|
|
23
|
+
await this.confirmFinishedInstallingDependencies()
|
|
24
|
+
await this.waitForInput()
|
|
25
|
+
|
|
26
|
+
await this.ui.sendInput('local')
|
|
27
|
+
|
|
28
|
+
await promise
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private static async confirmFinishedInstallingDependencies() {
|
|
32
|
+
await this.waitForInput()
|
|
33
|
+
await this.pressEnter()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private static async confirmInstallPermissionFeature() {
|
|
37
|
+
await this.waitForInput()
|
|
38
|
+
await this.pressEnter()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private static async confirmInstallSchemaFeature() {
|
|
42
|
+
await this.waitForInput()
|
|
43
|
+
await this.pressEnter()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private static async pressEnter() {
|
|
47
|
+
await this.ui.sendInput('\n')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private static cleanEnv() {
|
|
51
|
+
const envPath = this.resolvePath('.env')
|
|
52
|
+
diskUtil.deleteFile(envPath)
|
|
53
|
+
diskUtil.writeFile(envPath, 'SKILL_NAME="don\'t double me"')
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class CountingRemoteService extends RemoteService {
|
|
58
|
+
public static wasCalled = false
|
|
59
|
+
public set(host: Remote) {
|
|
60
|
+
if (CountingRemoteService.wasCalled) {
|
|
61
|
+
throw new Error('Called twice')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
super.set(host)
|
|
65
|
+
|
|
66
|
+
CountingRemoteService.wasCalled = true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -107,12 +107,6 @@ export default class SettingUpASkill extends AbstractCliTest {
|
|
|
107
107
|
this.assertSkillNameIsSaved()
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
private static assertSkillNameIsSaved() {
|
|
111
|
-
const env = this.Service('env')
|
|
112
|
-
assert.isTruthy(env.get('SKILL_NAME'))
|
|
113
|
-
assert.isEqual(env.get('SKILL_NAME'), 'Transfer file check skill')
|
|
114
|
-
}
|
|
115
|
-
|
|
116
110
|
@test()
|
|
117
111
|
protected static async canAcceptOptionalDestination() {
|
|
118
112
|
const cli = await this.Cli()
|
|
@@ -148,6 +142,12 @@ export default class SettingUpASkill extends AbstractCliTest {
|
|
|
148
142
|
assert.doesInclude(first.path, 'taco')
|
|
149
143
|
}
|
|
150
144
|
|
|
145
|
+
private static assertSkillNameIsSaved() {
|
|
146
|
+
const env = this.Service('env')
|
|
147
|
+
assert.isTruthy(env.get('SKILL_NAME'))
|
|
148
|
+
assert.isEqual(env.get('SKILL_NAME'), 'Transfer file check skill')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
151
|
protected static assertDevDependenciesExist() {
|
|
152
152
|
const pkg = this.Service('pkg')
|
|
153
153
|
const devDependencies = pkg.get('devDependencies')
|
|
@@ -277,6 +277,10 @@ export default class SpruceError extends AbstractSpruceError<ErrorOptions> {
|
|
|
277
277
|
message = `You already have an AppController! Run \`spruce sync.views\` if you are having issues.`
|
|
278
278
|
break
|
|
279
279
|
|
|
280
|
+
case 'AGENT_ALREADY_REGISTERED':
|
|
281
|
+
message = `You already registerd an AI Agent at ${options.promptPath}. If you want to register a new one, delete that file first.`
|
|
282
|
+
break
|
|
283
|
+
|
|
280
284
|
default:
|
|
281
285
|
message = super.friendlyMessage()
|
|
282
286
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { buildErrorSchema } from '@sprucelabs/schema'
|
|
2
|
+
|
|
3
|
+
export default buildErrorSchema({
|
|
4
|
+
id: 'agentAlreadyRegistered',
|
|
5
|
+
name: 'agent already registered',
|
|
6
|
+
fields: {
|
|
7
|
+
promptPath: {
|
|
8
|
+
type: 'text',
|
|
9
|
+
isRequired: true,
|
|
10
|
+
label: 'Prompt Path',
|
|
11
|
+
hint: 'The path to the existing agent prompt file.',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Schema } from '@sprucelabs/schema'
|
|
1
2
|
import { eventResponseUtil } from '@sprucelabs/spruce-event-utils'
|
|
2
3
|
import merge from 'lodash/merge'
|
|
3
4
|
import SpruceError from '../errors/SpruceError'
|
|
@@ -40,8 +41,8 @@ export default class ActionExecuter {
|
|
|
40
41
|
private async execute(options: {
|
|
41
42
|
featureCode: FeatureCode
|
|
42
43
|
actionCode: string
|
|
43
|
-
action:
|
|
44
|
-
originalExecute:
|
|
44
|
+
action: FeatureAction<Schema>
|
|
45
|
+
originalExecute: FeatureAction<Schema>['execute']
|
|
45
46
|
options?: Record<string, any>
|
|
46
47
|
}): Promise<FeatureInstallResponse & FeatureActionResponse> {
|
|
47
48
|
const {
|
|
@@ -187,7 +188,7 @@ export default class ActionExecuter {
|
|
|
187
188
|
|
|
188
189
|
const originalExecute = action.execute.bind(action)
|
|
189
190
|
|
|
190
|
-
action.execute = async (options: any) => {
|
|
191
|
+
action.execute = async (options: Record<string, any>) => {
|
|
191
192
|
return this.execute({
|
|
192
193
|
featureCode,
|
|
193
194
|
actionCode,
|
|
@@ -197,7 +198,7 @@ export default class ActionExecuter {
|
|
|
197
198
|
})
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
return action as
|
|
201
|
+
return action as FeatureAction<Schema>
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
204
|
|
|
@@ -6,6 +6,7 @@ import { ApiClientFactory } from '../types/apiClient.types'
|
|
|
6
6
|
import { GraphicsInterface } from '../types/cli.types'
|
|
7
7
|
import { FeatureOptions } from './AbstractFeature'
|
|
8
8
|
import ActionExecuter from './ActionExecuter'
|
|
9
|
+
import AgentFeature from './agent/AgentFeature'
|
|
9
10
|
import CacheFeature from './cache/CacheFeature'
|
|
10
11
|
import ConversationFeature from './conversation/ConversationFeature'
|
|
11
12
|
import DependencyFeature from './dependencies/DependencyFeature'
|
|
@@ -55,6 +56,7 @@ export default class FeatureInstallerFactory {
|
|
|
55
56
|
DependencyFeature,
|
|
56
57
|
PolishFeature,
|
|
57
58
|
PermissionFeature,
|
|
59
|
+
AgentFeature,
|
|
58
60
|
]
|
|
59
61
|
|
|
60
62
|
public static readonly featureCodes: FeatureCode[] = [
|
|
@@ -80,6 +82,7 @@ export default class FeatureInstallerFactory {
|
|
|
80
82
|
'dependency',
|
|
81
83
|
'polish',
|
|
82
84
|
'permission',
|
|
85
|
+
'agent',
|
|
83
86
|
]
|
|
84
87
|
|
|
85
88
|
public static WithAllFeatures(
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
|
|
2
|
+
import { FileDescription } from '../../types/cli.types'
|
|
3
|
+
import AbstractFeature, { FeatureDependency } from '../AbstractFeature'
|
|
4
|
+
import { FeatureCode } from '../features.types'
|
|
5
|
+
|
|
6
|
+
export default class AgentFeature extends AbstractFeature {
|
|
7
|
+
public description = 'AI Agent support for your skill.'
|
|
8
|
+
public code: FeatureCode = 'agent'
|
|
9
|
+
public nameReadable = 'Agent'
|
|
10
|
+
public actionsDir = diskUtil.resolvePath(__dirname, 'actions')
|
|
11
|
+
public dependencies: FeatureDependency[] = [
|
|
12
|
+
{ code: 'event', isRequired: true },
|
|
13
|
+
]
|
|
14
|
+
public packageDependencies = [
|
|
15
|
+
{
|
|
16
|
+
name: '@sprucelabs/spruce-agent-plugin',
|
|
17
|
+
},
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
public readonly fileDescriptions: FileDescription[] = []
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare module '../../features/features.types' {
|
|
24
|
+
interface FeatureMap {
|
|
25
|
+
agent: AgentFeature
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface FeatureOptionsMap {
|
|
29
|
+
agent: undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { buildSchema, SchemaValues } from '@sprucelabs/schema'
|
|
2
|
+
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
|
|
3
|
+
import SpruceError from '../../../errors/SpruceError'
|
|
4
|
+
import AbstractAction from '../../AbstractAction'
|
|
5
|
+
import { FeatureActionResponse } from '../../features.types'
|
|
6
|
+
|
|
7
|
+
const optionsSchema = buildSchema({
|
|
8
|
+
id: 'registerAgentOptions',
|
|
9
|
+
description:
|
|
10
|
+
'Turn Sprucebot into an agent of your own design. Heck, even give him a new name! You can create a Platform Agent or a Skill Agent. Skill Agent coming soon...',
|
|
11
|
+
fields: {
|
|
12
|
+
type: {
|
|
13
|
+
label: 'Agent Type',
|
|
14
|
+
type: 'select',
|
|
15
|
+
hint: 'You can only create a System Agent if you have permission to do so...',
|
|
16
|
+
options: {
|
|
17
|
+
choices: [
|
|
18
|
+
{
|
|
19
|
+
value: 'system',
|
|
20
|
+
label: 'System Agent',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: 'skill',
|
|
24
|
+
label: 'Skill Agent (coming soon)',
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
name: {
|
|
30
|
+
type: 'text',
|
|
31
|
+
label: 'Agent Name',
|
|
32
|
+
isRequired: true,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
type OptionsSchema = typeof optionsSchema
|
|
38
|
+
type Options = SchemaValues<OptionsSchema>
|
|
39
|
+
|
|
40
|
+
export default class RegisterAction extends AbstractAction<OptionsSchema> {
|
|
41
|
+
public optionsSchema = optionsSchema
|
|
42
|
+
public invocationMessage = 'Registering your AI Agent... 🤖'
|
|
43
|
+
|
|
44
|
+
public async execute(options: Options): Promise<FeatureActionResponse> {
|
|
45
|
+
const { name } = this.validateAndNormalizeOptions(options)
|
|
46
|
+
|
|
47
|
+
const writer = this.Writer('agent')
|
|
48
|
+
const promptPath = writer.resolveSystemPromptPath(this.cwd)
|
|
49
|
+
if (diskUtil.doesFileExist(promptPath)) {
|
|
50
|
+
return {
|
|
51
|
+
errors: [
|
|
52
|
+
new SpruceError({
|
|
53
|
+
code: 'AGENT_ALREADY_REGISTERED',
|
|
54
|
+
promptPath,
|
|
55
|
+
}),
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const plugin = await writer.writePlugin(this.cwd)
|
|
60
|
+
const prompt = await writer.writeSystemPrompt(this.cwd, {
|
|
61
|
+
name,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
headline: `AI Agent ${name} Registered Successfully!`,
|
|
66
|
+
summaryLines: [
|
|
67
|
+
`Registered ${name} AI Agent!`,
|
|
68
|
+
`Agent name: ${name}`,
|
|
69
|
+
],
|
|
70
|
+
hints: [
|
|
71
|
+
'Next steps:',
|
|
72
|
+
' - Customize your agent prompt in agents/SYSTEM_PROMPT.md',
|
|
73
|
+
' - Boot your skill',
|
|
74
|
+
' - Message the agent (try responding to the pin code email/text)',
|
|
75
|
+
],
|
|
76
|
+
files: [...plugin, ...prompt],
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import AbstractStore from '../../../stores/AbstractStore'
|
|
2
|
+
|
|
3
|
+
export default class AgentStore extends AbstractStore {
|
|
4
|
+
public name = 'agent'
|
|
5
|
+
|
|
6
|
+
public async getPlatformAgent() {
|
|
7
|
+
const client = await this.connectToApi({
|
|
8
|
+
shouldAuthAsCurrentSkill: true,
|
|
9
|
+
})
|
|
10
|
+
const [{ agent }] = await client.emitAndFlattenResponses(
|
|
11
|
+
'get-agent::v2020_12_25'
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
return agent
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
|
|
2
|
+
import AbstractWriter from '../../../writers/AbstractWriter'
|
|
3
|
+
|
|
4
|
+
export default class AgentWriter extends AbstractWriter {
|
|
5
|
+
public async writePlugin(cwd: string) {
|
|
6
|
+
const destination = diskUtil.resolveHashSprucePath(
|
|
7
|
+
cwd,
|
|
8
|
+
'features',
|
|
9
|
+
'agent.plugin.ts'
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const pluginContents = this.templates.agentPlugin()
|
|
13
|
+
|
|
14
|
+
const results = await this.writeFileIfChangedMixinResults(
|
|
15
|
+
destination,
|
|
16
|
+
pluginContents,
|
|
17
|
+
'Supports your skill with registering ai agents.'
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return results
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async writeSystemPrompt(
|
|
24
|
+
destinationDir: string,
|
|
25
|
+
options: {
|
|
26
|
+
name: string
|
|
27
|
+
}
|
|
28
|
+
) {
|
|
29
|
+
const { name } = options
|
|
30
|
+
|
|
31
|
+
const destination = this.resolveSystemPromptPath(destinationDir)
|
|
32
|
+
const promptContents = this.templates.agentSystemPrompt({
|
|
33
|
+
name,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const results = await this.writeFileIfChangedMixinResults(
|
|
37
|
+
destination,
|
|
38
|
+
promptContents,
|
|
39
|
+
`The prompt file that defines how your AI Platform Agent behaves.`
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return results
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public resolveSystemPromptPath(destinationDir: string) {
|
|
46
|
+
const filename = 'SYSTEM_PROMPT.md'
|
|
47
|
+
const destination = diskUtil.resolvePath(
|
|
48
|
+
destinationDir,
|
|
49
|
+
'agents',
|
|
50
|
+
filename
|
|
51
|
+
)
|
|
52
|
+
return destination
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -104,6 +104,7 @@ export default class EventFeature extends AbstractFeature {
|
|
|
104
104
|
(featureCode === 'event' ||
|
|
105
105
|
featureCode === 'eventContract' ||
|
|
106
106
|
actionCode === 'login') &&
|
|
107
|
+
this.initiatingAction !== 'event.setRemote' &&
|
|
107
108
|
actionCode !== 'setRemote'
|
|
108
109
|
|
|
109
110
|
if (isRemoteRelevant) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import AgentStore from '../features/agent/stores/AgentStore'
|
|
1
2
|
import ConversationStore from '../features/conversation/stores/ConversationStore'
|
|
2
3
|
import EventStore from '../features/event/stores/EventStore'
|
|
3
4
|
import ListenerStore from '../features/event/stores/ListenerStore'
|
|
@@ -78,6 +79,7 @@ export interface StoreMap {
|
|
|
78
79
|
view: ViewStore
|
|
79
80
|
listener: ListenerStore
|
|
80
81
|
permission: PermissionStore
|
|
82
|
+
agent: AgentStore
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
const storeMap = {
|
|
@@ -91,6 +93,7 @@ const storeMap = {
|
|
|
91
93
|
view: ViewStore,
|
|
92
94
|
listener: ListenerStore,
|
|
93
95
|
permission: PermissionStore,
|
|
96
|
+
agent: AgentStore,
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
export type StoreCode = keyof StoreMap
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from 'child_process'
|
|
3
|
-
import {
|
|
3
|
+
import { RemoteService } from '@sprucelabs/spruce-event-utils'
|
|
4
|
+
import { diskUtil, EnvService } from '@sprucelabs/spruce-skill-utils'
|
|
4
5
|
import dotenv from 'dotenv'
|
|
5
6
|
import TerminalInterface from '../interfaces/TerminalInterface'
|
|
6
7
|
import ImportService from '../services/ImportService'
|
|
@@ -206,11 +207,17 @@ async function run() {
|
|
|
206
207
|
diskUtil.deleteDir(cwd)
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
renderLine(lineNum, `
|
|
210
|
+
renderLine(lineNum, `Building '${cacheKey}'...`, [
|
|
210
211
|
GraphicsTextEffect.Green,
|
|
211
212
|
])
|
|
212
213
|
|
|
213
214
|
try {
|
|
215
|
+
const env = new EnvService(cwd)
|
|
216
|
+
const remote = new RemoteService(env)
|
|
217
|
+
if (!remote.getHost()) {
|
|
218
|
+
remote.set('local')
|
|
219
|
+
}
|
|
220
|
+
|
|
214
221
|
await fixture.installFeatures(options, cacheKey)
|
|
215
222
|
renderLine(
|
|
216
223
|
lineNum,
|
|
@@ -89,9 +89,9 @@ const testUtil = {
|
|
|
89
89
|
name: string | RegExp,
|
|
90
90
|
files: GeneratedFile[] | undefined
|
|
91
91
|
): string {
|
|
92
|
-
const
|
|
92
|
+
const path = (files ?? []).find((f) => f.name.search(name) > -1)?.path
|
|
93
93
|
assert.isTruthy(
|
|
94
|
-
|
|
94
|
+
path,
|
|
95
95
|
`file named '${name}' not found in generated files.\n\n${JSON.stringify(
|
|
96
96
|
files ?? [],
|
|
97
97
|
null,
|
|
@@ -99,7 +99,7 @@ const testUtil = {
|
|
|
99
99
|
)}`
|
|
100
100
|
)
|
|
101
101
|
|
|
102
|
-
return
|
|
102
|
+
return path
|
|
103
103
|
},
|
|
104
104
|
|
|
105
105
|
assertFileByPathInGeneratedFiles(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SettingsService } from '@sprucelabs/spruce-skill-utils'
|
|
2
2
|
import { Templates } from '@sprucelabs/spruce-templates'
|
|
3
|
+
import AgentWriter from '../features/agent/writers/AgentWriter'
|
|
3
4
|
import ConversationWriter from '../features/conversation/writers/ConversationWriter'
|
|
4
5
|
import DeployWriter from '../features/deploy/writers/DeployWriter'
|
|
5
6
|
import ErrorWriter from '../features/error/writers/ErrorWriter'
|
|
@@ -26,6 +27,7 @@ const classMap = {
|
|
|
26
27
|
schema: SchemaWriter,
|
|
27
28
|
skill: SkillGenerator,
|
|
28
29
|
test: TestWriter,
|
|
30
|
+
agent: AgentWriter,
|
|
29
31
|
node: NodeWriter,
|
|
30
32
|
vscode: VsCodeWriter,
|
|
31
33
|
conversation: ConversationWriter,
|
|
@@ -102,6 +104,7 @@ export interface WriterMap {
|
|
|
102
104
|
log: LogWriter
|
|
103
105
|
polish: PolishWriter
|
|
104
106
|
permission: PermissionWriter
|
|
107
|
+
agent: AgentWriter
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
export type WriterCode = keyof WriterMap
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SettingRemote.test.js","sourceRoot":"","sources":["../../../src/__tests__/behavioral/SettingRemote.test.ts"],"names":[],"mappings":"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"}
|