gpt-connector 0.1.0 → 0.2.0
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 +100 -13
- package/dist/src/asset-discovery.d.ts +2 -0
- package/dist/src/asset-discovery.js +58 -12
- package/dist/src/asset-discovery.js.map +1 -1
- package/dist/src/attachment-files.d.ts +25 -0
- package/dist/src/attachment-files.js +272 -0
- package/dist/src/attachment-files.js.map +1 -0
- package/dist/src/cli.js +90 -7
- package/dist/src/cli.js.map +1 -1
- package/dist/src/connector.d.ts +6 -1
- package/dist/src/connector.js +368 -10
- package/dist/src/connector.js.map +1 -1
- package/dist/src/consult-job-store.d.ts +37 -0
- package/dist/src/consult-job-store.js +464 -0
- package/dist/src/consult-job-store.js.map +1 -0
- package/dist/src/contract.d.ts +86 -0
- package/dist/src/contract.js +42 -0
- package/dist/src/contract.js.map +1 -1
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js +13 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp-server.d.ts +8 -3
- package/dist/src/mcp-server.js +67 -5
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp.js +1 -1
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/page-bridge.d.ts +2 -2
- package/dist/src/page-bridge.js +333 -12
- package/dist/src/page-bridge.js.map +1 -1
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +2 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { GptConnector } from "./connector.js";
|
|
3
|
+
import { ConsultJobStore } from "./consult-job-store.js";
|
|
3
4
|
import { ConnectorError } from "./errors.js";
|
|
5
|
+
import { packageVersion } from "./version.js";
|
|
4
6
|
function parseArgs(args) {
|
|
5
7
|
const [command, ...rest] = args;
|
|
6
8
|
const values = new Map();
|
|
@@ -10,10 +12,16 @@ function parseArgs(args) {
|
|
|
10
12
|
throw new Error(`不明な引数: ${current}`);
|
|
11
13
|
const key = current.slice(2);
|
|
12
14
|
const next = rest[index + 1];
|
|
13
|
-
|
|
15
|
+
const existing = values.get(key);
|
|
16
|
+
if (next === undefined || next.startsWith("--")) {
|
|
17
|
+
if (existing !== undefined)
|
|
18
|
+
throw new Error(`重複したflag: --${key}`);
|
|
14
19
|
values.set(key, true);
|
|
20
|
+
}
|
|
15
21
|
else {
|
|
16
|
-
|
|
22
|
+
if (existing === true)
|
|
23
|
+
throw new Error(`値とflagを混在できません: --${key}`);
|
|
24
|
+
values.set(key, [...(existing ?? []), next]);
|
|
17
25
|
index += 1;
|
|
18
26
|
}
|
|
19
27
|
}
|
|
@@ -21,15 +29,65 @@ function parseArgs(args) {
|
|
|
21
29
|
}
|
|
22
30
|
function stringArg(values, name) {
|
|
23
31
|
const value = values.get(name);
|
|
24
|
-
|
|
32
|
+
if (value === undefined)
|
|
33
|
+
return undefined;
|
|
34
|
+
if (value === true || value.length !== 1)
|
|
35
|
+
throw new Error(`--${name}は1つの値が必要です。`);
|
|
36
|
+
return value[0];
|
|
37
|
+
}
|
|
38
|
+
function stringArgs(values, name) {
|
|
39
|
+
const value = values.get(name);
|
|
40
|
+
if (value === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (value === true)
|
|
43
|
+
throw new Error(`--${name}には値が必要です。`);
|
|
44
|
+
return [...value];
|
|
45
|
+
}
|
|
46
|
+
function flagArg(values, name) {
|
|
47
|
+
const value = values.get(name);
|
|
48
|
+
if (value === undefined)
|
|
49
|
+
return false;
|
|
50
|
+
if (value !== true)
|
|
51
|
+
throw new Error(`--${name}は値なしflagです。`);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function writeJson(value) {
|
|
55
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
25
56
|
}
|
|
26
57
|
async function main() {
|
|
27
58
|
const { command, values } = parseArgs(process.argv.slice(2));
|
|
59
|
+
if (command === "--version" || command === "version") {
|
|
60
|
+
process.stdout.write(`${packageVersion}\n`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
28
63
|
const endpoint = stringArg(values, "endpoint") ?? "http://127.0.0.1:9223";
|
|
29
|
-
const
|
|
64
|
+
const stateDirectory = stringArg(values, "state-directory") ??
|
|
65
|
+
process.env.GPT_CONNECTOR_STATE_DIR;
|
|
66
|
+
if (command === "sessions") {
|
|
67
|
+
const slug = stringArg(values, "slug");
|
|
68
|
+
if (slug === undefined)
|
|
69
|
+
throw new Error("sessionsには--slugが必要です。");
|
|
70
|
+
const store = new ConsultJobStore({ stateDirectory, readOnly: true });
|
|
71
|
+
await store.initialize();
|
|
72
|
+
try {
|
|
73
|
+
writeJson(store.get(slug));
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
store.close();
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (command === "doctor" || command === "diagnostics") {
|
|
81
|
+
const diagnostics = await GptConnector.doctor({ endpoint, stateDirectory });
|
|
82
|
+
writeJson(diagnostics);
|
|
83
|
+
if (diagnostics.overall !== "ready")
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const connector = await GptConnector.connect({ endpoint, stateDirectory });
|
|
30
88
|
try {
|
|
31
89
|
if (command === "models") {
|
|
32
|
-
|
|
90
|
+
writeJson(await connector.models());
|
|
33
91
|
return;
|
|
34
92
|
}
|
|
35
93
|
if (command === "chat") {
|
|
@@ -42,10 +100,35 @@ async function main() {
|
|
|
42
100
|
effort: stringArg(values, "effort"),
|
|
43
101
|
keepOpen: false,
|
|
44
102
|
});
|
|
45
|
-
|
|
103
|
+
writeJson(result);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (command === "consult") {
|
|
107
|
+
const prompt = stringArg(values, "prompt");
|
|
108
|
+
const slug = stringArg(values, "slug");
|
|
109
|
+
if (prompt === undefined || slug === undefined) {
|
|
110
|
+
throw new Error("consultには--promptと--slugが必要です。");
|
|
111
|
+
}
|
|
112
|
+
writeJson(await connector.consult({
|
|
113
|
+
prompt,
|
|
114
|
+
slug,
|
|
115
|
+
files: stringArgs(values, "file"),
|
|
116
|
+
workspaceRoot: stringArg(values, "workspace-root"),
|
|
117
|
+
model: stringArg(values, "model"),
|
|
118
|
+
effort: stringArg(values, "effort"),
|
|
119
|
+
keepOpen: flagArg(values, "keep-open"),
|
|
120
|
+
dryRun: flagArg(values, "dry-run"),
|
|
121
|
+
}));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (command === "close") {
|
|
125
|
+
const sessionId = stringArg(values, "session-id");
|
|
126
|
+
if (sessionId === undefined)
|
|
127
|
+
throw new Error("closeには--session-idが必要です。");
|
|
128
|
+
writeJson(await connector.closeSession({ sessionId }));
|
|
46
129
|
return;
|
|
47
130
|
}
|
|
48
|
-
throw new Error("usage: gpt-connector models | chat --prompt <text> [--model <id>] [--
|
|
131
|
+
throw new Error("usage: gpt-connector --version | models | doctor | chat --prompt <text> | consult --prompt <text> --slug <id> [--workspace-root <abs> --file <spec> ...] [--model <id> --effort <id>] [--dry-run] | sessions --slug <id> | close --session-id <uuid>");
|
|
49
132
|
}
|
|
50
133
|
finally {
|
|
51
134
|
connector.close();
|
package/dist/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/src/connector.d.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
import { type ChatInput, type ChatResult, type CloseInput, type CloseResult, type ModelCatalog } from "./contract.js";
|
|
1
|
+
import { type ChatInput, type ChatResult, type CloseInput, type CloseResult, type ConnectorDiagnostics, type ConsultDryRunResult, type ConsultInput, type ConsultSnapshot, type ModelCatalog, type SessionsInput } from "./contract.js";
|
|
2
2
|
export interface ConnectorOptions {
|
|
3
3
|
readonly endpoint?: string;
|
|
4
4
|
readonly operationTimeoutMs?: number;
|
|
5
5
|
readonly pollIntervalMs?: number;
|
|
6
|
+
readonly stateDirectory?: string;
|
|
6
7
|
}
|
|
7
8
|
export declare class GptConnector {
|
|
8
9
|
#private;
|
|
9
10
|
private constructor();
|
|
10
11
|
static connect(options?: ConnectorOptions): Promise<GptConnector>;
|
|
12
|
+
static doctor(options?: ConnectorOptions): Promise<ConnectorDiagnostics>;
|
|
11
13
|
models(): Promise<ModelCatalog>;
|
|
14
|
+
diagnostics(): Promise<ConnectorDiagnostics>;
|
|
12
15
|
chat(input: ChatInput): Promise<ChatResult>;
|
|
16
|
+
consult(input: ConsultInput): Promise<ConsultSnapshot | ConsultDryRunResult>;
|
|
17
|
+
sessions(input: SessionsInput): ConsultSnapshot;
|
|
13
18
|
closeSession(input: CloseInput): Promise<CloseResult>;
|
|
14
19
|
close(): void;
|
|
15
20
|
shutdown(): Promise<void>;
|
package/dist/src/connector.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2
3
|
import { z } from "zod";
|
|
4
|
+
import { attachmentLimits, prepareAttachmentFiles, } from "./attachment-files.js";
|
|
3
5
|
import { discoverRuntimeAssets, listLoadedAssetUrls } from "./asset-discovery.js";
|
|
4
6
|
import { CdpClient, discoverChatGptTarget } from "./cdp.js";
|
|
5
|
-
import { chatInputSchema, closeInputSchema, } from "./contract.js";
|
|
7
|
+
import { chatInputSchema, closeInputSchema, consultInputSchema, sessionsInputSchema, } from "./contract.js";
|
|
8
|
+
import { ConsultJobStore } from "./consult-job-store.js";
|
|
6
9
|
import { ConnectorError, connectorErrorCodes, } from "./errors.js";
|
|
7
10
|
import { validateModelSelection } from "./model-catalog.js";
|
|
8
11
|
import { bridgeBuildId, createBridgeBootstrapExpression, createBridgeCallExpression, } from "./page-bridge.js";
|
|
9
12
|
import { evaluateByValue } from "./runtime-evaluate.js";
|
|
10
13
|
import { SessionRegistry } from "./session-registry.js";
|
|
14
|
+
import { packageVersion } from "./version.js";
|
|
11
15
|
const operationStartSchema = z.object({ operationId: z.string().uuid() });
|
|
12
16
|
const operationErrorSchema = z.object({
|
|
13
17
|
code: z.string(),
|
|
@@ -37,14 +41,42 @@ const chatResultSchema = z.object({
|
|
|
37
41
|
resolvedEffort: z.string().nullable(),
|
|
38
42
|
sessionId: z.string().uuid().optional(),
|
|
39
43
|
});
|
|
44
|
+
const attachmentSummarySchema = z.object({
|
|
45
|
+
count: z.number().int().nonnegative(),
|
|
46
|
+
names: z.array(z.string()),
|
|
47
|
+
mimeTypes: z.array(z.string().nullable()),
|
|
48
|
+
readBack: z.literal("confirmed"),
|
|
49
|
+
retention: z.literal("unknown"),
|
|
50
|
+
cleanup: z.enum(["not_supported", "failed", "deleted"]),
|
|
51
|
+
});
|
|
52
|
+
const bridgeChatResultSchema = chatResultSchema.extend({
|
|
53
|
+
attachments: attachmentSummarySchema,
|
|
54
|
+
});
|
|
55
|
+
const uploadHandleSchema = z.object({ uploadHandle: z.string().uuid() });
|
|
56
|
+
const uploadChunkResultSchema = z.object({ receivedBytes: z.number().int().nonnegative() });
|
|
57
|
+
const uploadResultSchema = z.object({
|
|
58
|
+
uploadHandle: z.string().uuid(),
|
|
59
|
+
name: z.string(),
|
|
60
|
+
size: z.number().int().positive(),
|
|
61
|
+
mimeType: z.string(),
|
|
62
|
+
});
|
|
63
|
+
const uploadChunkBytes = 256 * 1024;
|
|
40
64
|
const closeResultSchema = z.object({ archived: z.literal(true) });
|
|
65
|
+
const pageDiagnosticsSchema = z.object({
|
|
66
|
+
sessionCount: z.number().int().nonnegative(),
|
|
67
|
+
operationCount: z.number().int().nonnegative(),
|
|
68
|
+
uploadCount: z.number().int().nonnegative(),
|
|
69
|
+
bufferedUploadBytes: z.number().int().nonnegative(),
|
|
70
|
+
});
|
|
41
71
|
export class GptConnector {
|
|
42
72
|
#client;
|
|
43
73
|
#sessions = new SessionRegistry();
|
|
74
|
+
#jobs;
|
|
44
75
|
#operationTimeoutMs;
|
|
45
76
|
#pollIntervalMs;
|
|
46
77
|
constructor(client, options) {
|
|
47
78
|
this.#client = client;
|
|
79
|
+
this.#jobs = new ConsultJobStore({ stateDirectory: options.stateDirectory });
|
|
48
80
|
this.#operationTimeoutMs = options.operationTimeoutMs ?? 180_000;
|
|
49
81
|
this.#pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
50
82
|
}
|
|
@@ -55,28 +87,214 @@ export class GptConnector {
|
|
|
55
87
|
const connector = new GptConnector(client, options);
|
|
56
88
|
try {
|
|
57
89
|
await client.call("Runtime.enable");
|
|
90
|
+
await connector.#jobs.initialize();
|
|
58
91
|
await connector.#bootstrap();
|
|
59
92
|
return connector;
|
|
60
93
|
}
|
|
61
94
|
catch (error) {
|
|
62
|
-
|
|
95
|
+
try {
|
|
96
|
+
connector.#jobs.close();
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
client.close();
|
|
100
|
+
}
|
|
63
101
|
throw error;
|
|
64
102
|
}
|
|
65
103
|
}
|
|
104
|
+
static async doctor(options = {}) {
|
|
105
|
+
let connector = null;
|
|
106
|
+
try {
|
|
107
|
+
connector = await GptConnector.connect(options);
|
|
108
|
+
return await connector.diagnostics();
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const code = error instanceof ConnectorError ? error.code : null;
|
|
112
|
+
return {
|
|
113
|
+
schema: "gpt-connector.diagnostics.v1",
|
|
114
|
+
packageVersion,
|
|
115
|
+
overall: "not_ready",
|
|
116
|
+
reasonCode: diagnosticReason(code),
|
|
117
|
+
cdpConnected: false,
|
|
118
|
+
officialOrigin: null,
|
|
119
|
+
authenticated: code === "AUTH_REQUIRED" ? false : null,
|
|
120
|
+
bridgeBuildId,
|
|
121
|
+
sessionCount: null,
|
|
122
|
+
operationCount: null,
|
|
123
|
+
uploadCount: null,
|
|
124
|
+
bufferedUploadBytes: null,
|
|
125
|
+
jobCount: null,
|
|
126
|
+
activeJobCount: null,
|
|
127
|
+
terminalJobCount: null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
connector?.close();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
66
134
|
async models() {
|
|
67
135
|
const result = await this.#runOperation("startModels", []);
|
|
68
136
|
return modelCatalogSchema.parse(result);
|
|
69
137
|
}
|
|
138
|
+
async diagnostics() {
|
|
139
|
+
const page = pageDiagnosticsSchema.parse(await evaluateByValue(this.#client, createBridgeCallExpression("diagnostics", []), false));
|
|
140
|
+
const jobs = this.#jobs.diagnostics();
|
|
141
|
+
return {
|
|
142
|
+
schema: "gpt-connector.diagnostics.v1",
|
|
143
|
+
packageVersion,
|
|
144
|
+
overall: "ready",
|
|
145
|
+
reasonCode: "ready",
|
|
146
|
+
cdpConnected: true,
|
|
147
|
+
officialOrigin: true,
|
|
148
|
+
authenticated: true,
|
|
149
|
+
bridgeBuildId,
|
|
150
|
+
...page,
|
|
151
|
+
...jobs,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
70
154
|
async chat(input) {
|
|
71
155
|
const parsed = chatInputSchema.parse(input);
|
|
156
|
+
const result = await this.#chatParsed(parsed, []);
|
|
157
|
+
return chatResultSchema.parse(result);
|
|
158
|
+
}
|
|
159
|
+
async consult(input) {
|
|
160
|
+
let parsed;
|
|
161
|
+
try {
|
|
162
|
+
parsed = consultInputSchema.parse(input);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
throw new ConnectorError("INVALID_INPUT", "consult inputが公開schemaに一致しません。");
|
|
166
|
+
}
|
|
72
167
|
const catalog = await this.models();
|
|
73
168
|
validateModelSelection(catalog, parsed.model, parsed.effort);
|
|
169
|
+
const prepared = parsed.files === undefined
|
|
170
|
+
? { files: [], totalBytes: 0 }
|
|
171
|
+
: await prepareAttachmentFiles({
|
|
172
|
+
workspaceRoot: parsed.workspaceRoot,
|
|
173
|
+
specs: parsed.files,
|
|
174
|
+
});
|
|
175
|
+
const fileMetadata = prepared.files.map((file) => ({
|
|
176
|
+
relativePath: file.relativePath,
|
|
177
|
+
name: file.name,
|
|
178
|
+
bytes: file.bytes,
|
|
179
|
+
mimeType: file.mimeType,
|
|
180
|
+
sha256: file.sha256,
|
|
181
|
+
}));
|
|
182
|
+
if (parsed.dryRun) {
|
|
183
|
+
for (const file of prepared.files)
|
|
184
|
+
file.content.fill(0);
|
|
185
|
+
return {
|
|
186
|
+
dryRun: true,
|
|
187
|
+
slug: parsed.slug,
|
|
188
|
+
files: fileMetadata,
|
|
189
|
+
totalBytes: prepared.totalBytes,
|
|
190
|
+
requestedModel: parsed.model ?? null,
|
|
191
|
+
requestedEffort: parsed.effort ?? null,
|
|
192
|
+
limits: attachmentLimits,
|
|
193
|
+
uploadWouldRun: false,
|
|
194
|
+
conversationWouldRun: false,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const fingerprint = consultFingerprint({
|
|
198
|
+
prompt: parsed.prompt,
|
|
199
|
+
files: fileMetadata,
|
|
200
|
+
model: parsed.model ?? null,
|
|
201
|
+
effort: parsed.effort ?? null,
|
|
202
|
+
keepOpen: parsed.keepOpen,
|
|
203
|
+
});
|
|
204
|
+
const reservation = await this.#jobs.reserve(parsed.slug, fingerprint);
|
|
205
|
+
if (!reservation.created) {
|
|
206
|
+
for (const file of prepared.files)
|
|
207
|
+
file.content.fill(0);
|
|
208
|
+
return reservation.snapshot;
|
|
209
|
+
}
|
|
210
|
+
return this.#runConsultJob(parsed, prepared.files);
|
|
211
|
+
}
|
|
212
|
+
sessions(input) {
|
|
213
|
+
let parsed;
|
|
214
|
+
try {
|
|
215
|
+
parsed = sessionsInputSchema.parse(input);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
throw new ConnectorError("INVALID_INPUT", "sessions inputが公開schemaに一致しません。");
|
|
219
|
+
}
|
|
220
|
+
return this.#jobs.get(parsed.slug);
|
|
221
|
+
}
|
|
222
|
+
async #runConsultJob(parsed, files) {
|
|
223
|
+
let uploadHandles = [];
|
|
224
|
+
try {
|
|
225
|
+
await this.#jobs.transition(parsed.slug, "uploading");
|
|
226
|
+
uploadHandles = await this.#uploadAttachments(files);
|
|
227
|
+
await this.#jobs.transition(parsed.slug, "submitted");
|
|
228
|
+
await this.#jobs.transition(parsed.slug, "running");
|
|
229
|
+
const result = await this.#chatParsed({
|
|
230
|
+
prompt: parsed.prompt,
|
|
231
|
+
model: parsed.model,
|
|
232
|
+
effort: parsed.effort,
|
|
233
|
+
keepOpen: parsed.keepOpen,
|
|
234
|
+
}, uploadHandles, true);
|
|
235
|
+
return this.#jobs.transition(parsed.slug, "succeeded", {
|
|
236
|
+
result: {
|
|
237
|
+
text: result.text,
|
|
238
|
+
status: result.status,
|
|
239
|
+
endTurn: true,
|
|
240
|
+
resolvedModel: result.resolvedModel,
|
|
241
|
+
resolvedEffort: result.resolvedEffort,
|
|
242
|
+
...(result.sessionId === undefined ? {} : { sessionId: result.sessionId }),
|
|
243
|
+
attachments: result.attachments,
|
|
244
|
+
archived: parsed.keepOpen !== true,
|
|
245
|
+
},
|
|
246
|
+
error: null,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
let jobError = error;
|
|
251
|
+
let cleanup = "not_supported";
|
|
252
|
+
for (const uploadHandle of uploadHandles) {
|
|
253
|
+
try {
|
|
254
|
+
await this.#discardUpload(uploadHandle);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// job errorをcleanup failureへ昇格し、成功や元errorの握り潰しを防ぐ。
|
|
258
|
+
jobError = new ConnectorError("UPLOAD_FAILED", "consult失敗後にpage側upload handleを完全破棄できませんでした。");
|
|
259
|
+
cleanup = "failed";
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const connectorError = jobError instanceof ConnectorError
|
|
264
|
+
? jobError
|
|
265
|
+
: new ConnectorError("CHAT_FAILED", "consult jobが失敗しました。");
|
|
266
|
+
const partialCount = typeof connectorError.details?.uploadedCount === "number"
|
|
267
|
+
? connectorError.details.uploadedCount
|
|
268
|
+
: uploadHandles.length;
|
|
269
|
+
const partialCleanup = connectorError.details?.cleanup === "failed"
|
|
270
|
+
? "failed"
|
|
271
|
+
: cleanup;
|
|
272
|
+
return this.#jobs.transition(parsed.slug, "failed", {
|
|
273
|
+
result: null,
|
|
274
|
+
error: {
|
|
275
|
+
code: connectorError.code,
|
|
276
|
+
message: connectorError.message,
|
|
277
|
+
retry: retryFor(connectorError.code),
|
|
278
|
+
...(partialCount > 0 ? {
|
|
279
|
+
partialUpload: { count: partialCount, cleanup: partialCleanup },
|
|
280
|
+
} : {}),
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async #chatParsed(parsed, attachmentHandles, selectionValidated = false) {
|
|
286
|
+
if (!selectionValidated) {
|
|
287
|
+
const catalog = await this.models();
|
|
288
|
+
validateModelSelection(catalog, parsed.model, parsed.effort);
|
|
289
|
+
}
|
|
74
290
|
const existingSession = parsed.sessionId;
|
|
75
291
|
if (existingSession !== undefined)
|
|
76
292
|
this.#sessions.acquire(existingSession);
|
|
77
293
|
try {
|
|
78
|
-
const raw = await this.#runOperation("startChat", [
|
|
79
|
-
|
|
294
|
+
const raw = await this.#runOperation("startChat", [
|
|
295
|
+
{ ...parsed, attachmentHandles },
|
|
296
|
+
]);
|
|
297
|
+
const result = bridgeChatResultSchema.parse(raw);
|
|
80
298
|
if (existingSession !== undefined) {
|
|
81
299
|
if (parsed.keepOpen)
|
|
82
300
|
this.#sessions.release(existingSession);
|
|
@@ -101,6 +319,87 @@ export class GptConnector {
|
|
|
101
319
|
throw error;
|
|
102
320
|
}
|
|
103
321
|
}
|
|
322
|
+
async #uploadAttachments(files) {
|
|
323
|
+
const uploadHandles = [];
|
|
324
|
+
try {
|
|
325
|
+
for (const file of files) {
|
|
326
|
+
uploadHandles.push(await this.#transferAttachment(file));
|
|
327
|
+
}
|
|
328
|
+
return uploadHandles;
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
const cleanupFailures = [];
|
|
332
|
+
for (const uploadHandle of uploadHandles) {
|
|
333
|
+
try {
|
|
334
|
+
await this.#discardUpload(uploadHandle);
|
|
335
|
+
}
|
|
336
|
+
catch (cleanupError) {
|
|
337
|
+
cleanupFailures.push(cleanupError instanceof ConnectorError ? cleanupError.code : "RUNTIME_DRIFT");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (cleanupFailures.length > 0) {
|
|
341
|
+
throw new ConnectorError("UPLOAD_FAILED", "添付upload失敗後にpage側handleを完全破棄できませんでした。", {
|
|
342
|
+
cleanupFailureCount: cleanupFailures.length,
|
|
343
|
+
uploadedCount: uploadHandles.length,
|
|
344
|
+
cleanup: "failed",
|
|
345
|
+
originalCode: error instanceof ConnectorError ? error.code : "UPLOAD_FAILED",
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
if (uploadHandles.length > 0) {
|
|
349
|
+
const original = error instanceof ConnectorError
|
|
350
|
+
? error
|
|
351
|
+
: new ConnectorError("UPLOAD_FAILED", "添付uploadが途中で失敗しました。");
|
|
352
|
+
throw new ConnectorError(original.code, original.message, {
|
|
353
|
+
uploadedCount: uploadHandles.length,
|
|
354
|
+
cleanup: "not_supported",
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
for (const file of files)
|
|
361
|
+
file.content.fill(0);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
async #transferAttachment(file) {
|
|
365
|
+
const created = uploadHandleSchema.parse(await evaluateByValue(this.#client, createBridgeCallExpression("createUpload", [{
|
|
366
|
+
name: file.name,
|
|
367
|
+
mimeType: file.mimeType,
|
|
368
|
+
size: file.bytes,
|
|
369
|
+
sha256: file.sha256,
|
|
370
|
+
}]), false));
|
|
371
|
+
try {
|
|
372
|
+
for (let offset = 0; offset < file.content.byteLength; offset += uploadChunkBytes) {
|
|
373
|
+
const length = Math.min(uploadChunkBytes, file.content.byteLength - offset);
|
|
374
|
+
const base64Chunk = Buffer.from(file.content.buffer, file.content.byteOffset + offset, length).toString("base64");
|
|
375
|
+
const appended = uploadChunkResultSchema.parse(await evaluateByValue(this.#client, createBridgeCallExpression("appendUploadChunk", [
|
|
376
|
+
created.uploadHandle,
|
|
377
|
+
base64Chunk,
|
|
378
|
+
]), false));
|
|
379
|
+
if (appended.receivedBytes !== offset + length) {
|
|
380
|
+
throw new ConnectorError("UPLOAD_FAILED", "page側の添付byte受信数が一致しませんでした。");
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const result = uploadResultSchema.parse(await this.#runOperation("startUpload", [{
|
|
384
|
+
uploadHandle: created.uploadHandle,
|
|
385
|
+
timeoutMs: Math.min(this.#operationTimeoutMs, 120_000),
|
|
386
|
+
}]));
|
|
387
|
+
if (result.uploadHandle !== created.uploadHandle ||
|
|
388
|
+
result.name !== file.name ||
|
|
389
|
+
result.size !== file.bytes ||
|
|
390
|
+
result.mimeType !== file.mimeType) {
|
|
391
|
+
throw new ConnectorError("RUNTIME_DRIFT", "upload完了metadataが送信fileと一致しませんでした。");
|
|
392
|
+
}
|
|
393
|
+
return created.uploadHandle;
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
await this.#discardUpload(created.uploadHandle);
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async #discardUpload(uploadHandle) {
|
|
401
|
+
await evaluateByValue(this.#client, createBridgeCallExpression("discardUpload", [uploadHandle]), false);
|
|
402
|
+
}
|
|
104
403
|
async closeSession(input) {
|
|
105
404
|
const parsed = closeInputSchema.parse(input);
|
|
106
405
|
this.#sessions.acquire(parsed.sessionId);
|
|
@@ -117,7 +416,12 @@ export class GptConnector {
|
|
|
117
416
|
}
|
|
118
417
|
}
|
|
119
418
|
close() {
|
|
120
|
-
|
|
419
|
+
try {
|
|
420
|
+
this.#jobs.close();
|
|
421
|
+
}
|
|
422
|
+
finally {
|
|
423
|
+
this.#client.close();
|
|
424
|
+
}
|
|
121
425
|
}
|
|
122
426
|
async shutdown() {
|
|
123
427
|
const failures = [];
|
|
@@ -129,7 +433,12 @@ export class GptConnector {
|
|
|
129
433
|
failures.push(error instanceof ConnectorError ? error.code : "CHAT_FAILED");
|
|
130
434
|
}
|
|
131
435
|
}
|
|
132
|
-
|
|
436
|
+
try {
|
|
437
|
+
this.#jobs.close();
|
|
438
|
+
}
|
|
439
|
+
finally {
|
|
440
|
+
this.#client.close();
|
|
441
|
+
}
|
|
133
442
|
if (failures.length > 0) {
|
|
134
443
|
throw new ConnectorError("ARCHIVE_FAILED", "shutdown時に一部sessionをarchiveできませんでした。", { failureCount: failures.length });
|
|
135
444
|
}
|
|
@@ -175,7 +484,7 @@ export class GptConnector {
|
|
|
175
484
|
return;
|
|
176
485
|
const urls = await listLoadedAssetUrls(this.#client);
|
|
177
486
|
const assets = await discoverRuntimeAssets(urls);
|
|
178
|
-
const summary = await evaluateByValue(this.#client, createBridgeBootstrapExpression(assets.coreUrl, assets.conversationUrl));
|
|
487
|
+
const summary = await evaluateByValue(this.#client, createBridgeBootstrapExpression(assets.coreUrl, assets.conversationUrl, assets.uploadUrl));
|
|
179
488
|
const parsed = z
|
|
180
489
|
.object({
|
|
181
490
|
version: z.literal(1),
|
|
@@ -187,6 +496,7 @@ export class GptConnector {
|
|
|
187
496
|
throw new ConnectorError("RUNTIME_DRIFT", "page bridgeを初期化できませんでした。", {
|
|
188
497
|
coreFingerprint: assets.coreFingerprint,
|
|
189
498
|
conversationFingerprint: assets.conversationFingerprint,
|
|
499
|
+
uploadFingerprint: assets.uploadFingerprint,
|
|
190
500
|
});
|
|
191
501
|
}
|
|
192
502
|
}
|
|
@@ -206,9 +516,7 @@ export class GptConnector {
|
|
|
206
516
|
}
|
|
207
517
|
await delay(this.#pollIntervalMs);
|
|
208
518
|
}
|
|
209
|
-
throw new ConnectorError("CHAT_FAILED", "ChatGPT runtime operationがtimeoutしました。", {
|
|
210
|
-
method,
|
|
211
|
-
});
|
|
519
|
+
throw new ConnectorError(method === "startUpload" ? "UPLOAD_TIMEOUT" : "CHAT_FAILED", "ChatGPT runtime operationがtimeoutしました。", { method });
|
|
212
520
|
}
|
|
213
521
|
async #consumeOperation(operationId) {
|
|
214
522
|
await evaluateByValue(this.#client, createBridgeCallExpression("poll", [operationId, true]), false);
|
|
@@ -219,4 +527,54 @@ function toConnectorErrorCode(value) {
|
|
|
219
527
|
? value
|
|
220
528
|
: "CHAT_FAILED";
|
|
221
529
|
}
|
|
530
|
+
function diagnosticReason(code) {
|
|
531
|
+
if (code === "AUTH_REQUIRED")
|
|
532
|
+
return "auth_required";
|
|
533
|
+
if (code === "CDP_UNAVAILABLE")
|
|
534
|
+
return "cdp_unavailable";
|
|
535
|
+
if (code === "RUNTIME_DRIFT")
|
|
536
|
+
return "runtime_drift";
|
|
537
|
+
if (code === "JOB_RECOVERY_UNAVAILABLE")
|
|
538
|
+
return "state_unavailable";
|
|
539
|
+
return "connector_error";
|
|
540
|
+
}
|
|
541
|
+
function consultFingerprint(input) {
|
|
542
|
+
return createHash("sha256")
|
|
543
|
+
.update(JSON.stringify({
|
|
544
|
+
promptSha256: createHash("sha256").update(input.prompt).digest("hex"),
|
|
545
|
+
files: input.files.map((file) => ({
|
|
546
|
+
relativePath: file.relativePath,
|
|
547
|
+
bytes: file.bytes,
|
|
548
|
+
sha256: file.sha256,
|
|
549
|
+
})),
|
|
550
|
+
model: input.model,
|
|
551
|
+
effort: input.effort,
|
|
552
|
+
keepOpen: input.keepOpen,
|
|
553
|
+
}))
|
|
554
|
+
.digest("hex");
|
|
555
|
+
}
|
|
556
|
+
function retryFor(code) {
|
|
557
|
+
if (code === "AUTH_REQUIRED")
|
|
558
|
+
return "after_auth";
|
|
559
|
+
if (code === "RUNTIME_DRIFT")
|
|
560
|
+
return "after_runtime_update";
|
|
561
|
+
if (code === "INVALID_INPUT" ||
|
|
562
|
+
code === "FILE_NOT_FOUND" ||
|
|
563
|
+
code === "FILE_OUTSIDE_ROOT" ||
|
|
564
|
+
code === "SENSITIVE_FILE_BLOCKED" ||
|
|
565
|
+
code === "FILE_TYPE_NOT_SUPPORTED" ||
|
|
566
|
+
code === "FILE_EMPTY" ||
|
|
567
|
+
code === "FILE_LIMIT_EXCEEDED" ||
|
|
568
|
+
code === "MODEL_NOT_AVAILABLE" ||
|
|
569
|
+
code === "EFFORT_NOT_SUPPORTED")
|
|
570
|
+
return "after_input_change";
|
|
571
|
+
if (code === "UPLOAD_TIMEOUT" ||
|
|
572
|
+
code === "UPLOAD_FAILED" ||
|
|
573
|
+
code === "CHAT_FAILED" ||
|
|
574
|
+
code === "STREAM_INCOMPLETE" ||
|
|
575
|
+
code === "ATTACHMENT_READBACK_FAILED" ||
|
|
576
|
+
code === "JOB_RECOVERY_UNAVAILABLE")
|
|
577
|
+
return "status_first";
|
|
578
|
+
return "never";
|
|
579
|
+
}
|
|
222
580
|
//# sourceMappingURL=connector.js.map
|