negotium 0.4.8 → 0.5.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 +10 -3
- package/dist/agent-helpers.js.map +5 -5
- package/dist/background-bash.js +2 -2
- package/dist/background-bash.js.map +2 -2
- package/dist/browser-runtime.js +2 -2
- package/dist/browser-runtime.js.map +2 -2
- package/dist/{chunk-y35zxjtx.js → chunk-0e3ygr6w.js} +2 -2
- package/dist/{chunk-y35zxjtx.js.map → chunk-0e3ygr6w.js.map} +2 -2
- package/dist/hosted-agent.js +3 -3
- package/dist/hosted-agent.js.map +3 -3
- package/dist/main.js +418 -111
- package/dist/main.js.map +15 -15
- package/dist/mcp-factories.js +10 -3
- package/dist/mcp-factories.js.map +5 -5
- package/dist/prompts.js +2 -2
- package/dist/prompts.js.map +2 -2
- package/dist/query-runtime.js +2 -2
- package/dist/query-runtime.js.map +2 -2
- package/dist/registry.js +3 -3
- package/dist/registry.js.map +2 -2
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/index.ts +3 -0
- package/dist/runtime/src/node-host.ts +2 -0
- package/dist/runtime/src/platform/config.ts +1 -1
- package/dist/runtime/src/storage/runtime-events.ts +69 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +2 -2
- package/dist/runtime-helpers.js.map +2 -2
- package/dist/types/packages/core/src/platform/config.d.ts +1 -1
- package/dist/types/packages/core/src/storage/runtime-events.d.ts +14 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +2 -2
- package/dist/vault.js.map +2 -2
- package/install-browser-rs.mjs +3 -3
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -273,7 +273,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
|
|
|
273
273
|
function codexAuthFilePath() {
|
|
274
274
|
return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
|
|
275
275
|
}
|
|
276
|
-
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.
|
|
276
|
+
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.23", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.7", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, DECISION_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
|
|
277
277
|
var init_config = __esm(() => {
|
|
278
278
|
init_config_helpers();
|
|
279
279
|
init_logger();
|
|
@@ -1868,7 +1868,7 @@ var exports_version = {};
|
|
|
1868
1868
|
__export(exports_version, {
|
|
1869
1869
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
1870
1870
|
});
|
|
1871
|
-
var NEGOTIUM_VERSION = "0.
|
|
1871
|
+
var NEGOTIUM_VERSION = "0.5.0";
|
|
1872
1872
|
|
|
1873
1873
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
1874
1874
|
import { spawn } from "child_process";
|
|
@@ -6962,6 +6962,10 @@ function latestRuntimeEventSeq() {
|
|
|
6962
6962
|
const row = db.query("SELECT MAX(seq) AS seq FROM runtime_events").get();
|
|
6963
6963
|
return Number(row?.seq ?? 0);
|
|
6964
6964
|
}
|
|
6965
|
+
function earliestRuntimeEventSeq() {
|
|
6966
|
+
const row = db.query("SELECT MIN(seq) AS seq FROM runtime_events").get();
|
|
6967
|
+
return Number(row?.seq ?? 0);
|
|
6968
|
+
}
|
|
6965
6969
|
function appendRuntimeEvent(sourceId, event) {
|
|
6966
6970
|
const createdAt = new Date().toISOString();
|
|
6967
6971
|
const result = db.query(`INSERT INTO runtime_events
|
|
@@ -6978,6 +6982,30 @@ function listRuntimeEventsAfter(seq, limit = 500) {
|
|
|
6978
6982
|
LIMIT ?`).all(Math.max(0, seq), Math.max(1, Math.min(limit, 5000)));
|
|
6979
6983
|
return rows.map(rowToEvent).filter((event) => event !== null);
|
|
6980
6984
|
}
|
|
6985
|
+
function heartbeatRuntimeEventConsumer(consumerId, cursor, now = Date.now()) {
|
|
6986
|
+
db.query(`INSERT INTO runtime_event_consumers (consumer_id, cursor, heartbeat_at)
|
|
6987
|
+
VALUES (?, ?, ?)
|
|
6988
|
+
ON CONFLICT(consumer_id) DO UPDATE SET
|
|
6989
|
+
cursor = MAX(runtime_event_consumers.cursor, excluded.cursor),
|
|
6990
|
+
heartbeat_at = excluded.heartbeat_at`).run(consumerId, Math.max(0, cursor), now);
|
|
6991
|
+
}
|
|
6992
|
+
function pruneRuntimeEvents(options = {}) {
|
|
6993
|
+
const maxEvents = Math.max(1, Math.floor(options.maxEvents ?? 1e5));
|
|
6994
|
+
const now = options.now ?? Date.now();
|
|
6995
|
+
const activeAfter = now - Math.max(1000, options.activeConsumerMaxAgeMs ?? 5 * 60000);
|
|
6996
|
+
db.query("DELETE FROM runtime_event_consumers WHERE heartbeat_at < ?").run(activeAfter);
|
|
6997
|
+
const boundary = db.query("SELECT seq FROM runtime_events ORDER BY seq DESC LIMIT 1 OFFSET ?").get(maxEvents - 1);
|
|
6998
|
+
if (!boundary)
|
|
6999
|
+
return { deleted: 0, cutoff: 0, retainedForConsumer: null };
|
|
7000
|
+
const targetCutoff = Math.max(0, Number(boundary.seq) - 1);
|
|
7001
|
+
const consumer = db.query("SELECT MIN(cursor) AS cursor FROM runtime_event_consumers").get();
|
|
7002
|
+
const retainedForConsumer = consumer?.cursor == null ? null : Number(consumer.cursor);
|
|
7003
|
+
const cutoff = Math.min(targetCutoff, retainedForConsumer ?? targetCutoff);
|
|
7004
|
+
if (cutoff <= 0)
|
|
7005
|
+
return { deleted: 0, cutoff, retainedForConsumer };
|
|
7006
|
+
const result = db.query("DELETE FROM runtime_events WHERE seq <= ?").run(cutoff);
|
|
7007
|
+
return { deleted: Number(result.changes), cutoff, retainedForConsumer };
|
|
7008
|
+
}
|
|
6981
7009
|
function listRecentRuntimeEventsForTopic(topicId, limit = 300) {
|
|
6982
7010
|
const rows = db.query(`SELECT seq, source_id, event_type, topic_id, payload_json, created_at
|
|
6983
7011
|
FROM (
|
|
@@ -7021,6 +7049,13 @@ var init_runtime_events = __esm(async () => {
|
|
|
7021
7049
|
payload_json TEXT NOT NULL,
|
|
7022
7050
|
created_at TEXT NOT NULL
|
|
7023
7051
|
)
|
|
7052
|
+
`);
|
|
7053
|
+
database.exec(`
|
|
7054
|
+
CREATE TABLE IF NOT EXISTS runtime_event_consumers (
|
|
7055
|
+
consumer_id TEXT PRIMARY KEY,
|
|
7056
|
+
cursor INTEGER NOT NULL,
|
|
7057
|
+
heartbeat_at INTEGER NOT NULL
|
|
7058
|
+
)
|
|
7024
7059
|
`);
|
|
7025
7060
|
database.exec("CREATE INDEX IF NOT EXISTS idx_runtime_events_topic_seq ON runtime_events(topic_id, seq)");
|
|
7026
7061
|
});
|
|
@@ -23001,6 +23036,7 @@ __export(exports_src, {
|
|
|
23001
23036
|
reconcilePendingAskUserQuestionGates: () => reconcilePendingAskUserQuestionGates,
|
|
23002
23037
|
reapOrphanBrowsers: () => reapPlaywrightOrphans,
|
|
23003
23038
|
purgeTopicLogs: () => purgeTopicLogs,
|
|
23039
|
+
pruneRuntimeEvents: () => pruneRuntimeEvents,
|
|
23004
23040
|
prepareDeliveryAck: () => prepareDeliveryAck,
|
|
23005
23041
|
onShutdown: () => onShutdown,
|
|
23006
23042
|
normalizeVaultKey: () => normalizeVaultKey,
|
|
@@ -23040,6 +23076,7 @@ __export(exports_src, {
|
|
|
23040
23076
|
isAgentKind: () => isAgentKind,
|
|
23041
23077
|
interSessionQueue: () => interSessionQueue,
|
|
23042
23078
|
ingestAttachment: () => ingestAttachment,
|
|
23079
|
+
heartbeatRuntimeEventConsumer: () => heartbeatRuntimeEventConsumer,
|
|
23043
23080
|
grantSubagentTellTarget: () => grantSubagentTellTarget,
|
|
23044
23081
|
getVisibleTopics: () => getVisibleTopics,
|
|
23045
23082
|
getTopics: () => getTopics,
|
|
@@ -23074,6 +23111,7 @@ __export(exports_src, {
|
|
|
23074
23111
|
errMsg: () => errMsg,
|
|
23075
23112
|
ensurePersonalGeneral: () => ensurePersonalGeneral,
|
|
23076
23113
|
ensureBgBash: () => ensureBgBash,
|
|
23114
|
+
earliestRuntimeEventSeq: () => earliestRuntimeEventSeq,
|
|
23077
23115
|
dispatchPeerRuntimeVisual: () => dispatchPeerRuntimeVisual,
|
|
23078
23116
|
dispatchPeerRuntimeSpawn: () => dispatchPeerRuntimeSpawn,
|
|
23079
23117
|
dispatchPeerRuntimeSelfConfig: () => dispatchPeerRuntimeSelfConfig,
|
|
@@ -23572,6 +23610,7 @@ __export(exports_node_host, {
|
|
|
23572
23610
|
reconcilePendingAskUserQuestionGates: () => reconcilePendingAskUserQuestionGates,
|
|
23573
23611
|
reapOrphanBrowsers: () => reapPlaywrightOrphans,
|
|
23574
23612
|
readDecisions: () => readDecisions,
|
|
23613
|
+
pruneRuntimeEvents: () => pruneRuntimeEvents,
|
|
23575
23614
|
onShutdown: () => onShutdown,
|
|
23576
23615
|
nodeRequestHandlerNames: () => nodeRequestHandlerNames,
|
|
23577
23616
|
logger: () => logger,
|
|
@@ -23595,6 +23634,7 @@ __export(exports_node_host, {
|
|
|
23595
23634
|
flushBashrsCompletions: () => flushBashrsCompletions,
|
|
23596
23635
|
executeVaultCommand: () => executeVaultCommand,
|
|
23597
23636
|
ensurePersonalGeneral: () => ensurePersonalGeneral,
|
|
23637
|
+
earliestRuntimeEventSeq: () => earliestRuntimeEventSeq,
|
|
23598
23638
|
deleteVaultEntry: () => deleteVaultEntry,
|
|
23599
23639
|
compactTopicSession: () => compactTopicSession,
|
|
23600
23640
|
appendApiMessage: () => appendApiMessage,
|
|
@@ -29840,8 +29880,8 @@ function createPollingSseStream(req, options) {
|
|
|
29840
29880
|
} catch {}
|
|
29841
29881
|
};
|
|
29842
29882
|
const send = (event, data, id) => {
|
|
29843
|
-
if (closed)
|
|
29844
|
-
return;
|
|
29883
|
+
if (closed || controller.desiredSize !== null && controller.desiredSize <= 0)
|
|
29884
|
+
return false;
|
|
29845
29885
|
try {
|
|
29846
29886
|
const lines = [
|
|
29847
29887
|
id === undefined ? "" : `id: ${id}`,
|
|
@@ -29852,8 +29892,10 @@ function createPollingSseStream(req, options) {
|
|
|
29852
29892
|
controller.enqueue(encoder.encode(`${lines}
|
|
29853
29893
|
|
|
29854
29894
|
`));
|
|
29895
|
+
return true;
|
|
29855
29896
|
} catch (error2) {
|
|
29856
29897
|
fail(error2);
|
|
29898
|
+
return false;
|
|
29857
29899
|
}
|
|
29858
29900
|
};
|
|
29859
29901
|
const close = () => {
|
|
@@ -29896,7 +29938,7 @@ function createPollingSseStream(req, options) {
|
|
|
29896
29938
|
return;
|
|
29897
29939
|
pollTimer = setInterval(pump, options.pollIntervalMs ?? 100);
|
|
29898
29940
|
heartbeatTimer = setInterval(() => {
|
|
29899
|
-
if (closed)
|
|
29941
|
+
if (closed || controller.desiredSize !== null && controller.desiredSize <= 0)
|
|
29900
29942
|
return;
|
|
29901
29943
|
try {
|
|
29902
29944
|
controller.enqueue(encoder.encode(`: heartbeat ${Date.now()}
|
|
@@ -29910,7 +29952,7 @@ function createPollingSseStream(req, options) {
|
|
|
29910
29952
|
cancel() {
|
|
29911
29953
|
stop();
|
|
29912
29954
|
}
|
|
29913
|
-
});
|
|
29955
|
+
}, { highWaterMark: 64 });
|
|
29914
29956
|
return new Response(stream, {
|
|
29915
29957
|
headers: {
|
|
29916
29958
|
"cache-control": "no-cache, no-transform",
|
|
@@ -30018,7 +30060,6 @@ function runtimeEvent(event) {
|
|
|
30018
30060
|
}
|
|
30019
30061
|
function createRuntimeContractEventStream(req, after, topicId, scope = {}) {
|
|
30020
30062
|
const scoped = "surfaceScope" in scope;
|
|
30021
|
-
const wanted = scope.surfaceScope ?? null;
|
|
30022
30063
|
const visible = new Map;
|
|
30023
30064
|
const eventInScope = (eventTopicId) => {
|
|
30024
30065
|
if (!scoped)
|
|
@@ -30026,26 +30067,39 @@ function createRuntimeContractEventStream(req, after, topicId, scope = {}) {
|
|
|
30026
30067
|
const cached = visible.get(eventTopicId);
|
|
30027
30068
|
if (cached !== undefined)
|
|
30028
30069
|
return cached;
|
|
30029
|
-
const
|
|
30030
|
-
const allowed =
|
|
30070
|
+
const topic = getTopic(eventTopicId);
|
|
30071
|
+
const allowed = Boolean(topic && topicInRequestScope(req, topic));
|
|
30031
30072
|
visible.set(eventTopicId, allowed);
|
|
30032
30073
|
return allowed;
|
|
30033
30074
|
};
|
|
30034
30075
|
let cursor = Math.max(0, after);
|
|
30076
|
+
let reportedCursor = cursor;
|
|
30077
|
+
const oldestCursor = earliestRuntimeEventSeq();
|
|
30035
30078
|
return createPollingSseStream(req, {
|
|
30036
|
-
ready: {
|
|
30079
|
+
ready: {
|
|
30080
|
+
v: NODE_RUNTIME_CONTRACT_VERSION,
|
|
30081
|
+
cursor,
|
|
30082
|
+
oldestCursor,
|
|
30083
|
+
truncated: oldestCursor > 0 && cursor < oldestCursor - 1
|
|
30084
|
+
},
|
|
30037
30085
|
pump(send) {
|
|
30038
|
-
|
|
30086
|
+
for (let batch = 0;batch < 5; batch += 1) {
|
|
30039
30087
|
const events = listRuntimeEventsAfter(cursor, 500);
|
|
30040
|
-
if (events.length === 0)
|
|
30088
|
+
if (events.length === 0) {
|
|
30089
|
+
if (reportedCursor < cursor && send("cursor", { cursor }, cursor))
|
|
30090
|
+
reportedCursor = cursor;
|
|
30041
30091
|
break;
|
|
30092
|
+
}
|
|
30042
30093
|
for (const event of events) {
|
|
30043
|
-
cursor = event.seq;
|
|
30044
30094
|
if ((!topicId || event.topicId === topicId) && eventInScope(event.topicId)) {
|
|
30045
|
-
send("runtime", runtimeEvent(event), event.seq)
|
|
30095
|
+
if (!send("runtime", runtimeEvent(event), event.seq))
|
|
30096
|
+
return;
|
|
30046
30097
|
}
|
|
30098
|
+
cursor = event.seq;
|
|
30047
30099
|
}
|
|
30048
|
-
send("cursor", { cursor }, cursor)
|
|
30100
|
+
if (!send("cursor", { cursor }, cursor))
|
|
30101
|
+
return;
|
|
30102
|
+
reportedCursor = cursor;
|
|
30049
30103
|
if (events.length < 500)
|
|
30050
30104
|
break;
|
|
30051
30105
|
}
|
|
@@ -30055,15 +30109,24 @@ function createRuntimeContractEventStream(req, after, topicId, scope = {}) {
|
|
|
30055
30109
|
function createEventStream(req, userId, after, surface) {
|
|
30056
30110
|
const allowedTopics = new Set(topicsForUser(userId, surface).map((topic) => topic.id));
|
|
30057
30111
|
let cursor = Math.max(0, after);
|
|
30112
|
+
let reportedCursor = cursor;
|
|
30113
|
+
const oldestCursor = earliestRuntimeEventSeq();
|
|
30058
30114
|
return createPollingSseStream(req, {
|
|
30059
|
-
ready: {
|
|
30115
|
+
ready: {
|
|
30116
|
+
protocolVersion: NODE_CONTROL_PROTOCOL_VERSION,
|
|
30117
|
+
cursor,
|
|
30118
|
+
oldestCursor,
|
|
30119
|
+
truncated: oldestCursor > 0 && cursor < oldestCursor - 1
|
|
30120
|
+
},
|
|
30060
30121
|
pump(send) {
|
|
30061
|
-
|
|
30122
|
+
for (let batch = 0;batch < 5; batch += 1) {
|
|
30062
30123
|
const events = listRuntimeEventsAfter(cursor, 500);
|
|
30063
|
-
if (events.length === 0)
|
|
30124
|
+
if (events.length === 0) {
|
|
30125
|
+
if (reportedCursor < cursor && send("cursor", { cursor }, cursor))
|
|
30126
|
+
reportedCursor = cursor;
|
|
30064
30127
|
break;
|
|
30128
|
+
}
|
|
30065
30129
|
for (const event of events) {
|
|
30066
|
-
cursor = event.seq;
|
|
30067
30130
|
if (event.type === "topic-created" || event.type === "topic-updated") {
|
|
30068
30131
|
const topic = getTopic(event.topicId);
|
|
30069
30132
|
const admissible = topic && isParticipant(topic, userId) && (!surface || topic.surface === surface);
|
|
@@ -30073,12 +30136,15 @@ function createEventStream(req, userId, after, surface) {
|
|
|
30073
30136
|
allowedTopics.delete(event.topicId);
|
|
30074
30137
|
}
|
|
30075
30138
|
const visible = allowedTopics.has(event.topicId);
|
|
30076
|
-
if (visible)
|
|
30077
|
-
|
|
30139
|
+
if (visible && !send("runtime", runtimeEvent(event), event.seq))
|
|
30140
|
+
return;
|
|
30141
|
+
cursor = event.seq;
|
|
30078
30142
|
if (event.type === "topic-deleted")
|
|
30079
30143
|
allowedTopics.delete(event.topicId);
|
|
30080
30144
|
}
|
|
30081
|
-
send("cursor", { cursor }, cursor)
|
|
30145
|
+
if (!send("cursor", { cursor }, cursor))
|
|
30146
|
+
return;
|
|
30147
|
+
reportedCursor = cursor;
|
|
30082
30148
|
if (events.length < 500)
|
|
30083
30149
|
break;
|
|
30084
30150
|
}
|
|
@@ -32830,6 +32896,19 @@ function startNode(opts = {}) {
|
|
|
32830
32896
|
setRuntimeMcpPort(port);
|
|
32831
32897
|
const stopTurnRequests = startDurableTurnRequestWorker();
|
|
32832
32898
|
const stopInbox = startSessionInboxWorker();
|
|
32899
|
+
const pruneEventLog = () => {
|
|
32900
|
+
try {
|
|
32901
|
+
const result = pruneRuntimeEvents();
|
|
32902
|
+
if (result.deleted > 0) {
|
|
32903
|
+
logger.info(result, "runtime event log pruned");
|
|
32904
|
+
}
|
|
32905
|
+
} catch (err2) {
|
|
32906
|
+
logger.warn({ err: err2 }, "runtime event log prune failed");
|
|
32907
|
+
}
|
|
32908
|
+
};
|
|
32909
|
+
pruneEventLog();
|
|
32910
|
+
const eventPruneTimer = setInterval(pruneEventLog, 5 * 60000);
|
|
32911
|
+
eventPruneTimer.unref?.();
|
|
32833
32912
|
const stopBashrsCompletions = startBashrsCompletionsWorker();
|
|
32834
32913
|
let modules;
|
|
32835
32914
|
try {
|
|
@@ -32844,6 +32923,7 @@ function startNode(opts = {}) {
|
|
|
32844
32923
|
} catch (error2) {
|
|
32845
32924
|
stopTurnRequests();
|
|
32846
32925
|
stopInbox();
|
|
32926
|
+
clearInterval(eventPruneTimer);
|
|
32847
32927
|
stopBashrsCompletions();
|
|
32848
32928
|
server.stop(true);
|
|
32849
32929
|
processLease?.stop();
|
|
@@ -32870,6 +32950,7 @@ function startNode(opts = {}) {
|
|
|
32870
32950
|
});
|
|
32871
32951
|
stopTurnRequests();
|
|
32872
32952
|
stopInbox();
|
|
32953
|
+
clearInterval(eventPruneTimer);
|
|
32873
32954
|
stopBashrsCompletions();
|
|
32874
32955
|
server.stop(true);
|
|
32875
32956
|
processLease?.stop();
|
|
@@ -32882,6 +32963,7 @@ function startNode(opts = {}) {
|
|
|
32882
32963
|
onShutdown("node-server", 130, () => {
|
|
32883
32964
|
stopTurnRequests();
|
|
32884
32965
|
stopInbox();
|
|
32966
|
+
clearInterval(eventPruneTimer);
|
|
32885
32967
|
stopBashrsCompletions();
|
|
32886
32968
|
server.stop(true);
|
|
32887
32969
|
});
|
|
@@ -33130,13 +33212,60 @@ function compactDetail(decision) {
|
|
|
33130
33212
|
const rationale = decision.reasoning.replace(/\s+/g, " ").trim();
|
|
33131
33213
|
return `${rationale} \xB7 ${decision.agent}${decision.model ? `/${decision.model}` : ""}`;
|
|
33132
33214
|
}
|
|
33215
|
+
function chronologicalSequenceEdges(ordered) {
|
|
33216
|
+
const parent = new Map;
|
|
33217
|
+
for (const decision of ordered)
|
|
33218
|
+
parent.set(decision.id, decision.id);
|
|
33219
|
+
const find = (id) => {
|
|
33220
|
+
let root = id;
|
|
33221
|
+
while (parent.get(root) !== root) {
|
|
33222
|
+
const next = parent.get(root);
|
|
33223
|
+
if (next === undefined)
|
|
33224
|
+
break;
|
|
33225
|
+
root = next;
|
|
33226
|
+
}
|
|
33227
|
+
return root;
|
|
33228
|
+
};
|
|
33229
|
+
const union = (a, b) => {
|
|
33230
|
+
const rootA = find(a);
|
|
33231
|
+
const rootB = find(b);
|
|
33232
|
+
if (rootA !== rootB)
|
|
33233
|
+
parent.set(rootA, rootB);
|
|
33234
|
+
};
|
|
33235
|
+
for (const decision of ordered) {
|
|
33236
|
+
for (const upstream of decision.causedBy ?? []) {
|
|
33237
|
+
if (parent.has(upstream))
|
|
33238
|
+
union(upstream, decision.id);
|
|
33239
|
+
}
|
|
33240
|
+
}
|
|
33241
|
+
const edges = [];
|
|
33242
|
+
for (let index = 1;index < ordered.length; index += 1) {
|
|
33243
|
+
const previous = ordered[index - 1];
|
|
33244
|
+
const current3 = ordered[index];
|
|
33245
|
+
if (!previous || !current3)
|
|
33246
|
+
continue;
|
|
33247
|
+
if (find(previous.id) === find(current3.id))
|
|
33248
|
+
continue;
|
|
33249
|
+
union(previous.id, current3.id);
|
|
33250
|
+
edges.push({
|
|
33251
|
+
id: `sequence:${previous.id}:${current3.id}`,
|
|
33252
|
+
source: previous.id,
|
|
33253
|
+
target: current3.id,
|
|
33254
|
+
kind: "sequence",
|
|
33255
|
+
direction: "none",
|
|
33256
|
+
style: "dashed"
|
|
33257
|
+
});
|
|
33258
|
+
}
|
|
33259
|
+
return edges;
|
|
33260
|
+
}
|
|
33133
33261
|
function buildDecisionGraph(decisions2, topicTitle) {
|
|
33134
33262
|
const ids = new Set(decisions2.map((decision) => decision.id));
|
|
33263
|
+
const ordered = [...decisions2].sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0) || a.id.localeCompare(b.id));
|
|
33135
33264
|
return {
|
|
33136
33265
|
id: "decisions",
|
|
33137
33266
|
title: topicTitle,
|
|
33138
33267
|
direction: "DOWN",
|
|
33139
|
-
nodes:
|
|
33268
|
+
nodes: ordered.map((decision) => ({
|
|
33140
33269
|
id: decision.id,
|
|
33141
33270
|
label: `#${decision.id} ${decision.action}`,
|
|
33142
33271
|
detail: compactDetail(decision),
|
|
@@ -33144,15 +33273,17 @@ function buildDecisionGraph(decisions2, topicTitle) {
|
|
|
33144
33273
|
state: decisionNodeState(decision.status),
|
|
33145
33274
|
metadata: { timestamp: decision.timestamp, agent: decision.agent, model: decision.model }
|
|
33146
33275
|
})),
|
|
33147
|
-
edges:
|
|
33148
|
-
|
|
33149
|
-
|
|
33150
|
-
|
|
33151
|
-
|
|
33152
|
-
|
|
33153
|
-
|
|
33154
|
-
|
|
33155
|
-
|
|
33276
|
+
edges: [
|
|
33277
|
+
...ordered.flatMap((decision) => (decision.causedBy ?? []).filter((upstream) => ids.has(upstream)).map((upstream) => ({
|
|
33278
|
+
id: `caused:${upstream}:${decision.id}`,
|
|
33279
|
+
source: upstream,
|
|
33280
|
+
target: decision.id,
|
|
33281
|
+
kind: "caused",
|
|
33282
|
+
direction: "forward",
|
|
33283
|
+
style: "solid"
|
|
33284
|
+
}))),
|
|
33285
|
+
...chronologicalSequenceEdges(ordered)
|
|
33286
|
+
]
|
|
33156
33287
|
};
|
|
33157
33288
|
}
|
|
33158
33289
|
async function renderDecisionGraph(graph, spacing = DEFAULT_DECISION_GRAPH_SPACING, signal) {
|
|
@@ -33160,14 +33291,15 @@ async function renderDecisionGraph(graph, spacing = DEFAULT_DECISION_GRAPH_SPACI
|
|
|
33160
33291
|
direction: "DOWN",
|
|
33161
33292
|
spacing,
|
|
33162
33293
|
signal,
|
|
33163
|
-
timeoutMs: 15000
|
|
33294
|
+
timeoutMs: 15000,
|
|
33295
|
+
maxNodeWidth: DECISION_NODE_MAX_WIDTH
|
|
33164
33296
|
});
|
|
33165
33297
|
return {
|
|
33166
33298
|
canvas: { ...renderTerminalGraph(graph, geometry), title: graph.title },
|
|
33167
33299
|
svg: renderSvgGraph(graph, geometry, { title: graph.title })
|
|
33168
33300
|
};
|
|
33169
33301
|
}
|
|
33170
|
-
var DEFAULT_DECISION_GRAPH_SPACING = 4, MIN_DECISION_GRAPH_SPACING = 2, MAX_DECISION_GRAPH_SPACING = 10;
|
|
33302
|
+
var DEFAULT_DECISION_GRAPH_SPACING = 4, MIN_DECISION_GRAPH_SPACING = 2, MAX_DECISION_GRAPH_SPACING = 10, DECISION_NODE_MAX_WIDTH = 30;
|
|
33171
33303
|
var init_decision_graph = () => {};
|
|
33172
33304
|
|
|
33173
33305
|
// ../../adapters/terminal/src/subagent-graph.ts
|
|
@@ -35474,7 +35606,7 @@ function decisionGraphLines(state, width, height) {
|
|
|
35474
35606
|
bold: true
|
|
35475
35607
|
}),
|
|
35476
35608
|
line(` [/] spacing ${state.decisionGraphSpacing} \xB7 drag/wheel/arrows/hjkl move \xB7 Ctrl-D/Esc close${position}`, { fg: theme.muted }),
|
|
35477
|
-
line(" \u25CB accepted \xB7 \
|
|
35609
|
+
line(" \u25CB accepted \xB7 \u25CC proposed \xB7 \u2713 executed \xB7 \u2715 rejected \xB7 \u25C6 superseded", {
|
|
35478
35610
|
fg: theme.subtle
|
|
35479
35611
|
}),
|
|
35480
35612
|
line("")
|
|
@@ -40800,6 +40932,11 @@ function createTables(db4) {
|
|
|
40800
40932
|
key TEXT PRIMARY KEY,
|
|
40801
40933
|
value TEXT NOT NULL
|
|
40802
40934
|
)`);
|
|
40935
|
+
db4.run(`CREATE TABLE IF NOT EXISTS runtime_inbox (
|
|
40936
|
+
seq INTEGER PRIMARY KEY,
|
|
40937
|
+
runtime_message_id TEXT,
|
|
40938
|
+
event_json TEXT NOT NULL
|
|
40939
|
+
)`);
|
|
40803
40940
|
}
|
|
40804
40941
|
function migrateOutboxSchema(db4) {
|
|
40805
40942
|
try {
|
|
@@ -40810,6 +40947,13 @@ function migrateOutboxSchema(db4) {
|
|
|
40810
40947
|
} catch {}
|
|
40811
40948
|
db4.run("CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)");
|
|
40812
40949
|
}
|
|
40950
|
+
function migrateRuntimeInboxSchema(db4) {
|
|
40951
|
+
try {
|
|
40952
|
+
db4.run("ALTER TABLE runtime_inbox ADD COLUMN runtime_message_id TEXT");
|
|
40953
|
+
} catch {}
|
|
40954
|
+
db4.run(`CREATE UNIQUE INDEX IF NOT EXISTS idx_telegram_runtime_inbox_message
|
|
40955
|
+
ON runtime_inbox(runtime_message_id) WHERE runtime_message_id IS NOT NULL`);
|
|
40956
|
+
}
|
|
40813
40957
|
function openMappingStore(path) {
|
|
40814
40958
|
const dbPath = path ?? join45(DATA_DIR, "adapter-telegram.db");
|
|
40815
40959
|
if (dbPath !== ":memory:")
|
|
@@ -40818,6 +40962,7 @@ function openMappingStore(path) {
|
|
|
40818
40962
|
migrateLegacySchema(db4);
|
|
40819
40963
|
createTables(db4);
|
|
40820
40964
|
migrateOutboxSchema(db4);
|
|
40965
|
+
migrateRuntimeInboxSchema(db4);
|
|
40821
40966
|
return {
|
|
40822
40967
|
load() {
|
|
40823
40968
|
const rows = db4.query("SELECT chat_id, thread_id, topic_id FROM mappings").all();
|
|
@@ -40891,6 +41036,40 @@ function openMappingStore(path) {
|
|
|
40891
41036
|
entry.lastError ?? null
|
|
40892
41037
|
]);
|
|
40893
41038
|
},
|
|
41039
|
+
runtimeEventCursor() {
|
|
41040
|
+
const row = db4.query("SELECT value FROM settings WHERE key = 'runtime_event_cursor'").get();
|
|
41041
|
+
if (!row)
|
|
41042
|
+
return;
|
|
41043
|
+
const value = Number.parseInt(row.value, 10);
|
|
41044
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
41045
|
+
},
|
|
41046
|
+
captureRuntimeEvent(event) {
|
|
41047
|
+
const messageId = event.payload && typeof event.payload === "object" && "id" in event.payload && typeof event.payload.id === "string" ? event.payload.id : null;
|
|
41048
|
+
db4.transaction(() => {
|
|
41049
|
+
db4.run(`INSERT OR IGNORE INTO runtime_inbox (seq, runtime_message_id, event_json)
|
|
41050
|
+
VALUES (?, ?, ?)`, [event.seq, messageId, JSON.stringify(event)]);
|
|
41051
|
+
db4.run(`INSERT INTO settings (key, value) VALUES ('runtime_event_cursor', ?)
|
|
41052
|
+
ON CONFLICT(key) DO UPDATE SET value = MAX(CAST(value AS INTEGER), CAST(excluded.value AS INTEGER))`, [String(event.seq)]);
|
|
41053
|
+
})();
|
|
41054
|
+
},
|
|
41055
|
+
advanceRuntimeEventCursor(seq) {
|
|
41056
|
+
db4.run(`INSERT INTO settings (key, value) VALUES ('runtime_event_cursor', ?)
|
|
41057
|
+
ON CONFLICT(key) DO UPDATE SET value = MAX(CAST(value AS INTEGER), CAST(excluded.value AS INTEGER))`, [String(seq)]);
|
|
41058
|
+
},
|
|
41059
|
+
pendingRuntimeEvents() {
|
|
41060
|
+
const rows = db4.query("SELECT seq, event_json FROM runtime_inbox ORDER BY seq ASC").all();
|
|
41061
|
+
return rows.flatMap((row) => {
|
|
41062
|
+
try {
|
|
41063
|
+
return [{ seq: row.seq, event: JSON.parse(row.event_json) }];
|
|
41064
|
+
} catch {
|
|
41065
|
+
db4.run("DELETE FROM runtime_inbox WHERE seq = ?", [row.seq]);
|
|
41066
|
+
return [];
|
|
41067
|
+
}
|
|
41068
|
+
});
|
|
41069
|
+
},
|
|
41070
|
+
acknowledgeRuntimeEvent(seq) {
|
|
41071
|
+
db4.run("DELETE FROM runtime_inbox WHERE seq = ?", [seq]);
|
|
41072
|
+
},
|
|
40894
41073
|
outboxDue(now) {
|
|
40895
41074
|
const rows = db4.query("SELECT * FROM outbox WHERE dead = 0 AND next_try_at <= ? ORDER BY id ASC").all(now);
|
|
40896
41075
|
return rows.map(outboxRowToEntry);
|
|
@@ -41768,15 +41947,29 @@ function startTelegramAdapter(opts) {
|
|
|
41768
41947
|
}
|
|
41769
41948
|
const sendQueues = new Map;
|
|
41770
41949
|
function enqueueSend(topicId, task) {
|
|
41771
|
-
const prev = sendQueues.get(topicId) ?? Promise.resolve();
|
|
41950
|
+
const prev = sendQueues.get(topicId) ?? Promise.resolve(true);
|
|
41772
41951
|
const next = prev.then(() => new Promise((resolve24) => {
|
|
41952
|
+
let settled = false;
|
|
41773
41953
|
const timer = setTimeout(() => {
|
|
41954
|
+
if (settled)
|
|
41955
|
+
return;
|
|
41956
|
+
settled = true;
|
|
41774
41957
|
logger.warn({ topicId, sendTimeoutMs }, "telegram adapter: send timed out \u2014 abandoning it and continuing the queue");
|
|
41775
|
-
resolve24();
|
|
41958
|
+
resolve24(false);
|
|
41776
41959
|
}, sendTimeoutMs);
|
|
41777
|
-
task().
|
|
41960
|
+
task().then(() => {
|
|
41961
|
+
if (settled)
|
|
41962
|
+
return;
|
|
41963
|
+
settled = true;
|
|
41778
41964
|
clearTimeout(timer);
|
|
41779
|
-
resolve24();
|
|
41965
|
+
resolve24(true);
|
|
41966
|
+
}).catch((err2) => {
|
|
41967
|
+
logger.warn({ err: err2, topicId }, "telegram adapter: send task failed");
|
|
41968
|
+
if (settled)
|
|
41969
|
+
return;
|
|
41970
|
+
settled = true;
|
|
41971
|
+
clearTimeout(timer);
|
|
41972
|
+
resolve24(false);
|
|
41780
41973
|
});
|
|
41781
41974
|
}));
|
|
41782
41975
|
sendQueues.set(topicId, next);
|
|
@@ -41784,13 +41977,14 @@ function startTelegramAdapter(opts) {
|
|
|
41784
41977
|
if (sendQueues.get(topicId) === next)
|
|
41785
41978
|
sendQueues.delete(topicId);
|
|
41786
41979
|
});
|
|
41980
|
+
return next;
|
|
41787
41981
|
}
|
|
41788
41982
|
function enqueueFanout(topicId, mappings, payload) {
|
|
41789
41983
|
const targets = [...mappings];
|
|
41790
|
-
enqueueSend(topicId, () => deliverToTargets(topicId, targets, payload));
|
|
41984
|
+
enqueueSend(topicId, () => deliverToTargets(topicId, targets, payload)).then(payload.onSettled);
|
|
41791
41985
|
}
|
|
41792
41986
|
function enqueueTarget(topicId, target, payload) {
|
|
41793
|
-
enqueueSend(topicId, () => deliverToTargets(topicId, [target], payload));
|
|
41987
|
+
enqueueSend(topicId, () => deliverToTargets(topicId, [target], payload)).then(payload.onSettled);
|
|
41794
41988
|
}
|
|
41795
41989
|
const pendingByTopic = new Map;
|
|
41796
41990
|
const permissionBlockedTopics = new Map;
|
|
@@ -41808,8 +42002,9 @@ function startTelegramAdapter(opts) {
|
|
|
41808
42002
|
});
|
|
41809
42003
|
}
|
|
41810
42004
|
function flushBuffered(topicId, buffer, send) {
|
|
41811
|
-
for (const payload of buffer)
|
|
41812
|
-
enqueueSend(topicId, () => send(payload));
|
|
42005
|
+
for (const payload of buffer) {
|
|
42006
|
+
enqueueSend(topicId, () => send(payload)).then(payload.onSettled);
|
|
42007
|
+
}
|
|
41813
42008
|
}
|
|
41814
42009
|
function materializeTopic(topic) {
|
|
41815
42010
|
if (!forumManageTopicsAvailable || suppressMaterialize > 0 || byTopic.has(topic.id) || pendingByTopic.has(topic.id) || permissionBlockedTopics.has(topic.id) || materializeTombstones.has(topic.id)) {
|
|
@@ -41871,8 +42066,12 @@ function startTelegramAdapter(opts) {
|
|
|
41871
42066
|
if (materializeTombstones.delete(topicId))
|
|
41872
42067
|
store.deleteTombstone(topicId);
|
|
41873
42068
|
const pending2 = pendingByTopic.get(topicId);
|
|
41874
|
-
if (pending2)
|
|
42069
|
+
if (pending2) {
|
|
41875
42070
|
pending2.cancelled = true;
|
|
42071
|
+
for (const payload of pending2.buffer)
|
|
42072
|
+
payload.onSettled?.(true);
|
|
42073
|
+
pending2.buffer = [];
|
|
42074
|
+
}
|
|
41876
42075
|
for (const [messageId, message] of runtimeMessages) {
|
|
41877
42076
|
if (message.topicId === topicId)
|
|
41878
42077
|
deleteDeliveredRuntimeMessage(topicId, messageId);
|
|
@@ -41919,7 +42118,7 @@ function startTelegramAdapter(opts) {
|
|
|
41919
42118
|
}
|
|
41920
42119
|
const tombstoneTitle = materializeTombstones.get(topicId);
|
|
41921
42120
|
if (tombstoneTitle !== undefined) {
|
|
41922
|
-
enqueueSend(topicId, () => deliverFallback(topicId, tombstoneTitle, payload));
|
|
42121
|
+
enqueueSend(topicId, () => deliverFallback(topicId, tombstoneTitle, payload)).then(payload.onSettled);
|
|
41923
42122
|
return true;
|
|
41924
42123
|
}
|
|
41925
42124
|
const topic = getTopic(topicId);
|
|
@@ -41927,7 +42126,7 @@ function startTelegramAdapter(opts) {
|
|
|
41927
42126
|
return false;
|
|
41928
42127
|
if (forumMode) {
|
|
41929
42128
|
if (!forumManageTopicsAvailable || permissionBlockedTopics.has(topicId)) {
|
|
41930
|
-
enqueueSend(topicId, () => deliverFallback(topicId, topic.title, payload));
|
|
42129
|
+
enqueueSend(topicId, () => deliverFallback(topicId, topic.title, payload)).then(payload.onSettled);
|
|
41931
42130
|
return true;
|
|
41932
42131
|
}
|
|
41933
42132
|
if (!materializeTopic(topic))
|
|
@@ -42375,6 +42574,113 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42375
42574
|
}
|
|
42376
42575
|
linkForumAndAnnounce(update.from.id, update.chat, update.new_chat_member).catch((err2) => logger.warn({ err: err2, groupId: update.chat.id }, "telegram adapter: forum auto-connect failed"));
|
|
42377
42576
|
});
|
|
42577
|
+
async function deliverPersistedRuntimeMessage(event) {
|
|
42578
|
+
const msg = event.payload;
|
|
42579
|
+
if (msg.authorId === userId && msg.sourceAdapter === "telegram")
|
|
42580
|
+
return true;
|
|
42581
|
+
if (msg.kind === "tool")
|
|
42582
|
+
return true;
|
|
42583
|
+
const hasAttachments = Boolean(msg.attachments && msg.attachments.length > 0);
|
|
42584
|
+
if (!msg.text && !hasAttachments)
|
|
42585
|
+
return true;
|
|
42586
|
+
const runtimeMessageId = msg.authorId === "ai" ? msg.id : undefined;
|
|
42587
|
+
if (runtimeMessageId) {
|
|
42588
|
+
runtimeMessages.set(runtimeMessageId, msg);
|
|
42589
|
+
if (!msg.queryId) {
|
|
42590
|
+
const timer = setTimeout(() => {
|
|
42591
|
+
runtimeMessages.delete(runtimeMessageId);
|
|
42592
|
+
deliveredByRuntimeMessageId.delete(runtimeMessageId);
|
|
42593
|
+
}, 5 * 60000);
|
|
42594
|
+
timer.unref?.();
|
|
42595
|
+
}
|
|
42596
|
+
}
|
|
42597
|
+
const tagFiles = msg.text ? extractFileTagPaths(msg.text).map((path) => ({ path, filename: basename12(path) })) : [];
|
|
42598
|
+
const attachmentFiles = hasAttachments ? (msg.attachments ?? []).map((attachment) => {
|
|
42599
|
+
const path = resolveUploadedFilePathByFileId(attachment.id);
|
|
42600
|
+
if (!path)
|
|
42601
|
+
return null;
|
|
42602
|
+
return {
|
|
42603
|
+
path,
|
|
42604
|
+
filename: basename12(attachment.filename) || basename12(path),
|
|
42605
|
+
...attachment.mimeType ? { mimeType: attachment.mimeType } : {}
|
|
42606
|
+
};
|
|
42607
|
+
}).filter((file) => file !== null) : [];
|
|
42608
|
+
const files = [...tagFiles, ...attachmentFiles];
|
|
42609
|
+
const rawText = tagFiles.length > 0 && msg.text ? stripFileTags(msg.text) : msg.text ?? "";
|
|
42610
|
+
const text2 = msg.authorId === userId && rawText ? `[From: User] ${rawText}` : rawText;
|
|
42611
|
+
if (!text2 && files.length === 0)
|
|
42612
|
+
return true;
|
|
42613
|
+
let settle;
|
|
42614
|
+
const settled = new Promise((resolve24) => {
|
|
42615
|
+
settle = resolve24;
|
|
42616
|
+
});
|
|
42617
|
+
const payload = {
|
|
42618
|
+
text: text2,
|
|
42619
|
+
files,
|
|
42620
|
+
runtimeMessageId,
|
|
42621
|
+
deliveryAckRequested: msg.deliveryAckRequested === true,
|
|
42622
|
+
onSettled: settle
|
|
42623
|
+
};
|
|
42624
|
+
const routed = routeMessage(event.topicId, payload, msg.queryId);
|
|
42625
|
+
if (routed && payload.deliveryAckRequested)
|
|
42626
|
+
claimDeliveryAck(event.topicId, msg.id);
|
|
42627
|
+
return routed ? settled : true;
|
|
42628
|
+
}
|
|
42629
|
+
const savedRuntimeEventCursor = store.runtimeEventCursor();
|
|
42630
|
+
let runtimeEventCursor = savedRuntimeEventCursor ?? latestRuntimeEventSeq();
|
|
42631
|
+
if (savedRuntimeEventCursor === undefined) {
|
|
42632
|
+
store.advanceRuntimeEventCursor(runtimeEventCursor);
|
|
42633
|
+
}
|
|
42634
|
+
const runtimeEventConsumerId = `telegram:${userId}:${opts.mappingDbPath ?? "default"}`;
|
|
42635
|
+
heartbeatRuntimeEventConsumer(runtimeEventConsumerId, runtimeEventCursor);
|
|
42636
|
+
let pollingRuntimeEvents = false;
|
|
42637
|
+
let drainingRuntimeInbox = false;
|
|
42638
|
+
const drainRuntimeInbox = async () => {
|
|
42639
|
+
if (drainingRuntimeInbox || stopped)
|
|
42640
|
+
return;
|
|
42641
|
+
drainingRuntimeInbox = true;
|
|
42642
|
+
try {
|
|
42643
|
+
while (!stopped) {
|
|
42644
|
+
const pending2 = store.pendingRuntimeEvents()[0];
|
|
42645
|
+
if (!pending2)
|
|
42646
|
+
break;
|
|
42647
|
+
const delivered = await deliverPersistedRuntimeMessage(pending2.event);
|
|
42648
|
+
if (!delivered || stopped)
|
|
42649
|
+
break;
|
|
42650
|
+
store.acknowledgeRuntimeEvent(pending2.seq);
|
|
42651
|
+
}
|
|
42652
|
+
} catch (err2) {
|
|
42653
|
+
if (!stopped)
|
|
42654
|
+
logger.warn({ err: err2 }, "telegram adapter: durable runtime inbox drain failed");
|
|
42655
|
+
} finally {
|
|
42656
|
+
drainingRuntimeInbox = false;
|
|
42657
|
+
}
|
|
42658
|
+
};
|
|
42659
|
+
const pollRuntimeEvents = () => {
|
|
42660
|
+
if (pollingRuntimeEvents || stopped)
|
|
42661
|
+
return;
|
|
42662
|
+
pollingRuntimeEvents = true;
|
|
42663
|
+
try {
|
|
42664
|
+
for (let batch = 0;batch < 5; batch += 1) {
|
|
42665
|
+
const events = listRuntimeEventsAfter(runtimeEventCursor, 500);
|
|
42666
|
+
if (events.length === 0)
|
|
42667
|
+
break;
|
|
42668
|
+
for (const event of events) {
|
|
42669
|
+
if (event.type === "message")
|
|
42670
|
+
store.captureRuntimeEvent({ ...event, seq: event.seq });
|
|
42671
|
+
else
|
|
42672
|
+
store.advanceRuntimeEventCursor(event.seq);
|
|
42673
|
+
runtimeEventCursor = event.seq;
|
|
42674
|
+
}
|
|
42675
|
+
if (events.length < 500)
|
|
42676
|
+
break;
|
|
42677
|
+
}
|
|
42678
|
+
drainRuntimeInbox();
|
|
42679
|
+
heartbeatRuntimeEventConsumer(runtimeEventConsumerId, runtimeEventCursor);
|
|
42680
|
+
} finally {
|
|
42681
|
+
pollingRuntimeEvents = false;
|
|
42682
|
+
}
|
|
42683
|
+
};
|
|
42378
42684
|
const unsubscribe = runtimeBus().subscribe((event) => {
|
|
42379
42685
|
if (stopped)
|
|
42380
42686
|
return;
|
|
@@ -42387,22 +42693,22 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42387
42693
|
return;
|
|
42388
42694
|
}
|
|
42389
42695
|
if (event.type === "message-updated") {
|
|
42390
|
-
const
|
|
42391
|
-
if (!
|
|
42696
|
+
const payload = event.payload;
|
|
42697
|
+
if (!payload.messageId || !payload.patch)
|
|
42392
42698
|
return;
|
|
42393
|
-
if (
|
|
42394
|
-
deleteDeliveredRuntimeMessage(event.topicId,
|
|
42699
|
+
if (payload.patch.deleted) {
|
|
42700
|
+
deleteDeliveredRuntimeMessage(event.topicId, payload.messageId);
|
|
42395
42701
|
return;
|
|
42396
42702
|
}
|
|
42397
|
-
const current3 = runtimeMessages.get(
|
|
42703
|
+
const current3 = runtimeMessages.get(payload.messageId);
|
|
42398
42704
|
if (!current3)
|
|
42399
42705
|
return;
|
|
42400
|
-
const updated = { ...current3, ...
|
|
42401
|
-
runtimeMessages.set(
|
|
42402
|
-
if (footerEnabled &&
|
|
42706
|
+
const updated = { ...current3, ...payload.patch };
|
|
42707
|
+
runtimeMessages.set(payload.messageId, updated);
|
|
42708
|
+
if (footerEnabled && payload.patch.usage && updated.authorId === "ai") {
|
|
42403
42709
|
const footer = renderTurnFooter(updated);
|
|
42404
42710
|
if (footer)
|
|
42405
|
-
attachUpdatedFooter(event.topicId,
|
|
42711
|
+
attachUpdatedFooter(event.topicId, payload.messageId, footer);
|
|
42406
42712
|
}
|
|
42407
42713
|
return;
|
|
42408
42714
|
}
|
|
@@ -42425,53 +42731,10 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42425
42731
|
}
|
|
42426
42732
|
return;
|
|
42427
42733
|
}
|
|
42428
|
-
if (event.type !== "message")
|
|
42429
|
-
return;
|
|
42430
|
-
const msg = event.payload;
|
|
42431
|
-
if (msg.authorId === userId && msg.sourceAdapter === "telegram")
|
|
42432
|
-
return;
|
|
42433
|
-
if (msg.kind === "tool")
|
|
42434
|
-
return;
|
|
42435
|
-
const hasAttachments = Boolean(msg.attachments && msg.attachments.length > 0);
|
|
42436
|
-
if (!msg.text && !hasAttachments)
|
|
42437
|
-
return;
|
|
42438
|
-
const runtimeMessageId = msg.authorId === "ai" ? msg.id : undefined;
|
|
42439
|
-
if (runtimeMessageId) {
|
|
42440
|
-
runtimeMessages.set(runtimeMessageId, msg);
|
|
42441
|
-
if (!msg.queryId) {
|
|
42442
|
-
const timer = setTimeout(() => {
|
|
42443
|
-
runtimeMessages.delete(runtimeMessageId);
|
|
42444
|
-
deliveredByRuntimeMessageId.delete(runtimeMessageId);
|
|
42445
|
-
}, 5 * 60000);
|
|
42446
|
-
timer.unref?.();
|
|
42447
|
-
}
|
|
42448
|
-
}
|
|
42449
|
-
const tagFiles = msg.text ? extractFileTagPaths(msg.text).map((path) => ({ path, filename: basename12(path) })) : [];
|
|
42450
|
-
const attachmentFiles = hasAttachments ? (msg.attachments ?? []).map((attachment) => {
|
|
42451
|
-
const path = resolveUploadedFilePathByFileId(attachment.id);
|
|
42452
|
-
if (!path)
|
|
42453
|
-
return null;
|
|
42454
|
-
return {
|
|
42455
|
-
path,
|
|
42456
|
-
filename: basename12(attachment.filename) || basename12(path),
|
|
42457
|
-
...attachment.mimeType ? { mimeType: attachment.mimeType } : {}
|
|
42458
|
-
};
|
|
42459
|
-
}).filter((file) => file !== null) : [];
|
|
42460
|
-
const files = [...tagFiles, ...attachmentFiles];
|
|
42461
|
-
const rawText = tagFiles.length > 0 && msg.text ? stripFileTags(msg.text) : msg.text ?? "";
|
|
42462
|
-
const text2 = msg.authorId === userId && rawText ? `[From: User] ${rawText}` : rawText;
|
|
42463
|
-
if (!text2 && files.length === 0)
|
|
42464
|
-
return;
|
|
42465
|
-
const payload = {
|
|
42466
|
-
text: text2,
|
|
42467
|
-
files,
|
|
42468
|
-
runtimeMessageId,
|
|
42469
|
-
deliveryAckRequested: msg.deliveryAckRequested === true
|
|
42470
|
-
};
|
|
42471
|
-
if (routeMessage(event.topicId, payload, msg.queryId) && payload.deliveryAckRequested) {
|
|
42472
|
-
claimDeliveryAck(event.topicId, msg.id);
|
|
42473
|
-
}
|
|
42474
42734
|
});
|
|
42735
|
+
pollRuntimeEvents();
|
|
42736
|
+
const runtimeEventPollTimer = setInterval(pollRuntimeEvents, 100);
|
|
42737
|
+
runtimeEventPollTimer.unref?.();
|
|
42475
42738
|
if (forumMode) {
|
|
42476
42739
|
bindMapping(forumChat, undefined, personalGeneral.id);
|
|
42477
42740
|
materializeVisibleTopics();
|
|
@@ -42491,6 +42754,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42491
42754
|
for (const queryId of toolStatusByQueryId.keys())
|
|
42492
42755
|
closeToolStatus(queryId);
|
|
42493
42756
|
mediaIntake.stop();
|
|
42757
|
+
clearInterval(runtimeEventPollTimer);
|
|
42494
42758
|
unsubscribe();
|
|
42495
42759
|
store.close();
|
|
42496
42760
|
}
|
|
@@ -44802,8 +45066,18 @@ class TunnelClient {
|
|
|
44802
45066
|
this.bridgedSockets.clear();
|
|
44803
45067
|
}
|
|
44804
45068
|
send(frame) {
|
|
44805
|
-
|
|
44806
|
-
|
|
45069
|
+
const ws = this.ws;
|
|
45070
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
45071
|
+
return;
|
|
45072
|
+
if (Number(ws.bufferedAmount ?? 0) > MAX_TUNNEL_BUFFERED_AMOUNT) {
|
|
45073
|
+
this.disconnectActiveConnection(ws, this.connectionGeneration, { reason: "relay outbound buffer limit exceeded" }, true);
|
|
45074
|
+
return;
|
|
45075
|
+
}
|
|
45076
|
+
try {
|
|
45077
|
+
ws.send(encodeFrame(frame));
|
|
45078
|
+
} catch {
|
|
45079
|
+
this.disconnectActiveConnection(ws, this.connectionGeneration, { reason: "relay send failed" }, true);
|
|
45080
|
+
}
|
|
44807
45081
|
}
|
|
44808
45082
|
handleFrame(frame) {
|
|
44809
45083
|
switch (frame.type) {
|
|
@@ -44838,11 +45112,23 @@ class TunnelClient {
|
|
|
44838
45112
|
break;
|
|
44839
45113
|
case "http_req_chunk": {
|
|
44840
45114
|
const pending2 = this.pendingHttp.get(frame.id);
|
|
45115
|
+
if (!pending2)
|
|
45116
|
+
break;
|
|
44841
45117
|
try {
|
|
44842
|
-
pending2
|
|
44843
|
-
|
|
44844
|
-
|
|
44845
|
-
|
|
45118
|
+
if (!pending2.body)
|
|
45119
|
+
throw new Error("body chunk received for bodyless request");
|
|
45120
|
+
const chunk = fromB64(frame.dataB64);
|
|
45121
|
+
pending2.receivedBytes += chunk.byteLength;
|
|
45122
|
+
if (pending2.receivedBytes > MAX_HTTP_REQUEST_BODY_BYTES) {
|
|
45123
|
+
throw new Error("relay HTTP request body limit exceeded");
|
|
45124
|
+
}
|
|
45125
|
+
pending2.bodyController?.enqueue(chunk);
|
|
45126
|
+
this.startPendingHttp(frame.id, pending2);
|
|
45127
|
+
} catch {
|
|
45128
|
+
pending2.abort.abort();
|
|
45129
|
+
this.pendingHttp.delete(frame.id);
|
|
45130
|
+
throw new Error("invalid or oversized relay HTTP request body");
|
|
45131
|
+
}
|
|
44846
45132
|
break;
|
|
44847
45133
|
}
|
|
44848
45134
|
case "http_req_end": {
|
|
@@ -44873,6 +45159,12 @@ class TunnelClient {
|
|
|
44873
45159
|
if (!bridged)
|
|
44874
45160
|
break;
|
|
44875
45161
|
if (!bridged.opened) {
|
|
45162
|
+
bridged.bufferedBytes += frame.text === undefined ? Math.floor((frame.dataB64 ?? "").length * 3 / 4) : Buffer.byteLength(frame.text, "utf8");
|
|
45163
|
+
if (bridged.bufferedBytes > MAX_PREOPEN_WEBSOCKET_BYTES) {
|
|
45164
|
+
this.bridgedSockets.delete(frame.id);
|
|
45165
|
+
bridged.ws.close(1009, "pre-open buffer limit exceeded");
|
|
45166
|
+
throw new Error("bridged WebSocket pre-open buffer limit exceeded");
|
|
45167
|
+
}
|
|
44876
45168
|
bridged.buffer.push(frame);
|
|
44877
45169
|
break;
|
|
44878
45170
|
}
|
|
@@ -44892,6 +45184,11 @@ class TunnelClient {
|
|
|
44892
45184
|
}
|
|
44893
45185
|
}
|
|
44894
45186
|
startHttpRequest(frame) {
|
|
45187
|
+
if (this.pendingHttp.has(frame.id))
|
|
45188
|
+
throw new Error("duplicate relay HTTP request id");
|
|
45189
|
+
if (this.pendingHttp.size >= MAX_IN_FLIGHT_HTTP_REQUESTS) {
|
|
45190
|
+
throw new Error("too many in-flight relay HTTP requests");
|
|
45191
|
+
}
|
|
44895
45192
|
const abort = new AbortController;
|
|
44896
45193
|
const headers = new Headers;
|
|
44897
45194
|
for (const [name, value] of frame.headers)
|
|
@@ -44903,7 +45200,8 @@ class TunnelClient {
|
|
|
44903
45200
|
method: frame.method,
|
|
44904
45201
|
path: frame.path,
|
|
44905
45202
|
headers,
|
|
44906
|
-
started: false
|
|
45203
|
+
started: false,
|
|
45204
|
+
receivedBytes: 0
|
|
44907
45205
|
};
|
|
44908
45206
|
if (frame.hasBody) {
|
|
44909
45207
|
pending2.body = new ReadableStream({
|
|
@@ -44964,6 +45262,11 @@ class TunnelClient {
|
|
|
44964
45262
|
}
|
|
44965
45263
|
}
|
|
44966
45264
|
openBridgedSocket(id, path, headers) {
|
|
45265
|
+
if (this.bridgedSockets.has(id))
|
|
45266
|
+
throw new Error("duplicate bridged WebSocket id");
|
|
45267
|
+
if (this.bridgedSockets.size >= MAX_BRIDGED_SOCKETS) {
|
|
45268
|
+
throw new Error("too many bridged WebSockets");
|
|
45269
|
+
}
|
|
44967
45270
|
const wsOrigin = this.opts.targetOrigin.replace(/^http/, "ws");
|
|
44968
45271
|
let local;
|
|
44969
45272
|
try {
|
|
@@ -44980,7 +45283,7 @@ class TunnelClient {
|
|
|
44980
45283
|
});
|
|
44981
45284
|
return;
|
|
44982
45285
|
}
|
|
44983
|
-
const bridged = { ws: local, opened: false, buffer: [] };
|
|
45286
|
+
const bridged = { ws: local, opened: false, buffer: [], bufferedBytes: 0 };
|
|
44984
45287
|
this.bridgedSockets.set(id, bridged);
|
|
44985
45288
|
local.onopen = () => {
|
|
44986
45289
|
bridged.opened = true;
|
|
@@ -44988,6 +45291,7 @@ class TunnelClient {
|
|
|
44988
45291
|
for (const frame of bridged.buffer)
|
|
44989
45292
|
this.deliverToLocal(local, frame);
|
|
44990
45293
|
bridged.buffer = [];
|
|
45294
|
+
bridged.bufferedBytes = 0;
|
|
44991
45295
|
};
|
|
44992
45296
|
local.onmessage = (event) => {
|
|
44993
45297
|
if (typeof event.data === "string") {
|
|
@@ -45019,11 +45323,14 @@ class TunnelClient {
|
|
|
45019
45323
|
local.send(fromB64(frame.dataB64));
|
|
45020
45324
|
}
|
|
45021
45325
|
}
|
|
45022
|
-
var MAX_WS_UPGRADE_HEADER_BYTES, WS_PROTOCOL_TOKEN, DEFAULT_MIN_RECONNECT_MS = 1000, DEFAULT_MAX_RECONNECT_MS = 30000, RECONNECT_JITTER_RATIO = 0.2, LIVENESS_INTERVALS = 3, noop = () => {}, silentLogger;
|
|
45326
|
+
var MAX_WS_UPGRADE_HEADER_BYTES, WS_PROTOCOL_TOKEN, DEFAULT_MIN_RECONNECT_MS = 1000, DEFAULT_MAX_RECONNECT_MS = 30000, MAX_IN_FLIGHT_HTTP_REQUESTS = 128, MAX_BRIDGED_SOCKETS = 128, MAX_HTTP_REQUEST_BODY_BYTES, MAX_PREOPEN_WEBSOCKET_BYTES, MAX_TUNNEL_BUFFERED_AMOUNT, RECONNECT_JITTER_RATIO = 0.2, LIVENESS_INTERVALS = 3, noop = () => {}, silentLogger;
|
|
45023
45327
|
var init_tunnel_client = __esm(() => {
|
|
45024
45328
|
init_relay_protocol();
|
|
45025
45329
|
MAX_WS_UPGRADE_HEADER_BYTES = 32 * 1024;
|
|
45026
45330
|
WS_PROTOCOL_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
45331
|
+
MAX_HTTP_REQUEST_BODY_BYTES = 16 * 1024 * 1024;
|
|
45332
|
+
MAX_PREOPEN_WEBSOCKET_BYTES = 1024 * 1024;
|
|
45333
|
+
MAX_TUNNEL_BUFFERED_AMOUNT = 8 * 1024 * 1024;
|
|
45027
45334
|
silentLogger = { info: noop, warn: noop, error: noop };
|
|
45028
45335
|
});
|
|
45029
45336
|
|
|
@@ -47332,4 +47639,4 @@ switch (command) {
|
|
|
47332
47639
|
}
|
|
47333
47640
|
}
|
|
47334
47641
|
|
|
47335
|
-
//# debugId=
|
|
47642
|
+
//# debugId=A120DD1C769C1B1164756E2164756E21
|