negotium 0.8.0 → 0.9.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 +2 -2
- package/dist/agent-helpers.js.map +4 -4
- package/dist/{chunk-1bfta5qh.js → chunk-ae0ya01v.js} +2 -2
- package/dist/{chunk-1bfta5qh.js.map → chunk-ae0ya01v.js.map} +2 -2
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +2 -2
- package/dist/main.js +593 -81
- package/dist/main.js.map +15 -15
- package/dist/mcp-factories.js +2 -2
- package/dist/mcp-factories.js.map +4 -4
- package/dist/query-runtime.js +1 -1
- package/dist/query-runtime.js.map +3 -3
- package/dist/registry.js +1 -1
- package/dist/runtime/src/application/submit-runtime-gateway-turn.ts +10 -6
- package/dist/runtime/src/identifiers.ts +21 -0
- package/dist/runtime/src/index.ts +10 -0
- package/dist/runtime/src/node-host.ts +7 -0
- package/dist/runtime/src/runtime-gateway.ts +19 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-gateway.js +6 -2
- package/dist/runtime-gateway.js.map +3 -3
- package/dist/types/packages/core/src/identifiers.d.ts +6 -0
- package/dist/types/packages/core/src/runtime-gateway.d.ts +5 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -3708,7 +3708,7 @@ var exports_version = {};
|
|
|
3708
3708
|
__export(exports_version, {
|
|
3709
3709
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
3710
3710
|
});
|
|
3711
|
-
var NEGOTIUM_VERSION = "0.
|
|
3711
|
+
var NEGOTIUM_VERSION = "0.9.0";
|
|
3712
3712
|
|
|
3713
3713
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
3714
3714
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -11518,6 +11518,21 @@ var init_manager2 = __esm(async () => {
|
|
|
11518
11518
|
});
|
|
11519
11519
|
|
|
11520
11520
|
// ../../packages/core/src/identifiers.ts
|
|
11521
|
+
function asUserId(value) {
|
|
11522
|
+
return value;
|
|
11523
|
+
}
|
|
11524
|
+
function asTopicId(value) {
|
|
11525
|
+
return value;
|
|
11526
|
+
}
|
|
11527
|
+
function asMessageId(value) {
|
|
11528
|
+
return value;
|
|
11529
|
+
}
|
|
11530
|
+
function asRequestId(value) {
|
|
11531
|
+
return value;
|
|
11532
|
+
}
|
|
11533
|
+
function asClientMessageId(value) {
|
|
11534
|
+
return value;
|
|
11535
|
+
}
|
|
11521
11536
|
function asTurnId(value) {
|
|
11522
11537
|
return value;
|
|
11523
11538
|
}
|
|
@@ -21535,12 +21550,13 @@ var init_runtime_gateway_submissions = __esm(async () => {
|
|
|
21535
21550
|
// ../../packages/core/src/application/submit-runtime-gateway-turn.ts
|
|
21536
21551
|
import { createHash as createHash9, randomUUID as randomUUID18 } from "crypto";
|
|
21537
21552
|
function duplicateResult(submission, params, requestId, actorUserId, payloadHash) {
|
|
21553
|
+
const sourceAdapter = params.sourceAdapter?.trim() || "runtime-gateway";
|
|
21538
21554
|
const message = getApiMessage(submission.topicId, submission.messageId) ?? (params.silent ? {
|
|
21539
21555
|
id: submission.messageId,
|
|
21540
21556
|
topicId: params.topic.id,
|
|
21541
21557
|
authorId: actorUserId,
|
|
21542
21558
|
authorName: params.actorLabel,
|
|
21543
|
-
sourceAdapter
|
|
21559
|
+
sourceAdapter,
|
|
21544
21560
|
sourceMessageId: params.clientMessageId,
|
|
21545
21561
|
text: params.text,
|
|
21546
21562
|
createdAt: submission.createdAt
|
|
@@ -21583,6 +21599,7 @@ function gatewayPayloadHash(params, requestId, actorUserId) {
|
|
|
21583
21599
|
function submitRuntimeGatewayTurn(params) {
|
|
21584
21600
|
const requestId = params.requestId ?? params.clientMessageId;
|
|
21585
21601
|
const actorUserId = params.actorUserId ?? params.userId;
|
|
21602
|
+
const sourceAdapter = params.sourceAdapter?.trim() || "runtime-gateway";
|
|
21586
21603
|
const respond = params.respond ?? true;
|
|
21587
21604
|
const payloadHash = gatewayPayloadHash(params, requestId, actorUserId);
|
|
21588
21605
|
const existing = findRuntimeGatewaySubmission(params.clientMessageId, requestId);
|
|
@@ -21603,7 +21620,7 @@ function submitRuntimeGatewayTurn(params) {
|
|
|
21603
21620
|
topicId: params.topic.id,
|
|
21604
21621
|
authorId: actorUserId,
|
|
21605
21622
|
authorName: params.actorLabel,
|
|
21606
|
-
sourceAdapter
|
|
21623
|
+
sourceAdapter,
|
|
21607
21624
|
sourceMessageId: params.clientMessageId,
|
|
21608
21625
|
text: params.text,
|
|
21609
21626
|
...attachments2?.length ? { attachments: attachments2 } : {},
|
|
@@ -24313,6 +24330,13 @@ __export(exports_src, {
|
|
|
24313
24330
|
bgBashContextCapability: () => bgBashContextCapability,
|
|
24314
24331
|
backgroundSessionProgress: () => backgroundSessionProgress,
|
|
24315
24332
|
attachmentPromptLine: () => attachmentPromptLine,
|
|
24333
|
+
asUserId: () => asUserId,
|
|
24334
|
+
asTurnSlotKey: () => asTurnSlotKey,
|
|
24335
|
+
asTurnId: () => asTurnId,
|
|
24336
|
+
asTopicId: () => asTopicId,
|
|
24337
|
+
asRequestId: () => asRequestId,
|
|
24338
|
+
asMessageId: () => asMessageId,
|
|
24339
|
+
asClientMessageId: () => asClientMessageId,
|
|
24316
24340
|
appendJsonlEntry: () => appendJsonlEntry,
|
|
24317
24341
|
appendApiMessage: () => appendApiMessage,
|
|
24318
24342
|
answerPendingAskUserQuestion: () => answerPendingAskUserQuestion,
|
|
@@ -24811,6 +24835,11 @@ __export(exports_node_host, {
|
|
|
24811
24835
|
earliestRuntimeEventSeq: () => earliestRuntimeEventSeq,
|
|
24812
24836
|
deleteVaultEntry: () => deleteVaultEntry,
|
|
24813
24837
|
compactTopicSession: () => compactTopicSession,
|
|
24838
|
+
asUserId: () => asUserId,
|
|
24839
|
+
asTopicId: () => asTopicId,
|
|
24840
|
+
asRequestId: () => asRequestId,
|
|
24841
|
+
asMessageId: () => asMessageId,
|
|
24842
|
+
asClientMessageId: () => asClientMessageId,
|
|
24814
24843
|
appendApiMessage: () => appendApiMessage,
|
|
24815
24844
|
acquireRuntimeProcessLease: () => acquireRuntimeProcessLease,
|
|
24816
24845
|
abortAllRooms: () => abortAllRooms,
|
|
@@ -30944,8 +30973,376 @@ var init_src3 = __esm(() => {
|
|
|
30944
30973
|
});
|
|
30945
30974
|
|
|
30946
30975
|
// ../../packages/core/src/runtime-gateway.ts
|
|
30947
|
-
|
|
30948
|
-
|
|
30976
|
+
function record(value) {
|
|
30977
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
30978
|
+
}
|
|
30979
|
+
async function json(response) {
|
|
30980
|
+
try {
|
|
30981
|
+
return await response.json();
|
|
30982
|
+
} catch {
|
|
30983
|
+
throw new RuntimeGatewayError("Runtime Gateway returned invalid JSON", "protocol", response.status);
|
|
30984
|
+
}
|
|
30985
|
+
}
|
|
30986
|
+
function validHealth(value) {
|
|
30987
|
+
const body = record(value);
|
|
30988
|
+
return Boolean(body?.ok === true && body.v === RUNTIME_GATEWAY_VERSION && Array.isArray(body.capabilities) && typeof body.cursor === "number");
|
|
30989
|
+
}
|
|
30990
|
+
function validAcknowledgedMessage(value) {
|
|
30991
|
+
const message = record(value);
|
|
30992
|
+
return Boolean(message && typeof message.id === "string" && typeof message.topicId === "string" && typeof message.authorId === "string" && typeof message.text === "string" && typeof message.createdAt === "string");
|
|
30993
|
+
}
|
|
30994
|
+
function validTurnAck(value) {
|
|
30995
|
+
const body = record(value);
|
|
30996
|
+
return Boolean(body?.ok === true && body.v === RUNTIME_GATEWAY_VERSION && body.accepted === true && typeof body.deduplicated === "boolean" && typeof body.requestId === "string" && typeof body.clientMessageId === "string" && typeof body.topicId === "string" && typeof body.messageId === "string" && (body.message === undefined || validAcknowledgedMessage(body.message)) && typeof body.cursor === "number");
|
|
30997
|
+
}
|
|
30998
|
+
function validManagerTopic(value) {
|
|
30999
|
+
const topic = record(value);
|
|
31000
|
+
return Boolean(typeof topic?.id === "string" && typeof topic.title === "string" && topic.kind === "manager" && Array.isArray(topic.participants));
|
|
31001
|
+
}
|
|
31002
|
+
function validDeletedMessage(value) {
|
|
31003
|
+
const message = record(value);
|
|
31004
|
+
return Boolean(typeof message?.id === "string" && typeof message.topicId === "string" && typeof message.authorId === "string" && typeof message.text === "string" && message.deleted === true && typeof message.createdAt === "string");
|
|
31005
|
+
}
|
|
31006
|
+
function validCronJob(value) {
|
|
31007
|
+
const job = record(value);
|
|
31008
|
+
return Boolean(typeof job?.id === "string" && typeof job.name === "string" && typeof job.executionPrincipalUserId === "string" && typeof job.actorOwnerUserId === "string" && typeof job.topicId === "string" && typeof job.schedule === "string" && typeof job.enabled === "boolean" && typeof job.nextRunAt === "string" && typeof job.canMutate === "boolean");
|
|
31009
|
+
}
|
|
31010
|
+
async function* parseRuntimeGatewaySse(body) {
|
|
31011
|
+
const reader = body.getReader();
|
|
31012
|
+
const decoder = new TextDecoder;
|
|
31013
|
+
let buffer = "";
|
|
31014
|
+
let event = "message";
|
|
31015
|
+
let id;
|
|
31016
|
+
let data = [];
|
|
31017
|
+
const flush = () => {
|
|
31018
|
+
if (data.length === 0)
|
|
31019
|
+
return null;
|
|
31020
|
+
const raw = data.join(`
|
|
31021
|
+
`);
|
|
31022
|
+
data = [];
|
|
31023
|
+
try {
|
|
31024
|
+
return { event, id, data: JSON.parse(raw) };
|
|
31025
|
+
} catch {
|
|
31026
|
+
throw new RuntimeGatewayError("Runtime Gateway SSE event has invalid JSON", "protocol");
|
|
31027
|
+
} finally {
|
|
31028
|
+
event = "message";
|
|
31029
|
+
id = undefined;
|
|
31030
|
+
}
|
|
31031
|
+
};
|
|
31032
|
+
try {
|
|
31033
|
+
while (true) {
|
|
31034
|
+
const chunk = await reader.read();
|
|
31035
|
+
if (chunk.done)
|
|
31036
|
+
break;
|
|
31037
|
+
buffer += decoder.decode(chunk.value, { stream: true }).replace(/\r\n/g, `
|
|
31038
|
+
`);
|
|
31039
|
+
let newline = buffer.indexOf(`
|
|
31040
|
+
`);
|
|
31041
|
+
while (newline >= 0) {
|
|
31042
|
+
const line = buffer.slice(0, newline);
|
|
31043
|
+
buffer = buffer.slice(newline + 1);
|
|
31044
|
+
if (line === "") {
|
|
31045
|
+
const parsed2 = flush();
|
|
31046
|
+
if (parsed2)
|
|
31047
|
+
yield parsed2;
|
|
31048
|
+
} else if (line.startsWith("event:")) {
|
|
31049
|
+
event = line.slice(6).trim() || "message";
|
|
31050
|
+
} else if (line.startsWith("id:")) {
|
|
31051
|
+
const parsed2 = Number.parseInt(line.slice(3).trim(), 10);
|
|
31052
|
+
if (Number.isFinite(parsed2))
|
|
31053
|
+
id = parsed2;
|
|
31054
|
+
} else if (line.startsWith("data:")) {
|
|
31055
|
+
data.push(line.slice(5).trimStart());
|
|
31056
|
+
}
|
|
31057
|
+
newline = buffer.indexOf(`
|
|
31058
|
+
`);
|
|
31059
|
+
}
|
|
31060
|
+
}
|
|
31061
|
+
buffer += decoder.decode();
|
|
31062
|
+
if (buffer.startsWith("data:"))
|
|
31063
|
+
data.push(buffer.slice(5).trimStart());
|
|
31064
|
+
const parsed = flush();
|
|
31065
|
+
if (parsed)
|
|
31066
|
+
yield parsed;
|
|
31067
|
+
} finally {
|
|
31068
|
+
reader.releaseLock();
|
|
31069
|
+
}
|
|
31070
|
+
}
|
|
31071
|
+
|
|
31072
|
+
class RuntimeGatewayClient {
|
|
31073
|
+
options;
|
|
31074
|
+
pathPrefix;
|
|
31075
|
+
request;
|
|
31076
|
+
requestTimeoutMs;
|
|
31077
|
+
compactTimeoutMs;
|
|
31078
|
+
constructor(options) {
|
|
31079
|
+
this.options = options;
|
|
31080
|
+
this.pathPrefix = options.pathPrefix ?? RUNTIME_GATEWAY_CONTROL_PATH;
|
|
31081
|
+
this.request = options.fetch ?? fetch;
|
|
31082
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
31083
|
+
this.compactTimeoutMs = options.compactTimeoutMs ?? 5 * 60000;
|
|
31084
|
+
}
|
|
31085
|
+
endpoint(path) {
|
|
31086
|
+
if (!this.options.baseUrl || !this.options.token) {
|
|
31087
|
+
throw new RuntimeGatewayError("Runtime Gateway is not configured", "config");
|
|
31088
|
+
}
|
|
31089
|
+
return `${this.options.baseUrl.replace(/\/+$/, "")}${this.pathPrefix}${path}`;
|
|
31090
|
+
}
|
|
31091
|
+
async authorization() {
|
|
31092
|
+
try {
|
|
31093
|
+
const token = typeof this.options.token === "function" ? await this.options.token() : this.options.token;
|
|
31094
|
+
return `Bearer ${token}`;
|
|
31095
|
+
} catch (error2) {
|
|
31096
|
+
throw new RuntimeGatewayError(error2 instanceof Error ? error2.message : "Runtime Gateway token resolution failed", "config");
|
|
31097
|
+
}
|
|
31098
|
+
}
|
|
31099
|
+
async send(path, init, timeoutMs) {
|
|
31100
|
+
const authorization = await this.authorization();
|
|
31101
|
+
try {
|
|
31102
|
+
return await this.request(this.endpoint(path), {
|
|
31103
|
+
...init,
|
|
31104
|
+
headers: { authorization, ...init.headers },
|
|
31105
|
+
signal: timeoutMs === undefined ? init.signal : AbortSignal.timeout(timeoutMs)
|
|
31106
|
+
});
|
|
31107
|
+
} catch (error2) {
|
|
31108
|
+
if (error2 instanceof DOMException && error2.name === "TimeoutError") {
|
|
31109
|
+
throw new RuntimeGatewayError("Runtime Gateway request timed out", "timeout");
|
|
31110
|
+
}
|
|
31111
|
+
throw new RuntimeGatewayError("Runtime Gateway request failed", "transport");
|
|
31112
|
+
}
|
|
31113
|
+
}
|
|
31114
|
+
async health() {
|
|
31115
|
+
const response = await this.send("/health", { method: "GET" }, this.requestTimeoutMs);
|
|
31116
|
+
if (!response.ok) {
|
|
31117
|
+
throw new RuntimeGatewayError("Runtime Gateway health request failed", "http", response.status);
|
|
31118
|
+
}
|
|
31119
|
+
const body = await json(response);
|
|
31120
|
+
if (!validHealth(body)) {
|
|
31121
|
+
throw new RuntimeGatewayError("Runtime Gateway health response is incompatible", "protocol");
|
|
31122
|
+
}
|
|
31123
|
+
return body;
|
|
31124
|
+
}
|
|
31125
|
+
async submitTurn(input) {
|
|
31126
|
+
const response = await this.send("/turns", {
|
|
31127
|
+
method: "POST",
|
|
31128
|
+
headers: { "content-type": "application/json" },
|
|
31129
|
+
body: JSON.stringify({ v: RUNTIME_GATEWAY_VERSION, ...input })
|
|
31130
|
+
}, this.requestTimeoutMs);
|
|
31131
|
+
if (response.status !== 202) {
|
|
31132
|
+
throw new RuntimeGatewayError("Runtime Gateway turn was not accepted", "http", response.status);
|
|
31133
|
+
}
|
|
31134
|
+
const body = await json(response);
|
|
31135
|
+
if (!validTurnAck(body)) {
|
|
31136
|
+
throw new RuntimeGatewayError("Runtime Gateway turn acknowledgement is incompatible", "protocol");
|
|
31137
|
+
}
|
|
31138
|
+
return body;
|
|
31139
|
+
}
|
|
31140
|
+
async deriveTopic(topicId, input) {
|
|
31141
|
+
const response = await this.send(`/topics/${encodeURIComponent(topicId)}/derive`, {
|
|
31142
|
+
method: "POST",
|
|
31143
|
+
headers: { "content-type": "application/json" },
|
|
31144
|
+
body: JSON.stringify({ v: RUNTIME_GATEWAY_VERSION, ...input })
|
|
31145
|
+
}, this.requestTimeoutMs);
|
|
31146
|
+
if (response.status !== 201) {
|
|
31147
|
+
throw new RuntimeGatewayError("Runtime Gateway topic derive failed", "http", response.status);
|
|
31148
|
+
}
|
|
31149
|
+
const body = await json(response);
|
|
31150
|
+
const topic = record(body)?.topic;
|
|
31151
|
+
const topicRecord = record(topic);
|
|
31152
|
+
if (!topicRecord || typeof topicRecord.id !== "string" || typeof topicRecord.title !== "string") {
|
|
31153
|
+
throw new RuntimeGatewayError("Runtime Gateway topic derive response is incompatible", "protocol");
|
|
31154
|
+
}
|
|
31155
|
+
return topic;
|
|
31156
|
+
}
|
|
31157
|
+
async ensureManagerTopic(userId) {
|
|
31158
|
+
const response = await this.send("/manager-topic", {
|
|
31159
|
+
method: "POST",
|
|
31160
|
+
headers: { "content-type": "application/json" },
|
|
31161
|
+
body: JSON.stringify({ v: RUNTIME_GATEWAY_VERSION, userId })
|
|
31162
|
+
}, this.requestTimeoutMs);
|
|
31163
|
+
if (!response.ok) {
|
|
31164
|
+
throw new RuntimeGatewayError("Runtime Gateway manager topic request failed", "http", response.status);
|
|
31165
|
+
}
|
|
31166
|
+
const body = record(await json(response));
|
|
31167
|
+
if (body?.ok !== true || body.v !== RUNTIME_GATEWAY_VERSION || !validManagerTopic(body.topic)) {
|
|
31168
|
+
throw new RuntimeGatewayError("Runtime Gateway manager topic response is incompatible", "protocol");
|
|
31169
|
+
}
|
|
31170
|
+
return body.topic;
|
|
31171
|
+
}
|
|
31172
|
+
async deleteMessage(topicId, messageId, actorUserId, allowAdmin = false) {
|
|
31173
|
+
const response = await this.send(`/topics/${encodeURIComponent(topicId)}/messages/${encodeURIComponent(messageId)}`, {
|
|
31174
|
+
method: "DELETE",
|
|
31175
|
+
headers: { "content-type": "application/json" },
|
|
31176
|
+
body: JSON.stringify({
|
|
31177
|
+
v: RUNTIME_GATEWAY_VERSION,
|
|
31178
|
+
actorUserId,
|
|
31179
|
+
...allowAdmin ? { allowAdmin: true } : {}
|
|
31180
|
+
})
|
|
31181
|
+
}, this.requestTimeoutMs);
|
|
31182
|
+
if (!response.ok) {
|
|
31183
|
+
throw new RuntimeGatewayError("Runtime Gateway message delete failed", "http", response.status);
|
|
31184
|
+
}
|
|
31185
|
+
const body = record(await json(response));
|
|
31186
|
+
if (body?.ok !== true || body.v !== RUNTIME_GATEWAY_VERSION || !validDeletedMessage(body.message)) {
|
|
31187
|
+
throw new RuntimeGatewayError("Runtime Gateway message delete response is incompatible", "protocol");
|
|
31188
|
+
}
|
|
31189
|
+
return body.message;
|
|
31190
|
+
}
|
|
31191
|
+
async cronRequest(path, init) {
|
|
31192
|
+
const response = await this.send(path, init, this.requestTimeoutMs);
|
|
31193
|
+
if (!response.ok) {
|
|
31194
|
+
throw new RuntimeGatewayError("Runtime Gateway cron request failed", "http", response.status);
|
|
31195
|
+
}
|
|
31196
|
+
const body = record(await json(response));
|
|
31197
|
+
if (body?.ok !== true || body.v !== RUNTIME_GATEWAY_VERSION) {
|
|
31198
|
+
throw new RuntimeGatewayError("Runtime Gateway cron response is incompatible", "protocol");
|
|
31199
|
+
}
|
|
31200
|
+
return body;
|
|
31201
|
+
}
|
|
31202
|
+
async listCronScripts() {
|
|
31203
|
+
const body = await this.cronRequest("/cron/scripts", { method: "GET" });
|
|
31204
|
+
if (!Array.isArray(body.scripts) || !body.scripts.every((value) => typeof value === "string")) {
|
|
31205
|
+
throw new RuntimeGatewayError("Runtime Gateway cron scripts are incompatible", "protocol");
|
|
31206
|
+
}
|
|
31207
|
+
return body.scripts;
|
|
31208
|
+
}
|
|
31209
|
+
async listCronJobs(userId, actorUserId, actorIsAdmin = false) {
|
|
31210
|
+
const search = new URLSearchParams({
|
|
31211
|
+
user: userId,
|
|
31212
|
+
actorUserId,
|
|
31213
|
+
actorIsAdmin: actorIsAdmin ? "1" : "0"
|
|
31214
|
+
});
|
|
31215
|
+
const body = await this.cronRequest(`/cron/jobs?${search}`, { method: "GET" });
|
|
31216
|
+
if (!Array.isArray(body.jobs) || !body.jobs.every(validCronJob)) {
|
|
31217
|
+
throw new RuntimeGatewayError("Runtime Gateway cron jobs are incompatible", "protocol");
|
|
31218
|
+
}
|
|
31219
|
+
return body.jobs;
|
|
31220
|
+
}
|
|
31221
|
+
async createCronJob(input) {
|
|
31222
|
+
const body = await this.cronRequest("/cron/jobs", {
|
|
31223
|
+
method: "POST",
|
|
31224
|
+
headers: { "content-type": "application/json" },
|
|
31225
|
+
body: JSON.stringify({ v: RUNTIME_GATEWAY_VERSION, ...input })
|
|
31226
|
+
});
|
|
31227
|
+
if (!validCronJob(body.job)) {
|
|
31228
|
+
throw new RuntimeGatewayError("Runtime Gateway cron job is incompatible", "protocol");
|
|
31229
|
+
}
|
|
31230
|
+
return body.job;
|
|
31231
|
+
}
|
|
31232
|
+
async updateCronJob(jobId, userId, actorUserId, patch, actorIsAdmin = false) {
|
|
31233
|
+
const body = await this.cronRequest(`/cron/jobs/${encodeURIComponent(jobId)}`, {
|
|
31234
|
+
method: "PATCH",
|
|
31235
|
+
headers: { "content-type": "application/json" },
|
|
31236
|
+
body: JSON.stringify({
|
|
31237
|
+
v: RUNTIME_GATEWAY_VERSION,
|
|
31238
|
+
userId,
|
|
31239
|
+
actorUserId,
|
|
31240
|
+
actorIsAdmin,
|
|
31241
|
+
patch
|
|
31242
|
+
})
|
|
31243
|
+
});
|
|
31244
|
+
if (!validCronJob(body.job)) {
|
|
31245
|
+
throw new RuntimeGatewayError("Runtime Gateway cron job is incompatible", "protocol");
|
|
31246
|
+
}
|
|
31247
|
+
return body.job;
|
|
31248
|
+
}
|
|
31249
|
+
async deleteCronJob(jobId, userId, actorUserId, actorIsAdmin = false) {
|
|
31250
|
+
const search = new URLSearchParams({
|
|
31251
|
+
user: userId,
|
|
31252
|
+
actorUserId,
|
|
31253
|
+
actorIsAdmin: actorIsAdmin ? "1" : "0"
|
|
31254
|
+
});
|
|
31255
|
+
const body = await this.cronRequest(`/cron/jobs/${encodeURIComponent(jobId)}?${search}`, {
|
|
31256
|
+
method: "DELETE"
|
|
31257
|
+
});
|
|
31258
|
+
if (typeof body.deleted !== "string") {
|
|
31259
|
+
throw new RuntimeGatewayError("Runtime Gateway cron delete is incompatible", "protocol");
|
|
31260
|
+
}
|
|
31261
|
+
return body.deleted;
|
|
31262
|
+
}
|
|
31263
|
+
async* events(after, topicId, signal) {
|
|
31264
|
+
const search = new URLSearchParams({ after: String(Math.max(0, after)) });
|
|
31265
|
+
if (topicId)
|
|
31266
|
+
search.set("topicId", topicId);
|
|
31267
|
+
const response = await this.send(`/events?${search}`, { method: "GET", signal });
|
|
31268
|
+
if (!response.ok || !response.body) {
|
|
31269
|
+
throw new RuntimeGatewayError("Runtime Gateway event stream failed", "http", response.status);
|
|
31270
|
+
}
|
|
31271
|
+
yield* parseRuntimeGatewaySse(response.body);
|
|
31272
|
+
}
|
|
31273
|
+
async getTopicUsage(topicId, userId) {
|
|
31274
|
+
const response = await this.send(`/topics/${encodeURIComponent(topicId)}/usage?user=${encodeURIComponent(userId)}`, { method: "GET" }, this.requestTimeoutMs);
|
|
31275
|
+
if (!response.ok) {
|
|
31276
|
+
throw new RuntimeGatewayError("Runtime Gateway topic usage request failed", "http", response.status);
|
|
31277
|
+
}
|
|
31278
|
+
const usage = record(record(await json(response))?.usage);
|
|
31279
|
+
const read = (key) => {
|
|
31280
|
+
const value = usage?.[key];
|
|
31281
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
31282
|
+
};
|
|
31283
|
+
return {
|
|
31284
|
+
queries: read("queries"),
|
|
31285
|
+
inputTokens: read("inputTokens"),
|
|
31286
|
+
outputTokens: read("outputTokens"),
|
|
31287
|
+
cacheCreationInputTokens: read("cacheCreationInputTokens"),
|
|
31288
|
+
cacheReadInputTokens: read("cacheReadInputTokens"),
|
|
31289
|
+
estimatedCostUsd: read("estimatedCostUsd")
|
|
31290
|
+
};
|
|
31291
|
+
}
|
|
31292
|
+
async abortTurn(topicId, userId) {
|
|
31293
|
+
const response = await this.send(`/topics/${encodeURIComponent(topicId)}/abort`, {
|
|
31294
|
+
method: "POST",
|
|
31295
|
+
headers: { "content-type": "application/json" },
|
|
31296
|
+
body: JSON.stringify({ v: RUNTIME_GATEWAY_VERSION, userId })
|
|
31297
|
+
}, this.requestTimeoutMs);
|
|
31298
|
+
if (!response.ok) {
|
|
31299
|
+
throw new RuntimeGatewayError("Runtime Gateway turn abort failed", "http", response.status);
|
|
31300
|
+
}
|
|
31301
|
+
const body = record(await json(response));
|
|
31302
|
+
if (body?.ok !== true || body.v !== RUNTIME_GATEWAY_VERSION || typeof body.aborted !== "boolean") {
|
|
31303
|
+
throw new RuntimeGatewayError("Runtime Gateway turn abort response is incompatible", "protocol");
|
|
31304
|
+
}
|
|
31305
|
+
return body.aborted;
|
|
31306
|
+
}
|
|
31307
|
+
async resetSession(topicId, userId, reason, actorUserId) {
|
|
31308
|
+
return this.sessionCommand(topicId, userId, "reset", reason, actorUserId);
|
|
31309
|
+
}
|
|
31310
|
+
async compactSession(topicId, userId, reason, actorUserId) {
|
|
31311
|
+
return this.sessionCommand(topicId, userId, "compact", reason, actorUserId);
|
|
31312
|
+
}
|
|
31313
|
+
async sessionCommand(topicId, userId, command, reason, actorUserId) {
|
|
31314
|
+
const response = await this.send(`/topics/${encodeURIComponent(topicId)}/session/${command}`, {
|
|
31315
|
+
method: "POST",
|
|
31316
|
+
headers: { "content-type": "application/json" },
|
|
31317
|
+
body: JSON.stringify({
|
|
31318
|
+
v: RUNTIME_GATEWAY_VERSION,
|
|
31319
|
+
userId,
|
|
31320
|
+
...actorUserId ? { actorUserId } : {},
|
|
31321
|
+
...reason ? { reason } : {}
|
|
31322
|
+
})
|
|
31323
|
+
}, command === "compact" ? this.compactTimeoutMs : this.requestTimeoutMs);
|
|
31324
|
+
if (!response.ok) {
|
|
31325
|
+
throw new RuntimeGatewayError(`Runtime Gateway session ${command} failed`, "http", response.status);
|
|
31326
|
+
}
|
|
31327
|
+
const body = record(await json(response));
|
|
31328
|
+
if (body?.ok !== true || body.v !== RUNTIME_GATEWAY_VERSION) {
|
|
31329
|
+
throw new RuntimeGatewayError(`Runtime Gateway session ${command} response is incompatible`, "protocol");
|
|
31330
|
+
}
|
|
31331
|
+
return typeof body.result === "string" ? body.result : undefined;
|
|
31332
|
+
}
|
|
31333
|
+
}
|
|
31334
|
+
var RUNTIME_GATEWAY_VERSION = 1, RUNTIME_GATEWAY_CONTROL_PATH = "/api/v1/control/runtime/v1", RuntimeGatewayError;
|
|
31335
|
+
var init_runtime_gateway = __esm(() => {
|
|
31336
|
+
RuntimeGatewayError = class RuntimeGatewayError extends Error {
|
|
31337
|
+
kind;
|
|
31338
|
+
status;
|
|
31339
|
+
constructor(message, kind, status) {
|
|
31340
|
+
super(message);
|
|
31341
|
+
this.kind = kind;
|
|
31342
|
+
this.status = status;
|
|
31343
|
+
}
|
|
31344
|
+
};
|
|
31345
|
+
});
|
|
30949
31346
|
|
|
30950
31347
|
// ../../packages/core/src/cron-host.ts
|
|
30951
31348
|
var init_cron_host = __esm(async () => {
|
|
@@ -33528,21 +33925,22 @@ function createNodeControlHandler(options) {
|
|
|
33528
33925
|
const body = await bodyRecord(req);
|
|
33529
33926
|
if (body.v !== NODE_RUNTIME_CONTRACT_VERSION)
|
|
33530
33927
|
return jsonError(400, "Unsupported v");
|
|
33531
|
-
const topicId = requiredText(body.topicId, "topicId");
|
|
33928
|
+
const topicId = asTopicId(requiredText(body.topicId, "topicId"));
|
|
33532
33929
|
const turnTopic = getTopic(topicId);
|
|
33533
33930
|
if (turnTopic && !topicInRequestScope(req, turnTopic)) {
|
|
33534
33931
|
return jsonError(404, "Topic not found");
|
|
33535
33932
|
}
|
|
33536
|
-
const userId = requiredText(body.userId, "userId");
|
|
33537
|
-
const actorUserId = body.actorUserId === undefined ? undefined : requiredText(body.actorUserId, "actorUserId");
|
|
33933
|
+
const userId = asUserId(requiredText(body.userId, "userId"));
|
|
33934
|
+
const actorUserId = body.actorUserId === undefined ? undefined : asUserId(requiredText(body.actorUserId, "actorUserId"));
|
|
33538
33935
|
const actorLabel = body.actorLabel === undefined ? undefined : requiredText(body.actorLabel, "actorLabel");
|
|
33539
|
-
const vaultUserId = body.vaultUserId === undefined ? undefined : requiredText(body.vaultUserId, "vaultUserId");
|
|
33936
|
+
const vaultUserId = body.vaultUserId === undefined ? undefined : asUserId(requiredText(body.vaultUserId, "vaultUserId"));
|
|
33937
|
+
const sourceAdapter = body.sourceAdapter === undefined ? undefined : requiredText(body.sourceAdapter, "sourceAdapter");
|
|
33540
33938
|
if (typeof body.text !== "string")
|
|
33541
33939
|
throw new ControlRequestError("text is required");
|
|
33542
33940
|
const text2 = body.text;
|
|
33543
|
-
const clientMessageId = requiredText(body.clientMessageId, "clientMessageId");
|
|
33544
|
-
const requestId = body.requestId === undefined ? undefined : requiredText(body.requestId, "requestId");
|
|
33545
|
-
const threadRootId = body.threadRootId === undefined ? undefined : requiredText(body.threadRootId, "threadRootId");
|
|
33941
|
+
const clientMessageId = asClientMessageId(requiredText(body.clientMessageId, "clientMessageId"));
|
|
33942
|
+
const requestId = body.requestId === undefined ? undefined : asRequestId(requiredText(body.requestId, "requestId"));
|
|
33943
|
+
const threadRootId = body.threadRootId === undefined ? undefined : asMessageId(requiredText(body.threadRootId, "threadRootId"));
|
|
33546
33944
|
const attachments2 = body.attachments === undefined ? [] : Array.isArray(body.attachments) && body.attachments.every((value) => typeof value === "string" && value.trim()) ? body.attachments : (() => {
|
|
33547
33945
|
throw new ControlRequestError("attachments must be an array of file ids");
|
|
33548
33946
|
})();
|
|
@@ -33570,6 +33968,7 @@ function createNodeControlHandler(options) {
|
|
|
33570
33968
|
actorUserId,
|
|
33571
33969
|
actorLabel,
|
|
33572
33970
|
vaultUserId,
|
|
33971
|
+
sourceAdapter,
|
|
33573
33972
|
text: text2,
|
|
33574
33973
|
clientMessageId,
|
|
33575
33974
|
requestId,
|
|
@@ -33590,6 +33989,7 @@ function createNodeControlHandler(options) {
|
|
|
33590
33989
|
clientMessageId: submission.clientMessageId,
|
|
33591
33990
|
topicId: submission.topicId,
|
|
33592
33991
|
messageId: submission.messageId,
|
|
33992
|
+
message: submission.message,
|
|
33593
33993
|
cursor: submission.ackCursor
|
|
33594
33994
|
}, { status: 202 });
|
|
33595
33995
|
}
|
|
@@ -36454,7 +36854,7 @@ function parseVisualizationReference(value) {
|
|
|
36454
36854
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
36455
36855
|
return null;
|
|
36456
36856
|
const keys = Object.keys(parsed);
|
|
36457
|
-
if (keys.length < 1 || keys.length >
|
|
36857
|
+
if (keys.length < 1 || keys.length > 3 || keys.some((key) => key !== "path" && key !== "mode" && key !== "title")) {
|
|
36458
36858
|
return null;
|
|
36459
36859
|
}
|
|
36460
36860
|
const candidate = parsed;
|
|
@@ -36463,13 +36863,17 @@ function parseVisualizationReference(value) {
|
|
|
36463
36863
|
}
|
|
36464
36864
|
if (candidate.mode !== undefined && candidate.mode !== "wide")
|
|
36465
36865
|
return null;
|
|
36866
|
+
if (candidate.title !== undefined && (typeof candidate.title !== "string" || candidate.title.length === 0 || candidate.title.length > MAX_VISUALIZATION_TITLE_LENGTH || hasControlCharacter(candidate.title))) {
|
|
36867
|
+
return null;
|
|
36868
|
+
}
|
|
36466
36869
|
return {
|
|
36467
36870
|
path: candidate.path,
|
|
36468
36871
|
name: basename12(candidate.path) || candidate.path,
|
|
36469
|
-
...candidate.mode === "wide" ? { mode: "wide" } : {}
|
|
36872
|
+
...candidate.mode === "wide" ? { mode: "wide" } : {},
|
|
36873
|
+
...typeof candidate.title === "string" ? { title: candidate.title } : {}
|
|
36470
36874
|
};
|
|
36471
36875
|
}
|
|
36472
|
-
var VISUALIZE_PREFIX = "\uE200visualize\uE202", VISUALIZE_SUFFIX = "\uE201", MAX_VISUALIZATION_REFERENCE_LENGTH = 8192, MAX_VISUALIZATION_PATH_LENGTH = 4096;
|
|
36876
|
+
var VISUALIZE_PREFIX = "\uE200visualize\uE202", VISUALIZE_SUFFIX = "\uE201", MAX_VISUALIZATION_REFERENCE_LENGTH = 8192, MAX_VISUALIZATION_PATH_LENGTH = 4096, MAX_VISUALIZATION_TITLE_LENGTH = 200;
|
|
36473
36877
|
var init_visualization = () => {};
|
|
36474
36878
|
|
|
36475
36879
|
// ../../adapters/terminal/src/render.ts
|
|
@@ -36920,7 +37324,8 @@ function renderMarkdown(value, width) {
|
|
|
36920
37324
|
if (visualization) {
|
|
36921
37325
|
flushTable();
|
|
36922
37326
|
const mode = visualization.mode ? ` \xB7 ${visualization.mode}` : "";
|
|
36923
|
-
|
|
37327
|
+
const label = visualization.title ?? visualization.name;
|
|
37328
|
+
result.push(line(` \u25C7 visualization${mode} \xB7 ${label}`, {
|
|
36924
37329
|
fg: theme.cyan,
|
|
36925
37330
|
bg: theme.surfaceRaised,
|
|
36926
37331
|
bold: true
|
|
@@ -38614,6 +39019,22 @@ __export(exports_client, {
|
|
|
38614
39019
|
INITIAL_MESSAGE_HISTORY_LIMIT: () => INITIAL_MESSAGE_HISTORY_LIMIT,
|
|
38615
39020
|
EmbeddedNegotiumClient: () => EmbeddedNegotiumClient
|
|
38616
39021
|
});
|
|
39022
|
+
import { randomUUID as randomUUID28 } from "crypto";
|
|
39023
|
+
function terminalClientMessageId() {
|
|
39024
|
+
return `terminal:${randomUUID28()}`;
|
|
39025
|
+
}
|
|
39026
|
+
function retryableGatewaySubmission(error2) {
|
|
39027
|
+
return error2 instanceof RuntimeGatewayError && (error2.kind === "transport" || error2.kind === "timeout" || error2.kind === "http" && (error2.status ?? 0) >= 500);
|
|
39028
|
+
}
|
|
39029
|
+
async function submitTerminalGatewayTurn(gateway, input) {
|
|
39030
|
+
try {
|
|
39031
|
+
return await gateway.submitTurn(input);
|
|
39032
|
+
} catch (error2) {
|
|
39033
|
+
if (!retryableGatewaySubmission(error2))
|
|
39034
|
+
throw error2;
|
|
39035
|
+
return gateway.submitTurn(input);
|
|
39036
|
+
}
|
|
39037
|
+
}
|
|
38617
39038
|
|
|
38618
39039
|
class EmbeddedNegotiumClient {
|
|
38619
39040
|
#userId;
|
|
@@ -38743,11 +39164,14 @@ class EmbeddedNegotiumClient {
|
|
|
38743
39164
|
await topicService.delete({ topicId: topic.id, userId: this.#userId });
|
|
38744
39165
|
}
|
|
38745
39166
|
sendMessage(topic, text2) {
|
|
38746
|
-
|
|
39167
|
+
const clientMessageId = terminalClientMessageId();
|
|
39168
|
+
return submitRuntimeGatewayTurn({
|
|
38747
39169
|
topic,
|
|
38748
39170
|
userId: this.#userId,
|
|
38749
39171
|
text: text2,
|
|
38750
39172
|
sourceAdapter: "terminal",
|
|
39173
|
+
clientMessageId,
|
|
39174
|
+
requestId: clientMessageId,
|
|
38751
39175
|
visualTools: false,
|
|
38752
39176
|
fileDeliveryTools: false
|
|
38753
39177
|
}).message;
|
|
@@ -38808,6 +39232,7 @@ class RemoteNegotiumClient {
|
|
|
38808
39232
|
#userId;
|
|
38809
39233
|
#baseUrl;
|
|
38810
39234
|
#token;
|
|
39235
|
+
#gateway;
|
|
38811
39236
|
#onEvent = null;
|
|
38812
39237
|
#eventAbort = null;
|
|
38813
39238
|
#eventTask = null;
|
|
@@ -38819,6 +39244,7 @@ class RemoteNegotiumClient {
|
|
|
38819
39244
|
throw new Error("Remote node control requires HTTPS or loopback HTTP");
|
|
38820
39245
|
}
|
|
38821
39246
|
this.#token = options.token;
|
|
39247
|
+
this.#gateway = new RuntimeGatewayClient({ baseUrl: this.#baseUrl, token: this.#token });
|
|
38822
39248
|
}
|
|
38823
39249
|
async start(onEvent) {
|
|
38824
39250
|
if (this.#started)
|
|
@@ -38935,11 +39361,26 @@ class RemoteNegotiumClient {
|
|
|
38935
39361
|
await this.#request(`/topics/${encodeURIComponent(topic.id)}?user=${encodeURIComponent(this.#userId)}`, { method: "DELETE" });
|
|
38936
39362
|
}
|
|
38937
39363
|
async sendMessage(topic, text2) {
|
|
38938
|
-
const
|
|
38939
|
-
|
|
38940
|
-
|
|
39364
|
+
const clientMessageId = terminalClientMessageId();
|
|
39365
|
+
const acknowledgement = await submitTerminalGatewayTurn(this.#gateway, {
|
|
39366
|
+
topicId: topic.id,
|
|
39367
|
+
userId: this.#userId,
|
|
39368
|
+
sourceAdapter: "terminal",
|
|
39369
|
+
text: text2,
|
|
39370
|
+
clientMessageId,
|
|
39371
|
+
requestId: clientMessageId,
|
|
39372
|
+
visualTools: false,
|
|
39373
|
+
fileDeliveryTools: false
|
|
38941
39374
|
});
|
|
38942
|
-
return
|
|
39375
|
+
return acknowledgement.message ?? {
|
|
39376
|
+
id: acknowledgement.messageId,
|
|
39377
|
+
topicId: topic.id,
|
|
39378
|
+
authorId: this.#userId,
|
|
39379
|
+
sourceAdapter: "terminal",
|
|
39380
|
+
sourceMessageId: clientMessageId,
|
|
39381
|
+
text: text2,
|
|
39382
|
+
createdAt: new Date().toISOString()
|
|
39383
|
+
};
|
|
38943
39384
|
}
|
|
38944
39385
|
async answerQuestion(topicId, messageId, label) {
|
|
38945
39386
|
try {
|
|
@@ -39119,6 +39560,7 @@ class RemoteNegotiumClient {
|
|
|
39119
39560
|
var MESSAGE_HISTORY_PAGE_SIZE = 50, INITIAL_MESSAGE_HISTORY_PAGE_COUNT = 3, INITIAL_MESSAGE_HISTORY_LIMIT;
|
|
39120
39561
|
var init_client = __esm(async () => {
|
|
39121
39562
|
await init_src();
|
|
39563
|
+
init_runtime_gateway();
|
|
39122
39564
|
await init_storage_public();
|
|
39123
39565
|
await init_src5();
|
|
39124
39566
|
await init_history_store();
|
|
@@ -43227,7 +43669,7 @@ function createTelegramMediaIntake(options) {
|
|
|
43227
43669
|
if (typeof client.getFileLink !== "function") {
|
|
43228
43670
|
logger.warn({ chatId }, "telegram adapter: media message but client lacks getFileLink \u2014 caption only");
|
|
43229
43671
|
if (caption)
|
|
43230
|
-
runTurn(topic, caption, chatId, threadId);
|
|
43672
|
+
runTurn(topic, caption, chatId, threadId, msg);
|
|
43231
43673
|
else
|
|
43232
43674
|
reply(chatId, threadId, "this bot cannot download attachments");
|
|
43233
43675
|
return;
|
|
@@ -43260,7 +43702,7 @@ ${transcript}`;
|
|
|
43260
43702
|
${caption}` : voiceText : caption;
|
|
43261
43703
|
if (!userText && promptLines.length === 0)
|
|
43262
43704
|
return;
|
|
43263
|
-
runTurn(topic, composeAttachmentPrompt(userText, promptLines), chatId, threadId);
|
|
43705
|
+
runTurn(topic, composeAttachmentPrompt(userText, promptLines), chatId, threadId, msg);
|
|
43264
43706
|
}
|
|
43265
43707
|
function flushGroup(key) {
|
|
43266
43708
|
const entry = mediaGroups.get(key);
|
|
@@ -43301,13 +43743,20 @@ ${caption}` : voiceText : caption;
|
|
|
43301
43743
|
}
|
|
43302
43744
|
async function handleGroupFlush(entry) {
|
|
43303
43745
|
const { messages, chatId, threadId } = entry;
|
|
43746
|
+
const sourceMessage = messages.reduce((earliest, message) => {
|
|
43747
|
+
if (!Number.isSafeInteger(message.message_id))
|
|
43748
|
+
return earliest;
|
|
43749
|
+
if (!earliest || !Number.isSafeInteger(earliest.message_id))
|
|
43750
|
+
return message;
|
|
43751
|
+
return message.message_id < earliest.message_id ? message : earliest;
|
|
43752
|
+
}, undefined) ?? messages[0];
|
|
43304
43753
|
const topic = resolveTopic(chatId, threadId);
|
|
43305
43754
|
const captions = messages.map((message) => (message.text ?? message.caption ?? "").trim()).filter((caption) => caption.length > 0);
|
|
43306
43755
|
if (typeof client.getFileLink !== "function") {
|
|
43307
43756
|
logger.warn({ chatId }, "telegram adapter: media group but client lacks getFileLink \u2014 captions only");
|
|
43308
43757
|
if (captions.length > 0)
|
|
43309
43758
|
runTurn(topic, captions.join(`
|
|
43310
|
-
`), chatId, threadId);
|
|
43759
|
+
`), chatId, threadId, sourceMessage);
|
|
43311
43760
|
else
|
|
43312
43761
|
reply(chatId, threadId, "this bot cannot download attachments");
|
|
43313
43762
|
return;
|
|
@@ -43327,7 +43776,7 @@ ${caption}` : voiceText : caption;
|
|
|
43327
43776
|
`);
|
|
43328
43777
|
if (!userText && promptLines.length === 0)
|
|
43329
43778
|
return;
|
|
43330
|
-
runTurn(topic, composeAttachmentPrompt(userText, promptLines), chatId, threadId);
|
|
43779
|
+
runTurn(topic, composeAttachmentPrompt(userText, promptLines), chatId, threadId, sourceMessage);
|
|
43331
43780
|
}
|
|
43332
43781
|
function stop() {
|
|
43333
43782
|
for (const entry of mediaGroups.values()) {
|
|
@@ -43403,6 +43852,7 @@ function renderOutbound(text2, maxLen = 4096) {
|
|
|
43403
43852
|
}
|
|
43404
43853
|
|
|
43405
43854
|
// ../../adapters/telegram/src/adapter.ts
|
|
43855
|
+
import { randomUUID as randomUUID29 } from "crypto";
|
|
43406
43856
|
import { existsSync as existsSync37 } from "fs";
|
|
43407
43857
|
import { basename as basename13, extname as extname6 } from "path";
|
|
43408
43858
|
function telegramGroupScope(chatId) {
|
|
@@ -43414,6 +43864,15 @@ function telegramGroupIdFromScope(scope) {
|
|
|
43414
43864
|
const chatId = Number(scope.slice(3));
|
|
43415
43865
|
return Number.isSafeInteger(chatId) ? chatId : null;
|
|
43416
43866
|
}
|
|
43867
|
+
function telegramClientMessageId(msg, chatId, threadId) {
|
|
43868
|
+
const messageId = msg?.message_id;
|
|
43869
|
+
const source = msg?.media_group_id ? Number.isSafeInteger(messageId) ? `album:${msg.media_group_id}:${messageId}` : `album:${msg.media_group_id}:legacy:${randomUUID29()}` : Number.isSafeInteger(messageId) ? `message:${messageId}` : `legacy:${randomUUID29()}`;
|
|
43870
|
+
return `telegram:${chatId}:${threadId ?? "main"}:${source}`;
|
|
43871
|
+
}
|
|
43872
|
+
function telegramActorLabel(msg) {
|
|
43873
|
+
const username = msg?.from?.username?.trim().replace(/^@/, "");
|
|
43874
|
+
return username ? `@${username}` : undefined;
|
|
43875
|
+
}
|
|
43417
43876
|
function startTelegramAdapter(opts) {
|
|
43418
43877
|
const { client, forumChatId } = opts;
|
|
43419
43878
|
const userId = opts.userId ?? "local";
|
|
@@ -43429,7 +43888,6 @@ function startTelegramAdapter(opts) {
|
|
|
43429
43888
|
const sendTimeoutMs = opts.sendTimeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;
|
|
43430
43889
|
const typingHeartbeatMs = Math.max(250, opts.typingHeartbeatMs ?? 4000);
|
|
43431
43890
|
const footerEnabled = opts.footer === true;
|
|
43432
|
-
const dispatchTurn = opts.startTurn ?? startAiTurn;
|
|
43433
43891
|
const store = openMappingStore(opts.mappingDbPath);
|
|
43434
43892
|
const restoredForumChatId = store.loadForumChatId();
|
|
43435
43893
|
if (forumChatId !== undefined) {
|
|
@@ -44658,39 +45116,78 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44658
45116
|
}
|
|
44659
45117
|
}
|
|
44660
45118
|
verifyInitialForumPermissions();
|
|
44661
|
-
function runTurn(topic, prompt, chatId, threadId) {
|
|
45119
|
+
function runTurn(topic, prompt, chatId, threadId, sourceMessage) {
|
|
44662
45120
|
const target = {
|
|
44663
45121
|
topicId: topic.id,
|
|
44664
45122
|
chatId,
|
|
44665
45123
|
...threadId !== undefined ? { threadId } : {}
|
|
44666
45124
|
};
|
|
44667
|
-
const rememberTarget = (
|
|
44668
|
-
targetByQueryId.set(
|
|
45125
|
+
const rememberTarget = (queryId) => {
|
|
45126
|
+
targetByQueryId.set(queryId, target);
|
|
44669
45127
|
};
|
|
45128
|
+
const actorLabel = telegramActorLabel(sourceMessage);
|
|
44670
45129
|
const input = {
|
|
44671
45130
|
topic,
|
|
44672
45131
|
userId,
|
|
45132
|
+
clientMessageId: telegramClientMessageId(sourceMessage, chatId, threadId),
|
|
45133
|
+
...actorLabel ? { actorLabel } : {},
|
|
44673
45134
|
text: prompt,
|
|
44674
45135
|
sourceAdapter: "telegram",
|
|
44675
45136
|
visualTools: false,
|
|
44676
45137
|
fileDeliveryTools: true
|
|
44677
45138
|
};
|
|
45139
|
+
const provisionalQueryId = input.clientMessageId;
|
|
45140
|
+
rememberTarget(provisionalQueryId);
|
|
45141
|
+
const adoptQueryId = (queryId) => {
|
|
45142
|
+
if (!queryId)
|
|
45143
|
+
return;
|
|
45144
|
+
if (queryId !== provisionalQueryId && targetByQueryId.get(provisionalQueryId) === target) {
|
|
45145
|
+
targetByQueryId.delete(provisionalQueryId);
|
|
45146
|
+
}
|
|
45147
|
+
rememberTarget(queryId);
|
|
45148
|
+
};
|
|
45149
|
+
const removeProvisionalTarget = () => {
|
|
45150
|
+
if (targetByQueryId.get(provisionalQueryId) === target) {
|
|
45151
|
+
targetByQueryId.delete(provisionalQueryId);
|
|
45152
|
+
}
|
|
45153
|
+
};
|
|
44678
45154
|
if (opts.submitTurn) {
|
|
44679
|
-
opts.submitTurn(input).then(({ queryId
|
|
44680
|
-
|
|
44681
|
-
rememberTarget(queryId2);
|
|
45155
|
+
opts.submitTurn(input).then(({ queryId }) => {
|
|
45156
|
+
adoptQueryId(queryId ?? provisionalQueryId);
|
|
44682
45157
|
}).catch((error2) => {
|
|
45158
|
+
const mayHaveCommitted = error2 instanceof RuntimeGatewayError && (error2.kind === "transport" || error2.kind === "timeout" || error2.kind === "http" && (error2.status ?? 0) >= 500);
|
|
45159
|
+
if (mayHaveCommitted) {
|
|
45160
|
+
const timer = setTimeout(removeProvisionalTarget, 60 * 60000);
|
|
45161
|
+
timer.unref?.();
|
|
45162
|
+
} else {
|
|
45163
|
+
removeProvisionalTarget();
|
|
45164
|
+
}
|
|
44683
45165
|
logger.error({ err: error2, topicId: topic.id }, "telegram adapter: remote turn failed");
|
|
44684
45166
|
});
|
|
44685
45167
|
return;
|
|
44686
45168
|
}
|
|
44687
|
-
|
|
44688
|
-
|
|
44689
|
-
|
|
44690
|
-
|
|
44691
|
-
|
|
44692
|
-
|
|
44693
|
-
|
|
45169
|
+
if (opts.startTurn) {
|
|
45170
|
+
const { queryId } = submitUserMessage({
|
|
45171
|
+
...input,
|
|
45172
|
+
onDispatched: adoptQueryId,
|
|
45173
|
+
startTurn: opts.startTurn
|
|
45174
|
+
});
|
|
45175
|
+
if (queryId)
|
|
45176
|
+
adoptQueryId(queryId);
|
|
45177
|
+
else
|
|
45178
|
+
removeProvisionalTarget();
|
|
45179
|
+
return;
|
|
45180
|
+
}
|
|
45181
|
+
try {
|
|
45182
|
+
const submission = submitRuntimeGatewayTurn({
|
|
45183
|
+
...input,
|
|
45184
|
+
requestId: input.clientMessageId
|
|
45185
|
+
});
|
|
45186
|
+
adoptQueryId(submission.requestId);
|
|
45187
|
+
} catch (error2) {
|
|
45188
|
+
removeProvisionalTarget();
|
|
45189
|
+
throw error2;
|
|
45190
|
+
}
|
|
44694
45191
|
}
|
|
44695
45192
|
const mediaIntake = createTelegramMediaIntake({
|
|
44696
45193
|
client,
|
|
@@ -44760,7 +45257,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44760
45257
|
}
|
|
44761
45258
|
if (!text2)
|
|
44762
45259
|
return;
|
|
44763
|
-
mediaIntake.enqueue(chatId, threadId, () => runTurn(resolveMapping(chatId, threadId), text2, chatId, threadId));
|
|
45260
|
+
mediaIntake.enqueue(chatId, threadId, () => runTurn(resolveMapping(chatId, threadId), text2, chatId, threadId, msg));
|
|
44764
45261
|
}
|
|
44765
45262
|
client.on("message", (msg) => {
|
|
44766
45263
|
if (stopped)
|
|
@@ -44803,7 +45300,8 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44803
45300
|
});
|
|
44804
45301
|
async function deliverPersistedRuntimeMessage(event) {
|
|
44805
45302
|
const msg = event.payload;
|
|
44806
|
-
|
|
45303
|
+
const isTelegramOrigin = msg.sourceAdapter === "telegram" || msg.sourceAdapter === "runtime-gateway" && msg.sourceMessageId?.startsWith("telegram:");
|
|
45304
|
+
if (msg.authorId === userId && isTelegramOrigin)
|
|
44807
45305
|
return true;
|
|
44808
45306
|
if (msg.kind === "tool")
|
|
44809
45307
|
return true;
|
|
@@ -44990,6 +45488,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
44990
45488
|
var SURFACE_BACKFILL_FLAG = "surface_backfill_20260808", GROUP_SCOPE_BACKFILL_FLAG = "telegram_group_scope_backfill_20260829", FORUM_TOPIC_NAME_MAX = 128, MAX_PARENT_HOPS = 5, DEFAULT_SEND_TIMEOUT_MS = 60000, PHOTO_EXTS;
|
|
44991
45489
|
var init_adapter = __esm(async () => {
|
|
44992
45490
|
await init_src();
|
|
45491
|
+
init_runtime_gateway();
|
|
44993
45492
|
await init_commands2();
|
|
44994
45493
|
await init_mapping_store();
|
|
44995
45494
|
await init_media_intake();
|
|
@@ -45021,11 +45520,40 @@ var init_src7 = __esm(async () => {
|
|
|
45021
45520
|
// ../../adapters/telegram/src/cli.ts
|
|
45022
45521
|
var exports_cli2 = {};
|
|
45023
45522
|
__export(exports_cli2, {
|
|
45523
|
+
submitTelegramTurnToNode: () => submitTelegramTurnToNode,
|
|
45024
45524
|
startTelegramFromEnv: () => startTelegramFromEnv,
|
|
45025
45525
|
runTelegramCli: () => runTelegramCli,
|
|
45026
45526
|
installTelegramNodeFileHooks: () => installTelegramNodeFileHooks
|
|
45027
45527
|
});
|
|
45028
45528
|
import TelegramBot from "node-telegram-bot-api";
|
|
45529
|
+
async function submitTelegramTurnToNode(node, input, fetchRequest) {
|
|
45530
|
+
const gateway = new RuntimeGatewayClient({
|
|
45531
|
+
baseUrl: node.baseUrl,
|
|
45532
|
+
token: node.token,
|
|
45533
|
+
...fetchRequest ? { fetch: fetchRequest } : {}
|
|
45534
|
+
});
|
|
45535
|
+
const turn = {
|
|
45536
|
+
topicId: input.topic.id,
|
|
45537
|
+
userId: input.userId,
|
|
45538
|
+
...input.actorLabel ? { actorLabel: input.actorLabel } : {},
|
|
45539
|
+
sourceAdapter: input.sourceAdapter,
|
|
45540
|
+
text: input.text,
|
|
45541
|
+
clientMessageId: input.clientMessageId,
|
|
45542
|
+
requestId: input.clientMessageId,
|
|
45543
|
+
visualTools: input.visualTools,
|
|
45544
|
+
fileDeliveryTools: input.fileDeliveryTools
|
|
45545
|
+
};
|
|
45546
|
+
let acknowledgement;
|
|
45547
|
+
try {
|
|
45548
|
+
acknowledgement = await gateway.submitTurn(turn);
|
|
45549
|
+
} catch (error2) {
|
|
45550
|
+
const retryable = error2 instanceof RuntimeGatewayError && (error2.kind === "transport" || error2.kind === "timeout" || error2.kind === "http" && (error2.status ?? 0) >= 500);
|
|
45551
|
+
if (!retryable)
|
|
45552
|
+
throw error2;
|
|
45553
|
+
acknowledgement = await gateway.submitTurn(turn);
|
|
45554
|
+
}
|
|
45555
|
+
return { queryId: acknowledgement.requestId };
|
|
45556
|
+
}
|
|
45029
45557
|
function installTelegramNodeFileHooks() {
|
|
45030
45558
|
setFileHooks(nodeFileStore.hooks);
|
|
45031
45559
|
}
|
|
@@ -45127,24 +45655,7 @@ async function runTelegramCli(args = process.argv.slice(2)) {
|
|
|
45127
45655
|
},
|
|
45128
45656
|
submitTurn: async (input) => {
|
|
45129
45657
|
const node = await waitForNodeDaemon(1500);
|
|
45130
|
-
|
|
45131
|
-
method: "POST",
|
|
45132
|
-
headers: {
|
|
45133
|
-
authorization: `Bearer ${NODE_CONTROL_TOKEN}`,
|
|
45134
|
-
"content-type": "application/json"
|
|
45135
|
-
},
|
|
45136
|
-
body: JSON.stringify({
|
|
45137
|
-
userId: input.userId,
|
|
45138
|
-
text: input.text,
|
|
45139
|
-
sourceAdapter: input.sourceAdapter,
|
|
45140
|
-
visualTools: input.visualTools,
|
|
45141
|
-
fileDeliveryTools: input.fileDeliveryTools
|
|
45142
|
-
})
|
|
45143
|
-
});
|
|
45144
|
-
const body = await response.json();
|
|
45145
|
-
if (!response.ok)
|
|
45146
|
-
throw new Error(body.error ?? `node returned HTTP ${response.status}`);
|
|
45147
|
-
return { queryId: body.queryId };
|
|
45658
|
+
return submitTelegramTurnToNode(node, input);
|
|
45148
45659
|
}
|
|
45149
45660
|
});
|
|
45150
45661
|
} catch (error2) {
|
|
@@ -45164,6 +45675,7 @@ async function runTelegramCli(args = process.argv.slice(2)) {
|
|
|
45164
45675
|
}
|
|
45165
45676
|
var init_cli2 = __esm(async () => {
|
|
45166
45677
|
await init_src();
|
|
45678
|
+
init_runtime_gateway();
|
|
45167
45679
|
await init_src5();
|
|
45168
45680
|
init_env_auth();
|
|
45169
45681
|
await init_src7();
|
|
@@ -45378,7 +45890,7 @@ var init_protocol = __esm(() => {
|
|
|
45378
45890
|
});
|
|
45379
45891
|
|
|
45380
45892
|
// ../../adapters/otium/src/canonical-mcp-bridge.ts
|
|
45381
|
-
import { randomUUID as
|
|
45893
|
+
import { randomUUID as randomUUID30 } from "crypto";
|
|
45382
45894
|
function readAuthorization(request) {
|
|
45383
45895
|
const value = request.headers.get("authorization");
|
|
45384
45896
|
return value?.startsWith("Bearer ") ? value.slice(7) : null;
|
|
@@ -45519,7 +46031,7 @@ function startCanonicalMcpBridge(options = {}) {
|
|
|
45519
46031
|
const url = `http://127.0.0.1:${server.port}/`;
|
|
45520
46032
|
const unregister = registerCanonicalMcpBridgeEnvProvider((scope) => {
|
|
45521
46033
|
sweep();
|
|
45522
|
-
const token = `${
|
|
46034
|
+
const token = `${randomUUID30()}${randomUUID30()}`;
|
|
45523
46035
|
capabilities.set(token, {
|
|
45524
46036
|
surface: scope.surface,
|
|
45525
46037
|
userId: scope.userId,
|
|
@@ -45629,7 +46141,7 @@ __export(exports_join, {
|
|
|
45629
46141
|
joinCredentialDigest: () => joinCredentialDigest,
|
|
45630
46142
|
isJoinPersisted: () => isJoinPersisted
|
|
45631
46143
|
});
|
|
45632
|
-
import { createHash as createHash12, randomUUID as
|
|
46144
|
+
import { createHash as createHash12, randomUUID as randomUUID31 } from "crypto";
|
|
45633
46145
|
import {
|
|
45634
46146
|
chmodSync as chmodSync7,
|
|
45635
46147
|
closeSync as closeSync5,
|
|
@@ -45718,7 +46230,7 @@ function processIsAlive(pid) {
|
|
|
45718
46230
|
function withJoinCredentialLock(operation) {
|
|
45719
46231
|
const lockPath = joinLockPath();
|
|
45720
46232
|
const ownerPath = resolve25(lockPath, "owner.json");
|
|
45721
|
-
const owner = { pid: process.pid, token:
|
|
46233
|
+
const owner = { pid: process.pid, token: randomUUID31() };
|
|
45722
46234
|
mkdirSync34(dirname23(lockPath), { recursive: true });
|
|
45723
46235
|
for (let attempt = 0;; attempt += 1) {
|
|
45724
46236
|
let created = false;
|
|
@@ -45759,7 +46271,7 @@ function withJoinCredentialLock(operation) {
|
|
|
45759
46271
|
if (attempt > 0) {
|
|
45760
46272
|
throw new Error(`could not recover stale Otium join credential lock at ${lockPath}`);
|
|
45761
46273
|
}
|
|
45762
|
-
const stalePath = `${lockPath}.stale.${process.pid}.${
|
|
46274
|
+
const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID31()}`;
|
|
45763
46275
|
try {
|
|
45764
46276
|
renameSync17(lockPath, stalePath);
|
|
45765
46277
|
rmSync11(stalePath, { recursive: true, force: true });
|
|
@@ -45802,10 +46314,10 @@ function readPersistedJoins(path = joinFilePath()) {
|
|
|
45802
46314
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
45803
46315
|
throw new Error("persisted join credentials are not a JSON object");
|
|
45804
46316
|
}
|
|
45805
|
-
const
|
|
45806
|
-
if (!Array.isArray(
|
|
45807
|
-
return [normalizeJoin(
|
|
45808
|
-
return
|
|
46317
|
+
const record2 = parsed;
|
|
46318
|
+
if (!Array.isArray(record2.joins))
|
|
46319
|
+
return [normalizeJoin(record2)];
|
|
46320
|
+
return record2.joins.map((entry) => {
|
|
45809
46321
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
45810
46322
|
throw new Error("persisted join credentials contain a non-object entry");
|
|
45811
46323
|
}
|
|
@@ -45831,7 +46343,7 @@ function fsyncPath(target) {
|
|
|
45831
46343
|
function writeJoins(joins, allowOverwrite) {
|
|
45832
46344
|
const path = joinFilePath();
|
|
45833
46345
|
const directory = dirname23(path);
|
|
45834
|
-
const temporaryPath = resolve25(directory, `.otium-join.json.${process.pid}.${
|
|
46346
|
+
const temporaryPath = resolve25(directory, `.otium-join.json.${process.pid}.${randomUUID31()}.tmp`);
|
|
45835
46347
|
const payload = { v: JOIN_FILE_VERSION, joins };
|
|
45836
46348
|
let fd;
|
|
45837
46349
|
try {
|
|
@@ -45956,7 +46468,7 @@ var init_join = __esm(async () => {
|
|
|
45956
46468
|
});
|
|
45957
46469
|
|
|
45958
46470
|
// ../../adapters/otium/src/peer-files.ts
|
|
45959
|
-
import { randomUUID as
|
|
46471
|
+
import { randomUUID as randomUUID32 } from "crypto";
|
|
45960
46472
|
import { copyFileSync as copyFileSync5, mkdirSync as mkdirSync35, rmSync as rmSync12, statSync as statSync21 } from "fs";
|
|
45961
46473
|
import { basename as basename14, extname as extname7, join as join47 } from "path";
|
|
45962
46474
|
function fileType(mimeType) {
|
|
@@ -46022,7 +46534,7 @@ function recordFile(args) {
|
|
|
46022
46534
|
});
|
|
46023
46535
|
}
|
|
46024
46536
|
function insertLocalFile(args) {
|
|
46025
|
-
const id =
|
|
46537
|
+
const id = randomUUID32();
|
|
46026
46538
|
mkdirSync35(PEER_FILES_DIR, { recursive: true });
|
|
46027
46539
|
const path = join47(PEER_FILES_DIR, `${id}-${safeFilename(args.filename)}`);
|
|
46028
46540
|
copyFileSync5(args.sourcePath, path);
|
|
@@ -46086,7 +46598,7 @@ var init_peer_files = __esm(async () => {
|
|
|
46086
46598
|
});
|
|
46087
46599
|
|
|
46088
46600
|
// ../../adapters/otium/src/runtime-bridge.ts
|
|
46089
|
-
import { randomUUID as
|
|
46601
|
+
import { randomUUID as randomUUID33 } from "crypto";
|
|
46090
46602
|
function isMcpToolResult(value) {
|
|
46091
46603
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
46092
46604
|
return false;
|
|
@@ -46148,7 +46660,7 @@ var init_runtime_bridge = __esm(async () => {
|
|
|
46148
46660
|
} catch (error2) {
|
|
46149
46661
|
return errorResult(`Error: Failed to open hub question: ${error2.message}`);
|
|
46150
46662
|
}
|
|
46151
|
-
const bridgeRequestId = `bridge-ask-${
|
|
46663
|
+
const bridgeRequestId = `bridge-ask-${randomUUID33()}`;
|
|
46152
46664
|
const baseUrl = hubNode.baseUrl.replace(/\/+$/, "");
|
|
46153
46665
|
const post = async (path, body) => {
|
|
46154
46666
|
const response = await fetch(`${baseUrl}${path}`, {
|
|
@@ -46497,10 +47009,10 @@ function readCache() {
|
|
|
46497
47009
|
}
|
|
46498
47010
|
}
|
|
46499
47011
|
function cachedSurfaceScope(join48) {
|
|
46500
|
-
const
|
|
46501
|
-
if (!
|
|
47012
|
+
const record2 = readCache()[join48.cellId];
|
|
47013
|
+
if (!record2 || record2.central !== join48.central || !record2.workspaceId)
|
|
46502
47014
|
return null;
|
|
46503
|
-
return surfaceScopeFor(
|
|
47015
|
+
return surfaceScopeFor(record2.central, record2.workspaceId);
|
|
46504
47016
|
}
|
|
46505
47017
|
function cacheSurfaceScope(join48, workspaceId) {
|
|
46506
47018
|
const scope = surfaceScopeFor(join48.central, workspaceId);
|
|
@@ -47629,7 +48141,7 @@ import {
|
|
|
47629
48141
|
diffieHellman,
|
|
47630
48142
|
generateKeyPairSync,
|
|
47631
48143
|
hkdfSync,
|
|
47632
|
-
randomUUID as
|
|
48144
|
+
randomUUID as randomUUID34
|
|
47633
48145
|
} from "crypto";
|
|
47634
48146
|
import {
|
|
47635
48147
|
chmodSync as chmodSync8,
|
|
@@ -47689,13 +48201,13 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
47689
48201
|
const pair = generateKeyPairSync("x25519");
|
|
47690
48202
|
const pending2 = {
|
|
47691
48203
|
...invite,
|
|
47692
|
-
idempotencyKey:
|
|
48204
|
+
idempotencyKey: randomUUID34(),
|
|
47693
48205
|
privateKey: pair.privateKey.export({ format: "der", type: "pkcs8" }).toString("base64url"),
|
|
47694
48206
|
publicKey: pair.publicKey.export({ format: "der", type: "spki" }).toString("base64url"),
|
|
47695
48207
|
...nodeName ? { nodeName } : {}
|
|
47696
48208
|
};
|
|
47697
48209
|
mkdirSync37(dirname25(path), { recursive: true });
|
|
47698
|
-
const temporaryPath = resolve27(dirname25(path), `.otium-enrollment-pending.json.${process.pid}.${
|
|
48210
|
+
const temporaryPath = resolve27(dirname25(path), `.otium-enrollment-pending.json.${process.pid}.${randomUUID34()}.tmp`);
|
|
47699
48211
|
let fd;
|
|
47700
48212
|
try {
|
|
47701
48213
|
fd = openSync6(temporaryPath, "wx", 384);
|
|
@@ -47730,7 +48242,7 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
47730
48242
|
function replacePendingEnrollment(pending2) {
|
|
47731
48243
|
const path = pendingEnrollmentPath();
|
|
47732
48244
|
const directory = dirname25(path);
|
|
47733
|
-
const temporaryPath = resolve27(directory, `.otium-enrollment-pending.json.${process.pid}.${
|
|
48245
|
+
const temporaryPath = resolve27(directory, `.otium-enrollment-pending.json.${process.pid}.${randomUUID34()}.tmp`);
|
|
47734
48246
|
let fd;
|
|
47735
48247
|
try {
|
|
47736
48248
|
fd = openSync6(temporaryPath, "wx", 384);
|
|
@@ -49950,4 +50462,4 @@ switch (command) {
|
|
|
49950
50462
|
}
|
|
49951
50463
|
}
|
|
49952
50464
|
|
|
49953
|
-
//# debugId=
|
|
50465
|
+
//# debugId=5392FFAC60CD6CD864756E2164756E21
|