replicas-engine 0.1.632 → 0.1.634
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.
|
@@ -226,14 +226,43 @@ function gitIdentityConfigCommands(identity, scope = "global") {
|
|
|
226
226
|
|
|
227
227
|
// ../shared/src/headless-agent.ts
|
|
228
228
|
import { z } from "zod";
|
|
229
|
-
var
|
|
229
|
+
var headlessAgentRequestBaseSchema = z.object({
|
|
230
230
|
agent: z.custom(
|
|
231
231
|
(value) => typeof value === "string" && isValidCodingAgentProvider(value)
|
|
232
232
|
),
|
|
233
233
|
model: z.string().min(1),
|
|
234
234
|
prompt: z.string(),
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
workingDirectory: z.string().min(1),
|
|
236
|
+
timeoutSeconds: z.number().int().min(1).max(1800).default(300)
|
|
237
|
+
});
|
|
238
|
+
var headlessAgentInputFileSchema = z.object({
|
|
239
|
+
path: z.string().min(1),
|
|
240
|
+
downloadUrl: z.url()
|
|
241
|
+
});
|
|
242
|
+
var headlessAgentOutputFileSchema = z.object({
|
|
243
|
+
path: z.string().min(1),
|
|
244
|
+
uploadUrl: z.url(),
|
|
245
|
+
contentType: z.string().min(1),
|
|
246
|
+
maxChars: z.number().int().positive().optional()
|
|
247
|
+
});
|
|
248
|
+
var headlessAgentRequestSchema = z.discriminatedUnion("mode", [
|
|
249
|
+
headlessAgentRequestBaseSchema.extend({
|
|
250
|
+
mode: z.literal("structured"),
|
|
251
|
+
outputSchema: z.record(z.string(), z.json())
|
|
252
|
+
}),
|
|
253
|
+
headlessAgentRequestBaseSchema.extend({
|
|
254
|
+
mode: z.literal("filesystem"),
|
|
255
|
+
inputFiles: z.array(headlessAgentInputFileSchema),
|
|
256
|
+
outputFiles: z.array(headlessAgentOutputFileSchema),
|
|
257
|
+
sensitiveValues: z.array(z.string())
|
|
258
|
+
})
|
|
259
|
+
]);
|
|
260
|
+
var headlessFilesystemAgentResultSchema = z.object({
|
|
261
|
+
message: z.string(),
|
|
262
|
+
files: z.record(z.string(), z.object({
|
|
263
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
264
|
+
sizeBytes: z.number().int().nonnegative()
|
|
265
|
+
}))
|
|
237
266
|
});
|
|
238
267
|
|
|
239
268
|
// ../shared/src/engine/environment.ts
|
|
@@ -876,6 +905,53 @@ function paginateChatHistory(full, params) {
|
|
|
876
905
|
};
|
|
877
906
|
}
|
|
878
907
|
|
|
908
|
+
// ../shared/src/memory-safety.ts
|
|
909
|
+
var SECRET_PATTERNS = [
|
|
910
|
+
/sk-[A-Za-z0-9_-]{10,}/g,
|
|
911
|
+
/ghp_[A-Za-z0-9]{20,}/g,
|
|
912
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
913
|
+
/xox[abps]-[A-Za-z0-9-]{10,}/g,
|
|
914
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
915
|
+
/eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{10,}/g,
|
|
916
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
917
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/g,
|
|
918
|
+
/\b(?:authorization\s*:\s*bearer|bearer)\s+[a-z0-9._~+/=-]{16,}/gi,
|
|
919
|
+
/\b(?:api[_-]?key|token|secret|password|passwd)\s*[:=]\s*["']?[a-z0-9._~+/=-]{12,}["']?/gi,
|
|
920
|
+
/\b[A-Z][A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD)\s*=\s*[^\s]{12,}/g
|
|
921
|
+
];
|
|
922
|
+
var MIN_SECRET_MATCH_CHARS = 16;
|
|
923
|
+
var flatten = (value) => value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
924
|
+
function containsSecret(value) {
|
|
925
|
+
return SECRET_PATTERNS.some((pattern) => {
|
|
926
|
+
pattern.lastIndex = 0;
|
|
927
|
+
return pattern.test(value);
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
function secretEncodings(secret) {
|
|
931
|
+
const bytes = new TextEncoder().encode(secret);
|
|
932
|
+
let binary = "";
|
|
933
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
934
|
+
const base64 = btoa(binary);
|
|
935
|
+
return [
|
|
936
|
+
secret,
|
|
937
|
+
base64,
|
|
938
|
+
base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""),
|
|
939
|
+
[...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join(""),
|
|
940
|
+
[...secret].reverse().join("")
|
|
941
|
+
];
|
|
942
|
+
}
|
|
943
|
+
function containsKnownSecret(value, secrets) {
|
|
944
|
+
const haystack = flatten(value);
|
|
945
|
+
if (!haystack) return false;
|
|
946
|
+
return secrets.some((secret) => secretEncodings(secret).some((needle) => {
|
|
947
|
+
const flattened = flatten(needle);
|
|
948
|
+
return flattened.length >= MIN_SECRET_MATCH_CHARS && haystack.includes(flattened);
|
|
949
|
+
}));
|
|
950
|
+
}
|
|
951
|
+
function isUnsafeMemoryOutput(value, secrets, maxChars) {
|
|
952
|
+
return maxChars !== void 0 && value.length > maxChars || containsSecret(value) || containsKnownSecret(value, secrets);
|
|
953
|
+
}
|
|
954
|
+
|
|
879
955
|
// ../shared/src/async.ts
|
|
880
956
|
var TIMEOUT = /* @__PURE__ */ Symbol("timeout");
|
|
881
957
|
async function raceWithTimeout(promise, ms) {
|
|
@@ -5514,6 +5590,39 @@ function isSkillRegistryManifest(value) {
|
|
|
5514
5590
|
);
|
|
5515
5591
|
}
|
|
5516
5592
|
|
|
5593
|
+
// src/utils/presigned-upload.ts
|
|
5594
|
+
import { createReadStream } from "fs";
|
|
5595
|
+
import { request as httpRequest } from "http";
|
|
5596
|
+
import { request as httpsRequest } from "https";
|
|
5597
|
+
async function putPresignedFile(urlValue, filePath, size, contentType) {
|
|
5598
|
+
await new Promise((resolve, reject) => {
|
|
5599
|
+
const url = new URL(urlValue);
|
|
5600
|
+
const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
|
|
5601
|
+
method: "PUT",
|
|
5602
|
+
headers: {
|
|
5603
|
+
"content-length": String(size),
|
|
5604
|
+
"content-type": contentType
|
|
5605
|
+
}
|
|
5606
|
+
}, (response) => {
|
|
5607
|
+
response.setEncoding("utf8");
|
|
5608
|
+
let body = "";
|
|
5609
|
+
response.on("data", (chunk) => {
|
|
5610
|
+
body += chunk;
|
|
5611
|
+
});
|
|
5612
|
+
response.on("end", () => {
|
|
5613
|
+
const status = response.statusCode ?? 0;
|
|
5614
|
+
if (status >= 200 && status < 300) resolve();
|
|
5615
|
+
else reject(new Error(`upload failed: ${status} ${body}`));
|
|
5616
|
+
});
|
|
5617
|
+
response.on("error", reject);
|
|
5618
|
+
});
|
|
5619
|
+
request.on("error", reject);
|
|
5620
|
+
const file = size > 0 ? createReadStream(filePath, { start: 0, end: size - 1 }) : createReadStream(filePath);
|
|
5621
|
+
file.on("error", (error) => request.destroy(error));
|
|
5622
|
+
file.pipe(request);
|
|
5623
|
+
});
|
|
5624
|
+
}
|
|
5625
|
+
|
|
5517
5626
|
// src/engine-env.ts
|
|
5518
5627
|
import { readFileSync as readFileSync2 } from "fs";
|
|
5519
5628
|
import { homedir as homedir2 } from "os";
|
|
@@ -5930,7 +6039,7 @@ var DEFAULT_CODEX_ARGS = [
|
|
|
5930
6039
|
var MIN_CODEX_CLI_VERSION = "0.144.6";
|
|
5931
6040
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
5932
6041
|
var codexCliVersionEnsured = null;
|
|
5933
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
6042
|
+
var ENGINE_PACKAGE_VERSION = "0.1.634";
|
|
5934
6043
|
var INITIALIZE_METHOD = "initialize";
|
|
5935
6044
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
5936
6045
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -6247,7 +6356,9 @@ export {
|
|
|
6247
6356
|
parseAgentEvents,
|
|
6248
6357
|
parseDisplayMessages,
|
|
6249
6358
|
parseChatTranscriptArtifact,
|
|
6359
|
+
isUnsafeMemoryOutput,
|
|
6250
6360
|
isSkillRegistryManifest,
|
|
6361
|
+
putPresignedFile,
|
|
6251
6362
|
isRecord4 as isRecord2,
|
|
6252
6363
|
IS_WARMING_MODE,
|
|
6253
6364
|
ENGINE_ENV,
|
|
@@ -2,24 +2,106 @@
|
|
|
2
2
|
import {
|
|
3
3
|
AGENT,
|
|
4
4
|
AppServerProcess,
|
|
5
|
-
headlessAgentRequestSchema
|
|
6
|
-
|
|
5
|
+
headlessAgentRequestSchema,
|
|
6
|
+
isUnsafeMemoryOutput,
|
|
7
|
+
putPresignedFile
|
|
8
|
+
} from "./chunk-GT5CS5BI.js";
|
|
7
9
|
|
|
8
10
|
// src/headless-agent.ts
|
|
9
|
-
import {
|
|
11
|
+
import { createHash } from "crypto";
|
|
12
|
+
import { createWriteStream } from "fs";
|
|
13
|
+
import { mkdir, readFile, stat, writeFile } from "fs/promises";
|
|
14
|
+
import { request as httpRequest } from "http";
|
|
15
|
+
import { request as httpsRequest } from "https";
|
|
16
|
+
import path from "path";
|
|
10
17
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
11
|
-
var
|
|
18
|
+
var FILESYSTEM_TOOLS = ["Read", "Write", "Edit", "Glob", "Grep"];
|
|
19
|
+
function resolveFile(root, relativePath) {
|
|
20
|
+
if (path.isAbsolute(relativePath)) throw new Error("Headless agent file paths must be relative");
|
|
21
|
+
const resolved = path.resolve(root, relativePath);
|
|
22
|
+
if (resolved === root || !resolved.startsWith(`${root}${path.sep}`)) {
|
|
23
|
+
throw new Error("Headless agent file path escapes its working directory");
|
|
24
|
+
}
|
|
25
|
+
return resolved;
|
|
26
|
+
}
|
|
27
|
+
async function downloadFile(urlValue, destination) {
|
|
28
|
+
await mkdir(path.dirname(destination), { recursive: true, mode: 448 });
|
|
29
|
+
await new Promise((resolve, reject) => {
|
|
30
|
+
const url = new URL(urlValue);
|
|
31
|
+
const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, (response) => {
|
|
32
|
+
const status = response.statusCode ?? 0;
|
|
33
|
+
if (status < 200 || status >= 300) {
|
|
34
|
+
response.resume();
|
|
35
|
+
reject(new Error(`File download failed with status ${status}`));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const file = createWriteStream(destination, { mode: 384 });
|
|
39
|
+
response.on("error", (error) => file.destroy(error));
|
|
40
|
+
file.on("error", reject);
|
|
41
|
+
file.on("finish", resolve);
|
|
42
|
+
response.pipe(file);
|
|
43
|
+
});
|
|
44
|
+
request.on("error", reject);
|
|
45
|
+
request.end();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async function stageFilesystemInputs(request) {
|
|
49
|
+
await Promise.all(request.inputFiles.map((file) => downloadFile(
|
|
50
|
+
file.downloadUrl,
|
|
51
|
+
resolveFile(request.workingDirectory, file.path)
|
|
52
|
+
)));
|
|
53
|
+
}
|
|
54
|
+
async function publishFilesystemOutputs(request) {
|
|
55
|
+
const files = {};
|
|
56
|
+
const uploads = [];
|
|
57
|
+
for (const output of request.outputFiles) {
|
|
58
|
+
const filePath = resolveFile(request.workingDirectory, output.path);
|
|
59
|
+
const content = (await readFile(filePath, "utf8")).trim();
|
|
60
|
+
if (isUnsafeMemoryOutput(content, request.sensitiveValues, output.maxChars)) {
|
|
61
|
+
throw new Error(`Headless agent output failed validation: ${output.path}`);
|
|
62
|
+
}
|
|
63
|
+
await writeFile(filePath, content, { mode: 384 });
|
|
64
|
+
const { size } = await stat(filePath);
|
|
65
|
+
files[output.path] = { sha256: createHash("sha256").update(content).digest("hex"), sizeBytes: size };
|
|
66
|
+
uploads.push({ url: output.uploadUrl, path: filePath, contentType: output.contentType, size });
|
|
67
|
+
}
|
|
68
|
+
await Promise.all(uploads.map((upload) => putPresignedFile(
|
|
69
|
+
upload.url,
|
|
70
|
+
upload.path,
|
|
71
|
+
upload.size,
|
|
72
|
+
upload.contentType
|
|
73
|
+
)));
|
|
74
|
+
return files;
|
|
75
|
+
}
|
|
76
|
+
function filesystemPermission(root) {
|
|
77
|
+
return async (toolName, input) => {
|
|
78
|
+
const candidate = input.file_path ?? input.path;
|
|
79
|
+
if (typeof candidate === "string") {
|
|
80
|
+
const resolved = path.resolve(root, candidate);
|
|
81
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
|
|
82
|
+
return { behavior: "deny", message: "Memory maintenance is restricted to its working directory." };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (toolName === "Glob" && typeof input.pattern === "string") {
|
|
86
|
+
if (path.isAbsolute(input.pattern) || input.pattern.split(/[\\/]/).includes("..")) {
|
|
87
|
+
return { behavior: "deny", message: "Memory maintenance is restricted to its working directory." };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { behavior: "allow", updatedInput: input };
|
|
91
|
+
};
|
|
92
|
+
}
|
|
12
93
|
async function runClaude(request) {
|
|
13
94
|
const response = query({
|
|
14
95
|
prompt: request.prompt,
|
|
15
96
|
options: {
|
|
16
97
|
cwd: request.workingDirectory,
|
|
17
98
|
model: request.model,
|
|
18
|
-
tools: [],
|
|
19
|
-
permissionMode: "dontAsk",
|
|
99
|
+
tools: request.mode === "filesystem" ? FILESYSTEM_TOOLS : [],
|
|
100
|
+
permissionMode: request.mode === "filesystem" ? "default" : "dontAsk",
|
|
101
|
+
...request.mode === "filesystem" ? { canUseTool: filesystemPermission(request.workingDirectory) } : {},
|
|
20
102
|
settingSources: [],
|
|
21
103
|
persistSession: false,
|
|
22
|
-
outputFormat: { type: "json_schema", schema: request.outputSchema },
|
|
104
|
+
...request.mode === "structured" ? { outputFormat: { type: "json_schema", schema: request.outputSchema } } : {},
|
|
23
105
|
env: { ...process.env, CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1" }
|
|
24
106
|
}
|
|
25
107
|
});
|
|
@@ -33,9 +115,10 @@ async function runClaude(request) {
|
|
|
33
115
|
}
|
|
34
116
|
if (!result) throw new Error("Claude Agent SDK returned no result");
|
|
35
117
|
if (result.subtype !== "success") throw new Error(result.errors.join("\n") || result.subtype);
|
|
118
|
+
if (request.mode === "filesystem") return result.result;
|
|
36
119
|
return result.structured_output ?? JSON.parse(result.result);
|
|
37
120
|
}
|
|
38
|
-
function runCodexTurn(client, params) {
|
|
121
|
+
function runCodexTurn(client, params, timeoutMs) {
|
|
39
122
|
return new Promise((resolve, reject) => {
|
|
40
123
|
const cleanup = () => {
|
|
41
124
|
clearTimeout(timeout);
|
|
@@ -54,7 +137,7 @@ function runCodexTurn(client, params) {
|
|
|
54
137
|
const timeout = setTimeout(() => {
|
|
55
138
|
cleanup();
|
|
56
139
|
reject(new Error("Codex ASP turn timed out"));
|
|
57
|
-
},
|
|
140
|
+
}, timeoutMs);
|
|
58
141
|
client.on("notification", onNotification);
|
|
59
142
|
client.on("dispose", onDispose);
|
|
60
143
|
void client.request("turn/start", params).catch((error) => {
|
|
@@ -78,7 +161,7 @@ async function runCodex(request) {
|
|
|
78
161
|
cwd: request.workingDirectory,
|
|
79
162
|
approvalPolicy: "never",
|
|
80
163
|
approvalsReviewer: "user",
|
|
81
|
-
sandbox: "read-only",
|
|
164
|
+
sandbox: request.mode === "filesystem" ? "workspace-write" : "read-only",
|
|
82
165
|
ephemeral: true,
|
|
83
166
|
environments: [],
|
|
84
167
|
dynamicTools: [],
|
|
@@ -87,14 +170,15 @@ async function runCodex(request) {
|
|
|
87
170
|
const turn = await runCodexTurn(client, {
|
|
88
171
|
threadId: thread.thread.id,
|
|
89
172
|
input: [{ type: "text", text: request.prompt, text_elements: [] }],
|
|
90
|
-
outputSchema: request.outputSchema,
|
|
173
|
+
...request.mode === "structured" ? { outputSchema: request.outputSchema } : {},
|
|
91
174
|
approvalPolicy: "never",
|
|
92
175
|
approvalsReviewer: "user",
|
|
93
176
|
environments: []
|
|
94
|
-
});
|
|
177
|
+
}, request.timeoutSeconds * 1e3);
|
|
95
178
|
if (turn.status === "failed") throw new Error(turn.error?.message ?? "Codex ASP turn failed");
|
|
96
179
|
const message = turn.items.findLast((item) => item.type === "agentMessage");
|
|
97
180
|
if (!message || message.type !== "agentMessage") throw new Error("Codex ASP returned no final message");
|
|
181
|
+
if (request.mode === "filesystem") return message.text;
|
|
98
182
|
return JSON.parse(message.text);
|
|
99
183
|
} finally {
|
|
100
184
|
await appServer.stop();
|
|
@@ -104,6 +188,7 @@ async function main() {
|
|
|
104
188
|
const [requestPath, outputPath] = process.argv.slice(2);
|
|
105
189
|
if (!requestPath || !outputPath) throw new Error("Usage: replicas-headless-agent <request.json> <output.json>");
|
|
106
190
|
const request = headlessAgentRequestSchema.parse(JSON.parse(await readFile(requestPath, "utf8")));
|
|
191
|
+
if (request.mode === "filesystem") await stageFilesystemInputs(request);
|
|
107
192
|
let result;
|
|
108
193
|
switch (request.agent) {
|
|
109
194
|
case AGENT.CLAUDE:
|
|
@@ -115,6 +200,10 @@ async function main() {
|
|
|
115
200
|
default:
|
|
116
201
|
throw new Error(`Unsupported headless agent: ${request.agent}`);
|
|
117
202
|
}
|
|
203
|
+
if (request.mode === "filesystem") {
|
|
204
|
+
if (typeof result !== "string") throw new Error("Filesystem agent returned an invalid result");
|
|
205
|
+
result = { message: result, files: await publishFilesystemOutputs(request) };
|
|
206
|
+
}
|
|
118
207
|
await writeFile(outputPath, JSON.stringify(result), { mode: 384 });
|
|
119
208
|
}
|
|
120
209
|
main().catch((error) => {
|
package/dist/src/index.js
CHANGED
|
@@ -140,6 +140,7 @@ import {
|
|
|
140
140
|
parseMcpToolName,
|
|
141
141
|
parseReplicasConfigString,
|
|
142
142
|
percentage,
|
|
143
|
+
putPresignedFile,
|
|
143
144
|
raceWithTimeout,
|
|
144
145
|
resolveClaudeAuthMethodForMessage,
|
|
145
146
|
resolveWarmHookConfig,
|
|
@@ -148,7 +149,7 @@ import {
|
|
|
148
149
|
setAgentCredentialSnapshot,
|
|
149
150
|
shellQuotePosix,
|
|
150
151
|
stripAgentDiagnosticErrors
|
|
151
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-GT5CS5BI.js";
|
|
152
153
|
|
|
153
154
|
// src/index.ts
|
|
154
155
|
import { serve } from "@hono/node-server";
|
|
@@ -10099,8 +10100,6 @@ async function reconcileCanvasItems(filenames) {
|
|
|
10099
10100
|
import { createReadStream } from "fs";
|
|
10100
10101
|
import { createHash as createHash2 } from "crypto";
|
|
10101
10102
|
import { readdir as readdir8, readFile as readFile14, stat as stat4 } from "fs/promises";
|
|
10102
|
-
import { request as httpRequest } from "http";
|
|
10103
|
-
import { request as httpsRequest } from "https";
|
|
10104
10103
|
import { basename as basename2, join as join23 } from "path";
|
|
10105
10104
|
|
|
10106
10105
|
// src/services/chat/chat-senders.ts
|
|
@@ -10127,34 +10126,6 @@ var HISTORY_DIRS = [
|
|
|
10127
10126
|
join23(ENGINE_DIR2, "relay-histories"),
|
|
10128
10127
|
join23(ENGINE_DIR2, "codex-histories")
|
|
10129
10128
|
];
|
|
10130
|
-
async function putTranscript(uploadUrl, filePath, size) {
|
|
10131
|
-
await new Promise((resolve5, reject) => {
|
|
10132
|
-
const url = new URL(uploadUrl);
|
|
10133
|
-
const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
|
|
10134
|
-
method: "PUT",
|
|
10135
|
-
headers: {
|
|
10136
|
-
"content-length": String(size),
|
|
10137
|
-
"content-type": "application/x-ndjson"
|
|
10138
|
-
}
|
|
10139
|
-
}, (response) => {
|
|
10140
|
-
response.setEncoding("utf8");
|
|
10141
|
-
let body = "";
|
|
10142
|
-
response.on("data", (chunk) => {
|
|
10143
|
-
body += chunk;
|
|
10144
|
-
});
|
|
10145
|
-
response.on("end", () => {
|
|
10146
|
-
const status = response.statusCode ?? 0;
|
|
10147
|
-
if (status >= 200 && status < 300) resolve5();
|
|
10148
|
-
else reject(new Error(`upload failed: ${status} ${body}`));
|
|
10149
|
-
});
|
|
10150
|
-
response.on("error", reject);
|
|
10151
|
-
});
|
|
10152
|
-
request.on("error", reject);
|
|
10153
|
-
const file = createReadStream(filePath, { start: 0, end: size - 1 });
|
|
10154
|
-
file.on("error", (error) => request.destroy(error));
|
|
10155
|
-
file.pipe(request);
|
|
10156
|
-
});
|
|
10157
|
-
}
|
|
10158
10129
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), capture) {
|
|
10159
10130
|
let flushed = 0;
|
|
10160
10131
|
let failed = 0;
|
|
@@ -10222,7 +10193,7 @@ async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
|
10222
10193
|
throw new Error("prepare failed: invalid response");
|
|
10223
10194
|
}
|
|
10224
10195
|
if (prepareBody.uploadUrl === null) return null;
|
|
10225
|
-
await
|
|
10196
|
+
await putPresignedFile(prepareBody.uploadUrl, filePath, size, "application/x-ndjson");
|
|
10226
10197
|
const finalizeResponse = await monolithRequest("/v1/engine/chat-transcripts/finalize", {
|
|
10227
10198
|
body: uploadRequest
|
|
10228
10199
|
});
|