Skip to content

Commit f16db7c

Browse files
committed
feat: use previousMessages for AiAgent Context
1 parent 27543bc commit f16db7c

File tree

10 files changed

+118
-108
lines changed

10 files changed

+118
-108
lines changed

packages/botonic-core/src/models/ai-agents.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ export enum VerbosityLevel {
9393
High = 'high',
9494
}
9595

96+
export interface HubtypeAssistantMessage {
97+
role: 'assistant'
98+
content: string
99+
}
100+
101+
export interface HubtypeUserMessage {
102+
role: 'user'
103+
content: string
104+
}
105+
96106
export interface AiAgentArgs {
97107
name: string
98108
instructions: string
@@ -101,5 +111,5 @@ export interface AiAgentArgs {
101111
activeTools?: { name: string }[]
102112
inputGuardrailRules?: GuardrailRule[]
103113
sourceIds?: string[]
104-
previousFollowUps?: any[]
114+
previousHubtypeMessages?: HubtypeAssistantMessage[]
105115
}

packages/botonic-plugin-ai-agents/src/debug-logger.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { AiAgentArgs, ToolExecution } from '@botonic/core'
22
import type { ModelSettings } from '@openai/agents'
3-
import { MAX_MEMORY_LENGTH, OPENAI_PROVIDER } from './constants'
3+
import { OPENAI_PROVIDER } from './constants'
44
import type { AgenticInputMessage, MemoryOptions, RunResult } from './types'
55

66
const PREFIX = '[BotonicPluginAiAgents]'
@@ -50,10 +50,10 @@ class EnabledDebugLogger implements DebugLogger {
5050
`${PREFIX} Custom Tools Registered: ${config.customToolNames.join(', ') || 'none'}`
5151
)
5252
console.log(`${PREFIX} Memory Options:`, {
53-
maxMessages: config.memory.maxMessages ?? MAX_MEMORY_LENGTH,
54-
includeToolCalls: config.memory.includeToolCalls ?? true,
55-
maxFullToolResults: config.memory.maxFullToolResults ?? 1,
56-
debugMode: config.memory.debugMode ?? false,
53+
maxMessages: config.memory.maxMessages,
54+
includeToolCalls: config.memory.includeToolCalls,
55+
maxFullToolResults: config.memory.maxFullToolResults,
56+
debugMode: config.memory.debugMode,
5757
})
5858
console.log(`${PREFIX} === End Plugin Initialization ===`)
5959
}

packages/botonic-plugin-ai-agents/src/index.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
AiAgentArgs,
33
BotContext,
4+
HubtypeAssistantMessage,
45
Plugin,
56
ResolvedPlugins,
67
} from '@botonic/core'
@@ -52,20 +53,29 @@ export default class BotonicPluginAiAgents<
5253
this.authToken = options?.authToken
5354
this.toolDefinitions = options?.customTools || []
5455
this.messageHistoryApiVersion = options?.messageHistoryApiVersion ?? 'v2'
55-
this.memory = options?.memory ?? {}
56+
this.memory = this.getMemoryOptions(options?.memory)
5657
this.timeout = options?.timeout ?? DEFAULT_TIMEOUT_16_SECONDS
5758
this.maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES
5859
this.logger = createDebugLogger(options?.enableDebug ?? false)
5960

6061
this.logger.logInitialConfig({
6162
messageHistoryApiVersion: this.messageHistoryApiVersion,
62-
maxRetries: options?.maxRetries ?? 2,
63-
timeout: options?.timeout ?? 16000,
63+
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES,
64+
timeout: options?.timeout ?? DEFAULT_TIMEOUT_16_SECONDS,
6465
customToolNames: this.toolDefinitions.map(t => t.name),
6566
memory: this.memory,
6667
})
6768
}
6869

70+
private getMemoryOptions(memory?: Partial<MemoryOptions>): MemoryOptions {
71+
return {
72+
maxMessages: memory?.maxMessages ?? MAX_MEMORY_LENGTH,
73+
includeToolCalls: memory?.includeToolCalls ?? true,
74+
maxFullToolResults: memory?.maxFullToolResults ?? 1,
75+
debugMode: memory?.debugMode ?? false,
76+
}
77+
}
78+
6979
pre(): void {
7080
return
7181
}
@@ -120,7 +130,7 @@ export default class BotonicPluginAiAgents<
120130
const messages = await this.getMessages(
121131
botContext,
122132
authToken,
123-
MAX_MEMORY_LENGTH
133+
aiAgentArgs.previousHubtypeMessages || []
124134
)
125135

