negotium 0.21.2 → 0.22.0
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 +52 -6
- package/dist/agent-helpers.js.map +7 -7
- package/dist/background-bash.js.map +1 -1
- package/dist/browser-runtime.js.map +1 -1
- package/dist/{chunk-z3qhxy33.js → chunk-bbwa785m.js} +2 -2
- package/dist/{chunk-z3qhxy33.js.map → chunk-bbwa785m.js.map} +2 -2
- package/dist/chunk-pvp197f1.js.map +1 -1
- package/dist/chunk-zjz52hzq.js.map +1 -1
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +2 -2
- package/dist/main.js +137 -41
- package/dist/main.js.map +12 -12
- package/dist/mcp-factories.js +52 -6
- package/dist/mcp-factories.js.map +7 -7
- package/dist/media.js.map +1 -1
- package/dist/prompts.js.map +1 -1
- package/dist/query-runtime.js +14 -2
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +1 -1
- package/dist/runtime/src/mcp/session-comm/server.ts +2 -2
- package/dist/runtime/src/query/active-rooms.ts +22 -2
- package/dist/runtime/src/runtime/inbox.ts +74 -41
- package/dist/runtime/src/runtime/turn-runner.ts +4 -2
- package/dist/runtime/src/storage/token-stats.ts +62 -1
- package/dist/runtime/src/types.ts +6 -1
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js.map +1 -1
- package/dist/storage.js +36 -2
- package/dist/storage.js.map +4 -4
- package/dist/types/packages/core/src/query/active-rooms.d.ts +8 -2
- package/dist/types/packages/core/src/storage/token-stats.d.ts +9 -0
- package/dist/types/packages/core/src/types.d.ts +6 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js.map +1 -1
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -6520,7 +6520,7 @@ var exports_version = {};
|
|
|
6520
6520
|
__export(exports_version, {
|
|
6521
6521
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
6522
6522
|
});
|
|
6523
|
-
var NEGOTIUM_VERSION = "0.
|
|
6523
|
+
var NEGOTIUM_VERSION = "0.22.0";
|
|
6524
6524
|
|
|
6525
6525
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
6526
6526
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -13748,8 +13748,20 @@ class InterSessionQueue {
|
|
|
13748
13748
|
keysForRoom() {
|
|
13749
13749
|
return Array.from(this.queue.keys());
|
|
13750
13750
|
}
|
|
13751
|
-
drop(topicId) {
|
|
13751
|
+
drop(topicId, reason = "target session was stopped before the request ran") {
|
|
13752
|
+
const bucket = this.queue.get(topicId);
|
|
13752
13753
|
this.queue.delete(topicId);
|
|
13754
|
+
if (!bucket)
|
|
13755
|
+
return 0;
|
|
13756
|
+
const dropped = bucket.items.slice(bucket.head);
|
|
13757
|
+
for (const inject of dropped) {
|
|
13758
|
+
try {
|
|
13759
|
+
inject.onSettled?.({ queryId: "", kind: "error", error: reason });
|
|
13760
|
+
} catch (err) {
|
|
13761
|
+
logger.warn({ err, topicId, requestId: inject.requestId }, "session inject drop settlement hook failed");
|
|
13762
|
+
}
|
|
13763
|
+
}
|
|
13764
|
+
return dropped.length;
|
|
13753
13765
|
}
|
|
13754
13766
|
size(topicId) {
|
|
13755
13767
|
const bucket = this.queue.get(topicId);
|
|
@@ -15574,6 +15586,30 @@ function isQueryRecord(value) {
|
|
|
15574
15586
|
const record = value;
|
|
15575
15587
|
return record.schemaVersion === 2 && typeof record.timestamp === "string" && typeof record.session === "string" && typeof record.topicId === "string" && typeof record.agent === "string" && typeof record.model === "string" && typeof record.inputTokens === "number" && typeof record.outputTokens === "number" && typeof record.cacheCreationInputTokens === "number" && typeof record.cacheReadInputTokens === "number" && typeof record.estimatedCostUsd === "number";
|
|
15576
15588
|
}
|
|
15589
|
+
function previousCumulativeCost(userId, providerSessionId) {
|
|
15590
|
+
let lines;
|
|
15591
|
+
try {
|
|
15592
|
+
lines = readJsonlLines(queriesPath(userId));
|
|
15593
|
+
} catch {
|
|
15594
|
+
return 0;
|
|
15595
|
+
}
|
|
15596
|
+
for (let i = lines.length - 1;i >= 0; i--) {
|
|
15597
|
+
let parsed;
|
|
15598
|
+
try {
|
|
15599
|
+
parsed = JSON.parse(lines[i]);
|
|
15600
|
+
} catch {
|
|
15601
|
+
continue;
|
|
15602
|
+
}
|
|
15603
|
+
if (parsed.providerSessionId !== providerSessionId)
|
|
15604
|
+
continue;
|
|
15605
|
+
if (typeof parsed.cumulativeCostUsd === "number")
|
|
15606
|
+
return parsed.cumulativeCostUsd;
|
|
15607
|
+
if (typeof parsed.estimatedCostUsd === "number")
|
|
15608
|
+
return parsed.estimatedCostUsd;
|
|
15609
|
+
return 0;
|
|
15610
|
+
}
|
|
15611
|
+
return 0;
|
|
15612
|
+
}
|
|
15577
15613
|
function recordUsage(userId, session, usage, context) {
|
|
15578
15614
|
const cacheReadInputTokens = usage.cacheReadInputTokens ?? 0;
|
|
15579
15615
|
const inputTokens = context.agent === "claude" ? usage.inputTokens : Math.max(0, usage.inputTokens - cacheReadInputTokens);
|
|
@@ -15583,6 +15619,15 @@ function recordUsage(userId, session, usage, context) {
|
|
|
15583
15619
|
cacheCreationInputTokens: usage.cacheCreationInputTokens ?? 0,
|
|
15584
15620
|
cacheReadInputTokens
|
|
15585
15621
|
};
|
|
15622
|
+
let estimatedCostUsd;
|
|
15623
|
+
let cumulativeCostUsd;
|
|
15624
|
+
if (usage.costUsd !== undefined) {
|
|
15625
|
+
const previous = context.providerSessionId ? previousCumulativeCost(userId, context.providerSessionId) : 0;
|
|
15626
|
+
estimatedCostUsd = Math.max(0, usage.costUsd - previous);
|
|
15627
|
+
cumulativeCostUsd = usage.costUsd;
|
|
15628
|
+
} else {
|
|
15629
|
+
estimatedCostUsd = estimateUsageCost(context.agent, context.model, normalized);
|
|
15630
|
+
}
|
|
15586
15631
|
const record = {
|
|
15587
15632
|
schemaVersion: 2,
|
|
15588
15633
|
timestamp: new Date().toISOString(),
|
|
@@ -15594,7 +15639,8 @@ function recordUsage(userId, session, usage, context) {
|
|
|
15594
15639
|
...normalized,
|
|
15595
15640
|
...usage.contextTokens !== undefined ? { contextTokens: usage.contextTokens } : {},
|
|
15596
15641
|
...usage.contextWindow !== undefined ? { contextWindow: usage.contextWindow } : {},
|
|
15597
|
-
estimatedCostUsd
|
|
15642
|
+
estimatedCostUsd,
|
|
15643
|
+
...cumulativeCostUsd !== undefined ? { cumulativeCostUsd } : {}
|
|
15598
15644
|
};
|
|
15599
15645
|
try {
|
|
15600
15646
|
appendJsonlEntry(queriesPath(userId), record);
|
|
@@ -23436,9 +23482,8 @@ function startAiTurn(params) {
|
|
|
23436
23482
|
contextWindow: outcome.usage.contextWindow
|
|
23437
23483
|
} : undefined, { agent: agentKind, model: resolvedModel, budgetReason: outcome.reason });
|
|
23438
23484
|
WsHub.get().broadcastTopicNotice(topicId, "warning", "\uC608\uC0B0 \uD55C\uB3C4 \uB3C4\uB2EC");
|
|
23439
|
-
} else {
|
|
23440
|
-
await deliverAskError(queryId, topic.title, error);
|
|
23441
23485
|
}
|
|
23486
|
+
await deliverAskError(queryId, topic.title, error);
|
|
23442
23487
|
await settleSubagentFailure(queryId, error);
|
|
23443
23488
|
try {
|
|
23444
23489
|
onSettled?.({ queryId, kind: "error", error });
|
|
@@ -23483,6 +23528,7 @@ function startAiTurn(params) {
|
|
|
23483
23528
|
WsHub.get().broadcastError(topicId, queryId, error);
|
|
23484
23529
|
WsHub.get().broadcastTopicNotice(topicId, "error", "\uC751\uB2F5 \uC2E4\uD328");
|
|
23485
23530
|
}
|
|
23531
|
+
await deliverAskError(queryId, topic.title, error);
|
|
23486
23532
|
await settleSubagentFailure(queryId, classifyAgentError(error, agentKind));
|
|
23487
23533
|
try {
|
|
23488
23534
|
onSettled?.({
|
|
@@ -27512,6 +27558,9 @@ function normalizeAskTarget(target) {
|
|
|
27512
27558
|
return "main";
|
|
27513
27559
|
return target === "cron" ? "cron" : null;
|
|
27514
27560
|
}
|
|
27561
|
+
function askRunsOnTargetSession(target) {
|
|
27562
|
+
return target === "main";
|
|
27563
|
+
}
|
|
27515
27564
|
async function createAskForkPlan(options) {
|
|
27516
27565
|
const snapshot = structuredClone(options.entries);
|
|
27517
27566
|
const prepareSession = options.prepareSession ?? (async () => options.synthesize(structuredClone(snapshot)));
|
|
@@ -28113,6 +28162,59 @@ ${entry.message}
|
|
|
28113
28162
|
}
|
|
28114
28163
|
return;
|
|
28115
28164
|
}
|
|
28165
|
+
const onSettled = (result) => {
|
|
28166
|
+
if (result.queryId || result.kind !== "error")
|
|
28167
|
+
return;
|
|
28168
|
+
clearPendingAskForEntry(scope, entry, topicName, "target-unavailable-before-dispatch");
|
|
28169
|
+
const message2 = `(error: ${result.error ?? "target topic became unavailable before dispatch"})`;
|
|
28170
|
+
if (remoteReply) {
|
|
28171
|
+
deliverPeerReply(remoteReply, targetLabel, message2, "error");
|
|
28172
|
+
} else {
|
|
28173
|
+
notifyAskDrop(scope, entry, targetLabel, message2);
|
|
28174
|
+
}
|
|
28175
|
+
};
|
|
28176
|
+
const onDispatched = (queryId) => {
|
|
28177
|
+
registerAskCallback2({
|
|
28178
|
+
requestId,
|
|
28179
|
+
contextId: entry.contextId,
|
|
28180
|
+
callerTopicId,
|
|
28181
|
+
...entry.fromThreadRootId ? { callerThreadRootId: entry.fromThreadRootId } : {},
|
|
28182
|
+
callerUserId: String(scope.userId),
|
|
28183
|
+
targetQueryId: queryId,
|
|
28184
|
+
createdAt: Date.now(),
|
|
28185
|
+
...remoteReply ? { remoteReply } : {
|
|
28186
|
+
pendingAsk: {
|
|
28187
|
+
userId: scope.userId,
|
|
28188
|
+
from: entry.from,
|
|
28189
|
+
to: topicName,
|
|
28190
|
+
requestId
|
|
28191
|
+
}
|
|
28192
|
+
},
|
|
28193
|
+
sourceLabel: targetLabel
|
|
28194
|
+
});
|
|
28195
|
+
};
|
|
28196
|
+
if (askRunsOnTargetSession(askTarget)) {
|
|
28197
|
+
triggerTopicAiTurn2(topic.id, String(scope.userId), prompt, agentOverride, {
|
|
28198
|
+
origin: entry.from,
|
|
28199
|
+
requestId,
|
|
28200
|
+
contextId: entry.contextId,
|
|
28201
|
+
depth: (entry.fromDepth ?? 0) + 1,
|
|
28202
|
+
from: fromLabel,
|
|
28203
|
+
injectAuthorId: "system",
|
|
28204
|
+
injectSourceAdapter: "session-comm",
|
|
28205
|
+
injectKind: "tell",
|
|
28206
|
+
injectTellCard: {
|
|
28207
|
+
fromLabel,
|
|
28208
|
+
fromTopicId: entry.fromTopicId,
|
|
28209
|
+
label: `Ask from ${fromLabel}`,
|
|
28210
|
+
message: entry.message
|
|
28211
|
+
},
|
|
28212
|
+
onSettled,
|
|
28213
|
+
onDispatched
|
|
28214
|
+
});
|
|
28215
|
+
logger.info({ topicName, from: entry.from, requestId, callerTopicId, agent: agentOverride }, "session-inbox: ask delivered to target session");
|
|
28216
|
+
return;
|
|
28217
|
+
}
|
|
28116
28218
|
const forkNative = parentSessionId ? () => forkAgentSession2({
|
|
28117
28219
|
agent: agentOverride,
|
|
28118
28220
|
parentSessionId,
|
|
@@ -28200,36 +28302,8 @@ ${entry.message}
|
|
|
28200
28302
|
forkHandle: forkPlan.forkHandle,
|
|
28201
28303
|
prepareSession: forkPlan.prepareSession,
|
|
28202
28304
|
cwd,
|
|
28203
|
-
onSettled
|
|
28204
|
-
|
|
28205
|
-
return;
|
|
28206
|
-
clearPendingAskForEntry(scope, entry, topicName, "target-unavailable-before-dispatch");
|
|
28207
|
-
if (remoteReply) {
|
|
28208
|
-
deliverPeerReply(remoteReply, targetLabel, `(error: target topic became unavailable before dispatch)`, "error");
|
|
28209
|
-
} else {
|
|
28210
|
-
notifyAskDrop(scope, entry, targetLabel, `(error: target topic became unavailable before dispatch)`);
|
|
28211
|
-
}
|
|
28212
|
-
},
|
|
28213
|
-
onDispatched: (queryId) => {
|
|
28214
|
-
registerAskCallback2({
|
|
28215
|
-
requestId,
|
|
28216
|
-
contextId: entry.contextId,
|
|
28217
|
-
callerTopicId,
|
|
28218
|
-
...entry.fromThreadRootId ? { callerThreadRootId: entry.fromThreadRootId } : {},
|
|
28219
|
-
callerUserId: String(scope.userId),
|
|
28220
|
-
targetQueryId: queryId,
|
|
28221
|
-
createdAt: Date.now(),
|
|
28222
|
-
...remoteReply ? { remoteReply } : {
|
|
28223
|
-
pendingAsk: {
|
|
28224
|
-
userId: scope.userId,
|
|
28225
|
-
from: entry.from,
|
|
28226
|
-
to: topicName,
|
|
28227
|
-
requestId
|
|
28228
|
-
}
|
|
28229
|
-
},
|
|
28230
|
-
sourceLabel: targetLabel
|
|
28231
|
-
});
|
|
28232
|
-
}
|
|
28305
|
+
onSettled,
|
|
28306
|
+
onDispatched
|
|
28233
28307
|
});
|
|
28234
28308
|
logger.info({ topicName, from: entry.from, requestId, callerTopicId }, "session-inbox: ask delivered");
|
|
28235
28309
|
}
|
|
@@ -29924,6 +29998,10 @@ function callerSurface(ctx) {
|
|
|
29924
29998
|
function callerSurfaceScope(ctx) {
|
|
29925
29999
|
return getTopic(ctx.topicId)?.surfaceScope ?? null;
|
|
29926
30000
|
}
|
|
30001
|
+
function isTelegramDmGeneral(ctx) {
|
|
30002
|
+
const topic = getTopic(ctx.topicId);
|
|
30003
|
+
return topic?.surface === "telegram" && topic.kind === "manager" && !(topic.surfaceScope ?? null);
|
|
30004
|
+
}
|
|
29927
30005
|
function resolvableTopicsForCaller(ctx) {
|
|
29928
30006
|
const surface = callerSurface(ctx);
|
|
29929
30007
|
if (surface !== "otium") {
|
|
@@ -30004,11 +30082,15 @@ function registerNodeTools(server, ctx) {
|
|
|
30004
30082
|
description: z6.string().optional().describe("Short description of the topic's purpose."),
|
|
30005
30083
|
memory_key: z6.string().optional().describe("Wiki memory persona the room continues.")
|
|
30006
30084
|
}, async ({ title, agent, model, effort, description, memory_key }) => {
|
|
30085
|
+
if (isTelegramDmGeneral(ctx)) {
|
|
30086
|
+
return errorResult("Error: topics can't be created from the Telegram DM. Topic management lives in " + "a connected forum group \u2014 ask the user to send /start to connect one, then " + "create the topic from that group's General.");
|
|
30087
|
+
}
|
|
30007
30088
|
try {
|
|
30008
30089
|
const topic = registerTopic({
|
|
30009
30090
|
title,
|
|
30010
30091
|
userId: ctx.userId,
|
|
30011
30092
|
surface: callerSurface(ctx),
|
|
30093
|
+
surfaceScope: callerSurfaceScope(ctx),
|
|
30012
30094
|
agent,
|
|
30013
30095
|
model,
|
|
30014
30096
|
effort,
|
|
@@ -43759,7 +43841,7 @@ function footerUsageText(state) {
|
|
|
43759
43841
|
const ratio = contextUsage?.context !== undefined && contextUsage.contextWindow ? Math.round(contextUsage.context / contextUsage.contextWindow * 100) : undefined;
|
|
43760
43842
|
const context = contextUsage?.context !== undefined && contextUsage.contextWindow ? `${contextUsage.estimated ? "~" : ""}${tokenCount(contextUsage.context)}/${tokenCount(contextUsage.contextWindow)} ${ratio}%` : "";
|
|
43761
43843
|
const hasTopicUsage = total !== undefined && total.queries > 0;
|
|
43762
|
-
const cumulative = hasTopicUsage ? `\u03A3 ${tokenCount(total.inputTokens)}
|
|
43844
|
+
const cumulative = hasTopicUsage ? `\u03A3 ${tokenCount(total.inputTokens)} fresh/${tokenCount(total.outputTokens)} out` : "";
|
|
43763
43845
|
const cache = hasTopicUsage && total.cacheReadInputTokens ? `cache ${tokenCount(total.cacheReadInputTokens)}` : "";
|
|
43764
43846
|
const cost = hasTopicUsage ? `est $${total.estimatedCostUsd.toFixed(2)}` : "";
|
|
43765
43847
|
const variant = (values2) => {
|
|
@@ -48590,7 +48672,7 @@ function resolveTelegramTopicArg(argument, userId, surfaceScope) {
|
|
|
48590
48672
|
}
|
|
48591
48673
|
function createTelegramCommandRouter(context) {
|
|
48592
48674
|
const { userId, reply, currentTopicId, bindMapping, loadTopic, unloadTopic, abortTurn } = context;
|
|
48593
|
-
return async function handleCommand(text3, chatId, threadId, telegramUserId) {
|
|
48675
|
+
return async function handleCommand(text3, chatId, threadId, telegramUserId, isPrivateDm = false) {
|
|
48594
48676
|
const [rawCommand = ""] = text3.split(/\s+/);
|
|
48595
48677
|
const addressedUsername = rawCommand.match(/@(\w+)$/)?.[1];
|
|
48596
48678
|
if (addressedUsername) {
|
|
@@ -48608,6 +48690,20 @@ function createTelegramCommandRouter(context) {
|
|
|
48608
48690
|
}
|
|
48609
48691
|
const command = rawCommand.replace(/@\w+$/, "");
|
|
48610
48692
|
const argument = extractCommandArg(text3);
|
|
48693
|
+
const DM_RESTRICTED_COMMANDS = new Set([
|
|
48694
|
+
"/topics",
|
|
48695
|
+
"/load",
|
|
48696
|
+
"/unload",
|
|
48697
|
+
"/agent",
|
|
48698
|
+
"/fork",
|
|
48699
|
+
"/spawn",
|
|
48700
|
+
"/del",
|
|
48701
|
+
"/del!"
|
|
48702
|
+
]);
|
|
48703
|
+
if (isPrivateDm && (DM_RESTRICTED_COMMANDS.has(command) || command === "/new" && argument)) {
|
|
48704
|
+
reply(chatId, threadId, "topic management lives in a connected forum group, not this DM \u2014 " + "send /start to see how to connect one.");
|
|
48705
|
+
return;
|
|
48706
|
+
}
|
|
48611
48707
|
switch (command) {
|
|
48612
48708
|
case "/start":
|
|
48613
48709
|
await context.sendOnboardingGuide(chatId, threadId);
|
|
@@ -48751,7 +48847,7 @@ function createTelegramCommandRouter(context) {
|
|
|
48751
48847
|
return;
|
|
48752
48848
|
}
|
|
48753
48849
|
default:
|
|
48754
|
-
reply(chatId, threadId, "commands: /new [name], /topics, /agent <claude|codex|maestro>, " + "/load <topic>, /unload, /fork [name], /spawn [name], " + "/del [name], /del! [name], /abort, /vault <list|set|del>");
|
|
48850
|
+
reply(chatId, threadId, isPrivateDm ? "commands: /new, /abort, /vault <list|set|del> \u2014 topic management " + "(/topics, /load, /fork, /spawn, /del, /agent) lives in a connected " + "forum group; send /start to connect one" : "commands: /new [name], /topics, /agent <claude|codex|maestro>, " + "/load <topic>, /unload, /fork [name], /spawn [name], " + "/del [name], /del! [name], /abort, /vault <list|set|del>");
|
|
48755
48851
|
}
|
|
48756
48852
|
};
|
|
48757
48853
|
}
|
|
@@ -50672,9 +50768,9 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
50672
50768
|
if (text3?.startsWith("/")) {
|
|
50673
50769
|
const command = text3.split(/\s+/, 1)[0]?.replace(/@\w+$/, "");
|
|
50674
50770
|
if (command === "/abort") {
|
|
50675
|
-
handleCommand(text3, chatId, threadId, msg.from?.id);
|
|
50771
|
+
handleCommand(text3, chatId, threadId, msg.from?.id, privateDm);
|
|
50676
50772
|
} else {
|
|
50677
|
-
mediaIntake.enqueue(chatId, threadId, () => handleCommand(text3, chatId, threadId, msg.from?.id));
|
|
50773
|
+
mediaIntake.enqueue(chatId, threadId, () => handleCommand(text3, chatId, threadId, msg.from?.id, privateDm));
|
|
50678
50774
|
}
|
|
50679
50775
|
return;
|
|
50680
50776
|
}
|
|
@@ -58187,4 +58283,4 @@ switch (command) {
|
|
|
58187
58283
|
}
|
|
58188
58284
|
}
|
|
58189
58285
|
|
|
58190
|
-
//# debugId=
|
|
58286
|
+
//# debugId=205630437F8D066064756E2164756E21
|