Skip to content

Commit a8e23ed

Browse files
committed
fix(ai-bot): login token refresh and update actor flow with agent
1 parent 58cc1bc commit a8e23ed

File tree

13 files changed

+308
-248
lines changed

13 files changed

+308
-248
lines changed
Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import { type PromptFn } from "./prompt.type.js";
22

3-
export const EMBED_ACTOR_PROMPT: PromptFn<{
4-
text: string;
5-
question: string;
6-
}> = ({ vars: { text, question } }) => `
3+
export const EMBED_ACTOR_PROMPT: PromptFn = () => `
74
You are an expert in giving description about people.
85
Your goal is to give a description of a given person in a text format, including the requested fields, without inventing details.
6+
Execute the tools available to retrieve the info you need.
97
The text should be minimum 100 words long, but not exceeding 300 words long.
108
119
The requested fields are:
1210
- the name of the person
1311
- the birth date of the person (in the format "YYYY-MM-DD")
1412
- if has passed away, the death date of the person (in the format "YYYY-MM-DD")
1513
16-
Here's the text you should use to extract the information from:
17-
18-
---------------------------------------------------------------
19-
${text}
20-
---------------------------------------------------------------
21-
22-
There may be an additional question which answer should be included in the body of the text: ${question}
14+
If the user poses a specific question, try to include the answer in your description.
2315
`;

packages/@liexp/shared/src/utils/user.utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { AdminCreate, AdminDelete, AdminEdit } from "../io/http/User.js";
1+
import {
2+
AdminCreate,
3+
AdminDelete,
4+
AdminEdit,
5+
AdminRead,
6+
} from "../io/http/User.js";
27
import { type User } from "../io/http/index.js";
38

49
export const checkIsAdmin = (pp: readonly User.UserPermission[]): boolean => {
@@ -8,6 +13,7 @@ export const checkIsAdmin = (pp: readonly User.UserPermission[]): boolean => {
813
AdminDelete.literals[0],
914
AdminEdit.literals[0],
1015
AdminCreate.literals[0],
16+
AdminRead.literals[0],
1117
].some((p) => pp.includes(p))
1218
);
1319
};

services/ai-bot/AGENT.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# AI Agent Integration Guide
2+
3+
This document describes how to integrate and configure AI agents to work with the lies.exposed platform using the Model Context Protocol (MCP) servers.
4+
5+
## Overview
6+
7+
The lies.exposed platform provides several MCP servers that expose domain-specific tools for working with various types of content. AI agents should proactively use these tools as their primary knowledge source and execution capability.
8+
9+
When you identify a tool that can help with a task, you should:
10+
1. Execute the tool directly using the available methods
11+
2. Use the tool's response to complete the task
12+
3. Never output tool calls in your response - execute them instead
13+
14+
When a tool call is needed, use it directly through the provided interface. Do not describe the tool call or show it in your response.
15+
16+
### Available Tools
17+
18+
The platform provides several domain-specific tools through MCP:
19+
20+
#### Content Search Tools
21+
- `findActor` - Search for people and organizations
22+
- `findArea` - Search for geographical and thematic areas
23+
- `findEvents` - Search for events and timelines
24+
- `findGroup` - Search for groups and organizations
25+
- `findLink` - Search for web resources and references
26+
- `findMedia` - Search for images, videos and documents
27+
28+
Each search tool supports:
29+
- Full-text search via the `query` parameter
30+
- Sorting options (typically by `createdAt` and resource-specific fields)
31+
- Order control (`ASC`/`DESC`)
32+
33+
#### Content Parsing Tools
34+
- `blockNoteToText` - Convert BlockNote JSON documents to plain text
35+
36+
### Tool Usage Guidelines
37+
38+
1. **Proactive Tool Use**:
39+
- AI agents should actively use MCP tools without waiting for explicit user permission
40+
- Tools should be used as the primary source of domain knowledge
41+
- Multiple tools can be queried in parallel when needed
42+
43+
2. **Search Strategy**:
44+
- Start with broad searches using key terms
45+
- Refine searches based on initial results
46+
- Use multiple content types to build comprehensive context
47+
48+
3. **Content Processing**:
49+
- Parse BlockNote content when encountering formatted text
50+
- Extract key entities (actors, areas, events) from search results
51+
- Build relationships between different content types

services/ai-bot/config/ai-bot.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"models": {
77
"summarize": "gpt-4o",
88
"chat": "qwen3-4b",
9-
"embeddings": "qwen3-embedding-4b"
9+
"embeddings": "qwen3-4b"
1010
}
1111
}
1212
}

services/ai-bot/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
"dependencies": {
3131
"@aws-sdk/client-sso-oidc": "^3.895.0",
3232
"@aws-sdk/client-sts": "^3.895.0",
33-
"@langchain/community": "^0.3.56",
34-
"@langchain/core": "^0.3.77",
33+
"@langchain/community": "^0.3.57",
34+
"@langchain/core": "^0.3.78",
3535
"@langchain/langgraph": "^0.4.9",
36+
"@langchain/mcp-adapters": "^0.6.0",
3637
"@liexp/backend": "workspace:*",
3738
"@liexp/core": "workspace:*",
3839
"@liexp/shared": "workspace:*",
@@ -43,8 +44,8 @@
4344
"debug": "^4.4.0",
4445
"effect": "^3.17.13",
4546
"fp-ts": "^2.16.10",
46-
"langchain": "^0.3.34",
47-
"openai": "^5.20.2",
47+
"langchain": "^0.3.35",
48+
"openai": "^5.23.1",
4849
"pdfjs-dist": "^5.4.149",
4950
"prompts": "^2.4.2",
5051
"puppeteer-core": "^24.8.1",

services/ai-bot/src/cli/agent.command.ts

Lines changed: 17 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,38 @@
1-
import { MemorySaver } from "@langchain/langgraph";
2-
import { createReactAgent } from "@langchain/langgraph/prebuilt";
1+
import { type AIMessage, type ToolMessage } from "@langchain/core/messages";
2+
import { AIMessageLogger } from "@liexp/backend/lib/providers/ai/aiMessage.helper.js";
33
import { fp } from "@liexp/core/lib/fp/index.js";
4+
import { uuid } from "@liexp/shared/lib/io/http/Common/UUID.js";
45
import { throwTE } from "@liexp/shared/lib/utils/task.utils.js";
56
import { pipe } from "fp-ts/lib/function.js";
67
import prompts from "prompts";
78
import { toAIBotError } from "../common/error/index.js";
89
import { type CommandFlow } from "./CommandFlow.js";
910

10-
// const GraphState = Annotation.Root({
11-
// messages: Annotation<BaseMessage[]>({
12-
// reducer: (x, y) => x.concat(y),
13-
// default: () => [],
14-
// }),
15-
// });
16-
17-
// export const ConfigurationSchema = Annotation.Root({
18-
// /**
19-
// * The system prompt to be used by the agent.
20-
// */
21-
// systemPromptTemplate: Annotation<string>,
22-
23-
// /**
24-
// * The name of the language model to be used by the agent.
25-
// */
26-
// model: Annotation<string>,
27-
// });
28-
29-
// Define the function that determines whether to continue or not
30-
// function routeModelOutput(state: typeof MessagesAnnotation.State): string {
31-
// const messages = state.messages;
32-
// const lastMessage = messages[messages.length - 1];
33-
// // If the LLM is invoking tools, route there.
34-
// if ((lastMessage as AIMessage)?.tool_calls?.length || 0 > 0) {
35-
// return "tools";
36-
// }
37-
// // Otherwise end the graph.
38-
// else {
39-
// return "__end__";
40-
// }
41-
// }
42-
4311
export const agentCommand: CommandFlow = async (ctx, args) => {
44-
// Initialize memory to persist state between graph runs
45-
46-
const agentCheckpointer = new MemorySaver();
47-
const agent = createReactAgent({
48-
llm: ctx.langchain.chat,
49-
tools: [],
50-
checkpointSaver: agentCheckpointer,
12+
const threadId = uuid();
13+
const agent = ctx.agent.agent.withConfig({
14+
configurable: {
15+
thread_id: threadId,
16+
},
5117
});
5218

5319
const ask = async (ag: typeof agent, message: string) => {
5420
const agentFinalState = await ag.stream(
5521
{
5622
messages: [message],
5723
},
58-
{ configurable: { thread_id: "42" } },
24+
{},
5925
);
6026

61-
const messages = [];
27+
const aiMessageLogger = AIMessageLogger(ctx.logger);
28+
6229
for await (const chunk of agentFinalState) {
63-
ctx.logger.debug.log(`Chunk %O`, chunk.agent.messages);
64-
messages.push(chunk);
30+
const messages = (chunk.agent?.messages ??
31+
chunk.tools?.messages ??
32+
[]) as (ToolMessage | AIMessage)[];
33+
34+
messages.forEach(aiMessageLogger);
6535
}
66-
return messages;
6736
};
6837

6938
const chat = async (ag: typeof agent) => {
@@ -73,7 +42,7 @@ export const agentCommand: CommandFlow = async (ctx, args) => {
7342
name: "question",
7443
});
7544

76-
if (question.toLowerCase() === "exit") {
45+
if (!question || question.toLowerCase() === "exit") {
7746
ctx.logger.info.log("Goodbye!");
7847
return;
7948
} else {

services/ai-bot/src/cli/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { throwTE } from "@liexp/shared/lib/utils/task.utils.js";
44
import D from "debug";
55
import { pipe } from "fp-ts/lib/function.js";
66
import { type ClientContext } from "../context.js";
7-
import { userLogin } from "../flows/userLogin.flow.js";
7+
import { currentToken, userLogin } from "../flows/userLogin.flow.js";
88
import { loadContext } from "../load-context.js";
99
import { type CommandFlow } from "./CommandFlow.js";
1010
import { agentCommand } from "./agent.command.js";
@@ -26,9 +26,13 @@ const run = async ([command, ...args]: string[]): Promise<void> => {
2626
process.exit(1);
2727
}
2828

29-
loadENV(process.cwd(), process.env.DOTENV_CONFIG_PATH ?? "../../.env");
29+
loadENV(process.cwd(), process.env.DOTENV_CONFIG_PATH ?? ".env");
3030

31-
let token: string = "invalid-token";
31+
if (process.env.NODE_ENV === "development") {
32+
loadENV(process.cwd(), ".env.local", true);
33+
}
34+
35+
let token: string = currentToken();
3236
let ctx: ClientContext | undefined = undefined;
3337
try {
3438
ctx = await pipe(

services/ai-bot/src/context.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,42 @@ import { type LangchainContext } from "@liexp/backend/lib/context/langchain.cont
44
import { type LoggerContext } from "@liexp/backend/lib/context/logger.context.js";
55
import { type PDFProviderContext } from "@liexp/backend/lib/context/pdf.context.js";
66
import { type PuppeteerProviderContext } from "@liexp/backend/lib/context/puppeteer.context.js";
7+
import { type AgentProvider } from "@liexp/backend/lib/providers/ai/agent.provider.js";
78
import { type Endpoints } from "@liexp/shared/lib/endpoints/index.js";
89
import { type OpenAIProvider } from "@liexp/shared/lib/providers/openai/openai.provider.js";
910
import { type API } from "@ts-endpoint/resource-client";
1011
import { type AIBotConfig } from "./config.js";
1112
import { type ENV } from "./env.js";
1213
import { type ConfigProvider } from "#common/config/config.reader.js";
1314

14-
interface APIClientContext {
15+
export interface APIClientContext {
1516
api: API<Endpoints>;
1617
}
1718

18-
interface ENVContext {
19+
export interface ENVContext {
1920
env: ENV;
2021
}
2122

22-
interface ConfigContext {
23+
export interface AIBotConfigContext {
2324
config: ConfigProvider<AIBotConfig>;
2425
}
2526

2627
interface OpenAIContext {
2728
openAI: OpenAIProvider;
2829
}
2930

31+
interface AgentContext {
32+
agent: AgentProvider;
33+
}
34+
3035
export type ClientContext = ENVContext &
31-
ConfigContext &
36+
AIBotConfigContext &
3237
LangchainContext &
3338
OpenAIContext &
3439
HTTPProviderContext &
3540
PDFProviderContext &
3641
APIClientContext &
3742
FSClientContext &
3843
PuppeteerProviderContext &
44+
AgentContext &
3945
LoggerContext;

0 commit comments

Comments
 (0)