@sprucelabs/sprucebot-llm 0.0.1

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.
Files changed (85) hide show
  1. package/README.md +148 -0
  2. package/build/.spruce/errors/errors.types.d.ts +13 -0
  3. package/build/.spruce/errors/errors.types.js +4 -0
  4. package/build/.spruce/errors/options.types.d.ts +7 -0
  5. package/build/.spruce/errors/options.types.js +2 -0
  6. package/build/.spruce/errors/sprucebotLlm/noBotInstanceSet.schema.d.ts +3 -0
  7. package/build/.spruce/errors/sprucebotLlm/noBotInstanceSet.schema.js +11 -0
  8. package/build/.spruce/schemas/fields/fieldClassMap.d.ts +2 -0
  9. package/build/.spruce/schemas/fields/fieldClassMap.js +4 -0
  10. package/build/.spruce/schemas/fields/fields.types.d.ts +1 -0
  11. package/build/.spruce/schemas/fields/fields.types.js +2 -0
  12. package/build/.spruce/settings.json +13 -0
  13. package/build/bots/PromptGenerator.d.ts +15 -0
  14. package/build/bots/PromptGenerator.js +84 -0
  15. package/build/bots/SprucebotLlmBotImpl.d.ts +18 -0
  16. package/build/bots/SprucebotLlmBotImpl.js +69 -0
  17. package/build/bots/SprucebotLlmFactory.d.ts +9 -0
  18. package/build/bots/SprucebotLlmFactory.js +35 -0
  19. package/build/bots/SprucebotLlmSkillImpl.d.ts +12 -0
  20. package/build/bots/SprucebotLlmSkillImpl.js +39 -0
  21. package/build/bots/adapters/OpenAi.d.ts +10 -0
  22. package/build/bots/adapters/OpenAi.js +32 -0
  23. package/build/bots/adapters/SpyOpenAiApi.d.ts +12 -0
  24. package/build/bots/adapters/SpyOpenAiApi.js +34 -0
  25. package/build/bots/templates.d.ts +4 -0
  26. package/build/bots/templates.js +74 -0
  27. package/build/chat.d.ts +1 -0
  28. package/build/chat.js +60 -0
  29. package/build/errors/SpruceError.d.ts +6 -0
  30. package/build/errors/SpruceError.js +25 -0
  31. package/build/errors/noBotInstanceSet.builder.d.ts +6 -0
  32. package/build/errors/noBotInstanceSet.builder.js +8 -0
  33. package/build/esm/.spruce/errors/errors.types.d.ts +13 -0
  34. package/build/esm/.spruce/errors/errors.types.js +3 -0
  35. package/build/esm/.spruce/errors/options.types.d.ts +7 -0
  36. package/build/esm/.spruce/errors/options.types.js +1 -0
  37. package/build/esm/bots/PromptGenerator.d.ts +15 -0
  38. package/build/esm/bots/PromptGenerator.js +67 -0
  39. package/build/esm/bots/SprucebotLlmBotImpl.d.ts +18 -0
  40. package/build/esm/bots/SprucebotLlmBotImpl.js +76 -0
  41. package/build/esm/bots/SprucebotLlmFactory.d.ts +9 -0
  42. package/build/esm/bots/SprucebotLlmFactory.js +29 -0
  43. package/build/esm/bots/SprucebotLlmSkillImpl.d.ts +12 -0
  44. package/build/esm/bots/SprucebotLlmSkillImpl.js +47 -0
  45. package/build/esm/bots/adapters/OpenAi.d.ts +10 -0
  46. package/build/esm/bots/adapters/OpenAi.js +36 -0
  47. package/build/esm/bots/adapters/SpyOpenAiApi.d.ts +12 -0
  48. package/build/esm/bots/adapters/SpyOpenAiApi.js +42 -0
  49. package/build/esm/bots/templates.d.ts +4 -0
  50. package/build/esm/bots/templates.js +68 -0
  51. package/build/esm/chat.d.ts +1 -0
  52. package/build/esm/chat.js +41 -0
  53. package/build/esm/errors/SpruceError.d.ts +6 -0
  54. package/build/esm/errors/SpruceError.js +19 -0
  55. package/build/esm/errors/noBotInstanceSet.builder.d.ts +6 -0
  56. package/build/esm/errors/noBotInstanceSet.builder.js +6 -0
  57. package/build/esm/examples/buildCallbackSkill.d.ts +2 -0
  58. package/build/esm/examples/buildCallbackSkill.js +28 -0
  59. package/build/esm/examples/buildJokeSkill.d.ts +2 -0
  60. package/build/esm/examples/buildJokeSkill.js +12 -0
  61. package/build/esm/examples/buildProfileSkill.d.ts +2 -0
  62. package/build/esm/examples/buildProfileSkill.js +29 -0
  63. package/build/esm/index.d.ts +0 -0
  64. package/build/esm/index.js +2 -0
  65. package/build/esm/llm.types.d.ts +61 -0
  66. package/build/esm/llm.types.js +6 -0
  67. package/build/esm/parsingResponses/ResponseParser.d.ts +15 -0
  68. package/build/esm/parsingResponses/ResponseParser.js +60 -0
  69. package/build/esm/parsingResponses/renderPlaceholder.d.ts +1 -0
  70. package/build/esm/parsingResponses/renderPlaceholder.js +4 -0
  71. package/build/examples/buildCallbackSkill.d.ts +2 -0
  72. package/build/examples/buildCallbackSkill.js +22 -0
  73. package/build/examples/buildJokeSkill.d.ts +2 -0
  74. package/build/examples/buildJokeSkill.js +15 -0
  75. package/build/examples/buildProfileSkill.d.ts +2 -0
  76. package/build/examples/buildProfileSkill.js +32 -0
  77. package/build/index.d.ts +0 -0
  78. package/build/index.js +2 -0
  79. package/build/llm.types.d.ts +61 -0
  80. package/build/llm.types.js +9 -0
  81. package/build/parsingResponses/ResponseParser.d.ts +15 -0
  82. package/build/parsingResponses/ResponseParser.js +53 -0
  83. package/build/parsingResponses/renderPlaceholder.d.ts +1 -0
  84. package/build/parsingResponses/renderPlaceholder.js +7 -0
  85. package/package.json +101 -0