126136
// Build context
@@ -168,25 +178,22 @@ export default class BotonicPluginAiAgents<
168178
private async getMessages(
169179
botContext: BotContext,
170180
authToken: string,
171-
memoryLength: number
181+
previousHubtypeMessages: HubtypeAssistantMessage[]
172182
): Promise<AgenticInputMessage[]> {
173183
const hubtypeClient = new HubtypeApiClient(authToken)
174-
175184
if (!isProd) {
176-
return await hubtypeClient.getLocalMessages(memoryLength)
185+
return await hubtypeClient.getLocalMessages(
186+
MAX_MEMORY_LENGTH,
187+
previousHubtypeMessages
188+
)
177189
}
178190

179-
// if (this.messageHistoryApiVersion === 'v1') {
180-
// return await hubtypeClient.getMessages(botContext, memoryLength)
181-
// }
182-
183191
// Default to V2
184-
const result = await hubtypeClient.getMessagesV2(botContext, {
185-
maxMessages: this.memory.maxMessages ?? memoryLength,
186-
includeToolCalls: this.memory.includeToolCalls ?? true,
187-
maxFullToolResults: this.memory.maxFullToolResults ?? 1,
188-
debugMode: this.memory.debugMode ?? false,
189-
})
192+
const result = await hubtypeClient.getMessagesV2(
193+
botContext,
194+
this.memory,
195+
previousHubtypeMessages
196+
)
190197
return result.messages
191198
}
192199

packages/botonic-plugin-ai-agents/src/services/hubtype-api-client.ts

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
/* eslint-disable @typescript-eslint/naming-convention */
2-
import type { BotContext } from '@botonic/core'
2+
import type { BotContext, HubtypeAssistantMessage } from '@botonic/core'
33
import axios from 'axios'
44

55
import { HUBTYPE_API_URL } from '../constants'
6-
import type { AgenticInputMessage, Chunk } from '../types'
6+
import type { AgenticInputMessage, Chunk, MemoryOptions } from '../types'
77
import type {
8-
GetMessagesV2Options,
98
GetMessagesV2Result,
109
HubtypeAssistantMessageV2,
1110
HubtypeMessage,
@@ -46,7 +45,8 @@ export class HubtypeApiClient {
4645
}
4746

4847
async getLocalMessages(
49-
maxMemoryLength: number
48+
maxMemoryLength: number,
49+
previousHubtypeMessages: HubtypeAssistantMessage[]
5050
): Promise<AgenticInputMessage[]> {
5151
const localBotonicState =
5252
typeof globalThis !== 'undefined' && globalThis.localStorage
@@ -61,39 +61,15 @@ export class HubtypeApiClient {
6161
content: message.data.text,
6262
}))
6363
.map(message => this.formatMessage(message))
64-
return filteredMessages.slice(-maxMemoryLength)
65-
}
66-
67-
// async getMessages(
68-
// botContext: BotContext,
69-
// maxMemoryLength: number
70-
// ): Promise<AgenticInputMessage[]> {
71-
// const url = `${HUBTYPE_API_URL}/external/v1/ai/agent/message_history/`
72-
// const headers = {
73-
// 'Content-Type': 'application/json',
74-
// Authorization: `Bearer ${this.authToken}`,
75-
// }
76-
// const params = {
77-
// last_message_id: botContext.input.message_id,
78-
// num_messages: maxMemoryLength,
79-
// }
64+
const resultMessages = [...filteredMessages, ...previousHubtypeMessages]
8065

81-
// try {
82-
// const response = await axios.get<{ messages: HubtypeMessage[] }>(url, {
83-
// headers,
84-
// params,
85-
// })
86-
// const messages = response.data.messages
87-
// return messages.map(message => this.formatMessage(message))
88-
// } catch (error) {
89-
// console.error(error)
90-
// throw new Error('Failed to get messages from Hubtype')
91-
// }
92-
// }
66+
return resultMessages.slice(-maxMemoryLength)
67+
}
9368

