@agentrific/server 0.1.6 → 0.2.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/index.js CHANGED
@@ -492,11 +492,18 @@ var CreateSessionSchema = z2.object({
492
492
  var SendMessageSchema = z2.object({
493
493
  message: z2.string().trim().max(2e4),
494
494
  attachmentIds: AttachmentIdsSchema.optional(),
495
- clientMessageId: z2.string().min(1).max(120).optional()
495
+ clientMessageId: z2.string().min(1).max(120).optional(),
496
+ mode: z2.enum(["followUp", "steer"]).optional()
496
497
  }).refine(
497
498
  (input) => input.message.length > 0 || (input.attachmentIds?.length ?? 0) > 0,
498
499
  "Write a message or attach a file."
499
500
  );
501
+ var FileChangeSchema = z2.object({
502
+ path: z2.string(),
503
+ patch: z2.string().optional(),
504
+ content: z2.string().optional(),
505
+ omitted: z2.boolean().optional()
506
+ });
500
507
  var SessionEventSchema = z2.discriminatedUnion("type", [
501
508
  z2.object({ type: z2.literal("session.updated"), session: SessionSchema }),
502
509
  z2.object({
@@ -531,7 +538,8 @@ var SessionEventSchema = z2.discriminatedUnion("type", [
531
538
  sessionId: z2.string(),
532
539
  toolCallId: z2.string().optional(),
533
540
  tool: z2.string(),
534
- input: z2.string()
541
+ input: z2.string(),
542
+ filePath: z2.string().optional()
535
543
  }),
536
544
  z2.object({
537
545
  type: z2.literal("tool.completed"),
@@ -539,6 +547,7 @@ var SessionEventSchema = z2.discriminatedUnion("type", [
539
547
  toolCallId: z2.string().optional(),
540
548
  tool: z2.string(),
541
549
  output: z2.string(),
550
+ fileChange: FileChangeSchema.optional(),
542
551
  isError: z2.boolean().default(false)
543
552
  }),
544
553
  z2.object({
@@ -1081,7 +1090,7 @@ async function startControl(directory, security2, status, maintenance2) {
1081
1090
  // package.json
1082
1091
  var package_default = {
1083
1092
  name: "@agentrific/server",
1084
- version: "0.1.6",
1093
+ version: "0.2.0",
1085
1094
  description: "Self-hosted control plane for long-running coding agents",
1086
1095
  keywords: [
1087
1096
  "agentrific",
@@ -1118,6 +1127,7 @@ var package_default = {
1118
1127
  "@fastify/cors": "^11.3.0",
1119
1128
  "@fastify/multipart": "^10.1.2",
1120
1129
  "@inquirer/select": "^5.2.5",
1130
+ diff: "^9.0.0",
1121
1131
  effect: "4.0.0-rc.117",
1122
1132
  fastify: "^5.6.2",
1123
1133
  "pino-pretty": "^13.1.3",
@@ -1467,7 +1477,7 @@ var UpdateDiscovery = class {
1467
1477
 
1468
1478
  // src/index.ts
1469
1479
  import { Effect as Effect16, ManagedRuntime } from "effect";
1470
- import { z as z16 } from "zod";
1480
+ import { z as z17 } from "zod";
1471
1481
 
1472
1482
  // src/automation.ts
1473
1483
  import { Effect as Effect7 } from "effect";
@@ -1829,7 +1839,7 @@ var AgentController = class {
1829
1839
  Effect8.ensuring(Effect8.sync(() => this.working.delete(entry.session.id)))
1830
1840
  );
1831
1841
  }
1832
- send(session, message, attachments2 = [], messageId = randomUUID4()) {
1842
+ send(session, message, attachments2 = [], messageId = randomUUID4(), mode = "followUp") {
1833
1843
  return this.lock(session.id).withPermit(
1834
1844
  Effect8.gen({ self: this }, function* () {
1835
1845
  if (this.closed)
@@ -1839,6 +1849,16 @@ var AgentController = class {
1839
1849
  if (this.hasMessage(session.id, messageId)) return;
1840
1850
  const entry = yield* this.open(session);
1841
1851
  yield* this.operation(async () => entry.agent.validateAttachments?.(attachments2));
1852
+ const steering = entry.running && mode === "steer";
1853
+ if (steering) {
1854
+ if (!entry.agent.steer)
1855
+ return yield* Effect8.fail(
1856
+ new AgentError({ message: "This agent does not support steering." })
1857
+ );
1858
+ yield* this.operation(
1859
+ () => entry.agent.steer(gitFlowPrompt(entry.session, message), attachments2)
1860
+ );
1861
+ }
1842
1862
  this.emit({
1843
1863
  type: "message.user",
1844
1864
  sessionId: session.id,
@@ -1846,6 +1866,7 @@ var AgentController = class {
1846
1866
  text: message,
1847
1867
  attachments: attachments2
1848
1868
  });
1869
+ if (steering) return;
1849
1870
  if (entry.running) {
1850
1871
  entry.pending.push({ text: message, attachments: attachments2 });
1851
1872
  return;
@@ -2749,7 +2770,7 @@ import {
2749
2770
  createAgentSession as createAgentSession2,
2750
2771
  SessionManager as SessionManager2
2751
2772
  } from "@earendil-works/pi-coding-agent";
2752
- import { z as z12 } from "zod";
2773
+ import { z as z13 } from "zod";
2753
2774
 
2754
2775
  // src/delivery-tool.ts
2755
2776
  import { defineTool } from "@earendil-works/pi-coding-agent";
@@ -2783,9 +2804,70 @@ function deliveryTool(sessionId, delivery2) {
2783
2804
  });
2784
2805
  }
2785
2806
 
2807
+ // src/file-change.ts
2808
+ import { createWriteToolDefinition, defineTool as defineTool2 } from "@earendil-works/pi-coding-agent";
2809
+ import { createTwoFilesPatch } from "diff";
2810
+ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
2811
+ import { z as z12 } from "zod";
2812
+ var previewLimit = 256e3;
2813
+ function boundFileChange(change) {
2814
+ if ((change.patch?.length ?? 0) + (change.content?.length ?? 0) > previewLimit)
2815
+ return { path: change.path, omitted: true };
2816
+ return change;
2817
+ }
2818
+ var EditResultSchema = z12.object({
2819
+ details: z12.object({ patch: z12.string().optional(), fileChange: FileChangeSchema.optional() }).optional()
2820
+ });
2821
+ function completedFileChange(result, path10) {
2822
+ const parsed = EditResultSchema.safeParse(result);
2823
+ if (!parsed.success) return;
2824
+ const details = parsed.data.details;
2825
+ if (details?.fileChange) return boundFileChange(details.fileChange);
2826
+ if (path10 && details?.patch) return boundFileChange({ path: path10, patch: details.patch });
2827
+ }
2828
+ function fileWriteTool(cwd) {
2829
+ const base = createWriteToolDefinition(cwd);
2830
+ return defineTool2({
2831
+ name: base.name,
2832
+ label: base.label,
2833
+ description: base.description,
2834
+ promptSnippet: base.promptSnippet,
2835
+ promptGuidelines: base.promptGuidelines,
2836
+ parameters: base.parameters,
2837
+ constrainedSampling: base.constrainedSampling,
2838
+ async execute(toolCallId, args, signal, _onUpdate, ctx) {
2839
+ let fileChange;
2840
+ const tool = createWriteToolDefinition(cwd, {
2841
+ operations: {
2842
+ mkdir: async (dir) => {
2843
+ await mkdir4(dir, { recursive: true });
2844
+ },
2845
+ // Pi invokes this inside its per-file mutation queue, so the snapshot
2846
+ // and write cannot race another built-in edit/write on the same file.
2847
+ writeFile: async (path10, content) => {
2848
+ const previous = await readFile4(path10, "utf8").catch((error) => {
2849
+ if (error.code === "ENOENT") return void 0;
2850
+ throw error;
2851
+ });
2852
+ await writeFile2(path10, content, "utf8");
2853
+ fileChange = boundFileChange(
2854
+ previous === void 0 ? { path: args.path, content } : {
2855
+ path: args.path,
2856
+ patch: createTwoFilesPatch(args.path, args.path, previous, content)
2857
+ }
2858
+ );
2859
+ }
2860
+ }
2861
+ });
2862
+ const result = await tool.execute(toolCallId, args, signal, void 0, ctx);
2863
+ return { ...result, details: { fileChange } };
2864
+ }
2865
+ });
2866
+ }
2867
+
2786
2868
  // src/pi.ts
2787
- var ToolResultSchema = z12.object({
2788
- content: z12.array(z12.object({ type: z12.string(), text: z12.string().optional() })).optional()
2869
+ var ToolResultSchema = z13.object({
2870
+ content: z13.array(z13.object({ type: z13.string(), text: z13.string().optional() })).optional()
2789
2871
  }).passthrough();
2790
2872
  var boundedJson = (value, limit) => {
2791
2873
  let text;
@@ -2810,7 +2892,10 @@ function createPiFactory(files, models2, delivery2, createSession = createAgentS
2810
2892
  model,
2811
2893
  modelRuntime: models2.runtime,
2812
2894
  sessionManager: SessionManager2.continueRecent(cwd, sessionDirectory),
2813
- customTools: run?.gitFlow && delivery2 ? [deliveryTool(sessionId, delivery2)] : []
2895
+ customTools: [
2896
+ fileWriteTool(cwd),
2897
+ ...run?.gitFlow && delivery2 ? [deliveryTool(sessionId, delivery2)] : []
2898
+ ]
2814
2899
  });
2815
2900
  return {
2816
2901
  get model() {
@@ -2834,6 +2919,12 @@ function createPiFactory(files, models2, delivery2, createSession = createAgentS
2834
2919
  throw new Error(last.errorMessage ?? "The model request failed");
2835
2920
  }
2836
2921
  },
2922
+ async steer(message, attachments2 = []) {
2923
+ const context = await Effect12.runPromise(files.prepare(attachments2));
2924
+ if (!session.isStreaming)
2925
+ throw new Error("The response has finished. Send this message as a follow-up instead.");
2926
+ await session.steer(message + context.context, context.images);
2927
+ },
2837
2928
  async abort() {
2838
2929
  session.clearQueue();
2839
2930
  await session.abort();
@@ -2898,16 +2989,23 @@ function createPiFactory(files, models2, delivery2, createSession = createAgentS
2898
2989
  }
2899
2990
  return false;
2900
2991
  }
2992
+ const filePaths = /* @__PURE__ */ new Map();
2993
+ const FileArgsSchema = z13.object({ path: z13.string() });
2901
2994
  function handleTool(event) {
2902
2995
  if (event.type === "tool_execution_start") {
2903
2996
  flushText();
2904
2997
  setActivity("thinking");
2998
+ if (event.toolName === "edit" || event.toolName === "write") {
2999
+ const args = FileArgsSchema.safeParse(event.args);
3000
+ if (args.success) filePaths.set(event.toolCallId, args.data.path);
3001
+ }
2905
3002
  emit({
2906
3003
  type: "tool.started",
2907
3004
  sessionId,
2908
3005
  toolCallId: event.toolCallId,
2909
3006
  tool: event.toolName,
2910
- input: boundedJson(event.args, 1200)
3007
+ input: boundedJson(event.args, 1200),
3008
+ filePath: filePaths.get(event.toolCallId)
2911
3009
  });
2912
3010
  return true;
2913
3011
  }
@@ -2919,8 +3017,10 @@ function createPiFactory(files, models2, delivery2, createSession = createAgentS
2919
3017
  toolCallId: event.toolCallId,
2920
3018
  tool: event.toolName,
2921
3019
  output: toolOutput(event.result),
3020
+ fileChange: event.isError ? void 0 : completedFileChange(event.result, filePaths.get(event.toolCallId)),
2922
3021
  isError: event.isError
2923
3022
  });
3023
+ filePaths.delete(event.toolCallId);
2924
3024
  setActivity("thinking");
2925
3025
  return true;
2926
3026
  }
@@ -2949,9 +3049,9 @@ function createPiFactory(files, models2, delivery2, createSession = createAgentS
2949
3049
  }
2950
3050
 
2951
3051
  // src/projects.ts
2952
- import { access, readdir as readdir2, realpath, stat as stat2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
3052
+ import { access, readdir as readdir2, realpath, stat as stat2, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
2953
3053
  import { randomUUID as randomUUID6 } from "node:crypto";
2954
- import { z as z13 } from "zod";
3054
+ import { z as z14 } from "zod";
2955
3055
  import { constants } from "node:fs";
2956
3056
  import { homedir } from "node:os";
2957
3057
  import path6 from "node:path";
@@ -2983,12 +3083,12 @@ function projectLock(store2) {
2983
3083
  }
2984
3084
  return lock;
2985
3085
  }
2986
- var ProjectId = z13.string().trim().min(1).max(255);
3086
+ var ProjectId = z14.string().trim().min(1).max(255);
2987
3087
  async function gitDirectory(directory) {
2988
3088
  const location = path6.join(directory, ".git");
2989
3089
  const info = await stat2(location);
2990
3090
  if (info.isDirectory()) return location;
2991
- const contents = await readFile4(location, "utf8");
3091
+ const contents = await readFile5(location, "utf8");
2992
3092
  const match = /^gitdir: (.+)\s*$/m.exec(contents);
2993
3093
  if (!match) throw new Error("Invalid Git worktree metadata.");
2994
3094
  const resolved = await realpath(path6.resolve(directory, match[1].trim()));
@@ -2998,21 +3098,21 @@ async function gitDirectory(directory) {
2998
3098
  async function identity(directory, preferred) {
2999
3099
  const filename = path6.join(await gitDirectory(directory), "agentrific-project-id");
3000
3100
  try {
3001
- return ProjectId.parse(await readFile4(filename, "utf8"));
3101
+ return ProjectId.parse(await readFile5(filename, "utf8"));
3002
3102
  } catch (error) {
3003
- if (!z13.object({ code: z13.literal("ENOENT") }).safeParse(error).success) throw error;
3103
+ if (!z14.object({ code: z14.literal("ENOENT") }).safeParse(error).success) throw error;
3004
3104
  const legacyFilename = path6.join(await gitDirectory(directory), "chatplans-project-id");
3005
- const legacy = await readFile4(legacyFilename, "utf8").catch((cause) => {
3006
- if (!z13.object({ code: z13.literal("ENOENT") }).safeParse(cause).success) throw cause;
3105
+ const legacy = await readFile5(legacyFilename, "utf8").catch((cause) => {
3106
+ if (!z14.object({ code: z14.literal("ENOENT") }).safeParse(cause).success) throw cause;
3007
3107
  return null;
3008
3108
  });
3009
3109
  const id = legacy === null ? preferred ?? randomUUID6() : ProjectId.parse(legacy);
3010
3110
  try {
3011
- await writeFile2(filename, id + "\n", { flag: "wx" });
3111
+ await writeFile3(filename, id + "\n", { flag: "wx" });
3012
3112
  return id;
3013
3113
  } catch (writeError) {
3014
- if (!z13.object({ code: z13.literal("EEXIST") }).safeParse(writeError).success) throw writeError;
3015
- return ProjectId.parse(await readFile4(filename, "utf8"));
3114
+ if (!z14.object({ code: z14.literal("EEXIST") }).safeParse(writeError).success) throw writeError;
3115
+ return ProjectId.parse(await readFile5(filename, "utf8"));
3016
3116
  }
3017
3117
  }
3018
3118
  }
@@ -3032,7 +3132,7 @@ function scanProjects(root, store2) {
3032
3132
  let existing = registered.find((project2) => project2.id === id);
3033
3133
  if (found.some((project2) => project2.id === id) || existing && existing.path !== directory && await stat2(path6.join(existing.path, ".git")).catch(() => null)) {
3034
3134
  id = randomUUID6();
3035
- await writeFile2(
3135
+ await writeFile3(
3036
3136
  path6.join(await gitDirectory(directory), "agentrific-project-id"),
3037
3137
  id + "\n"
3038
3138
  );
@@ -3071,11 +3171,11 @@ function reconnectProject(root, id, input, store2) {
3071
3171
  const filename = path6.join(await gitDirectory(directory), "agentrific-project-id");
3072
3172
  const replacedId = await identity(directory);
3073
3173
  const project = { id, name: path6.basename(directory), path: directory, available: true };
3074
- await writeFile2(filename, id + "\n");
3174
+ await writeFile3(filename, id + "\n");
3075
3175
  try {
3076
3176
  await Effect13.runPromise(store2.relocateProject(project, previous.path, replacedId));
3077
3177
  } catch (error) {
3078
- await writeFile2(filename, replacedId + "\n");
3178
+ await writeFile3(filename, replacedId + "\n");
3079
3179
  throw error;
3080
3180
  }
3081
3181
  return project;
@@ -3089,32 +3189,32 @@ import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "n
3089
3189
  import path7 from "node:path";
3090
3190
 
3091
3191
  // src/push-schema.ts
3092
- import { z as z14 } from "zod";
3093
- var PushBindingSchema = z14.object({
3094
- bindingId: z14.string().uuid(),
3095
- installationId: z14.string().uuid(),
3096
- deviceId: z14.string().uuid()
3192
+ import { z as z15 } from "zod";
3193
+ var PushBindingSchema = z15.object({
3194
+ bindingId: z15.string().uuid(),
3195
+ installationId: z15.string().uuid(),
3196
+ deviceId: z15.string().uuid()
3097
3197
  });
3098
- var PushStateSchema = z14.object({
3099
- bindings: z14.array(PushBindingSchema).max(10),
3100
- error: z14.string().nullable()
3198
+ var PushStateSchema = z15.object({
3199
+ bindings: z15.array(PushBindingSchema).max(10),
3200
+ error: z15.string().nullable()
3101
3201
  });
3102
3202
  var PendingPushSchema = PushEventSchema.extend({
3103
- remaining: z14.array(PushBindingSchema),
3104
- createdAt: z14.number(),
3105
- attempts: z14.number().int().nonnegative(),
3106
- nextAt: z14.number()
3203
+ remaining: z15.array(PushBindingSchema),
3204
+ createdAt: z15.number(),
3205
+ attempts: z15.number().int().nonnegative(),
3206
+ nextAt: z15.number()
3107
3207
  });
3108
3208
 
3109
3209
  // src/store.ts
3110
3210
  import { DatabaseSync } from "node:sqlite";
3111
3211
  import { Context as Context3, Data as Data3, Effect as Effect14, Layer as Layer3 } from "effect";
3112
- import { z as z15 } from "zod";
3212
+ import { z as z16 } from "zod";
3113
3213
  import { randomUUID as randomUUID7 } from "node:crypto";
3114
3214
  var StorageError = class extends Data3.TaggedError("StorageError") {
3115
3215
  };
3116
- var PayloadRow = z15.object({ payload: z15.string() });
3117
- var EventRow = z15.object({ sequence: z15.number(), recorded_at: z15.string(), payload: z15.string() });
3216
+ var PayloadRow = z16.object({ payload: z16.string() });
3217
+ var EventRow = z16.object({ sequence: z16.number(), recorded_at: z16.string(), payload: z16.string() });
3118
3218
  var SqliteSessionStore = class {
3119
3219
  constructor(db) {
3120
3220
  this.db = db;
@@ -3165,7 +3265,7 @@ var SqliteSessionStore = class {
3165
3265
  const row = PayloadRow.parse(
3166
3266
  this.db.prepare("SELECT payload FROM settings WHERE id = 'server-id'").get()
3167
3267
  );
3168
- return z15.string().uuid().parse(JSON.parse(row.payload));
3268
+ return z16.string().uuid().parse(JSON.parse(row.payload));
3169
3269
  });
3170
3270
  }
3171
3271
  saveDevice(device, tokenHash) {
@@ -3253,7 +3353,7 @@ var SqliteSessionStore = class {
3253
3353
  `).all();
3254
3354
  const insert = this.db.prepare("INSERT OR IGNORE INTO projects(id, payload) VALUES (?, ?)");
3255
3355
  for (const row of legacy) {
3256
- const id = z15.object({ id: z15.string() }).parse(row).id;
3356
+ const id = z16.object({ id: z16.string() }).parse(row).id;
3257
3357
  insert.run(
3258
3358
  id,
3259
3359
  JSON.stringify({ id, name: id, path: path7.join(root, id), available: false })
@@ -3463,7 +3563,7 @@ var SqliteSessionStore = class {
3463
3563
  if (event.type === "message.user") this.claimAttachments(event.attachments ?? []);
3464
3564
  const result = this.db.prepare("INSERT INTO events(session_id, recorded_at, payload) VALUES (?, ?, ?)").run(sessionId, recordedAt, JSON.stringify(event));
3465
3565
  if (notification) {
3466
- const count = z15.object({ total: z15.number() }).parse(this.db.prepare("SELECT COUNT(*) AS total FROM push_outbox").get());
3566
+ const count = z16.object({ total: z16.number() }).parse(this.db.prepare("SELECT COUNT(*) AS total FROM push_outbox").get());
3467
3567
  if (count.total >= 1e3)
3468
3568
  this.db.prepare(
3469
3569
  "DELETE FROM push_outbox WHERE rowid IN (SELECT rowid FROM push_outbox ORDER BY rowid LIMIT 1)"
@@ -3515,7 +3615,7 @@ var SessionStore = class extends Context3.Service()(
3515
3615
  for (const suffix of ["-wal", "-shm"])
3516
3616
  if (existsSync2(filename + suffix)) chmodSync(filename + suffix, 384);
3517
3617
  try {
3518
- const schema = z15.object({ user_version: z15.number() }).parse(db.prepare("PRAGMA user_version").get());
3618
+ const schema = z16.object({ user_version: z16.number() }).parse(db.prepare("PRAGMA user_version").get());
3519
3619
  if (schema.user_version > 1)
3520
3620
  throw new Error("This database requires a newer Agentrific server.");
3521
3621
  db.exec(`
@@ -3905,7 +4005,7 @@ app.get("/api/projects/:id", async (request, reply) => {
3905
4005
  return project ?? reply.code(404).send({ error: "Project not found on this server." });
3906
4006
  });
3907
4007
  app.post("/api/projects/:id/reconnect", async (request, reply) => {
3908
- const parsed = z16.object({ path: z16.string().trim().min(1).max(4096) }).safeParse(request.body);
4008
+ const parsed = z17.object({ path: z17.string().trim().min(1).max(4096) }).safeParse(request.body);
3909
4009
  if (!parsed.success)
3910
4010
  return reply.code(400).send({ error: "Enter the project's new folder path." });
3911
4011
  const root = await Effect16.runPromise(store.projectsRoot(defaultProjectsRoot));
@@ -4037,9 +4137,9 @@ app.post(
4037
4137
  }
4038
4138
  })
4039
4139
  );
4040
- var HistoryQuery = z16.object({
4041
- after: z16.coerce.number().int().nonnegative().default(0),
4042
- limit: z16.coerce.number().int().min(1).max(1e3).default(500)
4140
+ var HistoryQuery = z17.object({
4141
+ after: z17.coerce.number().int().nonnegative().default(0),
4142
+ limit: z17.coerce.number().int().min(1).max(1e3).default(500)
4043
4143
  });
4044
4144
  app.get("/api/sessions/:id/events", async (request, reply) => {
4045
4145
  const query = HistoryQuery.safeParse(request.query);
@@ -4181,7 +4281,7 @@ app.post("/api/sessions", async (request, reply) => {
4181
4281
  if (!result.session) return reply.code(result.status).send({ error: result.error });
4182
4282
  return reply.code(201).send(result.session);
4183
4283
  });
4184
- var StartTaskBody = z16.object({ prompt: z16.string().trim().max(2e4).optional() }).default({});
4284
+ var StartTaskBody = z17.object({ prompt: z17.string().trim().max(2e4).optional() }).default({});
4185
4285
  function startTask(id, instructionsOverride, automated = false) {
4186
4286
  return withTaskLock(
4187
4287
  "agent-dispatch",
@@ -4259,7 +4359,7 @@ app.patch("/api/automation", async (request, reply) => {
4259
4359
  return automation.configure(parsed.data);
4260
4360
  });
4261
4361
  app.patch("/api/automation/queue", async (request, reply) => {
4262
- const parsed = z16.object({ taskId: z16.string().min(1), beforeId: z16.string().min(1).nullable() }).safeParse(request.body);
4362
+ const parsed = z17.object({ taskId: z17.string().min(1), beforeId: z17.string().min(1).nullable() }).safeParse(request.body);
4263
4363
  if (!parsed.success)
4264
4364
  return reply.code(400).send({ error: "Choose a task and a queue position." });
4265
4365
  try {
@@ -4289,7 +4389,13 @@ app.post(
4289
4389
  attachments.resolve(session.projectId, parsed.data.attachmentIds ?? [])
4290
4390
  );
4291
4391
  await Effect16.runPromise(
4292
- runtime.send(session, parsed.data.message, files, parsed.data.clientMessageId)
4392
+ runtime.send(
4393
+ session,
4394
+ parsed.data.message,
4395
+ files,
4396
+ parsed.data.clientMessageId,
4397
+ parsed.data.mode
4398
+ )
4293
4399
  );
4294
4400
  return reply.code(202).send({ accepted: true });
4295
4401
  } catch (error) {