@@ -0,0 +1,68 @@
1
+ import renderPlaceholder from '../parsingResponses/renderPlaceholder.js';
2
+ export const STATE_BOUNDARY = '*****';
3
+ export const DONE_TOKEN = `____ DONE ____`;
4
+ export const CALLBACK_BOUNDARY = 'xxxxx';
5
+ export const PROMPT_TEMPLATE = `You are <%= it.youAre %>
6
+
7
+
8
+ For this interaction, every message I send will start with "__Me__:" and I'll prompt you for your response by starting with "__You__:".
9
+
10
+ __Me__: Do you understand?
11
+ __You__: Yes
12
+
13
+ <% if (it.stateSchemaJson) { %>
14
+
15
+ Here is the schema that defines the state for this conversation:
16
+
17
+ <%= it.stateSchemaJson %>
18
+
19
+
20
+ Here is the current state, which is based on the schema above:
21
+
22
+ <%= it.stateJson %>
23
+
24
+
25
+ After each message, send the state in the form:
26
+
27
+ ${STATE_BOUNDARY} <%= it.stateJson %> ${STATE_BOUNDARY}
28
+
29
+ __Me__: Sound good?
30
+ __You__: Yup!
31
+
32
+ ${STATE_BOUNDARY} <%= it.stateJson %> ${STATE_BOUNDARY}
33
+
34
+ When asking me about a "select" field, make sure I only pick a valid choice by showing me their labels!<% } %>
35
+
36
+ <% if (it.skill) { %>
37
+
38
+ Your primary objective for this conversation is <%= it.skill.yourJobIfYouChooseToAcceptItIs %>
39
+ <% if (it.skill.callbacks) { %>
40
+ While we are talking, there are going to be things I don't want you to answer, but instead to respond with a placeholder in the form of ${renderPlaceholder('example')}.
41
+
42
+ Here are the placeholders we will be using:
43
+
44
+ <% Object.keys(it.skill.callbacks).forEach((key) => { %>
45
+ Whenever <%= it.skill.callbacks[key].useThisWhenever %>, respond with ${CALLBACK_BOUNDARY} <%= key %> ${CALLBACK_BOUNDARY}
46
+
47
+ <% }) %>
48
+ <% } %>
49
+ <% if (!it.stateSchemaJson && it.skill.weAreDoneWhen) { %>
50
+ We are done when <%= it.skill.weAreDoneWhen %> At that point, send me the following message so I know we are done:
51
+
52
+ ${DONE_TOKEN}
53
+ <% } %>
54
+ <% } %>
55
+ <% if (it.stateSchemaJson) { %>
56
+
57
+ Once you have asked about every field in the schema, send me the following message so I know we're done:
58
+
59
+ ${DONE_TOKEN}
60
+ <% } %>
61
+
62
+ Let's get started:
63
+
64
+ <% it.messages.forEach((message) => { %>
65
+ __<%= message.from %>__: <%= message.message %>
66
+
67
+ <% }) %>
68
+ __You__:`;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { stdin as input, stdout as output } from 'node:process';
11
+ import * as readline from 'node:readline/promises.js';
12
+ import dotenv from 'dotenv';
13
+ import { OpenAi } from './bots/adapters/OpenAi.js';
14
+ import SprucebotLlmFactory from './bots/SprucebotLlmFactory.js';
15
+ import buildCallbackSkill from './examples/buildCallbackSkill.js';
16
+ import buildJokeSkill from './examples/buildJokeSkill.js';
17
+ import buildProfileSkill from './examples/buildProfileSkill.js';
18
+ dotenv.config();
19
+ const rl = readline.createInterface({ input, output });
20
+ (() => __awaiter(void 0, void 0, void 0, function* () {
21
+ console.clear();
22
+ const adapter = new OpenAi(process.env.OPEN_AI_API_KEY);
23
+ const bots = SprucebotLlmFactory.Factory();
24
+ const skills = {
25
+ jokes: buildJokeSkill(bots),
26
+ profile: buildProfileSkill(bots),
27
+ callbacks: buildCallbackSkill(bots),
28
+ };
29
+ const bot = bots.Bot({
30
+ adapter,
31
+ skill: skills.callbacks,
32
+ 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'!",
33
+ });
34
+ do {
35
+ const input = yield rl.question('Message > ');
36
+ const response = yield bot.sendMessage(input);
37
+ console.log('>', response);
38
+ } while (!bot.getIsDone());
39
+ console.log('Signing off...');
40
+ rl.close();
41
+ }))();
@@ -0,0 +1,6 @@
1
+ import BaseSpruceError from '@sprucelabs/error';
2
+ import ErrorOptions from "./../.spruce/errors/options.types";
3
+ export default class SpruceError extends BaseSpruceError<ErrorOptions> {
4
+ /** an easy to understand version of the errors */
5
+ friendlyMessage(): string;
6
+ }
@@ -0,0 +1,19 @@
1
+ import BaseSpruceError from '@sprucelabs/error';
2
+ export default class SpruceError extends BaseSpruceError {
3
+ /** an easy to understand version of the errors */
4
+ friendlyMessage() {
5
+ const { options } = this;
6
+ let message;
7
+ switch (options === null || options === void 0 ? void 0 : options.code) {
8
+ case 'NO_BOT_INSTANCE_SET':
9
+ message = `You must create a bot and set it using 'SprucebotLlmFactory.setInstance(bot)' before you can get an instance of it.`;
10
+ break;
11
+ default:
12
+ message = super.friendlyMessage();
13
+ }
14
+ const fullMessage = options.friendlyMessage
15
+ ? options.friendlyMessage
16
+ : message;
17
+ return fullMessage;
18
+ }
19
+ }
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ id: string;
3
+ name: string;
4
+ fields: {};
5
+ };
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { buildErrorSchema } from '@sprucelabs/schema';
2
+ export default buildErrorSchema({
3
+ id: 'noBotInstanceSet',
4
+ name: 'No bot instance set',
5
+ fields: {},
6
+ });
@@ -0,0 +1,2 @@
1
+ import SprucebotLlmFactory from '../bots/SprucebotLlmFactory';
2
+ export default function buildCallbackSkill(bots: SprucebotLlmFactory): import("../llm.types").SprucebotLLmSkill<import("@sprucelabs/schema").Schema, import("@sprucelabs/schema").SchemaStaticValues<import("@sprucelabs/schema").Schema, false, never, import("@sprucelabs/schema").StaticSchemaAllValues<import("@sprucelabs/schema").Schema, false>>>;
@@ -0,0 +1,28 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ export default function buildCallbackSkill(bots) {
11
+ return bots.Skill({
12
+ yourJobIfYouChooseToAcceptItIs: "to be be the best appointment taker on the planet. You have a many years of experience. You are going to ask me only 2 questions for this practice run. First, you'll ask me to pick an available time. Then, you'll ask me to pick my favorite color:",
13
+ callbacks: {
14
+ availableTimes: {
15
+ cb: () => __awaiter(this, void 0, void 0, function* () {
16
+ return ['9am', '10am', '11am', '1pm', '4pm', '5pm', '12am.'].join('\n');
17
+ }),
18
+ useThisWhenever: 'your are showing what times i can pick from.',
19
+ },
20
+ favoriteColor: {
21
+ cb: () => __awaiter(this, void 0, void 0, function* () {
22
+ return ['red', 'blue', 'green', 'purple'].join('\n');
23
+ }),
24
+ useThisWhenever: 'your are showing what colors i can pick from.',
25
+ },
26
+ },
27
+ });
28
+ }
@@ -0,0 +1,2 @@
1
+ import SprucebotLlmFactory from '../bots/SprucebotLlmFactory';
2
+ export default function buildJokeSkill(bots: SprucebotLlmFactory): import("../llm.types").SprucebotLLmSkill<import("@sprucelabs/schema").Schema, import("@sprucelabs/schema").SchemaStaticValues<import("@sprucelabs/schema").Schema, false, never, import("@sprucelabs/schema").StaticSchemaAllValues<import("@sprucelabs/schema").Schema, false>>>;
@@ -0,0 +1,12 @@
1
+ export default function buildJokeSkill(bots) {
2
+ return bots.Skill({
3
+ yourJobIfYouChooseToAcceptItIs: 'to tell knock knock jokes!',
4
+ pleaseKeepInMindThat: [
5
+ 'our audience is younger, so keep it PG!',
6
+ 'you should never laugh when someone does not get the joke.',
7
+ "after each joke, you should tell me how many jokes you have left to tell before we're done.",
8
+ 'you should acknowledge if someone laughs at your joke by saying "Thanks!" or "Glad you thought that was funny"!',
9
+ ],
10
+ weAreDoneWhen: 'you have told 3 jokes!',
11
+ });
12
+ }
@@ -0,0 +1,2 @@
1
+ import SprucebotLlmFactory from '../bots/SprucebotLlmFactory';
2
+ export default function buildProfileSkill(bots: SprucebotLlmFactory): import("../llm.types").SprucebotLLmSkill<import("@sprucelabs/schema").Schema, import("@sprucelabs/schema").SchemaStaticValues<import("@sprucelabs/schema").Schema, false, never, import("@sprucelabs/schema").StaticSchemaAllValues<import("@sprucelabs/schema").Schema, false>>>;
@@ -0,0 +1,29 @@
1
+ import { buildSchema } from '@sprucelabs/schema';
2
+ export default function buildProfileSkill(bots) {
3
+ return bots.Skill({
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
+ stateSchema: buildSchema({
6
+ id: 'profile',
7
+ fields: {
8
+ firstName: {
9
+ type: 'text',
10
+ label: 'First name',
11
+ },
12
+ lastName: {
13
+ type: 'text',
14
+ label: 'Last name',
15
+ },
16
+ favoriteColor: {
17
+ type: 'select',
18
+ options: {
19
+ choices: [
20
+ { label: 'Red', value: 'red' },
21
+ { label: 'Blue', value: 'blue' },
22
+ { label: 'Green', value: 'green' },
23
+ ],
24
+ },
25
+ },
26
+ },
27
+ }),
28
+ });
29
+ }
File without changes
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //exports go here
@@ -0,0 +1,61 @@
1
+ import { MercuryEventEmitter } from '@sprucelabs/mercury-types';
2
+ import { Schema, SchemaValues } from '@sprucelabs/schema';
3
+ export interface BotOptions<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends Omit<PromptOptions<StateSchema, State>, 'skill'> {
4
+ adapter: LlmAdapter;
5
+ Class?: new (...opts: any[]) => SprucebotLlmBot<Schema, State>;
6
+ skill?: SprucebotLLmSkill<Schema>;
7
+ }
8
+ export interface SprucebotLlmBot<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends MercuryEventEmitter<LlmEventContract> {
9
+ markAsDone(): void;
10
+ getIsDone(): boolean;
11
+ sendMessage(message: string): Promise<string>;
12
+ serialize(): SerializedBot<StateSchema, State>;
13
+ updateState(state: Partial<State>): Promise<void>;
14
+ }
15
+ export interface LlmAdapter {
16
+ sendMessage(bot: SprucebotLlmBot<Schema>): Promise<string>;
17
+ }
18
+ export interface PromptOptions<StateSchema extends Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> {
19
+ /**
20
+ * Tell the bot who/what it is. Example: youAre: "a super funny comedian. You absolutely love dad jokes!"
21
+ */
22
+ youAre: string;
23
+ stateSchema?: StateSchema;
24
+ state?: Partial<State>;
25
+ skill?: SerializedSkill<Schema>;
26
+ }
27
+ export interface SerializedBot<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends PromptOptions<Schema, State> {
28
+ messages: LlmMessage[];
29
+ }
30
+ export declare const llmEventContract: {
31
+ eventSignatures: {
32
+ 'did-update-state': {};
33
+ };
34
+ };
35
+ export type LlmEventContract = typeof llmEventContract;
36
+ export interface LlmMessage {
37
+ from: 'Me' | 'You';
38
+ message: string;
39
+ }
40
+ export interface SkillOptions<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> {
41
+ yourJobIfYouChooseToAcceptItIs: string;
42
+ weAreDoneWhen?: string;
43
+ pleaseKeepInMindThat?: string[];
44
+ stateSchema?: StateSchema;
45
+ state?: Partial<State>;
46
+ callbacks?: LlmCallbackMap;
47
+ }
48
+ export interface SprucebotLLmSkill<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends MercuryEventEmitter<LlmEventContract> {
49
+ getState(): Partial<State> | undefined;
50
+ serialize(): SerializedSkill<StateSchema, State>;
51
+ updateState(state: Partial<State>): Promise<void>;
52
+ }
53
+ export interface SerializedSkill<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends SkillOptions<StateSchema, State> {
54
+ }
55
+ export interface LlmCallbackMap {
56
+ [key: string]: LlmCallback;
57
+ }
58
+ export interface LlmCallback {
59
+ cb: () => string | Promise<string>;
60
+ useThisWhenever: string;
61
+ }
@@ -0,0 +1,6 @@
1
+ import { buildEventContract, } from '@sprucelabs/mercury-types';
2
+ export const llmEventContract = buildEventContract({
3
+ eventSignatures: {
4
+ 'did-update-state': {},
5
+ },
6
+ });
@@ -0,0 +1,15 @@
1
+ import { LlmCallbackMap } from '../llm.types';
2
+ export default class ResponseParser {
3
+ private static instance;
4
+ static setInstance(parser: ResponseParser): void;
5
+ static getInstance(): ResponseParser;
6
+ parse(response: string, callbacks?: LlmCallbackMap): Promise<ParsedResponse>;
7
+ private invokeCallback;
8
+ private doesIncludeDoneToken;
9
+ private parseState;
10
+ }
11
+ export interface ParsedResponse {
12
+ isDone: boolean;
13
+ state?: Record<string, any>;
14
+ message: string;
15
+ }
@@ -0,0 +1,60 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { DONE_TOKEN, STATE_BOUNDARY } from '../bots/templates.js';
11
+ import renderPlaceholder from './renderPlaceholder.js';
12
+ export default class ResponseParser {
13
+ static setInstance(parser) {
14
+ this.instance = parser;
15
+ }
16
+ static getInstance() {
17
+ return this.instance;
18
+ }
19
+ parse(response, callbacks) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ let message = response.replace(DONE_TOKEN, '').trim();
22
+ let state;
23
+ for (const key of Object.keys(callbacks || {})) {
24
+ const match = message.match(renderPlaceholder(key));
25
+ if (match) {
26
+ message = yield this.invokeCallback(callbacks, key, message);
27
+ }
28
+ }
29
+ const { match, fullMatch } = this.parseState(message);
30
+ if (match && fullMatch) {
31
+ message = message.replace(fullMatch, '').trim();
32
+ state = JSON.parse(match);
33
+ }
34
+ return {
35
+ isDone: this.doesIncludeDoneToken(response),
36
+ state,
37
+ message,
38
+ };
39
+ });
40
+ }
41
+ invokeCallback(callbacks, key, message) {
42
+ var _a;
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ const v = yield ((_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks[key]) === null || _a === void 0 ? void 0 : _a.cb());
45
+ message = message.replace(renderPlaceholder(key), v !== null && v !== void 0 ? v : '').trim();
46
+ return message;
47
+ });
48
+ }
49
+ doesIncludeDoneToken(response) {
50
+ return response.includes(DONE_TOKEN);
51
+ }
52
+ parseState(message) {
53
+ const ESCAPED_BOUNDARY = STATE_BOUNDARY.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
54
+ const searchRegex = new RegExp(`${ESCAPED_BOUNDARY}(.*?)${ESCAPED_BOUNDARY}`);
55
+ const stateMatches = message.match(searchRegex);
56
+ const match = stateMatches === null || stateMatches === void 0 ? void 0 : stateMatches[1];
57
+ return { match, fullMatch: stateMatches === null || stateMatches === void 0 ? void 0 : stateMatches[0] };
58
+ }
59
+ }
60
+ ResponseParser.instance = new ResponseParser();
@@ -0,0 +1 @@
1
+ export default function renderPlaceholder(key: string): string;
@@ -0,0 +1,4 @@
1
+ import { CALLBACK_BOUNDARY } from '../bots/templates.js';
2
+ export default function renderPlaceholder(key) {
3
+ return `${CALLBACK_BOUNDARY} ${key} ${CALLBACK_BOUNDARY}`;
4
+ }
@@ -0,0 +1,2 @@
1
+ import SprucebotLlmFactory from '../bots/SprucebotLlmFactory';
2
+ export default function buildCallbackSkill(bots: SprucebotLlmFactory): import("../llm.types").SprucebotLLmSkill<import("@sprucelabs/schema").Schema, import("@sprucelabs/schema").SchemaStaticValues<import("@sprucelabs/schema").Schema, false, never, import("@sprucelabs/schema").StaticSchemaAllValues<import("@sprucelabs/schema").Schema, false>>>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function buildCallbackSkill(bots) {
4
+ return bots.Skill({
5
+ yourJobIfYouChooseToAcceptItIs: "to be be the best appointment taker on the planet. You have a many years of experience. You are going to ask me only 2 questions for this practice run. First, you'll ask me to pick an available time. Then, you'll ask me to pick my favorite color:",
6
+ callbacks: {
7
+ availableTimes: {
8
+ cb: async () => {
9
+ return ['9am', '10am', '11am', '1pm', '4pm', '5pm', '12am.'].join('\n');
10
+ },
11
+ useThisWhenever: 'your are showing what times i can pick from.',
12
+ },
13
+ favoriteColor: {
14
+ cb: async () => {
15
+ return ['red', 'blue', 'green', 'purple'].join('\n');
16
+ },
17
+ useThisWhenever: 'your are showing what colors i can pick from.',
18
+ },
19
+ },
20
+ });
21
+ }
22
+ exports.default = buildCallbackSkill;
@@ -0,0 +1,2 @@
1
+ import SprucebotLlmFactory from '../bots/SprucebotLlmFactory';
2
+ export default function buildJokeSkill(bots: SprucebotLlmFactory): import("../llm.types").SprucebotLLmSkill<import("@sprucelabs/schema").Schema, import("@sprucelabs/schema").SchemaStaticValues<import("@sprucelabs/schema").Schema, false, never, import("@sprucelabs/schema").StaticSchemaAllValues<import("@sprucelabs/schema").Schema, false>>>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function buildJokeSkill(bots) {
4
+ return bots.Skill({
5
+ yourJobIfYouChooseToAcceptItIs: 'to tell knock knock jokes!',
6
+ pleaseKeepInMindThat: [
7
+ 'our audience is younger, so keep it PG!',
8
+ 'you should never laugh when someone does not get the joke.',
9
+ "after each joke, you should tell me how many jokes you have left to tell before we're done.",
10
+ 'you should acknowledge if someone laughs at your joke by saying "Thanks!" or "Glad you thought that was funny"!',
11
+ ],
12
+ weAreDoneWhen: 'you have told 3 jokes!',
13
+ });
14
+ }
15
+ exports.default = buildJokeSkill;
@@ -0,0 +1,2 @@
1
+ import SprucebotLlmFactory from '../bots/SprucebotLlmFactory';
2
+ export default function buildProfileSkill(bots: SprucebotLlmFactory): import("../llm.types").SprucebotLLmSkill<import("@sprucelabs/schema").Schema, import("@sprucelabs/schema").SchemaStaticValues<import("@sprucelabs/schema").Schema, false, never, import("@sprucelabs/schema").StaticSchemaAllValues<import("@sprucelabs/schema").Schema, false>>>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schema_1 = require("@sprucelabs/schema");
4
+ function buildProfileSkill(bots) {
5
+ return bots.Skill({
6
+ 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',
7
+ stateSchema: (0, schema_1.buildSchema)({
8
+ id: 'profile',
9
+ fields: {
10
+ firstName: {
11
+ type: 'text',
12
+ label: 'First name',
13
+ },
14
+ lastName: {
15
+ type: 'text',
16
+ label: 'Last name',
17
+ },
18
+ favoriteColor: {
19
+ type: 'select',
20
+ options: {
21
+ choices: [
22
+ { label: 'Red', value: 'red' },
23
+ { label: 'Blue', value: 'blue' },
24
+ { label: 'Green', value: 'green' },
25
+ ],
26
+ },
27
+ },
28
+ },
29
+ }),
30
+ });
31
+ }
32
+ exports.default = buildProfileSkill;
File without changes
package/build/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //exports go here
@@ -0,0 +1,61 @@
1
+ import { MercuryEventEmitter } from '@sprucelabs/mercury-types';
2
+ import { Schema, SchemaValues } from '@sprucelabs/schema';
3
+ export interface BotOptions<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends Omit<PromptOptions<StateSchema, State>, 'skill'> {
4
+ adapter: LlmAdapter;
5
+ Class?: new (...opts: any[]) => SprucebotLlmBot<Schema, State>;
6
+ skill?: SprucebotLLmSkill<Schema>;
7
+ }
8
+ export interface SprucebotLlmBot<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends MercuryEventEmitter<LlmEventContract> {
9
+ markAsDone(): void;
10
+ getIsDone(): boolean;
11
+ sendMessage(message: string): Promise<string>;
12
+ serialize(): SerializedBot<StateSchema, State>;
13
+ updateState(state: Partial<State>): Promise<void>;
14
+ }
15
+ export interface LlmAdapter {
16
+ sendMessage(bot: SprucebotLlmBot<Schema>): Promise<string>;
17
+ }
18
+ export interface PromptOptions<StateSchema extends Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> {
19
+ /**
20
+ * Tell the bot who/what it is. Example: youAre: "a super funny comedian. You absolutely love dad jokes!"
21
+ */
22
+ youAre: string;
23
+ stateSchema?: StateSchema;
24
+ state?: Partial<State>;
25
+ skill?: SerializedSkill<Schema>;
26
+ }
27
+ export interface SerializedBot<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends PromptOptions<Schema, State> {
28
+ messages: LlmMessage[];
29
+ }
30
+ export declare const llmEventContract: {
31
+ eventSignatures: {
32
+ 'did-update-state': {};
33
+ };
34
+ };
35
+ export type LlmEventContract = typeof llmEventContract;
36
+ export interface LlmMessage {
37
+ from: 'Me' | 'You';
38
+ message: string;
39
+ }
40
+ export interface SkillOptions<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> {
41
+ yourJobIfYouChooseToAcceptItIs: string;
42
+ weAreDoneWhen?: string;
43
+ pleaseKeepInMindThat?: string[];
44
+ stateSchema?: StateSchema;
45
+ state?: Partial<State>;
46
+ callbacks?: LlmCallbackMap;
47
+ }
48
+ export interface SprucebotLLmSkill<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends MercuryEventEmitter<LlmEventContract> {
49
+ getState(): Partial<State> | undefined;
50
+ serialize(): SerializedSkill<StateSchema, State>;
51
+ updateState(state: Partial<State>): Promise<void>;
52
+ }
53
+ export interface SerializedSkill<StateSchema extends Schema = Schema, State extends SchemaValues<StateSchema> = SchemaValues<StateSchema>> extends SkillOptions<StateSchema, State> {
54
+ }
55
+ export interface LlmCallbackMap {
56
+ [key: string]: LlmCallback;
57
+ }
58
+ export interface LlmCallback {
59
+ cb: () => string | Promise<string>;
60
+ useThisWhenever: string;
61
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.llmEventContract = void 0;
4
+ const mercury_types_1 = require("@sprucelabs/mercury-types");
5
+ exports.llmEventContract = (0, mercury_types_1.buildEventContract)({
6
+ eventSignatures: {
7
+ 'did-update-state': {},
8
+ },
9
+ });
@@ -0,0 +1,15 @@
1
+ import { LlmCallbackMap } from '../llm.types';
2
+ export default class ResponseParser {
3
+ private static instance;
4
+ static setInstance(parser: ResponseParser): void;
5
+ static getInstance(): ResponseParser;
6
+ parse(response: string, callbacks?: LlmCallbackMap): Promise<ParsedResponse>;
7
+ private invokeCallback;
8
+ private doesIncludeDoneToken;
9
+ private parseState;
10
+ }
11
+ export interface ParsedResponse {
12
+ isDone: boolean;
13
+ state?: Record<string, any>;
14
+ message: string;
15
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const templates_1 = require("../bots/templates");
7
+ const renderPlaceholder_1 = __importDefault(require("./renderPlaceholder"));
8
+ class ResponseParser {
9
+ static setInstance(parser) {
10
+ this.instance = parser;
11
+ }
12
+ static getInstance() {
13
+ return this.instance;
14
+ }
15
+ async parse(response, callbacks) {
16
+ let message = response.replace(templates_1.DONE_TOKEN, '').trim();
17
+ let state;
18
+ for (const key of Object.keys(callbacks || {})) {
19
+ const match = message.match((0, renderPlaceholder_1.default)(key));
20
+ if (match) {
21
+ message = await this.invokeCallback(callbacks, key, message);
22
+ }
23
+ }
24
+ const { match, fullMatch } = this.parseState(message);
25
+ if (match && fullMatch) {
26
+ message = message.replace(fullMatch, '').trim();
27
+ state = JSON.parse(match);
28
+ }
29
+ return {
30
+ isDone: this.doesIncludeDoneToken(response),
31
+ state,
32
+ message,
33
+ };
34
+ }
35
+ async invokeCallback(callbacks, key, message) {
36
+ var _a;
37
+ const v = await ((_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks[key]) === null || _a === void 0 ? void 0 : _a.cb());
38
+ message = message.replace((0, renderPlaceholder_1.default)(key), v !== null && v !== void 0 ? v : '').trim();
39
+ return message;
40
+ }
41
+ doesIncludeDoneToken(response) {
42
+ return response.includes(templates_1.DONE_TOKEN);
43
+ }
44
+ parseState(message) {
45
+ const ESCAPED_BOUNDARY = templates_1.STATE_BOUNDARY.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
46
+ const searchRegex = new RegExp(`${ESCAPED_BOUNDARY}(.*?)${ESCAPED_BOUNDARY}`);
47
+ const stateMatches = message.match(searchRegex);
48
+ const match = stateMatches === null || stateMatches === void 0 ? void 0 : stateMatches[1];
49
+ return { match, fullMatch: stateMatches === null || stateMatches === void 0 ? void 0 : stateMatches[0] };
50
+ }
51
+ }
52
+ exports.default = ResponseParser;
53
+ ResponseParser.instance = new ResponseParser();
@@ -0,0 +1 @@
1
+ export default function renderPlaceholder(key: string): string;