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.
- package/dist/src/{chunk-SC7MWNN2.js → chunk-KS4CJNWB.js} +114 -96
- package/dist/src/headless-agent.js +1 -1
- package/dist/src/index.js +156 -62
- package/package.json +1 -1
- package/workspace-sdk/index.js +3 -1
- package/workspace-sdk/index.test.ts +23 -0
- package/workspace-sdk/shared/routes/plugin-catalog.d.ts +4 -4
- package/workspace-sdk/shared/workspace-sdk.d.ts +3 -0
|
@@ -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: "
|
|
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
|
-
|
|
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
|
|
6184
|
+
const applySyntheticNotices = (messages) => shouldFilter ? applyAuthFallbackNotices(applyInterruptions(messages, events), events) : messages;
|
|
6161
6185
|
if (agentType !== "codex" || !codexAspTranscript) {
|
|
6162
|
-
return
|
|
6186
|
+
return applySyntheticNotices(legacyMessages);
|
|
6163
6187
|
}
|
|
6164
6188
|
const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
|
|
6165
|
-
return
|
|
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
|
-
|
|
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)
|
|
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.
|
|
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";
|
package/dist/src/index.js
CHANGED
|
@@ -192,7 +192,7 @@ import {
|
|
|
192
192
|
serializeCanvasContentResponse,
|
|
193
193
|
shellQuotePosix,
|
|
194
194
|
stripAgentDiagnosticErrors
|
|
195
|
-
} from "./chunk-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
12070
|
-
request
|
|
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
|
-
|
|
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
package/workspace-sdk/index.js
CHANGED
|
@@ -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: "
|
|
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>;
|