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/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.8.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: "runtime-gateway",
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: "runtime-gateway",
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
- var RUNTIME_GATEWAY_VERSION = 1, RUNTIME_GATEWAY_CONTROL_PATH = "/api/v1/control/runtime/v1";
30948
- var init_runtime_gateway = () => {};
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 > 2 || keys.some((key) => key !== "path" && key !== "mode")) {
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
- result.push(line(` \u25C7 visualization${mode} \xB7 ${visualization.name}`, {
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
- return submitUserMessage({
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 result = await this.#request(`/topics/${encodeURIComponent(topic.id)}/messages`, {
38939
- method: "POST",
38940
- body: JSON.stringify({ userId: this.#userId, text: text2 })
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 result.message;
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 = (queryId2) => {
44668
- targetByQueryId.set(queryId2, target);
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: queryId2 }) => {
44680
- if (queryId2)
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
- const { queryId } = submitUserMessage({
44688
- ...input,
44689
- onDispatched: rememberTarget,
44690
- startTurn: dispatchTurn
44691
- });
44692
- if (queryId)
44693
- rememberTarget(queryId);
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
- if (msg.authorId === userId && msg.sourceAdapter === "telegram")
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
- const response = await fetch(`${node.baseUrl}${NODE_CONTROL_BASE_PATH}/topics/${encodeURIComponent(input.topic.id)}/messages`, {
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 randomUUID28 } from "crypto";
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 = `${randomUUID28()}${randomUUID28()}`;
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 randomUUID29 } from "crypto";
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: randomUUID29() };
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}.${randomUUID29()}`;
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 record = parsed;
45806
- if (!Array.isArray(record.joins))
45807
- return [normalizeJoin(record)];
45808
- return record.joins.map((entry) => {
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}.${randomUUID29()}.tmp`);
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 randomUUID30 } from "crypto";
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 = randomUUID30();
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 randomUUID31 } from "crypto";
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-${randomUUID31()}`;
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 record = readCache()[join48.cellId];
46501
- if (!record || record.central !== join48.central || !record.workspaceId)
47012
+ const record2 = readCache()[join48.cellId];
47013
+ if (!record2 || record2.central !== join48.central || !record2.workspaceId)
46502
47014
  return null;
46503
- return surfaceScopeFor(record.central, record.workspaceId);
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 randomUUID32
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: randomUUID32(),
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}.${randomUUID32()}.tmp`);
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}.${randomUUID32()}.tmp`);
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=37C7DCC041D0DB9F64756E2164756E21
50465
+ //# debugId=5392FFAC60CD6CD864756E2164756E21