replicas-engine 0.1.654 → 0.1.656
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/README.md +1 -0
- package/dist/src/{chunk-DDFRCI5Q.js → chunk-KCMDTZ5H.js} +137 -8
- package/dist/src/headless-agent.js +1 -1
- package/dist/src/index.js +212 -146
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ Chats:
|
|
|
28
28
|
- `GET /chats/:chatId`
|
|
29
29
|
- `DELETE /chats/:chatId`
|
|
30
30
|
- `GET /chats/:chatId/history`
|
|
31
|
+
- `GET /chats/:chatId/history-page?limit=<count>` (`limit` required)
|
|
31
32
|
- `GET /chats/:chatId/slash-commands`
|
|
32
33
|
- `POST /chats/:chatId/messages`
|
|
33
34
|
- `POST /chats/:chatId/interrupt`
|
|
@@ -758,7 +758,7 @@ var sendChatMessageRequestSchema = z3.object({
|
|
|
758
758
|
]).optional()
|
|
759
759
|
}).passthrough();
|
|
760
760
|
function isChatMessageSender(value) {
|
|
761
|
-
return isRecord(value) && typeof value.senderUserId === "string" && typeof value.senderEmail === "string" && typeof value.recordedAt === "string";
|
|
761
|
+
return isRecord(value) && (value.messageId === void 0 || typeof value.messageId === "string") && typeof value.senderUserId === "string" && typeof value.senderEmail === "string" && typeof value.recordedAt === "string";
|
|
762
762
|
}
|
|
763
763
|
function normalizeCodexAspTranscriptStatus(status, failed = false) {
|
|
764
764
|
if (failed || status === "failed" || status === "declined") return "failed";
|
|
@@ -881,6 +881,27 @@ function applyCodexAspTranscriptDelta(current, delta) {
|
|
|
881
881
|
turns
|
|
882
882
|
};
|
|
883
883
|
}
|
|
884
|
+
function isLatestChatHistoryPage(params) {
|
|
885
|
+
return params.beforeCursor === void 0 && params.beforeEvent === void 0 && params.beforeTurn === void 0;
|
|
886
|
+
}
|
|
887
|
+
function getChatHistoryPageSenders(senders, params) {
|
|
888
|
+
return isLatestChatHistoryPage(params) ? senders : senders?.filter((sender) => sender.messageId);
|
|
889
|
+
}
|
|
890
|
+
function parseChatHistoryCursor(value) {
|
|
891
|
+
if (value === void 0) return void 0;
|
|
892
|
+
try {
|
|
893
|
+
const parsed = JSON.parse(value);
|
|
894
|
+
if (!isRecord(parsed) || parsed.mode !== "range" && parsed.mode !== "legacy") return void 0;
|
|
895
|
+
const valid = (part) => part === null || typeof part === "string";
|
|
896
|
+
if (!valid(parsed.events) || !valid(parsed.turns)) return void 0;
|
|
897
|
+
return { mode: parsed.mode, events: parsed.events, turns: parsed.turns };
|
|
898
|
+
} catch {
|
|
899
|
+
return void 0;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
function createChatHistoryCursor(cursor, mode = "range") {
|
|
903
|
+
return cursor.events === null && cursor.turns === null ? null : JSON.stringify({ mode, ...cursor });
|
|
904
|
+
}
|
|
884
905
|
function chatHistoryPageParamsFromQuery(query) {
|
|
885
906
|
const parse = (value) => {
|
|
886
907
|
if (value === void 0) return void 0;
|
|
@@ -890,7 +911,8 @@ function chatHistoryPageParamsFromQuery(query) {
|
|
|
890
911
|
return {
|
|
891
912
|
limit: parse(query.limit),
|
|
892
913
|
beforeEvent: parse(query.beforeEvent),
|
|
893
|
-
beforeTurn: parse(query.beforeTurn)
|
|
914
|
+
beforeTurn: parse(query.beforeTurn),
|
|
915
|
+
beforeCursor: query.beforeCursor || void 0
|
|
894
916
|
};
|
|
895
917
|
}
|
|
896
918
|
function getChatHistoryPageWindow(totalItems, limit, before) {
|
|
@@ -5723,6 +5745,105 @@ var EMAIL_KEYS = [
|
|
|
5723
5745
|
var MANUAL_EMAIL_TEMPLATE_KEYS = ["product_update"];
|
|
5724
5746
|
var EMAIL_TEMPLATE_KEYS = [...EMAIL_KEYS, ...MANUAL_EMAIL_TEMPLATE_KEYS];
|
|
5725
5747
|
|
|
5748
|
+
// ../shared/src/chat-transcript-pages.ts
|
|
5749
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
5750
|
+
var MAX_SOURCE_PAGE_BYTES = 4 * 1024 * 1024;
|
|
5751
|
+
var SOURCE_RANGE_BYTES = 256 * 1024;
|
|
5752
|
+
async function readExactRange(readRange, startByte, endByte, error) {
|
|
5753
|
+
const bytes = await readRange(startByte, endByte);
|
|
5754
|
+
if (bytes.length !== endByte - startByte) throw new Error(error);
|
|
5755
|
+
return bytes;
|
|
5756
|
+
}
|
|
5757
|
+
async function readJsonlPage(args) {
|
|
5758
|
+
let endByte = args.size;
|
|
5759
|
+
if (args.before === null) endByte = 0;
|
|
5760
|
+
else if (args.before !== void 0) {
|
|
5761
|
+
endByte = /^(0|[1-9]\d*)$/.test(args.before) ? Number(args.before) : Number.NaN;
|
|
5762
|
+
}
|
|
5763
|
+
if (!Number.isSafeInteger(endByte) || endByte < 0 || endByte > args.size || !Number.isSafeInteger(args.limit) || args.limit < 1) {
|
|
5764
|
+
throw new RangeError("Invalid JSONL page");
|
|
5765
|
+
}
|
|
5766
|
+
let startByte = endByte;
|
|
5767
|
+
let bytes = new Uint8Array();
|
|
5768
|
+
let items = [];
|
|
5769
|
+
while (startByte > 0 && items.length < args.limit && (endByte - startByte < MAX_SOURCE_PAGE_BYTES || bytes.indexOf(10) === -1)) {
|
|
5770
|
+
const nextStartByte = Math.max(0, startByte - SOURCE_RANGE_BYTES);
|
|
5771
|
+
const chunk = await readExactRange(
|
|
5772
|
+
args.readRange,
|
|
5773
|
+
nextStartByte,
|
|
5774
|
+
startByte,
|
|
5775
|
+
"Incomplete JSONL page read"
|
|
5776
|
+
);
|
|
5777
|
+
const combined = new Uint8Array(chunk.length + bytes.length);
|
|
5778
|
+
combined.set(chunk);
|
|
5779
|
+
combined.set(bytes, chunk.length);
|
|
5780
|
+
bytes = combined;
|
|
5781
|
+
startByte = nextStartByte;
|
|
5782
|
+
items = [];
|
|
5783
|
+
let lineStart = 0;
|
|
5784
|
+
for (let lineEnd = bytes.indexOf(10); lineEnd !== -1; lineEnd = bytes.indexOf(10, lineStart)) {
|
|
5785
|
+
if (!(startByte > 0 && lineStart === 0)) {
|
|
5786
|
+
try {
|
|
5787
|
+
const item = args.parse(JSON.parse(decoder.decode(bytes.subarray(lineStart, lineEnd))));
|
|
5788
|
+
if (item !== void 0) items.push({ item, startByte: startByte + lineStart });
|
|
5789
|
+
} catch {
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
lineStart = lineEnd + 1;
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
const selected = items.slice(-args.limit);
|
|
5796
|
+
const firstCompleteLine = bytes.indexOf(10) + 1;
|
|
5797
|
+
let before = 0;
|
|
5798
|
+
if (selected.length === args.limit) before = selected[0].startByte;
|
|
5799
|
+
else if (startByte > 0) before = startByte + firstCompleteLine;
|
|
5800
|
+
return {
|
|
5801
|
+
items: selected.map(({ item }) => item),
|
|
5802
|
+
before: before > 0 ? String(before) : null
|
|
5803
|
+
};
|
|
5804
|
+
}
|
|
5805
|
+
function parseChatTranscriptHistoryIndex(value) {
|
|
5806
|
+
if (!isRecord(value) || value.version !== 2 || !isNonNegativeInteger(value.sourceSize)) return void 0;
|
|
5807
|
+
if (value.codexAspTranscript === void 0) {
|
|
5808
|
+
return { version: 2, sourceSize: value.sourceSize };
|
|
5809
|
+
}
|
|
5810
|
+
if (!isRecord(value.codexAspTranscript) || typeof value.codexAspTranscript.threadId !== "string" || typeof value.codexAspTranscript.updatedAt !== "string" || !isNonNegativeInteger(value.codexAspTranscript.size)) return void 0;
|
|
5811
|
+
return {
|
|
5812
|
+
version: 2,
|
|
5813
|
+
sourceSize: value.sourceSize,
|
|
5814
|
+
codexAspTranscript: {
|
|
5815
|
+
threadId: value.codexAspTranscript.threadId,
|
|
5816
|
+
updatedAt: value.codexAspTranscript.updatedAt,
|
|
5817
|
+
size: value.codexAspTranscript.size
|
|
5818
|
+
}
|
|
5819
|
+
};
|
|
5820
|
+
}
|
|
5821
|
+
function getChatTranscriptHistorySize(index) {
|
|
5822
|
+
return index.codexAspTranscript?.size ?? 0;
|
|
5823
|
+
}
|
|
5824
|
+
function createChatTranscriptPages(sourceBytes) {
|
|
5825
|
+
const history = parseAgentEventJsonlWithCodexAspTranscript(new TextDecoder("utf-8", { fatal: true }).decode(sourceBytes));
|
|
5826
|
+
const bytes = new TextEncoder().encode(history.transcript?.turns.length ? `${history.transcript.turns.map((turn) => JSON.stringify(turn)).join("\n")}
|
|
5827
|
+
` : "");
|
|
5828
|
+
return {
|
|
5829
|
+
bytes,
|
|
5830
|
+
index: {
|
|
5831
|
+
version: 2,
|
|
5832
|
+
sourceSize: sourceBytes.byteLength,
|
|
5833
|
+
...history.transcript ? {
|
|
5834
|
+
codexAspTranscript: {
|
|
5835
|
+
threadId: history.transcript.threadId,
|
|
5836
|
+
updatedAt: history.transcript.updatedAt,
|
|
5837
|
+
size: bytes.byteLength
|
|
5838
|
+
}
|
|
5839
|
+
} : {}
|
|
5840
|
+
}
|
|
5841
|
+
};
|
|
5842
|
+
}
|
|
5843
|
+
function isNonNegativeInteger(value) {
|
|
5844
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
5845
|
+
}
|
|
5846
|
+
|
|
5726
5847
|
// ../shared/src/object-store/types.ts
|
|
5727
5848
|
var MEDIA_KIND = {
|
|
5728
5849
|
IMAGE: "image",
|
|
@@ -5737,8 +5858,9 @@ function normalizeChatMessageSenders(value) {
|
|
|
5737
5858
|
if (!Array.isArray(value)) return void 0;
|
|
5738
5859
|
const senders = value.flatMap((sender) => {
|
|
5739
5860
|
if (!isChatMessageSender(sender)) return [];
|
|
5740
|
-
const { senderUserId, senderEmail, senderDisplayName, senderAvatarUrl, recordedAt } = sender;
|
|
5861
|
+
const { messageId, senderUserId, senderEmail, senderDisplayName, senderAvatarUrl, recordedAt } = sender;
|
|
5741
5862
|
return [{
|
|
5863
|
+
...typeof messageId === "string" ? { messageId } : {},
|
|
5742
5864
|
senderUserId,
|
|
5743
5865
|
senderEmail,
|
|
5744
5866
|
...typeof senderDisplayName === "string" ? { senderDisplayName } : {},
|
|
@@ -5760,6 +5882,7 @@ function normalizeChatTranscriptMetadata(value) {
|
|
|
5760
5882
|
parentChatId,
|
|
5761
5883
|
deletedAt,
|
|
5762
5884
|
senders,
|
|
5885
|
+
historyIndex,
|
|
5763
5886
|
captureId,
|
|
5764
5887
|
captureReason,
|
|
5765
5888
|
sha256
|
|
@@ -5774,6 +5897,8 @@ function normalizeChatTranscriptMetadata(value) {
|
|
|
5774
5897
|
if (typeof deletedAt === "string" || deletedAt === null) metadata.deletedAt = deletedAt;
|
|
5775
5898
|
const normalizedSenders = normalizeChatMessageSenders(senders);
|
|
5776
5899
|
if (normalizedSenders) metadata.senders = normalizedSenders;
|
|
5900
|
+
const parsedHistoryIndex = parseChatTranscriptHistoryIndex(historyIndex);
|
|
5901
|
+
if (parsedHistoryIndex) metadata.historyIndex = parsedHistoryIndex;
|
|
5777
5902
|
if (typeof captureId === "string") metadata.captureId = captureId;
|
|
5778
5903
|
if (captureReason === "workspace_sleep") metadata.captureReason = captureReason;
|
|
5779
5904
|
if (typeof sha256 === "string") metadata.sha256 = sha256;
|
|
@@ -5823,9 +5948,6 @@ var memoryGenerationManifestSchema = z6.object({
|
|
|
5823
5948
|
rolloutSources: z6.record(z6.string(), z6.string()).optional()
|
|
5824
5949
|
});
|
|
5825
5950
|
|
|
5826
|
-
// ../shared/src/chat-transcript-pages.ts
|
|
5827
|
-
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
5828
|
-
|
|
5829
5951
|
// ../shared/src/skill-registry.ts
|
|
5830
5952
|
var SKILL_REGISTRY_MANIFEST_VERSION = 1;
|
|
5831
5953
|
function isSkillRegistryManifest(value) {
|
|
@@ -6100,7 +6222,7 @@ var DEFAULT_CODEX_ARGS = [
|
|
|
6100
6222
|
var MIN_CODEX_CLI_VERSION = "0.144.6";
|
|
6101
6223
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
6102
6224
|
var codexCliVersionEnsured = null;
|
|
6103
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
6225
|
+
var ENGINE_PACKAGE_VERSION = "0.1.656";
|
|
6104
6226
|
var INITIALIZE_METHOD = "initialize";
|
|
6105
6227
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
6106
6228
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -6434,8 +6556,11 @@ export {
|
|
|
6434
6556
|
isCodexAspTranscript,
|
|
6435
6557
|
isCodexAspTranscriptDelta,
|
|
6436
6558
|
applyCodexAspTranscriptDelta,
|
|
6559
|
+
isLatestChatHistoryPage,
|
|
6560
|
+
getChatHistoryPageSenders,
|
|
6561
|
+
parseChatHistoryCursor,
|
|
6562
|
+
createChatHistoryCursor,
|
|
6437
6563
|
chatHistoryPageParamsFromQuery,
|
|
6438
|
-
getChatHistoryPageWindow,
|
|
6439
6564
|
paginateChatHistory,
|
|
6440
6565
|
CODEX_AUTH_ENV_KEYS,
|
|
6441
6566
|
codexAuthEnvFromResponse,
|
|
@@ -6464,6 +6589,10 @@ export {
|
|
|
6464
6589
|
parseLatestCodexAspTranscriptTurn,
|
|
6465
6590
|
parseAgentEvents,
|
|
6466
6591
|
parseDisplayMessages,
|
|
6592
|
+
isAgentBackendEvent,
|
|
6593
|
+
readJsonlPage,
|
|
6594
|
+
getChatTranscriptHistorySize,
|
|
6595
|
+
createChatTranscriptPages,
|
|
6467
6596
|
parseChatTranscriptArtifact,
|
|
6468
6597
|
MEMORY_ROOT,
|
|
6469
6598
|
MEMORY_SUMMARY_FILENAME,
|
package/dist/src/index.js
CHANGED
|
@@ -104,7 +104,9 @@ import {
|
|
|
104
104
|
coerceBackgroundTaskPayload,
|
|
105
105
|
coerceClaudeResultPayload,
|
|
106
106
|
createAcceptedUserMessageEvent,
|
|
107
|
+
createChatHistoryCursor,
|
|
107
108
|
createChatRequestSchema,
|
|
109
|
+
createChatTranscriptPages,
|
|
108
110
|
createErrorResult,
|
|
109
111
|
createProviderSlashCommand,
|
|
110
112
|
createSuccessResult,
|
|
@@ -119,7 +121,8 @@ import {
|
|
|
119
121
|
extractToolResultText,
|
|
120
122
|
findGitCommitSignals,
|
|
121
123
|
findPrMergeSignals,
|
|
122
|
-
|
|
124
|
+
getChatHistoryPageSenders,
|
|
125
|
+
getChatTranscriptHistorySize,
|
|
123
126
|
getClaudeModelContextWindow,
|
|
124
127
|
getCodexAspTurnResponse,
|
|
125
128
|
getDeepseekAssistantMessageText,
|
|
@@ -132,6 +135,7 @@ import {
|
|
|
132
135
|
gitIdentityConfigCommands,
|
|
133
136
|
hasChatStarted,
|
|
134
137
|
imageContentToUserMessageImages,
|
|
138
|
+
isAgentBackendEvent,
|
|
135
139
|
isAgentChatMcpActivityRecord,
|
|
136
140
|
isAgentChatSkillActivityRecord,
|
|
137
141
|
isAgentChatTurnActivityRecord,
|
|
@@ -143,6 +147,7 @@ import {
|
|
|
143
147
|
isCodexAuthError,
|
|
144
148
|
isDefaultChat,
|
|
145
149
|
isGitHubUrl,
|
|
150
|
+
isLatestChatHistoryPage,
|
|
146
151
|
isRecord,
|
|
147
152
|
isSkillRegistryManifest,
|
|
148
153
|
isTerminalBackgroundTaskStatus,
|
|
@@ -158,6 +163,7 @@ import {
|
|
|
158
163
|
paginateEngineLogContent,
|
|
159
164
|
parseAgentEventJsonlWithCodexAspTranscript,
|
|
160
165
|
parseAgentEvents,
|
|
166
|
+
parseChatHistoryCursor,
|
|
161
167
|
parseChatTranscriptArtifact,
|
|
162
168
|
parseCodeHostPrUrl,
|
|
163
169
|
parseDisplayMessages,
|
|
@@ -169,6 +175,7 @@ import {
|
|
|
169
175
|
percentage,
|
|
170
176
|
putPresignedFile,
|
|
171
177
|
raceWithTimeout,
|
|
178
|
+
readJsonlPage,
|
|
172
179
|
readReplicasRuntimeEnv,
|
|
173
180
|
recoverCompletedTurn,
|
|
174
181
|
resolveWarmHookConfig,
|
|
@@ -176,7 +183,7 @@ import {
|
|
|
176
183
|
serializeCanvasContentResponse,
|
|
177
184
|
shellQuotePosix,
|
|
178
185
|
stripAgentDiagnosticErrors
|
|
179
|
-
} from "./chunk-
|
|
186
|
+
} from "./chunk-KCMDTZ5H.js";
|
|
180
187
|
|
|
181
188
|
// src/index.ts
|
|
182
189
|
import { serve } from "@hono/node-server";
|
|
@@ -4147,11 +4154,11 @@ var CodexHistoryFile = class {
|
|
|
4147
4154
|
}
|
|
4148
4155
|
filePath;
|
|
4149
4156
|
writeLock = new AsyncLock();
|
|
4150
|
-
eventLineIndex = null;
|
|
4151
4157
|
/** Best-effort ordered append; failures must not disrupt the turn. */
|
|
4152
4158
|
append(event) {
|
|
4153
4159
|
void this.writeLock.run(
|
|
4154
|
-
() => appendFile2(this.filePath, JSON.stringify(event)
|
|
4160
|
+
() => appendFile2(this.filePath, `${JSON.stringify(event)}
|
|
4161
|
+
`).catch((error) => {
|
|
4155
4162
|
console.error("[CodexHistoryFile] Failed to append event:", error);
|
|
4156
4163
|
})
|
|
4157
4164
|
);
|
|
@@ -4172,85 +4179,51 @@ var CodexHistoryFile = class {
|
|
|
4172
4179
|
}
|
|
4173
4180
|
async loadEventsPage(page) {
|
|
4174
4181
|
if (page.limit === void 0) {
|
|
4175
|
-
const
|
|
4176
|
-
return { events:
|
|
4182
|
+
const history = await this.load();
|
|
4183
|
+
return { events: history.events };
|
|
4184
|
+
}
|
|
4185
|
+
const cursor = parseChatHistoryCursor(page.beforeCursor);
|
|
4186
|
+
if (page.beforeCursor !== void 0 && cursor?.mode !== "range") throw new RangeError("Invalid chat history cursor");
|
|
4187
|
+
if (cursor?.events === null) {
|
|
4188
|
+
return {
|
|
4189
|
+
events: [],
|
|
4190
|
+
beforeCursor: createChatHistoryCursor({
|
|
4191
|
+
events: null,
|
|
4192
|
+
turns: cursor.turns
|
|
4193
|
+
})
|
|
4194
|
+
};
|
|
4177
4195
|
}
|
|
4178
4196
|
let file;
|
|
4179
4197
|
try {
|
|
4180
4198
|
file = await open(this.filePath, "r");
|
|
4181
4199
|
} catch (error) {
|
|
4182
|
-
if (
|
|
4183
|
-
|
|
4200
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
4201
|
+
return { events: [], beforeCursor: null };
|
|
4184
4202
|
}
|
|
4185
|
-
|
|
4203
|
+
throw error;
|
|
4186
4204
|
}
|
|
4187
4205
|
try {
|
|
4188
|
-
const
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
position += bytesRead2;
|
|
4207
|
-
}
|
|
4208
|
-
index = { size: stats.size, mtimeMs: stats.mtimeMs, starts };
|
|
4209
|
-
this.eventLineIndex = index;
|
|
4210
|
-
}
|
|
4211
|
-
const totalEvents2 = index.starts.length;
|
|
4212
|
-
const { startIndex: eventsStartIndex2, endIndex: eventsEnd2 } = getChatHistoryPageWindow(
|
|
4213
|
-
totalEvents2,
|
|
4214
|
-
page.limit,
|
|
4215
|
-
page.beforeEvent
|
|
4216
|
-
);
|
|
4217
|
-
const startByte = index.starts[eventsStartIndex2] ?? index.size;
|
|
4218
|
-
const endByte = index.starts[eventsEnd2] ?? index.size;
|
|
4219
|
-
const content = Buffer.allocUnsafe(endByte - startByte);
|
|
4220
|
-
let bytesRead = 0;
|
|
4221
|
-
while (bytesRead < content.length) {
|
|
4222
|
-
const result = await file.read(
|
|
4223
|
-
content,
|
|
4224
|
-
bytesRead,
|
|
4225
|
-
content.length - bytesRead,
|
|
4226
|
-
startByte + bytesRead
|
|
4227
|
-
);
|
|
4228
|
-
if (result.bytesRead === 0) break;
|
|
4229
|
-
bytesRead += result.bytesRead;
|
|
4230
|
-
}
|
|
4231
|
-
if (bytesRead === content.length) {
|
|
4232
|
-
const parsed = parseAgentEventJsonlWithCodexAspTranscript(content.toString("utf-8"));
|
|
4233
|
-
if (!parsed.transcript && parsed.events.length === eventsEnd2 - eventsStartIndex2) {
|
|
4234
|
-
return { events: parsed.events, eventsStartIndex: eventsStartIndex2, totalEvents: totalEvents2 };
|
|
4235
|
-
}
|
|
4236
|
-
}
|
|
4237
|
-
} catch (error) {
|
|
4238
|
-
console.error("[CodexHistoryFile] Failed to load history page:", error);
|
|
4206
|
+
const result = await readJsonlPage({
|
|
4207
|
+
size: (await file.stat()).size,
|
|
4208
|
+
limit: page.limit,
|
|
4209
|
+
before: cursor?.events,
|
|
4210
|
+
readRange: async (startByte, endByte) => {
|
|
4211
|
+
const bytes = Buffer.allocUnsafe(endByte - startByte);
|
|
4212
|
+
const { bytesRead } = await file.read(bytes, 0, bytes.length, startByte);
|
|
4213
|
+
return bytes.subarray(0, bytesRead);
|
|
4214
|
+
},
|
|
4215
|
+
parse: (value) => isAgentBackendEvent(value) && value.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE ? value : void 0
|
|
4216
|
+
});
|
|
4217
|
+
return {
|
|
4218
|
+
events: result.items,
|
|
4219
|
+
beforeCursor: createChatHistoryCursor({
|
|
4220
|
+
events: result.before,
|
|
4221
|
+
turns: cursor?.turns ?? null
|
|
4222
|
+
})
|
|
4223
|
+
};
|
|
4239
4224
|
} finally {
|
|
4240
4225
|
await file.close();
|
|
4241
4226
|
}
|
|
4242
|
-
const history = await this.load();
|
|
4243
|
-
const totalEvents = history.events.length;
|
|
4244
|
-
const { startIndex: eventsStartIndex, endIndex: eventsEnd } = getChatHistoryPageWindow(
|
|
4245
|
-
totalEvents,
|
|
4246
|
-
page.limit,
|
|
4247
|
-
page.beforeEvent
|
|
4248
|
-
);
|
|
4249
|
-
return {
|
|
4250
|
-
events: history.events.slice(eventsStartIndex, eventsEnd),
|
|
4251
|
-
eventsStartIndex,
|
|
4252
|
-
totalEvents
|
|
4253
|
-
};
|
|
4254
4227
|
}
|
|
4255
4228
|
};
|
|
4256
4229
|
|
|
@@ -5721,6 +5694,7 @@ var DEFAULT_MODEL = DEFAULT_CODEX_MODEL;
|
|
|
5721
5694
|
var THREAD_START_METHOD = "thread/start";
|
|
5722
5695
|
var THREAD_RESUME_METHOD = "thread/resume";
|
|
5723
5696
|
var THREAD_READ_METHOD = "thread/read";
|
|
5697
|
+
var THREAD_TURNS_LIST_METHOD = "thread/turns/list";
|
|
5724
5698
|
var THREAD_GOAL_SET_METHOD = "thread/goal/set";
|
|
5725
5699
|
var THREAD_GOAL_GET_METHOD = "thread/goal/get";
|
|
5726
5700
|
var THREAD_GOAL_CLEAR_METHOD = "thread/goal/clear";
|
|
@@ -6049,8 +6023,11 @@ function formatTurnFailure(turn) {
|
|
|
6049
6023
|
return parts.join(" ");
|
|
6050
6024
|
}
|
|
6051
6025
|
function threadToAspTranscript(thread) {
|
|
6026
|
+
return turnsToAspTranscript(thread.id, timestampFromSeconds(thread.updatedAt), thread.turns);
|
|
6027
|
+
}
|
|
6028
|
+
function turnsToAspTranscript(threadId, updatedAt, sourceTurns) {
|
|
6052
6029
|
let sequence = 0;
|
|
6053
|
-
const turns =
|
|
6030
|
+
const turns = sourceTurns.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).map(({ turn }) => {
|
|
6054
6031
|
const startedAt = timestampFromSeconds(turn.startedAt);
|
|
6055
6032
|
const completedAt = turn.completedAt === null ? null : timestampFromSeconds(turn.completedAt);
|
|
6056
6033
|
const itemTimestamp = completedAt ?? startedAt;
|
|
@@ -6080,8 +6057,8 @@ function threadToAspTranscript(thread) {
|
|
|
6080
6057
|
};
|
|
6081
6058
|
});
|
|
6082
6059
|
return {
|
|
6083
|
-
threadId
|
|
6084
|
-
updatedAt
|
|
6060
|
+
threadId,
|
|
6061
|
+
updatedAt,
|
|
6085
6062
|
turns
|
|
6086
6063
|
};
|
|
6087
6064
|
}
|
|
@@ -6403,7 +6380,7 @@ async function readCodexAspThreadHistory(threadId) {
|
|
|
6403
6380
|
}
|
|
6404
6381
|
}
|
|
6405
6382
|
for (const entry of entries) {
|
|
6406
|
-
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
6383
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || entry.name.endsWith(".pages.jsonl")) continue;
|
|
6407
6384
|
const history = await new CodexHistoryFile(join19(CODEX_HISTORY_DIR, entry.name)).load();
|
|
6408
6385
|
const transcript = history.transcriptsByThreadId.get(threadId);
|
|
6409
6386
|
if (transcript) {
|
|
@@ -6452,7 +6429,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6452
6429
|
activeTurnId = null;
|
|
6453
6430
|
threadAttached = false;
|
|
6454
6431
|
historyFile;
|
|
6455
|
-
historyEvents = [];
|
|
6456
6432
|
codexAspTranscript = null;
|
|
6457
6433
|
lastEmittedTranscripts = /* @__PURE__ */ new Map();
|
|
6458
6434
|
codexAspSequence = 0;
|
|
@@ -6474,9 +6450,12 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6474
6450
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
6475
6451
|
}
|
|
6476
6452
|
async initialize() {
|
|
6453
|
+
if (this.initialSessionId) {
|
|
6454
|
+
this.currentThreadId = this.initialSessionId;
|
|
6455
|
+
return;
|
|
6456
|
+
}
|
|
6477
6457
|
const replayed = await this.historyFile?.load();
|
|
6478
6458
|
if (replayed) {
|
|
6479
|
-
this.historyEvents.push(...replayed.events);
|
|
6480
6459
|
if (replayed.transcript) {
|
|
6481
6460
|
this.mergeTranscriptSnapshot(replayed.transcript);
|
|
6482
6461
|
}
|
|
@@ -6565,51 +6544,87 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6565
6544
|
return true;
|
|
6566
6545
|
}
|
|
6567
6546
|
async getHistory(page = {}) {
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
}
|
|
6578
|
-
}
|
|
6579
|
-
return
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6547
|
+
await this.historyFile?.flush();
|
|
6548
|
+
if (page.limit === void 0) {
|
|
6549
|
+
const local = async () => {
|
|
6550
|
+
const history = await this.historyFile?.load();
|
|
6551
|
+
return {
|
|
6552
|
+
thread_id: this.currentThreadId,
|
|
6553
|
+
events: history?.events ?? [],
|
|
6554
|
+
codexAspTranscript: this.currentThreadId ? history?.transcriptsByThreadId.get(this.currentThreadId) ?? null : null,
|
|
6555
|
+
goal: this.currentGoal
|
|
6556
|
+
};
|
|
6557
|
+
};
|
|
6558
|
+
if (!this.currentThreadId) return local();
|
|
6559
|
+
return this.readFullNativeHistory().catch(local);
|
|
6560
|
+
}
|
|
6561
|
+
const events = await this.historyFile?.loadEventsPage(page) ?? { events: [], beforeCursor: null };
|
|
6562
|
+
if (!this.currentThreadId) return { thread_id: null, ...events, goal: this.currentGoal };
|
|
6563
|
+
const cursor = parseChatHistoryCursor(page.beforeCursor);
|
|
6564
|
+
if (page.beforeCursor !== void 0 && cursor?.mode !== "range") throw new RangeError("Invalid chat history cursor");
|
|
6565
|
+
let transcript = null;
|
|
6566
|
+
let turnsBefore = null;
|
|
6567
|
+
if (cursor?.turns !== null) {
|
|
6587
6568
|
const host = await getCodexAspHost();
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
),
|
|
6593
|
-
this.refreshThreadGoal(host, this.currentThreadId)
|
|
6594
|
-
]);
|
|
6595
|
-
const transcript = this.mergeTranscriptSnapshot(threadToAspTranscript(response.thread));
|
|
6596
|
-
if (transcript) {
|
|
6597
|
-
transcript.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6598
|
-
}
|
|
6599
|
-
return paginateChatHistory({
|
|
6600
|
-
thread_id: this.currentThreadId,
|
|
6601
|
-
events: [...this.historyEvents],
|
|
6602
|
-
codexAspTranscript: transcript,
|
|
6603
|
-
goal: this.currentGoal
|
|
6604
|
-
}, page);
|
|
6605
|
-
} catch {
|
|
6569
|
+
if (page.beforeCursor === void 0) await this.refreshThreadGoal(host, this.currentThreadId);
|
|
6570
|
+
const turns = await this.readNativeTurnsPage(page.limit, cursor?.turns, host);
|
|
6571
|
+
transcript = turns.transcript;
|
|
6572
|
+
turnsBefore = turns.before;
|
|
6606
6573
|
}
|
|
6607
|
-
|
|
6574
|
+
const eventCursor = parseChatHistoryCursor(events.beforeCursor ?? void 0);
|
|
6575
|
+
return {
|
|
6576
|
+
thread_id: this.currentThreadId,
|
|
6577
|
+
...events,
|
|
6578
|
+
codexAspTranscript: transcript,
|
|
6579
|
+
goal: this.currentGoal,
|
|
6580
|
+
beforeCursor: createChatHistoryCursor({
|
|
6581
|
+
events: eventCursor?.events ?? null,
|
|
6582
|
+
turns: turnsBefore
|
|
6583
|
+
})
|
|
6584
|
+
};
|
|
6585
|
+
}
|
|
6586
|
+
async readFullNativeHistory() {
|
|
6587
|
+
if (!this.currentThreadId) {
|
|
6588
|
+
return { thread_id: null, events: [], goal: this.currentGoal };
|
|
6589
|
+
}
|
|
6590
|
+
const host = await getCodexAspHost();
|
|
6591
|
+
const [response, history] = await Promise.all([
|
|
6592
|
+
host.client.request(
|
|
6593
|
+
THREAD_READ_METHOD,
|
|
6594
|
+
{ threadId: this.currentThreadId, includeTurns: true }
|
|
6595
|
+
),
|
|
6596
|
+
this.historyFile?.load()
|
|
6597
|
+
]);
|
|
6598
|
+
const transcript = this.mergeTranscriptSnapshot(threadToAspTranscript(response.thread));
|
|
6599
|
+
return {
|
|
6608
6600
|
thread_id: this.currentThreadId,
|
|
6609
|
-
events: [
|
|
6610
|
-
codexAspTranscript:
|
|
6601
|
+
events: history?.events ?? [],
|
|
6602
|
+
codexAspTranscript: transcript,
|
|
6611
6603
|
goal: this.currentGoal
|
|
6612
|
-
}
|
|
6604
|
+
};
|
|
6605
|
+
}
|
|
6606
|
+
async readNativeTurnsPage(limit, cursor, host) {
|
|
6607
|
+
if (!this.currentThreadId) throw new Error("A thread is required for native turn pagination");
|
|
6608
|
+
const response = await host.client.request(
|
|
6609
|
+
THREAD_TURNS_LIST_METHOD,
|
|
6610
|
+
{
|
|
6611
|
+
threadId: this.currentThreadId,
|
|
6612
|
+
cursor: cursor ?? null,
|
|
6613
|
+
limit,
|
|
6614
|
+
sortDirection: "desc",
|
|
6615
|
+
itemsView: "full"
|
|
6616
|
+
}
|
|
6617
|
+
);
|
|
6618
|
+
const transcript = turnsToAspTranscript(
|
|
6619
|
+
this.currentThreadId,
|
|
6620
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
6621
|
+
response.data
|
|
6622
|
+
);
|
|
6623
|
+
if (cursor === void 0) {
|
|
6624
|
+
this.codexAspTranscript = transcript;
|
|
6625
|
+
this.syncTranscriptSequence(transcript);
|
|
6626
|
+
}
|
|
6627
|
+
return { transcript, before: response.nextCursor };
|
|
6613
6628
|
}
|
|
6614
6629
|
getGoal() {
|
|
6615
6630
|
return this.currentGoal;
|
|
@@ -7538,7 +7553,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7538
7553
|
return event;
|
|
7539
7554
|
}
|
|
7540
7555
|
trackHistoryEvent(event) {
|
|
7541
|
-
this.historyEvents.push(event);
|
|
7542
7556
|
this.historyFile?.append(event);
|
|
7543
7557
|
}
|
|
7544
7558
|
emitTranscriptUpdated(threadId, options = {}) {
|
|
@@ -10800,7 +10814,7 @@ async function reconcileCanvasItems(filenames) {
|
|
|
10800
10814
|
// src/services/upload-chat-transcripts.ts
|
|
10801
10815
|
import { createReadStream } from "fs";
|
|
10802
10816
|
import { createHash as createHash2 } from "crypto";
|
|
10803
|
-
import {
|
|
10817
|
+
import { readFile as readFile14, readdir as readdir8, stat as stat4 } from "fs/promises";
|
|
10804
10818
|
import { basename as basename2, join as join27 } from "path";
|
|
10805
10819
|
|
|
10806
10820
|
// src/services/chat/chat-senders.ts
|
|
@@ -10859,6 +10873,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
|
|
|
10859
10873
|
async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
10860
10874
|
const { size } = await stat4(filePath);
|
|
10861
10875
|
if (size === 0) return null;
|
|
10876
|
+
const historyPages = createChatTranscriptPages(await readFile14(filePath));
|
|
10862
10877
|
const metadata = chat ? {
|
|
10863
10878
|
provider: chat.provider,
|
|
10864
10879
|
credential: ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS[chat.provider],
|
|
@@ -10882,6 +10897,7 @@ async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
|
10882
10897
|
} catch (error) {
|
|
10883
10898
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) throw error;
|
|
10884
10899
|
}
|
|
10900
|
+
if (historyPages.index.codexAspTranscript) metadata.historyIndex = historyPages.index;
|
|
10885
10901
|
const uploadRequest = { chatId, size, metadata };
|
|
10886
10902
|
const prepareResponse = await monolithRequest("/v1/engine/chat-transcripts/upload-url", {
|
|
10887
10903
|
body: uploadRequest
|
|
@@ -10890,11 +10906,25 @@ async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
|
10890
10906
|
throw new Error(`prepare failed: ${prepareResponse.status} ${await prepareResponse.text()}`);
|
|
10891
10907
|
}
|
|
10892
10908
|
const prepareBody = await prepareResponse.json();
|
|
10893
|
-
if (!isRecord(prepareBody) || typeof prepareBody.uploadUrl !== "string" && prepareBody.uploadUrl !== null) {
|
|
10909
|
+
if (!isRecord(prepareBody) || typeof prepareBody.uploadUrl !== "string" && prepareBody.uploadUrl !== null || prepareBody.historyPagesUploadUrl !== void 0 && typeof prepareBody.historyPagesUploadUrl !== "string") {
|
|
10894
10910
|
throw new Error("prepare failed: invalid response");
|
|
10895
10911
|
}
|
|
10896
10912
|
if (prepareBody.uploadUrl === null) return null;
|
|
10897
|
-
|
|
10913
|
+
const uploads = [putPresignedFile(prepareBody.uploadUrl, filePath, size, "application/x-ndjson")];
|
|
10914
|
+
const historyPagesSize = getChatTranscriptHistorySize(historyPages.index);
|
|
10915
|
+
if (historyPagesSize > 0) {
|
|
10916
|
+
if (typeof prepareBody.historyPagesUploadUrl !== "string") {
|
|
10917
|
+
throw new Error("prepare failed: missing history pages upload URL");
|
|
10918
|
+
}
|
|
10919
|
+
uploads.push(fetch(prepareBody.historyPagesUploadUrl, {
|
|
10920
|
+
method: "PUT",
|
|
10921
|
+
headers: { "content-type": "application/x-ndjson" },
|
|
10922
|
+
body: new Uint8Array(historyPages.bytes).buffer
|
|
10923
|
+
}).then((response) => {
|
|
10924
|
+
if (!response.ok) throw new Error(`history pages upload failed: ${response.status}`);
|
|
10925
|
+
}));
|
|
10926
|
+
}
|
|
10927
|
+
await Promise.all(uploads);
|
|
10898
10928
|
const finalizeResponse = await monolithRequest("/v1/engine/chat-transcripts/finalize", {
|
|
10899
10929
|
body: uploadRequest
|
|
10900
10930
|
});
|
|
@@ -11310,10 +11340,11 @@ var ChatService = class {
|
|
|
11310
11340
|
}
|
|
11311
11341
|
chat.persisted.acceptedSendResponses = Object.fromEntries(chat.acceptedSendResponses);
|
|
11312
11342
|
}
|
|
11343
|
+
const submittedAt = request.submittedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
11313
11344
|
const acceptedEvent = createAcceptedUserMessageEvent(
|
|
11314
11345
|
request.message,
|
|
11315
11346
|
result.messageId,
|
|
11316
|
-
|
|
11347
|
+
submittedAt,
|
|
11317
11348
|
request.images
|
|
11318
11349
|
);
|
|
11319
11350
|
if (!chat.pendingMessageIds.includes(result.messageId)) {
|
|
@@ -11329,11 +11360,12 @@ var ChatService = class {
|
|
|
11329
11360
|
let recordedSender;
|
|
11330
11361
|
if (request.senderUserId && request.senderEmail) {
|
|
11331
11362
|
recordedSender = {
|
|
11363
|
+
messageId: result.messageId,
|
|
11332
11364
|
senderUserId: request.senderUserId,
|
|
11333
11365
|
senderEmail: request.senderEmail,
|
|
11334
11366
|
...request.senderDisplayName ? { senderDisplayName: request.senderDisplayName } : {},
|
|
11335
11367
|
...request.senderAvatarUrl ? { senderAvatarUrl: request.senderAvatarUrl } : {},
|
|
11336
|
-
recordedAt:
|
|
11368
|
+
recordedAt: submittedAt
|
|
11337
11369
|
};
|
|
11338
11370
|
await this.appendSender(chatId, recordedSender);
|
|
11339
11371
|
}
|
|
@@ -11362,15 +11394,11 @@ var ChatService = class {
|
|
|
11362
11394
|
}
|
|
11363
11395
|
}
|
|
11364
11396
|
async readSenders(chatId) {
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
} catch (error) {
|
|
11368
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
11369
|
-
return [];
|
|
11370
|
-
}
|
|
11397
|
+
return readFile15(chatMessageSendersFilePath(chatId), "utf-8").then(parseChatMessageSendersJsonl).catch((error) => {
|
|
11398
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return [];
|
|
11371
11399
|
console.error("[ChatService] Failed to read sender records:", error);
|
|
11372
11400
|
return [];
|
|
11373
|
-
}
|
|
11401
|
+
});
|
|
11374
11402
|
}
|
|
11375
11403
|
async interrupt(chatId) {
|
|
11376
11404
|
const chat = this.requireChat(chatId);
|
|
@@ -11592,7 +11620,12 @@ var ChatService = class {
|
|
|
11592
11620
|
return descendants;
|
|
11593
11621
|
}
|
|
11594
11622
|
async deleteHistoryFile(persisted) {
|
|
11595
|
-
|
|
11623
|
+
const historyPath = join29(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
|
|
11624
|
+
await Promise.all([
|
|
11625
|
+
historyPath,
|
|
11626
|
+
`${historyPath}.pages.jsonl`,
|
|
11627
|
+
`${historyPath}.pages.index.json`
|
|
11628
|
+
].map((path6) => rm2(path6, { force: true })));
|
|
11596
11629
|
await rm2(chatMessageSendersFilePath(persisted.id), { force: true });
|
|
11597
11630
|
}
|
|
11598
11631
|
async getChatHistory(chatId, page = {}) {
|
|
@@ -11606,10 +11639,23 @@ var ChatService = class {
|
|
|
11606
11639
|
chat.acceptedUserEvents.delete(messageId);
|
|
11607
11640
|
}
|
|
11608
11641
|
}
|
|
11609
|
-
const isLatestPage = page
|
|
11642
|
+
const isLatestPage = isLatestChatHistoryPage(page);
|
|
11610
11643
|
const queuedMessageIds = new Set(chat.provider.getQueue().map((message) => message.id));
|
|
11611
11644
|
const acceptedEvents = (isLatestPage ? [...chat.acceptedUserEvents.entries()] : []).filter(([messageId]) => messageId === chat.activeMessageId || !chat.hasActiveTurn && chat.pendingMessageIds[0] === messageId && !queuedMessageIds.has(messageId)).map(([, acceptedEvent]) => acceptedEvent).filter((acceptedEvent) => !acceptedEventInCodexTranscript(acceptedEvent, history.codexAspTranscript) && !history.events.some((event) => isSameAcceptedUserEvent(event, acceptedEvent)));
|
|
11612
11645
|
const events = [...history.events, ...acceptedEvents].sort((a, b) => getEventTimestampMs(a) - getEventTimestampMs(b));
|
|
11646
|
+
if (page.limit !== void 0 && "beforeCursor" in history) {
|
|
11647
|
+
const cursor = parseChatHistoryCursor(history.beforeCursor ?? void 0);
|
|
11648
|
+
return {
|
|
11649
|
+
...history,
|
|
11650
|
+
events,
|
|
11651
|
+
goal: history.goal ?? chat.provider.getGoal?.() ?? null,
|
|
11652
|
+
senders: getChatHistoryPageSenders(senders, page),
|
|
11653
|
+
beforeCursor: createChatHistoryCursor({
|
|
11654
|
+
events: cursor?.events ?? null,
|
|
11655
|
+
turns: cursor?.turns ?? null
|
|
11656
|
+
})
|
|
11657
|
+
};
|
|
11658
|
+
}
|
|
11613
11659
|
if (history.eventsStartIndex !== void 0) {
|
|
11614
11660
|
return {
|
|
11615
11661
|
...history,
|
|
@@ -12940,6 +12986,22 @@ function jsonError(message, details) {
|
|
|
12940
12986
|
}
|
|
12941
12987
|
function createV1Routes(deps) {
|
|
12942
12988
|
const app2 = new Hono();
|
|
12989
|
+
const loadChatHistory = async (c, chatId, page, failureMessage, unexpectedStatus, legacy = false) => {
|
|
12990
|
+
try {
|
|
12991
|
+
const history = await deps.chatService.getChatHistory(chatId, legacy && page.limit !== void 0 ? {} : page);
|
|
12992
|
+
if (!legacy) return c.json(history);
|
|
12993
|
+
return c.json(paginateChatHistory({
|
|
12994
|
+
...history,
|
|
12995
|
+
senders: getChatHistoryPageSenders(history.senders, page)
|
|
12996
|
+
}, page));
|
|
12997
|
+
} catch (error) {
|
|
12998
|
+
const status = error instanceof ChatNotFoundError ? 404 : unexpectedStatus;
|
|
12999
|
+
return c.json(jsonError(
|
|
13000
|
+
failureMessage,
|
|
13001
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
13002
|
+
), status);
|
|
13003
|
+
}
|
|
13004
|
+
};
|
|
12943
13005
|
app2.get("/events", async () => {
|
|
12944
13006
|
const encoder = new TextEncoder();
|
|
12945
13007
|
let unsubscribe = null;
|
|
@@ -13059,19 +13121,23 @@ function createV1Routes(deps) {
|
|
|
13059
13121
|
return c.json(jsonError("Failed to restore chat", details), 500);
|
|
13060
13122
|
}
|
|
13061
13123
|
});
|
|
13062
|
-
app2.get("/chats/:chatId/history",
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
return c.json(jsonError("Failed to load chat history",
|
|
13124
|
+
app2.get("/chats/:chatId/history", (c) => loadChatHistory(
|
|
13125
|
+
c,
|
|
13126
|
+
c.req.param("chatId"),
|
|
13127
|
+
chatHistoryPageParamsFromQuery(c.req.query()),
|
|
13128
|
+
"Failed to load chat history",
|
|
13129
|
+
404,
|
|
13130
|
+
true
|
|
13131
|
+
));
|
|
13132
|
+
app2.get("/chats/:chatId/history-page", async (c) => {
|
|
13133
|
+
const page = chatHistoryPageParamsFromQuery(c.req.query());
|
|
13134
|
+
if (page.limit === void 0) {
|
|
13135
|
+
return c.json(jsonError("Failed to load chat history page", "limit is required"), 400);
|
|
13136
|
+
}
|
|
13137
|
+
if (page.beforeCursor !== void 0 && !parseChatHistoryCursor(page.beforeCursor)) {
|
|
13138
|
+
return c.json(jsonError("Failed to load chat history page", "invalid cursor"), 400);
|
|
13074
13139
|
}
|
|
13140
|
+
return loadChatHistory(c, c.req.param("chatId"), page, "Failed to load chat history page", 500);
|
|
13075
13141
|
});
|
|
13076
13142
|
app2.get("/chats/:chatId/slash-commands", async (c) => {
|
|
13077
13143
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replicas-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.656",
|
|
4
4
|
"description": "Lightweight API server for Replicas workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"@anthropic-ai/claude-agent-sdk": "0.3.219",
|
|
39
39
|
"@connectrpc/connect-node": "1.7.0",
|
|
40
40
|
"@cursor/sdk": "1.0.19",
|
|
41
|
-
"@deepseek-ai/dsh": "0.1.0-rc.
|
|
42
|
-
"@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.
|
|
41
|
+
"@deepseek-ai/dsh": "0.1.0-rc.7",
|
|
42
|
+
"@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.7",
|
|
43
43
|
"@earendil-works/pi-ai": "0.79.10",
|
|
44
44
|
"@earendil-works/pi-coding-agent": "0.79.0",
|
|
45
45
|
"@hono/node-server": "^1.19.5",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"zod": "^4.0.0"
|
|
53
53
|
},
|
|
54
54
|
"optionalDependencies": {
|
|
55
|
-
"node-pty": "1.2.0-beta.
|
|
55
|
+
"node-pty": "1.2.0-beta.15"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@replicas/codex-asp-types": "file:../codex-asp-types",
|