replicas-engine 0.1.220 → 0.1.222
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/index.js +222 -78
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -32,6 +32,9 @@ function codexReasoningEffortForThinkingLevel(thinkingLevel) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// ../shared/src/event.ts
|
|
35
|
+
var ACCEPTED_USER_MESSAGE_SOURCE = "replicas-chat-turn-accepted";
|
|
36
|
+
var USER_MESSAGE_ID_PAYLOAD_KEY = "replicasMessageId";
|
|
37
|
+
var CODEX_ASP_ITEM_ID_PAYLOAD_KEY = "codexAspItemId";
|
|
35
38
|
var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
|
|
36
39
|
var COMPACTION_STATUS_EVENT_TYPE = "compaction-status";
|
|
37
40
|
var CHAT_GOAL_EVENT_TYPE = "chat-goal";
|
|
@@ -707,8 +710,8 @@ gh pr review 123 --request-changes --body "Changes needed"
|
|
|
707
710
|
GitHub does NOT have a public API for uploading images to PRs/issues. When you need to include images:
|
|
708
711
|
- Do NOT use placeholder image URLs
|
|
709
712
|
- Do NOT commit screenshots as files to the repository
|
|
710
|
-
-
|
|
711
|
-
- If you were triggered from Slack, also upload the
|
|
713
|
+
- Use the \`replicas-agent\` skill to share the image
|
|
714
|
+
- If you were triggered from Slack, also upload the image to the Slack thread so the user can see it directly
|
|
712
715
|
`;
|
|
713
716
|
var GITHUB_ABILITY = {
|
|
714
717
|
label: "GitHub",
|
|
@@ -1156,10 +1159,9 @@ After (or alongside) the embeds, include a \`[View in Replicas](<deep-link>)\` h
|
|
|
1156
1159
|
|
|
1157
1160
|
### On external platforms (Slack, Linear, GitHub, etc.)
|
|
1158
1161
|
|
|
1159
|
-
|
|
1162
|
+
Always include a \`[View in Replicas](<deep-link>)\` hyperlink \u2014 use the per-file deep link the CLI printed for that file (\`...?mode=media&media=<media-id>\`), so the recipient lands directly on that specific item.
|
|
1160
1163
|
|
|
1161
|
-
|
|
1162
|
-
2. Include a \`[View in Replicas](<deep-link>)\` hyperlink \u2014 use the per-file deep link the CLI printed for that file (\`...?mode=media&media=<media-id>\`), so the recipient lands directly on that specific item.
|
|
1164
|
+
For platforms that support native uploads (Slack \`files.upload\`, Linear attachments, etc.), upload the raw bytes there too so the recipient sees the media inline in addition to the Replicas link. GitHub PRs/issues do not have a public upload API, so the \`View in Replicas\` link is the canonical way to share media there \u2014 do not commit screenshots to the repo and do not use placeholder URLs.
|
|
1163
1165
|
|
|
1164
1166
|
Do **not** include the \`\` markdown embed in external messages. It will render as a broken image / 401 for the recipient.
|
|
1165
1167
|
|
|
@@ -1205,7 +1207,7 @@ replicas media upload chart-a.svg chart-b.svg --kind image
|
|
|
1205
1207
|
var MEDIA_ABILITY = {
|
|
1206
1208
|
label: "Media",
|
|
1207
1209
|
description: "Share screenshots, recordings, generated images, and audio clips.",
|
|
1208
|
-
bullet: "-
|
|
1210
|
+
bullet: "- Producing or showing the user any media \u2014 screenshots, screen recordings, generated images or diagrams, audio clips \u2014 including in your Replicas chat reply, PR descriptions/comments, and other external platforms",
|
|
1209
1211
|
section: SECTION6,
|
|
1210
1212
|
referenceFile: { name: "MEDIA.md", content: REFERENCE6 }
|
|
1211
1213
|
};
|
|
@@ -1761,7 +1763,7 @@ function parseReplicasConfigString(content, filename) {
|
|
|
1761
1763
|
}
|
|
1762
1764
|
|
|
1763
1765
|
// ../shared/src/engine/environment.ts
|
|
1764
|
-
var DAYTONA_SNAPSHOT_ID = "27-05-2026-royal-york-
|
|
1766
|
+
var DAYTONA_SNAPSHOT_ID = "27-05-2026-royal-york-v6";
|
|
1765
1767
|
|
|
1766
1768
|
// ../shared/src/engine/types.ts
|
|
1767
1769
|
var DEFAULT_CHAT_TITLES = {
|
|
@@ -1814,6 +1816,12 @@ function codexAuthEnvFromResponse(response) {
|
|
|
1814
1816
|
return { OPENAI_API_KEY: response.apiKey, REPLICAS_CODEX_AUTH_METHOD: "api_key" };
|
|
1815
1817
|
}
|
|
1816
1818
|
}
|
|
1819
|
+
var CODEX_AUTH_ENV_KEYS_BY_METHOD = {
|
|
1820
|
+
none: [],
|
|
1821
|
+
oauth: ["REPLICAS_CODEX_AUTH_METHOD"],
|
|
1822
|
+
api_key: ["OPENAI_API_KEY", "REPLICAS_CODEX_AUTH_METHOD"],
|
|
1823
|
+
bedrock: []
|
|
1824
|
+
};
|
|
1817
1825
|
|
|
1818
1826
|
// ../shared/src/routes/claude.ts
|
|
1819
1827
|
var CLAUDE_AUTH_ENV_KEYS = [
|
|
@@ -1840,6 +1848,18 @@ function claudeAuthEnvFromResponse(response) {
|
|
|
1840
1848
|
};
|
|
1841
1849
|
}
|
|
1842
1850
|
}
|
|
1851
|
+
var CLAUDE_AUTH_ENV_KEYS_BY_METHOD = {
|
|
1852
|
+
none: [],
|
|
1853
|
+
oauth: ["REPLICAS_CLAUDE_AUTH_METHOD"],
|
|
1854
|
+
api_key: ["ANTHROPIC_API_KEY", "REPLICAS_CLAUDE_AUTH_METHOD"],
|
|
1855
|
+
bedrock: [
|
|
1856
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
1857
|
+
"AWS_ACCESS_KEY_ID",
|
|
1858
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
1859
|
+
"AWS_REGION",
|
|
1860
|
+
"REPLICAS_CLAUDE_AUTH_METHOD"
|
|
1861
|
+
]
|
|
1862
|
+
};
|
|
1843
1863
|
|
|
1844
1864
|
// ../shared/src/routes/workspaces.ts
|
|
1845
1865
|
var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
@@ -1863,6 +1883,50 @@ var MEDIA_KIND = {
|
|
|
1863
1883
|
};
|
|
1864
1884
|
var MEDIA_KINDS = [MEDIA_KIND.IMAGE, MEDIA_KIND.VIDEO, MEDIA_KIND.AUDIO];
|
|
1865
1885
|
|
|
1886
|
+
// ../shared/src/agent-event-utils.ts
|
|
1887
|
+
function getUserMessage(event) {
|
|
1888
|
+
return event.type === "event_msg" && event.payload.type === "user_message" && typeof event.payload.message === "string" ? event.payload.message : null;
|
|
1889
|
+
}
|
|
1890
|
+
function getUserMessageId(event) {
|
|
1891
|
+
const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
|
|
1892
|
+
return typeof messageId === "string" ? messageId : null;
|
|
1893
|
+
}
|
|
1894
|
+
function getUserMessageItemId(event) {
|
|
1895
|
+
const itemId = event.payload[CODEX_ASP_ITEM_ID_PAYLOAD_KEY];
|
|
1896
|
+
return typeof itemId === "string" ? itemId : null;
|
|
1897
|
+
}
|
|
1898
|
+
function getEventTimestampMs(event) {
|
|
1899
|
+
const value = Date.parse(event.timestamp);
|
|
1900
|
+
return Number.isNaN(value) ? 0 : value;
|
|
1901
|
+
}
|
|
1902
|
+
function areSameUserMessageEvents(a, b) {
|
|
1903
|
+
const aMessage = getUserMessage(a);
|
|
1904
|
+
const bMessage = getUserMessage(b);
|
|
1905
|
+
if (!aMessage || aMessage !== bMessage) return false;
|
|
1906
|
+
const aMessageId = getUserMessageId(a);
|
|
1907
|
+
const bMessageId = getUserMessageId(b);
|
|
1908
|
+
if (aMessageId || bMessageId) return aMessageId === bMessageId;
|
|
1909
|
+
const aItemId = getUserMessageItemId(a);
|
|
1910
|
+
const bItemId = getUserMessageItemId(b);
|
|
1911
|
+
if (aItemId || bItemId) return aItemId === bItemId;
|
|
1912
|
+
return Math.abs(getEventTimestampMs(a) - getEventTimestampMs(b)) <= 3e4;
|
|
1913
|
+
}
|
|
1914
|
+
function mergeAgentEvents(primary, supplemental, options) {
|
|
1915
|
+
const merged = [...primary];
|
|
1916
|
+
const { areDuplicates, mergeEvent } = options;
|
|
1917
|
+
for (const event of supplemental) {
|
|
1918
|
+
const existingIndex = merged.findIndex((existing) => areDuplicates(existing, event));
|
|
1919
|
+
if (existingIndex === -1) {
|
|
1920
|
+
merged.push(event);
|
|
1921
|
+
continue;
|
|
1922
|
+
}
|
|
1923
|
+
if (mergeEvent) {
|
|
1924
|
+
merged[existingIndex] = mergeEvent(merged[existingIndex], event);
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
return merged;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1866
1930
|
// src/runtime-env-loader.ts
|
|
1867
1931
|
function loadRuntimeEnvFile() {
|
|
1868
1932
|
let content;
|
|
@@ -2108,6 +2172,26 @@ var githubTokenManager = new GitHubTokenManager();
|
|
|
2108
2172
|
// src/managers/claude-token-manager.ts
|
|
2109
2173
|
import { promises as fs2 } from "fs";
|
|
2110
2174
|
import path2 from "path";
|
|
2175
|
+
|
|
2176
|
+
// src/managers/auth-env-transition.ts
|
|
2177
|
+
function applyAuthEnvTransition(params) {
|
|
2178
|
+
const newOwned = new Set(params.authKeysByMethod[params.newMethod]);
|
|
2179
|
+
const prevOwned = new Set(params.authKeysByMethod[params.prevMethod]);
|
|
2180
|
+
for (const key of params.authKeys) {
|
|
2181
|
+
const value = params.newEnvVars[key];
|
|
2182
|
+
if (value !== void 0) {
|
|
2183
|
+
for (const env of params.envs) {
|
|
2184
|
+
env[key] = value;
|
|
2185
|
+
}
|
|
2186
|
+
} else if (prevOwned.has(key) && !newOwned.has(key)) {
|
|
2187
|
+
for (const env of params.envs) {
|
|
2188
|
+
delete env[key];
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
// src/managers/claude-token-manager.ts
|
|
2111
2195
|
var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
2112
2196
|
constructor() {
|
|
2113
2197
|
super("ClaudeTokenManager");
|
|
@@ -2175,34 +2259,14 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
2175
2259
|
await this.removeOauthCredentialsFile();
|
|
2176
2260
|
}
|
|
2177
2261
|
const envVars = claudeAuthEnvFromResponse(response);
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
case "CLAUDE_CODE_USE_BEDROCK":
|
|
2187
|
-
ENGINE_ENV.CLAUDE_CODE_USE_BEDROCK = envVars.CLAUDE_CODE_USE_BEDROCK;
|
|
2188
|
-
break;
|
|
2189
|
-
case "AWS_ACCESS_KEY_ID":
|
|
2190
|
-
ENGINE_ENV.AWS_ACCESS_KEY_ID = envVars.AWS_ACCESS_KEY_ID;
|
|
2191
|
-
break;
|
|
2192
|
-
case "AWS_SECRET_ACCESS_KEY":
|
|
2193
|
-
ENGINE_ENV.AWS_SECRET_ACCESS_KEY = envVars.AWS_SECRET_ACCESS_KEY;
|
|
2194
|
-
break;
|
|
2195
|
-
case "AWS_REGION":
|
|
2196
|
-
ENGINE_ENV.AWS_REGION = envVars.AWS_REGION;
|
|
2197
|
-
break;
|
|
2198
|
-
}
|
|
2199
|
-
const value = envVars[key];
|
|
2200
|
-
if (value !== void 0) {
|
|
2201
|
-
process.env[key] = value;
|
|
2202
|
-
} else {
|
|
2203
|
-
delete process.env[key];
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2262
|
+
applyAuthEnvTransition({
|
|
2263
|
+
prevMethod: ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD ?? "none",
|
|
2264
|
+
newMethod: envVars.REPLICAS_CLAUDE_AUTH_METHOD ?? "none",
|
|
2265
|
+
authKeys: CLAUDE_AUTH_ENV_KEYS,
|
|
2266
|
+
authKeysByMethod: CLAUDE_AUTH_ENV_KEYS_BY_METHOD,
|
|
2267
|
+
newEnvVars: envVars,
|
|
2268
|
+
envs: [ENGINE_ENV, process.env]
|
|
2269
|
+
});
|
|
2206
2270
|
}
|
|
2207
2271
|
async writeOauthCredentialsFile(credentials) {
|
|
2208
2272
|
const workspaceHome = ENGINE_ENV.HOME_DIR;
|
|
@@ -2301,22 +2365,14 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
2301
2365
|
await this.removeOauthCredentialsFile();
|
|
2302
2366
|
}
|
|
2303
2367
|
const envVars = codexAuthEnvFromResponse(response);
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2313
|
-
const value = envVars[key];
|
|
2314
|
-
if (value !== void 0) {
|
|
2315
|
-
process.env[key] = value;
|
|
2316
|
-
} else {
|
|
2317
|
-
delete process.env[key];
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2368
|
+
applyAuthEnvTransition({
|
|
2369
|
+
prevMethod: ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? "none",
|
|
2370
|
+
newMethod: envVars.REPLICAS_CODEX_AUTH_METHOD ?? "none",
|
|
2371
|
+
authKeys: CODEX_AUTH_ENV_KEYS,
|
|
2372
|
+
authKeysByMethod: CODEX_AUTH_ENV_KEYS_BY_METHOD,
|
|
2373
|
+
newEnvVars: envVars,
|
|
2374
|
+
envs: [ENGINE_ENV, process.env]
|
|
2375
|
+
});
|
|
2320
2376
|
}
|
|
2321
2377
|
async writeOauthCredentialsFile(credentials) {
|
|
2322
2378
|
const workspaceHome = ENGINE_ENV.HOME_DIR;
|
|
@@ -6265,21 +6321,27 @@ function itemToAgentEventDrafts(item, lifecycle) {
|
|
|
6265
6321
|
}
|
|
6266
6322
|
function threadToHistoryEvents(thread) {
|
|
6267
6323
|
const events = [];
|
|
6268
|
-
|
|
6324
|
+
const turns = thread.turns.map((turn, index) => ({ turn, index })).sort((a, b) => (a.turn.startedAt ?? a.turn.completedAt ?? Number.MAX_SAFE_INTEGER) - (b.turn.startedAt ?? b.turn.completedAt ?? Number.MAX_SAFE_INTEGER) || a.index - b.index);
|
|
6325
|
+
for (const { turn } of turns) {
|
|
6269
6326
|
const startedAt = timestampFromSeconds(turn.startedAt);
|
|
6270
6327
|
const completedAt = timestampFromSeconds(turn.completedAt ?? turn.startedAt);
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6328
|
+
const userMessages = turn.items.filter((item) => item.type === "userMessage");
|
|
6329
|
+
const agentItems = turn.items.filter((item) => item.type !== "userMessage");
|
|
6330
|
+
for (const item of userMessages) {
|
|
6331
|
+
const message = item.content.filter((input) => input.type === "text").map((input) => input.text).join("\n");
|
|
6332
|
+
if (message) {
|
|
6333
|
+
events.push({
|
|
6334
|
+
timestamp: startedAt,
|
|
6335
|
+
type: "event_msg",
|
|
6336
|
+
payload: {
|
|
6337
|
+
type: "user_message",
|
|
6338
|
+
message,
|
|
6339
|
+
[CODEX_ASP_ITEM_ID_PAYLOAD_KEY]: item.id
|
|
6340
|
+
}
|
|
6341
|
+
});
|
|
6282
6342
|
}
|
|
6343
|
+
}
|
|
6344
|
+
for (const item of agentItems) {
|
|
6283
6345
|
for (const draft of itemToAgentEventDrafts(item, "started")) {
|
|
6284
6346
|
events.push({ timestamp: startedAt, ...draft });
|
|
6285
6347
|
}
|
|
@@ -6380,6 +6442,49 @@ function dispatchAspNotification(notification, handlers) {
|
|
|
6380
6442
|
}
|
|
6381
6443
|
|
|
6382
6444
|
// src/managers/codex-asp/codex-asp-manager.ts
|
|
6445
|
+
function historyEventKey(event) {
|
|
6446
|
+
const payloadType = typeof event.payload.type === "string" ? event.payload.type : null;
|
|
6447
|
+
const callId = typeof event.payload.call_id === "string" ? event.payload.call_id : null;
|
|
6448
|
+
const itemId = typeof event.payload[CODEX_ASP_ITEM_ID_PAYLOAD_KEY] === "string" ? event.payload[CODEX_ASP_ITEM_ID_PAYLOAD_KEY] : null;
|
|
6449
|
+
const messageId = typeof event.payload[USER_MESSAGE_ID_PAYLOAD_KEY] === "string" ? event.payload[USER_MESSAGE_ID_PAYLOAD_KEY] : null;
|
|
6450
|
+
if (event.type === "response_item" && payloadType && callId) {
|
|
6451
|
+
return `${event.type}:${payloadType}:${callId}`;
|
|
6452
|
+
}
|
|
6453
|
+
if (event.type === "event_msg" && event.payload.type === "user_message") {
|
|
6454
|
+
if (messageId) return `${event.type}:user_message:message:${messageId}`;
|
|
6455
|
+
if (itemId) return `${event.type}:user_message:item:${itemId}`;
|
|
6456
|
+
const command = typeof event.payload.command === "string" ? event.payload.command : "";
|
|
6457
|
+
const message = typeof event.payload.message === "string" ? event.payload.message : "";
|
|
6458
|
+
return `${event.type}:user_message:${event.timestamp}:${command}:${message}`;
|
|
6459
|
+
}
|
|
6460
|
+
if (itemId && payloadType) {
|
|
6461
|
+
return `${event.type}:${payloadType}:item:${itemId}`;
|
|
6462
|
+
}
|
|
6463
|
+
return `${event.type}:${event.timestamp}:${JSON.stringify(event.payload)}`;
|
|
6464
|
+
}
|
|
6465
|
+
function areDuplicateHistoryEvents(a, b) {
|
|
6466
|
+
if (historyEventKey(a) === historyEventKey(b)) return true;
|
|
6467
|
+
return areSameUserMessageEvents(a, b);
|
|
6468
|
+
}
|
|
6469
|
+
function mergeHistoryEvent(current, candidate) {
|
|
6470
|
+
if (getUserMessage(current) && getUserMessage(current) === getUserMessage(candidate)) {
|
|
6471
|
+
return {
|
|
6472
|
+
...current,
|
|
6473
|
+
timestamp: getEventTimestampMs(current) <= getEventTimestampMs(candidate) ? current.timestamp : candidate.timestamp,
|
|
6474
|
+
payload: {
|
|
6475
|
+
...current.payload,
|
|
6476
|
+
...candidate.payload
|
|
6477
|
+
}
|
|
6478
|
+
};
|
|
6479
|
+
}
|
|
6480
|
+
return candidate;
|
|
6481
|
+
}
|
|
6482
|
+
function mergeHistoryEvents(primary, supplemental) {
|
|
6483
|
+
return mergeAgentEvents(primary, supplemental, {
|
|
6484
|
+
areDuplicates: areDuplicateHistoryEvents,
|
|
6485
|
+
mergeEvent: mergeHistoryEvent
|
|
6486
|
+
});
|
|
6487
|
+
}
|
|
6383
6488
|
var CodexAspManager = class extends CodingAgentManager {
|
|
6384
6489
|
currentThreadId = null;
|
|
6385
6490
|
activeTurnId = null;
|
|
@@ -6425,15 +6530,13 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6425
6530
|
),
|
|
6426
6531
|
this.refreshThreadGoal(host, this.currentThreadId)
|
|
6427
6532
|
]);
|
|
6428
|
-
const events = threadToHistoryEvents(response.thread);
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
};
|
|
6436
|
-
}
|
|
6533
|
+
const events = mergeHistoryEvents(this.historyEvents, threadToHistoryEvents(response.thread));
|
|
6534
|
+
this.historyEvents.splice(0, this.historyEvents.length, ...events);
|
|
6535
|
+
return {
|
|
6536
|
+
thread_id: this.currentThreadId,
|
|
6537
|
+
events,
|
|
6538
|
+
goal: this.currentGoal
|
|
6539
|
+
};
|
|
6437
6540
|
} catch {
|
|
6438
6541
|
}
|
|
6439
6542
|
return {
|
|
@@ -6492,8 +6595,8 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6492
6595
|
async executeGoalClearCommand(request, recordUserMessage) {
|
|
6493
6596
|
const host = await getCodexAspHost();
|
|
6494
6597
|
const developerInstructions = this.buildCombinedInstructions(request.customInstructions);
|
|
6495
|
-
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
6496
6598
|
recordUserMessage({ command: "goal" });
|
|
6599
|
+
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
6497
6600
|
await host.client.request(
|
|
6498
6601
|
THREAD_GOAL_CLEAR_METHOD,
|
|
6499
6602
|
{ threadId }
|
|
@@ -6511,8 +6614,8 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6511
6614
|
}
|
|
6512
6615
|
}
|
|
6513
6616
|
const developerInstructions = this.buildCombinedInstructions(request.customInstructions);
|
|
6514
|
-
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
6515
6617
|
recordUserMessage(options.userMessagePayload);
|
|
6618
|
+
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
6516
6619
|
const runTurn = options.runTurn ?? ((aspHost, aspThreadId, aspInstructions) => this.runTurn(aspHost, aspThreadId, request, aspInstructions));
|
|
6517
6620
|
let completedTurn;
|
|
6518
6621
|
try {
|
|
@@ -6747,8 +6850,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6747
6850
|
}
|
|
6748
6851
|
seedHistoryFromThread(thread) {
|
|
6749
6852
|
const events = threadToHistoryEvents(thread);
|
|
6750
|
-
|
|
6751
|
-
this.historyEvents.splice(0, this.historyEvents.length, ...events);
|
|
6853
|
+
this.historyEvents.splice(0, this.historyEvents.length, ...mergeHistoryEvents(this.historyEvents, events));
|
|
6752
6854
|
}
|
|
6753
6855
|
async refreshThreadGoal(host, threadId) {
|
|
6754
6856
|
try {
|
|
@@ -7457,6 +7559,19 @@ function isPersistedChat(value) {
|
|
|
7457
7559
|
const candidate = value;
|
|
7458
7560
|
return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "relay") && typeof candidate.title === "string" && typeof candidate.createdAt === "string" && typeof candidate.updatedAt === "string" && (candidate.providerSessionId === null || typeof candidate.providerSessionId === "string") && (candidate.parentChatId === void 0 || candidate.parentChatId === null || typeof candidate.parentChatId === "string");
|
|
7459
7561
|
}
|
|
7562
|
+
function createUserMessageEvent(message, messageId) {
|
|
7563
|
+
return {
|
|
7564
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7565
|
+
type: "event_msg",
|
|
7566
|
+
payload: {
|
|
7567
|
+
type: "user_message",
|
|
7568
|
+
message,
|
|
7569
|
+
source: ACCEPTED_USER_MESSAGE_SOURCE,
|
|
7570
|
+
[USER_MESSAGE_ID_PAYLOAD_KEY]: messageId
|
|
7571
|
+
}
|
|
7572
|
+
};
|
|
7573
|
+
}
|
|
7574
|
+
var isSameUserMessageEvent = areSameUserMessageEvents;
|
|
7460
7575
|
var ChatService = class {
|
|
7461
7576
|
constructor(workingDirectory) {
|
|
7462
7577
|
this.workingDirectory = workingDirectory;
|
|
@@ -7534,7 +7649,9 @@ var ChatService = class {
|
|
|
7534
7649
|
async sendMessage(chatId, request) {
|
|
7535
7650
|
const chat = this.requireChat(chatId);
|
|
7536
7651
|
const result = await chat.provider.enqueueMessage(request);
|
|
7652
|
+
const acceptedEvent = createUserMessageEvent(request.message, result.messageId);
|
|
7537
7653
|
chat.pendingMessageIds.push(result.messageId);
|
|
7654
|
+
chat.acceptedUserEvents.set(result.messageId, acceptedEvent);
|
|
7538
7655
|
this.touch(chat);
|
|
7539
7656
|
let recordedSender;
|
|
7540
7657
|
if (request.senderUserId && request.senderEmail) {
|
|
@@ -7553,6 +7670,7 @@ var ChatService = class {
|
|
|
7553
7670
|
messageId: result.messageId,
|
|
7554
7671
|
queued: result.queued,
|
|
7555
7672
|
position: result.position,
|
|
7673
|
+
event: acceptedEvent,
|
|
7556
7674
|
...recordedSender ? { sender: recordedSender } : {}
|
|
7557
7675
|
}
|
|
7558
7676
|
});
|
|
@@ -7599,8 +7717,10 @@ var ChatService = class {
|
|
|
7599
7717
|
const chat = this.requireChat(chatId);
|
|
7600
7718
|
const result = await chat.provider.interrupt();
|
|
7601
7719
|
chat.hasActiveTurn = false;
|
|
7720
|
+
chat.activeMessageId = null;
|
|
7602
7721
|
keepAliveService.stop();
|
|
7603
7722
|
chat.pendingMessageIds = [];
|
|
7723
|
+
chat.acceptedUserEvents.clear();
|
|
7604
7724
|
this.touch(chat);
|
|
7605
7725
|
await this.publish({
|
|
7606
7726
|
type: "chat.interrupted",
|
|
@@ -7690,9 +7810,10 @@ var ChatService = class {
|
|
|
7690
7810
|
chat.provider.getHistory(),
|
|
7691
7811
|
this.readSenders(chatId)
|
|
7692
7812
|
]);
|
|
7813
|
+
const acceptedEvents = [...chat.acceptedUserEvents.values()].filter((acceptedEvent) => !history.events.some((event) => isSameUserMessageEvent(event, acceptedEvent)));
|
|
7693
7814
|
return {
|
|
7694
7815
|
thread_id: history.thread_id,
|
|
7695
|
-
events: history.events,
|
|
7816
|
+
events: [...history.events, ...acceptedEvents],
|
|
7696
7817
|
goal: history.goal ?? chat.provider.getGoal?.() ?? null,
|
|
7697
7818
|
senders
|
|
7698
7819
|
};
|
|
@@ -7760,6 +7881,8 @@ var ChatService = class {
|
|
|
7760
7881
|
persisted,
|
|
7761
7882
|
provider,
|
|
7762
7883
|
pendingMessageIds: [],
|
|
7884
|
+
acceptedUserEvents: /* @__PURE__ */ new Map(),
|
|
7885
|
+
activeMessageId: null,
|
|
7763
7886
|
hasActiveTurn: false,
|
|
7764
7887
|
observedBranchesByRepo: /* @__PURE__ */ new Map()
|
|
7765
7888
|
};
|
|
@@ -7801,6 +7924,7 @@ var ChatService = class {
|
|
|
7801
7924
|
return;
|
|
7802
7925
|
}
|
|
7803
7926
|
chat.hasActiveTurn = true;
|
|
7927
|
+
chat.activeMessageId = messageId;
|
|
7804
7928
|
keepAliveService.start();
|
|
7805
7929
|
this.publish({
|
|
7806
7930
|
type: "chat.turn.started",
|
|
@@ -7811,6 +7935,25 @@ var ChatService = class {
|
|
|
7811
7935
|
}).catch(() => {
|
|
7812
7936
|
});
|
|
7813
7937
|
}
|
|
7938
|
+
let eventToPublish = event;
|
|
7939
|
+
if (event.type === "event_msg" && event.payload.type === "user_message") {
|
|
7940
|
+
if (chat.activeMessageId) {
|
|
7941
|
+
event.payload[USER_MESSAGE_ID_PAYLOAD_KEY] = chat.activeMessageId;
|
|
7942
|
+
eventToPublish = {
|
|
7943
|
+
...event,
|
|
7944
|
+
payload: {
|
|
7945
|
+
...event.payload,
|
|
7946
|
+
[USER_MESSAGE_ID_PAYLOAD_KEY]: chat.activeMessageId
|
|
7947
|
+
}
|
|
7948
|
+
};
|
|
7949
|
+
}
|
|
7950
|
+
for (const [messageId, acceptedEvent] of chat.acceptedUserEvents) {
|
|
7951
|
+
if (isSameUserMessageEvent(event, acceptedEvent)) {
|
|
7952
|
+
chat.acceptedUserEvents.delete(messageId);
|
|
7953
|
+
break;
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
}
|
|
7814
7957
|
this.touch(chat);
|
|
7815
7958
|
this.observeCurrentBranches(chat).catch(() => {
|
|
7816
7959
|
});
|
|
@@ -7818,7 +7961,7 @@ var ChatService = class {
|
|
|
7818
7961
|
type: "chat.turn.delta",
|
|
7819
7962
|
payload: {
|
|
7820
7963
|
chatId,
|
|
7821
|
-
event
|
|
7964
|
+
event: eventToPublish
|
|
7822
7965
|
}
|
|
7823
7966
|
}).catch(() => {
|
|
7824
7967
|
});
|
|
@@ -7840,6 +7983,7 @@ var ChatService = class {
|
|
|
7840
7983
|
return;
|
|
7841
7984
|
}
|
|
7842
7985
|
chat.hasActiveTurn = false;
|
|
7986
|
+
chat.activeMessageId = null;
|
|
7843
7987
|
keepAliveService.stop();
|
|
7844
7988
|
this.publish({
|
|
7845
7989
|
type: "chat.turn.completed",
|