9469
async getMessagesV2(
9570
botContext: BotContext,
96-
options: GetMessagesV2Options = {}
71+
options: MemoryOptions,
72+
previousHubtypeMessages: HubtypeAssistantMessage[]
9773
): Promise<GetMessagesV2Result> {
9874
const url = `${HUBTYPE_API_URL}/external/v2/ai/agent/message_history/`
9975
const headers = {
@@ -102,18 +78,10 @@ export class HubtypeApiClient {
10278
}
10379
const params: MessageHistoryV2Params = {
10480
last_message_id: botContext.input.message_id,
105-
...(options.maxMessages !== undefined && {
106-
max_messages: options.maxMessages,
107-
}),
108-
...(options.includeToolCalls !== undefined && {
109-
include_tool_calls: options.includeToolCalls,
110-
}),
111-
...(options.maxFullToolResults !== undefined && {
112-
max_full_tool_results: options.maxFullToolResults,
113-
}),
114-
...(options.debugMode !== undefined && {
115-
debug_mode: options.debugMode,
116-
}),
81+
max_messages: options.maxMessages,
82+
include_tool_calls: options.includeToolCalls,
83+
max_full_tool_results: options.maxFullToolResults,
84+
debug_mode: options.debugMode,
11785
}
11886

11987
try {
@@ -122,9 +90,10 @@ export class HubtypeApiClient {
12290
params,
12391
})
12492
const { messages, conversation_id, truncated } = response.data
125-
const formattedMessages = messages
93+
const formattedMessages = [...messages, ...previousHubtypeMessages]
12694
.map(message => this.formatMessageV2(message))
12795
.filter((message): message is AgenticInputMessage => message !== null)
96+
12897
return {
12998
messages: formattedMessages,
13099
conversationId: conversation_id,

packages/botonic-plugin-ai-agents/src/services/types.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { HubtypeAssistantMessage, HubtypeUserMessage } from '@botonic/core'
12
import type { AgenticInputMessage } from '../types'
23

34
export enum TrackProductName {
@@ -28,16 +29,6 @@ export interface TrackLlmRunsData {
2829
llm_runs: LlmRunData[]
2930
}
3031

31-
interface HubtypeAssistantMessage {
32-
role: 'assistant'
33-
content: string
34-
}
35-
36-
interface HubtypeUserMessage {
37-
role: 'user'
38-
content: string
39-
}
40-
4132
export type HubtypeMessage = HubtypeAssistantMessage | HubtypeUserMessage
4233

4334
// V2 API Types
@@ -84,13 +75,6 @@ export interface MessageHistoryResponseV2 {
8475
truncated: boolean
8576
}
8677

87-
export interface GetMessagesV2Options {
88-
maxMessages?: number
89-
includeToolCalls?: boolean
90-
maxFullToolResults?: number
91-
debugMode?: boolean
92-
}
93-
9478
export interface GetMessagesV2Result {
9579
messages: AgenticInputMessage[]
9680
conversationId: string | null

packages/botonic-plugin-ai-agents/src/types.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ export type AIAgent<
6969
export type MessageHistoryApiVersion = 'v1' | 'v2'
7070

7171
export interface MemoryOptions {
72-
maxMessages?: number
73-
includeToolCalls?: boolean
74-
maxFullToolResults?: number
75-
debugMode?: boolean
72+
maxMessages: number
73+
includeToolCalls: boolean
74+
maxFullToolResults: number
75+
debugMode: boolean
7676
}
7777

7878
export interface PluginAiAgentOptions<
@@ -86,7 +86,7 @@ export interface PluginAiAgentOptions<
8686
/** API version for message history endpoint. Defaults to 'v2'. */
8787
messageHistoryApiVersion?: MessageHistoryApiVersion
8888
/** Options for V2 message history API. Only used when messageHistoryApiVersion is 'v2'. */
89-
memory?: MemoryOptions
89+
memory?: Partial<MemoryOptions>
9090
/** Enable debug logging for AI agent configuration and execution details. */
9191
enableDebug?: boolean
9292
}

packages/botonic-plugin-ai-agents/tests/debug-logger.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ describe('DebugLogger', () => {
5555
maxMessages: 30,
5656
includeToolCalls: true,
5757
maxFullToolResults: 2,
58+
debugMode: false,
5859
},
5960
})
6061

@@ -207,7 +208,12 @@ describe('DebugLogger', () => {
207208
maxRetries: 2,
208209
timeout: 16000,
209210
customToolNames: [],
210-
memory: {},
211+
memory: {
212+
maxMessages: 30,
213+
includeToolCalls: true,
214+
maxFullToolResults: 2,
215+
debugMode: false,
216+
},
211217
})
212218
logger.logAgentDebugInfo(
213219
{

packages/botonic-plugin-flow-builder/src/action/ai-agent.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@ export async function getContentsByAiAgent({
1515
const contents =
1616
await flowBuilderPlugin.getContentsByNode(startNodeAiAgentFlow)
1717

18-
const aiAgentContent = contents.find(
19-
content => content instanceof FlowAiAgent
20-
) as FlowAiAgent
21-
22-
if (!aiAgentContent) {
18+
const splitContents = splitAiAgentAndContentsBefore(contents)
19+
if (!splitContents) {
2320
return []
2421
}
22+
const { aiAgentContent, contentsBeforeAiAgent } = splitContents
2523

26-
const aiAgentResponse = await aiAgentContent.getAIAgentResponse(request)
24+
const aiAgentResponse = await aiAgentContent.getAIAgentResponse(
25+
request,
26+
contentsBeforeAiAgent
27+
)
2728

2829
if (!aiAgentResponse) {
2930
return []
@@ -39,3 +40,24 @@ export async function getContentsByAiAgent({
3940

4041
return contents
4142
}
43+
44+
interface SplitAiAgentAndContentsBeforeResult {
45+
aiAgentContent: FlowAiAgent
46+
contentsBeforeAiAgent: FlowContent[]
47+
}
48+
49+
export function splitAiAgentAndContentsBefore(
50+
contents: FlowContent[]
51+
): SplitAiAgentAndContentsBeforeResult | undefined {
52+
const aiAgentIndex = contents.findIndex(
53+
content => content instanceof FlowAiAgent
54+
)
55+
if (aiAgentIndex < 0) {
56+
return undefined
57+
}
58+
59+
const aiAgentContent = contents[aiAgentIndex] as FlowAiAgent
60+
const contentsBeforeAiAgent = contents.slice(0, aiAgentIndex)
61+
62+
return { aiAgentContent, contentsBeforeAiAgent }
63+
}

0 commit comments

Comments
 (0)