@agi-cli/server 0.1.124 → 0.1.125
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/package.json +3 -3
- package/src/index.ts +4 -0
- package/src/routes/research.ts +423 -0
- package/src/routes/sessions.ts +33 -2
- package/src/runtime/agent/registry.ts +18 -0
- package/src/runtime/agent/runner-setup.ts +16 -0
- package/src/runtime/message/compaction-auto.ts +32 -3
- package/src/tools/database/get-parent-session.ts +178 -0
- package/src/tools/database/get-session-context.ts +156 -0
- package/src/tools/database/index.ts +42 -0
- package/src/tools/database/present-session-links.ts +47 -0
- package/src/tools/database/query-messages.ts +160 -0
- package/src/tools/database/query-sessions.ts +124 -0
- package/src/tools/database/search-history.ts +135 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { tool } from 'ai';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getDb } from '@agi-cli/database';
|
|
4
|
+
import { sessions, messages, messageParts } from '@agi-cli/database/schema';
|
|
5
|
+
import { eq, desc, asc, like, and, sql } from 'drizzle-orm';
|
|
6
|
+
|
|
7
|
+
const inputSchema = z.object({
|
|
8
|
+
query: z.string().min(1).describe('Search term to find in message content'),
|
|
9
|
+
limit: z
|
|
10
|
+
.number()
|
|
11
|
+
.min(1)
|
|
12
|
+
.max(50)
|
|
13
|
+
.default(20)
|
|
14
|
+
.describe('Max results to return'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export function buildSearchHistoryTool(projectRoot: string) {
|
|
18
|
+
return {
|
|
19
|
+
name: 'search_history',
|
|
20
|
+
tool: tool({
|
|
21
|
+
description:
|
|
22
|
+
'Full-text search across all message content in session history. Find past conversations, solutions, or discussions about specific topics.',
|
|
23
|
+
inputSchema,
|
|
24
|
+
async execute(input) {
|
|
25
|
+
const db = await getDb(projectRoot);
|
|
26
|
+
|
|
27
|
+
const projectSessionIds = await db
|
|
28
|
+
.select({ id: sessions.id })
|
|
29
|
+
.from(sessions)
|
|
30
|
+
.where(eq(sessions.projectPath, projectRoot));
|
|
31
|
+
|
|
32
|
+
const sessionIdSet = new Set(projectSessionIds.map((s) => s.id));
|
|
33
|
+
|
|
34
|
+
if (sessionIdSet.size === 0) {
|
|
35
|
+
return {
|
|
36
|
+
ok: true,
|
|
37
|
+
results: [],
|
|
38
|
+
total: 0,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const searchPattern = `%${input.query}%`;
|
|
43
|
+
|
|
44
|
+
const matchingParts = await db
|
|
45
|
+
.select({
|
|
46
|
+
id: messageParts.id,
|
|
47
|
+
messageId: messageParts.messageId,
|
|
48
|
+
content: messageParts.content,
|
|
49
|
+
type: messageParts.type,
|
|
50
|
+
})
|
|
51
|
+
.from(messageParts)
|
|
52
|
+
.where(
|
|
53
|
+
and(
|
|
54
|
+
eq(messageParts.type, 'text'),
|
|
55
|
+
like(messageParts.content, searchPattern),
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
.limit(input.limit * 3);
|
|
59
|
+
|
|
60
|
+
const results: Array<{
|
|
61
|
+
sessionId: string;
|
|
62
|
+
sessionTitle: string | null;
|
|
63
|
+
messageId: string;
|
|
64
|
+
role: string;
|
|
65
|
+
matchedContent: string;
|
|
66
|
+
createdAt: number;
|
|
67
|
+
}> = [];
|
|
68
|
+
|
|
69
|
+
for (const part of matchingParts) {
|
|
70
|
+
if (results.length >= input.limit) break;
|
|
71
|
+
|
|
72
|
+
const msgRows = await db
|
|
73
|
+
.select({
|
|
74
|
+
id: messages.id,
|
|
75
|
+
sessionId: messages.sessionId,
|
|
76
|
+
role: messages.role,
|
|
77
|
+
createdAt: messages.createdAt,
|
|
78
|
+
})
|
|
79
|
+
.from(messages)
|
|
80
|
+
.where(eq(messages.id, part.messageId))
|
|
81
|
+
.limit(1);
|
|
82
|
+
|
|
83
|
+
if (msgRows.length === 0) continue;
|
|
84
|
+
|
|
85
|
+
const msg = msgRows[0];
|
|
86
|
+
|
|
87
|
+
if (!sessionIdSet.has(msg.sessionId)) continue;
|
|
88
|
+
|
|
89
|
+
const sessionRows = await db
|
|
90
|
+
.select({ title: sessions.title })
|
|
91
|
+
.from(sessions)
|
|
92
|
+
.where(eq(sessions.id, msg.sessionId))
|
|
93
|
+
.limit(1);
|
|
94
|
+
|
|
95
|
+
const content = part.content ?? '';
|
|
96
|
+
const queryLower = input.query.toLowerCase();
|
|
97
|
+
const contentLower = content.toLowerCase();
|
|
98
|
+
const matchIndex = contentLower.indexOf(queryLower);
|
|
99
|
+
|
|
100
|
+
let matchedContent: string;
|
|
101
|
+
if (matchIndex >= 0) {
|
|
102
|
+
const start = Math.max(0, matchIndex - 50);
|
|
103
|
+
const end = Math.min(
|
|
104
|
+
content.length,
|
|
105
|
+
matchIndex + input.query.length + 50,
|
|
106
|
+
);
|
|
107
|
+
const prefix = start > 0 ? '...' : '';
|
|
108
|
+
const suffix = end < content.length ? '...' : '';
|
|
109
|
+
matchedContent = prefix + content.slice(start, end) + suffix;
|
|
110
|
+
} else {
|
|
111
|
+
matchedContent =
|
|
112
|
+
content.slice(0, 150) + (content.length > 150 ? '...' : '');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
results.push({
|
|
116
|
+
sessionId: msg.sessionId,
|
|
117
|
+
sessionTitle: sessionRows[0]?.title ?? null,
|
|
118
|
+
messageId: msg.id,
|
|
119
|
+
role: msg.role,
|
|
120
|
+
matchedContent,
|
|
121
|
+
createdAt: msg.createdAt,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
results.sort((a, b) => b.createdAt - a.createdAt);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
ok: true,
|
|
129
|
+
results,
|
|
130
|
+
total: results.length,
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
};
|
|
135
|
+
}
|