negotium 0.4.6 → 0.4.9
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 -10
- package/dist/agent-helpers.js.map +6 -6
- package/dist/background-bash.js +1 -2
- package/dist/background-bash.js.map +3 -3
- package/dist/browser-runtime.js +1 -2
- package/dist/browser-runtime.js.map +3 -3
- package/dist/{chunk-bzbxgbgg.js → chunk-y35zxjtx.js} +1 -8
- package/dist/{chunk-bzbxgbgg.js.map → chunk-y35zxjtx.js.map} +4 -4
- package/dist/hosted-agent.js +2 -9
- package/dist/hosted-agent.js.map +5 -5
- package/dist/main.js +355 -105
- package/dist/main.js.map +14 -14
- package/dist/mcp-factories.js +10 -10
- package/dist/mcp-factories.js.map +6 -6
- package/dist/prompts.js +1 -2
- package/dist/prompts.js.map +3 -3
- package/dist/query-runtime.js +1 -2
- package/dist/query-runtime.js.map +3 -3
- 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 +0 -4
- package/dist/runtime/src/platform/mcp-config.ts +0 -10
- package/dist/runtime/src/storage/runtime-events.ts +69 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +1 -2
- package/dist/runtime-helpers.js.map +3 -3
- package/dist/types/packages/core/src/platform/config.d.ts +0 -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 +1 -2
- package/dist/vault.js.map +3 -3
- package/package.json +2 -2
- package/dist/runtime/src/mcp/browser-sse-proxy-server.ts +0 -48
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.22", 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,
|
|
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.22", 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();
|
|
@@ -304,7 +304,6 @@ var init_config = __esm(() => {
|
|
|
304
304
|
SESSION_COMM_SERVER = resolve(PROJECT_ROOT, "src/mcp/session-comm/server.ts");
|
|
305
305
|
TASK_SERVER = resolve(PROJECT_ROOT, "src/mcp/task-server.ts");
|
|
306
306
|
DECISION_SERVER = resolve(PROJECT_ROOT, "src/mcp/decision-server.ts");
|
|
307
|
-
BROWSER_MCP_SSE_PROXY_SERVER = resolve(PROJECT_ROOT, "src/mcp/browser-sse-proxy-server.ts");
|
|
308
307
|
CANONICAL_MCP_PROXY_SERVER = resolve(PROJECT_ROOT, "src/mcp/canonical-proxy-server.ts");
|
|
309
308
|
WIKI_SERVER = resolve(PROJECT_ROOT, "src/mcp/wiki-server.ts");
|
|
310
309
|
TOKEN_STATS_SERVER = resolve(PROJECT_ROOT, "src/mcp/token-stats-server.ts");
|
|
@@ -1869,7 +1868,7 @@ var exports_version = {};
|
|
|
1869
1868
|
__export(exports_version, {
|
|
1870
1869
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
1871
1870
|
});
|
|
1872
|
-
var NEGOTIUM_VERSION = "0.4.
|
|
1871
|
+
var NEGOTIUM_VERSION = "0.4.9";
|
|
1873
1872
|
|
|
1874
1873
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
1875
1874
|
import { spawn } from "child_process";
|
|
@@ -2755,12 +2754,6 @@ function playwrightTransport(port, owner, capability, agent) {
|
|
|
2755
2754
|
};
|
|
2756
2755
|
}
|
|
2757
2756
|
const query = new URLSearchParams({ owner });
|
|
2758
|
-
if (agent === "maestro") {
|
|
2759
|
-
return buildStdioMcpServer("maestro", BROWSER_MCP_SSE_PROXY_SERVER, [], {
|
|
2760
|
-
NEGOTIUM_BROWSER_SSE_URL: `http://127.0.0.1:${port}/sse?${query}`,
|
|
2761
|
-
NEGOTIUM_BROWSER_OWNER_CAPABILITY: ownerCapability
|
|
2762
|
-
});
|
|
2763
|
-
}
|
|
2764
2757
|
return {
|
|
2765
2758
|
type: "sse",
|
|
2766
2759
|
url: `http://127.0.0.1:${port}/sse?${query}`,
|
|
@@ -6969,6 +6962,10 @@ function latestRuntimeEventSeq() {
|
|
|
6969
6962
|
const row = db.query("SELECT MAX(seq) AS seq FROM runtime_events").get();
|
|
6970
6963
|
return Number(row?.seq ?? 0);
|
|
6971
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
|
+
}
|
|
6972
6969
|
function appendRuntimeEvent(sourceId, event) {
|
|
6973
6970
|
const createdAt = new Date().toISOString();
|
|
6974
6971
|
const result = db.query(`INSERT INTO runtime_events
|
|
@@ -6985,6 +6982,30 @@ function listRuntimeEventsAfter(seq, limit = 500) {
|
|
|
6985
6982
|
LIMIT ?`).all(Math.max(0, seq), Math.max(1, Math.min(limit, 5000)));
|
|
6986
6983
|
return rows.map(rowToEvent).filter((event) => event !== null);
|
|
6987
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
|
+
}
|
|
6988
7009
|
function listRecentRuntimeEventsForTopic(topicId, limit = 300) {
|
|
6989
7010
|
const rows = db.query(`SELECT seq, source_id, event_type, topic_id, payload_json, created_at
|
|
6990
7011
|
FROM (
|
|
@@ -7028,6 +7049,13 @@ var init_runtime_events = __esm(async () => {
|
|
|
7028
7049
|
payload_json TEXT NOT NULL,
|
|
7029
7050
|
created_at TEXT NOT NULL
|
|
7030
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
|
+
)
|
|
7031
7059
|
`);
|
|
7032
7060
|
database.exec("CREATE INDEX IF NOT EXISTS idx_runtime_events_topic_seq ON runtime_events(topic_id, seq)");
|
|
7033
7061
|
});
|
|
@@ -23008,6 +23036,7 @@ __export(exports_src, {
|
|
|
23008
23036
|
reconcilePendingAskUserQuestionGates: () => reconcilePendingAskUserQuestionGates,
|
|
23009
23037
|
reapOrphanBrowsers: () => reapPlaywrightOrphans,
|
|
23010
23038
|
purgeTopicLogs: () => purgeTopicLogs,
|
|
23039
|
+
pruneRuntimeEvents: () => pruneRuntimeEvents,
|
|
23011
23040
|
prepareDeliveryAck: () => prepareDeliveryAck,
|
|
23012
23041
|
onShutdown: () => onShutdown,
|
|
23013
23042
|
normalizeVaultKey: () => normalizeVaultKey,
|
|
@@ -23047,6 +23076,7 @@ __export(exports_src, {
|
|
|
23047
23076
|
isAgentKind: () => isAgentKind,
|
|
23048
23077
|
interSessionQueue: () => interSessionQueue,
|
|
23049
23078
|
ingestAttachment: () => ingestAttachment,
|
|
23079
|
+
heartbeatRuntimeEventConsumer: () => heartbeatRuntimeEventConsumer,
|
|
23050
23080
|
grantSubagentTellTarget: () => grantSubagentTellTarget,
|
|
23051
23081
|
getVisibleTopics: () => getVisibleTopics,
|
|
23052
23082
|
getTopics: () => getTopics,
|
|
@@ -23081,6 +23111,7 @@ __export(exports_src, {
|
|
|
23081
23111
|
errMsg: () => errMsg,
|
|
23082
23112
|
ensurePersonalGeneral: () => ensurePersonalGeneral,
|
|
23083
23113
|
ensureBgBash: () => ensureBgBash,
|
|
23114
|
+
earliestRuntimeEventSeq: () => earliestRuntimeEventSeq,
|
|
23084
23115
|
dispatchPeerRuntimeVisual: () => dispatchPeerRuntimeVisual,
|
|
23085
23116
|
dispatchPeerRuntimeSpawn: () => dispatchPeerRuntimeSpawn,
|
|
23086
23117
|
dispatchPeerRuntimeSelfConfig: () => dispatchPeerRuntimeSelfConfig,
|
|
@@ -23579,6 +23610,7 @@ __export(exports_node_host, {
|
|
|
23579
23610
|
reconcilePendingAskUserQuestionGates: () => reconcilePendingAskUserQuestionGates,
|
|
23580
23611
|
reapOrphanBrowsers: () => reapPlaywrightOrphans,
|
|
23581
23612
|
readDecisions: () => readDecisions,
|
|
23613
|
+
pruneRuntimeEvents: () => pruneRuntimeEvents,
|
|
23582
23614
|
onShutdown: () => onShutdown,
|
|
23583
23615
|
nodeRequestHandlerNames: () => nodeRequestHandlerNames,
|
|
23584
23616
|
logger: () => logger,
|
|
@@ -23602,6 +23634,7 @@ __export(exports_node_host, {
|
|
|
23602
23634
|
flushBashrsCompletions: () => flushBashrsCompletions,
|
|
23603
23635
|
executeVaultCommand: () => executeVaultCommand,
|
|
23604
23636
|
ensurePersonalGeneral: () => ensurePersonalGeneral,
|
|
23637
|
+
earliestRuntimeEventSeq: () => earliestRuntimeEventSeq,
|
|
23605
23638
|
deleteVaultEntry: () => deleteVaultEntry,
|
|
23606
23639
|
compactTopicSession: () => compactTopicSession,
|
|
23607
23640
|
appendApiMessage: () => appendApiMessage,
|
|
@@ -29847,8 +29880,8 @@ function createPollingSseStream(req, options) {
|
|
|
29847
29880
|
} catch {}
|
|
29848
29881
|
};
|
|
29849
29882
|
const send = (event, data, id) => {
|
|
29850
|
-
if (closed)
|
|
29851
|
-
return;
|
|
29883
|
+
if (closed || controller.desiredSize !== null && controller.desiredSize <= 0)
|
|
29884
|
+
return false;
|
|
29852
29885
|
try {
|
|
29853
29886
|
const lines = [
|
|
29854
29887
|
id === undefined ? "" : `id: ${id}`,
|
|
@@ -29859,8 +29892,10 @@ function createPollingSseStream(req, options) {
|
|
|
29859
29892
|
controller.enqueue(encoder.encode(`${lines}
|
|
29860
29893
|
|
|
29861
29894
|
`));
|
|
29895
|
+
return true;
|
|
29862
29896
|
} catch (error2) {
|
|
29863
29897
|
fail(error2);
|
|
29898
|
+
return false;
|
|
29864
29899
|
}
|
|
29865
29900
|
};
|
|
29866
29901
|
const close = () => {
|
|
@@ -29903,7 +29938,7 @@ function createPollingSseStream(req, options) {
|
|
|
29903
29938
|
return;
|
|
29904
29939
|
pollTimer = setInterval(pump, options.pollIntervalMs ?? 100);
|
|
29905
29940
|
heartbeatTimer = setInterval(() => {
|
|
29906
|
-
if (closed)
|
|
29941
|
+
if (closed || controller.desiredSize !== null && controller.desiredSize <= 0)
|
|
29907
29942
|
return;
|
|
29908
29943
|
try {
|
|
29909
29944
|
controller.enqueue(encoder.encode(`: heartbeat ${Date.now()}
|
|
@@ -29917,7 +29952,7 @@ function createPollingSseStream(req, options) {
|
|
|
29917
29952
|
cancel() {
|
|
29918
29953
|
stop();
|
|
29919
29954
|
}
|
|
29920
|
-
});
|
|
29955
|
+
}, { highWaterMark: 64 });
|
|
29921
29956
|
return new Response(stream, {
|
|
29922
29957
|
headers: {
|
|
29923
29958
|
"cache-control": "no-cache, no-transform",
|
|
@@ -30025,7 +30060,6 @@ function runtimeEvent(event) {
|
|
|
30025
30060
|
}
|
|
30026
30061
|
function createRuntimeContractEventStream(req, after, topicId, scope = {}) {
|
|
30027
30062
|
const scoped = "surfaceScope" in scope;
|
|
30028
|
-
const wanted = scope.surfaceScope ?? null;
|
|
30029
30063
|
const visible = new Map;
|
|
30030
30064
|
const eventInScope = (eventTopicId) => {
|
|
30031
30065
|
if (!scoped)
|
|
@@ -30033,26 +30067,39 @@ function createRuntimeContractEventStream(req, after, topicId, scope = {}) {
|
|
|
30033
30067
|
const cached = visible.get(eventTopicId);
|
|
30034
30068
|
if (cached !== undefined)
|
|
30035
30069
|
return cached;
|
|
30036
|
-
const
|
|
30037
|
-
const allowed =
|
|
30070
|
+
const topic = getTopic(eventTopicId);
|
|
30071
|
+
const allowed = Boolean(topic && topicInRequestScope(req, topic));
|
|
30038
30072
|
visible.set(eventTopicId, allowed);
|
|
30039
30073
|
return allowed;
|
|
30040
30074
|
};
|
|
30041
30075
|
let cursor = Math.max(0, after);
|
|
30076
|
+
let reportedCursor = cursor;
|
|
30077
|
+
const oldestCursor = earliestRuntimeEventSeq();
|
|
30042
30078
|
return createPollingSseStream(req, {
|
|
30043
|
-
ready: {
|
|
30079
|
+
ready: {
|
|
30080
|
+
v: NODE_RUNTIME_CONTRACT_VERSION,
|
|
30081
|
+
cursor,
|
|
30082
|
+
oldestCursor,
|
|
30083
|
+
truncated: oldestCursor > 0 && cursor < oldestCursor - 1
|
|
30084
|
+
},
|
|
30044
30085
|
pump(send) {
|
|
30045
|
-
|
|
30086
|
+
for (let batch = 0;batch < 5; batch += 1) {
|
|
30046
30087
|
const events = listRuntimeEventsAfter(cursor, 500);
|
|
30047
|
-
if (events.length === 0)
|
|
30088
|
+
if (events.length === 0) {
|
|
30089
|
+
if (reportedCursor < cursor && send("cursor", { cursor }, cursor))
|
|
30090
|
+
reportedCursor = cursor;
|
|
30048
30091
|
break;
|
|
30092
|
+
}
|
|
30049
30093
|
for (const event of events) {
|
|
30050
|
-
cursor = event.seq;
|
|
30051
30094
|
if ((!topicId || event.topicId === topicId) && eventInScope(event.topicId)) {
|
|
30052
|
-
send("runtime", runtimeEvent(event), event.seq)
|
|
30095
|
+
if (!send("runtime", runtimeEvent(event), event.seq))
|
|
30096
|
+
return;
|
|
30053
30097
|
}
|
|
30098
|
+
cursor = event.seq;
|
|
30054
30099
|
}
|
|
30055
|
-
send("cursor", { cursor }, cursor)
|
|
30100
|
+
if (!send("cursor", { cursor }, cursor))
|
|
30101
|
+
return;
|
|
30102
|
+
reportedCursor = cursor;
|
|
30056
30103
|
if (events.length < 500)
|
|
30057
30104
|
break;
|
|
30058
30105
|
}
|
|
@@ -30062,15 +30109,24 @@ function createRuntimeContractEventStream(req, after, topicId, scope = {}) {
|
|
|
30062
30109
|
function createEventStream(req, userId, after, surface) {
|
|
30063
30110
|
const allowedTopics = new Set(topicsForUser(userId, surface).map((topic) => topic.id));
|
|
30064
30111
|
let cursor = Math.max(0, after);
|
|
30112
|
+
let reportedCursor = cursor;
|
|
30113
|
+
const oldestCursor = earliestRuntimeEventSeq();
|
|
30065
30114
|
return createPollingSseStream(req, {
|
|
30066
|
-
ready: {
|
|
30115
|
+
ready: {
|
|
30116
|
+
protocolVersion: NODE_CONTROL_PROTOCOL_VERSION,
|
|
30117
|
+
cursor,
|
|
30118
|
+
oldestCursor,
|
|
30119
|
+
truncated: oldestCursor > 0 && cursor < oldestCursor - 1
|
|
30120
|
+
},
|
|
30067
30121
|
pump(send) {
|
|
30068
|
-
|
|
30122
|
+
for (let batch = 0;batch < 5; batch += 1) {
|
|
30069
30123
|
const events = listRuntimeEventsAfter(cursor, 500);
|
|
30070
|
-
if (events.length === 0)
|
|
30124
|
+
if (events.length === 0) {
|
|
30125
|
+
if (reportedCursor < cursor && send("cursor", { cursor }, cursor))
|
|
30126
|
+
reportedCursor = cursor;
|
|
30071
30127
|
break;
|
|
30128
|
+
}
|
|
30072
30129
|
for (const event of events) {
|
|
30073
|
-
cursor = event.seq;
|
|
30074
30130
|
if (event.type === "topic-created" || event.type === "topic-updated") {
|
|
30075
30131
|
const topic = getTopic(event.topicId);
|
|
30076
30132
|
const admissible = topic && isParticipant(topic, userId) && (!surface || topic.surface === surface);
|
|
@@ -30080,12 +30136,15 @@ function createEventStream(req, userId, after, surface) {
|
|
|
30080
30136
|
allowedTopics.delete(event.topicId);
|
|
30081
30137
|
}
|
|
30082
30138
|
const visible = allowedTopics.has(event.topicId);
|
|
30083
|
-
if (visible)
|
|
30084
|
-
|
|
30139
|
+
if (visible && !send("runtime", runtimeEvent(event), event.seq))
|
|
30140
|
+
return;
|
|
30141
|
+
cursor = event.seq;
|
|
30085
30142
|
if (event.type === "topic-deleted")
|
|
30086
30143
|
allowedTopics.delete(event.topicId);
|
|
30087
30144
|
}
|
|
30088
|
-
send("cursor", { cursor }, cursor)
|
|
30145
|
+
if (!send("cursor", { cursor }, cursor))
|
|
30146
|
+
return;
|
|
30147
|
+
reportedCursor = cursor;
|
|
30089
30148
|
if (events.length < 500)
|
|
30090
30149
|
break;
|
|
30091
30150
|
}
|
|
@@ -32837,6 +32896,19 @@ function startNode(opts = {}) {
|
|
|
32837
32896
|
setRuntimeMcpPort(port);
|
|
32838
32897
|
const stopTurnRequests = startDurableTurnRequestWorker();
|
|
32839
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?.();
|
|
32840
32912
|
const stopBashrsCompletions = startBashrsCompletionsWorker();
|
|
32841
32913
|
let modules;
|
|
32842
32914
|
try {
|
|
@@ -32851,6 +32923,7 @@ function startNode(opts = {}) {
|
|
|
32851
32923
|
} catch (error2) {
|
|
32852
32924
|
stopTurnRequests();
|
|
32853
32925
|
stopInbox();
|
|
32926
|
+
clearInterval(eventPruneTimer);
|
|
32854
32927
|
stopBashrsCompletions();
|
|
32855
32928
|
server.stop(true);
|
|
32856
32929
|
processLease?.stop();
|
|
@@ -32877,6 +32950,7 @@ function startNode(opts = {}) {
|
|
|
32877
32950
|
});
|
|
32878
32951
|
stopTurnRequests();
|
|
32879
32952
|
stopInbox();
|
|
32953
|
+
clearInterval(eventPruneTimer);
|
|
32880
32954
|
stopBashrsCompletions();
|
|
32881
32955
|
server.stop(true);
|
|
32882
32956
|
processLease?.stop();
|
|
@@ -32889,6 +32963,7 @@ function startNode(opts = {}) {
|
|
|
32889
32963
|
onShutdown("node-server", 130, () => {
|
|
32890
32964
|
stopTurnRequests();
|
|
32891
32965
|
stopInbox();
|
|
32966
|
+
clearInterval(eventPruneTimer);
|
|
32892
32967
|
stopBashrsCompletions();
|
|
32893
32968
|
server.stop(true);
|
|
32894
32969
|
});
|
|
@@ -40807,6 +40882,11 @@ function createTables(db4) {
|
|
|
40807
40882
|
key TEXT PRIMARY KEY,
|
|
40808
40883
|
value TEXT NOT NULL
|
|
40809
40884
|
)`);
|
|
40885
|
+
db4.run(`CREATE TABLE IF NOT EXISTS runtime_inbox (
|
|
40886
|
+
seq INTEGER PRIMARY KEY,
|
|
40887
|
+
runtime_message_id TEXT,
|
|
40888
|
+
event_json TEXT NOT NULL
|
|
40889
|
+
)`);
|
|
40810
40890
|
}
|
|
40811
40891
|
function migrateOutboxSchema(db4) {
|
|
40812
40892
|
try {
|
|
@@ -40817,6 +40897,13 @@ function migrateOutboxSchema(db4) {
|
|
|
40817
40897
|
} catch {}
|
|
40818
40898
|
db4.run("CREATE INDEX IF NOT EXISTS idx_telegram_outbox_runtime_message ON outbox(runtime_message_id)");
|
|
40819
40899
|
}
|
|
40900
|
+
function migrateRuntimeInboxSchema(db4) {
|
|
40901
|
+
try {
|
|
40902
|
+
db4.run("ALTER TABLE runtime_inbox ADD COLUMN runtime_message_id TEXT");
|
|
40903
|
+
} catch {}
|
|
40904
|
+
db4.run(`CREATE UNIQUE INDEX IF NOT EXISTS idx_telegram_runtime_inbox_message
|
|
40905
|
+
ON runtime_inbox(runtime_message_id) WHERE runtime_message_id IS NOT NULL`);
|
|
40906
|
+
}
|
|
40820
40907
|
function openMappingStore(path) {
|
|
40821
40908
|
const dbPath = path ?? join45(DATA_DIR, "adapter-telegram.db");
|
|
40822
40909
|
if (dbPath !== ":memory:")
|
|
@@ -40825,6 +40912,7 @@ function openMappingStore(path) {
|
|
|
40825
40912
|
migrateLegacySchema(db4);
|
|
40826
40913
|
createTables(db4);
|
|
40827
40914
|
migrateOutboxSchema(db4);
|
|
40915
|
+
migrateRuntimeInboxSchema(db4);
|
|
40828
40916
|
return {
|
|
40829
40917
|
load() {
|
|
40830
40918
|
const rows = db4.query("SELECT chat_id, thread_id, topic_id FROM mappings").all();
|
|
@@ -40898,6 +40986,40 @@ function openMappingStore(path) {
|
|
|
40898
40986
|
entry.lastError ?? null
|
|
40899
40987
|
]);
|
|
40900
40988
|
},
|
|
40989
|
+
runtimeEventCursor() {
|
|
40990
|
+
const row = db4.query("SELECT value FROM settings WHERE key = 'runtime_event_cursor'").get();
|
|
40991
|
+
if (!row)
|
|
40992
|
+
return;
|
|
40993
|
+
const value = Number.parseInt(row.value, 10);
|
|
40994
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
40995
|
+
},
|
|
40996
|
+
captureRuntimeEvent(event) {
|
|
40997
|
+
const messageId = event.payload && typeof event.payload === "object" && "id" in event.payload && typeof event.payload.id === "string" ? event.payload.id : null;
|
|
40998
|
+
db4.transaction(() => {
|
|
40999
|
+
db4.run(`INSERT OR IGNORE INTO runtime_inbox (seq, runtime_message_id, event_json)
|
|
41000
|
+
VALUES (?, ?, ?)`, [event.seq, messageId, JSON.stringify(event)]);
|
|
41001
|
+
db4.run(`INSERT INTO settings (key, value) VALUES ('runtime_event_cursor', ?)
|
|
41002
|
+
ON CONFLICT(key) DO UPDATE SET value = MAX(CAST(value AS INTEGER), CAST(excluded.value AS INTEGER))`, [String(event.seq)]);
|
|
41003
|
+
})();
|
|
41004
|
+
},
|
|
41005
|
+
advanceRuntimeEventCursor(seq) {
|
|
41006
|
+
db4.run(`INSERT INTO settings (key, value) VALUES ('runtime_event_cursor', ?)
|
|
41007
|
+
ON CONFLICT(key) DO UPDATE SET value = MAX(CAST(value AS INTEGER), CAST(excluded.value AS INTEGER))`, [String(seq)]);
|
|
41008
|
+
},
|
|
41009
|
+
pendingRuntimeEvents() {
|
|
41010
|
+
const rows = db4.query("SELECT seq, event_json FROM runtime_inbox ORDER BY seq ASC").all();
|
|
41011
|
+
return rows.flatMap((row) => {
|
|
41012
|
+
try {
|
|
41013
|
+
return [{ seq: row.seq, event: JSON.parse(row.event_json) }];
|
|
41014
|
+
} catch {
|
|
41015
|
+
db4.run("DELETE FROM runtime_inbox WHERE seq = ?", [row.seq]);
|
|
41016
|
+
return [];
|
|
41017
|
+
}
|
|
41018
|
+
});
|
|
41019
|
+
},
|
|
41020
|
+
acknowledgeRuntimeEvent(seq) {
|
|
41021
|
+
db4.run("DELETE FROM runtime_inbox WHERE seq = ?", [seq]);
|
|
41022
|
+
},
|
|
40901
41023
|
outboxDue(now) {
|
|
40902
41024
|
const rows = db4.query("SELECT * FROM outbox WHERE dead = 0 AND next_try_at <= ? ORDER BY id ASC").all(now);
|
|
40903
41025
|
return rows.map(outboxRowToEntry);
|
|
@@ -41775,15 +41897,29 @@ function startTelegramAdapter(opts) {
|
|
|
41775
41897
|
}
|
|
41776
41898
|
const sendQueues = new Map;
|
|
41777
41899
|
function enqueueSend(topicId, task) {
|
|
41778
|
-
const prev = sendQueues.get(topicId) ?? Promise.resolve();
|
|
41900
|
+
const prev = sendQueues.get(topicId) ?? Promise.resolve(true);
|
|
41779
41901
|
const next = prev.then(() => new Promise((resolve24) => {
|
|
41902
|
+
let settled = false;
|
|
41780
41903
|
const timer = setTimeout(() => {
|
|
41904
|
+
if (settled)
|
|
41905
|
+
return;
|
|
41906
|
+
settled = true;
|
|
41781
41907
|
logger.warn({ topicId, sendTimeoutMs }, "telegram adapter: send timed out \u2014 abandoning it and continuing the queue");
|
|
41782
|
-
resolve24();
|
|
41908
|
+
resolve24(false);
|
|
41783
41909
|
}, sendTimeoutMs);
|
|
41784
|
-
task().
|
|
41910
|
+
task().then(() => {
|
|
41911
|
+
if (settled)
|
|
41912
|
+
return;
|
|
41913
|
+
settled = true;
|
|
41785
41914
|
clearTimeout(timer);
|
|
41786
|
-
resolve24();
|
|
41915
|
+
resolve24(true);
|
|
41916
|
+
}).catch((err2) => {
|
|
41917
|
+
logger.warn({ err: err2, topicId }, "telegram adapter: send task failed");
|
|
41918
|
+
if (settled)
|
|
41919
|
+
return;
|
|
41920
|
+
settled = true;
|
|
41921
|
+
clearTimeout(timer);
|
|
41922
|
+
resolve24(false);
|
|
41787
41923
|
});
|
|
41788
41924
|
}));
|
|
41789
41925
|
sendQueues.set(topicId, next);
|
|
@@ -41791,13 +41927,14 @@ function startTelegramAdapter(opts) {
|
|
|
41791
41927
|
if (sendQueues.get(topicId) === next)
|
|
41792
41928
|
sendQueues.delete(topicId);
|
|
41793
41929
|
});
|
|
41930
|
+
return next;
|
|
41794
41931
|
}
|
|
41795
41932
|
function enqueueFanout(topicId, mappings, payload) {
|
|
41796
41933
|
const targets = [...mappings];
|
|
41797
|
-
enqueueSend(topicId, () => deliverToTargets(topicId, targets, payload));
|
|
41934
|
+
enqueueSend(topicId, () => deliverToTargets(topicId, targets, payload)).then(payload.onSettled);
|
|
41798
41935
|
}
|
|
41799
41936
|
function enqueueTarget(topicId, target, payload) {
|
|
41800
|
-
enqueueSend(topicId, () => deliverToTargets(topicId, [target], payload));
|
|
41937
|
+
enqueueSend(topicId, () => deliverToTargets(topicId, [target], payload)).then(payload.onSettled);
|
|
41801
41938
|
}
|
|
41802
41939
|
const pendingByTopic = new Map;
|
|
41803
41940
|
const permissionBlockedTopics = new Map;
|
|
@@ -41815,8 +41952,9 @@ function startTelegramAdapter(opts) {
|
|
|
41815
41952
|
});
|
|
41816
41953
|
}
|
|
41817
41954
|
function flushBuffered(topicId, buffer, send) {
|
|
41818
|
-
for (const payload of buffer)
|
|
41819
|
-
enqueueSend(topicId, () => send(payload));
|
|
41955
|
+
for (const payload of buffer) {
|
|
41956
|
+
enqueueSend(topicId, () => send(payload)).then(payload.onSettled);
|
|
41957
|
+
}
|
|
41820
41958
|
}
|
|
41821
41959
|
function materializeTopic(topic) {
|
|
41822
41960
|
if (!forumManageTopicsAvailable || suppressMaterialize > 0 || byTopic.has(topic.id) || pendingByTopic.has(topic.id) || permissionBlockedTopics.has(topic.id) || materializeTombstones.has(topic.id)) {
|
|
@@ -41878,8 +42016,12 @@ function startTelegramAdapter(opts) {
|
|
|
41878
42016
|
if (materializeTombstones.delete(topicId))
|
|
41879
42017
|
store.deleteTombstone(topicId);
|
|
41880
42018
|
const pending2 = pendingByTopic.get(topicId);
|
|
41881
|
-
if (pending2)
|
|
42019
|
+
if (pending2) {
|
|
41882
42020
|
pending2.cancelled = true;
|
|
42021
|
+
for (const payload of pending2.buffer)
|
|
42022
|
+
payload.onSettled?.(true);
|
|
42023
|
+
pending2.buffer = [];
|
|
42024
|
+
}
|
|
41883
42025
|
for (const [messageId, message] of runtimeMessages) {
|
|
41884
42026
|
if (message.topicId === topicId)
|
|
41885
42027
|
deleteDeliveredRuntimeMessage(topicId, messageId);
|
|
@@ -41926,7 +42068,7 @@ function startTelegramAdapter(opts) {
|
|
|
41926
42068
|
}
|
|
41927
42069
|
const tombstoneTitle = materializeTombstones.get(topicId);
|
|
41928
42070
|
if (tombstoneTitle !== undefined) {
|
|
41929
|
-
enqueueSend(topicId, () => deliverFallback(topicId, tombstoneTitle, payload));
|
|
42071
|
+
enqueueSend(topicId, () => deliverFallback(topicId, tombstoneTitle, payload)).then(payload.onSettled);
|
|
41930
42072
|
return true;
|
|
41931
42073
|
}
|
|
41932
42074
|
const topic = getTopic(topicId);
|
|
@@ -41934,7 +42076,7 @@ function startTelegramAdapter(opts) {
|
|
|
41934
42076
|
return false;
|
|
41935
42077
|
if (forumMode) {
|
|
41936
42078
|
if (!forumManageTopicsAvailable || permissionBlockedTopics.has(topicId)) {
|
|
41937
|
-
enqueueSend(topicId, () => deliverFallback(topicId, topic.title, payload));
|
|
42079
|
+
enqueueSend(topicId, () => deliverFallback(topicId, topic.title, payload)).then(payload.onSettled);
|
|
41938
42080
|
return true;
|
|
41939
42081
|
}
|
|
41940
42082
|
if (!materializeTopic(topic))
|
|
@@ -42382,6 +42524,113 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42382
42524
|
}
|
|
42383
42525
|
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"));
|
|
42384
42526
|
});
|
|
42527
|
+
async function deliverPersistedRuntimeMessage(event) {
|
|
42528
|
+
const msg = event.payload;
|
|
42529
|
+
if (msg.authorId === userId && msg.sourceAdapter === "telegram")
|
|
42530
|
+
return true;
|
|
42531
|
+
if (msg.kind === "tool")
|
|
42532
|
+
return true;
|
|
42533
|
+
const hasAttachments = Boolean(msg.attachments && msg.attachments.length > 0);
|
|
42534
|
+
if (!msg.text && !hasAttachments)
|
|
42535
|
+
return true;
|
|
42536
|
+
const runtimeMessageId = msg.authorId === "ai" ? msg.id : undefined;
|
|
42537
|
+
if (runtimeMessageId) {
|
|
42538
|
+
runtimeMessages.set(runtimeMessageId, msg);
|
|
42539
|
+
if (!msg.queryId) {
|
|
42540
|
+
const timer = setTimeout(() => {
|
|
42541
|
+
runtimeMessages.delete(runtimeMessageId);
|
|
42542
|
+
deliveredByRuntimeMessageId.delete(runtimeMessageId);
|
|
42543
|
+
}, 5 * 60000);
|
|
42544
|
+
timer.unref?.();
|
|
42545
|
+
}
|
|
42546
|
+
}
|
|
42547
|
+
const tagFiles = msg.text ? extractFileTagPaths(msg.text).map((path) => ({ path, filename: basename12(path) })) : [];
|
|
42548
|
+
const attachmentFiles = hasAttachments ? (msg.attachments ?? []).map((attachment) => {
|
|
42549
|
+
const path = resolveUploadedFilePathByFileId(attachment.id);
|
|
42550
|
+
if (!path)
|
|
42551
|
+
return null;
|
|
42552
|
+
return {
|
|
42553
|
+
path,
|
|
42554
|
+
filename: basename12(attachment.filename) || basename12(path),
|
|
42555
|
+
...attachment.mimeType ? { mimeType: attachment.mimeType } : {}
|
|
42556
|
+
};
|
|
42557
|
+
}).filter((file) => file !== null) : [];
|
|
42558
|
+
const files = [...tagFiles, ...attachmentFiles];
|
|
42559
|
+
const rawText = tagFiles.length > 0 && msg.text ? stripFileTags(msg.text) : msg.text ?? "";
|
|
42560
|
+
const text2 = msg.authorId === userId && rawText ? `[From: User] ${rawText}` : rawText;
|
|
42561
|
+
if (!text2 && files.length === 0)
|
|
42562
|
+
return true;
|
|
42563
|
+
let settle;
|
|
42564
|
+
const settled = new Promise((resolve24) => {
|
|
42565
|
+
settle = resolve24;
|
|
42566
|
+
});
|
|
42567
|
+
const payload = {
|
|
42568
|
+
text: text2,
|
|
42569
|
+
files,
|
|
42570
|
+
runtimeMessageId,
|
|
42571
|
+
deliveryAckRequested: msg.deliveryAckRequested === true,
|
|
42572
|
+
onSettled: settle
|
|
42573
|
+
};
|
|
42574
|
+
const routed = routeMessage(event.topicId, payload, msg.queryId);
|
|
42575
|
+
if (routed && payload.deliveryAckRequested)
|
|
42576
|
+
claimDeliveryAck(event.topicId, msg.id);
|
|
42577
|
+
return routed ? settled : true;
|
|
42578
|
+
}
|
|
42579
|
+
const savedRuntimeEventCursor = store.runtimeEventCursor();
|
|
42580
|
+
let runtimeEventCursor = savedRuntimeEventCursor ?? latestRuntimeEventSeq();
|
|
42581
|
+
if (savedRuntimeEventCursor === undefined) {
|
|
42582
|
+
store.advanceRuntimeEventCursor(runtimeEventCursor);
|
|
42583
|
+
}
|
|
42584
|
+
const runtimeEventConsumerId = `telegram:${userId}:${opts.mappingDbPath ?? "default"}`;
|
|
42585
|
+
heartbeatRuntimeEventConsumer(runtimeEventConsumerId, runtimeEventCursor);
|
|
42586
|
+
let pollingRuntimeEvents = false;
|
|
42587
|
+
let drainingRuntimeInbox = false;
|
|
42588
|
+
const drainRuntimeInbox = async () => {
|
|
42589
|
+
if (drainingRuntimeInbox || stopped)
|
|
42590
|
+
return;
|
|
42591
|
+
drainingRuntimeInbox = true;
|
|
42592
|
+
try {
|
|
42593
|
+
while (!stopped) {
|
|
42594
|
+
const pending2 = store.pendingRuntimeEvents()[0];
|
|
42595
|
+
if (!pending2)
|
|
42596
|
+
break;
|
|
42597
|
+
const delivered = await deliverPersistedRuntimeMessage(pending2.event);
|
|
42598
|
+
if (!delivered || stopped)
|
|
42599
|
+
break;
|
|
42600
|
+
store.acknowledgeRuntimeEvent(pending2.seq);
|
|
42601
|
+
}
|
|
42602
|
+
} catch (err2) {
|
|
42603
|
+
if (!stopped)
|
|
42604
|
+
logger.warn({ err: err2 }, "telegram adapter: durable runtime inbox drain failed");
|
|
42605
|
+
} finally {
|
|
42606
|
+
drainingRuntimeInbox = false;
|
|
42607
|
+
}
|
|
42608
|
+
};
|
|
42609
|
+
const pollRuntimeEvents = () => {
|
|
42610
|
+
if (pollingRuntimeEvents || stopped)
|
|
42611
|
+
return;
|
|
42612
|
+
pollingRuntimeEvents = true;
|
|
42613
|
+
try {
|
|
42614
|
+
for (let batch = 0;batch < 5; batch += 1) {
|
|
42615
|
+
const events = listRuntimeEventsAfter(runtimeEventCursor, 500);
|
|
42616
|
+
if (events.length === 0)
|
|
42617
|
+
break;
|
|
42618
|
+
for (const event of events) {
|
|
42619
|
+
if (event.type === "message")
|
|
42620
|
+
store.captureRuntimeEvent({ ...event, seq: event.seq });
|
|
42621
|
+
else
|
|
42622
|
+
store.advanceRuntimeEventCursor(event.seq);
|
|
42623
|
+
runtimeEventCursor = event.seq;
|
|
42624
|
+
}
|
|
42625
|
+
if (events.length < 500)
|
|
42626
|
+
break;
|
|
42627
|
+
}
|
|
42628
|
+
drainRuntimeInbox();
|
|
42629
|
+
heartbeatRuntimeEventConsumer(runtimeEventConsumerId, runtimeEventCursor);
|
|
42630
|
+
} finally {
|
|
42631
|
+
pollingRuntimeEvents = false;
|
|
42632
|
+
}
|
|
42633
|
+
};
|
|
42385
42634
|
const unsubscribe = runtimeBus().subscribe((event) => {
|
|
42386
42635
|
if (stopped)
|
|
42387
42636
|
return;
|
|
@@ -42394,22 +42643,22 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42394
42643
|
return;
|
|
42395
42644
|
}
|
|
42396
42645
|
if (event.type === "message-updated") {
|
|
42397
|
-
const
|
|
42398
|
-
if (!
|
|
42646
|
+
const payload = event.payload;
|
|
42647
|
+
if (!payload.messageId || !payload.patch)
|
|
42399
42648
|
return;
|
|
42400
|
-
if (
|
|
42401
|
-
deleteDeliveredRuntimeMessage(event.topicId,
|
|
42649
|
+
if (payload.patch.deleted) {
|
|
42650
|
+
deleteDeliveredRuntimeMessage(event.topicId, payload.messageId);
|
|
42402
42651
|
return;
|
|
42403
42652
|
}
|
|
42404
|
-
const current3 = runtimeMessages.get(
|
|
42653
|
+
const current3 = runtimeMessages.get(payload.messageId);
|
|
42405
42654
|
if (!current3)
|
|
42406
42655
|
return;
|
|
42407
|
-
const updated = { ...current3, ...
|
|
42408
|
-
runtimeMessages.set(
|
|
42409
|
-
if (footerEnabled &&
|
|
42656
|
+
const updated = { ...current3, ...payload.patch };
|
|
42657
|
+
runtimeMessages.set(payload.messageId, updated);
|
|
42658
|
+
if (footerEnabled && payload.patch.usage && updated.authorId === "ai") {
|
|
42410
42659
|
const footer = renderTurnFooter(updated);
|
|
42411
42660
|
if (footer)
|
|
42412
|
-
attachUpdatedFooter(event.topicId,
|
|
42661
|
+
attachUpdatedFooter(event.topicId, payload.messageId, footer);
|
|
42413
42662
|
}
|
|
42414
42663
|
return;
|
|
42415
42664
|
}
|
|
@@ -42432,53 +42681,10 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42432
42681
|
}
|
|
42433
42682
|
return;
|
|
42434
42683
|
}
|
|
42435
|
-
if (event.type !== "message")
|
|
42436
|
-
return;
|
|
42437
|
-
const msg = event.payload;
|
|
42438
|
-
if (msg.authorId === userId && msg.sourceAdapter === "telegram")
|
|
42439
|
-
return;
|
|
42440
|
-
if (msg.kind === "tool")
|
|
42441
|
-
return;
|
|
42442
|
-
const hasAttachments = Boolean(msg.attachments && msg.attachments.length > 0);
|
|
42443
|
-
if (!msg.text && !hasAttachments)
|
|
42444
|
-
return;
|
|
42445
|
-
const runtimeMessageId = msg.authorId === "ai" ? msg.id : undefined;
|
|
42446
|
-
if (runtimeMessageId) {
|
|
42447
|
-
runtimeMessages.set(runtimeMessageId, msg);
|
|
42448
|
-
if (!msg.queryId) {
|
|
42449
|
-
const timer = setTimeout(() => {
|
|
42450
|
-
runtimeMessages.delete(runtimeMessageId);
|
|
42451
|
-
deliveredByRuntimeMessageId.delete(runtimeMessageId);
|
|
42452
|
-
}, 5 * 60000);
|
|
42453
|
-
timer.unref?.();
|
|
42454
|
-
}
|
|
42455
|
-
}
|
|
42456
|
-
const tagFiles = msg.text ? extractFileTagPaths(msg.text).map((path) => ({ path, filename: basename12(path) })) : [];
|
|
42457
|
-
const attachmentFiles = hasAttachments ? (msg.attachments ?? []).map((attachment) => {
|
|
42458
|
-
const path = resolveUploadedFilePathByFileId(attachment.id);
|
|
42459
|
-
if (!path)
|
|
42460
|
-
return null;
|
|
42461
|
-
return {
|
|
42462
|
-
path,
|
|
42463
|
-
filename: basename12(attachment.filename) || basename12(path),
|
|
42464
|
-
...attachment.mimeType ? { mimeType: attachment.mimeType } : {}
|
|
42465
|
-
};
|
|
42466
|
-
}).filter((file) => file !== null) : [];
|
|
42467
|
-
const files = [...tagFiles, ...attachmentFiles];
|
|
42468
|
-
const rawText = tagFiles.length > 0 && msg.text ? stripFileTags(msg.text) : msg.text ?? "";
|
|
42469
|
-
const text2 = msg.authorId === userId && rawText ? `[From: User] ${rawText}` : rawText;
|
|
42470
|
-
if (!text2 && files.length === 0)
|
|
42471
|
-
return;
|
|
42472
|
-
const payload = {
|
|
42473
|
-
text: text2,
|
|
42474
|
-
files,
|
|
42475
|
-
runtimeMessageId,
|
|
42476
|
-
deliveryAckRequested: msg.deliveryAckRequested === true
|
|
42477
|
-
};
|
|
42478
|
-
if (routeMessage(event.topicId, payload, msg.queryId) && payload.deliveryAckRequested) {
|
|
42479
|
-
claimDeliveryAck(event.topicId, msg.id);
|
|
42480
|
-
}
|
|
42481
42684
|
});
|
|
42685
|
+
pollRuntimeEvents();
|
|
42686
|
+
const runtimeEventPollTimer = setInterval(pollRuntimeEvents, 100);
|
|
42687
|
+
runtimeEventPollTimer.unref?.();
|
|
42482
42688
|
if (forumMode) {
|
|
42483
42689
|
bindMapping(forumChat, undefined, personalGeneral.id);
|
|
42484
42690
|
materializeVisibleTopics();
|
|
@@ -42498,6 +42704,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
42498
42704
|
for (const queryId of toolStatusByQueryId.keys())
|
|
42499
42705
|
closeToolStatus(queryId);
|
|
42500
42706
|
mediaIntake.stop();
|
|
42707
|
+
clearInterval(runtimeEventPollTimer);
|
|
42501
42708
|
unsubscribe();
|
|
42502
42709
|
store.close();
|
|
42503
42710
|
}
|
|
@@ -44809,8 +45016,18 @@ class TunnelClient {
|
|
|
44809
45016
|
this.bridgedSockets.clear();
|
|
44810
45017
|
}
|
|
44811
45018
|
send(frame) {
|
|
44812
|
-
|
|
44813
|
-
|
|
45019
|
+
const ws = this.ws;
|
|
45020
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
45021
|
+
return;
|
|
45022
|
+
if (Number(ws.bufferedAmount ?? 0) > MAX_TUNNEL_BUFFERED_AMOUNT) {
|
|
45023
|
+
this.disconnectActiveConnection(ws, this.connectionGeneration, { reason: "relay outbound buffer limit exceeded" }, true);
|
|
45024
|
+
return;
|
|
45025
|
+
}
|
|
45026
|
+
try {
|
|
45027
|
+
ws.send(encodeFrame(frame));
|
|
45028
|
+
} catch {
|
|
45029
|
+
this.disconnectActiveConnection(ws, this.connectionGeneration, { reason: "relay send failed" }, true);
|
|
45030
|
+
}
|
|
44814
45031
|
}
|
|
44815
45032
|
handleFrame(frame) {
|
|
44816
45033
|
switch (frame.type) {
|
|
@@ -44845,11 +45062,23 @@ class TunnelClient {
|
|
|
44845
45062
|
break;
|
|
44846
45063
|
case "http_req_chunk": {
|
|
44847
45064
|
const pending2 = this.pendingHttp.get(frame.id);
|
|
45065
|
+
if (!pending2)
|
|
45066
|
+
break;
|
|
44848
45067
|
try {
|
|
44849
|
-
pending2
|
|
44850
|
-
|
|
44851
|
-
|
|
44852
|
-
|
|
45068
|
+
if (!pending2.body)
|
|
45069
|
+
throw new Error("body chunk received for bodyless request");
|
|
45070
|
+
const chunk = fromB64(frame.dataB64);
|
|
45071
|
+
pending2.receivedBytes += chunk.byteLength;
|
|
45072
|
+
if (pending2.receivedBytes > MAX_HTTP_REQUEST_BODY_BYTES) {
|
|
45073
|
+
throw new Error("relay HTTP request body limit exceeded");
|
|
45074
|
+
}
|
|
45075
|
+
pending2.bodyController?.enqueue(chunk);
|
|
45076
|
+
this.startPendingHttp(frame.id, pending2);
|
|
45077
|
+
} catch {
|
|
45078
|
+
pending2.abort.abort();
|
|
45079
|
+
this.pendingHttp.delete(frame.id);
|
|
45080
|
+
throw new Error("invalid or oversized relay HTTP request body");
|
|
45081
|
+
}
|
|
44853
45082
|
break;
|
|
44854
45083
|
}
|
|
44855
45084
|
case "http_req_end": {
|
|
@@ -44880,6 +45109,12 @@ class TunnelClient {
|
|
|
44880
45109
|
if (!bridged)
|
|
44881
45110
|
break;
|
|
44882
45111
|
if (!bridged.opened) {
|
|
45112
|
+
bridged.bufferedBytes += frame.text === undefined ? Math.floor((frame.dataB64 ?? "").length * 3 / 4) : Buffer.byteLength(frame.text, "utf8");
|
|
45113
|
+
if (bridged.bufferedBytes > MAX_PREOPEN_WEBSOCKET_BYTES) {
|
|
45114
|
+
this.bridgedSockets.delete(frame.id);
|
|
45115
|
+
bridged.ws.close(1009, "pre-open buffer limit exceeded");
|
|
45116
|
+
throw new Error("bridged WebSocket pre-open buffer limit exceeded");
|
|
45117
|
+
}
|
|
44883
45118
|
bridged.buffer.push(frame);
|
|
44884
45119
|
break;
|
|
44885
45120
|
}
|
|
@@ -44899,6 +45134,11 @@ class TunnelClient {
|
|
|
44899
45134
|
}
|
|
44900
45135
|
}
|
|
44901
45136
|
startHttpRequest(frame) {
|
|
45137
|
+
if (this.pendingHttp.has(frame.id))
|
|
45138
|
+
throw new Error("duplicate relay HTTP request id");
|
|
45139
|
+
if (this.pendingHttp.size >= MAX_IN_FLIGHT_HTTP_REQUESTS) {
|
|
45140
|
+
throw new Error("too many in-flight relay HTTP requests");
|
|
45141
|
+
}
|
|
44902
45142
|
const abort = new AbortController;
|
|
44903
45143
|
const headers = new Headers;
|
|
44904
45144
|
for (const [name, value] of frame.headers)
|
|
@@ -44910,7 +45150,8 @@ class TunnelClient {
|
|
|
44910
45150
|
method: frame.method,
|
|
44911
45151
|
path: frame.path,
|
|
44912
45152
|
headers,
|
|
44913
|
-
started: false
|
|
45153
|
+
started: false,
|
|
45154
|
+
receivedBytes: 0
|
|
44914
45155
|
};
|
|
44915
45156
|
if (frame.hasBody) {
|
|
44916
45157
|
pending2.body = new ReadableStream({
|
|
@@ -44971,6 +45212,11 @@ class TunnelClient {
|
|
|
44971
45212
|
}
|
|
44972
45213
|
}
|
|
44973
45214
|
openBridgedSocket(id, path, headers) {
|
|
45215
|
+
if (this.bridgedSockets.has(id))
|
|
45216
|
+
throw new Error("duplicate bridged WebSocket id");
|
|
45217
|
+
if (this.bridgedSockets.size >= MAX_BRIDGED_SOCKETS) {
|
|
45218
|
+
throw new Error("too many bridged WebSockets");
|
|
45219
|
+
}
|
|
44974
45220
|
const wsOrigin = this.opts.targetOrigin.replace(/^http/, "ws");
|
|
44975
45221
|
let local;
|
|
44976
45222
|
try {
|
|
@@ -44987,7 +45233,7 @@ class TunnelClient {
|
|
|
44987
45233
|
});
|
|
44988
45234
|
return;
|
|
44989
45235
|
}
|
|
44990
|
-
const bridged = { ws: local, opened: false, buffer: [] };
|
|
45236
|
+
const bridged = { ws: local, opened: false, buffer: [], bufferedBytes: 0 };
|
|
44991
45237
|
this.bridgedSockets.set(id, bridged);
|
|
44992
45238
|
local.onopen = () => {
|
|
44993
45239
|
bridged.opened = true;
|
|
@@ -44995,6 +45241,7 @@ class TunnelClient {
|
|
|
44995
45241
|
for (const frame of bridged.buffer)
|
|
44996
45242
|
this.deliverToLocal(local, frame);
|
|
44997
45243
|
bridged.buffer = [];
|
|
45244
|
+
bridged.bufferedBytes = 0;
|
|
44998
45245
|
};
|
|
44999
45246
|
local.onmessage = (event) => {
|
|
45000
45247
|
if (typeof event.data === "string") {
|
|
@@ -45026,11 +45273,14 @@ class TunnelClient {
|
|
|
45026
45273
|
local.send(fromB64(frame.dataB64));
|
|
45027
45274
|
}
|
|
45028
45275
|
}
|
|
45029
|
-
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;
|
|
45276
|
+
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;
|
|
45030
45277
|
var init_tunnel_client = __esm(() => {
|
|
45031
45278
|
init_relay_protocol();
|
|
45032
45279
|
MAX_WS_UPGRADE_HEADER_BYTES = 32 * 1024;
|
|
45033
45280
|
WS_PROTOCOL_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
45281
|
+
MAX_HTTP_REQUEST_BODY_BYTES = 16 * 1024 * 1024;
|
|
45282
|
+
MAX_PREOPEN_WEBSOCKET_BYTES = 1024 * 1024;
|
|
45283
|
+
MAX_TUNNEL_BUFFERED_AMOUNT = 8 * 1024 * 1024;
|
|
45034
45284
|
silentLogger = { info: noop, warn: noop, error: noop };
|
|
45035
45285
|
});
|
|
45036
45286
|
|
|
@@ -47339,4 +47589,4 @@ switch (command) {
|
|
|
47339
47589
|
}
|
|
47340
47590
|
}
|
|
47341
47591
|
|
|
47342
|
-
//# debugId=
|
|
47592
|
+
//# debugId=A95E28BED5799E3A64756E2164756E21
|