@tianshu-ai/tianshu 0.48.3 → 0.48.5
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 +1 -1
- package/packages/server/dist/boot/routes-usage.d.ts +12 -0
- package/packages/server/dist/boot/routes-usage.d.ts.map +1 -0
- package/packages/server/dist/boot/routes-usage.js +289 -0
- package/packages/server/dist/boot/routes-usage.js.map +1 -0
- package/packages/server/dist/chat/agent-tool-adapter.d.ts.map +1 -1
- package/packages/server/dist/chat/agent-tool-adapter.js +5 -0
- package/packages/server/dist/chat/agent-tool-adapter.js.map +1 -1
- package/packages/server/dist/chat/handler.d.ts.map +1 -1
- package/packages/server/dist/chat/handler.js +22 -2
- package/packages/server/dist/chat/handler.js.map +1 -1
- package/packages/server/dist/chat/tool-result-truncation.d.ts +68 -0
- package/packages/server/dist/chat/tool-result-truncation.d.ts.map +1 -0
- package/packages/server/dist/chat/tool-result-truncation.js +189 -0
- package/packages/server/dist/chat/tool-result-truncation.js.map +1 -0
- package/packages/server/dist/core/config.d.ts +16 -0
- package/packages/server/dist/core/config.d.ts.map +1 -1
- package/packages/server/dist/core/config.js.map +1 -1
- package/packages/server/dist/index.js +12 -0
- package/packages/server/dist/index.js.map +1 -1
- package/packages/web/dist/assets/DataSourceConfigForm-DGI6vrDq.js +1 -0
- package/packages/web/dist/assets/{bundle-web-B6dgdeDE.js → bundle-web-mSUKUofm.js} +4 -4
- package/packages/web/dist/assets/{index-BtXUS8Tb.css → index-DMVV8sLL.css} +1 -1
- package/packages/web/dist/assets/index-Dq07Mu0N.js +223 -0
- package/packages/web/dist/assets/react-force-graph-2d-Ct3HbWgk.js +44 -0
- package/packages/web/dist/index.html +2 -2
- package/packages/web/package.json +1 -0
- package/packages/web/dist/assets/DataSourceConfigForm-Ct3wgj1z.js +0 -1
- package/packages/web/dist/assets/index-qep8DnMK.js +0 -165
- package/packages/web/dist/assets/react-force-graph-2d-BbuJlX_C.js +0 -44
package/package.json
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token usage analytics API — super-admin only.
|
|
3
|
+
*
|
|
4
|
+
* Aggregates usage from assistant messages in each tenant's DB.
|
|
5
|
+
* GET /api/admin/usage?tenantId=demo&days=30
|
|
6
|
+
*/
|
|
7
|
+
import { type Express } from "express";
|
|
8
|
+
export declare function mountUsageRoutes(app: Express, deps: {
|
|
9
|
+
listTenants: () => string[];
|
|
10
|
+
getTenantDb: (tenantId: string) => import("better-sqlite3").Database | null;
|
|
11
|
+
}): void;
|
|
12
|
+
//# sourceMappingURL=routes-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes-usage.d.ts","sourceRoot":"","sources":["../../src/boot/routes-usage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAC;AAYpE,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE;IACJ,WAAW,EAAE,MAAM,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,gBAAgB,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC7E,GACA,IAAI,CA+SN"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token usage analytics API — super-admin only.
|
|
3
|
+
*
|
|
4
|
+
* Aggregates usage from assistant messages in each tenant's DB.
|
|
5
|
+
* GET /api/admin/usage?tenantId=demo&days=30
|
|
6
|
+
*/
|
|
7
|
+
import { requireSuperAdmin } from "./routes-auth.js";
|
|
8
|
+
export function mountUsageRoutes(app, deps) {
|
|
9
|
+
// Per-user usage breakdown for a tenant
|
|
10
|
+
app.get("/api/admin/usage", requireSuperAdmin, (req, res) => {
|
|
11
|
+
const tenantId = String(req.query.tenantId ?? req.ctx?.tenant.tenantId ?? "");
|
|
12
|
+
const days = Math.min(Math.max(parseInt(String(req.query.days ?? "30"), 10) || 30, 1), 365);
|
|
13
|
+
const db = deps.getTenantDb(tenantId);
|
|
14
|
+
if (!db) {
|
|
15
|
+
res.status(404).json({ error: "tenant_not_found" });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const sinceMs = Date.now() - days * 86400_000;
|
|
19
|
+
// Extract usage from the JSON content of assistant messages.
|
|
20
|
+
// SQLite json_extract works on the stored pi-ai Message JSON.
|
|
21
|
+
try {
|
|
22
|
+
const rows = db.prepare(`
|
|
23
|
+
SELECT
|
|
24
|
+
s.user_id,
|
|
25
|
+
COALESCE(json_extract(m.content, '$.model'), 'unknown') as model,
|
|
26
|
+
COALESCE(SUM(json_extract(m.content, '$.usage.input')), 0) as input_tokens,
|
|
27
|
+
COALESCE(SUM(json_extract(m.content, '$.usage.output')), 0) as output_tokens,
|
|
28
|
+
COALESCE(SUM(json_extract(m.content, '$.usage.totalTokens')), 0) as total_tokens,
|
|
29
|
+
COUNT(*) as msg_count
|
|
30
|
+
FROM messages m
|
|
31
|
+
JOIN sessions s ON m.session_id = s.id
|
|
32
|
+
WHERE m.role = 'assistant'
|
|
33
|
+
AND m.created_at > ?
|
|
34
|
+
AND m.content LIKE '{%'
|
|
35
|
+
AND json_valid(m.content)
|
|
36
|
+
AND json_extract(m.content, '$.usage') IS NOT NULL
|
|
37
|
+
GROUP BY s.user_id, json_extract(m.content, '$.model')
|
|
38
|
+
ORDER BY total_tokens DESC
|
|
39
|
+
`).all(sinceMs);
|
|
40
|
+
// Also get per-user totals
|
|
41
|
+
const userTotals = new Map();
|
|
42
|
+
for (const r of rows) {
|
|
43
|
+
const existing = userTotals.get(r.user_id) ?? { input: 0, output: 0, total: 0, messages: 0 };
|
|
44
|
+
existing.input += r.input_tokens;
|
|
45
|
+
existing.output += r.output_tokens;
|
|
46
|
+
existing.total += r.total_tokens;
|
|
47
|
+
existing.messages += r.msg_count;
|
|
48
|
+
userTotals.set(r.user_id, existing);
|
|
49
|
+
}
|
|
50
|
+
// Daily breakdown for trend chart
|
|
51
|
+
// Daily breakdown grouped by model for stacked bar chart
|
|
52
|
+
const dailyModelRows = db.prepare(`
|
|
53
|
+
SELECT
|
|
54
|
+
date(m.created_at/1000, 'unixepoch') as day,
|
|
55
|
+
COALESCE(json_extract(m.content, '$.model'), 'unknown') as model,
|
|
56
|
+
COALESCE(SUM(json_extract(m.content, '$.usage.totalTokens')), 0) as total_tokens,
|
|
57
|
+
COUNT(*) as msg_count
|
|
58
|
+
FROM messages m
|
|
59
|
+
WHERE m.role = 'assistant' AND m.created_at > ?
|
|
60
|
+
AND m.content LIKE '{%' AND json_valid(m.content)
|
|
61
|
+
AND json_extract(m.content, '$.usage') IS NOT NULL
|
|
62
|
+
GROUP BY day, model ORDER BY day
|
|
63
|
+
`).all(sinceMs);
|
|
64
|
+
// Pivot: each day becomes { day, totalTokens, [model1]: tokens, [model2]: tokens, ... }
|
|
65
|
+
const dayMap = new Map();
|
|
66
|
+
const allModels = new Set();
|
|
67
|
+
for (const r of dailyModelRows) {
|
|
68
|
+
allModels.add(r.model);
|
|
69
|
+
const entry = dayMap.get(r.day) ?? { totalTokens: 0 };
|
|
70
|
+
entry[r.model] = (entry[r.model] ?? 0) + r.total_tokens;
|
|
71
|
+
entry.totalTokens = (entry.totalTokens ?? 0) + r.total_tokens;
|
|
72
|
+
dayMap.set(r.day, entry);
|
|
73
|
+
}
|
|
74
|
+
const dailyRows = Array.from(dayMap.entries())
|
|
75
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
76
|
+
.map(([day, data]) => ({ day, ...data }));
|
|
77
|
+
// Model breakdown
|
|
78
|
+
const modelRows = db.prepare(`
|
|
79
|
+
SELECT
|
|
80
|
+
COALESCE(json_extract(m.content, '$.model'), 'unknown') as model,
|
|
81
|
+
COALESCE(SUM(json_extract(m.content, '$.usage.totalTokens')), 0) as total_tokens,
|
|
82
|
+
COUNT(*) as msg_count
|
|
83
|
+
FROM messages m
|
|
84
|
+
WHERE m.role = 'assistant' AND m.created_at > ?
|
|
85
|
+
AND m.content LIKE '{%' AND json_valid(m.content)
|
|
86
|
+
AND json_extract(m.content, '$.usage') IS NOT NULL
|
|
87
|
+
GROUP BY model ORDER BY total_tokens DESC
|
|
88
|
+
`).all(sinceMs);
|
|
89
|
+
res.json({
|
|
90
|
+
tenantId,
|
|
91
|
+
days,
|
|
92
|
+
daily: dailyRows,
|
|
93
|
+
models: Array.from(allModels),
|
|
94
|
+
byModel: modelRows.map((r) => ({
|
|
95
|
+
model: r.model,
|
|
96
|
+
totalTokens: r.total_tokens,
|
|
97
|
+
messageCount: r.msg_count,
|
|
98
|
+
})),
|
|
99
|
+
byUser: Array.from(userTotals.entries()).map(([userId, t]) => ({
|
|
100
|
+
userId,
|
|
101
|
+
...t,
|
|
102
|
+
})).sort((a, b) => b.total - a.total),
|
|
103
|
+
byUserModel: rows.map((r) => ({
|
|
104
|
+
userId: r.user_id,
|
|
105
|
+
model: r.model,
|
|
106
|
+
totalTokens: r.total_tokens,
|
|
107
|
+
messageCount: r.msg_count,
|
|
108
|
+
})),
|
|
109
|
+
totals: {
|
|
110
|
+
inputTokens: rows.reduce((s, r) => s + r.input_tokens, 0),
|
|
111
|
+
outputTokens: rows.reduce((s, r) => s + r.output_tokens, 0),
|
|
112
|
+
totalTokens: rows.reduce((s, r) => s + r.total_tokens, 0),
|
|
113
|
+
messageCount: rows.reduce((s, r) => s + r.msg_count, 0),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
console.error(`[usage] query failed for tenant ${tenantId}:`, e);
|
|
119
|
+
res.status(500).json({ error: `query failed: ${e instanceof Error ? e.message : String(e)}` });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
// List tenants with basic usage stats
|
|
123
|
+
app.get("/api/admin/usage/overview", requireSuperAdmin, (_req, res) => {
|
|
124
|
+
const tenants = deps.listTenants();
|
|
125
|
+
const sinceMs = Date.now() - 30 * 86400_000;
|
|
126
|
+
const overview = tenants.map((tid) => {
|
|
127
|
+
const db = deps.getTenantDb(tid);
|
|
128
|
+
if (!db)
|
|
129
|
+
return { tenantId: tid, totalTokens: 0, messageCount: 0 };
|
|
130
|
+
try {
|
|
131
|
+
const row = db.prepare(`
|
|
132
|
+
SELECT
|
|
133
|
+
COALESCE(SUM(json_extract(m.content, '$.usage.totalTokens')), 0) as total_tokens,
|
|
134
|
+
COUNT(*) as msg_count
|
|
135
|
+
FROM messages m
|
|
136
|
+
WHERE m.role = 'assistant'
|
|
137
|
+
AND m.created_at > ?
|
|
138
|
+
AND m.content LIKE '{%'
|
|
139
|
+
AND json_valid(m.content)
|
|
140
|
+
AND json_extract(m.content, '$.usage') IS NOT NULL
|
|
141
|
+
`).get(sinceMs);
|
|
142
|
+
return { tenantId: tid, totalTokens: row?.total_tokens ?? 0, messageCount: row?.msg_count ?? 0 };
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return { tenantId: tid, totalTokens: 0, messageCount: 0 };
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
res.json({ overview, days: 30 });
|
|
149
|
+
});
|
|
150
|
+
// Drill-down: messages for a specific day
|
|
151
|
+
app.get("/api/admin/usage/messages", requireSuperAdmin, (req, res) => {
|
|
152
|
+
const tenantId = String(req.query.tenantId ?? req.ctx?.tenant.tenantId ?? "");
|
|
153
|
+
const day = String(req.query.day ?? "");
|
|
154
|
+
const userId = req.query.userId ? String(req.query.userId) : undefined;
|
|
155
|
+
if (!day.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
156
|
+
res.status(400).json({ error: "day must be YYYY-MM-DD" });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const db = deps.getTenantDb(tenantId);
|
|
160
|
+
if (!db) {
|
|
161
|
+
res.status(404).json({ error: "tenant_not_found" });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
// Get all assistant messages for the day with usage
|
|
166
|
+
const dayStart = new Date(day + "T00:00:00Z").getTime();
|
|
167
|
+
const dayEnd = dayStart + 86400_000;
|
|
168
|
+
const params = [dayStart, dayEnd];
|
|
169
|
+
let userFilter = "";
|
|
170
|
+
if (userId) {
|
|
171
|
+
userFilter = " AND s.user_id = ?";
|
|
172
|
+
params.push(userId);
|
|
173
|
+
}
|
|
174
|
+
const rows = db.prepare(`
|
|
175
|
+
SELECT
|
|
176
|
+
m.id as message_id,
|
|
177
|
+
m.session_id,
|
|
178
|
+
s.user_id,
|
|
179
|
+
m.created_at,
|
|
180
|
+
COALESCE(json_extract(m.content, '$.model'), 'unknown') as model,
|
|
181
|
+
COALESCE(json_extract(m.content, '$.usage.input'), 0) as input_tokens,
|
|
182
|
+
COALESCE(json_extract(m.content, '$.usage.output'), 0) as output_tokens,
|
|
183
|
+
COALESCE(json_extract(m.content, '$.usage.totalTokens'), 0) as total_tokens,
|
|
184
|
+
COALESCE(json_extract(m.content, '$.usage.cacheRead'), 0) as cache_read,
|
|
185
|
+
COALESCE(json_extract(m.content, '$.usage.cacheWrite'), 0) as cache_write,
|
|
186
|
+
LENGTH(m.content) as content_bytes
|
|
187
|
+
FROM messages m
|
|
188
|
+
JOIN sessions s ON m.session_id = s.id
|
|
189
|
+
WHERE m.role = 'assistant'
|
|
190
|
+
AND m.created_at >= ? AND m.created_at < ?
|
|
191
|
+
AND m.content LIKE '{%' AND json_valid(m.content)
|
|
192
|
+
AND json_extract(m.content, '$.usage') IS NOT NULL
|
|
193
|
+
${userFilter}
|
|
194
|
+
ORDER BY m.created_at DESC
|
|
195
|
+
`).all(...params);
|
|
196
|
+
res.json({
|
|
197
|
+
day,
|
|
198
|
+
tenantId,
|
|
199
|
+
messages: rows.map((r) => ({
|
|
200
|
+
messageId: r.message_id,
|
|
201
|
+
sessionId: r.session_id,
|
|
202
|
+
userId: r.user_id,
|
|
203
|
+
createdAt: r.created_at,
|
|
204
|
+
model: r.model,
|
|
205
|
+
inputTokens: r.input_tokens,
|
|
206
|
+
outputTokens: r.output_tokens,
|
|
207
|
+
totalTokens: r.total_tokens,
|
|
208
|
+
cacheRead: r.cache_read,
|
|
209
|
+
cacheWrite: r.cache_write,
|
|
210
|
+
contentBytes: r.content_bytes,
|
|
211
|
+
})),
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
console.error(`[usage] messages query failed:`, e);
|
|
216
|
+
res.status(500).json({ error: `query failed: ${e instanceof Error ? e.message : String(e)}` });
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
// Drill-down: session context around a specific message
|
|
220
|
+
app.get("/api/admin/usage/message/:messageId", requireSuperAdmin, (req, res) => {
|
|
221
|
+
const tenantId = String(req.query.tenantId ?? req.ctx?.tenant.tenantId ?? "");
|
|
222
|
+
const { messageId } = req.params;
|
|
223
|
+
const db = deps.getTenantDb(tenantId);
|
|
224
|
+
if (!db) {
|
|
225
|
+
res.status(404).json({ error: "tenant_not_found" });
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
// Get the target message
|
|
230
|
+
const target = db.prepare(`
|
|
231
|
+
SELECT m.*, s.user_id
|
|
232
|
+
FROM messages m JOIN sessions s ON m.session_id = s.id
|
|
233
|
+
WHERE m.id = ?
|
|
234
|
+
`).get(messageId);
|
|
235
|
+
if (!target) {
|
|
236
|
+
res.status(404).json({ error: "message_not_found" });
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
// Get surrounding messages in the same session (5 before, 5 after)
|
|
240
|
+
const context = db.prepare(`
|
|
241
|
+
SELECT id, role, created_at, LENGTH(content) as content_bytes,
|
|
242
|
+
CASE
|
|
243
|
+
WHEN role = 'assistant' AND content LIKE '{%' AND json_valid(content)
|
|
244
|
+
THEN json_extract(content, '$.usage.totalTokens')
|
|
245
|
+
ELSE NULL
|
|
246
|
+
END as total_tokens,
|
|
247
|
+
CASE
|
|
248
|
+
WHEN content LIKE '{%' AND json_valid(content)
|
|
249
|
+
THEN substr(json_extract(content, '$.content'), 1, 200)
|
|
250
|
+
ELSE substr(content, 1, 200)
|
|
251
|
+
END as preview
|
|
252
|
+
FROM messages
|
|
253
|
+
WHERE session_id = ?
|
|
254
|
+
AND created_at BETWEEN ? - 300000 AND ? + 300000
|
|
255
|
+
ORDER BY created_at
|
|
256
|
+
LIMIT 20
|
|
257
|
+
`).all(target.session_id, target.created_at, target.created_at);
|
|
258
|
+
// Parse the target message's usage
|
|
259
|
+
let usage = null;
|
|
260
|
+
try {
|
|
261
|
+
const parsed = JSON.parse(target.content);
|
|
262
|
+
usage = parsed.usage ?? null;
|
|
263
|
+
}
|
|
264
|
+
catch { /* ignore */ }
|
|
265
|
+
res.json({
|
|
266
|
+
messageId,
|
|
267
|
+
sessionId: target.session_id,
|
|
268
|
+
userId: target.user_id,
|
|
269
|
+
createdAt: target.created_at,
|
|
270
|
+
usage,
|
|
271
|
+
contentBytes: target.content.length,
|
|
272
|
+
context: context.map((r) => ({
|
|
273
|
+
id: r.id,
|
|
274
|
+
role: r.role,
|
|
275
|
+
createdAt: r.created_at,
|
|
276
|
+
contentBytes: r.content_bytes,
|
|
277
|
+
totalTokens: r.total_tokens,
|
|
278
|
+
preview: r.preview,
|
|
279
|
+
isCurrent: r.id === messageId,
|
|
280
|
+
})),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
console.error(`[usage] message detail failed:`, e);
|
|
285
|
+
res.status(500).json({ error: `query failed: ${e instanceof Error ? e.message : String(e)}` });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=routes-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes-usage.js","sourceRoot":"","sources":["../../src/boot/routes-usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-tool-adapter.d.ts","sourceRoot":"","sources":["../../src/chat/agent-tool-adapter.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,SAAS,IAAI,WAAW,EAEzB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-tool-adapter.d.ts","sourceRoot":"","sources":["../../src/chat/agent-tool-adapter.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,SAAS,IAAI,WAAW,EAEzB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb;;;gEAG4D;IAC5D,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAoB/D;AAED,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB;mEAC+D;IAC/D,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,CAoH7D;AAED;;qEAEqE;AACrE,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAIvD"}
|
|
@@ -150,6 +150,11 @@ export function adaptToolset(toolset) {
|
|
|
150
150
|
// Plugin tools are sync OR async; both are fine.
|
|
151
151
|
const raw = await Promise.resolve(exec(args));
|
|
152
152
|
const norm = normaliseToolResult(raw);
|
|
153
|
+
// NOTE: we do NOT truncate at write time. The current turn's
|
|
154
|
+
// tool results must be seen in full by the model so it can
|
|
155
|
+
// act on complete information. Truncation/aging of OLD tool
|
|
156
|
+
// results happens in the harness "context" hook (handler.ts)
|
|
157
|
+
// before subsequent LLM calls — see pruneOldToolResults().
|
|
153
158
|
// Tool text first, then any images the tool returned so the
|
|
154
159
|
// vision model sees them this turn (pi ToolResultMessage.content
|
|
155
160
|
// is (Text | Image)[]). Images are opt-in per call — most tools
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-tool-adapter.js","sourceRoot":"","sources":["../../src/chat/agent-tool-adapter.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,mBAAmB;AACnB,2DAA2D;AAC3D,+CAA+C;AAC/C,gEAAgE;AAChE,4DAA4D;AAC5D,gEAAgE;AAChE,cAAc;AACd,wEAAwE;AACxE,+DAA+D;AAC/D,2DAA2D;AAC3D,+DAA+D;AAC/D,oEAAoE;AACpE,EAAE;AACF,qEAAqE;AACrE,mEAAmE;AACnE,wDAAwD;AACxD,gEAAgE;AAChE,mEAAmE;AACnE,oEAAoE;AACpE,kEAAkE;AAClE,+DAA+D;AAC/D,8BAA8B;
|
|
1
|
+
{"version":3,"file":"agent-tool-adapter.js","sourceRoot":"","sources":["../../src/chat/agent-tool-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/chat/handler.ts"],"names":[],"mappings":"AAgDA,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEd,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC9B,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,GAC9B,CAAC;AAGF,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,2BAA2B,EAC3B,4BAA4B,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/chat/handler.ts"],"names":[],"mappings":"AAgDA,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEd,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC9B,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,GAC9B,CAAC;AAGF,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,2BAA2B,EAC3B,4BAA4B,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAOL,KAAK,WAAW,EAEjB,MAAM,eAAe,CAAC;AAUvB,OAAO,EAGL,KAAK,SAAS,EAEd,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAC;AAY1B,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC;IACtE,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAyP7D;AAED,UAAU,aAAa;IACrB,GAAG,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,OAAO,eAAe,EAAE,WAAW,CAAC;IAC9C;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAquBlE;AA2TD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,aAAa,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CA0Ef;AA4QD,wBAAgB,cAAc,IAAI,WAAW,EAAE,CAkC9C;AAGD,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -34,6 +34,7 @@ import { buildModel, buildModels, findModel, getDefaultModel, resolveApiKey, } f
|
|
|
34
34
|
import { loadMainAgentConfig } from "../core/main-agent-config.js";
|
|
35
35
|
import { buildToolset } from "../tools/index.js";
|
|
36
36
|
import { adaptToolset } from "./agent-tool-adapter.js";
|
|
37
|
+
import { pruneOldToolResults } from "./tool-result-truncation.js";
|
|
37
38
|
import { dumpSystemPrompt } from "./dump-system-prompt.js";
|
|
38
39
|
import { SqliteSessionRepo } from "./sqlite-session-repo.js";
|
|
39
40
|
import { drainPending as drainInbox, renderForPrompt as renderInboxForPrompt, extractEvents, markDeliveredFromMessage, } from "./session-inbox.js";
|
|
@@ -397,8 +398,8 @@ export async function runPrompt(args) {
|
|
|
397
398
|
enabled: compactionCfg.enabled ?? true,
|
|
398
399
|
reserveTokens: compactionCfg.reserveTokens ?? 16384,
|
|
399
400
|
keepRecentTokens: compactionCfg.keepRecentTokens ?? 20000,
|
|
400
|
-
triggerPercent: compactionCfg.triggerPercent ??
|
|
401
|
-
} : { enabled: true, reserveTokens: 16384, keepRecentTokens: 20000, triggerPercent:
|
|
401
|
+
triggerPercent: compactionCfg.triggerPercent ?? 50,
|
|
402
|
+
} : { enabled: true, reserveTokens: 16384, keepRecentTokens: 20000, triggerPercent: 50 };
|
|
402
403
|
const hostToolsDefs = buildHostTools({
|
|
403
404
|
contextWindow: modelInfo.contextWindow,
|
|
404
405
|
compactionSettings,
|
|
@@ -513,6 +514,7 @@ export async function runPrompt(args) {
|
|
|
513
514
|
executors: Object.fromEntries(Object.entries(toolset.executors).filter(([name]) => !mainConfig.toolsDeny.has(name))),
|
|
514
515
|
}
|
|
515
516
|
: toolset;
|
|
517
|
+
const toolResultCfg = ctx.config.models?.toolResults;
|
|
516
518
|
const adapted = adaptToolset(effectiveToolset);
|
|
517
519
|
const systemPrompt = defaultSystemPrompt(ctx, userId, effectiveSkills, [...channelFragments, ...pluginFragments], {
|
|
518
520
|
tenantPrompt: mainConfig.tenantPrompt,
|
|
@@ -555,6 +557,22 @@ export async function runPrompt(args) {
|
|
|
555
557
|
},
|
|
556
558
|
}),
|
|
557
559
|
});
|
|
560
|
+
// ── Tool-result aging: prune old tool results before each LLM call ──
|
|
561
|
+
// This reduces context bloat by replacing old (far from the current
|
|
562
|
+
// turn) tool results with a short placeholder. The original data is
|
|
563
|
+
// preserved in the session tree — pruning only affects the transient
|
|
564
|
+
// message array the model sees.
|
|
565
|
+
// Tool-result aging: directly patch the harness's internal handlers map
|
|
566
|
+
// to intercept the "context" hook event that transformContext fires.
|
|
567
|
+
// Tool-result aging: hook into harness's "context" event.
|
|
568
|
+
// @ts-expect-error — harness.on type doesn't expose "context" in generic
|
|
569
|
+
const unsubscribePrune = harness.on("context", (event) => {
|
|
570
|
+
const pruned = pruneOldToolResults(event.messages, toolResultCfg);
|
|
571
|
+
if (pruned > 0) {
|
|
572
|
+
console.log(`[handler] pruned ${pruned} old tool result(s) from context`);
|
|
573
|
+
}
|
|
574
|
+
return { messages: event.messages };
|
|
575
|
+
});
|
|
558
576
|
// Bind the compact tool's deferred ref now that piSession + harness exist.
|
|
559
577
|
const compactRef = getCompactRef(hostToolsDefs);
|
|
560
578
|
compactRef.piSession = piSession;
|
|
@@ -652,6 +670,7 @@ export async function runPrompt(args) {
|
|
|
652
670
|
// re-enter, so we don't leave a dangling subscription /
|
|
653
671
|
// registry entry for a turn we're abandoning.
|
|
654
672
|
unsubscribe();
|
|
673
|
+
unsubscribePrune();
|
|
655
674
|
unregisterHarness();
|
|
656
675
|
signal.removeEventListener("abort", onAbort);
|
|
657
676
|
if (storage)
|
|
@@ -871,6 +890,7 @@ export async function runPrompt(args) {
|
|
|
871
890
|
}
|
|
872
891
|
outstandingToolCalls.clear();
|
|
873
892
|
unsubscribe();
|
|
893
|
+
unsubscribePrune();
|
|
874
894
|
unregisterHarness();
|
|
875
895
|
signal.removeEventListener("abort", onAbort);
|
|
876
896
|
if (storage)
|