@sprucelabs/sprucebot-llm 5.0.687 → 5.0.689
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/build/bots/adapters/OpenAi.d.ts +2 -3
- package/build/bots/adapters/OpenAi.js +10 -16
- package/build/bots/adapters/OpenAiMessageBuilder.d.ts +17 -0
- package/build/bots/adapters/OpenAiMessageBuilder.js +115 -0
- package/build/bots/adapters/SpyOpenAiApi.d.ts +16 -9
- package/build/bots/adapters/SpyOpenAiApi.js +26 -17
- package/build/chat.js +1 -1
- package/build/esm/bots/adapters/OpenAi.d.ts +2 -3
- package/build/esm/bots/adapters/OpenAi.js +11 -17
- package/build/esm/bots/adapters/OpenAiMessageBuilder.d.ts +17 -0
- package/build/esm/bots/adapters/OpenAiMessageBuilder.js +112 -0
- package/build/esm/bots/adapters/SpyOpenAiApi.d.ts +16 -9
- package/build/esm/bots/adapters/SpyOpenAiApi.js +23 -17
- package/build/esm/chat.js +1 -1
- package/build/esm/examples/buildProfileSkill.js +1 -0
- package/build/esm/llm.types.d.ts +7 -0
- package/build/examples/buildProfileSkill.js +1 -0
- package/build/llm.types.d.ts +7 -0
- package/package.json +4 -5
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
2
|
import { LlmAdapter, SendMessageOptions, SprucebotLlmBot } from '../../llm.types';
|
|
3
3
|
export declare class OpenAiAdapter implements LlmAdapter {
|
|
4
|
-
static
|
|
5
|
-
static OpenAIApi: typeof OpenAIApi;
|
|
4
|
+
static OpenAI: typeof OpenAI;
|
|
6
5
|
private api;
|
|
7
6
|
constructor(apiKey: string);
|
|
8
7
|
sendMessage(bot: SprucebotLlmBot, options?: SendMessageOptions): Promise<string>;
|
|
@@ -5,30 +5,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.MESSAGE_RESPONSE_ERROR_MESSAGE = exports.OpenAiAdapter = void 0;
|
|
7
7
|
const schema_1 = require("@sprucelabs/schema");
|
|
8
|
-
const openai_1 = require("openai");
|
|
9
|
-
const
|
|
8
|
+
const openai_1 = __importDefault(require("openai"));
|
|
9
|
+
const OpenAiMessageBuilder_1 = __importDefault(require("./OpenAiMessageBuilder"));
|
|
10
10
|
class OpenAiAdapter {
|
|
11
11
|
constructor(apiKey) {
|
|
12
12
|
(0, schema_1.assertOptions)({ apiKey }, ['apiKey']);
|
|
13
|
-
|
|
14
|
-
this.api = new OpenAiAdapter.OpenAIApi(config);
|
|
13
|
+
this.api = new OpenAiAdapter.OpenAI({ apiKey });
|
|
15
14
|
}
|
|
16
15
|
async sendMessage(bot, options) {
|
|
17
|
-
const
|
|
18
|
-
|
|
16
|
+
const messageBuilder = OpenAiMessageBuilder_1.default.Builder(bot);
|
|
17
|
+
const messages = messageBuilder.buildMessages();
|
|
18
|
+
const response = await this.api.chat.completions.create({
|
|
19
|
+
messages,
|
|
20
|
+
model: options?.model ?? 'gpt-4o',
|
|
19
21
|
});
|
|
20
|
-
|
|
21
|
-
const response = await this.api.createCompletion({
|
|
22
|
-
prompt,
|
|
23
|
-
model: options?.model ?? 'text-davinci-003',
|
|
24
|
-
max_tokens: 250,
|
|
25
|
-
stop: ['__Me__:'],
|
|
26
|
-
});
|
|
27
|
-
return (response.data.choices[0]?.text?.trim() ??
|
|
22
|
+
return (response.choices?.[0]?.message?.content?.trim() ??
|
|
28
23
|
exports.MESSAGE_RESPONSE_ERROR_MESSAGE);
|
|
29
24
|
}
|
|
30
25
|
}
|
|
31
26
|
exports.OpenAiAdapter = OpenAiAdapter;
|
|
32
|
-
OpenAiAdapter.
|
|
33
|
-
OpenAiAdapter.OpenAIApi = openai_1.OpenAIApi;
|
|
27
|
+
OpenAiAdapter.OpenAI = openai_1.default;
|
|
34
28
|
exports.MESSAGE_RESPONSE_ERROR_MESSAGE = "Oh no! Something went wrong and I can't talk right now!";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChatCompletionMessageParam } from 'openai/resources';
|
|
2
|
+
import { SprucebotLlmBot } from '../../llm.types';
|
|
3
|
+
export default class OpenAiMessageBuilder {
|
|
4
|
+
private bot;
|
|
5
|
+
protected constructor(bot: SprucebotLlmBot);
|
|
6
|
+
static Builder(bot: SprucebotLlmBot): OpenAiMessageBuilder;
|
|
7
|
+
buildMessages(): ChatCompletionMessageParam[];
|
|
8
|
+
private buildChatHistoryMessages;
|
|
9
|
+
private buildFirstMessage;
|
|
10
|
+
private buildSkillMessages;
|
|
11
|
+
private buildCallbacksMessage;
|
|
12
|
+
private buildPleaseKeepInMindMessage;
|
|
13
|
+
private buildStateMessage;
|
|
14
|
+
private buildYourJobMessage;
|
|
15
|
+
private buildWeAreDoneWhenMessage;
|
|
16
|
+
private buildStateSchemaMessage;
|
|
17
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const templates_1 = require("../templates");
|
|
4
|
+
class OpenAiMessageBuilder {
|
|
5
|
+
constructor(bot) {
|
|
6
|
+
this.bot = bot;
|
|
7
|
+
}
|
|
8
|
+
static Builder(bot) {
|
|
9
|
+
return new this(bot);
|
|
10
|
+
}
|
|
11
|
+
buildMessages() {
|
|
12
|
+
const values = this.bot.serialize();
|
|
13
|
+
const allMessages = [
|
|
14
|
+
this.buildFirstMessage(values.youAre),
|
|
15
|
+
...this.buildSkillMessages(values.skill),
|
|
16
|
+
...this.buildChatHistoryMessages(values.messages),
|
|
17
|
+
];
|
|
18
|
+
return allMessages;
|
|
19
|
+
}
|
|
20
|
+
buildChatHistoryMessages(messages) {
|
|
21
|
+
return messages.map((message) => ({
|
|
22
|
+
role: message.from === 'Me' ? 'user' : 'assistant',
|
|
23
|
+
content: message.message,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
buildFirstMessage(youAre) {
|
|
27
|
+
return {
|
|
28
|
+
role: 'system',
|
|
29
|
+
content: `You are ${youAre}.`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
buildSkillMessages(skill) {
|
|
33
|
+
if (!skill) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const messages = [];
|
|
37
|
+
messages.push(this.buildYourJobMessage(skill.yourJobIfYouChooseToAcceptItIs));
|
|
38
|
+
if (skill.stateSchema) {
|
|
39
|
+
messages.push(this.buildStateSchemaMessage(skill.stateSchema));
|
|
40
|
+
}
|
|
41
|
+
if (skill.state) {
|
|
42
|
+
messages.push(this.buildStateMessage(skill.state));
|
|
43
|
+
}
|
|
44
|
+
if (skill.weAreDoneWhen) {
|
|
45
|
+
messages.push(this.buildWeAreDoneWhenMessage(skill.weAreDoneWhen));
|
|
46
|
+
}
|
|
47
|
+
if (skill.pleaseKeepInMindThat) {
|
|
48
|
+
messages.push(this.buildPleaseKeepInMindMessage(skill.pleaseKeepInMindThat));
|
|
49
|
+
}
|
|
50
|
+
if (skill.callbacks) {
|
|
51
|
+
messages.push(this.buildCallbacksMessage(skill.callbacks));
|
|
52
|
+
}
|
|
53
|
+
return messages;
|
|
54
|
+
}
|
|
55
|
+
buildCallbacksMessage(callbacks) {
|
|
56
|
+
const keys = Object.keys(callbacks);
|
|
57
|
+
const descriptions = [];
|
|
58
|
+
for (const key of keys) {
|
|
59
|
+
const callback = callbacks[key];
|
|
60
|
+
let definition = `<Function name="${key}">
|
|
61
|
+
<Description>For use when ${callback.useThisWhenever}</Description>`;
|
|
62
|
+
if (callback.parameters) {
|
|
63
|
+
let params = '<Parameters>';
|
|
64
|
+
for (const param of callback.parameters) {
|
|
65
|
+
params += `
|
|
66
|
+
<Parameter${param.isRequired ? ' required="true"' : ''}>
|
|
67
|
+
<Name>${param.name}</Name>
|
|
68
|
+
<Type>${param.type}</Type>
|
|
69
|
+
${param.description ? `<Description>${param.description}</Description>` : ''}
|
|
70
|
+
</Parameter>`;
|
|
71
|
+
}
|
|
72
|
+
params += '</Parameters>';
|
|
73
|
+
definition += params;
|
|
74
|
+
}
|
|
75
|
+
definition += `</Function>`;
|
|
76
|
+
descriptions.push(definition);
|
|
77
|
+
}
|
|
78
|
+
const api = `<APIReference>\n\n${descriptions.join('\n\n')}</APIReference>`;
|
|
79
|
+
return {
|
|
80
|
+
role: 'system',
|
|
81
|
+
content: `You have an API available to you to lookup answers. To use it, respond with a message in handlebars format like this: {{ FunctionName }} and I'll respond with the response of the api call in my next message. If the api call has parameters, call it like this: {{ FunctionName parameter1="value1" parameter2="value2" }}. It'll work the same way. After I respond with the api's response and you can use it going forward. The api is as follows (in xml format):\n\n${api}`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
buildPleaseKeepInMindMessage(pleaseKeepInMindThat) {
|
|
85
|
+
return {
|
|
86
|
+
role: 'system',
|
|
87
|
+
content: `During this conversation, please keep the following in mind:\n\n${pleaseKeepInMindThat.map((m, idx) => `${idx + 1}. ${m}`).join('\n')}.`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
buildStateMessage(state) {
|
|
91
|
+
return {
|
|
92
|
+
role: 'system',
|
|
93
|
+
content: `The current state of this conversation is:\n\n${JSON.stringify(state)}. As the state is being updated, send it back to me in json format (something in can JSON.parse()) at the end of each response (it's not meant for reading, but for parsing, so don't call it out, but send it as we progress), surrounded by a boundary, like this: ${templates_1.STATE_BOUNDARY} { "fieldName": "fieldValue" } ${templates_1.STATE_BOUNDARY}`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
buildYourJobMessage(yourJob) {
|
|
97
|
+
return {
|
|
98
|
+
role: 'system',
|
|
99
|
+
content: `For this interaction, your job is ${yourJob}.`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
buildWeAreDoneWhenMessage(weAreDoneWhen) {
|
|
103
|
+
return {
|
|
104
|
+
role: 'system',
|
|
105
|
+
content: `Our conversation is done when ${weAreDoneWhen}. Once you determine we are done, send me the following message so I know we're done: ${templates_1.DONE_TOKEN}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
buildStateSchemaMessage(schema) {
|
|
109
|
+
return {
|
|
110
|
+
role: 'system',
|
|
111
|
+
content: `We will be tracking state for this conversation. The following schema is what we'll use to define the shape of the state:\n\n${JSON.stringify(schema)}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.default = OpenAiMessageBuilder;
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export default class SpyOpenAiApi extends
|
|
4
|
-
static config?:
|
|
5
|
-
static
|
|
6
|
-
static lastModel?: string;
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { ChatCompletion, ChatCompletionCreateParamsNonStreaming } from 'openai/resources';
|
|
3
|
+
export default class SpyOpenAiApi extends OpenAI {
|
|
4
|
+
static config?: OpenAiOptions;
|
|
5
|
+
static lastSentCompletion?: ChatCompletionCreateParamsNonStreaming;
|
|
7
6
|
static responseMessage: string | false;
|
|
8
|
-
constructor(config:
|
|
9
|
-
|
|
7
|
+
constructor(config: OpenAiOptions);
|
|
8
|
+
chat: {
|
|
9
|
+
completions: {
|
|
10
|
+
create: (options: ChatCompletionCreateParamsNonStreaming) => Promise<Response>;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
private createCompletion;
|
|
14
|
+
}
|
|
15
|
+
type Response = ChatCompletion;
|
|
16
|
+
interface OpenAiOptions {
|
|
17
|
+
apiKey: string;
|
|
10
18
|
}
|
|
11
|
-
type Response = AxiosResponse<CreateCompletionResponse, any>;
|
|
12
19
|
export {};
|
|
@@ -1,32 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const openai_1 = require("openai");
|
|
4
|
-
class SpyOpenAiApi extends openai_1.
|
|
6
|
+
const openai_1 = __importDefault(require("openai"));
|
|
7
|
+
class SpyOpenAiApi extends openai_1.default {
|
|
5
8
|
constructor(config) {
|
|
6
9
|
super(config);
|
|
10
|
+
//@ts-ignore
|
|
11
|
+
this.chat = {
|
|
12
|
+
completions: {
|
|
13
|
+
create: this.createCompletion.bind(this),
|
|
14
|
+
},
|
|
15
|
+
};
|
|
7
16
|
SpyOpenAiApi.config = config;
|
|
8
17
|
}
|
|
9
|
-
async createCompletion(
|
|
10
|
-
SpyOpenAiApi.
|
|
11
|
-
SpyOpenAiApi.lastModel = createCompletionRequest.model;
|
|
18
|
+
async createCompletion(options) {
|
|
19
|
+
SpyOpenAiApi.lastSentCompletion = options;
|
|
12
20
|
const choices = [];
|
|
13
21
|
if (SpyOpenAiApi.responseMessage) {
|
|
14
22
|
choices.push({
|
|
15
|
-
|
|
23
|
+
finish_reason: 'stop',
|
|
24
|
+
index: 0,
|
|
25
|
+
logprobs: null,
|
|
26
|
+
message: {
|
|
27
|
+
content: SpyOpenAiApi.responseMessage,
|
|
28
|
+
role: 'assistant',
|
|
29
|
+
refusal: null,
|
|
30
|
+
},
|
|
16
31
|
});
|
|
17
32
|
}
|
|
18
33
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
id: 'cmpl-1',
|
|
25
|
-
model: 'text-davinci-003',
|
|
26
|
-
created: 0,
|
|
27
|
-
object: 'text_completion',
|
|
28
|
-
choices,
|
|
29
|
-
},
|
|
34
|
+
id: 'cmpl-1',
|
|
35
|
+
model: 'text-davinci-003',
|
|
36
|
+
created: 0,
|
|
37
|
+
choices,
|
|
38
|
+
object: 'chat.completion',
|
|
30
39
|
};
|
|
31
40
|
}
|
|
32
41
|
}
|
package/build/chat.js
CHANGED
|
@@ -61,7 +61,7 @@ void (async () => {
|
|
|
61
61
|
};
|
|
62
62
|
const bot = bots.Bot({
|
|
63
63
|
adapter,
|
|
64
|
-
skill: skills.
|
|
64
|
+
skill: skills.profile,
|
|
65
65
|
youAre: "a bot named Sprucebot that is in test mode. At the start of every conversation, you introduce yourself and announce that you are in test mode so I don't get confused! You are both hip and adorable. You say things like, 'Jeepers' and 'Golly' or even 'Jeezey peezy'!",
|
|
66
66
|
});
|
|
67
67
|
do {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
2
|
import { LlmAdapter, SendMessageOptions, SprucebotLlmBot } from '../../llm.types';
|
|
3
3
|
export declare class OpenAiAdapter implements LlmAdapter {
|
|
4
|
-
static
|
|
5
|
-
static OpenAIApi: typeof OpenAIApi;
|
|
4
|
+
static OpenAI: typeof OpenAI;
|
|
6
5
|
private api;
|
|
7
6
|
constructor(apiKey: string);
|
|
8
7
|
sendMessage(bot: SprucebotLlmBot, options?: SendMessageOptions): Promise<string>;
|
|
@@ -8,31 +8,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { assertOptions } from '@sprucelabs/schema';
|
|
11
|
-
import
|
|
12
|
-
import
|
|
11
|
+
import OpenAI from 'openai';
|
|
12
|
+
import OpenAiMessageBuilder from './OpenAiMessageBuilder.js';
|
|
13
13
|
export class OpenAiAdapter {
|
|
14
14
|
constructor(apiKey) {
|
|
15
15
|
assertOptions({ apiKey }, ['apiKey']);
|
|
16
|
-
|
|
17
|
-
this.api = new OpenAiAdapter.OpenAIApi(config);
|
|
16
|
+
this.api = new OpenAiAdapter.OpenAI({ apiKey });
|
|
18
17
|
}
|
|
19
18
|
sendMessage(bot, options) {
|
|
20
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
var _a, _b, _c, _d;
|
|
22
|
-
const
|
|
23
|
-
|
|
20
|
+
var _a, _b, _c, _d, _e, _f;
|
|
21
|
+
const messageBuilder = OpenAiMessageBuilder.Builder(bot);
|
|
22
|
+
const messages = messageBuilder.buildMessages();
|
|
23
|
+
const response = yield this.api.chat.completions.create({
|
|
24
|
+
messages,
|
|
25
|
+
model: (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : 'gpt-4o',
|
|
24
26
|
});
|
|
25
|
-
|
|
26
|
-
const response = yield this.api.createCompletion({
|
|
27
|
-
prompt,
|
|
28
|
-
model: (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : 'text-davinci-003',
|
|
29
|
-
max_tokens: 250,
|
|
30
|
-
stop: ['__Me__:'],
|
|
31
|
-
});
|
|
32
|
-
return ((_d = (_c = (_b = response.data.choices[0]) === null || _b === void 0 ? void 0 : _b.text) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : MESSAGE_RESPONSE_ERROR_MESSAGE);
|
|
27
|
+
return ((_f = (_e = (_d = (_c = (_b = response.choices) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) === null || _d === void 0 ? void 0 : _d.content) === null || _e === void 0 ? void 0 : _e.trim()) !== null && _f !== void 0 ? _f : MESSAGE_RESPONSE_ERROR_MESSAGE);
|
|
33
28
|
});
|
|
34
29
|
}
|
|
35
30
|
}
|
|
36
|
-
OpenAiAdapter.
|
|
37
|
-
OpenAiAdapter.OpenAIApi = OpenAIApi;
|
|
31
|
+
OpenAiAdapter.OpenAI = OpenAI;
|
|
38
32
|
export const MESSAGE_RESPONSE_ERROR_MESSAGE = "Oh no! Something went wrong and I can't talk right now!";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChatCompletionMessageParam } from 'openai/resources';
|
|
2
|
+
import { SprucebotLlmBot } from '../../llm.types';
|
|
3
|
+
export default class OpenAiMessageBuilder {
|
|
4
|
+
private bot;
|
|
5
|
+
protected constructor(bot: SprucebotLlmBot);
|
|
6
|
+
static Builder(bot: SprucebotLlmBot): OpenAiMessageBuilder;
|
|
7
|
+
buildMessages(): ChatCompletionMessageParam[];
|
|
8
|
+
private buildChatHistoryMessages;
|
|
9
|
+
private buildFirstMessage;
|
|
10
|
+
private buildSkillMessages;
|
|
11
|
+
private buildCallbacksMessage;
|
|
12
|
+
private buildPleaseKeepInMindMessage;
|
|
13
|
+
private buildStateMessage;
|
|
14
|
+
private buildYourJobMessage;
|
|
15
|
+
private buildWeAreDoneWhenMessage;
|
|
16
|
+
private buildStateSchemaMessage;
|
|
17
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { DONE_TOKEN, STATE_BOUNDARY } from '../templates.js';
|
|
2
|
+
export default class OpenAiMessageBuilder {
|
|
3
|
+
constructor(bot) {
|
|
4
|
+
this.bot = bot;
|
|
5
|
+
}
|
|
6
|
+
static Builder(bot) {
|
|
7
|
+
return new this(bot);
|
|
8
|
+
}
|
|
9
|
+
buildMessages() {
|
|
10
|
+
const values = this.bot.serialize();
|
|
11
|
+
const allMessages = [
|
|
12
|
+
this.buildFirstMessage(values.youAre),
|
|
13
|
+
...this.buildSkillMessages(values.skill),
|
|
14
|
+
...this.buildChatHistoryMessages(values.messages),
|
|
15
|
+
];
|
|
16
|
+
return allMessages;
|
|
17
|
+
}
|
|
18
|
+
buildChatHistoryMessages(messages) {
|
|
19
|
+
return messages.map((message) => ({
|
|
20
|
+
role: message.from === 'Me' ? 'user' : 'assistant',
|
|
21
|
+
content: message.message,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
buildFirstMessage(youAre) {
|
|
25
|
+
return {
|
|
26
|
+
role: 'system',
|
|
27
|
+
content: `You are ${youAre}.`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
buildSkillMessages(skill) {
|
|
31
|
+
if (!skill) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
const messages = [];
|
|
35
|
+
messages.push(this.buildYourJobMessage(skill.yourJobIfYouChooseToAcceptItIs));
|
|
36
|
+
if (skill.stateSchema) {
|
|
37
|
+
messages.push(this.buildStateSchemaMessage(skill.stateSchema));
|
|
38
|
+
}
|
|
39
|
+
if (skill.state) {
|
|
40
|
+
messages.push(this.buildStateMessage(skill.state));
|
|
41
|
+
}
|
|
42
|
+
if (skill.weAreDoneWhen) {
|
|
43
|
+
messages.push(this.buildWeAreDoneWhenMessage(skill.weAreDoneWhen));
|
|
44
|
+
}
|
|
45
|
+
if (skill.pleaseKeepInMindThat) {
|
|
46
|
+
messages.push(this.buildPleaseKeepInMindMessage(skill.pleaseKeepInMindThat));
|
|
47
|
+
}
|
|
48
|
+
if (skill.callbacks) {
|
|
49
|
+
messages.push(this.buildCallbacksMessage(skill.callbacks));
|
|
50
|
+
}
|
|
51
|
+
return messages;
|
|
52
|
+
}
|
|
53
|
+
buildCallbacksMessage(callbacks) {
|
|
54
|
+
const keys = Object.keys(callbacks);
|
|
55
|
+
const descriptions = [];
|
|
56
|
+
for (const key of keys) {
|
|
57
|
+
const callback = callbacks[key];
|
|
58
|
+
let definition = `<Function name="${key}">
|
|
59
|
+
<Description>For use when ${callback.useThisWhenever}</Description>`;
|
|
60
|
+
if (callback.parameters) {
|
|
61
|
+
let params = '<Parameters>';
|
|
62
|
+
for (const param of callback.parameters) {
|
|
63
|
+
params += `
|
|
64
|
+
<Parameter${param.isRequired ? ' required="true"' : ''}>
|
|
65
|
+
<Name>${param.name}</Name>
|
|
66
|
+
<Type>${param.type}</Type>
|
|
67
|
+
${param.description ? `<Description>${param.description}</Description>` : ''}
|
|
68
|
+
</Parameter>`;
|
|
69
|
+
}
|
|
70
|
+
params += '</Parameters>';
|
|
71
|
+
definition += params;
|
|
72
|
+
}
|
|
73
|
+
definition += `</Function>`;
|
|
74
|
+
descriptions.push(definition);
|
|
75
|
+
}
|
|
76
|
+
const api = `<APIReference>\n\n${descriptions.join('\n\n')}</APIReference>`;
|
|
77
|
+
return {
|
|
78
|
+
role: 'system',
|
|
79
|
+
content: `You have an API available to you to lookup answers. To use it, respond with a message in handlebars format like this: {{ FunctionName }} and I'll respond with the response of the api call in my next message. If the api call has parameters, call it like this: {{ FunctionName parameter1="value1" parameter2="value2" }}. It'll work the same way. After I respond with the api's response and you can use it going forward. The api is as follows (in xml format):\n\n${api}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
buildPleaseKeepInMindMessage(pleaseKeepInMindThat) {
|
|
83
|
+
return {
|
|
84
|
+
role: 'system',
|
|
85
|
+
content: `During this conversation, please keep the following in mind:\n\n${pleaseKeepInMindThat.map((m, idx) => `${idx + 1}. ${m}`).join('\n')}.`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
buildStateMessage(state) {
|
|
89
|
+
return {
|
|
90
|
+
role: 'system',
|
|
91
|
+
content: `The current state of this conversation is:\n\n${JSON.stringify(state)}. As the state is being updated, send it back to me in json format (something in can JSON.parse()) at the end of each response (it's not meant for reading, but for parsing, so don't call it out, but send it as we progress), surrounded by a boundary, like this: ${STATE_BOUNDARY} { "fieldName": "fieldValue" } ${STATE_BOUNDARY}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
buildYourJobMessage(yourJob) {
|
|
95
|
+
return {
|
|
96
|
+
role: 'system',
|
|
97
|
+
content: `For this interaction, your job is ${yourJob}.`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
buildWeAreDoneWhenMessage(weAreDoneWhen) {
|
|
101
|
+
return {
|
|
102
|
+
role: 'system',
|
|
103
|
+
content: `Our conversation is done when ${weAreDoneWhen}. Once you determine we are done, send me the following message so I know we're done: ${DONE_TOKEN}`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
buildStateSchemaMessage(schema) {
|
|
107
|
+
return {
|
|
108
|
+
role: 'system',
|
|
109
|
+
content: `We will be tracking state for this conversation. The following schema is what we'll use to define the shape of the state:\n\n${JSON.stringify(schema)}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export default class SpyOpenAiApi extends
|
|
4
|
-
static config?:
|
|
5
|
-
static
|
|
6
|
-
static lastModel?: string;
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { ChatCompletion, ChatCompletionCreateParamsNonStreaming } from 'openai/resources';
|
|
3
|
+
export default class SpyOpenAiApi extends OpenAI {
|
|
4
|
+
static config?: OpenAiOptions;
|
|
5
|
+
static lastSentCompletion?: ChatCompletionCreateParamsNonStreaming;
|
|
7
6
|
static responseMessage: string | false;
|
|
8
|
-
constructor(config:
|
|
9
|
-
|
|
7
|
+
constructor(config: OpenAiOptions);
|
|
8
|
+
chat: {
|
|
9
|
+
completions: {
|
|
10
|
+
create: (options: ChatCompletionCreateParamsNonStreaming) => Promise<Response>;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
private createCompletion;
|
|
14
|
+
}
|
|
15
|
+
type Response = ChatCompletion;
|
|
16
|
+
interface OpenAiOptions {
|
|
17
|
+
apiKey: string;
|
|
10
18
|
}
|
|
11
|
-
type Response = AxiosResponse<CreateCompletionResponse, any>;
|
|
12
19
|
export {};
|
|
@@ -7,34 +7,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import
|
|
11
|
-
class SpyOpenAiApi extends
|
|
10
|
+
import OpenAI from 'openai';
|
|
11
|
+
class SpyOpenAiApi extends OpenAI {
|
|
12
12
|
constructor(config) {
|
|
13
13
|
super(config);
|
|
14
|
+
//@ts-ignore
|
|
15
|
+
this.chat = {
|
|
16
|
+
completions: {
|
|
17
|
+
create: this.createCompletion.bind(this),
|
|
18
|
+
},
|
|
19
|
+
};
|
|
14
20
|
SpyOpenAiApi.config = config;
|
|
15
21
|
}
|
|
16
|
-
createCompletion(
|
|
22
|
+
createCompletion(options) {
|
|
17
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
-
SpyOpenAiApi.
|
|
19
|
-
SpyOpenAiApi.lastModel = createCompletionRequest.model;
|
|
24
|
+
SpyOpenAiApi.lastSentCompletion = options;
|
|
20
25
|
const choices = [];
|
|
21
26
|
if (SpyOpenAiApi.responseMessage) {
|
|
22
27
|
choices.push({
|
|
23
|
-
|
|
28
|
+
finish_reason: 'stop',
|
|
29
|
+
index: 0,
|
|
30
|
+
logprobs: null,
|
|
31
|
+
message: {
|
|
32
|
+
content: SpyOpenAiApi.responseMessage,
|
|
33
|
+
role: 'assistant',
|
|
34
|
+
refusal: null,
|
|
35
|
+
},
|
|
24
36
|
});
|
|
25
37
|
}
|
|
26
38
|
return {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
id: 'cmpl-1',
|
|
33
|
-
model: 'text-davinci-003',
|
|
34
|
-
created: 0,
|
|
35
|
-
object: 'text_completion',
|
|
36
|
-
choices,
|
|
37
|
-
},
|
|
39
|
+
id: 'cmpl-1',
|
|
40
|
+
model: 'text-davinci-003',
|
|
41
|
+
created: 0,
|
|
42
|
+
choices,
|
|
43
|
+
object: 'chat.completion',
|
|
38
44
|
};
|
|
39
45
|
});
|
|
40
46
|
}
|
package/build/esm/chat.js
CHANGED
|
@@ -32,7 +32,7 @@ void (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
32
32
|
};
|
|
33
33
|
const bot = bots.Bot({
|
|
34
34
|
adapter,
|
|
35
|
-
skill: skills.
|
|
35
|
+
skill: skills.profile,
|
|
36
36
|
youAre: "a bot named Sprucebot that is in test mode. At the start of every conversation, you introduce yourself and announce that you are in test mode so I don't get confused! You are both hip and adorable. You say things like, 'Jeepers' and 'Golly' or even 'Jeezey peezy'!",
|
|
37
37
|
});
|
|
38
38
|
do {
|
|
@@ -2,6 +2,7 @@ import { buildSchema } from '@sprucelabs/schema';
|
|
|
2
2
|
export default function buildProfileSkill(bots) {
|
|
3
3
|
return bots.Skill({
|
|
4
4
|
yourJobIfYouChooseToAcceptItIs: 'to collect some information from me! You are a receptionist with 20 years experience and are very focused on getting answers needed to complete my profile',
|
|
5
|
+
weAreDoneWhen: 'You have all the information to complete my profile',
|
|
5
6
|
stateSchema: buildSchema({
|
|
6
7
|
id: 'profile',
|
|
7
8
|
fields: {
|
package/build/esm/llm.types.d.ts
CHANGED
|
@@ -64,4 +64,11 @@ export type LlmCallbackMap = Record<string, LlmCallback>;
|
|
|
64
64
|
export interface LlmCallback {
|
|
65
65
|
cb: () => string | Promise<string>;
|
|
66
66
|
useThisWhenever: string;
|
|
67
|
+
parameters?: LlmCallbackParameter[];
|
|
68
|
+
}
|
|
69
|
+
export interface LlmCallbackParameter {
|
|
70
|
+
name: string;
|
|
71
|
+
type: ('string' | 'number' | 'boolean' | 'dateMs' | 'dateTimeMs') | (string & {});
|
|
72
|
+
isRequired?: boolean;
|
|
73
|
+
description?: string;
|
|
67
74
|
}
|
|
@@ -5,6 +5,7 @@ const schema_1 = require("@sprucelabs/schema");
|
|
|
5
5
|
function buildProfileSkill(bots) {
|
|
6
6
|
return bots.Skill({
|
|
7
7
|
yourJobIfYouChooseToAcceptItIs: 'to collect some information from me! You are a receptionist with 20 years experience and are very focused on getting answers needed to complete my profile',
|
|
8
|
+
weAreDoneWhen: 'You have all the information to complete my profile',
|
|
8
9
|
stateSchema: (0, schema_1.buildSchema)({
|
|
9
10
|
id: 'profile',
|
|
10
11
|
fields: {
|
package/build/llm.types.d.ts
CHANGED
|
@@ -64,4 +64,11 @@ export type LlmCallbackMap = Record<string, LlmCallback>;
|
|
|
64
64
|
export interface LlmCallback {
|
|
65
65
|
cb: () => string | Promise<string>;
|
|
66
66
|
useThisWhenever: string;
|
|
67
|
+
parameters?: LlmCallbackParameter[];
|
|
68
|
+
}
|
|
69
|
+
export interface LlmCallbackParameter {
|
|
70
|
+
name: string;
|
|
71
|
+
type: ('string' | 'number' | 'boolean' | 'dateMs' | 'dateTimeMs') | (string & {});
|
|
72
|
+
isRequired?: boolean;
|
|
73
|
+
description?: string;
|
|
67
74
|
}
|
package/package.json
CHANGED
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
"upgradeIgnoreList": [
|
|
7
7
|
"@sprucelabs/spruce-core-schemas",
|
|
8
8
|
"@sprucelabs/spruce-skill-utils",
|
|
9
|
-
"@sprucelabs/spruce-test-fixtures"
|
|
10
|
-
"openai"
|
|
9
|
+
"@sprucelabs/spruce-test-fixtures"
|
|
11
10
|
]
|
|
12
11
|
},
|
|
13
|
-
"version": "5.0.
|
|
12
|
+
"version": "5.0.689",
|
|
14
13
|
"files": [
|
|
15
14
|
"build"
|
|
16
15
|
],
|
|
@@ -55,11 +54,11 @@
|
|
|
55
54
|
},
|
|
56
55
|
"dependencies": {
|
|
57
56
|
"@sprucelabs/error": "^6.0.556",
|
|
58
|
-
"@sprucelabs/mercury-event-emitter": "^42.0.
|
|
57
|
+
"@sprucelabs/mercury-event-emitter": "^42.0.660",
|
|
59
58
|
"@sprucelabs/mercury-types": "^47.0.641",
|
|
60
59
|
"@sprucelabs/schema": "^31.0.3",
|
|
61
60
|
"eta": "^3.5.0",
|
|
62
|
-
"openai": "^
|
|
61
|
+
"openai": "^4.77.0"
|
|
63
62
|
},
|
|
64
63
|
"devDependencies": {
|
|
65
64
|
"@sprucelabs/esm-postbuild": "^6.0.533",
|