@the-open-engine/zeroshot 6.16.0 → 6.18.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 +2 -2
- package/cli/index.js +9 -13
- package/lib/agent-cli-provider/adapters/claude.d.ts +2 -2
- package/lib/agent-cli-provider/adapters/claude.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/claude.js +30 -0
- package/lib/agent-cli-provider/adapters/claude.js.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.d.ts +2 -2
- package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +37 -0
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/agent-cli-provider/adapters/gemini.d.ts +2 -2
- package/lib/agent-cli-provider/adapters/gemini.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/gemini.js +115 -4
- package/lib/agent-cli-provider/adapters/gemini.js.map +1 -1
- package/lib/agent-cli-provider/adapters/omp.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/omp.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/omp.js +356 -0
- package/lib/agent-cli-provider/adapters/omp.js.map +1 -0
- package/lib/agent-cli-provider/adapters/opencode.d.ts +2 -2
- package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/opencode.js +108 -0
- package/lib/agent-cli-provider/adapters/opencode.js.map +1 -1
- package/lib/agent-cli-provider/contract-options.d.ts.map +1 -1
- package/lib/agent-cli-provider/contract-options.js +17 -0
- package/lib/agent-cli-provider/contract-options.js.map +1 -1
- package/lib/agent-cli-provider/index.d.ts +2 -2
- package/lib/agent-cli-provider/index.d.ts.map +1 -1
- package/lib/agent-cli-provider/index.js +2 -1
- package/lib/agent-cli-provider/index.js.map +1 -1
- package/lib/agent-cli-provider/provider-registry.d.ts +65 -7
- package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
- package/lib/agent-cli-provider/provider-registry.js +43 -0
- package/lib/agent-cli-provider/provider-registry.js.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.js +35 -4
- package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
- package/lib/agent-cli-provider/types.d.ts +49 -4
- package/lib/agent-cli-provider/types.d.ts.map +1 -1
- package/lib/agent-cli-provider/types.js.map +1 -1
- package/lib/cluster/errors.cjs +4 -1
- package/lib/cluster/errors.d.ts +2 -0
- package/lib/cluster/errors.mjs +2 -0
- package/lib/cluster/index.cjs +8 -1
- package/lib/cluster/index.d.ts +4 -1
- package/lib/cluster/index.mjs +4 -1
- package/lib/cluster/json-source.cjs +61 -0
- package/lib/cluster/json-source.d.ts +4 -0
- package/lib/cluster/json-source.mjs +55 -0
- package/lib/cluster/payload-value.cjs +76 -0
- package/lib/cluster/payload-value.d.ts +7 -0
- package/lib/cluster/payload-value.mjs +72 -0
- package/lib/cluster/validators.cjs +21 -0
- package/lib/cluster/validators.d.ts +4 -1
- package/lib/cluster/validators.mjs +19 -1
- package/lib/provider-names.js +5 -0
- package/package.json +2 -2
- package/src/agent/agent-task-executor.js +194 -410
- package/src/agent/output-extraction.js +39 -14
- package/src/agent/output-reformatter.js +154 -111
- package/src/agent-cli-provider/adapters/claude.ts +39 -2
- package/src/agent-cli-provider/adapters/codex.ts +56 -2
- package/src/agent-cli-provider/adapters/gemini.ts +102 -6
- package/src/agent-cli-provider/adapters/omp.ts +448 -0
- package/src/agent-cli-provider/adapters/opencode.ts +85 -2
- package/src/agent-cli-provider/contract-options.ts +21 -0
- package/src/agent-cli-provider/index.ts +5 -0
- package/src/agent-cli-provider/provider-registry.ts +62 -3
- package/src/agent-cli-provider/single-agent-runtime.ts +50 -4
- package/src/agent-cli-provider/types.ts +56 -2
- package/src/agent-wrapper.js +2 -2
- package/src/cluster/errors.ts +1 -0
- package/src/cluster/index.ts +4 -0
- package/src/cluster/json-source.ts +71 -0
- package/src/cluster/payload-value.ts +84 -0
- package/src/cluster/validators.ts +31 -2
- package/src/orchestrator.js +33 -13
- package/task-lib/attachable-watcher.js +1 -0
- package/task-lib/command-spec-cleanup.js +57 -11
- package/task-lib/commands/run.js +1 -0
- package/task-lib/provider-session-capture.js +8 -0
- package/task-lib/runner.js +9 -6
- package/task-lib/watcher.js +1 -0
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { contractError } from '../contract-errors';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as path from 'node:path';
|
|
2
6
|
import { UnsupportedProviderCapabilityError } from '../errors';
|
|
3
7
|
import { appendJsonSchemaPrompt } from '../schema';
|
|
4
8
|
import {
|
|
@@ -15,7 +19,7 @@ import {
|
|
|
15
19
|
type ErrorClassification,
|
|
16
20
|
type OpencodeCliFeatures,
|
|
17
21
|
type OutputEvent,
|
|
18
|
-
type
|
|
22
|
+
type StructuredOutputRecoveryAdapter,
|
|
19
23
|
type WarningMetadata,
|
|
20
24
|
} from '../types';
|
|
21
25
|
import {
|
|
@@ -49,7 +53,9 @@ function detectCliFeatures(
|
|
|
49
53
|
supportsCwd: unknown ? false : /--cwd\b/.test(help),
|
|
50
54
|
supportsAutoApprove: false,
|
|
51
55
|
supportsResume: !unknown && /--session\b/.test(help) && /--continue\b/.test(help),
|
|
56
|
+
supportsAgent: !unknown && /--agent\b/.test(help),
|
|
52
57
|
supportsWebSearch: isCliVersionAtLeast(versionText, '1.0.137'),
|
|
58
|
+
supportsRecoveryIsolation: isCliVersionAtLeast(versionText, '1.17.20'),
|
|
53
59
|
unknown,
|
|
54
60
|
};
|
|
55
61
|
}
|
|
@@ -162,6 +168,82 @@ function buildCommand(context: string, options: BuildProviderCommandOptions = {}
|
|
|
162
168
|
});
|
|
163
169
|
}
|
|
164
170
|
|
|
171
|
+
function buildStructuredOutputRecoveryCommand(
|
|
172
|
+
context: string,
|
|
173
|
+
options: BuildProviderCommandOptions = {}
|
|
174
|
+
): CommandSpec {
|
|
175
|
+
const features = optionFeatures(options);
|
|
176
|
+
if (features.supportsAgent !== true || features.supportsRecoveryIsolation !== true) {
|
|
177
|
+
throw new UnsupportedProviderCapabilityError(
|
|
178
|
+
'opencode',
|
|
179
|
+
'structuredOutputRecovery',
|
|
180
|
+
'OpenCode structured-output recovery requires CLI evidence for --agent and isolation controls available in OpenCode >= 1.17.20. Upgrade OpenCode before retrying.'
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const agentName = `zeroshot-output-reformatter-${randomUUID()}`;
|
|
184
|
+
const profile = {
|
|
185
|
+
description: 'Convert supplied text to schema-valid JSON without external actions',
|
|
186
|
+
mode: 'primary',
|
|
187
|
+
permission: { '*': 'deny' },
|
|
188
|
+
tools: { '*': false },
|
|
189
|
+
};
|
|
190
|
+
const recoveryOptions = { ...options };
|
|
191
|
+
delete recoveryOptions.resumeSessionId;
|
|
192
|
+
delete recoveryOptions.continueSession;
|
|
193
|
+
const isolatedConfigHome = fs.mkdtempSync(path.join(os.tmpdir(), 'zeroshot-opencode-config-'));
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const spec = buildCommand(context, {
|
|
197
|
+
...recoveryOptions,
|
|
198
|
+
agentName,
|
|
199
|
+
autoApprove: false,
|
|
200
|
+
webSearch: false,
|
|
201
|
+
});
|
|
202
|
+
const restrictedConfig = {
|
|
203
|
+
default_agent: agentName,
|
|
204
|
+
permission: { '*': 'deny' },
|
|
205
|
+
tools: { '*': false },
|
|
206
|
+
agent: { [agentName]: profile },
|
|
207
|
+
mode: { [agentName]: profile },
|
|
208
|
+
mcp: {},
|
|
209
|
+
instructions: [],
|
|
210
|
+
plugin: [],
|
|
211
|
+
command: {},
|
|
212
|
+
};
|
|
213
|
+
return {
|
|
214
|
+
...spec,
|
|
215
|
+
env: {
|
|
216
|
+
...spec.env,
|
|
217
|
+
ZEROSHOT_OPENCODE_AGENT: agentName,
|
|
218
|
+
XDG_CONFIG_HOME: isolatedConfigHome,
|
|
219
|
+
OPENCODE_DB: ':memory:',
|
|
220
|
+
OPENCODE_CONFIG: '',
|
|
221
|
+
OPENCODE_CONFIG_DIR: isolatedConfigHome,
|
|
222
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify(restrictedConfig),
|
|
223
|
+
OPENCODE_PERMISSION: JSON.stringify({ '*': 'deny' }),
|
|
224
|
+
OPENCODE_DISABLE_PROJECT_CONFIG: '1',
|
|
225
|
+
OPENCODE_PURE: '1',
|
|
226
|
+
OPENCODE_DISABLE_DEFAULT_PLUGINS: '1',
|
|
227
|
+
OPENCODE_DISABLE_EXTERNAL_SKILLS: '1',
|
|
228
|
+
OPENCODE_DISABLE_CLAUDE_CODE: '1',
|
|
229
|
+
},
|
|
230
|
+
cleanup: [...(spec.cleanup || []), isolatedConfigHome],
|
|
231
|
+
cleanupMetadata: [
|
|
232
|
+
...(spec.cleanupMetadata || []),
|
|
233
|
+
{
|
|
234
|
+
kind: 'temp-directory',
|
|
235
|
+
provider: 'opencode',
|
|
236
|
+
path: isolatedConfigHome,
|
|
237
|
+
reason: 'isolated-config',
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
};
|
|
241
|
+
} catch (error) {
|
|
242
|
+
fs.rmSync(isolatedConfigHome, { recursive: true, force: true });
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
165
247
|
function parseToolPart(part: Record<string, unknown>): OutputEvent | null {
|
|
166
248
|
const state = getRecord(part, 'state') ?? {};
|
|
167
249
|
const status = getString(state, 'status');
|
|
@@ -262,7 +344,7 @@ function classifyError(error: unknown): ErrorClassification {
|
|
|
262
344
|
return classifyBaseProviderError(error, [], []);
|
|
263
345
|
}
|
|
264
346
|
|
|
265
|
-
export const opencodeAdapter:
|
|
347
|
+
export const opencodeAdapter: StructuredOutputRecoveryAdapter = {
|
|
266
348
|
id: 'opencode',
|
|
267
349
|
displayName: 'Opencode',
|
|
268
350
|
binary: 'opencode',
|
|
@@ -281,6 +363,7 @@ export const opencodeAdapter: ProviderAdapter = {
|
|
|
281
363
|
defaultMinLevel: 'level1',
|
|
282
364
|
detectCliFeatures,
|
|
283
365
|
buildCommand,
|
|
366
|
+
buildStructuredOutputRecoveryCommand,
|
|
284
367
|
extractSessionId,
|
|
285
368
|
parseEvent,
|
|
286
369
|
createParserState: () => createParserState('opencode'),
|
|
@@ -24,6 +24,9 @@ const CLI_FEATURE_FIELDS = [
|
|
|
24
24
|
'supportsModel',
|
|
25
25
|
'supportsEffort',
|
|
26
26
|
'supportsSettings',
|
|
27
|
+
'supportsTools',
|
|
28
|
+
'supportsStrictMcpConfig',
|
|
29
|
+
'supportsNoSessionPersistence',
|
|
27
30
|
'supportsJson',
|
|
28
31
|
'supportsOutputSchema',
|
|
29
32
|
'supportsDir',
|
|
@@ -31,13 +34,26 @@ const CLI_FEATURE_FIELDS = [
|
|
|
31
34
|
'supportsConfigOverride',
|
|
32
35
|
'supportsSkipGitRepoCheck',
|
|
33
36
|
'supportsVariant',
|
|
37
|
+
'supportsSandbox',
|
|
38
|
+
'supportsEphemeral',
|
|
39
|
+
'supportsIgnoreUserConfig',
|
|
40
|
+
'supportsIgnoreRules',
|
|
41
|
+
'supportsStrictConfig',
|
|
34
42
|
'supportsJsonMode',
|
|
43
|
+
'supportsAdminPolicy',
|
|
35
44
|
'supportsNoSession',
|
|
45
|
+
'supportsAgent',
|
|
46
|
+
'supportsRecoveryIsolation',
|
|
36
47
|
'supportsNoExtensions',
|
|
37
48
|
'supportsNoSkills',
|
|
38
49
|
'supportsNoPromptTemplates',
|
|
39
50
|
'supportsNoContextFiles',
|
|
40
51
|
'supportsNoApprove',
|
|
52
|
+
'supportsModeJson',
|
|
53
|
+
'supportsPrint',
|
|
54
|
+
'supportsThinking',
|
|
55
|
+
'supportsNoRules',
|
|
56
|
+
'supportsNoTitle',
|
|
41
57
|
'supportsJsonOutput',
|
|
42
58
|
'supportsAllowAll',
|
|
43
59
|
'supportsNoAskUser',
|
|
@@ -224,6 +240,11 @@ function normalizeBuildOptions(value: Record<string, unknown>): BuildProviderCom
|
|
|
224
240
|
'strictSchema',
|
|
225
241
|
optionalBooleanValue(value.strictSchema, 'options.strictSchema')
|
|
226
242
|
);
|
|
243
|
+
addDefined(
|
|
244
|
+
result,
|
|
245
|
+
'structuredOutputRecovery',
|
|
246
|
+
optionalBooleanValue(value.structuredOutputRecovery, 'options.structuredOutputRecovery')
|
|
247
|
+
);
|
|
227
248
|
addDefined(
|
|
228
249
|
result,
|
|
229
250
|
'gateway',
|
|
@@ -53,6 +53,7 @@ export {
|
|
|
53
53
|
providerRegistry,
|
|
54
54
|
resolveProviderCommand,
|
|
55
55
|
supportsProviderCapability,
|
|
56
|
+
supportsProviderOutputReformatting,
|
|
56
57
|
} from './provider-registry';
|
|
57
58
|
|
|
58
59
|
export type {
|
|
@@ -78,6 +79,7 @@ export type {
|
|
|
78
79
|
ModelCatalogEntry,
|
|
79
80
|
ModelLevel,
|
|
80
81
|
ModelSpec,
|
|
82
|
+
OmpCliFeatures,
|
|
81
83
|
OpencodeCliFeatures,
|
|
82
84
|
OutputEvent,
|
|
83
85
|
OutputFormat,
|
|
@@ -92,6 +94,9 @@ export type {
|
|
|
92
94
|
ProviderCliFeatures,
|
|
93
95
|
ProviderId,
|
|
94
96
|
ProviderRegistryEntry,
|
|
97
|
+
StructuredOutputRecoveryAdapter,
|
|
98
|
+
StructuredOutputProviderRegistryEntry,
|
|
99
|
+
UnstructuredOutputProviderRegistryEntry,
|
|
95
100
|
RedactionMetadata,
|
|
96
101
|
ReasoningEffort,
|
|
97
102
|
ResolvedGatewayBuildOptions,
|
|
@@ -5,9 +5,10 @@ import { copilotAdapter } from './adapters/copilot';
|
|
|
5
5
|
import { gatewayAdapter, gatewaySettingsDefaults, validateGatewaySettings } from './adapters/gateway';
|
|
6
6
|
import { geminiAdapter } from './adapters/gemini';
|
|
7
7
|
import { opencodeAdapter } from './adapters/opencode';
|
|
8
|
+
import { ompAdapter } from './adapters/omp';
|
|
8
9
|
import { piAdapter } from './adapters/pi';
|
|
9
10
|
import { resolveClaudeCommand } from './claude-command';
|
|
10
|
-
import type { ModelLevel, ProviderAdapter } from './types';
|
|
11
|
+
import type { ModelLevel, ProviderAdapter, StructuredOutputRecoveryAdapter } from './types';
|
|
11
12
|
|
|
12
13
|
export type ProviderCapabilityState = boolean | 'experimental';
|
|
13
14
|
|
|
@@ -68,7 +69,7 @@ export interface ProviderDockerMetadata {
|
|
|
68
69
|
readonly install?: string;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
interface ProviderRegistryEntryBase {
|
|
72
73
|
readonly id: string;
|
|
73
74
|
readonly aliases: readonly string[];
|
|
74
75
|
readonly displayName: string;
|
|
@@ -83,7 +84,6 @@ export interface ProviderRegistryEntry {
|
|
|
83
84
|
readonly settingsDefaults?: Readonly<Record<string, unknown>>;
|
|
84
85
|
readonly settingsValidator?: (settings: Record<string, unknown>) => string | null;
|
|
85
86
|
readonly availabilityProbe?: 'command' | 'help-or-version';
|
|
86
|
-
readonly capabilities: ProviderCapabilities;
|
|
87
87
|
readonly docs: ProviderDocsMetadata;
|
|
88
88
|
readonly docker: ProviderDockerMetadata;
|
|
89
89
|
readonly defaultLevels: Readonly<{
|
|
@@ -91,9 +91,26 @@ export interface ProviderRegistryEntry {
|
|
|
91
91
|
readonly default: ModelLevel;
|
|
92
92
|
readonly max: ModelLevel;
|
|
93
93
|
}>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface StructuredOutputProviderRegistryEntry extends ProviderRegistryEntryBase {
|
|
97
|
+
readonly capabilities: Omit<ProviderCapabilities, 'jsonSchema'> & {
|
|
98
|
+
readonly jsonSchema: true | 'experimental';
|
|
99
|
+
};
|
|
100
|
+
readonly adapter: StructuredOutputRecoveryAdapter;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface UnstructuredOutputProviderRegistryEntry extends ProviderRegistryEntryBase {
|
|
104
|
+
readonly capabilities: Omit<ProviderCapabilities, 'jsonSchema'> & {
|
|
105
|
+
readonly jsonSchema: false;
|
|
106
|
+
};
|
|
94
107
|
readonly adapter: ProviderAdapter;
|
|
95
108
|
}
|
|
96
109
|
|
|
110
|
+
export type ProviderRegistryEntry =
|
|
111
|
+
| StructuredOutputProviderRegistryEntry
|
|
112
|
+
| UnstructuredOutputProviderRegistryEntry;
|
|
113
|
+
|
|
97
114
|
const STANDARD_CAPABILITIES: Readonly<
|
|
98
115
|
Pick<
|
|
99
116
|
ProviderCapabilities,
|
|
@@ -400,6 +417,44 @@ export const providerRegistry = [
|
|
|
400
417
|
},
|
|
401
418
|
adapter: piAdapter,
|
|
402
419
|
},
|
|
420
|
+
{
|
|
421
|
+
id: 'omp',
|
|
422
|
+
aliases: [],
|
|
423
|
+
displayName: 'OMP',
|
|
424
|
+
binary: 'omp',
|
|
425
|
+
command: { kind: 'fixed', command: 'omp', args: [] },
|
|
426
|
+
invoke: SPAWN_INVOKE,
|
|
427
|
+
installInstructions: 'npm install -g --ignore-scripts @oh-my-pi/pi-coding-agent',
|
|
428
|
+
authInstructions: 'omp\n/login',
|
|
429
|
+
credentialPaths: ['~/.omp'],
|
|
430
|
+
credentialEnvKeys: ompAdapter.credentialEnvKeys,
|
|
431
|
+
settingsFields: [],
|
|
432
|
+
availabilityProbe: 'help-or-version',
|
|
433
|
+
capabilities: {
|
|
434
|
+
...STANDARD_CAPABILITIES,
|
|
435
|
+
mcpServers: false,
|
|
436
|
+
jsonSchema: false,
|
|
437
|
+
reasoningEffort: true,
|
|
438
|
+
},
|
|
439
|
+
docs: {
|
|
440
|
+
label: 'OMP',
|
|
441
|
+
setupHeading: 'OMP Setup',
|
|
442
|
+
},
|
|
443
|
+
docker: {
|
|
444
|
+
mount: {
|
|
445
|
+
host: '~/.omp',
|
|
446
|
+
container: '$HOME/.omp',
|
|
447
|
+
readonly: true,
|
|
448
|
+
},
|
|
449
|
+
envPassthrough: [],
|
|
450
|
+
},
|
|
451
|
+
defaultLevels: {
|
|
452
|
+
min: ompAdapter.defaultMinLevel,
|
|
453
|
+
default: ompAdapter.defaultLevel,
|
|
454
|
+
max: ompAdapter.defaultMaxLevel,
|
|
455
|
+
},
|
|
456
|
+
adapter: ompAdapter,
|
|
457
|
+
},
|
|
403
458
|
{
|
|
404
459
|
id: 'kiro',
|
|
405
460
|
aliases: [],
|
|
@@ -551,3 +606,7 @@ export function supportsProviderCapability(
|
|
|
551
606
|
): boolean {
|
|
552
607
|
return getProviderRegistryEntry(name).capabilities[capability] === true;
|
|
553
608
|
}
|
|
609
|
+
|
|
610
|
+
export function supportsProviderOutputReformatting(name: string): boolean {
|
|
611
|
+
return getProviderRegistryEntry(name).capabilities.jsonSchema !== false;
|
|
612
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getProviderRegistryEntry,
|
|
7
7
|
resolveProviderCommand,
|
|
8
8
|
supportsProviderCapability,
|
|
9
|
+
supportsProviderOutputReformatting,
|
|
9
10
|
} from './provider-registry';
|
|
10
11
|
import type {
|
|
11
12
|
BuildProviderCommandOptions,
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
ModelLevel,
|
|
17
18
|
ModelSpec,
|
|
18
19
|
ProviderAdapter,
|
|
20
|
+
StructuredOutputRecoveryAdapter,
|
|
19
21
|
ProviderCliFeatures,
|
|
20
22
|
ProviderId,
|
|
21
23
|
ResolvedGatewayBuildOptions,
|
|
@@ -106,7 +108,9 @@ export function prepareSingleAgentProviderCommand(
|
|
|
106
108
|
adapter.id,
|
|
107
109
|
baseOptions.cwd ?? process.cwd()
|
|
108
110
|
);
|
|
109
|
-
const requestedWebSearch = baseOptions.
|
|
111
|
+
const requestedWebSearch = baseOptions.structuredOutputRecovery
|
|
112
|
+
? recoveryWebSearchOption(adapter)
|
|
113
|
+
: (baseOptions.webSearch ?? providerSettings.webSearch);
|
|
110
114
|
assertWebSearchDeclared(adapter.id, requestedWebSearch);
|
|
111
115
|
const cliFeatures = resolveRuntimeCliFeatures(
|
|
112
116
|
adapter.id,
|
|
@@ -125,10 +129,37 @@ export function prepareSingleAgentProviderCommand(
|
|
|
125
129
|
configuration: {
|
|
126
130
|
webSearch: webSearchAttestation(options),
|
|
127
131
|
},
|
|
128
|
-
commandSpec: adapter
|
|
132
|
+
commandSpec: buildRuntimeCommand(adapter, input.context, options),
|
|
129
133
|
};
|
|
130
134
|
}
|
|
131
135
|
|
|
136
|
+
function buildRuntimeCommand(
|
|
137
|
+
adapter: ProviderAdapter,
|
|
138
|
+
context: string,
|
|
139
|
+
options: BuildProviderCommandOptions
|
|
140
|
+
): CommandSpec {
|
|
141
|
+
if (options.structuredOutputRecovery !== true) {
|
|
142
|
+
return adapter.buildCommand(context, options);
|
|
143
|
+
}
|
|
144
|
+
if (!supportsProviderOutputReformatting(adapter.id)) {
|
|
145
|
+
throw new UnsupportedProviderCapabilityError(
|
|
146
|
+
adapter.id,
|
|
147
|
+
'structuredOutputRecovery',
|
|
148
|
+
`Provider ${adapter.id} does not advertise structured-output recovery.`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const recoveryAdapter = adapter as ProviderAdapter &
|
|
152
|
+
Partial<StructuredOutputRecoveryAdapter>;
|
|
153
|
+
if (typeof recoveryAdapter.buildStructuredOutputRecoveryCommand !== 'function') {
|
|
154
|
+
throw new UnsupportedProviderCapabilityError(
|
|
155
|
+
adapter.id,
|
|
156
|
+
'structuredOutputRecovery',
|
|
157
|
+
`Provider ${adapter.id} advertises structured output without a recovery adapter. Upgrade Zeroshot before retrying.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return recoveryAdapter.buildStructuredOutputRecoveryCommand(context, options);
|
|
161
|
+
}
|
|
162
|
+
|
|
132
163
|
export function detectRuntimeProviderCliFeatures(provider: string): ProviderCliFeatures {
|
|
133
164
|
return probeRuntimeProviderCli(provider).capabilities;
|
|
134
165
|
}
|
|
@@ -262,15 +293,26 @@ function buildRuntimeOptions(
|
|
|
262
293
|
providerSettings,
|
|
263
294
|
modelSpec
|
|
264
295
|
);
|
|
265
|
-
const webSearch = baseOptions.
|
|
296
|
+
const webSearch = baseOptions.structuredOutputRecovery
|
|
297
|
+
? recoveryWebSearchOption(adapter)
|
|
298
|
+
: (baseOptions.webSearch ?? providerSettings.webSearch);
|
|
266
299
|
assertWebSearchDeclared(adapter.id, webSearch);
|
|
267
|
-
const
|
|
300
|
+
const baseResolved = {
|
|
268
301
|
...baseOptions,
|
|
269
302
|
modelSpec,
|
|
270
303
|
...(gateway === undefined ? {} : { gateway }),
|
|
271
304
|
...(webSearch === undefined ? {} : { webSearch }),
|
|
272
305
|
cliFeatures: runtime.cliFeatures,
|
|
273
306
|
};
|
|
307
|
+
const resolved = { ...baseResolved };
|
|
308
|
+
if (baseOptions.structuredOutputRecovery) {
|
|
309
|
+
delete resolved.resumeSessionId;
|
|
310
|
+
delete resolved.continueSession;
|
|
311
|
+
delete resolved.mcpConfig;
|
|
312
|
+
resolved.autoApprove = false;
|
|
313
|
+
if (recoveryWebSearchOption(adapter) === undefined) delete resolved.webSearch;
|
|
314
|
+
else resolved.webSearch = false;
|
|
315
|
+
}
|
|
274
316
|
if (baseOptions.jsonSchema && !supportsProviderCapability(adapter.id, 'jsonSchema')) {
|
|
275
317
|
if (!shouldIncludeAuthEnv(baseOptions, runtime.authEnv)) {
|
|
276
318
|
return { ...resolved, strictSchema: false };
|
|
@@ -281,6 +323,10 @@ function buildRuntimeOptions(
|
|
|
281
323
|
return { ...resolved, authEnv: runtime.authEnv };
|
|
282
324
|
}
|
|
283
325
|
|
|
326
|
+
function recoveryWebSearchOption(adapter: ProviderAdapter): false | undefined {
|
|
327
|
+
return getProviderRegistryEntry(adapter.id).capabilities.webSearch === false ? undefined : false;
|
|
328
|
+
}
|
|
329
|
+
|
|
284
330
|
function resolveRuntimeGatewayOptions(
|
|
285
331
|
provider: ProviderId,
|
|
286
332
|
baseOptions: BuildProviderCommandOptions,
|
|
@@ -9,6 +9,8 @@ import type {
|
|
|
9
9
|
ProviderDocsMetadata,
|
|
10
10
|
ProviderInvokeSpec,
|
|
11
11
|
ProviderRegistryEntry,
|
|
12
|
+
StructuredOutputProviderRegistryEntry,
|
|
13
|
+
UnstructuredOutputProviderRegistryEntry,
|
|
12
14
|
} from './provider-registry';
|
|
13
15
|
|
|
14
16
|
export type ProviderId = (typeof providerIds)[number];
|
|
@@ -27,8 +29,9 @@ export type {
|
|
|
27
29
|
ProviderDocsMetadata,
|
|
28
30
|
ProviderInvokeSpec,
|
|
29
31
|
ProviderRegistryEntry,
|
|
32
|
+
StructuredOutputProviderRegistryEntry,
|
|
33
|
+
UnstructuredOutputProviderRegistryEntry,
|
|
30
34
|
};
|
|
31
|
-
|
|
32
35
|
export interface AgentCliProviderHelperMetadata {
|
|
33
36
|
readonly packageName: '@the-open-engine/zeroshot';
|
|
34
37
|
readonly buildOutputDir: 'lib/agent-cli-provider';
|
|
@@ -105,6 +108,9 @@ export interface ClaudeCliFeatures extends BaseCliFeatures {
|
|
|
105
108
|
readonly supportsSettings: boolean;
|
|
106
109
|
readonly supportsMcpConfig: boolean;
|
|
107
110
|
readonly supportsResume: boolean;
|
|
111
|
+
readonly supportsTools: boolean;
|
|
112
|
+
readonly supportsStrictMcpConfig: boolean;
|
|
113
|
+
readonly supportsNoSessionPersistence: boolean;
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
export interface CodexCliFeatures extends BaseCliFeatures {
|
|
@@ -118,6 +124,11 @@ export interface CodexCliFeatures extends BaseCliFeatures {
|
|
|
118
124
|
readonly supportsSkipGitRepoCheck: boolean;
|
|
119
125
|
readonly supportsResume: boolean;
|
|
120
126
|
readonly supportsWebSearch: boolean;
|
|
127
|
+
readonly supportsSandbox: boolean;
|
|
128
|
+
readonly supportsEphemeral: boolean;
|
|
129
|
+
readonly supportsIgnoreUserConfig: boolean;
|
|
130
|
+
readonly supportsIgnoreRules: boolean;
|
|
131
|
+
readonly supportsStrictConfig: boolean;
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
export interface GeminiCliFeatures extends BaseCliFeatures {
|
|
@@ -126,6 +137,7 @@ export interface GeminiCliFeatures extends BaseCliFeatures {
|
|
|
126
137
|
readonly supportsAutoApprove: boolean;
|
|
127
138
|
readonly supportsCwd: boolean;
|
|
128
139
|
readonly supportsModel: boolean;
|
|
140
|
+
readonly supportsAdminPolicy: boolean;
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
export interface OpencodeCliFeatures extends BaseCliFeatures {
|
|
@@ -138,6 +150,8 @@ export interface OpencodeCliFeatures extends BaseCliFeatures {
|
|
|
138
150
|
readonly supportsAutoApprove: false;
|
|
139
151
|
readonly supportsResume: boolean;
|
|
140
152
|
readonly supportsWebSearch: boolean;
|
|
153
|
+
readonly supportsAgent: boolean;
|
|
154
|
+
readonly supportsRecoveryIsolation: boolean;
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
export interface PiCliFeatures extends BaseCliFeatures {
|
|
@@ -152,6 +166,20 @@ export interface PiCliFeatures extends BaseCliFeatures {
|
|
|
152
166
|
readonly supportsNoApprove: boolean;
|
|
153
167
|
}
|
|
154
168
|
|
|
169
|
+
export interface OmpCliFeatures extends BaseCliFeatures {
|
|
170
|
+
readonly provider: 'omp';
|
|
171
|
+
readonly supportsModeJson: boolean;
|
|
172
|
+
readonly supportsPrint: boolean;
|
|
173
|
+
readonly supportsCwd: boolean;
|
|
174
|
+
readonly supportsAutoApprove: boolean;
|
|
175
|
+
readonly supportsModel: boolean;
|
|
176
|
+
readonly supportsThinking: boolean;
|
|
177
|
+
readonly supportsNoExtensions: boolean;
|
|
178
|
+
readonly supportsNoSkills: boolean;
|
|
179
|
+
readonly supportsNoRules: boolean;
|
|
180
|
+
readonly supportsNoTitle: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
155
183
|
export interface CopilotCliFeatures extends BaseCliFeatures {
|
|
156
184
|
readonly provider: 'copilot';
|
|
157
185
|
readonly supportsJsonOutput: boolean;
|
|
@@ -188,6 +216,7 @@ export type ProviderCliFeatures =
|
|
|
188
216
|
| GeminiCliFeatures
|
|
189
217
|
| OpencodeCliFeatures
|
|
190
218
|
| PiCliFeatures
|
|
219
|
+
| OmpCliFeatures
|
|
191
220
|
| CopilotCliFeatures
|
|
192
221
|
| GatewayCliFeatures
|
|
193
222
|
| AcpCliFeatures;
|
|
@@ -200,6 +229,9 @@ export interface CliFeatureOverrides {
|
|
|
200
229
|
readonly supportsIncludePartials?: boolean;
|
|
201
230
|
readonly supportsVerbose?: boolean;
|
|
202
231
|
readonly supportsModel?: boolean;
|
|
232
|
+
readonly supportsTools?: boolean;
|
|
233
|
+
readonly supportsStrictMcpConfig?: boolean;
|
|
234
|
+
readonly supportsNoSessionPersistence?: boolean;
|
|
203
235
|
readonly supportsEffort?: boolean;
|
|
204
236
|
readonly supportsSettings?: boolean;
|
|
205
237
|
readonly supportsJson?: boolean;
|
|
@@ -208,14 +240,27 @@ export interface CliFeatureOverrides {
|
|
|
208
240
|
readonly supportsCwd?: boolean;
|
|
209
241
|
readonly supportsConfigOverride?: boolean;
|
|
210
242
|
readonly supportsSkipGitRepoCheck?: boolean;
|
|
243
|
+
readonly supportsSandbox?: boolean;
|
|
244
|
+
readonly supportsEphemeral?: boolean;
|
|
245
|
+
readonly supportsIgnoreUserConfig?: boolean;
|
|
246
|
+
readonly supportsIgnoreRules?: boolean;
|
|
247
|
+
readonly supportsStrictConfig?: boolean;
|
|
211
248
|
readonly supportsVariant?: boolean;
|
|
249
|
+
readonly supportsAdminPolicy?: boolean;
|
|
212
250
|
readonly supportsJsonMode?: boolean;
|
|
213
251
|
readonly supportsNoSession?: boolean;
|
|
214
252
|
readonly supportsNoExtensions?: boolean;
|
|
215
253
|
readonly supportsNoSkills?: boolean;
|
|
216
254
|
readonly supportsNoPromptTemplates?: boolean;
|
|
255
|
+
readonly supportsAgent?: boolean;
|
|
256
|
+
readonly supportsRecoveryIsolation?: boolean;
|
|
217
257
|
readonly supportsNoContextFiles?: boolean;
|
|
218
258
|
readonly supportsNoApprove?: boolean;
|
|
259
|
+
readonly supportsModeJson?: boolean;
|
|
260
|
+
readonly supportsPrint?: boolean;
|
|
261
|
+
readonly supportsThinking?: boolean;
|
|
262
|
+
readonly supportsNoRules?: boolean;
|
|
263
|
+
readonly supportsNoTitle?: boolean;
|
|
219
264
|
readonly supportsJsonOutput?: boolean;
|
|
220
265
|
readonly supportsAllowAll?: boolean;
|
|
221
266
|
readonly supportsNoAskUser?: boolean;
|
|
@@ -242,7 +287,7 @@ export interface CleanupMetadata {
|
|
|
242
287
|
readonly kind: 'temp-file' | 'temp-directory';
|
|
243
288
|
readonly provider: ProviderId;
|
|
244
289
|
readonly path: string;
|
|
245
|
-
readonly reason: 'output-schema' | 'settings-overlay';
|
|
290
|
+
readonly reason: 'output-schema' | 'settings-overlay' | 'admin-policy' | 'isolated-config';
|
|
246
291
|
}
|
|
247
292
|
|
|
248
293
|
export interface WarningMetadata {
|
|
@@ -292,6 +337,8 @@ export interface BuildProviderCommandOptions {
|
|
|
292
337
|
// one variadic `--mcp-config` followed by file paths; adapters such as Copilot accept repeated
|
|
293
338
|
// flags with inline JSON so configs survive container path translation.
|
|
294
339
|
readonly mcpConfig?: readonly string[];
|
|
340
|
+
/** Internal profile for provider-neutral structured-output correction turns. */
|
|
341
|
+
readonly structuredOutputRecovery?: boolean;
|
|
295
342
|
}
|
|
296
343
|
|
|
297
344
|
export interface TextEvent {
|
|
@@ -395,6 +442,13 @@ export interface ProviderAdapter {
|
|
|
395
442
|
classifyError(error: unknown): ErrorClassification;
|
|
396
443
|
}
|
|
397
444
|
|
|
445
|
+
export interface StructuredOutputRecoveryAdapter extends ProviderAdapter {
|
|
446
|
+
buildStructuredOutputRecoveryCommand(
|
|
447
|
+
context: string,
|
|
448
|
+
options?: BuildProviderCommandOptions
|
|
449
|
+
): CommandSpec;
|
|
450
|
+
}
|
|
451
|
+
|
|
398
452
|
export class InvalidProviderModelError extends Error {
|
|
399
453
|
readonly permanent = true;
|
|
400
454
|
|
package/src/agent-wrapper.js
CHANGED
|
@@ -586,8 +586,8 @@ class AgentWrapper {
|
|
|
586
586
|
* Falls back to reformatting if extraction fails
|
|
587
587
|
* @private
|
|
588
588
|
*/
|
|
589
|
-
_parseResultOutput(output) {
|
|
590
|
-
return parseResultOutput(this, output);
|
|
589
|
+
_parseResultOutput(output, options = {}) {
|
|
590
|
+
return parseResultOutput(this, output, options);
|
|
591
591
|
}
|
|
592
592
|
|
|
593
593
|
/**
|
package/src/cluster/errors.ts
CHANGED
|
@@ -13,6 +13,7 @@ export class ClusterInternalError extends ClusterError {}
|
|
|
13
13
|
export class ClusterProtocolError extends ClusterError {}
|
|
14
14
|
export class ClusterTransportError extends ClusterError {}
|
|
15
15
|
export class ClusterTimeoutError extends ClusterError {}
|
|
16
|
+
export class ClusterRequestError extends ClusterError {}
|
|
16
17
|
|
|
17
18
|
export function requestAbortError(method: string): DOMException {
|
|
18
19
|
return new DOMException(
|
package/src/cluster/index.ts
CHANGED
|
@@ -5,11 +5,15 @@ export {
|
|
|
5
5
|
ClusterError,
|
|
6
6
|
ClusterInternalError,
|
|
7
7
|
ClusterProtocolError,
|
|
8
|
+
ClusterRequestError,
|
|
8
9
|
ClusterRpcError,
|
|
9
10
|
ClusterStateError,
|
|
10
11
|
ClusterTimeoutError,
|
|
11
12
|
ClusterTransportError,
|
|
12
13
|
} from './errors.js';
|
|
14
|
+
export { assertGraphProfile, assertGraphProfileSupported, assertGraphSpec } from './validators.js';
|
|
15
|
+
export * from './payload-value.js';
|
|
16
|
+
export * from './json-source.js';
|
|
13
17
|
export { CONNECTION_TRANSITIONS, PROTOCOL_DIAGNOSTIC_CAPACITY, Connection } from './connection.js';
|
|
14
18
|
export type {
|
|
15
19
|
CallOptions,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ClusterRequestError } from './errors.js';
|
|
2
|
+
import { MAX_FRAME_BYTES } from './generated/protocol.js';
|
|
3
|
+
|
|
4
|
+
export const MAX_REQUEST_BYTES = MAX_FRAME_BYTES;
|
|
5
|
+
|
|
6
|
+
export function decodeBoundedJson(bytes: Uint8Array): unknown {
|
|
7
|
+
if (bytes.length > MAX_REQUEST_BYTES) {
|
|
8
|
+
throw new ClusterRequestError(
|
|
9
|
+
`request payload of ${bytes.length} bytes exceeds the ${MAX_REQUEST_BYTES} byte limit`,
|
|
10
|
+
'OVERSIZED_JSON',
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
let text: string;
|
|
14
|
+
try {
|
|
15
|
+
text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
16
|
+
} catch {
|
|
17
|
+
throw new ClusterRequestError('request payload is not valid UTF-8', 'INVALID_UTF8');
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(text) as unknown;
|
|
21
|
+
} catch {
|
|
22
|
+
throw new ClusterRequestError('request payload is not valid JSON', 'MALFORMED_JSON');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Callers resolve `--graph`/`--input` specifiers ('-' vs. a file path) to a byte
|
|
27
|
+
// source themselves; opening the filesystem stream stays outside src/cluster so this
|
|
28
|
+
// module keeps no host-specific dependency (not even the `NodeJS` ambient namespace,
|
|
29
|
+
// which isn't resolvable from a consumer's declaration-only install) beyond the
|
|
30
|
+
// standard async-iterable protocol every Node Readable already implements — mirrors
|
|
31
|
+
// how WebSocketLike is injected instead of importing 'ws' directly, see socket.ts.
|
|
32
|
+
export async function readBoundedSource(
|
|
33
|
+
source: AsyncIterable<Uint8Array | string>,
|
|
34
|
+
): Promise<Uint8Array> {
|
|
35
|
+
const encoder = new TextEncoder();
|
|
36
|
+
const chunks: Uint8Array[] = [];
|
|
37
|
+
let total = 0;
|
|
38
|
+
for await (const chunk of source) {
|
|
39
|
+
const bytes = typeof chunk === 'string' ? encoder.encode(chunk) : new Uint8Array(chunk);
|
|
40
|
+
total += bytes.length;
|
|
41
|
+
if (total > MAX_REQUEST_BYTES) {
|
|
42
|
+
throw new ClusterRequestError(
|
|
43
|
+
`request payload exceeds the ${MAX_REQUEST_BYTES} byte limit`,
|
|
44
|
+
'OVERSIZED_JSON',
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
chunks.push(bytes);
|
|
48
|
+
}
|
|
49
|
+
const assembled = new Uint8Array(total);
|
|
50
|
+
let offset = 0;
|
|
51
|
+
for (const bytes of chunks) {
|
|
52
|
+
assembled.set(bytes, offset);
|
|
53
|
+
offset += bytes.length;
|
|
54
|
+
}
|
|
55
|
+
return assembled;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function assertDistinctRequestSources(
|
|
59
|
+
graph: string,
|
|
60
|
+
input: string | undefined,
|
|
61
|
+
): asserts input is string {
|
|
62
|
+
if (input === undefined) {
|
|
63
|
+
throw new ClusterRequestError('--input is required for every hosted run', 'MISSING_INPUT');
|
|
64
|
+
}
|
|
65
|
+
if (graph === '-' && input === '-') {
|
|
66
|
+
throw new ClusterRequestError(
|
|
67
|
+
'graph and input cannot both read from stdin',
|
|
68
|
+
'AMBIGUOUS_STDIN_SOURCE',
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|