negotium 0.5.12 → 0.5.15
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/agent-helpers.js +100 -37
- package/dist/agent-helpers.js.map +10 -9
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +2 -2
- package/dist/main.js +553 -317
- package/dist/main.js.map +16 -14
- package/dist/mcp-factories.js +102 -39
- package/dist/mcp-factories.js.map +10 -9
- package/dist/outbox.js +103 -21
- package/dist/outbox.js.map +5 -4
- package/dist/registry.js +2 -2
- package/dist/registry.js.map +2 -2
- package/dist/runtime/src/bus.ts +21 -2
- package/dist/runtime/src/index.ts +1 -0
- package/dist/runtime/src/outbox/coalescing-runner.ts +157 -0
- package/dist/runtime/src/outbox/index.ts +6 -0
- package/dist/runtime/src/runtime/inbox.ts +98 -20
- package/dist/runtime/src/runtime/turn-event-stream.ts +5 -0
- package/dist/runtime/src/runtime/turn-runner.ts +61 -3
- package/dist/runtime/src/storage/api-messages.ts +11 -2
- package/dist/runtime/src/storage/session-inbox-signal.ts +76 -0
- package/dist/runtime/src/storage/session-inbox.ts +5 -1
- package/dist/runtime/src/types/api.ts +11 -1
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +53 -10
- package/dist/runtime-helpers.js.map +6 -5
- package/dist/storage.js +9 -4
- package/dist/storage.js.map +3 -3
- package/dist/types/packages/core/src/bus.d.ts +4 -0
- package/dist/types/packages/core/src/outbox/coalescing-runner.d.ts +68 -0
- package/dist/types/packages/core/src/outbox/index.d.ts +1 -0
- package/dist/types/packages/core/src/runtime/turn-event-stream.d.ts +5 -1
- package/dist/types/packages/core/src/runtime/turn-runner.d.ts +4 -0
- package/dist/types/packages/core/src/storage/api-messages.d.ts +1 -0
- package/dist/types/packages/core/src/storage/session-inbox-signal.d.ts +35 -0
- package/dist/types/packages/core/src/types/api.d.ts +10 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/agent-helpers.js
CHANGED
|
@@ -2443,7 +2443,7 @@ var init_claude_registry = __esm(() => {
|
|
|
2443
2443
|
});
|
|
2444
2444
|
|
|
2445
2445
|
// ../../packages/core/src/version.ts
|
|
2446
|
-
var NEGOTIUM_VERSION = "0.5.
|
|
2446
|
+
var NEGOTIUM_VERSION = "0.5.15";
|
|
2447
2447
|
|
|
2448
2448
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
2449
2449
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -6413,12 +6413,21 @@ class SqliteRuntimeBus {
|
|
|
6413
6413
|
queryId,
|
|
6414
6414
|
usage,
|
|
6415
6415
|
agent: meta?.agent,
|
|
6416
|
-
model: meta?.model
|
|
6416
|
+
model: meta?.model,
|
|
6417
|
+
budgetReason: meta?.budgetReason
|
|
6417
6418
|
});
|
|
6418
6419
|
}
|
|
6419
6420
|
broadcastError(topicId, queryId, error) {
|
|
6420
6421
|
this.broadcastAiStatus(topicId, { kind: "ai_error", queryId, error });
|
|
6421
6422
|
}
|
|
6423
|
+
broadcastTopicNotice(topicId, severity, label) {
|
|
6424
|
+
this.broadcastAiStatus(topicId, {
|
|
6425
|
+
kind: "topic_notice",
|
|
6426
|
+
severity,
|
|
6427
|
+
label,
|
|
6428
|
+
ts: new Date().toISOString()
|
|
6429
|
+
});
|
|
6430
|
+
}
|
|
6422
6431
|
broadcastAborted(topicId, queryId, reason) {
|
|
6423
6432
|
this.broadcastAiStatus(topicId, { kind: "ai_aborted", queryId, reason });
|
|
6424
6433
|
}
|
|
@@ -7112,6 +7121,7 @@ function initializeApiMessagesSchema() {
|
|
|
7112
7121
|
reactions TEXT,
|
|
7113
7122
|
kind TEXT,
|
|
7114
7123
|
ask_user_question TEXT,
|
|
7124
|
+
tell_card TEXT,
|
|
7115
7125
|
mentions TEXT,
|
|
7116
7126
|
thread_root_id TEXT,
|
|
7117
7127
|
created_at TEXT NOT NULL
|
|
@@ -7141,6 +7151,9 @@ function initializeApiMessagesSchema() {
|
|
|
7141
7151
|
try {
|
|
7142
7152
|
db.exec("ALTER TABLE api_messages ADD COLUMN ask_user_question TEXT");
|
|
7143
7153
|
} catch {}
|
|
7154
|
+
try {
|
|
7155
|
+
db.exec("ALTER TABLE api_messages ADD COLUMN tell_card TEXT");
|
|
7156
|
+
} catch {}
|
|
7144
7157
|
try {
|
|
7145
7158
|
db.exec("ALTER TABLE api_messages ADD COLUMN mentions TEXT");
|
|
7146
7159
|
} catch {}
|
|
@@ -7184,6 +7197,7 @@ function rowToDto(r) {
|
|
|
7184
7197
|
reactions: r.reactions ? JSON.parse(r.reactions) : undefined,
|
|
7185
7198
|
kind: r.kind ?? undefined,
|
|
7186
7199
|
askUserQuestion: r.ask_user_question ? JSON.parse(r.ask_user_question) : undefined,
|
|
7200
|
+
tellCard: r.tell_card ? JSON.parse(r.tell_card) : undefined,
|
|
7187
7201
|
subagentCard: r.subagent_card ? JSON.parse(r.subagent_card) : undefined,
|
|
7188
7202
|
mentions: r.mentions ? JSON.parse(r.mentions) : undefined,
|
|
7189
7203
|
threadRootId: r.thread_root_id ?? undefined,
|
|
@@ -7206,9 +7220,9 @@ function appendApiMessage(msg, options = {}) {
|
|
|
7206
7220
|
let inserted = false;
|
|
7207
7221
|
db.transaction(() => {
|
|
7208
7222
|
const result = db.query(`INSERT INTO api_messages
|
|
7209
|
-
(id, topic_id, parent_id, author_id, source_adapter, source_node, source_message_id, text, query_id, agent_type, model, attachments, usage, deleted, edited_at, reactions, kind, ask_user_question, subagent_card, mentions, thread_root_id, created_at)
|
|
7210
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
7211
|
-
ON CONFLICT(id) DO NOTHING`).run(msg.id, msg.topicId, msg.parentId ?? null, msg.authorId, msg.sourceAdapter ?? null, msg.sourceNode ?? null, msg.sourceMessageId ?? null, msg.text, msg.queryId ?? null, msg.agentType ?? null, msg.model ?? null, msg.attachments ? JSON.stringify(msg.attachments) : null, msg.usage ? JSON.stringify(msg.usage) : null, msg.deleted ? 1 : 0, msg.editedAt ?? null, msg.reactions?.length ? JSON.stringify(msg.reactions) : null, msg.kind ?? null, msg.askUserQuestion ? JSON.stringify(msg.askUserQuestion) : null, msg.subagentCard ? JSON.stringify(msg.subagentCard) : null, msg.mentions?.length ? JSON.stringify(msg.mentions) : null, msg.threadRootId ?? null, msg.createdAt);
|
|
7223
|
+
(id, topic_id, parent_id, author_id, source_adapter, source_node, source_message_id, text, query_id, agent_type, model, attachments, usage, deleted, edited_at, reactions, kind, ask_user_question, tell_card, subagent_card, mentions, thread_root_id, created_at)
|
|
7224
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
7225
|
+
ON CONFLICT(id) DO NOTHING`).run(msg.id, msg.topicId, msg.parentId ?? null, msg.authorId, msg.sourceAdapter ?? null, msg.sourceNode ?? null, msg.sourceMessageId ?? null, msg.text, msg.queryId ?? null, msg.agentType ?? null, msg.model ?? null, msg.attachments ? JSON.stringify(msg.attachments) : null, msg.usage ? JSON.stringify(msg.usage) : null, msg.deleted ? 1 : 0, msg.editedAt ?? null, msg.reactions?.length ? JSON.stringify(msg.reactions) : null, msg.kind ?? null, msg.askUserQuestion ? JSON.stringify(msg.askUserQuestion) : null, msg.tellCard ? JSON.stringify(msg.tellCard) : null, msg.subagentCard ? JSON.stringify(msg.subagentCard) : null, msg.mentions?.length ? JSON.stringify(msg.mentions) : null, msg.threadRootId ?? null, msg.createdAt);
|
|
7212
7226
|
inserted = Number(result.changes ?? 0) > 0;
|
|
7213
7227
|
if (inserted && updateTopicLastMessageAt && !msg.deleted) {
|
|
7214
7228
|
db.query(`UPDATE api_topics
|
|
@@ -13308,12 +13322,23 @@ var init_session_inbox_path = __esm(() => {
|
|
|
13308
13322
|
init_config();
|
|
13309
13323
|
});
|
|
13310
13324
|
|
|
13325
|
+
// ../../packages/core/src/storage/session-inbox-signal.ts
|
|
13326
|
+
import { join as join23 } from "path";
|
|
13327
|
+
var SESSION_INBOX_WAKE_FILE, listeners;
|
|
13328
|
+
var init_session_inbox_signal = __esm(() => {
|
|
13329
|
+
init_config();
|
|
13330
|
+
init_logger();
|
|
13331
|
+
SESSION_INBOX_WAKE_FILE = join23(SESSION_INBOX_DIR, ".wake");
|
|
13332
|
+
listeners = new Set;
|
|
13333
|
+
});
|
|
13334
|
+
|
|
13311
13335
|
// ../../packages/core/src/storage/session-inbox.ts
|
|
13312
13336
|
function deleteSessionInboxForTopic(topicId) {
|
|
13313
13337
|
return Number(db.run("DELETE FROM session_inbox WHERE topic_id = ?", [topicId]).changes ?? 0);
|
|
13314
13338
|
}
|
|
13315
13339
|
var init_session_inbox = __esm(async () => {
|
|
13316
13340
|
await init_forum_db();
|
|
13341
|
+
init_session_inbox_signal();
|
|
13317
13342
|
await init_storage_host();
|
|
13318
13343
|
registerStorageSchemaInitializer((database) => {
|
|
13319
13344
|
database.exec(`
|
|
@@ -13339,13 +13364,13 @@ var init_session_inbox = __esm(async () => {
|
|
|
13339
13364
|
|
|
13340
13365
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
13341
13366
|
import { unlinkSync as unlinkSync14 } from "fs";
|
|
13342
|
-
import { basename as basename3, join as
|
|
13367
|
+
import { basename as basename3, join as join24 } from "path";
|
|
13343
13368
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
13344
13369
|
const live = sessionInboxPath(userId, topicId);
|
|
13345
13370
|
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
13346
13371
|
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
13347
13372
|
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
|
|
13348
|
-
const legacyBase =
|
|
13373
|
+
const legacyBase = join24(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
13349
13374
|
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
13350
13375
|
candidates.add(`${legacyBase}${suffix}`);
|
|
13351
13376
|
}
|
|
@@ -13372,16 +13397,16 @@ var init_session_inbox_cleanup = __esm(async () => {
|
|
|
13372
13397
|
|
|
13373
13398
|
// ../../packages/core/src/query/state.ts
|
|
13374
13399
|
import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
13375
|
-
import { basename as basename4, join as
|
|
13400
|
+
import { basename as basename4, join as join25 } from "path";
|
|
13376
13401
|
function createQueryStateStore(options) {
|
|
13377
13402
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
13378
|
-
const queryStateDirPath = (userId) =>
|
|
13379
|
-
const queryStateFile = (userId, topicId) =>
|
|
13403
|
+
const queryStateDirPath = (userId) => join25(options.usersLogDir, String(userId), "active-queries");
|
|
13404
|
+
const queryStateFile = (userId, topicId) => join25(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
|
|
13380
13405
|
const legacyQueryStateFile = (userId, topicName) => {
|
|
13381
13406
|
if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
|
|
13382
13407
|
return null;
|
|
13383
13408
|
}
|
|
13384
|
-
return
|
|
13409
|
+
return join25(queryStateDirPath(userId), `${topicName}.json`);
|
|
13385
13410
|
};
|
|
13386
13411
|
return {
|
|
13387
13412
|
write(userId, topicId, topicName, task) {
|
|
@@ -13542,29 +13567,29 @@ import {
|
|
|
13542
13567
|
unlinkSync as unlinkSync16,
|
|
13543
13568
|
writeFileSync as writeFileSync13
|
|
13544
13569
|
} from "fs";
|
|
13545
|
-
import { dirname as dirname14, join as
|
|
13570
|
+
import { dirname as dirname14, join as join26 } from "path";
|
|
13546
13571
|
function pendingAskDir(userId) {
|
|
13547
13572
|
const rawUserId = String(userId);
|
|
13548
13573
|
const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
|
|
13549
|
-
return
|
|
13574
|
+
return join26(resolveStorageSessionAsksDir(), safeUserId);
|
|
13550
13575
|
}
|
|
13551
13576
|
function encodeAskKey(key) {
|
|
13552
13577
|
return JSON.stringify([key.from, key.to]);
|
|
13553
13578
|
}
|
|
13554
13579
|
function pendingAskPath(key) {
|
|
13555
13580
|
const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
|
|
13556
|
-
return
|
|
13581
|
+
return join26(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
|
|
13557
13582
|
}
|
|
13558
13583
|
function v2PendingAskPath(key) {
|
|
13559
13584
|
const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
|
|
13560
|
-
return
|
|
13585
|
+
return join26(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
|
|
13561
13586
|
}
|
|
13562
13587
|
function legacyPendingAskPath(key) {
|
|
13563
13588
|
if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
|
|
13564
13589
|
return null;
|
|
13565
13590
|
}
|
|
13566
13591
|
const dir = pendingAskDir(key.userId);
|
|
13567
|
-
const candidate =
|
|
13592
|
+
const candidate = join26(dir, `${key.from}___${key.to}.pending`);
|
|
13568
13593
|
return dirname14(candidate) === dir ? candidate : null;
|
|
13569
13594
|
}
|
|
13570
13595
|
function parsePendingAskFilename(fileName) {
|
|
@@ -13805,7 +13830,7 @@ function listPendingAsksForCaller(args) {
|
|
|
13805
13830
|
const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
|
|
13806
13831
|
if (!parsed)
|
|
13807
13832
|
continue;
|
|
13808
|
-
const path =
|
|
13833
|
+
const path = join26(dir, fileName);
|
|
13809
13834
|
const record = readPendingAskFile(path, {
|
|
13810
13835
|
userId: args.userId,
|
|
13811
13836
|
from: parsed.from,
|
|
@@ -13847,7 +13872,7 @@ function deletePendingAsksForTopic(args) {
|
|
|
13847
13872
|
}
|
|
13848
13873
|
let deleted = 0;
|
|
13849
13874
|
for (const fileName of files) {
|
|
13850
|
-
const path =
|
|
13875
|
+
const path = join26(dir, fileName);
|
|
13851
13876
|
const parsed = parsePendingAskFilename(fileName);
|
|
13852
13877
|
const record = readPendingAskFile(path, {
|
|
13853
13878
|
userId: args.userId,
|
|
@@ -14247,7 +14272,7 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
|
|
|
14247
14272
|
// ../../packages/core/src/storage/token-stats.ts
|
|
14248
14273
|
import { createHash as createHash7 } from "crypto";
|
|
14249
14274
|
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
14250
|
-
import { join as
|
|
14275
|
+
import { join as join27 } from "path";
|
|
14251
14276
|
function tokenStatsFileId(userId) {
|
|
14252
14277
|
const rawUserId = String(userId);
|
|
14253
14278
|
return /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash7("sha256").update(rawUserId).digest("hex")}`;
|
|
@@ -14256,7 +14281,7 @@ function queriesPath(userId) {
|
|
|
14256
14281
|
const fileId = tokenStatsFileId(userId);
|
|
14257
14282
|
const logDir = resolveStorageLogDir();
|
|
14258
14283
|
mkdirSync16(logDir, { recursive: true });
|
|
14259
|
-
return
|
|
14284
|
+
return join27(logDir, `token-queries-${fileId}.jsonl`);
|
|
14260
14285
|
}
|
|
14261
14286
|
function estimateUsageCost(agent, model, usage) {
|
|
14262
14287
|
const prices = TOKEN_PRICES[`${agent}:${model}`];
|
|
@@ -14600,7 +14625,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
14600
14625
|
// ../../packages/core/src/runtime/attachments.ts
|
|
14601
14626
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
14602
14627
|
import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
14603
|
-
import { basename as basename5, join as
|
|
14628
|
+
import { basename as basename5, join as join28 } from "path";
|
|
14604
14629
|
function workspaceCwdFor(topicId) {
|
|
14605
14630
|
return resolveTopicWorkspaceDir(topicId);
|
|
14606
14631
|
}
|
|
@@ -14613,7 +14638,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
14613
14638
|
if (!attachmentIds?.length)
|
|
14614
14639
|
return [];
|
|
14615
14640
|
const out = [];
|
|
14616
|
-
const destDir =
|
|
14641
|
+
const destDir = join28(workspaceCwdFor(topicId), "attachments", queryId);
|
|
14617
14642
|
for (const rawId of attachmentIds) {
|
|
14618
14643
|
if (typeof rawId !== "string")
|
|
14619
14644
|
continue;
|
|
@@ -14630,7 +14655,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
14630
14655
|
mkdirSync17(destDir, { recursive: true });
|
|
14631
14656
|
const index = String(out.length + 1).padStart(2, "0");
|
|
14632
14657
|
const safeName = safeAttachmentFilename(attachment.filename, fileId);
|
|
14633
|
-
const destPath =
|
|
14658
|
+
const destPath = join28(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
|
|
14634
14659
|
copyFileSync2(sourcePath, destPath);
|
|
14635
14660
|
out.push({
|
|
14636
14661
|
id: attachment.id,
|
|
@@ -14660,10 +14685,10 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
14660
14685
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
14661
14686
|
}
|
|
14662
14687
|
function ingestAttachment(args) {
|
|
14663
|
-
const destDir =
|
|
14688
|
+
const destDir = join28(UPLOADS_DIR, args.topicId);
|
|
14664
14689
|
mkdirSync17(destDir, { recursive: true });
|
|
14665
14690
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
14666
|
-
const destPath =
|
|
14691
|
+
const destPath = join28(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
|
|
14667
14692
|
if (args.sourcePath !== undefined) {
|
|
14668
14693
|
copyFileSync2(args.sourcePath, destPath);
|
|
14669
14694
|
} else if (args.bytes !== undefined) {
|
|
@@ -15755,6 +15780,10 @@ ${JSON.stringify(event.input ?? {})}`);
|
|
|
15755
15780
|
logger.warn({ topicId, queryId, agentType, model, silent, error: event.content }, "ai: provider returned error");
|
|
15756
15781
|
terminalEmitted = true;
|
|
15757
15782
|
errorOccurred = true;
|
|
15783
|
+
if (event.code === "budget_exceeded") {
|
|
15784
|
+
outcome = { kind: "budget-capped", reason: "cost", usage: event.usage };
|
|
15785
|
+
return outcome;
|
|
15786
|
+
}
|
|
15758
15787
|
if (retryableSessionExpired && isSessionExpiredError(event.content)) {
|
|
15759
15788
|
outcome = { kind: "session-expired", error: event.content };
|
|
15760
15789
|
return outcome;
|
|
@@ -15958,9 +15987,9 @@ var init_turn_session = __esm(async () => {
|
|
|
15958
15987
|
|
|
15959
15988
|
// ../../packages/core/src/storage/app-settings.ts
|
|
15960
15989
|
import { existsSync as existsSync19, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
|
|
15961
|
-
import { dirname as dirname15, join as
|
|
15990
|
+
import { dirname as dirname15, join as join29 } from "path";
|
|
15962
15991
|
function settingsFile() {
|
|
15963
|
-
return
|
|
15992
|
+
return join29(resolveStorageDataDir(), "otium-settings.json");
|
|
15964
15993
|
}
|
|
15965
15994
|
function getGlobalAiName() {
|
|
15966
15995
|
const path = settingsFile();
|
|
@@ -16055,7 +16084,7 @@ __export(exports_turn_runner, {
|
|
|
16055
16084
|
});
|
|
16056
16085
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
16057
16086
|
import { existsSync as existsSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
|
|
16058
|
-
import { join as
|
|
16087
|
+
import { join as join30 } from "path";
|
|
16059
16088
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
16060
16089
|
if (isManager)
|
|
16061
16090
|
return configuredMcp;
|
|
@@ -16095,13 +16124,20 @@ function notifyPlaywrightUnavailable(topicId) {
|
|
|
16095
16124
|
return;
|
|
16096
16125
|
playwrightUnavailableNoticeAt.set(topicId, now);
|
|
16097
16126
|
appendSystemMessage(topicId, "Playwright browser tools are unavailable this turn. Browser automation was removed from the tool catalog; retry shortly if browser interaction is required.");
|
|
16127
|
+
WsHub.get().broadcastTopicNotice(topicId, "info", "Playwright \uC0AC\uC6A9 \uBD88\uAC00");
|
|
16098
16128
|
}
|
|
16099
|
-
function appendAskReplyMessage(topicId, text2, agentType) {
|
|
16129
|
+
function appendAskReplyMessage(topicId, text2, sourceLabel, body, kind, agentType) {
|
|
16100
16130
|
const message = {
|
|
16101
16131
|
id: randomUUID16(),
|
|
16102
16132
|
topicId,
|
|
16103
16133
|
authorId: "ai",
|
|
16104
16134
|
text: text2,
|
|
16135
|
+
kind: "tell",
|
|
16136
|
+
tellCard: {
|
|
16137
|
+
fromLabel: sourceLabel,
|
|
16138
|
+
label: `${kind === "error" ? "Error" : "Reply"} from ${sourceLabel}`,
|
|
16139
|
+
message: body
|
|
16140
|
+
},
|
|
16105
16141
|
...agentType ? { agentType } : {},
|
|
16106
16142
|
createdAt: new Date().toISOString()
|
|
16107
16143
|
};
|
|
@@ -16110,7 +16146,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
16110
16146
|
return message;
|
|
16111
16147
|
}
|
|
16112
16148
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
16113
|
-
const preferred =
|
|
16149
|
+
const preferred = join30(directory, preferredFilename);
|
|
16114
16150
|
if (preferExact && existsSync20(preferred))
|
|
16115
16151
|
return preferred;
|
|
16116
16152
|
let newestLegacyId = null;
|
|
@@ -16121,7 +16157,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
16121
16157
|
const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
|
|
16122
16158
|
if (!titleMatch && !legacyIdMatch)
|
|
16123
16159
|
continue;
|
|
16124
|
-
const path =
|
|
16160
|
+
const path = join30(directory, filename);
|
|
16125
16161
|
const mtimeMs = statSync10(path).mtimeMs;
|
|
16126
16162
|
if (titleMatch) {
|
|
16127
16163
|
if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
|
|
@@ -16135,9 +16171,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
16135
16171
|
return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
|
|
16136
16172
|
}
|
|
16137
16173
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
16138
|
-
const briefFile = resolveWikiMirrorPath(
|
|
16174
|
+
const briefFile = resolveWikiMirrorPath(join30(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
16139
16175
|
const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
|
|
16140
|
-
const latestSummaryCandidate = resolveWikiMirrorPath(
|
|
16176
|
+
const latestSummaryCandidate = resolveWikiMirrorPath(join30(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
16141
16177
|
const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
16142
16178
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
16143
16179
|
}
|
|
@@ -16244,7 +16280,7 @@ ${body}`;
|
|
|
16244
16280
|
await markPendingAskFile(pending, "reply_ready");
|
|
16245
16281
|
if (!callerTopic?.agent) {
|
|
16246
16282
|
try {
|
|
16247
|
-
appendAskReplyMessage(pending.callerTopicId, prompt);
|
|
16283
|
+
appendAskReplyMessage(pending.callerTopicId, prompt, sourceLabel, body, kind);
|
|
16248
16284
|
await clearPendingAskFile(pending);
|
|
16249
16285
|
return true;
|
|
16250
16286
|
} catch (err2) {
|
|
@@ -16274,7 +16310,7 @@ ${body}`;
|
|
|
16274
16310
|
}
|
|
16275
16311
|
});
|
|
16276
16312
|
if (queued) {
|
|
16277
|
-
appendAskReplyMessage(pending.callerTopicId, prompt, callerTopic.agent);
|
|
16313
|
+
appendAskReplyMessage(pending.callerTopicId, prompt, sourceLabel, body, kind, callerTopic.agent);
|
|
16278
16314
|
await markPendingAskFile(pending, "queued_for_caller");
|
|
16279
16315
|
return true;
|
|
16280
16316
|
}
|
|
@@ -16283,7 +16319,7 @@ ${body}`;
|
|
|
16283
16319
|
return true;
|
|
16284
16320
|
}
|
|
16285
16321
|
logger.warn({ requestId: pending.requestId, callerTopicId: pending.callerTopicId, source: sourceLabel }, "sessions: ask callback could not enter caller batch; appending direct fallback");
|
|
16286
|
-
appendAskReplyMessage(pending.callerTopicId, prompt, callerTopic.agent);
|
|
16322
|
+
appendAskReplyMessage(pending.callerTopicId, prompt, sourceLabel, body, kind, callerTopic.agent);
|
|
16287
16323
|
await clearPendingAskFile(pending);
|
|
16288
16324
|
return true;
|
|
16289
16325
|
}
|
|
@@ -17151,12 +17187,36 @@ function startAiTurn(params) {
|
|
|
17151
17187
|
return;
|
|
17152
17188
|
}
|
|
17153
17189
|
}
|
|
17190
|
+
if (outcome.kind === "budget-capped") {
|
|
17191
|
+
const error = "The job reached its cost limit";
|
|
17192
|
+
if (!silent) {
|
|
17193
|
+
appendSystemMessage(topicId, "\uC5EC\uAE30\uAE4C\uC9C0 \uC644\uB8CC\uD588\uC5B4\uC694. \uBE44\uC6A9 \uC608\uC0B0 \uD55C\uB3C4\uC5D0 \uB3C4\uB2EC\uD574 \uC791\uC5C5\uC744 \uBA48\uCDC4\uC2B5\uB2C8\uB2E4.");
|
|
17194
|
+
WsHub.get().broadcastDone(topicId, queryId, outcome.usage ? {
|
|
17195
|
+
input: outcome.usage.inputTokens,
|
|
17196
|
+
output: outcome.usage.outputTokens,
|
|
17197
|
+
cachedInput: outcome.usage.cacheReadInputTokens,
|
|
17198
|
+
context: outcome.usage.contextTokens,
|
|
17199
|
+
contextWindow: outcome.usage.contextWindow
|
|
17200
|
+
} : undefined, { agent: agentKind, model: resolvedModel, budgetReason: outcome.reason });
|
|
17201
|
+
WsHub.get().broadcastTopicNotice(topicId, "warning", "\uC608\uC0B0 \uD55C\uB3C4 \uB3C4\uB2EC");
|
|
17202
|
+
} else {
|
|
17203
|
+
await deliverAskError(queryId, topic.title, error);
|
|
17204
|
+
}
|
|
17205
|
+
await settleSubagentFailure(queryId, error);
|
|
17206
|
+
try {
|
|
17207
|
+
onSettled?.({ queryId, kind: "error", error });
|
|
17208
|
+
} catch (err2) {
|
|
17209
|
+
logger.warn({ err: err2, topicId, queryId }, "ai: turn settlement hook failed");
|
|
17210
|
+
}
|
|
17211
|
+
return;
|
|
17212
|
+
}
|
|
17154
17213
|
if (outcome.kind === "provider-error") {
|
|
17155
17214
|
if (!silent) {
|
|
17156
17215
|
appendSystemMessage(topicId, `${classifyAgentError(outcome.error, agentKind)}
|
|
17157
17216
|
|
|
17158
17217
|
\uB2E4\uB978 \uB4F1\uB85D\uB41C \uBAA8\uB378\uC744 \uC4F0\uB824\uBA74 /model <model>\uB85C \uBC14\uAFBC \uB4A4 \uB2E4\uC2DC \uBCF4\uB0B4\uC138\uC694.`);
|
|
17159
17218
|
WsHub.get().broadcastError(topicId, queryId, outcome.error);
|
|
17219
|
+
WsHub.get().broadcastTopicNotice(topicId, "error", "\uC751\uB2F5 \uC2E4\uD328");
|
|
17160
17220
|
}
|
|
17161
17221
|
await deliverAskError(queryId, topic.title, outcome.error);
|
|
17162
17222
|
await settleSubagentFailure(queryId, classifyAgentError(outcome.error, agentKind));
|
|
@@ -17184,6 +17244,7 @@ function startAiTurn(params) {
|
|
|
17184
17244
|
logger.warn({ err: err2, topicId, queryId, agent: agentKind, model: resolvedModel, silent }, "ai: background stream task failed");
|
|
17185
17245
|
if (!silent) {
|
|
17186
17246
|
WsHub.get().broadcastError(topicId, queryId, error);
|
|
17247
|
+
WsHub.get().broadcastTopicNotice(topicId, "error", "\uC751\uB2F5 \uC2E4\uD328");
|
|
17187
17248
|
}
|
|
17188
17249
|
await settleSubagentFailure(queryId, classifyAgentError(error, agentKind));
|
|
17189
17250
|
try {
|
|
@@ -17238,6 +17299,8 @@ function triggerTopicAiTurn(topicId, userId, prompt, agentType, opts) {
|
|
|
17238
17299
|
text: prompt,
|
|
17239
17300
|
agentType: execution.agent,
|
|
17240
17301
|
model: execution.model,
|
|
17302
|
+
kind: opts?.injectKind,
|
|
17303
|
+
tellCard: opts?.injectTellCard,
|
|
17241
17304
|
createdAt: now
|
|
17242
17305
|
};
|
|
17243
17306
|
try {
|
|
@@ -19219,4 +19282,4 @@ export {
|
|
|
19219
19282
|
DEFAULT_SELF_CONFIG_PRODUCT
|
|
19220
19283
|
};
|
|
19221
19284
|
|
|
19222
|
-
//# debugId=
|
|
19285
|
+
//# debugId=693942027C41748764756E2164756E21
|