replicas-engine 0.1.686 → 0.1.688

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.
@@ -2586,6 +2586,7 @@ Use this when:
2586
2586
  - The user asks to discover which external services are connected
2587
2587
  - The user asks to create or control an E2B sandbox
2588
2588
  - The user asks to invoke a connected Modal function
2589
+ - The user asks to access Vercel projects, deployments, domains, logs, or infrastructure
2589
2590
  - The user asks to query or update a connected turbopuffer namespace
2590
2591
  - The user asks for PlanetScale organizations, databases, branches, or Insights data
2591
2592
  - The user asks to analyze text with Pangram`;
@@ -2653,6 +2654,17 @@ const databases = await replicas.planetscale.request('/organizations/acme/databa
2653
2654
 
2654
2655
  OAuth scopes control permitted operations. Confirm mutations before using POST, PUT, PATCH, or DELETE.
2655
2656
 
2657
+ ## Vercel
2658
+
2659
+ Vercel is a native access-token integration. Pass a relative path from the Vercel REST API, including a \`teamId\` query parameter for team-owned resources:
2660
+
2661
+ \`\`\`ts
2662
+ const projects = await replicas.vercel.request('/v9/projects?teamId=team_123');
2663
+ const deployments = await replicas.vercel.request('/v6/deployments?teamId=team_123');
2664
+ \`\`\`
2665
+
2666
+ Confirm mutations before using POST, PUT, PATCH, or DELETE.
2667
+
2656
2668
  ## Modal
2657
2669
 
2658
2670
  Modal is a native integration and uses its official JavaScript SDK behind the Replicas gateway. Invoke a deployed function by name:
@@ -3734,7 +3746,7 @@ var EXPLICIT_PLUGIN_CATALOG = [
3734
3746
  },
3735
3747
  {
3736
3748
  id: "vercel",
3737
- backend: "composio",
3749
+ backend: "native",
3738
3750
  toolkit: "vercel",
3739
3751
  authType: "api_key",
3740
3752
  category: "data",
@@ -3825,6 +3837,7 @@ var HOSTED_COMPOSIO_PLUGIN_DEFINITIONS = [
3825
3837
  ["xero", "xero", "OAUTH2", false, "business", "Xero"],
3826
3838
  ["brex", "brex", "API_KEY", false, "business", "Brex"],
3827
3839
  ["buffer", "buffer", "OAUTH2", false, "business", "Buffer"],
3840
+ ["docusign", "docusign", "OAUTH2", false, "business", "DocuSign"],
3828
3841
  ["canva", "canva", "OAUTH2", true, "productivity", "Canva"],
3829
3842
  ["webflow", "webflow", "API_KEY", false, "business", "Webflow"],
3830
3843
  ["firecrawl", "firecrawl", "API_KEY", false, "data", "Firecrawl"],
@@ -4015,6 +4028,86 @@ function isTerminalBackgroundTaskStatus(status) {
4015
4028
  // ../shared/src/display-message/constants.ts
4016
4029
  var USER_MESSAGE_MATCH_GRACE_PERIOD_MS = 3e4;
4017
4030
 
4031
+ // ../shared/src/user-message-matching.ts
4032
+ function parseTimestampMs(timestamp) {
4033
+ const value = Date.parse(timestamp);
4034
+ return Number.isFinite(value) ? value : 0;
4035
+ }
4036
+ function areUserMessagesWithinMatchWindow(a, b) {
4037
+ return a.content === b.content && Math.abs(parseTimestampMs(a.timestamp) - parseTimestampMs(b.timestamp)) <= USER_MESSAGE_MATCH_GRACE_PERIOD_MS;
4038
+ }
4039
+
4040
+ // ../shared/src/agent-event-utils.ts
4041
+ function getUserMessage(event) {
4042
+ return event.type === "event_msg" && event.payload.type === "user_message" && typeof event.payload.message === "string" ? event.payload.message : null;
4043
+ }
4044
+ function getUserMessageId(event) {
4045
+ const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
4046
+ return typeof messageId === "string" ? messageId : null;
4047
+ }
4048
+ function getUserMessageItemId(event) {
4049
+ const itemId = event.payload[CODEX_ASP_ITEM_ID_PAYLOAD_KEY];
4050
+ return typeof itemId === "string" ? itemId : null;
4051
+ }
4052
+ function getEventTimestampMs(event) {
4053
+ return parseTimestampMs(event.timestamp);
4054
+ }
4055
+ function areSameUserMessageEvents(a, b) {
4056
+ const aMessage = getUserMessage(a);
4057
+ const bMessage = getUserMessage(b);
4058
+ if (!aMessage || aMessage !== bMessage) return false;
4059
+ const aMessageId = getUserMessageId(a);
4060
+ const bMessageId = getUserMessageId(b);
4061
+ if (aMessageId || bMessageId) return aMessageId === bMessageId;
4062
+ const aItemId = getUserMessageItemId(a);
4063
+ const bItemId = getUserMessageItemId(b);
4064
+ if (aItemId || bItemId) return aItemId === bItemId;
4065
+ return areUserMessagesWithinMatchWindow(
4066
+ { content: aMessage, timestamp: a.timestamp },
4067
+ { content: bMessage, timestamp: b.timestamp }
4068
+ );
4069
+ }
4070
+ function parseAgentEventJsonl(content, options = {}) {
4071
+ const events = [];
4072
+ for (const line of content.split("\n")) {
4073
+ const trimmed = line.trim();
4074
+ if (!trimmed) continue;
4075
+ try {
4076
+ const parsed = JSON.parse(trimmed);
4077
+ if (isAgentBackendEvent(parsed)) {
4078
+ events.push(parsed);
4079
+ } else {
4080
+ options.onInvalidLine?.({ line: trimmed });
4081
+ }
4082
+ } catch (error) {
4083
+ options.onInvalidLine?.({ line: trimmed, error });
4084
+ }
4085
+ }
4086
+ return events;
4087
+ }
4088
+ function parseAgentEventJsonlWithCodexAspTranscript(content, options = {}) {
4089
+ const events = [];
4090
+ let transcript = null;
4091
+ const transcriptsByThreadId = /* @__PURE__ */ new Map();
4092
+ for (const event of parseAgentEventJsonl(content, options)) {
4093
+ if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) {
4094
+ events.push(event);
4095
+ continue;
4096
+ }
4097
+ const delta = event.payload.transcriptDelta;
4098
+ if (isCodexAspTranscriptDelta(delta)) {
4099
+ const previous = transcriptsByThreadId.get(delta.threadId) ?? null;
4100
+ transcript = applyCodexAspTranscriptDelta(previous, delta);
4101
+ } else if (isCodexAspTranscript(event.payload.transcript)) {
4102
+ transcript = event.payload.transcript;
4103
+ }
4104
+ if (transcript) {
4105
+ transcriptsByThreadId.set(transcript.threadId, transcript);
4106
+ }
4107
+ }
4108
+ return { events, transcript, transcriptsByThreadId };
4109
+ }
4110
+
4018
4111
  // ../shared/src/json.ts
4019
4112
  function safeJsonParse(str, fallback) {
4020
4113
  try {
@@ -4095,6 +4188,12 @@ function createCallDisplayMessage(message) {
4095
4188
  timestamp: message.timestamp
4096
4189
  };
4097
4190
  }
4191
+ function insertDisplayMessageByTimestamp(messages, message) {
4192
+ const messageMs = parseTimestampMs(message.timestamp);
4193
+ let index = messages.length;
4194
+ while (index > 0 && parseTimestampMs(messages[index - 1].timestamp) > messageMs) index--;
4195
+ messages.splice(index, 0, message);
4196
+ }
4098
4197
 
4099
4198
  // ../shared/src/display-message/format.ts
4100
4199
  function unquoteShellArg(value) {
@@ -4162,86 +4261,6 @@ function skillNamesFromCommand(command) {
4162
4261
  })));
4163
4262
  }
4164
4263
 
4165
- // ../shared/src/user-message-matching.ts
4166
- function parseTimestampMs(timestamp) {
4167
- const value = Date.parse(timestamp);
4168
- return Number.isFinite(value) ? value : 0;
4169
- }
4170
- function areUserMessagesWithinMatchWindow(a, b) {
4171
- return a.content === b.content && Math.abs(parseTimestampMs(a.timestamp) - parseTimestampMs(b.timestamp)) <= USER_MESSAGE_MATCH_GRACE_PERIOD_MS;
4172
- }
4173
-
4174
- // ../shared/src/agent-event-utils.ts
4175
- function getUserMessage(event) {
4176
- return event.type === "event_msg" && event.payload.type === "user_message" && typeof event.payload.message === "string" ? event.payload.message : null;
4177
- }
4178
- function getUserMessageId(event) {
4179
- const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
4180
- return typeof messageId === "string" ? messageId : null;
4181
- }
4182
- function getUserMessageItemId(event) {
4183
- const itemId = event.payload[CODEX_ASP_ITEM_ID_PAYLOAD_KEY];
4184
- return typeof itemId === "string" ? itemId : null;
4185
- }
4186
- function getEventTimestampMs(event) {
4187
- return parseTimestampMs(event.timestamp);
4188
- }
4189
- function areSameUserMessageEvents(a, b) {
4190
- const aMessage = getUserMessage(a);
4191
- const bMessage = getUserMessage(b);
4192
- if (!aMessage || aMessage !== bMessage) return false;
4193
- const aMessageId = getUserMessageId(a);
4194
- const bMessageId = getUserMessageId(b);
4195
- if (aMessageId || bMessageId) return aMessageId === bMessageId;
4196
- const aItemId = getUserMessageItemId(a);
4197
- const bItemId = getUserMessageItemId(b);
4198
- if (aItemId || bItemId) return aItemId === bItemId;
4199
- return areUserMessagesWithinMatchWindow(
4200
- { content: aMessage, timestamp: a.timestamp },
4201
- { content: bMessage, timestamp: b.timestamp }
4202
- );
4203
- }
4204
- function parseAgentEventJsonl(content, options = {}) {
4205
- const events = [];
4206
- for (const line of content.split("\n")) {
4207
- const trimmed = line.trim();
4208
- if (!trimmed) continue;
4209
- try {
4210
- const parsed = JSON.parse(trimmed);
4211
- if (isAgentBackendEvent(parsed)) {
4212
- events.push(parsed);
4213
- } else {
4214
- options.onInvalidLine?.({ line: trimmed });
4215
- }
4216
- } catch (error) {
4217
- options.onInvalidLine?.({ line: trimmed, error });
4218
- }
4219
- }
4220
- return events;
4221
- }
4222
- function parseAgentEventJsonlWithCodexAspTranscript(content, options = {}) {
4223
- const events = [];
4224
- let transcript = null;
4225
- const transcriptsByThreadId = /* @__PURE__ */ new Map();
4226
- for (const event of parseAgentEventJsonl(content, options)) {
4227
- if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) {
4228
- events.push(event);
4229
- continue;
4230
- }
4231
- const delta = event.payload.transcriptDelta;
4232
- if (isCodexAspTranscriptDelta(delta)) {
4233
- const previous = transcriptsByThreadId.get(delta.threadId) ?? null;
4234
- transcript = applyCodexAspTranscriptDelta(previous, delta);
4235
- } else if (isCodexAspTranscript(event.payload.transcript)) {
4236
- transcript = event.payload.transcript;
4237
- }
4238
- if (transcript) {
4239
- transcriptsByThreadId.set(transcript.threadId, transcript);
4240
- }
4241
- }
4242
- return { events, transcript, transcriptsByThreadId };
4243
- }
4244
-
4245
4264
  // ../shared/src/display-message/parsers/codex-parser.ts
4246
4265
  function getStatusFromExitCode(exitCode) {
4247
4266
  return exitCode === 0 ? "completed" : "failed";
@@ -6028,6 +6047,7 @@ function duplicateBucketKey(message, bucketOffset = 0) {
6028
6047
  }
6029
6048
  function mergeCodexAspDisplayMessages(primary, supplemental) {
6030
6049
  const merged = [...primary];
6050
+ const primaryCount = primary.length;
6031
6051
  const firstIndexById = /* @__PURE__ */ new Map();
6032
6052
  const indexesByDuplicateBucket = /* @__PURE__ */ new Map();
6033
6053
  const indexMessage = (message, index) => {
@@ -6064,14 +6084,18 @@ function mergeCodexAspDisplayMessages(primary, supplemental) {
6064
6084
  unindexMessage(merged[duplicateIndex], duplicateIndex);
6065
6085
  merged[duplicateIndex] = {
6066
6086
  ...merged[duplicateIndex],
6067
- id: message.id,
6068
- timestamp: message.timestamp
6087
+ id: message.id
6069
6088
  };
6070
6089
  firstIndexById.set(message.id, duplicateIndex);
6071
6090
  indexMessage(merged[duplicateIndex], duplicateIndex);
6072
6091
  }
6073
6092
  }
6074
- return merged.map((message, index) => ({ message, index })).sort((a, b) => parseTimestampMs(a.message.timestamp) - parseTimestampMs(b.message.timestamp) || a.index - b.index).map(({ message }) => message);
6093
+ const ordered = merged.slice(0, primaryCount);
6094
+ const supplementalOnly = merged.slice(primaryCount).map((message, index) => ({ message, index })).sort((a, b) => parseTimestampMs(a.message.timestamp) - parseTimestampMs(b.message.timestamp) || a.index - b.index);
6095
+ for (const { message } of supplementalOnly) {
6096
+ insertDisplayMessageByTimestamp(ordered, message);
6097
+ }
6098
+ return ordered;
6075
6099
  }
6076
6100
  function parseCodexAspTranscript(transcript) {
6077
6101
  const messages = [];
@@ -6157,24 +6181,18 @@ function parseDisplayMessages(events, agentType, codexAspTranscript, options = {
6157
6181
  const shouldFilter = options.filter ?? true;
6158
6182
  const parsedEvents = agentType === "claude" || agentType === "relay" ? parseClaudeEvents(events, options.parentToolUseId) : parseAgentEvents(events, agentType);
6159
6183
  const legacyMessages = shouldFilter ? filterDisplayMessages(parsedEvents, agentType) : parsedEvents;
6160
- const finalize = (messages) => shouldFilter ? applyAuthFallbackNotices(applyInterruptions(messages, events), events) : messages;
6184
+ const applySyntheticNotices = (messages) => shouldFilter ? applyAuthFallbackNotices(applyInterruptions(messages, events), events) : messages;
6161
6185
  if (agentType !== "codex" || !codexAspTranscript) {
6162
- return finalize(legacyMessages);
6186
+ return applySyntheticNotices(legacyMessages);
6163
6187
  }
6164
6188
  const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
6165
- return finalize(mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages));
6166
- }
6167
- function insertByTimestamp(messages, message) {
6168
- const messageMs = parseTimestampMs(message.timestamp);
6169
- let index = messages.length;
6170
- while (index > 0 && parseTimestampMs(messages[index - 1].timestamp) > messageMs) index--;
6171
- messages.splice(index, 0, message);
6189
+ return applySyntheticNotices(mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages));
6172
6190
  }
6173
6191
  function applyInterruptions(messages, events) {
6174
6192
  const result = [...messages];
6175
6193
  for (const event of events) {
6176
6194
  if (event.type !== CHAT_INTERRUPTED_EVENT_TYPE) continue;
6177
- insertByTimestamp(result, {
6195
+ insertDisplayMessageByTimestamp(result, {
6178
6196
  id: `interruption-${event.timestamp}`,
6179
6197
  type: "interruption",
6180
6198
  timestamp: event.timestamp
@@ -6221,7 +6239,7 @@ function applyAuthFallbackNotices(messages, events) {
6221
6239
  });
6222
6240
  if (notices.length === 0) return messages;
6223
6241
  const result = [...messages];
6224
- for (const notice of notices) insertByTimestamp(result, notice);
6242
+ for (const notice of notices) insertDisplayMessageByTimestamp(result, notice);
6225
6243
  return result;
6226
6244
  }
6227
6245
  function isCodexInitializationPrompt(message) {
@@ -6743,7 +6761,7 @@ var DEFAULT_CODEX_ARGS = [
6743
6761
  var MIN_CODEX_CLI_VERSION = "0.144.6";
6744
6762
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
6745
6763
  var codexCliVersionEnsured = null;
6746
- var ENGINE_PACKAGE_VERSION = "0.1.686";
6764
+ var ENGINE_PACKAGE_VERSION = "0.1.688";
6747
6765
  var INITIALIZE_METHOD = "initialize";
6748
6766
  var INITIALIZED_NOTIFICATION = "initialized";
6749
6767
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -7,7 +7,7 @@ import {
7
7
  headlessAgentRequestSchema,
8
8
  putPresignedFile,
9
9
  recoverCompletedTurn
10
- } from "./chunk-SC7MWNN2.js";
10
+ } from "./chunk-KS4CJNWB.js";
11
11
 
12
12
  // src/headless-agent.ts
13
13
  import { createHash } from "crypto";
package/dist/src/index.js CHANGED
@@ -192,7 +192,7 @@ import {
192
192
  serializeCanvasContentResponse,
193
193
  shellQuotePosix,
194
194
  stripAgentDiagnosticErrors
195
- } from "./chunk-SC7MWNN2.js";
195
+ } from "./chunk-KS4CJNWB.js";
196
196
 
197
197
  // src/index.ts
198
198
  import { serve } from "@hono/node-server";
@@ -3383,10 +3383,14 @@ var MessageQueueService = class {
3383
3383
  messageIdCounter = 0;
3384
3384
  processMessage;
3385
3385
  onProcessingChanged;
3386
+ onMessageStarted;
3387
+ acceptanceByMessage = /* @__PURE__ */ new WeakMap();
3386
3388
  constructor(processMessage, onProcessingChanged = () => {
3389
+ }, onMessageStarted = async () => {
3387
3390
  }) {
3388
3391
  this.processMessage = processMessage;
3389
3392
  this.onProcessingChanged = onProcessingChanged;
3393
+ this.onMessageStarted = onMessageStarted;
3390
3394
  }
3391
3395
  generateMessageId() {
3392
3396
  return `msg_${Date.now()}_${++this.messageIdCounter}`;
@@ -3395,15 +3399,20 @@ var MessageQueueService = class {
3395
3399
  * Add a message to the queue or start processing immediately if not busy
3396
3400
  * @returns Object indicating whether the message was queued or started processing
3397
3401
  */
3398
- async enqueue(request) {
3402
+ async enqueue(request, onAccepted = async () => {
3403
+ }) {
3399
3404
  if (this.processing && this.canMergeIntoTail(request)) {
3400
3405
  const tail = this.queue[this.queue.length - 1];
3401
3406
  this.mergeInto(tail, request);
3402
- return {
3407
+ const response2 = {
3403
3408
  queued: true,
3404
3409
  messageId: tail.id,
3405
3410
  position: this.queue.length
3406
3411
  };
3412
+ const acceptance = (this.acceptanceByMessage.get(tail) ?? Promise.resolve()).then(() => onAccepted(response2));
3413
+ this.acceptanceByMessage.set(tail, acceptance);
3414
+ await acceptance;
3415
+ return response2;
3407
3416
  }
3408
3417
  const messageId = request.messageId ?? this.generateMessageId();
3409
3418
  const queuedMessage = {
@@ -3416,20 +3425,26 @@ var MessageQueueService = class {
3416
3425
  };
3417
3426
  if (this.processing) {
3418
3427
  this.queue.push(queuedMessage);
3419
- return {
3428
+ const response2 = {
3420
3429
  queued: true,
3421
3430
  messageId,
3422
3431
  position: this.queue.length
3423
3432
  };
3433
+ const acceptance = onAccepted(response2);
3434
+ this.acceptanceByMessage.set(queuedMessage, acceptance);
3435
+ await acceptance;
3436
+ return response2;
3424
3437
  }
3425
- this.startProcessing(queuedMessage).catch((error) => {
3426
- console.error("[MessageQueue] Unhandled error in startProcessing:", error);
3427
- });
3428
- return {
3438
+ const response = {
3429
3439
  queued: false,
3430
3440
  messageId,
3431
3441
  position: 0
3432
3442
  };
3443
+ await onAccepted(response);
3444
+ this.startProcessing(queuedMessage).catch((error) => {
3445
+ console.error("[MessageQueue] Unhandled error in startProcessing:", error);
3446
+ });
3447
+ return response;
3433
3448
  }
3434
3449
  canMergeIntoTail(request) {
3435
3450
  if (!request.merge || !request.type) return false;
@@ -3447,6 +3462,15 @@ var MessageQueueService = class {
3447
3462
  this.processing = true;
3448
3463
  this.onProcessingChanged(true);
3449
3464
  try {
3465
+ while (true) {
3466
+ const acceptance = this.acceptanceByMessage.get(queuedMessage);
3467
+ if (!acceptance) break;
3468
+ await acceptance;
3469
+ if (this.acceptanceByMessage.get(queuedMessage) !== acceptance) continue;
3470
+ this.acceptanceByMessage.delete(queuedMessage);
3471
+ break;
3472
+ }
3473
+ await this.onMessageStarted(queuedMessage);
3450
3474
  await this.processMessage(queuedMessage);
3451
3475
  } catch (error) {
3452
3476
  console.error("[MessageQueue] Error processing message:", error);
@@ -3562,6 +3586,7 @@ var CodingAgentManager = class {
3562
3586
  onEvent;
3563
3587
  hostOnTurnComplete;
3564
3588
  onProcessingChanged;
3589
+ onMessageStarted;
3565
3590
  authFallback;
3566
3591
  compacting = false;
3567
3592
  constructor(options) {
@@ -3572,6 +3597,8 @@ var CodingAgentManager = class {
3572
3597
  this.hostOnTurnComplete = options.onTurnComplete;
3573
3598
  this.onProcessingChanged = options.onProcessingChanged ?? (() => {
3574
3599
  });
3600
+ this.onMessageStarted = options.onMessageStarted ?? (async () => {
3601
+ });
3575
3602
  this.authFallback = options.provider ? new AuthFallbackCoordinator(options.provider, (event) => {
3576
3603
  this.onEvent(event);
3577
3604
  this.getHistorySink()?.append(event);
@@ -3621,7 +3648,11 @@ var CodingAgentManager = class {
3621
3648
  historyFile.append(event);
3622
3649
  }
3623
3650
  initializeManager(processMessage) {
3624
- this.messageQueue = new MessageQueueService(processMessage, this.onProcessingChanged);
3651
+ this.messageQueue = new MessageQueueService(
3652
+ processMessage,
3653
+ this.onProcessingChanged,
3654
+ this.onMessageStarted
3655
+ );
3625
3656
  this.initialized = this.initialize();
3626
3657
  }
3627
3658
  async interrupt() {
@@ -3671,9 +3702,9 @@ var CodingAgentManager = class {
3671
3702
  reorderQueue(messageId, newPosition) {
3672
3703
  return this.messageQueue.reorderQueue(messageId, newPosition);
3673
3704
  }
3674
- async enqueueMessage(request) {
3705
+ async enqueueMessage(request, onAccepted) {
3675
3706
  await this.initialized;
3676
- return this.messageQueue.enqueue(request);
3707
+ return this.messageQueue.enqueue(request, onAccepted);
3677
3708
  }
3678
3709
  // Take the message off the queue before steering: a turn completing mid-steer could otherwise pop it too.
3679
3710
  async steerFromQueue(messageId) {
@@ -7002,6 +7033,7 @@ var CodexAspManager = class extends CodingAgentManager {
7002
7033
  const observedTurnIds = /* @__PURE__ */ new Set();
7003
7034
  let lastCompletedTurn = null;
7004
7035
  let completedResolved = false;
7036
+ let userMessageAttached = false;
7005
7037
  let goalContinuationTimer = null;
7006
7038
  const completedItems = [];
7007
7039
  const agentMessageDeltas = /* @__PURE__ */ new Map();
@@ -7030,6 +7062,11 @@ var CodexAspManager = class extends CodingAgentManager {
7030
7062
  resolveCompleted(lastCompletedTurn);
7031
7063
  }, GOAL_TURN_CONTINUATION_GRACE_MS);
7032
7064
  };
7065
+ const attachUserMessage = (turn) => {
7066
+ if (userMessageAttached) return;
7067
+ userMessageAttached = true;
7068
+ this.ensureTranscriptTurnUserMessage(threadId, turn, request);
7069
+ };
7033
7070
  const handlers = {
7034
7071
  [ACCOUNT_RATE_LIMITS_UPDATED_METHOD]: (notification) => {
7035
7072
  this.handleRateLimits(notification.params.rateLimits);
@@ -7064,6 +7101,7 @@ var CodexAspManager = class extends CodingAgentManager {
7064
7101
  lastCompletedTurn = null;
7065
7102
  completedItems.length = 0;
7066
7103
  agentMessageDeltas.clear();
7104
+ attachUserMessage(notification.params.turn);
7067
7105
  this.mergeTranscriptTurn(notification.params.threadId, notification.params.turn);
7068
7106
  this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
7069
7107
  linearForwarder.sendEvent(convertCodexAspNotification(notification, linearSessionId ?? ""));
@@ -7202,9 +7240,15 @@ var CodexAspManager = class extends CodingAgentManager {
7202
7240
  const started = await startTurn();
7203
7241
  tempImagePaths = started.tempImagePaths;
7204
7242
  if (started.turn) {
7243
+ const alreadyObserved = observedTurnIds.has(started.turn.id);
7205
7244
  observedTurnId = started.turn.id;
7206
7245
  observedTurnIds.add(started.turn.id);
7207
7246
  this.activeTurnId = started.turn.id;
7247
+ if (!alreadyObserved) {
7248
+ attachUserMessage(started.turn);
7249
+ this.mergeTranscriptTurn(threadId, started.turn);
7250
+ this.emitTranscriptUpdated(threadId, { immediate: true });
7251
+ }
7208
7252
  }
7209
7253
  const turn = await Promise.race([completed, disposed]);
7210
7254
  linearForwarder.flushThoughtAsResponse();
@@ -7449,6 +7493,28 @@ var CodexAspManager = class extends CodingAgentManager {
7449
7493
  }
7450
7494
  return turn;
7451
7495
  }
7496
+ ensureTranscriptTurnUserMessage(threadId, turn, request) {
7497
+ const timestamp = timestampFromSeconds(turn.startedAt);
7498
+ const transcriptTurn = this.ensureTranscriptTurn(threadId, turn.id, timestamp);
7499
+ const images = imageContentToUserMessageImages(request.images);
7500
+ const userMessage = {
7501
+ type: "userMessage",
7502
+ id: request.messageId ?? `user-${turn.id}`,
7503
+ content: request.message,
7504
+ ...images ? { images } : {},
7505
+ timestamp,
7506
+ sequence: this.nextTranscriptSequence()
7507
+ };
7508
+ const existingIndex = findEquivalentCodexAspTranscriptItemIndex(transcriptTurn.items, userMessage);
7509
+ if (existingIndex === -1) {
7510
+ transcriptTurn.items.push(userMessage);
7511
+ } else {
7512
+ transcriptTurn.items[existingIndex] = mergeCodexAspTranscriptItem(
7513
+ transcriptTurn.items[existingIndex],
7514
+ userMessage
7515
+ );
7516
+ }
7517
+ }
7452
7518
  mergeTranscriptTurn(threadId, turn) {
7453
7519
  const startedAt = timestampFromSeconds(turn.startedAt);
7454
7520
  const completedAt = turn.completedAt === null ? null : timestampFromSeconds(turn.completedAt);
@@ -10122,12 +10188,12 @@ var PiManager = class extends CodingAgentManager {
10122
10188
  await this.initialized;
10123
10189
  return mergeSlashCommands((this.session?.promptTemplates ?? []).map((template) => createProviderSlashCommand("pi", template.name, template.description)).filter((command) => Boolean(command)));
10124
10190
  }
10125
- async enqueueMessage(request) {
10191
+ async enqueueMessage(request, onAccepted) {
10126
10192
  await this.initialized;
10127
10193
  if (!this.session && !this.getProviderCredentials()) {
10128
10194
  throw new Error("Aster or OpenRouter authentication is missing for Pi. Add an API key in Settings \u2192 Coding agents.");
10129
10195
  }
10130
- return this.messageQueue.enqueue(request);
10196
+ return this.messageQueue.enqueue(request, onAccepted);
10131
10197
  }
10132
10198
  dispose() {
10133
10199
  this.unsubscribe?.();
@@ -10865,8 +10931,8 @@ var RelayManager = class {
10865
10931
  disallowedTools: []
10866
10932
  });
10867
10933
  }
10868
- async enqueueMessage(request) {
10869
- return this.inner.enqueueMessage(request);
10934
+ async enqueueMessage(request, onAccepted) {
10935
+ return this.inner.enqueueMessage(request, onAccepted);
10870
10936
  }
10871
10937
  async interrupt() {
10872
10938
  return this.inner.interrupt();
@@ -11840,6 +11906,23 @@ function isPiAvailable() {
11840
11906
  function isCursorAvailable() {
11841
11907
  return Boolean(ENGINE_ENV.CURSOR_API_KEY);
11842
11908
  }
11909
+ function createTurnMetadata(message, messageId, recordedAt) {
11910
+ const event = createAcceptedUserMessageEvent(
11911
+ message.message,
11912
+ messageId,
11913
+ recordedAt,
11914
+ message.images
11915
+ );
11916
+ const sender = message.senderUserId && message.senderEmail ? {
11917
+ messageId,
11918
+ senderUserId: message.senderUserId,
11919
+ senderEmail: message.senderEmail,
11920
+ ...message.senderDisplayName ? { senderDisplayName: message.senderDisplayName } : {},
11921
+ ...message.senderAvatarUrl ? { senderAvatarUrl: message.senderAvatarUrl } : {},
11922
+ recordedAt
11923
+ } : void 0;
11924
+ return { event, ...sender ? { sender } : {} };
11925
+ }
11843
11926
  function isSameAcceptedUserEvent(event, acceptedEvent) {
11844
11927
  const eventMessageId = getUserMessageId(event);
11845
11928
  if (eventMessageId && eventMessageId === getUserMessageId(acceptedEvent)) return true;
@@ -12056,7 +12139,12 @@ var ChatService = class {
12056
12139
  return accepted;
12057
12140
  }
12058
12141
  }
12059
- const result = await chat.provider.enqueueMessage(request);
12142
+ return chat.provider.enqueueMessage(
12143
+ request,
12144
+ (result) => this.handleMessageAccepted(chatId, chat, request, result)
12145
+ );
12146
+ }
12147
+ async handleMessageAccepted(chatId, chat, request, result) {
12060
12148
  if (request.idempotencyKey) {
12061
12149
  chat.acceptedSendResponses.set(request.idempotencyKey, result);
12062
12150
  for (const key of chat.acceptedSendResponses.keys()) {
@@ -12066,11 +12154,10 @@ var ChatService = class {
12066
12154
  chat.persisted.acceptedSendResponses = Object.fromEntries(chat.acceptedSendResponses);
12067
12155
  }
12068
12156
  const submittedAt = request.submittedAt ?? (/* @__PURE__ */ new Date()).toISOString();
12069
- const acceptedEvent = createAcceptedUserMessageEvent(
12070
- request.message,
12157
+ const { event: acceptedEvent, sender: recordedSender } = createTurnMetadata(
12158
+ request,
12071
12159
  result.messageId,
12072
- submittedAt,
12073
- request.images
12160
+ submittedAt
12074
12161
  );
12075
12162
  if (!chat.pendingMessageIds.includes(result.messageId)) {
12076
12163
  chat.pendingMessageIds.push(result.messageId);
@@ -12082,16 +12169,7 @@ var ChatService = class {
12082
12169
  chat.acceptedUserEvents.set(result.messageId, acceptedEvent);
12083
12170
  chat.persisted.lastMessageText = request.message.trim().slice(0, LAST_MESSAGE_PREVIEW_MAX) || null;
12084
12171
  this.touch(chat);
12085
- let recordedSender;
12086
- if (request.senderUserId && request.senderEmail) {
12087
- recordedSender = {
12088
- messageId: result.messageId,
12089
- senderUserId: request.senderUserId,
12090
- senderEmail: request.senderEmail,
12091
- ...request.senderDisplayName ? { senderDisplayName: request.senderDisplayName } : {},
12092
- ...request.senderAvatarUrl ? { senderAvatarUrl: request.senderAvatarUrl } : {},
12093
- recordedAt: submittedAt
12094
- };
12172
+ if (recordedSender) {
12095
12173
  await this.appendSender(chatId, recordedSender);
12096
12174
  }
12097
12175
  await this.publish({
@@ -12105,11 +12183,6 @@ var ChatService = class {
12105
12183
  ...recordedSender ? { sender: recordedSender } : {}
12106
12184
  }
12107
12185
  });
12108
- return {
12109
- messageId: result.messageId,
12110
- queued: result.queued,
12111
- position: result.position
12112
- };
12113
12186
  }
12114
12187
  async appendSender(chatId, sender) {
12115
12188
  try {
@@ -12464,6 +12537,7 @@ var ChatService = class {
12464
12537
  const onProviderEvent = (event) => {
12465
12538
  this.handleTurnEvent(persisted.id, event);
12466
12539
  };
12540
+ const onMessageStarted = (message) => this.handleTurnStarted(persisted.id, message);
12467
12541
  const onProcessingChanged = (processing) => {
12468
12542
  if (processing) return;
12469
12543
  const chat = this.getRuntimeChat(persisted.id);
@@ -12486,7 +12560,8 @@ var ChatService = class {
12486
12560
  onSaveSessionId: saveSession,
12487
12561
  onTurnComplete: onProviderTurnComplete,
12488
12562
  onEvent: onProviderEvent,
12489
- onProcessingChanged
12563
+ onProcessingChanged,
12564
+ onMessageStarted
12490
12565
  });
12491
12566
  } else if (persisted.provider === "relay") {
12492
12567
  const getProviderAvailability = () => ({
@@ -12506,6 +12581,7 @@ var ChatService = class {
12506
12581
  onTurnComplete: onProviderTurnComplete,
12507
12582
  onEvent: onProviderEvent,
12508
12583
  onProcessingChanged,
12584
+ onMessageStarted,
12509
12585
  chatId: persisted.id,
12510
12586
  ...getProviderAvailability(),
12511
12587
  getProviderAvailability
@@ -12518,7 +12594,8 @@ var ChatService = class {
12518
12594
  onSaveSessionId: saveSession,
12519
12595
  onTurnComplete: onProviderTurnComplete,
12520
12596
  onEvent: onProviderEvent,
12521
- onProcessingChanged
12597
+ onProcessingChanged,
12598
+ onMessageStarted
12522
12599
  });
12523
12600
  } else if (persisted.provider === "deepseek") {
12524
12601
  provider = new DeepseekManager({
@@ -12528,7 +12605,8 @@ var ChatService = class {
12528
12605
  onSaveSessionId: saveSession,
12529
12606
  onTurnComplete: onProviderTurnComplete,
12530
12607
  onEvent: onProviderEvent,
12531
- onProcessingChanged
12608
+ onProcessingChanged,
12609
+ onMessageStarted
12532
12610
  });
12533
12611
  } else if (persisted.provider === "fx") {
12534
12612
  provider = new FxManager({
@@ -12538,7 +12616,8 @@ var ChatService = class {
12538
12616
  onSaveSessionId: saveSession,
12539
12617
  onTurnComplete: onProviderTurnComplete,
12540
12618
  onEvent: onProviderEvent,
12541
- onProcessingChanged
12619
+ onProcessingChanged,
12620
+ onMessageStarted
12542
12621
  });
12543
12622
  } else if (persisted.provider === "kimi") {
12544
12623
  provider = new KimiManager({
@@ -12548,7 +12627,8 @@ var ChatService = class {
12548
12627
  onSaveSessionId: saveSession,
12549
12628
  onTurnComplete: onProviderTurnComplete,
12550
12629
  onEvent: onProviderEvent,
12551
- onProcessingChanged
12630
+ onProcessingChanged,
12631
+ onMessageStarted
12552
12632
  });
12553
12633
  } else if (persisted.provider === "opencode") {
12554
12634
  provider = new OpencodeManager({
@@ -12558,7 +12638,8 @@ var ChatService = class {
12558
12638
  onSaveSessionId: saveSession,
12559
12639
  onTurnComplete: onProviderTurnComplete,
12560
12640
  onEvent: onProviderEvent,
12561
- onProcessingChanged
12641
+ onProcessingChanged,
12642
+ onMessageStarted
12562
12643
  });
12563
12644
  } else if (persisted.provider === "pi") {
12564
12645
  provider = new PiManager({
@@ -12568,7 +12649,8 @@ var ChatService = class {
12568
12649
  onSaveSessionId: saveSession,
12569
12650
  onTurnComplete: onProviderTurnComplete,
12570
12651
  onEvent: onProviderEvent,
12571
- onProcessingChanged
12652
+ onProcessingChanged,
12653
+ onMessageStarted
12572
12654
  });
12573
12655
  } else {
12574
12656
  provider = new CodexAspManager({
@@ -12578,7 +12660,8 @@ var ChatService = class {
12578
12660
  onSaveSessionId: saveSession,
12579
12661
  onTurnComplete: onProviderTurnComplete,
12580
12662
  onEvent: onProviderEvent,
12581
- onProcessingChanged
12663
+ onProcessingChanged,
12664
+ onMessageStarted
12582
12665
  });
12583
12666
  }
12584
12667
  return {
@@ -12626,31 +12709,41 @@ var ChatService = class {
12626
12709
  }
12627
12710
  return chat;
12628
12711
  }
12712
+ async handleTurnStarted(chatId, message) {
12713
+ const chat = this.getRuntimeChat(chatId);
12714
+ if (!chat) return;
12715
+ chat.pendingMessageIds = chat.pendingMessageIds.filter((messageId) => messageId !== message.id);
12716
+ chat.hasActiveTurn = true;
12717
+ chat.activeMessageId = message.id;
12718
+ const { event: acceptedEvent, sender } = createTurnMetadata(
12719
+ message,
12720
+ message.id,
12721
+ message.queuedAt
12722
+ );
12723
+ chat.acceptedUserEvents.set(message.id, acceptedEvent);
12724
+ this.agentChatActivityTrackerService.noteTurnStarted(
12725
+ chat.persisted.id,
12726
+ message.id,
12727
+ chat.persisted.provider
12728
+ );
12729
+ chat.activeErrorNotificationTarget = chat.errorNotificationTargets.get(message.id) ?? null;
12730
+ chat.errorNotificationTargets.delete(message.id);
12731
+ await this.publish({
12732
+ type: "chat.turn.started",
12733
+ payload: {
12734
+ chatId,
12735
+ messageId: message.id,
12736
+ event: acceptedEvent,
12737
+ ...sender ? { sender } : {}
12738
+ }
12739
+ });
12740
+ }
12629
12741
  handleTurnEvent(chatId, event) {
12630
12742
  const chat = this.getRuntimeChat(chatId);
12631
12743
  if (!chat) {
12632
12744
  return;
12633
12745
  }
12634
12746
  keepAliveService.noteActivity();
12635
- if (!chat.hasActiveTurn && chat.pendingMessageIds.length > 0) {
12636
- const messageId = chat.pendingMessageIds.shift();
12637
- if (!messageId) {
12638
- return;
12639
- }
12640
- chat.hasActiveTurn = true;
12641
- chat.activeMessageId = messageId;
12642
- this.agentChatActivityTrackerService.noteTurnStarted(chat.persisted.id, messageId, chat.persisted.provider);
12643
- chat.activeErrorNotificationTarget = chat.errorNotificationTargets.get(messageId) ?? null;
12644
- chat.errorNotificationTargets.delete(messageId);
12645
- this.publish({
12646
- type: "chat.turn.started",
12647
- payload: {
12648
- chatId: chat.persisted.id,
12649
- messageId
12650
- }
12651
- }).catch(() => {
12652
- });
12653
- }
12654
12747
  const codexTranscript = getCodexTranscriptFromEvent(event);
12655
12748
  if (chat.hasActiveTurn) {
12656
12749
  const displayMessages = codexTranscript ? parseLatestCodexAspTranscriptTurn(codexTranscript) : parseDisplayMessages([event], chat.persisted.provider, null, {
@@ -12698,6 +12791,7 @@ var ChatService = class {
12698
12791
  type: "chat.turn.delta",
12699
12792
  payload: {
12700
12793
  chatId,
12794
+ ...chat.activeMessageId ? { messageId: chat.activeMessageId } : {},
12701
12795
  event: eventToPublish
12702
12796
  }
12703
12797
  }).catch(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.686",
3
+ "version": "0.1.688",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -116,6 +116,8 @@ const turbopuffer = {
116
116
 
117
117
  const planetscale = providerClient('/v1/engine/planetscale/api');
118
118
 
119
+ const vercel = providerClient('/v1/engine/vercel/api');
120
+
119
121
  const pangramRequest = (operation, input) =>
120
122
  request('/v1/engine/pangram', { method: 'POST', body: { operation, ...input } });
121
123
  const pangram = {
@@ -132,5 +134,5 @@ const e2b = {
132
134
  kill: (sandboxId) => request('/v1/engine/e2b', { method: 'POST', body: { operation: 'kill', sandboxId } }),
133
135
  };
134
136
 
135
- export const replicas = { integrations, plugins, linear, slack, github, gitlab, sentry, modal, pangram, planetscale, turbopuffer, e2b };
137
+ export const replicas = { integrations, plugins, linear, slack, github, gitlab, sentry, modal, pangram, planetscale, vercel, turbopuffer, e2b };
136
138
  export default replicas;
@@ -161,6 +161,29 @@ describe('@replicas/sdk', () => {
161
161
  }
162
162
  });
163
163
 
164
+ test('calls Vercel through the workspace gateway', async () => {
165
+ let observed: { path: string; body: unknown } | null = null;
166
+ const server = Bun.serve({
167
+ port: 0,
168
+ async fetch(request) {
169
+ observed = { path: new URL(request.url).pathname, body: await request.json() };
170
+ return Response.json({ projects: [] });
171
+ },
172
+ });
173
+ process.env.REPLICAS_MONOLITH_URL = server.url.toString().replace(/\/$/, '');
174
+ process.env.REPLICAS_ENGINE_SECRET = 'engine-secret';
175
+ process.env.REPLICAS_WORKSPACE_ID = 'workspace-1';
176
+ try {
177
+ await replicas.vercel.request('/v9/projects?teamId=team_1');
178
+ expect(observed).toEqual({
179
+ path: '/v1/engine/vercel/api',
180
+ body: { path: '/v9/projects?teamId=team_1' },
181
+ });
182
+ } finally {
183
+ server.stop(true);
184
+ }
185
+ });
186
+
164
187
  test('runs E2B commands through the workspace gateway', async () => {
165
188
  let observed: { path: string; body: unknown } | null = null;
166
189
  const server = Bun.serve({
@@ -139,7 +139,7 @@ export declare const PLUGIN_CATALOG: readonly [{
139
139
  readonly description: "Analyze text for AI generation and plagiarism signals.";
140
140
  }, {
141
141
  readonly id: "vercel";
142
- readonly backend: "composio";
142
+ readonly backend: "native";
143
143
  readonly toolkit: "vercel";
144
144
  readonly authType: "api_key";
145
145
  readonly category: "data";
@@ -154,13 +154,13 @@ export declare const PLUGIN_CATALOG: readonly [{
154
154
  readonly name: "turbopuffer";
155
155
  readonly description: "Query and manage turbopuffer namespaces.";
156
156
  }, ...{
157
- id: "close" | "notion" | "jira" | "confluence" | "googlecalendar" | "microsoftteams" | "outlook" | "bitbucket" | "datadog" | "pagerduty" | "intercom" | "zendesk" | "hubspot" | "supabase" | "figma" | "launchdarkly" | "asana" | "clickup" | "trello" | "todoist" | "airtable" | "coda" | "miro" | "sharepoint" | "onedrive" | "googleslides" | "googlemeet" | "googletasks" | "dropbox" | "box" | "discord" | "discordbot" | "zoom" | "googlechat" | "newrelic" | "betterstack" | "incidentio" | "grafana" | "honeycomb" | "bugsnag" | "circleci" | "buildkite" | "dockerhub" | "digitalocean" | "railway" | "render" | "firebase" | "cloudinary" | "configcat" | "googleanalytics" | "googlebigquery" | "amplitude" | "mixpanel" | "segment" | "databricks" | "snowflake" | "algolia" | "elasticsearch" | "salesforce" | "pipedrive" | "apollo" | "gong" | "freshdesk" | "helpscout" | "servicenow" | "mailchimp" | "customerio" | "klaviyo" | "shopify" | "quickbooks" | "xero" | "brex" | "buffer" | "canva" | "webflow" | "firecrawl" | "browserbase" | "exa" | "youtube" | "twitter" | "instagram" | "facebook";
157
+ id: "close" | "notion" | "jira" | "confluence" | "googlecalendar" | "microsoftteams" | "outlook" | "bitbucket" | "datadog" | "pagerduty" | "intercom" | "zendesk" | "hubspot" | "supabase" | "figma" | "launchdarkly" | "asana" | "clickup" | "trello" | "todoist" | "airtable" | "coda" | "miro" | "sharepoint" | "onedrive" | "googleslides" | "googlemeet" | "googletasks" | "dropbox" | "box" | "discord" | "discordbot" | "zoom" | "googlechat" | "newrelic" | "betterstack" | "incidentio" | "grafana" | "honeycomb" | "bugsnag" | "circleci" | "buildkite" | "dockerhub" | "digitalocean" | "railway" | "render" | "firebase" | "cloudinary" | "configcat" | "googleanalytics" | "googlebigquery" | "amplitude" | "mixpanel" | "segment" | "databricks" | "snowflake" | "algolia" | "elasticsearch" | "salesforce" | "pipedrive" | "apollo" | "gong" | "freshdesk" | "helpscout" | "servicenow" | "mailchimp" | "customerio" | "klaviyo" | "shopify" | "quickbooks" | "xero" | "brex" | "buffer" | "docusign" | "canva" | "webflow" | "firecrawl" | "browserbase" | "exa" | "youtube" | "twitter" | "instagram" | "facebook";
158
158
  backend: "composio";
159
- toolkit: "close" | "notion" | "jira" | "confluence" | "googlecalendar" | "microsoft_teams" | "outlook" | "bitbucket" | "datadog" | "pagerduty" | "intercom" | "zendesk" | "hubspot" | "supabase" | "figma" | "launch_darkly" | "asana" | "clickup" | "trello" | "todoist" | "airtable" | "coda" | "miro" | "share_point" | "one_drive" | "googleslides" | "googlemeet" | "googletasks" | "dropbox" | "box" | "discord" | "discordbot" | "zoom" | "google_chat" | "new_relic" | "better_stack" | "incident_io" | "grafana" | "honeycomb_mcp" | "bugsnag" | "circleci" | "buildkite" | "docker_hub" | "digital_ocean" | "railway" | "render" | "firebase" | "cloudinary" | "configcat" | "google_analytics" | "googlebigquery" | "amplitude" | "mixpanel" | "segment" | "databricks" | "snowflake" | "algolia" | "elasticsearch" | "salesforce" | "pipedrive" | "apollo" | "gong" | "freshdesk" | "help_scout" | "servicenow" | "mailchimp" | "customerio" | "klaviyo" | "shopify" | "quickbooks" | "xero" | "brex" | "buffer" | "canva" | "webflow" | "firecrawl" | "browserbase_tool" | "exa" | "youtube" | "twitter" | "instagram" | "facebook";
159
+ toolkit: "close" | "notion" | "jira" | "confluence" | "googlecalendar" | "microsoft_teams" | "outlook" | "bitbucket" | "datadog" | "pagerduty" | "intercom" | "zendesk" | "hubspot" | "supabase" | "figma" | "launch_darkly" | "asana" | "clickup" | "trello" | "todoist" | "airtable" | "coda" | "miro" | "share_point" | "one_drive" | "googleslides" | "googlemeet" | "googletasks" | "dropbox" | "box" | "discord" | "discordbot" | "zoom" | "google_chat" | "new_relic" | "better_stack" | "incident_io" | "grafana" | "honeycomb_mcp" | "bugsnag" | "circleci" | "buildkite" | "docker_hub" | "digital_ocean" | "railway" | "render" | "firebase" | "cloudinary" | "configcat" | "google_analytics" | "googlebigquery" | "amplitude" | "mixpanel" | "segment" | "databricks" | "snowflake" | "algolia" | "elasticsearch" | "salesforce" | "pipedrive" | "apollo" | "gong" | "freshdesk" | "help_scout" | "servicenow" | "mailchimp" | "customerio" | "klaviyo" | "shopify" | "quickbooks" | "xero" | "brex" | "buffer" | "docusign" | "canva" | "webflow" | "firecrawl" | "browserbase_tool" | "exa" | "youtube" | "twitter" | "instagram" | "facebook";
160
160
  authType: "hosted";
161
161
  authScheme: "API_KEY" | "BASIC" | "BEARER_TOKEN" | "DCR_OAUTH" | "OAUTH1" | "OAUTH2";
162
162
  managedAuth: boolean;
163
163
  category: "data" | "productivity" | "business";
164
- name: "Notion" | "Jira" | "Confluence" | "Google Calendar" | "Microsoft Teams" | "Outlook" | "Bitbucket" | "Datadog" | "PagerDuty" | "Intercom" | "Zendesk" | "HubSpot" | "Supabase" | "Figma" | "LaunchDarkly" | "Asana" | "ClickUp" | "Trello" | "Todoist" | "Airtable" | "Coda" | "Miro" | "SharePoint" | "OneDrive" | "Google Slides" | "Google Meet" | "Google Tasks" | "Dropbox" | "Box" | "Discord" | "Discord Bot" | "Zoom" | "Google Chat" | "New Relic" | "Better Stack" | "incident.io" | "Grafana" | "Honeycomb MCP" | "Bugsnag" | "CircleCI" | "Buildkite" | "Docker Hub" | "DigitalOcean" | "Railway" | "Render" | "Firebase" | "Cloudinary" | "ConfigCat" | "Google Analytics" | "Google BigQuery" | "Amplitude" | "Mixpanel" | "Segment" | "Databricks" | "Snowflake" | "Algolia" | "Elasticsearch" | "Salesforce" | "Pipedrive" | "Close" | "Apollo" | "Gong" | "Freshdesk" | "Help Scout" | "ServiceNow" | "Mailchimp" | "Customer.io" | "Klaviyo" | "Shopify" | "QuickBooks" | "Xero" | "Brex" | "Buffer" | "Canva" | "Webflow" | "Firecrawl" | "Browserbase" | "Exa" | "YouTube" | "Twitter/X" | "Instagram" | "Facebook";
164
+ name: "Notion" | "Jira" | "Confluence" | "Google Calendar" | "Microsoft Teams" | "Outlook" | "Bitbucket" | "Datadog" | "PagerDuty" | "Intercom" | "Zendesk" | "HubSpot" | "Supabase" | "Figma" | "LaunchDarkly" | "Asana" | "ClickUp" | "Trello" | "Todoist" | "Airtable" | "Coda" | "Miro" | "SharePoint" | "OneDrive" | "Google Slides" | "Google Meet" | "Google Tasks" | "Dropbox" | "Box" | "Discord" | "Discord Bot" | "Zoom" | "Google Chat" | "New Relic" | "Better Stack" | "incident.io" | "Grafana" | "Honeycomb MCP" | "Bugsnag" | "CircleCI" | "Buildkite" | "Docker Hub" | "DigitalOcean" | "Railway" | "Render" | "Firebase" | "Cloudinary" | "ConfigCat" | "Google Analytics" | "Google BigQuery" | "Amplitude" | "Mixpanel" | "Segment" | "Databricks" | "Snowflake" | "Algolia" | "Elasticsearch" | "Salesforce" | "Pipedrive" | "Close" | "Apollo" | "Gong" | "Freshdesk" | "Help Scout" | "ServiceNow" | "Mailchimp" | "Customer.io" | "Klaviyo" | "Shopify" | "QuickBooks" | "Xero" | "Brex" | "Buffer" | "DocuSign" | "Canva" | "Webflow" | "Firecrawl" | "Browserbase" | "Exa" | "YouTube" | "Twitter/X" | "Instagram" | "Facebook";
165
165
  description: string;
166
166
  }[]];
@@ -60,6 +60,9 @@ export interface ReplicasSdk {
60
60
  planetscale: {
61
61
  request<T = unknown>(path: string, options?: ProviderRequestOptions): Promise<T>;
62
62
  };
63
+ vercel: {
64
+ request<T = unknown>(path: string, options?: ProviderRequestOptions): Promise<T>;
65
+ };
63
66
  pangram: {
64
67
  detect<T = unknown>(input: import('./routes/plugins').PangramAnalyzeRequest): Promise<T>;
65
68
  plagiarism<T = unknown>(text: string): Promise<T>;