@botonic/plugin-ai-agents 0.36.0-alpha.0 → 0.36.0-alpha.2
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/lib/cjs/ai-agent-client.d.ts +9 -10
- package/lib/cjs/ai-agent-client.js +37 -65
- package/lib/cjs/ai-agent-client.js.map +1 -1
- package/lib/cjs/constants.d.ts +4 -0
- package/lib/cjs/constants.js +5 -1
- package/lib/cjs/constants.js.map +1 -1
- package/lib/cjs/hubtype-client.d.ts +7 -0
- package/lib/cjs/hubtype-client.js +37 -0
- package/lib/cjs/hubtype-client.js.map +1 -0
- package/lib/cjs/index.d.ts +5 -5
- package/lib/cjs/index.js +28 -3
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/tools.d.ts +6 -0
- package/lib/cjs/tools.js +41 -0
- package/lib/cjs/tools.js.map +1 -0
- package/lib/cjs/types.d.ts +21 -23
- package/lib/cjs/utils.d.ts +2 -0
- package/lib/cjs/utils.js +22 -0
- package/lib/cjs/utils.js.map +1 -0
- package/lib/esm/ai-agent-client.d.ts +9 -10
- package/lib/esm/ai-agent-client.js +37 -65
- package/lib/esm/ai-agent-client.js.map +1 -1
- package/lib/esm/constants.d.ts +4 -0
- package/lib/esm/constants.js +4 -0
- package/lib/esm/constants.js.map +1 -1
- package/lib/esm/hubtype-client.d.ts +7 -0
- package/lib/esm/hubtype-client.js +33 -0
- package/lib/esm/hubtype-client.js.map +1 -0
- package/lib/esm/index.d.ts +5 -5
- package/lib/esm/index.js +28 -3
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/tools.d.ts +6 -0
- package/lib/esm/tools.js +38 -0
- package/lib/esm/tools.js.map +1 -0
- package/lib/esm/types.d.ts +21 -23
- package/lib/esm/utils.d.ts +2 -0
- package/lib/esm/utils.js +18 -0
- package/lib/esm/utils.js.map +1 -0
- package/package.json +5 -2
- package/src/ai-agent-client.ts +56 -95
- package/src/constants.ts +6 -0
- package/src/hubtype-client.ts +43 -0
- package/src/index.ts +40 -7
- package/src/tools.ts +51 -0
- package/src/types.ts +27 -21
- package/src/utils.ts +24 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { HUBTYPE_API_URL } from './constants';
|
|
4
|
+
export class HubtypeClient {
|
|
5
|
+
constructor(authToken) {
|
|
6
|
+
this.authToken = authToken;
|
|
7
|
+
}
|
|
8
|
+
getMessages(request, memoryLength) {
|
|
9
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10
|
+
const url = `${HUBTYPE_API_URL}/external/v1/ai/agent/message_history/`;
|
|
11
|
+
const headers = {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
14
|
+
};
|
|
15
|
+
const params = {
|
|
16
|
+
last_message_id: request.input.message_id,
|
|
17
|
+
num_messages: memoryLength,
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
const messages = yield axios.get(url, {
|
|
21
|
+
headers,
|
|
22
|
+
params,
|
|
23
|
+
});
|
|
24
|
+
return messages.data.messages;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error(error);
|
|
28
|
+
throw new Error('Failed to get messages from Hubtype');
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=hubtype-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubtype-client.js","sourceRoot":"","sources":["../../src/hubtype-client.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAG7C,MAAM,OAAO,aAAa;IAGxB,YAAY,SAAiB;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAEK,WAAW,CACf,OAAmB,EACnB,YAAoB;;YAEpB,MAAM,GAAG,GAAG,GAAG,eAAe,wCAAwC,CAAA;YACtE,MAAM,OAAO,GAAG;gBACd,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,SAAS,EAAE;aAC1C,CAAA;YACD,MAAM,MAAM,GAAG;gBACb,eAAe,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU;gBACzC,YAAY,EAAE,YAAY;aAC3B,CAAA;YAED,IAAI;gBACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAC9B,GAAG,EACH;oBACE,OAAO;oBACP,MAAM;iBACP,CACF,CAAA;gBAED,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAA;aAC9B;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;gBACpB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;aACvD;QACH,CAAC;KAAA;CACF"}
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BotContext, Plugin } from '@botonic/core';
|
|
2
|
-
import {
|
|
3
|
-
import { AiAgentArgs, AiAgentResponse } from './types';
|
|
2
|
+
import { AgenticOutputMessage, AiAgentArgs, PluginAiAgentOptions } from './types';
|
|
4
3
|
export default class BotonicPluginAiAgents implements Plugin {
|
|
5
|
-
|
|
6
|
-
constructor();
|
|
4
|
+
private readonly authToken?;
|
|
5
|
+
constructor(options?: PluginAiAgentOptions);
|
|
7
6
|
pre(): void;
|
|
8
|
-
getInference(request: BotContext, aiAgentArgs: AiAgentArgs): Promise<
|
|
7
|
+
getInference(request: BotContext, aiAgentArgs: AiAgentArgs): Promise<AgenticOutputMessage | undefined>;
|
|
9
8
|
}
|
|
9
|
+
export * from './types';
|
package/lib/esm/index.js
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { AiAgentClient } from './ai-agent-client';
|
|
3
|
+
import { HubtypeClient } from './hubtype-client';
|
|
4
|
+
import { MANDATORY_TOOLS } from './tools';
|
|
5
|
+
import { loadChatModel } from './utils';
|
|
6
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
3
7
|
export default class BotonicPluginAiAgents {
|
|
4
|
-
constructor() {
|
|
5
|
-
this.
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.authToken = options === null || options === void 0 ? void 0 : options.authToken;
|
|
6
10
|
}
|
|
7
11
|
pre() {
|
|
8
12
|
return;
|
|
9
13
|
}
|
|
10
14
|
getInference(request, aiAgentArgs) {
|
|
11
15
|
return __awaiter(this, void 0, void 0, function* () {
|
|
12
|
-
|
|
16
|
+
try {
|
|
17
|
+
const authToken = isProd ? request.session._access_token : this.authToken;
|
|
18
|
+
if (!authToken) {
|
|
19
|
+
throw new Error('Auth token is required');
|
|
20
|
+
}
|
|
21
|
+
const hubtypeClient = new HubtypeClient(authToken);
|
|
22
|
+
const messages = isProd
|
|
23
|
+
? yield hubtypeClient.getMessages(request, 10)
|
|
24
|
+
: [{ role: 'user', content: request.input.data }];
|
|
25
|
+
const customTools = [];
|
|
26
|
+
const chatModel = loadChatModel('azureOpenAI');
|
|
27
|
+
const aiAgentClient = new AiAgentClient(aiAgentArgs, chatModel, [
|
|
28
|
+
...customTools,
|
|
29
|
+
...MANDATORY_TOOLS,
|
|
30
|
+
]);
|
|
31
|
+
return yield aiAgentClient.runAgent(messages);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error('error plugin returns undefined', error);
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
13
37
|
});
|
|
14
38
|
}
|
|
15
39
|
}
|
|
40
|
+
export * from './types';
|
|
16
41
|
//# sourceMappingURL=index.js.map
|
package/lib/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEvC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAA;AAEpD,MAAM,CAAC,OAAO,OAAO,qBAAqB;IAExC,YAAY,OAA8B;QACxC,IAAI,CAAC,SAAS,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,CAAA;IACrC,CAAC;IAED,GAAG;QACD,OAAM;IACR,CAAC;IAEK,YAAY,CAChB,OAAmB,EACnB,WAAwB;;YAExB,IAAI;gBACF,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAA;gBACzE,IAAI,CAAC,SAAS,EAAE;oBACd,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;iBAC1C;gBAED,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,CAAA;gBAClD,MAAM,QAAQ,GAAG,MAAM;oBACrB,CAAC,CAAC,MAAM,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC9C,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAiB,CAAC,CAAA;gBAElE,MAAM,WAAW,GAAG,EAAE,CAAA;gBACtB,MAAM,SAAS,GAAG,aAAa,CAAC,aAAa,CAAC,CAAA;gBAC9C,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,WAAW,EAAE,SAAS,EAAE;oBAC9D,GAAG,WAAW;oBACd,GAAG,eAAe;iBACnB,CAAC,CAAA;gBAEF,OAAO,MAAM,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;aAC9C;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAA;gBACtD,OAAO,SAAS,CAAA;aACjB;QACH,CAAC;KAAA;CACF;AAED,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const handoffToHumanAgent: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, {}, {}, null>;
|
|
3
|
+
export declare const outOfContext: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, {}, {}, null>;
|
|
4
|
+
export declare const finishConversation: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, {}, {}, null>;
|
|
5
|
+
export declare const MANDATORY_TOOLS: import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, {}, {}, null>[];
|
|
6
|
+
export declare const EXIT_TOOLS: string[];
|
package/lib/esm/tools.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { tool } from '@langchain/core/tools';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export const handoffToHumanAgent = tool(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
return null;
|
|
6
|
+
}), {
|
|
7
|
+
name: 'handoffToHumanAgent',
|
|
8
|
+
schema: z.object({}),
|
|
9
|
+
description: 'Use this tool strictly when the user wants to talk with a human agent.',
|
|
10
|
+
returnDirect: true,
|
|
11
|
+
});
|
|
12
|
+
export const outOfContext = tool(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
13
|
+
return null;
|
|
14
|
+
}), {
|
|
15
|
+
name: 'outOfContext',
|
|
16
|
+
schema: z.object({}),
|
|
17
|
+
description: 'Use this when the user talks about something that is clearly out of your context. Example: "I want to buy a car" when you are a travel agent.',
|
|
18
|
+
returnDirect: true,
|
|
19
|
+
});
|
|
20
|
+
export const finishConversation = tool(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
return null;
|
|
22
|
+
}), {
|
|
23
|
+
name: 'finishConversation',
|
|
24
|
+
schema: z.object({}),
|
|
25
|
+
description: 'Use this when the user wants to end the conversation.',
|
|
26
|
+
returnDirect: true,
|
|
27
|
+
});
|
|
28
|
+
export const MANDATORY_TOOLS = [
|
|
29
|
+
handoffToHumanAgent,
|
|
30
|
+
outOfContext,
|
|
31
|
+
finishConversation,
|
|
32
|
+
];
|
|
33
|
+
export const EXIT_TOOLS = [
|
|
34
|
+
handoffToHumanAgent.name,
|
|
35
|
+
outOfContext.name,
|
|
36
|
+
finishConversation.name,
|
|
37
|
+
];
|
|
38
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/tools.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CACrC,GAAS,EAAE;IACT,OAAO,IAAI,CAAA;AACb,CAAC,CAAA,EACD;IACE,IAAI,EAAE,qBAAqB;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,WAAW,EACT,wEAAwE;IAC1E,YAAY,EAAE,IAAI;CACnB,CACF,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAC9B,GAAS,EAAE;IACT,OAAO,IAAI,CAAA;AACb,CAAC,CAAA,EACD;IACE,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,WAAW,EACT,+IAA+I;IACjJ,YAAY,EAAE,IAAI;CACnB,CACF,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CACpC,GAAS,EAAE;IACT,OAAO,IAAI,CAAA;AACb,CAAC,CAAA,EACD;IACE,IAAI,EAAE,oBAAoB;IAC1B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,WAAW,EAAE,uDAAuD;IACpE,YAAY,EAAE,IAAI;CACnB,CACF,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,mBAAmB;IACnB,YAAY;IACZ,kBAAkB;CACnB,CAAA;AACD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,mBAAmB,CAAC,IAAI;IACxB,YAAY,CAAC,IAAI;IACjB,kBAAkB,CAAC,IAAI;CACxB,CAAA"}
|
package/lib/esm/types.d.ts
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
|
+
export interface PluginAiAgentOptions {
|
|
2
|
+
authToken?: string;
|
|
3
|
+
}
|
|
1
4
|
export interface AiAgentArgs {
|
|
2
5
|
name: string;
|
|
3
6
|
instructions: string;
|
|
4
7
|
}
|
|
5
|
-
export interface
|
|
6
|
-
|
|
7
|
-
Authorization: string;
|
|
8
|
-
'Content-Type': string;
|
|
9
|
-
};
|
|
8
|
+
export interface AgenticBaseMessage {
|
|
9
|
+
role: 'assistant' | 'user' | 'tool' | 'exit';
|
|
10
10
|
}
|
|
11
|
-
export interface
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
content: string;
|
|
15
|
-
}[];
|
|
16
|
-
name: string;
|
|
17
|
-
instructions: string;
|
|
11
|
+
export interface AssistantMessage extends AgenticBaseMessage {
|
|
12
|
+
role: 'assistant';
|
|
13
|
+
content: string;
|
|
18
14
|
}
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
export interface UserMessage extends AgenticBaseMessage {
|
|
16
|
+
role: 'user';
|
|
17
|
+
content: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ToolMessage extends AgenticBaseMessage {
|
|
20
|
+
role: 'tool';
|
|
21
|
+
toolName: string;
|
|
22
|
+
toolOutput: string | null;
|
|
25
23
|
}
|
|
26
|
-
export interface
|
|
27
|
-
|
|
28
|
-
role: string;
|
|
29
|
-
content: string;
|
|
30
|
-
};
|
|
24
|
+
export interface ExitMessage extends AgenticBaseMessage {
|
|
25
|
+
role: 'exit';
|
|
31
26
|
}
|
|
27
|
+
export type AgenticInputMessage = AssistantMessage | UserMessage;
|
|
28
|
+
export type AgenticOutputMessage = AssistantMessage | ToolMessage | ExitMessage;
|
|
29
|
+
export type AgenticMessage = AssistantMessage | UserMessage | ToolMessage | ExitMessage;
|
package/lib/esm/utils.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AzureChatOpenAI } from '@langchain/openai';
|
|
2
|
+
import { AZURE_OPENAI_API_BASE, AZURE_OPENAI_API_DEPLOYMENT_NAME, AZURE_OPENAI_API_KEY, AZURE_OPENAI_API_VERSION, } from './constants';
|
|
3
|
+
export function loadChatModel(provider) {
|
|
4
|
+
switch (provider) {
|
|
5
|
+
case 'azureOpenAI':
|
|
6
|
+
return new AzureChatOpenAI({
|
|
7
|
+
azureOpenAIApiVersion: AZURE_OPENAI_API_VERSION,
|
|
8
|
+
azureOpenAIApiKey: AZURE_OPENAI_API_KEY,
|
|
9
|
+
azureOpenAIApiDeploymentName: AZURE_OPENAI_API_DEPLOYMENT_NAME,
|
|
10
|
+
azureOpenAIEndpoint: AZURE_OPENAI_API_BASE,
|
|
11
|
+
temperature: 0,
|
|
12
|
+
// other params...
|
|
13
|
+
});
|
|
14
|
+
default:
|
|
15
|
+
throw new Error(`Provider ${provider} not supported`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,EACL,qBAAqB,EACrB,gCAAgC,EAChC,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,MAAM,UAAU,aAAa,CAAC,QAAuB;IACnD,QAAQ,QAAQ,EAAE;QAChB,KAAK,aAAa;YAChB,OAAO,IAAI,eAAe,CAAC;gBACzB,qBAAqB,EAAE,wBAAwB;gBAC/C,iBAAiB,EAAE,oBAAoB;gBACvC,4BAA4B,EAAE,gCAAgC;gBAC9D,mBAAmB,EAAE,qBAAqB;gBAC1C,WAAW,EAAE,CAAC;gBACd,kBAAkB;aACnB,CAAC,CAAA;QACJ;YACE,MAAM,IAAI,KAAK,CAAC,YAAY,QAAQ,gBAAgB,CAAC,CAAA;KACxD;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botonic/plugin-ai-agents",
|
|
3
|
-
"version": "0.36.0-alpha.
|
|
3
|
+
"version": "0.36.0-alpha.2",
|
|
4
4
|
"main": "./lib/cjs/index.js",
|
|
5
5
|
"module": "./lib/esm/index.js",
|
|
6
6
|
"description": "Use AI Agents to generate your contents",
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
"lint_core": "../../node_modules/.bin/eslint_d --cache --quiet 'src/**/*.ts*'"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@botonic/core": "^0.
|
|
16
|
+
"@botonic/core": "^0.36.0-alpha.0",
|
|
17
|
+
"@langchain/core": "^0.3.57",
|
|
18
|
+
"@langchain/langgraph": "^0.3.0",
|
|
19
|
+
"@langchain/openai": "^0.5.12",
|
|
17
20
|
"axios": "^1.9.0",
|
|
18
21
|
"uuid": "^10.0.0"
|
|
19
22
|
},
|
package/src/ai-agent-client.ts
CHANGED
|
@@ -1,112 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { BaseChatModel } from '@langchain/core/language_models/chat_models'
|
|
2
|
+
import {
|
|
3
|
+
AIMessage as LangchainAIMessage,
|
|
4
|
+
ToolMessage as LangchainToolMessage,
|
|
5
|
+
} from '@langchain/core/messages'
|
|
6
|
+
import { StructuredTool } from '@langchain/core/tools'
|
|
7
|
+
import { CompiledStateGraph } from '@langchain/langgraph'
|
|
8
|
+
import { createReactAgent } from '@langchain/langgraph/prebuilt'
|
|
4
9
|
|
|
5
|
-
import {
|
|
6
|
-
import { AiAgentError } from './errors'
|
|
10
|
+
import { EXIT_TOOLS } from './tools'
|
|
7
11
|
import {
|
|
12
|
+
AgenticInputMessage,
|
|
13
|
+
AgenticOutputMessage,
|
|
8
14
|
AiAgentArgs,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Config,
|
|
15
|
+
AssistantMessage,
|
|
16
|
+
ExitMessage,
|
|
17
|
+
ToolMessage,
|
|
13
18
|
} from './types'
|
|
14
19
|
|
|
15
20
|
export class AiAgentClient {
|
|
16
|
-
|
|
21
|
+
public name: string
|
|
22
|
+
public instructions: string
|
|
23
|
+
public agent: CompiledStateGraph<any, any> // TODO: apply RunInput, RunOutput, etc.
|
|
17
24
|
|
|
18
|
-
constructor(
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
constructor(
|
|
26
|
+
aiAgentArgs: AiAgentArgs,
|
|
27
|
+
chatModel: BaseChatModel,
|
|
28
|
+
tools: StructuredTool[] = []
|
|
29
|
+
) {
|
|
30
|
+
this.name = aiAgentArgs.name
|
|
31
|
+
this.instructions = aiAgentArgs.instructions
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return this.agentTestInference(request, aiAgentArgs)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return this.agentInference(request, aiAgentArgs)
|
|
33
|
+
this.agent = createReactAgent({
|
|
34
|
+
llm: chatModel,
|
|
35
|
+
tools: tools,
|
|
36
|
+
prompt: this.instructions,
|
|
37
|
+
})
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
return response.data
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private async agentInference(
|
|
49
|
-
request: BotContext,
|
|
50
|
-
aiAgentArgs: AiAgentArgs
|
|
51
|
-
): Promise<AiAgentResponse> {
|
|
52
|
-
const config = this.getConfig(request)
|
|
53
|
-
const data = this.getData(request, aiAgentArgs)
|
|
54
|
-
const response = await axios.post<AiAgentResponse>(
|
|
55
|
-
`${this.url}/run/`,
|
|
56
|
-
data,
|
|
57
|
-
config
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
return response.data
|
|
61
|
-
}
|
|
40
|
+
async runAgent(
|
|
41
|
+
_messages: AgenticInputMessage[]
|
|
42
|
+
): Promise<AgenticOutputMessage> {
|
|
43
|
+
const response = await this.agent.invoke({
|
|
44
|
+
messages: _messages.map((message: AgenticInputMessage) => ({
|
|
45
|
+
role: message.role,
|
|
46
|
+
content: message.content,
|
|
47
|
+
})),
|
|
48
|
+
})
|
|
49
|
+
const lastMessage = response.messages.at(-1)
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
51
|
+
if (lastMessage instanceof LangchainToolMessage) {
|
|
52
|
+
if (lastMessage.name && EXIT_TOOLS.includes(lastMessage.name)) {
|
|
53
|
+
return {
|
|
54
|
+
role: 'exit',
|
|
55
|
+
} as ExitMessage
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
role: 'tool',
|
|
59
|
+
toolName: lastMessage.name,
|
|
60
|
+
toolOutput: lastMessage.content,
|
|
61
|
+
} as ToolMessage
|
|
69
62
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private getData(
|
|
73
|
-
request: BotContext,
|
|
74
|
-
aiAgentArgs: AiAgentArgs
|
|
75
|
-
): AiAgentRequestData {
|
|
76
|
-
if (!request.input.data) {
|
|
77
|
-
throw new AiAgentError('No input data provided')
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
message: request.input.message_id,
|
|
82
|
-
memory_length: 10,
|
|
83
|
-
name: aiAgentArgs.name,
|
|
84
|
-
instructions: aiAgentArgs.instructions,
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
63
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
throw new AiAgentError('No input data provided')
|
|
64
|
+
if (lastMessage instanceof LangchainAIMessage) {
|
|
65
|
+
return {
|
|
66
|
+
role: 'assistant',
|
|
67
|
+
content: lastMessage.content,
|
|
68
|
+
} as AssistantMessage
|
|
94
69
|
}
|
|
95
70
|
|
|
96
|
-
|
|
97
|
-
// if (isDev(request.session)) {
|
|
98
|
-
// const messages = localStorage.getItem('botonicState').
|
|
99
|
-
// }
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
messages: [
|
|
103
|
-
{
|
|
104
|
-
role: 'user',
|
|
105
|
-
content: request.input.data,
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
name: aiAgentArgs.name,
|
|
109
|
-
instructions: aiAgentArgs.instructions,
|
|
110
|
-
}
|
|
71
|
+
throw new Error('Last message is not a valid message')
|
|
111
72
|
}
|
|
112
73
|
}
|
package/src/constants.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export const HUBTYPE_API_URL =
|
|
2
2
|
process.env.HUBTYPE_API_URL || 'https://api.hubtype.com'
|
|
3
|
+
|
|
4
|
+
export const AZURE_OPENAI_API_KEY = process.env.AZURE_OPENAI_API_KEY
|
|
5
|
+
export const AZURE_OPENAI_API_DEPLOYMENT_NAME =
|
|
6
|
+
process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME
|
|
7
|
+
export const AZURE_OPENAI_API_VERSION = process.env.AZURE_OPENAI_API_VERSION
|
|
8
|
+
export const AZURE_OPENAI_API_BASE = process.env.AZURE_OPENAI_API_BASE
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BotContext } from '@botonic/core'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
|
|
4
|
+
import { HUBTYPE_API_URL } from './constants'
|
|
5
|
+
import { AgenticInputMessage } from './types'
|
|
6
|
+
|
|
7
|
+
export class HubtypeClient {
|
|
8
|
+
private readonly authToken: string
|
|
9
|
+
|
|
10
|
+
constructor(authToken: string) {
|
|
11
|
+
this.authToken = authToken
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async getMessages(
|
|
15
|
+
request: BotContext,
|
|
16
|
+
memoryLength: number
|
|
17
|
+
): Promise<AgenticInputMessage[]> {
|
|
18
|
+
const url = `${HUBTYPE_API_URL}/external/v1/ai/agent/message_history/`
|
|
19
|
+
const headers = {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
22
|
+
}
|
|
23
|
+
const params = {
|
|
24
|
+
last_message_id: request.input.message_id,
|
|
25
|
+
num_messages: memoryLength,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const messages = await axios.get<{ messages: AgenticInputMessage[] }>(
|
|
30
|
+
url,
|
|
31
|
+
{
|
|
32
|
+
headers,
|
|
33
|
+
params,
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return messages.data.messages
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(error)
|
|
40
|
+
throw new Error('Failed to get messages from Hubtype')
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { BotContext, Plugin } from '@botonic/core'
|
|
2
2
|
|
|
3
3
|
import { AiAgentClient } from './ai-agent-client'
|
|
4
|
-
import {
|
|
4
|
+
import { HubtypeClient } from './hubtype-client'
|
|
5
|
+
import { MANDATORY_TOOLS } from './tools'
|
|
6
|
+
import {
|
|
7
|
+
AgenticOutputMessage,
|
|
8
|
+
AiAgentArgs,
|
|
9
|
+
PluginAiAgentOptions,
|
|
10
|
+
UserMessage,
|
|
11
|
+
} from './types'
|
|
12
|
+
import { loadChatModel } from './utils'
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
public aiAgentClient: AiAgentClient
|
|
14
|
+
const isProd = process.env.NODE_ENV === 'production'
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
export default class BotonicPluginAiAgents implements Plugin {
|
|
17
|
+
private readonly authToken?: string
|
|
18
|
+
constructor(options?: PluginAiAgentOptions) {
|
|
19
|
+
this.authToken = options?.authToken
|
|
11
20
|
}
|
|
12
21
|
|
|
13
22
|
pre(): void {
|
|
@@ -17,7 +26,31 @@ export default class BotonicPluginAiAgents implements Plugin {
|
|
|
17
26
|
async getInference(
|
|
18
27
|
request: BotContext,
|
|
19
28
|
aiAgentArgs: AiAgentArgs
|
|
20
|
-
): Promise<
|
|
21
|
-
|
|
29
|
+
): Promise<AgenticOutputMessage | undefined> {
|
|
30
|
+
try {
|
|
31
|
+
const authToken = isProd ? request.session._access_token : this.authToken
|
|
32
|
+
if (!authToken) {
|
|
33
|
+
throw new Error('Auth token is required')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const hubtypeClient = new HubtypeClient(authToken)
|
|
37
|
+
const messages = isProd
|
|
38
|
+
? await hubtypeClient.getMessages(request, 10)
|
|
39
|
+
: [{ role: 'user', content: request.input.data } as UserMessage]
|
|
40
|
+
|
|
41
|
+
const customTools = []
|
|
42
|
+
const chatModel = loadChatModel('azureOpenAI')
|
|
43
|
+
const aiAgentClient = new AiAgentClient(aiAgentArgs, chatModel, [
|
|
44
|
+
...customTools,
|
|
45
|
+
...MANDATORY_TOOLS,
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
return await aiAgentClient.runAgent(messages)
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('error plugin returns undefined', error)
|
|
51
|
+
return undefined
|
|
52
|
+
}
|
|
22
53
|
}
|
|
23
54
|
}
|
|
55
|
+
|
|
56
|
+
export * from './types'
|
package/src/tools.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { tool } from '@langchain/core/tools'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
export const handoffToHumanAgent = tool(
|
|
5
|
+
async () => {
|
|
6
|
+
return null
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'handoffToHumanAgent',
|
|
10
|
+
schema: z.object({}),
|
|
11
|
+
description:
|
|
12
|
+
'Use this tool strictly when the user wants to talk with a human agent.',
|
|
13
|
+
returnDirect: true,
|
|
14
|
+
}
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
export const outOfContext = tool(
|
|
18
|
+
async () => {
|
|
19
|
+
return null
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'outOfContext',
|
|
23
|
+
schema: z.object({}),
|
|
24
|
+
description:
|
|
25
|
+
'Use this when the user talks about something that is clearly out of your context. Example: "I want to buy a car" when you are a travel agent.',
|
|
26
|
+
returnDirect: true,
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
export const finishConversation = tool(
|
|
31
|
+
async () => {
|
|
32
|
+
return null
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'finishConversation',
|
|
36
|
+
schema: z.object({}),
|
|
37
|
+
description: 'Use this when the user wants to end the conversation.',
|
|
38
|
+
returnDirect: true,
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export const MANDATORY_TOOLS = [
|
|
43
|
+
handoffToHumanAgent,
|
|
44
|
+
outOfContext,
|
|
45
|
+
finishConversation,
|
|
46
|
+
]
|
|
47
|
+
export const EXIT_TOOLS = [
|
|
48
|
+
handoffToHumanAgent.name,
|
|
49
|
+
outOfContext.name,
|
|
50
|
+
finishConversation.name,
|
|
51
|
+
]
|
package/src/types.ts
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
export interface PluginAiAgentOptions {
|
|
2
|
+
authToken?: string
|
|
3
|
+
}
|
|
2
4
|
export interface AiAgentArgs {
|
|
3
5
|
name: string
|
|
4
6
|
instructions: string
|
|
5
7
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'Content-Type': string
|
|
10
|
-
}
|
|
8
|
+
|
|
9
|
+
export interface AgenticBaseMessage {
|
|
10
|
+
role: 'assistant' | 'user' | 'tool' | 'exit'
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export interface
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
content: string
|
|
17
|
-
}[]
|
|
18
|
-
name: string
|
|
19
|
-
instructions: string
|
|
13
|
+
export interface AssistantMessage extends AgenticBaseMessage {
|
|
14
|
+
role: 'assistant'
|
|
15
|
+
content: string
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
export
|
|
18
|
+
export interface UserMessage extends AgenticBaseMessage {
|
|
19
|
+
role: 'user'
|
|
20
|
+
content: string
|
|
21
|
+
}
|
|
23
22
|
|
|
24
|
-
export interface
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
instructions: string
|
|
23
|
+
export interface ToolMessage extends AgenticBaseMessage {
|
|
24
|
+
role: 'tool'
|
|
25
|
+
toolName: string
|
|
26
|
+
toolOutput: string | null
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
export interface
|
|
32
|
-
|
|
29
|
+
export interface ExitMessage extends AgenticBaseMessage {
|
|
30
|
+
role: 'exit'
|
|
33
31
|
}
|
|
32
|
+
|
|
33
|
+
export type AgenticInputMessage = AssistantMessage | UserMessage
|
|
34
|
+
export type AgenticOutputMessage = AssistantMessage | ToolMessage | ExitMessage
|
|
35
|
+
export type AgenticMessage =
|
|
36
|
+
| AssistantMessage
|
|
37
|
+
| UserMessage
|
|
38
|
+
| ToolMessage
|
|
39
|
+
| ExitMessage
|