codex-chatgpt-control 0.1.0-alpha.1
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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +54 -0
- package/contracts/v1/fixtures/backend-capabilities.json +54 -0
- package/contracts/v1/fixtures/backend-error-event-missing-stream-input.json +10 -0
- package/contracts/v1/fixtures/backend-error-missing-run-input.json +10 -0
- package/contracts/v1/fixtures/backend-runner-plan-request.json +12 -0
- package/contracts/v1/fixtures/backend-version.json +10 -0
- package/contracts/v1/fixtures/command-descriptors.json +803 -0
- package/contracts/v1/fixtures/describe-runner-run.json +31 -0
- package/contracts/v1/fixtures/doctor-bridge-upload.json +34 -0
- package/contracts/v1/fixtures/help-root.json +6 -0
- package/contracts/v1/fixtures/named-plan-two-turn.json +39 -0
- package/contracts/v1/fixtures/output-json-parse-success.json +115 -0
- package/contracts/v1/fixtures/primitive-bootstrap-blocker.json +43 -0
- package/contracts/v1/fixtures/report-redaction-default.json +16 -0
- package/contracts/v1/fixtures/reports-create-redacted.json +16 -0
- package/contracts/v1/fixtures/reports-summarize-redacted.json +26 -0
- package/contracts/v1/fixtures/responses-basic-success.json +27 -0
- package/contracts/v1/fixtures/responses-hidden-instructions-unsupported.json +22 -0
- package/contracts/v1/fixtures/responses-unknown-field-unsupported.json +22 -0
- package/contracts/v1/fixtures/responses-unsupported-previous-response-id.json +22 -0
- package/contracts/v1/fixtures/responses-unsupported-temperature.json +22 -0
- package/contracts/v1/fixtures/run-basic-success.json +36 -0
- package/contracts/v1/fixtures/run-browser-bridge-blocker.json +180 -0
- package/contracts/v1/fixtures/run-file-attach-success.json +63 -0
- package/contracts/v1/fixtures/run-report-redacted.json +52 -0
- package/contracts/v1/fixtures/run-selector-drift-blocker.json +60 -0
- package/contracts/v1/fixtures/run-timeout-partial.json +81 -0
- package/contracts/v1/fixtures/run-two-turn-success.json +83 -0
- package/contracts/v1/fixtures/run-upload-permission-blocker.json +56 -0
- package/contracts/v1/fixtures/runner-budget-blocker.json +106 -0
- package/contracts/v1/fixtures/runner-full-agent-config.json +50 -0
- package/contracts/v1/fixtures/runner-input-items-and-files-plan.json +53 -0
- package/contracts/v1/fixtures/runner-metadata-only-plan.json +31 -0
- package/contracts/v1/fixtures/runner-visible-prefix-plan.json +28 -0
- package/contracts/v1/fixtures/runner-visible-setup-plan.json +37 -0
- package/contracts/v1/fixtures/stream-basic.ndjson +3 -0
- package/contracts/v1/fixtures/stream-blocked.ndjson +2 -0
- package/contracts/v1/fixtures/stream-submitted-completed.ndjson +3 -0
- package/contracts/v1/fixtures/workflow-ask-success.json +67 -0
- package/contracts/v1/manifest.json +210 -0
- package/contracts/v1/parity-suite.json +635 -0
- package/contracts/v1/schemas/agent.schema.json +52 -0
- package/contracts/v1/schemas/backend-event.schema.json +74 -0
- package/contracts/v1/schemas/backend-request.schema.json +59 -0
- package/contracts/v1/schemas/backend-response.schema.json +42 -0
- package/contracts/v1/schemas/capabilities.schema.json +33 -0
- package/contracts/v1/schemas/command-descriptor.schema.json +31 -0
- package/contracts/v1/schemas/command-result.schema.json +99 -0
- package/contracts/v1/schemas/manifest.schema.json +69 -0
- package/contracts/v1/schemas/response.schema.json +51 -0
- package/contracts/v1/schemas/run-result.schema.json +138 -0
- package/contracts/v1/schemas/sequence-plan.schema.json +44 -0
- package/contracts/v1/schemas/stream-event.schema.json +25 -0
- package/dist/codex-chatgpt-control-backend.mjs +5284 -0
- package/dist/codex-chatgpt-control.bundle.mjs +6013 -0
- package/dist/src/backend/client.d.ts +129 -0
- package/dist/src/backend/client.js +415 -0
- package/dist/src/backend/protocol.d.ts +74 -0
- package/dist/src/backend/protocol.js +128 -0
- package/dist/src/backend/session.d.ts +11 -0
- package/dist/src/backend/session.js +223 -0
- package/dist/src/backend/stdio-server.d.ts +9 -0
- package/dist/src/backend/stdio-server.js +88 -0
- package/dist/src/browser/attach.d.ts +8 -0
- package/dist/src/browser/attach.js +456 -0
- package/dist/src/browser/clipboard.d.ts +2 -0
- package/dist/src/browser/clipboard.js +26 -0
- package/dist/src/browser/downloads.d.ts +7 -0
- package/dist/src/browser/downloads.js +29 -0
- package/dist/src/browser/page-state.d.ts +17 -0
- package/dist/src/browser/page-state.js +66 -0
- package/dist/src/client.d.ts +167 -0
- package/dist/src/client.js +666 -0
- package/dist/src/commands/confirmations.d.ts +9 -0
- package/dist/src/commands/confirmations.js +33 -0
- package/dist/src/commands/context.d.ts +2 -0
- package/dist/src/commands/context.js +32 -0
- package/dist/src/commands/doctor.d.ts +16 -0
- package/dist/src/commands/doctor.js +120 -0
- package/dist/src/commands/files.d.ts +4 -0
- package/dist/src/commands/files.js +314 -0
- package/dist/src/commands/helpers.d.ts +16 -0
- package/dist/src/commands/helpers.js +128 -0
- package/dist/src/commands/messages.d.ts +16 -0
- package/dist/src/commands/messages.js +538 -0
- package/dist/src/commands/modes.d.ts +9 -0
- package/dist/src/commands/modes.js +323 -0
- package/dist/src/commands/output.d.ts +5 -0
- package/dist/src/commands/output.js +31 -0
- package/dist/src/commands/registry.d.ts +17 -0
- package/dist/src/commands/registry.js +275 -0
- package/dist/src/commands/reports.d.ts +14 -0
- package/dist/src/commands/reports.js +47 -0
- package/dist/src/commands/response-actions.d.ts +2 -0
- package/dist/src/commands/response-actions.js +141 -0
- package/dist/src/commands/sequence.d.ts +9 -0
- package/dist/src/commands/sequence.js +228 -0
- package/dist/src/commands/session.d.ts +2 -0
- package/dist/src/commands/session.js +25 -0
- package/dist/src/commands/threads.d.ts +6 -0
- package/dist/src/commands/threads.js +300 -0
- package/dist/src/dom/fixtures.d.ts +1 -0
- package/dist/src/dom/fixtures.js +8 -0
- package/dist/src/dom/menus.d.ts +8 -0
- package/dist/src/dom/menus.js +40 -0
- package/dist/src/dom/message-format.d.ts +30 -0
- package/dist/src/dom/message-format.js +593 -0
- package/dist/src/dom/messages.d.ts +40 -0
- package/dist/src/dom/messages.js +127 -0
- package/dist/src/dom/selectors.d.ts +20 -0
- package/dist/src/dom/selectors.js +72 -0
- package/dist/src/dom/visible-text.d.ts +5 -0
- package/dist/src/dom/visible-text.js +27 -0
- package/dist/src/errors.d.ts +32 -0
- package/dist/src/errors.js +127 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.js +34 -0
- package/dist/src/logger.d.ts +15 -0
- package/dist/src/logger.js +25 -0
- package/dist/src/runner/agent.d.ts +2 -0
- package/dist/src/runner/agent.js +17 -0
- package/dist/src/runner/index.d.ts +7 -0
- package/dist/src/runner/index.js +7 -0
- package/dist/src/runner/interruptions.d.ts +3 -0
- package/dist/src/runner/interruptions.js +65 -0
- package/dist/src/runner/responses.d.ts +30 -0
- package/dist/src/runner/responses.js +171 -0
- package/dist/src/runner/result.d.ts +3 -0
- package/dist/src/runner/result.js +128 -0
- package/dist/src/runner/resume.d.ts +11 -0
- package/dist/src/runner/resume.js +26 -0
- package/dist/src/runner/stream.d.ts +13 -0
- package/dist/src/runner/stream.js +66 -0
- package/dist/src/runner/types.d.ts +264 -0
- package/dist/src/runner/types.js +1 -0
- package/dist/src/safety/blockers.d.ts +7 -0
- package/dist/src/safety/blockers.js +60 -0
- package/dist/src/safety/redaction.d.ts +2 -0
- package/dist/src/safety/redaction.js +18 -0
- package/dist/src/safety/report-redaction.d.ts +8 -0
- package/dist/src/safety/report-redaction.js +74 -0
- package/dist/src/safety/risk.d.ts +26 -0
- package/dist/src/safety/risk.js +28 -0
- package/dist/src/scripts/backend-server.d.ts +2 -0
- package/dist/src/scripts/backend-server.js +7 -0
- package/dist/src/scripts/check-parity-suite.d.ts +1 -0
- package/dist/src/scripts/check-parity-suite.js +10 -0
- package/dist/src/scripts/continue-thread.d.ts +27 -0
- package/dist/src/scripts/continue-thread.js +388 -0
- package/dist/src/scripts/live-smoke/harness.d.ts +11 -0
- package/dist/src/scripts/live-smoke/harness.js +151 -0
- package/dist/src/scripts/live-smoke/scenarios.d.ts +3 -0
- package/dist/src/scripts/live-smoke/scenarios.js +648 -0
- package/dist/src/scripts/live-smoke/types.d.ts +53 -0
- package/dist/src/scripts/live-smoke/types.js +1 -0
- package/dist/src/scripts/live-smoke-module.d.ts +3 -0
- package/dist/src/scripts/live-smoke-module.js +2 -0
- package/dist/src/scripts/live-smoke.d.ts +1 -0
- package/dist/src/scripts/live-smoke.js +54 -0
- package/dist/src/scripts/smoke-attach-file.d.ts +1 -0
- package/dist/src/scripts/smoke-attach-file.js +39 -0
- package/dist/src/scripts/smoke-hi.d.ts +1 -0
- package/dist/src/scripts/smoke-hi.js +25 -0
- package/dist/src/scripts/smoke-search-open-read.d.ts +1 -0
- package/dist/src/scripts/smoke-search-open-read.js +41 -0
- package/dist/src/testing/parity-suite.d.ts +12 -0
- package/dist/src/testing/parity-suite.js +213 -0
- package/dist/src/types.d.ts +495 -0
- package/dist/src/types.js +1 -0
- package/package.json +81 -0
- package/references/agents-runner.md +32 -0
- package/references/backend-protocol.md +238 -0
- package/references/python-parity.md +168 -0
- package/references/responses-adapter.md +28 -0
- package/references/safety.md +14 -0
- package/references/streaming.md +15 -0
- package/references/troubleshooting.md +91 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RunReportOptions } from "../commands/reports.js";
|
|
2
|
+
import type { BootstrapArgs, ResponseFormat } from "../types.js";
|
|
3
|
+
import type { ChatGPTAttachmentInput, ChatGPTInputItem, ChatGPTResponse, ChatGPTRunInput, ChatGPTRunResult, ChatGPTThreadSelector, ChatGPTVisibleModePreference, ChatGPTVisibleToolPreference, UnsupportedField } from "./types.js";
|
|
4
|
+
export type ChatGPTResponsesCreateArgs = {
|
|
5
|
+
input: string | ChatGPTInputItem[];
|
|
6
|
+
thread?: ChatGPTThreadSelector;
|
|
7
|
+
existingTab?: BootstrapArgs["existingTab"];
|
|
8
|
+
preferExistingTab?: boolean;
|
|
9
|
+
attachments?: ChatGPTAttachmentInput[];
|
|
10
|
+
mode?: ChatGPTVisibleModePreference;
|
|
11
|
+
tools?: ChatGPTVisibleToolPreference[];
|
|
12
|
+
text?: {
|
|
13
|
+
format?: ResponseFormat;
|
|
14
|
+
};
|
|
15
|
+
stream?: false;
|
|
16
|
+
report?: boolean | RunReportOptions;
|
|
17
|
+
instructions?: string;
|
|
18
|
+
instructionsMode?: "visible_prefix";
|
|
19
|
+
};
|
|
20
|
+
export type ResponsesValidationResult = {
|
|
21
|
+
ok: true;
|
|
22
|
+
unsupported: [];
|
|
23
|
+
} | {
|
|
24
|
+
ok: false;
|
|
25
|
+
unsupported: UnsupportedField[];
|
|
26
|
+
};
|
|
27
|
+
export declare function validateResponsesCreateArgs(args: Record<string, unknown>): ResponsesValidationResult;
|
|
28
|
+
export declare function responsesCreateArgsToRunInput(args: ChatGPTResponsesCreateArgs): ChatGPTRunInput;
|
|
29
|
+
export declare function responseFromRunResult<TOutput>(result: ChatGPTRunResult<TOutput>, now?: Date): ChatGPTResponse;
|
|
30
|
+
export declare function unsupportedResponse(unsupported: UnsupportedField[], now?: Date): ChatGPTResponse;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const acceptedTopLevelFields = new Set([
|
|
2
|
+
"input",
|
|
3
|
+
"thread",
|
|
4
|
+
"existingTab",
|
|
5
|
+
"preferExistingTab",
|
|
6
|
+
"attachments",
|
|
7
|
+
"mode",
|
|
8
|
+
"tools",
|
|
9
|
+
"text",
|
|
10
|
+
"stream",
|
|
11
|
+
"report",
|
|
12
|
+
"instructions",
|
|
13
|
+
"instructionsMode"
|
|
14
|
+
]);
|
|
15
|
+
const unsupportedAlternatives = {
|
|
16
|
+
model: "Use mode for visible ChatGPT UI mode preference. This does not select an API model.",
|
|
17
|
+
temperature: "No browser-control equivalent. ChatGPT web does not expose API temperature.",
|
|
18
|
+
top_p: "No browser-control equivalent. ChatGPT web does not expose API nucleus sampling.",
|
|
19
|
+
seed: "No browser-control equivalent. Visible ChatGPT web does not expose deterministic API seeds.",
|
|
20
|
+
logprobs: "No browser-control equivalent. Visible ChatGPT web does not expose token log probabilities.",
|
|
21
|
+
top_logprobs: "No browser-control equivalent. Visible ChatGPT web does not expose token log probabilities.",
|
|
22
|
+
previous_response_id: "Use thread: { type: \"conversationId\", conversationId } or a ChatGPT thread URL.",
|
|
23
|
+
store: "No browser-control equivalent. Use visible ChatGPT settings or temporary chat controls when implemented.",
|
|
24
|
+
service_tier: "No browser-control equivalent. Visible ChatGPT web does not expose API service tiers.",
|
|
25
|
+
max_output_tokens: "Use response.maxChars/read maxChars for capture limits. This does not control model generation.",
|
|
26
|
+
parallel_tool_calls: "No browser-control equivalent. Visible ChatGPT browser control selects visible tools sequentially.",
|
|
27
|
+
truncation: "No browser-control equivalent. Use prompt design and response capture limits instead."
|
|
28
|
+
};
|
|
29
|
+
const responseFormats = new Set([
|
|
30
|
+
"markdown",
|
|
31
|
+
"text",
|
|
32
|
+
"normalized_text",
|
|
33
|
+
"visible_text",
|
|
34
|
+
"html",
|
|
35
|
+
"blocks",
|
|
36
|
+
"all"
|
|
37
|
+
]);
|
|
38
|
+
export function validateResponsesCreateArgs(args) {
|
|
39
|
+
const unsupported = [];
|
|
40
|
+
for (const [path, alternative] of Object.entries(unsupportedAlternatives)) {
|
|
41
|
+
if (args[path] !== undefined) {
|
|
42
|
+
unsupported.push(apiOnlyField(path, alternative));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const path of Object.keys(args)) {
|
|
46
|
+
if (!acceptedTopLevelFields.has(path) && unsupportedAlternatives[path] === undefined) {
|
|
47
|
+
unsupported.push({
|
|
48
|
+
path,
|
|
49
|
+
reason: "This field is not part of the narrow ChatGPT browser-control Responses adapter.",
|
|
50
|
+
alternative: "Use chatgpt.runner.run(...) for lower-level browser-control options."
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (args.input === undefined) {
|
|
55
|
+
unsupported.push({
|
|
56
|
+
path: "input",
|
|
57
|
+
reason: "Responses adapter calls must include visible input text or input items.",
|
|
58
|
+
alternative: "Provide input: \"your visible prompt\"."
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (args.stream !== undefined && args.stream !== false) {
|
|
62
|
+
unsupported.push({
|
|
63
|
+
path: "stream",
|
|
64
|
+
reason: "This adapter stage supports only non-streaming calls.",
|
|
65
|
+
alternative: "Set stream: false, or use the runner milestone stream when enabled."
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (args.instructions !== undefined && args.instructionsMode !== "visible_prefix") {
|
|
69
|
+
unsupported.push({
|
|
70
|
+
path: "instructions",
|
|
71
|
+
reason: "Responses API instructions are hidden context, but ChatGPT browser control can only submit visible text.",
|
|
72
|
+
alternative: "Set instructionsMode: \"visible_prefix\" to send instructions visibly."
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (args.instructionsMode !== undefined && args.instructionsMode !== "visible_prefix") {
|
|
76
|
+
unsupported.push({
|
|
77
|
+
path: "instructionsMode",
|
|
78
|
+
reason: "Only explicit visible-prefix instructions are supported by this adapter.",
|
|
79
|
+
alternative: "Use instructionsMode: \"visible_prefix\" or omit instructionsMode."
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (isRecord(args.text)) {
|
|
83
|
+
const format = args.text.format;
|
|
84
|
+
if (format !== undefined && (typeof format !== "string" || !responseFormats.has(format))) {
|
|
85
|
+
unsupported.push({
|
|
86
|
+
path: "text.format",
|
|
87
|
+
reason: "The requested response text format is not supported by ChatGPT browser-control capture.",
|
|
88
|
+
alternative: "Use markdown, visible_text, normalized_text, html, blocks, or all."
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
for (const path of Object.keys(args.text)) {
|
|
92
|
+
if (path !== "format") {
|
|
93
|
+
unsupported.push({
|
|
94
|
+
path: `text.${path}`,
|
|
95
|
+
reason: "Only text.format is supported by the narrow Responses adapter.",
|
|
96
|
+
alternative: "Use chatgpt.runner.run(...) for lower-level browser-control options."
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return unsupported.length === 0 ? { ok: true, unsupported: [] } : { ok: false, unsupported };
|
|
102
|
+
}
|
|
103
|
+
export function responsesCreateArgsToRunInput(args) {
|
|
104
|
+
const runInput = {
|
|
105
|
+
input: args.input,
|
|
106
|
+
response: { format: args.text?.format ?? "markdown" }
|
|
107
|
+
};
|
|
108
|
+
if (args.thread !== undefined)
|
|
109
|
+
runInput.thread = args.thread;
|
|
110
|
+
if (args.existingTab !== undefined)
|
|
111
|
+
runInput.existingTab = args.existingTab;
|
|
112
|
+
if (args.preferExistingTab !== undefined)
|
|
113
|
+
runInput.preferExistingTab = args.preferExistingTab;
|
|
114
|
+
if (args.attachments !== undefined)
|
|
115
|
+
runInput.attachments = args.attachments;
|
|
116
|
+
if (args.mode !== undefined)
|
|
117
|
+
runInput.mode = args.mode;
|
|
118
|
+
if (args.tools !== undefined)
|
|
119
|
+
runInput.tools = args.tools;
|
|
120
|
+
if (args.report !== undefined)
|
|
121
|
+
runInput.report = args.report;
|
|
122
|
+
return runInput;
|
|
123
|
+
}
|
|
124
|
+
export function responseFromRunResult(result, now = new Date()) {
|
|
125
|
+
const browserControl = {
|
|
126
|
+
visibleUi: true,
|
|
127
|
+
resultStatus: result.status
|
|
128
|
+
};
|
|
129
|
+
if (result.data?.thread !== undefined)
|
|
130
|
+
browserControl.thread = result.data.thread;
|
|
131
|
+
const reportPath = result.data?.reportPath ?? result.reportPath;
|
|
132
|
+
if (reportPath !== undefined)
|
|
133
|
+
browserControl.reportPath = reportPath;
|
|
134
|
+
return {
|
|
135
|
+
id: responseId(now),
|
|
136
|
+
object: "chatgpt.browser.response",
|
|
137
|
+
created_at: Math.floor(now.getTime() / 1000),
|
|
138
|
+
status: result.status,
|
|
139
|
+
output_text: result.output_text,
|
|
140
|
+
output: result.output,
|
|
141
|
+
browser_control: browserControl
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export function unsupportedResponse(unsupported, now = new Date()) {
|
|
145
|
+
return {
|
|
146
|
+
id: responseId(now),
|
|
147
|
+
object: "chatgpt.browser.response",
|
|
148
|
+
created_at: Math.floor(now.getTime() / 1000),
|
|
149
|
+
status: "unsupported",
|
|
150
|
+
output_text: "",
|
|
151
|
+
output: [],
|
|
152
|
+
browser_control: {
|
|
153
|
+
visibleUi: true,
|
|
154
|
+
resultStatus: "unsupported",
|
|
155
|
+
unsupported
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function apiOnlyField(path, alternative) {
|
|
160
|
+
return {
|
|
161
|
+
path,
|
|
162
|
+
reason: "This is an OpenAI API field that visible ChatGPT browser control cannot honestly support.",
|
|
163
|
+
alternative
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function responseId(now) {
|
|
167
|
+
return `chatgpt-browser-${now.getTime().toString(36)}`;
|
|
168
|
+
}
|
|
169
|
+
function isRecord(value) {
|
|
170
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
171
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { interruptionFromCommandResult } from "./interruptions.js";
|
|
2
|
+
import { augmentCommandBlocker } from "./resume.js";
|
|
3
|
+
export function toRunResult(agent, result) {
|
|
4
|
+
const outputText = extractOutputText(result.data);
|
|
5
|
+
const finalOutput = parseFinalOutput(agent, outputText);
|
|
6
|
+
const interruption = interruptionFromCommandResult(result, failedCommand(result));
|
|
7
|
+
const interruptions = interruption === undefined ? [] : [interruption];
|
|
8
|
+
const output = runItemsFromResult(result, outputText);
|
|
9
|
+
const state = runStateFromResult(result, interruptions);
|
|
10
|
+
const data = { outputText };
|
|
11
|
+
if (finalOutput !== undefined)
|
|
12
|
+
data.finalOutput = finalOutput;
|
|
13
|
+
const thread = threadRefFromContext(result.context);
|
|
14
|
+
if (thread !== undefined)
|
|
15
|
+
data.thread = thread;
|
|
16
|
+
if (result.reportPath !== undefined)
|
|
17
|
+
data.reportPath = result.reportPath;
|
|
18
|
+
const mapped = {
|
|
19
|
+
...result,
|
|
20
|
+
data,
|
|
21
|
+
output_text: outputText,
|
|
22
|
+
output,
|
|
23
|
+
newItems: output,
|
|
24
|
+
interruptions,
|
|
25
|
+
state,
|
|
26
|
+
activeAgentName: agent.name,
|
|
27
|
+
lastAgentName: agent.name
|
|
28
|
+
};
|
|
29
|
+
if (finalOutput !== undefined)
|
|
30
|
+
mapped.finalOutput = finalOutput;
|
|
31
|
+
return mapped;
|
|
32
|
+
}
|
|
33
|
+
function extractOutputText(data) {
|
|
34
|
+
if (!isRecord(data))
|
|
35
|
+
return "";
|
|
36
|
+
if (typeof data.responseText === "string")
|
|
37
|
+
return data.responseText;
|
|
38
|
+
if (typeof data.text === "string")
|
|
39
|
+
return data.text;
|
|
40
|
+
for (const value of Object.values(data)) {
|
|
41
|
+
const nested = extractOutputText(value);
|
|
42
|
+
if (nested.length > 0)
|
|
43
|
+
return nested;
|
|
44
|
+
}
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
function parseFinalOutput(agent, outputText) {
|
|
48
|
+
if (outputText.length === 0)
|
|
49
|
+
return undefined;
|
|
50
|
+
if (agent.output?.parse === "json") {
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(outputText);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return agent.output.onParseError === "return_text" ? outputText : undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return outputText;
|
|
59
|
+
}
|
|
60
|
+
function runItemsFromResult(result, outputText) {
|
|
61
|
+
const items = messageItemsFromData(result.data);
|
|
62
|
+
if (!items.some(item => item.type === "message.completed") && outputText.length > 0) {
|
|
63
|
+
items.push({ type: "message.completed", role: "assistant", output_text: outputText, format: "markdown" });
|
|
64
|
+
}
|
|
65
|
+
if (result.blocker !== undefined) {
|
|
66
|
+
items.push({ type: "run.blocked", blocker: augmentCommandBlocker(result.blocker) });
|
|
67
|
+
}
|
|
68
|
+
return items;
|
|
69
|
+
}
|
|
70
|
+
function messageItemsFromData(data) {
|
|
71
|
+
if (!isRecord(data))
|
|
72
|
+
return [];
|
|
73
|
+
const items = [];
|
|
74
|
+
if (typeof data.prompt === "string" && data.prompt.length > 0) {
|
|
75
|
+
items.push({
|
|
76
|
+
type: "message.submitted",
|
|
77
|
+
role: "user",
|
|
78
|
+
preview: data.prompt.length > 160 ? `${data.prompt.slice(0, 159)}...` : data.prompt,
|
|
79
|
+
redacted: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (typeof data.responseText === "string" && data.responseText.length > 0) {
|
|
83
|
+
items.push({ type: "message.completed", role: "assistant", output_text: data.responseText, format: "markdown" });
|
|
84
|
+
}
|
|
85
|
+
if (items.length > 0)
|
|
86
|
+
return items;
|
|
87
|
+
for (const value of Object.values(data)) {
|
|
88
|
+
const nested = messageItemsFromData(value);
|
|
89
|
+
if (nested.length > 0)
|
|
90
|
+
return nested;
|
|
91
|
+
}
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
function runStateFromResult(result, interruptions) {
|
|
95
|
+
const resumable = interruptions.some(interruption => interruption.resume.supported);
|
|
96
|
+
const firstResume = interruptions.find(interruption => interruption.resume.supported)?.resume;
|
|
97
|
+
const state = {
|
|
98
|
+
id: firstResume?.supported === true && firstResume.stateId !== undefined ? firstResume.stateId : `run_${Date.now().toString(36)}`,
|
|
99
|
+
resumable
|
|
100
|
+
};
|
|
101
|
+
const thread = threadRefFromContext(result.context);
|
|
102
|
+
if (thread !== undefined)
|
|
103
|
+
state.thread = thread;
|
|
104
|
+
return state;
|
|
105
|
+
}
|
|
106
|
+
function threadRefFromContext(context) {
|
|
107
|
+
const thread = {};
|
|
108
|
+
if (context.url !== undefined)
|
|
109
|
+
thread.url = context.url;
|
|
110
|
+
if (context.conversationId !== undefined)
|
|
111
|
+
thread.conversationId = context.conversationId;
|
|
112
|
+
if (context.title !== undefined)
|
|
113
|
+
thread.title = context.title;
|
|
114
|
+
return Object.keys(thread).length === 0 ? undefined : thread;
|
|
115
|
+
}
|
|
116
|
+
function failedCommand(result) {
|
|
117
|
+
if (result.steps === undefined)
|
|
118
|
+
return undefined;
|
|
119
|
+
for (let index = result.steps.length - 1; index >= 0; index -= 1) {
|
|
120
|
+
const step = result.steps[index];
|
|
121
|
+
if (step?.ok === false)
|
|
122
|
+
return step.command;
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
function isRecord(value) {
|
|
127
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
128
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CommandResult } from "../types.js";
|
|
2
|
+
import type { ChatGPTCommandBlocker } from "./types.js";
|
|
3
|
+
export type ResumeDecision = {
|
|
4
|
+
supported: true;
|
|
5
|
+
stateId?: string;
|
|
6
|
+
} | {
|
|
7
|
+
supported: false;
|
|
8
|
+
reason: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function resumeDecisionForBlocker(blocker: CommandResult["blocker"] | undefined, stateId?: string): ResumeDecision;
|
|
11
|
+
export declare function augmentCommandBlocker(blocker: NonNullable<CommandResult["blocker"]>): ChatGPTCommandBlocker;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const NEVER_AUTO_RESUME = new Set([
|
|
2
|
+
"captcha",
|
|
3
|
+
"login_required",
|
|
4
|
+
"rate_limit",
|
|
5
|
+
"selector_drift",
|
|
6
|
+
"unknown"
|
|
7
|
+
]);
|
|
8
|
+
export function resumeDecisionForBlocker(blocker, stateId) {
|
|
9
|
+
if (blocker === undefined) {
|
|
10
|
+
return { supported: false, reason: "This result has no resumable browser-control blocker." };
|
|
11
|
+
}
|
|
12
|
+
if (NEVER_AUTO_RESUME.has(blocker.kind)) {
|
|
13
|
+
return { supported: false, reason: "This blocker is not safe to resume automatically." };
|
|
14
|
+
}
|
|
15
|
+
if (blocker.resumable === true) {
|
|
16
|
+
return stateId === undefined ? { supported: true } : { supported: true, stateId };
|
|
17
|
+
}
|
|
18
|
+
return { supported: false, reason: "The underlying browser-control command did not mark this blocker as resumable." };
|
|
19
|
+
}
|
|
20
|
+
export function augmentCommandBlocker(blocker) {
|
|
21
|
+
const augmented = { ...blocker };
|
|
22
|
+
if (augmented.resumable === undefined) {
|
|
23
|
+
augmented.resumable = blocker.kind === "confirmation" || blocker.kind === "permission";
|
|
24
|
+
}
|
|
25
|
+
return augmented;
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChatGPTRunItem, ChatGPTRunResult } from "./types.js";
|
|
2
|
+
export type ChatGPTRunStreamEventName = "thread_opened" | "mode_selected" | "tool_selected" | "file_attached" | "message_submitted" | "message_completed" | "file_downloaded" | "run_blocked";
|
|
3
|
+
export type ChatGPTRunStreamEvent = {
|
|
4
|
+
type: "run_item_stream_event";
|
|
5
|
+
name: ChatGPTRunStreamEventName;
|
|
6
|
+
item: ChatGPTRunItem;
|
|
7
|
+
};
|
|
8
|
+
export type ChatGPTRunStream<TOutput = string> = AsyncIterable<ChatGPTRunStreamEvent> & {
|
|
9
|
+
completed: Promise<ChatGPTRunResult<TOutput>>;
|
|
10
|
+
};
|
|
11
|
+
export declare function createMilestoneStream<TOutput = string>(run: (emit: (event: ChatGPTRunStreamEvent) => void) => Promise<ChatGPTRunResult<TOutput>>): ChatGPTRunStream<TOutput>;
|
|
12
|
+
export declare function streamFromRunResult<TOutput>(run: () => Promise<ChatGPTRunResult<TOutput>>): ChatGPTRunStream<TOutput>;
|
|
13
|
+
export declare function runItemStreamEvent(item: ChatGPTRunItem): ChatGPTRunStreamEvent;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export function createMilestoneStream(run) {
|
|
2
|
+
const queue = [];
|
|
3
|
+
let resolveNext;
|
|
4
|
+
let finished = false;
|
|
5
|
+
const completed = run(event => {
|
|
6
|
+
queue.push(event);
|
|
7
|
+
resolveNext?.();
|
|
8
|
+
resolveNext = undefined;
|
|
9
|
+
}).finally(() => {
|
|
10
|
+
finished = true;
|
|
11
|
+
resolveNext?.();
|
|
12
|
+
resolveNext = undefined;
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
completed,
|
|
16
|
+
async *[Symbol.asyncIterator]() {
|
|
17
|
+
while (!finished || queue.length > 0) {
|
|
18
|
+
const next = queue.shift();
|
|
19
|
+
if (next !== undefined) {
|
|
20
|
+
yield next;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
await new Promise(resolve => {
|
|
24
|
+
resolveNext = resolve;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function streamFromRunResult(run) {
|
|
31
|
+
return createMilestoneStream(async (emit) => {
|
|
32
|
+
const result = await run();
|
|
33
|
+
for (const item of result.newItems) {
|
|
34
|
+
emit(runItemStreamEvent(item));
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function runItemStreamEvent(item) {
|
|
40
|
+
return {
|
|
41
|
+
type: "run_item_stream_event",
|
|
42
|
+
name: runItemEventName(item),
|
|
43
|
+
item
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function runItemEventName(item) {
|
|
47
|
+
switch (item.type) {
|
|
48
|
+
case "thread.opened":
|
|
49
|
+
return "thread_opened";
|
|
50
|
+
case "mode.selected":
|
|
51
|
+
return "mode_selected";
|
|
52
|
+
case "tool.selected":
|
|
53
|
+
return "tool_selected";
|
|
54
|
+
case "file.attached":
|
|
55
|
+
return "file_attached";
|
|
56
|
+
case "message.submitted":
|
|
57
|
+
return "message_submitted";
|
|
58
|
+
case "message.completed":
|
|
59
|
+
return "message_completed";
|
|
60
|
+
case "file.downloaded":
|
|
61
|
+
return "file_downloaded";
|
|
62
|
+
case "approval.required":
|
|
63
|
+
case "run.blocked":
|
|
64
|
+
return "run_blocked";
|
|
65
|
+
}
|
|
66
|
+
}
|