deepspace 0.2.4 → 0.2.6
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/dist/cli.js +720 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +80 -1
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +115 -0
- package/dist/testing.js +175 -0
- package/dist/testing.js.map +1 -0
- package/dist/worker.d.ts +222 -5
- package/dist/worker.js +481 -14
- package/dist/worker.js.map +1 -1
- package/package.json +18 -9
package/dist/worker.js
CHANGED
|
@@ -4130,6 +4130,40 @@ var DEFAULT_DO_MANIFEST = [
|
|
|
4130
4130
|
{ binding: "YJS_ROOMS", className: "AppYjsRoom", sqlite: true }
|
|
4131
4131
|
];
|
|
4132
4132
|
|
|
4133
|
+
// src/server/schemas/ai-chat.ts
|
|
4134
|
+
var AI_CHATS_SCHEMA = {
|
|
4135
|
+
name: "ai-chats",
|
|
4136
|
+
columns: [
|
|
4137
|
+
{ name: "userId", storage: "text", interpretation: "plain", userBound: true, immutable: true, required: true },
|
|
4138
|
+
{ name: "title", storage: "text", interpretation: "plain" },
|
|
4139
|
+
{ name: "model", storage: "text", interpretation: "plain" },
|
|
4140
|
+
{ name: "compactedSummary", storage: "text", interpretation: "plain" },
|
|
4141
|
+
{ name: "compactedThroughId", storage: "text", interpretation: "plain" }
|
|
4142
|
+
],
|
|
4143
|
+
ownerField: "userId",
|
|
4144
|
+
permissions: {
|
|
4145
|
+
admin: { read: true, create: true, update: true, delete: true },
|
|
4146
|
+
member: { read: "own", create: false, update: "own", delete: "own" },
|
|
4147
|
+
viewer: { read: "own", create: false, update: false, delete: false }
|
|
4148
|
+
}
|
|
4149
|
+
};
|
|
4150
|
+
var AI_MESSAGES_SCHEMA = {
|
|
4151
|
+
name: "ai-messages",
|
|
4152
|
+
columns: [
|
|
4153
|
+
{ name: "chatId", storage: "text", interpretation: "plain", immutable: true, required: true },
|
|
4154
|
+
{ name: "userId", storage: "text", interpretation: "plain", userBound: true, immutable: true, required: true },
|
|
4155
|
+
{ name: "role", storage: "text", interpretation: "plain", required: true },
|
|
4156
|
+
{ name: "content", storage: "text", interpretation: "plain" },
|
|
4157
|
+
{ name: "parts", storage: "text", interpretation: { kind: "json" } }
|
|
4158
|
+
],
|
|
4159
|
+
ownerField: "userId",
|
|
4160
|
+
permissions: {
|
|
4161
|
+
admin: { read: true, create: true, update: true, delete: true },
|
|
4162
|
+
member: { read: "own", create: false, update: "own", delete: "own" },
|
|
4163
|
+
viewer: { read: "own", create: false, update: false, delete: false }
|
|
4164
|
+
}
|
|
4165
|
+
};
|
|
4166
|
+
|
|
4133
4167
|
// src/server/schemas/messaging.ts
|
|
4134
4168
|
var CHANNELS_SCHEMA = {
|
|
4135
4169
|
name: "channels",
|
|
@@ -5073,7 +5107,7 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
|
5073
5107
|
const apiBase = env.API_BASE_URL || "https://api.deep.space";
|
|
5074
5108
|
const roomIdObj = env.RECORD_ROOMS.idFromName(roomId);
|
|
5075
5109
|
const room = env.RECORD_ROOMS.get(roomIdObj);
|
|
5076
|
-
async function
|
|
5110
|
+
async function executeTool3(tool, params) {
|
|
5077
5111
|
const response = await room.fetch(new Request("https://internal/api/tools/execute", {
|
|
5078
5112
|
method: "POST",
|
|
5079
5113
|
headers: {
|
|
@@ -5094,17 +5128,17 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
|
5094
5128
|
const params = { collection };
|
|
5095
5129
|
if (opts?.where) params.where = opts.where;
|
|
5096
5130
|
if (opts?.limit) params.limit = opts.limit;
|
|
5097
|
-
const data = await
|
|
5131
|
+
const data = await executeTool3("records.query", params);
|
|
5098
5132
|
return data.records || [];
|
|
5099
5133
|
},
|
|
5100
5134
|
async create(collection, data) {
|
|
5101
|
-
return
|
|
5135
|
+
return executeTool3("records.create", { collection, data });
|
|
5102
5136
|
},
|
|
5103
5137
|
async update(collection, recordId, data) {
|
|
5104
|
-
return
|
|
5138
|
+
return executeTool3("records.update", { collection, recordId, data });
|
|
5105
5139
|
},
|
|
5106
5140
|
async delete(collection, recordId) {
|
|
5107
|
-
return
|
|
5141
|
+
return executeTool3("records.delete", { collection, recordId });
|
|
5108
5142
|
}
|
|
5109
5143
|
};
|
|
5110
5144
|
const integrations = {
|
|
@@ -5221,6 +5255,21 @@ function authWorkerFetch(env, path, init) {
|
|
|
5221
5255
|
}
|
|
5222
5256
|
|
|
5223
5257
|
// src/server/utils/ai.ts
|
|
5258
|
+
var ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS = 4096;
|
|
5259
|
+
function withDefaultAnthropicMaxTokens(body) {
|
|
5260
|
+
if (typeof body !== "string") return body;
|
|
5261
|
+
try {
|
|
5262
|
+
const parsed = JSON.parse(body);
|
|
5263
|
+
const hasExplicitLimit = typeof parsed.max_tokens === "number" || typeof parsed.max_completion_tokens === "number" || typeof parsed.max_output_tokens === "number";
|
|
5264
|
+
if (hasExplicitLimit) return body;
|
|
5265
|
+
return JSON.stringify({
|
|
5266
|
+
...parsed,
|
|
5267
|
+
max_tokens: ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS
|
|
5268
|
+
});
|
|
5269
|
+
} catch {
|
|
5270
|
+
return body;
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5224
5273
|
function createDeepSpaceAI(env, provider, options = {}) {
|
|
5225
5274
|
const transport = resolveApiTransport(env);
|
|
5226
5275
|
const authToken = options.authToken ?? env.APP_OWNER_JWT;
|
|
@@ -5235,24 +5284,26 @@ function createDeepSpaceAI(env, provider, options = {}) {
|
|
|
5235
5284
|
headers.delete("authorization");
|
|
5236
5285
|
headers.delete("x-api-key");
|
|
5237
5286
|
headers.set("X-Auth-Token", authToken);
|
|
5287
|
+
const body = provider === "anthropic" ? withDefaultAnthropicMaxTokens(init?.body) : init?.body;
|
|
5288
|
+
if (body !== init?.body) {
|
|
5289
|
+
headers.delete("content-length");
|
|
5290
|
+
}
|
|
5291
|
+
const nextInit = { ...init, headers, body };
|
|
5238
5292
|
if (transport.kind === "binding") {
|
|
5239
|
-
return transport.fetcher.fetch(url,
|
|
5293
|
+
return transport.fetcher.fetch(url, nextInit);
|
|
5240
5294
|
}
|
|
5241
5295
|
const original = new URL(url);
|
|
5242
5296
|
const rewritten = `${transport.baseUrl}${original.pathname}${original.search}`;
|
|
5243
|
-
return fetch(rewritten,
|
|
5297
|
+
return fetch(rewritten, nextInit);
|
|
5244
5298
|
};
|
|
5245
5299
|
const baseURL = `https://api-worker.internal/api/proxy/${provider}/v1`;
|
|
5246
5300
|
switch (provider) {
|
|
5247
5301
|
case "anthropic":
|
|
5248
5302
|
return createAnthropic({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
|
|
5249
|
-
case "openai":
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
fetch: proxyFetch,
|
|
5254
|
-
compatibility: "strict"
|
|
5255
|
-
});
|
|
5303
|
+
case "openai": {
|
|
5304
|
+
const op = createOpenAI({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
|
|
5305
|
+
return op.chat;
|
|
5306
|
+
}
|
|
5256
5307
|
case "cerebras":
|
|
5257
5308
|
return createOpenAICompatible({
|
|
5258
5309
|
name: "cerebras",
|
|
@@ -5267,7 +5318,407 @@ function createDeepSpaceAI(env, provider, options = {}) {
|
|
|
5267
5318
|
}
|
|
5268
5319
|
}
|
|
5269
5320
|
}
|
|
5321
|
+
|
|
5322
|
+
// src/server/utils/chat-context.ts
|
|
5323
|
+
import { generateText } from "ai";
|
|
5324
|
+
var DEFAULT_CONTEXT_CONFIG = {
|
|
5325
|
+
contextBudget: 24e4,
|
|
5326
|
+
toolResultCap: 3e4,
|
|
5327
|
+
keepRecentToolResults: 5,
|
|
5328
|
+
minKept: 10
|
|
5329
|
+
};
|
|
5330
|
+
function sizeOf(m) {
|
|
5331
|
+
return (m.content ?? "").length + (m.parts ? JSON.stringify(m.parts).length : 0);
|
|
5332
|
+
}
|
|
5333
|
+
function totalChars(messages) {
|
|
5334
|
+
return messages.reduce((acc, m) => acc + sizeOf(m), 0);
|
|
5335
|
+
}
|
|
5336
|
+
function truncateOldToolResults(messages, keepRecent) {
|
|
5337
|
+
const assistantIdxs = [];
|
|
5338
|
+
for (let i = 0; i < messages.length; i++) {
|
|
5339
|
+
if (messages[i].role === "assistant") assistantIdxs.push(i);
|
|
5340
|
+
}
|
|
5341
|
+
const protectedStart = assistantIdxs.length > keepRecent ? assistantIdxs[assistantIdxs.length - keepRecent] : 0;
|
|
5342
|
+
return messages.map((msg, idx) => {
|
|
5343
|
+
if (msg.role !== "assistant" || idx >= protectedStart) return msg;
|
|
5344
|
+
if (!Array.isArray(msg.parts) || msg.parts.length === 0) return msg;
|
|
5345
|
+
const newParts = msg.parts.map((p) => {
|
|
5346
|
+
if (!p || typeof p !== "object") return p;
|
|
5347
|
+
const anyP = p;
|
|
5348
|
+
if (anyP.type !== "tool-invocation") return p;
|
|
5349
|
+
const inv = anyP.toolInvocation;
|
|
5350
|
+
if (!inv || inv.state !== "result") return p;
|
|
5351
|
+
const result = inv.result;
|
|
5352
|
+
if (result && result.success === false) return p;
|
|
5353
|
+
return {
|
|
5354
|
+
...anyP,
|
|
5355
|
+
toolInvocation: {
|
|
5356
|
+
...inv,
|
|
5357
|
+
result: {
|
|
5358
|
+
_truncated: true,
|
|
5359
|
+
note: "Result from an earlier turn omitted to save context. Call this tool again if you need the data."
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
};
|
|
5363
|
+
});
|
|
5364
|
+
return { ...msg, parts: newParts };
|
|
5365
|
+
});
|
|
5366
|
+
}
|
|
5367
|
+
function applySlidingWindow(messages, charCap, minKept) {
|
|
5368
|
+
let total = totalChars(messages);
|
|
5369
|
+
if (total <= charCap) return messages;
|
|
5370
|
+
const out = [...messages];
|
|
5371
|
+
while (out.length > minKept && total > charCap) {
|
|
5372
|
+
const idx = out.findIndex((m) => m.role !== "system");
|
|
5373
|
+
if (idx < 0) break;
|
|
5374
|
+
const dropped = out.splice(idx, 1)[0];
|
|
5375
|
+
total -= sizeOf(dropped);
|
|
5376
|
+
}
|
|
5377
|
+
return out;
|
|
5378
|
+
}
|
|
5379
|
+
function capToolResultSize(result, byteCap) {
|
|
5380
|
+
let serialized;
|
|
5381
|
+
try {
|
|
5382
|
+
serialized = JSON.stringify(result);
|
|
5383
|
+
} catch {
|
|
5384
|
+
return { success: false, error: "Tool result could not be serialized." };
|
|
5385
|
+
}
|
|
5386
|
+
if (typeof serialized !== "string") return result;
|
|
5387
|
+
if (serialized.length <= byteCap) return result;
|
|
5388
|
+
return {
|
|
5389
|
+
success: false,
|
|
5390
|
+
truncated: true,
|
|
5391
|
+
error: `Tool result exceeded ${byteCap} bytes (was ${serialized.length}). Retry with a narrower query (e.g. add a \`where\` filter, reduce \`limit\`, or call records.get for a single record).`,
|
|
5392
|
+
preview: serialized.slice(0, 2e3)
|
|
5393
|
+
};
|
|
5394
|
+
}
|
|
5395
|
+
function turnsToCoreMessages(turns) {
|
|
5396
|
+
const out = [];
|
|
5397
|
+
for (const t of turns) {
|
|
5398
|
+
if (t.role === "system") {
|
|
5399
|
+
out.push({ role: "system", content: t.content });
|
|
5400
|
+
continue;
|
|
5401
|
+
}
|
|
5402
|
+
if (t.role === "user") {
|
|
5403
|
+
out.push({ role: "user", content: t.content });
|
|
5404
|
+
continue;
|
|
5405
|
+
}
|
|
5406
|
+
if (!Array.isArray(t.parts) || t.parts.length === 0) {
|
|
5407
|
+
if (t.content) out.push({ role: "assistant", content: t.content });
|
|
5408
|
+
continue;
|
|
5409
|
+
}
|
|
5410
|
+
let pending = [];
|
|
5411
|
+
let emittedAny = false;
|
|
5412
|
+
const flushAssistant = () => {
|
|
5413
|
+
if (pending.length === 0) return;
|
|
5414
|
+
out.push({ role: "assistant", content: pending });
|
|
5415
|
+
pending = [];
|
|
5416
|
+
emittedAny = true;
|
|
5417
|
+
};
|
|
5418
|
+
for (const p of t.parts) {
|
|
5419
|
+
if (!p || typeof p !== "object") continue;
|
|
5420
|
+
const anyP = p;
|
|
5421
|
+
if (anyP.type === "text" && typeof anyP.text === "string" && anyP.text) {
|
|
5422
|
+
pending.push({ type: "text", text: anyP.text });
|
|
5423
|
+
continue;
|
|
5424
|
+
}
|
|
5425
|
+
if (anyP.type !== "tool-invocation") continue;
|
|
5426
|
+
const inv = anyP.toolInvocation;
|
|
5427
|
+
const toolCallId = typeof anyP.toolCallId === "string" ? anyP.toolCallId : void 0;
|
|
5428
|
+
const toolName = typeof inv?.toolName === "string" ? inv.toolName : void 0;
|
|
5429
|
+
if (!toolCallId || !toolName) continue;
|
|
5430
|
+
if (inv?.state !== "result") continue;
|
|
5431
|
+
pending.push({ type: "tool-call", toolCallId, toolName, input: inv?.args });
|
|
5432
|
+
flushAssistant();
|
|
5433
|
+
const tr = {
|
|
5434
|
+
type: "tool-result",
|
|
5435
|
+
toolCallId,
|
|
5436
|
+
toolName,
|
|
5437
|
+
output: { type: "json", value: inv.result }
|
|
5438
|
+
};
|
|
5439
|
+
out.push({ role: "tool", content: [tr] });
|
|
5440
|
+
}
|
|
5441
|
+
flushAssistant();
|
|
5442
|
+
if (!emittedAny && t.content) {
|
|
5443
|
+
out.push({ role: "assistant", content: t.content });
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5446
|
+
return out;
|
|
5447
|
+
}
|
|
5448
|
+
function buildUiParts(responseMessages) {
|
|
5449
|
+
const toolResults = /* @__PURE__ */ new Map();
|
|
5450
|
+
for (const msg of responseMessages) {
|
|
5451
|
+
if (msg.role !== "tool" || !Array.isArray(msg.content)) continue;
|
|
5452
|
+
for (const c of msg.content) {
|
|
5453
|
+
if (c.type === "tool-result") {
|
|
5454
|
+
toolResults.set(c.toolCallId, unwrapToolOutput(c.output));
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
const parts = [];
|
|
5459
|
+
for (const msg of responseMessages) {
|
|
5460
|
+
if (msg.role !== "assistant") continue;
|
|
5461
|
+
if (typeof msg.content === "string") {
|
|
5462
|
+
if (msg.content) parts.push({ type: "text", text: msg.content });
|
|
5463
|
+
continue;
|
|
5464
|
+
}
|
|
5465
|
+
if (!Array.isArray(msg.content)) continue;
|
|
5466
|
+
for (const c of msg.content) {
|
|
5467
|
+
if (c.type === "text" && typeof c.text === "string" && c.text) {
|
|
5468
|
+
parts.push({ type: "text", text: c.text });
|
|
5469
|
+
} else if (c.type === "tool-call") {
|
|
5470
|
+
const result = toolResults.get(c.toolCallId);
|
|
5471
|
+
if (result === void 0) {
|
|
5472
|
+
continue;
|
|
5473
|
+
}
|
|
5474
|
+
parts.push({
|
|
5475
|
+
type: "tool-invocation",
|
|
5476
|
+
toolCallId: c.toolCallId,
|
|
5477
|
+
toolInvocation: {
|
|
5478
|
+
toolName: c.toolName,
|
|
5479
|
+
state: "result",
|
|
5480
|
+
args: c.input,
|
|
5481
|
+
result
|
|
5482
|
+
}
|
|
5483
|
+
});
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
return parts;
|
|
5488
|
+
}
|
|
5489
|
+
function unwrapToolOutput(output) {
|
|
5490
|
+
if (!output || typeof output !== "object") return output;
|
|
5491
|
+
const o = output;
|
|
5492
|
+
const tag = typeof o.type === "string" ? o.type : null;
|
|
5493
|
+
if (tag === "json" || tag === "text") {
|
|
5494
|
+
return "value" in o ? o.value : output;
|
|
5495
|
+
}
|
|
5496
|
+
if (tag === "error-text" || tag === "error-json") {
|
|
5497
|
+
return { success: false, error: "value" in o ? o.value : "Tool execution failed" };
|
|
5498
|
+
}
|
|
5499
|
+
return output;
|
|
5500
|
+
}
|
|
5501
|
+
function buildSummaryMessage(text, throughId) {
|
|
5502
|
+
return {
|
|
5503
|
+
id: `summary-${throughId}`,
|
|
5504
|
+
role: "system",
|
|
5505
|
+
content: `Earlier conversation summary:
|
|
5506
|
+
${text}`
|
|
5507
|
+
};
|
|
5508
|
+
}
|
|
5509
|
+
async function prepareMessagesWithCompaction(messages, config, options) {
|
|
5510
|
+
const truncated = truncateOldToolResults(messages, config.keepRecentToolResults);
|
|
5511
|
+
let working = truncated;
|
|
5512
|
+
if (options.cachedSummary) {
|
|
5513
|
+
const idx = truncated.findIndex((m) => m.id === options.cachedSummary.throughId);
|
|
5514
|
+
if (idx >= 0) {
|
|
5515
|
+
working = [
|
|
5516
|
+
buildSummaryMessage(options.cachedSummary.text, options.cachedSummary.throughId),
|
|
5517
|
+
...truncated.slice(idx + 1)
|
|
5518
|
+
];
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
if (totalChars(working) <= config.contextBudget) {
|
|
5522
|
+
return { messages: working };
|
|
5523
|
+
}
|
|
5524
|
+
const half = Math.max(1, Math.floor(working.length / 2));
|
|
5525
|
+
const older = working.slice(0, half);
|
|
5526
|
+
const newer = working.slice(half);
|
|
5527
|
+
let throughId;
|
|
5528
|
+
for (let i = older.length - 1; i >= 0; i--) {
|
|
5529
|
+
const id = older[i].id;
|
|
5530
|
+
if (id && !id.startsWith("summary-")) {
|
|
5531
|
+
throughId = id;
|
|
5532
|
+
break;
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5535
|
+
if (throughId) {
|
|
5536
|
+
try {
|
|
5537
|
+
const text = await options.summarizer(older);
|
|
5538
|
+
return {
|
|
5539
|
+
messages: [buildSummaryMessage(text, throughId), ...newer],
|
|
5540
|
+
newSummary: { text, throughId }
|
|
5541
|
+
};
|
|
5542
|
+
} catch (err) {
|
|
5543
|
+
console.error("prepareMessagesWithCompaction: summarizer failed, falling back to sliding window", err);
|
|
5544
|
+
}
|
|
5545
|
+
} else {
|
|
5546
|
+
console.warn("prepareMessagesWithCompaction: messages lack ids; cannot anchor a summary, falling back to sliding window");
|
|
5547
|
+
}
|
|
5548
|
+
return {
|
|
5549
|
+
messages: applySlidingWindow(working, config.contextBudget, config.minKept)
|
|
5550
|
+
};
|
|
5551
|
+
}
|
|
5552
|
+
var SUMMARIZER_SYSTEM_PROMPT = `You are compressing a conversation between a user and an AI assistant into a
|
|
5553
|
+
concise memory summary. The summary will replace the original messages in the
|
|
5554
|
+
conversation history; the assistant will read it on subsequent turns to
|
|
5555
|
+
maintain continuity.
|
|
5556
|
+
|
|
5557
|
+
Preserve in the summary:
|
|
5558
|
+
- User preferences and constraints the user stated (coding style, tone,
|
|
5559
|
+
skill level, goals).
|
|
5560
|
+
- Decisions made and rejected alternatives ("we chose X over Y because Z").
|
|
5561
|
+
- Current task state (what's in progress, what's been completed).
|
|
5562
|
+
- Any facts the user might reasonably reference later.
|
|
5563
|
+
|
|
5564
|
+
If the messages below contain a prior summary, incorporate its content into
|
|
5565
|
+
your new summary \u2014 do not drop information from earlier summaries.
|
|
5566
|
+
|
|
5567
|
+
Keep the summary under 2000 tokens. Write as a factual note to future-you,
|
|
5568
|
+
not as a narrative. Use terse bullet points where possible.`;
|
|
5569
|
+
function formatTranscript(messages) {
|
|
5570
|
+
return messages.map((m) => {
|
|
5571
|
+
const label = m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : "System";
|
|
5572
|
+
const tools = Array.isArray(m.parts) ? m.parts.filter((p) => p?.type === "tool-invocation").map((p) => {
|
|
5573
|
+
const name = p.toolInvocation?.toolName;
|
|
5574
|
+
return ` [tool: ${name ?? "unknown"}]`;
|
|
5575
|
+
}).join("\n") : "";
|
|
5576
|
+
return `${label}: ${m.content}${tools ? "\n" + tools : ""}`;
|
|
5577
|
+
}).join("\n\n");
|
|
5578
|
+
}
|
|
5579
|
+
function makeDefaultSummarizer(env, options = {}) {
|
|
5580
|
+
return async (messages) => {
|
|
5581
|
+
const anthropic = createDeepSpaceAI(env, "anthropic", { authToken: options.authToken });
|
|
5582
|
+
const { text } = await generateText({
|
|
5583
|
+
// Stable alias — provider bug-fix snapshots roll forward without code change.
|
|
5584
|
+
model: anthropic("claude-haiku-4-5"),
|
|
5585
|
+
// 2500 gives the model room to finish a sentence after hitting the
|
|
5586
|
+
// "under 2000 tokens" soft limit in the prompt.
|
|
5587
|
+
maxOutputTokens: 2500,
|
|
5588
|
+
system: SUMMARIZER_SYSTEM_PROMPT,
|
|
5589
|
+
messages: [{ role: "user", content: formatTranscript(messages) }]
|
|
5590
|
+
});
|
|
5591
|
+
return text;
|
|
5592
|
+
};
|
|
5593
|
+
}
|
|
5594
|
+
|
|
5595
|
+
// src/server/utils/chat-history.ts
|
|
5596
|
+
async function executeTool2(stub, userId, tool, params) {
|
|
5597
|
+
const res = await stub.fetch(new Request("https://internal/api/tools/execute", {
|
|
5598
|
+
method: "POST",
|
|
5599
|
+
headers: {
|
|
5600
|
+
"Content-Type": "application/json",
|
|
5601
|
+
"X-User-Id": userId,
|
|
5602
|
+
"X-App-Action": "true"
|
|
5603
|
+
},
|
|
5604
|
+
body: JSON.stringify({ tool, params })
|
|
5605
|
+
}));
|
|
5606
|
+
const body = await res.json();
|
|
5607
|
+
if (!body.success) {
|
|
5608
|
+
throw new Error(`chat-history ${tool} failed: ${body.error ?? "unknown error"}`);
|
|
5609
|
+
}
|
|
5610
|
+
return body.data;
|
|
5611
|
+
}
|
|
5612
|
+
function toChatRow(env) {
|
|
5613
|
+
return {
|
|
5614
|
+
id: env.recordId,
|
|
5615
|
+
userId: env.data.userId,
|
|
5616
|
+
title: env.data.title ?? "",
|
|
5617
|
+
model: env.data.model,
|
|
5618
|
+
compactedSummary: env.data.compactedSummary,
|
|
5619
|
+
compactedThroughId: env.data.compactedThroughId,
|
|
5620
|
+
createdAt: env.createdAt,
|
|
5621
|
+
updatedAt: env.updatedAt
|
|
5622
|
+
};
|
|
5623
|
+
}
|
|
5624
|
+
function toMessageRow(env) {
|
|
5625
|
+
return {
|
|
5626
|
+
id: env.recordId,
|
|
5627
|
+
chatId: env.data.chatId,
|
|
5628
|
+
userId: env.data.userId,
|
|
5629
|
+
role: env.data.role,
|
|
5630
|
+
content: env.data.content ?? "",
|
|
5631
|
+
parts: env.data.parts,
|
|
5632
|
+
createdAt: env.createdAt
|
|
5633
|
+
};
|
|
5634
|
+
}
|
|
5635
|
+
async function getChat(stub, chatId, userId) {
|
|
5636
|
+
try {
|
|
5637
|
+
const result = await executeTool2(stub, userId, "records.get", {
|
|
5638
|
+
collection: "ai-chats",
|
|
5639
|
+
recordId: chatId
|
|
5640
|
+
});
|
|
5641
|
+
return result.record ? toChatRow(result.record) : null;
|
|
5642
|
+
} catch (err) {
|
|
5643
|
+
if (err instanceof Error && err.message.includes("Record not found")) return null;
|
|
5644
|
+
throw err;
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
async function createChat(stub, userId, opts = {}) {
|
|
5648
|
+
const data = { userId };
|
|
5649
|
+
if (opts.title !== void 0) data.title = opts.title;
|
|
5650
|
+
if (opts.model !== void 0) data.model = opts.model;
|
|
5651
|
+
const result = await executeTool2(stub, userId, "records.create", {
|
|
5652
|
+
collection: "ai-chats",
|
|
5653
|
+
data
|
|
5654
|
+
});
|
|
5655
|
+
return toChatRow(result.record);
|
|
5656
|
+
}
|
|
5657
|
+
async function updateChat(stub, chatId, userId, patch) {
|
|
5658
|
+
await executeTool2(stub, userId, "records.update", {
|
|
5659
|
+
collection: "ai-chats",
|
|
5660
|
+
recordId: chatId,
|
|
5661
|
+
data: patch
|
|
5662
|
+
});
|
|
5663
|
+
}
|
|
5664
|
+
async function deleteChatCascade(stub, chatId, userId) {
|
|
5665
|
+
const list = await executeTool2(stub, userId, "records.query", {
|
|
5666
|
+
collection: "ai-messages",
|
|
5667
|
+
where: { chatId }
|
|
5668
|
+
});
|
|
5669
|
+
const errors = [];
|
|
5670
|
+
for (const env of list.records) {
|
|
5671
|
+
try {
|
|
5672
|
+
await executeTool2(stub, userId, "records.delete", {
|
|
5673
|
+
collection: "ai-messages",
|
|
5674
|
+
recordId: env.recordId
|
|
5675
|
+
});
|
|
5676
|
+
} catch (err) {
|
|
5677
|
+
errors.push(err);
|
|
5678
|
+
}
|
|
5679
|
+
}
|
|
5680
|
+
try {
|
|
5681
|
+
await executeTool2(stub, userId, "records.delete", {
|
|
5682
|
+
collection: "ai-chats",
|
|
5683
|
+
recordId: chatId
|
|
5684
|
+
});
|
|
5685
|
+
} catch (err) {
|
|
5686
|
+
errors.push(err);
|
|
5687
|
+
}
|
|
5688
|
+
if (errors.length > 0) {
|
|
5689
|
+
const first = errors[0];
|
|
5690
|
+
throw new Error(
|
|
5691
|
+
`deleteChatCascade: ${errors.length} delete(s) failed; first: ${first instanceof Error ? first.message : String(first)}`,
|
|
5692
|
+
{ cause: errors }
|
|
5693
|
+
);
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
async function loadMessages(stub, chatId, userId) {
|
|
5697
|
+
const result = await executeTool2(stub, userId, "records.query", {
|
|
5698
|
+
collection: "ai-messages",
|
|
5699
|
+
where: { chatId, userId },
|
|
5700
|
+
orderBy: "createdAt",
|
|
5701
|
+
orderDir: "asc"
|
|
5702
|
+
});
|
|
5703
|
+
return result.records.map(toMessageRow);
|
|
5704
|
+
}
|
|
5705
|
+
async function appendMessage(stub, msg) {
|
|
5706
|
+
const data = {
|
|
5707
|
+
chatId: msg.chatId,
|
|
5708
|
+
userId: msg.userId,
|
|
5709
|
+
role: msg.role,
|
|
5710
|
+
content: msg.content
|
|
5711
|
+
};
|
|
5712
|
+
if (msg.parts !== void 0) data.parts = msg.parts;
|
|
5713
|
+
await executeTool2(stub, msg.userId, "records.create", {
|
|
5714
|
+
collection: "ai-messages",
|
|
5715
|
+
recordId: msg.id,
|
|
5716
|
+
data
|
|
5717
|
+
});
|
|
5718
|
+
}
|
|
5270
5719
|
export {
|
|
5720
|
+
AI_CHATS_SCHEMA,
|
|
5721
|
+
AI_MESSAGES_SCHEMA,
|
|
5271
5722
|
Awareness,
|
|
5272
5723
|
BASE_USERS_SCHEMA,
|
|
5273
5724
|
BUILT_IN_TOOLS,
|
|
@@ -5278,6 +5729,7 @@ export {
|
|
|
5278
5729
|
CONVERSATION_SCHEMAS,
|
|
5279
5730
|
CanvasRoom,
|
|
5280
5731
|
CronRoom,
|
|
5732
|
+
DEFAULT_CONTEXT_CONFIG,
|
|
5281
5733
|
DEFAULT_DO_MANIFEST,
|
|
5282
5734
|
DEFAULT_MAX_SKEW_MS,
|
|
5283
5735
|
DIRECTORY_SCHEMAS,
|
|
@@ -5310,20 +5762,25 @@ export {
|
|
|
5310
5762
|
YjsRoom,
|
|
5311
5763
|
analyzePermissions,
|
|
5312
5764
|
apiWorkerFetch,
|
|
5765
|
+
appendMessage,
|
|
5766
|
+
applySlidingWindow,
|
|
5313
5767
|
authWorkerFetch,
|
|
5314
5768
|
buildCronContext,
|
|
5315
5769
|
buildInternalPayload,
|
|
5316
5770
|
buildTableSelect,
|
|
5771
|
+
buildUiParts,
|
|
5317
5772
|
canCreate,
|
|
5318
5773
|
canDelete,
|
|
5319
5774
|
canRead,
|
|
5320
5775
|
canUpdate,
|
|
5776
|
+
capToolResultSize,
|
|
5321
5777
|
checkFieldPermissions,
|
|
5322
5778
|
clientBuild,
|
|
5323
5779
|
coerceValue,
|
|
5324
5780
|
collectionTableName,
|
|
5325
5781
|
columnId,
|
|
5326
5782
|
computeHmacHex,
|
|
5783
|
+
createChat,
|
|
5327
5784
|
createDecoder,
|
|
5328
5785
|
createDeepSpaceAI,
|
|
5329
5786
|
createDeepSpaceAuth,
|
|
@@ -5331,12 +5788,14 @@ export {
|
|
|
5331
5788
|
createScopedR2Handler,
|
|
5332
5789
|
dataToColumnValues,
|
|
5333
5790
|
decodeJwtPayload,
|
|
5791
|
+
deleteChatCascade,
|
|
5334
5792
|
dispatch,
|
|
5335
5793
|
encode,
|
|
5336
5794
|
encodeAwarenessMessage,
|
|
5337
5795
|
encodeSyncStep1,
|
|
5338
5796
|
encodeSyncStep2,
|
|
5339
5797
|
encodeUpdate,
|
|
5798
|
+
getChat,
|
|
5340
5799
|
getGlobalDOSchemas,
|
|
5341
5800
|
getGlobalDOType,
|
|
5342
5801
|
getMessageType,
|
|
@@ -5345,8 +5804,11 @@ export {
|
|
|
5345
5804
|
handleSyncMessage,
|
|
5346
5805
|
hasContent,
|
|
5347
5806
|
isOwner,
|
|
5807
|
+
loadMessages,
|
|
5808
|
+
makeDefaultSummarizer,
|
|
5348
5809
|
noopPermissionContext,
|
|
5349
5810
|
platformWorkerFetch,
|
|
5811
|
+
prepareMessagesWithCompaction,
|
|
5350
5812
|
readVarUint,
|
|
5351
5813
|
readVarUint8Array,
|
|
5352
5814
|
resolveColumn,
|
|
@@ -5355,6 +5817,11 @@ export {
|
|
|
5355
5817
|
signInternalPayload,
|
|
5356
5818
|
timingSafeEqualHex,
|
|
5357
5819
|
toUint8Array,
|
|
5820
|
+
totalChars,
|
|
5821
|
+
truncateOldToolResults,
|
|
5822
|
+
turnsToCoreMessages,
|
|
5823
|
+
unwrapToolOutput,
|
|
5824
|
+
updateChat,
|
|
5358
5825
|
verifyInternalSignature,
|
|
5359
5826
|
verifyJwt,
|
|
5360
5827
|
workspaceAccountsSchema,
|