@martinloop/mcp 0.5.3 → 0.5.6
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 +175 -175
- package/dist/arcade/capabilities.d.ts +36 -0
- package/dist/arcade/capabilities.js +37 -0
- package/dist/arcade/resource.d.ts +31 -0
- package/dist/arcade/resource.js +52 -0
- package/dist/arcade/status.d.ts +23 -0
- package/dist/arcade/status.js +25 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +3 -3
- package/dist/resources.js +147 -147
- package/dist/server-validation.js +2 -0
- package/dist/server.js +79 -35
- package/dist/tools/run-loop.d.ts +2 -2
- package/dist/tools/run-loop.js +26 -6
- package/dist/tools/tool-response.d.ts +9 -1
- package/dist/tools/tool-response.js +7 -5
- package/dist/tools/tool-support.js +62 -271
- package/dist/vendor/adapters/claude-cli.d.ts +9 -0
- package/dist/vendor/adapters/claude-cli.js +21 -3
- package/dist/vendor/adapters/cli-bridge.js +7 -1
- package/dist/vendor/adapters/codex-capabilities.d.ts +12 -3
- package/dist/vendor/adapters/codex-capabilities.js +46 -18
- package/dist/vendor/adapters/codex-cli.d.ts +2 -1
- package/dist/vendor/adapters/codex-cli.js +12 -2
- package/dist/vendor/adapters/codex-host.d.ts +4 -1
- package/dist/vendor/adapters/codex-host.js +34 -16
- package/dist/vendor/adapters/codex-launcher.d.ts +1 -1
- package/dist/vendor/adapters/codex-launcher.js +1 -1
- package/dist/vendor/adapters/index.d.ts +3 -1
- package/dist/vendor/adapters/index.js +2 -0
- package/dist/vendor/adapters/openai-compatible.js +12 -9
- package/dist/vendor/adapters/stub-agent-cli.d.ts +9 -0
- package/dist/vendor/adapters/stub-agent-cli.js +43 -0
- package/dist/vendor/adapters/stub-direct-provider.d.ts +8 -0
- package/dist/vendor/adapters/stub-direct-provider.js +16 -0
- package/dist/vendor/contracts/agent-execution.d.ts +9 -0
- package/dist/vendor/contracts/agent-execution.js +14 -0
- package/dist/vendor/contracts/index.d.ts +9 -0
- package/dist/vendor/contracts/index.js +1 -0
- package/dist/vendor/core/grounding.js +42 -7
- package/dist/vendor/core/index.d.ts +5 -2
- package/dist/vendor/core/index.js +20 -66
- package/dist/vendor/core/policy.d.ts +1 -0
- package/dist/vendor/core/policy.js +8 -0
- package/dist/vendor/core/rollback.d.ts +3 -0
- package/dist/vendor/core/rollback.js +33 -20
- package/dist/vendor/core/verified-handoff.js +25 -6
- package/dist/vendor/presentation/governed-plan.d.ts +33 -0
- package/dist/vendor/presentation/governed-plan.js +146 -0
- package/dist/vendor/presentation/index.d.ts +7 -0
- package/dist/vendor/presentation/index.js +7 -0
- package/dist/vendor/presentation/motion.d.ts +12 -0
- package/dist/vendor/presentation/motion.js +123 -0
- package/dist/vendor/presentation/status.d.ts +8 -0
- package/dist/vendor/presentation/status.js +11 -0
- package/dist/vendor/presentation/table.d.ts +11 -0
- package/dist/vendor/presentation/table.js +47 -0
- package/dist/vendor/presentation/text.d.ts +6 -0
- package/dist/vendor/presentation/text.js +30 -0
- package/dist/vendor/presentation/theme.d.ts +31 -0
- package/dist/vendor/presentation/theme.js +82 -0
- package/dist/vendor/presentation/verified-handoff.d.ts +15 -0
- package/dist/vendor/presentation/verified-handoff.js +148 -0
- package/package.json +81 -80
- package/server.json +21 -21
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* MCP tools and integration tests use the same factories.
|
|
13
13
|
*/
|
|
14
14
|
import type { MartinAdapter, MartinAdapterRequest } from "../core/index.js";
|
|
15
|
+
import { type AgentExecutionIntent } from "../core/index.js";
|
|
15
16
|
import { type SpawnLike } from "./cli-bridge.js";
|
|
16
17
|
/**
|
|
17
18
|
* Given a prompt string, returns the full argv array to pass to spawn().
|
|
@@ -33,6 +34,8 @@ export interface AgentCliAdapterOptions {
|
|
|
33
34
|
workingDirectory?: string;
|
|
34
35
|
/** Timeout for the agent subprocess in ms. Defaults to 300_000 (5 min). */
|
|
35
36
|
timeoutMs?: number;
|
|
37
|
+
agentExecutionIntent?: AgentExecutionIntent;
|
|
38
|
+
providerExecutionTimeoutMs?: number;
|
|
36
39
|
/** Timeout per verification command in ms. Defaults to 120_000 (2 min). */
|
|
37
40
|
verifyTimeoutMs?: number;
|
|
38
41
|
/** Human-readable label shown in loop records. */
|
|
@@ -60,6 +63,8 @@ export interface AgentCliAdapterOptions {
|
|
|
60
63
|
export interface ClaudeCliAdapterOptions {
|
|
61
64
|
workingDirectory?: string;
|
|
62
65
|
timeoutMs?: number;
|
|
66
|
+
agentExecutionIntent?: AgentExecutionIntent;
|
|
67
|
+
providerExecutionTimeoutMs?: number;
|
|
63
68
|
verifyTimeoutMs?: number;
|
|
64
69
|
label?: string;
|
|
65
70
|
/** Override the model passed via --model flag. */
|
|
@@ -73,6 +78,8 @@ export interface CodexCliAdapterOptions {
|
|
|
73
78
|
command?: string;
|
|
74
79
|
workingDirectory?: string;
|
|
75
80
|
timeoutMs?: number;
|
|
81
|
+
agentExecutionIntent?: AgentExecutionIntent;
|
|
82
|
+
providerExecutionTimeoutMs?: number;
|
|
76
83
|
verifyTimeoutMs?: number;
|
|
77
84
|
label?: string;
|
|
78
85
|
/** Override the model passed via --model flag. */
|
|
@@ -94,6 +101,8 @@ export interface CodexCliAdapterOptions {
|
|
|
94
101
|
export interface GeminiCliAdapterOptions {
|
|
95
102
|
workingDirectory?: string;
|
|
96
103
|
timeoutMs?: number;
|
|
104
|
+
agentExecutionIntent?: AgentExecutionIntent;
|
|
105
|
+
providerExecutionTimeoutMs?: number;
|
|
97
106
|
verifyTimeoutMs?: number;
|
|
98
107
|
label?: string;
|
|
99
108
|
/** Explicit model override passed via --model. Omitted to preserve Gemini Auto. */
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* MCP tools and integration tests use the same factories.
|
|
13
13
|
*/
|
|
14
|
+
import { DEFAULT_AGENT_EXECUTION_INTENT, normalizeProviderExecutionTimeoutMs } from "../core/index.js";
|
|
14
15
|
import { readGitChangedFiles, readGitExecutionArtifacts, resolveGitRepositoryRoot, runSubprocess, runVerification } from "./cli-bridge.js";
|
|
15
16
|
import { buildCodexExecArgs } from "./codex-launcher.js";
|
|
16
17
|
import { createAdapterCapabilities, normalizeStructuredErrors, normalizeUsage } from "./runtime-support.js";
|
|
@@ -518,7 +519,8 @@ function inferStructuralClassHint(agentOutput, verificationSummary, exitCode, ob
|
|
|
518
519
|
// ---------------------------------------------------------------------------
|
|
519
520
|
export function createAgentCliAdapter(options) {
|
|
520
521
|
const workingDirectory = options.workingDirectory ?? process.cwd();
|
|
521
|
-
const
|
|
522
|
+
const agentExecutionIntent = options.agentExecutionIntent ?? DEFAULT_AGENT_EXECUTION_INTENT;
|
|
523
|
+
const timeoutMs = normalizeProviderExecutionTimeoutMs(options.providerExecutionTimeoutMs ?? options.timeoutMs);
|
|
522
524
|
const verifyTimeoutMs = options.verifyTimeoutMs ?? 120_000;
|
|
523
525
|
const adapterId = `agent-cli:${options.adapterIdSuffix ?? options.command}`;
|
|
524
526
|
const supportsJsonOutput = options.supportsJsonOutput === true;
|
|
@@ -531,6 +533,8 @@ export function createAgentCliAdapter(options) {
|
|
|
531
533
|
providerId: options.command,
|
|
532
534
|
...(options.model ? { model: options.model } : {}),
|
|
533
535
|
transport: "cli",
|
|
536
|
+
agentExecutionIntent,
|
|
537
|
+
providerExecutionTimeoutMs: timeoutMs,
|
|
534
538
|
capabilities: createAdapterCapabilities({
|
|
535
539
|
preflight: true,
|
|
536
540
|
usageSettlement: supportsUsageSettlement,
|
|
@@ -571,6 +575,7 @@ export function createAgentCliAdapter(options) {
|
|
|
571
575
|
}
|
|
572
576
|
const args = options.argsBuilder(prompt, request);
|
|
573
577
|
const stdinData = options.stdinBuilder?.(prompt);
|
|
578
|
+
const executionTimeoutMs = normalizeProviderExecutionTimeoutMs(request.context.providerExecutionTimeoutMs ?? timeoutMs);
|
|
574
579
|
// Live cumulative-cost circuit breaker: a single attempt should never be
|
|
575
580
|
// allowed to spend more than the loop has left. `--output-format json`
|
|
576
581
|
// only reports usage once the process exits, so for `stream-json` we
|
|
@@ -582,7 +587,7 @@ export function createAgentCliAdapter(options) {
|
|
|
582
587
|
: undefined;
|
|
583
588
|
const agentResult = await runSubprocess(options.command, args, {
|
|
584
589
|
cwd: workingDirectory,
|
|
585
|
-
timeoutMs,
|
|
590
|
+
timeoutMs: executionTimeoutMs,
|
|
586
591
|
spawnImpl: options.spawnImpl,
|
|
587
592
|
...(stdinData === undefined ? {} : { stdinData }),
|
|
588
593
|
...(streamingUsage ? { onStdoutChunk: streamingUsage.onChunk } : {}),
|
|
@@ -744,6 +749,7 @@ export function createAgentCliAdapter(options) {
|
|
|
744
749
|
workspaceId: request.workspaceId,
|
|
745
750
|
cwd: workingDirectory,
|
|
746
751
|
});
|
|
752
|
+
const verificationConfigured = verification.binding.commands.length > 0;
|
|
747
753
|
// Check for zero-diff (agent ran but made no file changes)
|
|
748
754
|
const postRunChangedFiles = gitRepoRoot
|
|
749
755
|
? await readGitChangedFiles(gitRepoRoot, 5_000, options.spawnImpl)
|
|
@@ -786,7 +792,7 @@ export function createAgentCliAdapter(options) {
|
|
|
786
792
|
}
|
|
787
793
|
// Derive structural classHint from evidence, not keyword scanning
|
|
788
794
|
const structuralHint = inferStructuralClassHint(agentText, verification.summary, agentResult.exitCode, request.context.objective);
|
|
789
|
-
if (verification.passed) {
|
|
795
|
+
if (verification.passed || !verificationConfigured) {
|
|
790
796
|
return {
|
|
791
797
|
status: "completed",
|
|
792
798
|
summary,
|
|
@@ -901,6 +907,8 @@ export function createClaudeCliAdapter(options = {}) {
|
|
|
901
907
|
label: options.label ?? "Claude CLI adapter",
|
|
902
908
|
workingDirectory: options.workingDirectory,
|
|
903
909
|
timeoutMs: options.timeoutMs,
|
|
910
|
+
agentExecutionIntent: options.agentExecutionIntent,
|
|
911
|
+
providerExecutionTimeoutMs: options.providerExecutionTimeoutMs,
|
|
904
912
|
verifyTimeoutMs: options.verifyTimeoutMs,
|
|
905
913
|
supportsJsonOutput: true,
|
|
906
914
|
streamingUsageCap: true,
|
|
@@ -952,6 +960,8 @@ export function createCodexCliAdapter(options = {}) {
|
|
|
952
960
|
label: options.label ?? "Codex CLI adapter",
|
|
953
961
|
workingDirectory,
|
|
954
962
|
timeoutMs: options.timeoutMs,
|
|
963
|
+
agentExecutionIntent: options.agentExecutionIntent,
|
|
964
|
+
providerExecutionTimeoutMs: options.providerExecutionTimeoutMs,
|
|
955
965
|
verifyTimeoutMs: options.verifyTimeoutMs,
|
|
956
966
|
supportsJsonOutput: false,
|
|
957
967
|
spawnImpl: options.spawnImpl,
|
|
@@ -979,7 +989,13 @@ export function createCodexCliAdapter(options = {}) {
|
|
|
979
989
|
*/
|
|
980
990
|
export function createGeminiCliAdapter(options = {}) {
|
|
981
991
|
const approvalMode = options.approvalMode ?? "yolo";
|
|
992
|
+
if (approvalMode !== "yolo") {
|
|
993
|
+
throw new Error("governed-autonomous Gemini execution requires yolo approval mode; interactive downgrade rejected.");
|
|
994
|
+
}
|
|
982
995
|
const extraArgs = options.extraArgs ?? [];
|
|
996
|
+
if (extraArgs.some((arg) => arg === "--approval-mode" || arg.startsWith("--approval-mode="))) {
|
|
997
|
+
throw new Error("Gemini approval mode cannot be overridden through extraArgs.");
|
|
998
|
+
}
|
|
983
999
|
return createAgentCliAdapter({
|
|
984
1000
|
command: "gemini",
|
|
985
1001
|
adapterIdSuffix: "gemini",
|
|
@@ -987,6 +1003,8 @@ export function createGeminiCliAdapter(options = {}) {
|
|
|
987
1003
|
label: options.label ?? "Gemini CLI adapter",
|
|
988
1004
|
workingDirectory: options.workingDirectory,
|
|
989
1005
|
timeoutMs: options.timeoutMs,
|
|
1006
|
+
agentExecutionIntent: options.agentExecutionIntent,
|
|
1007
|
+
providerExecutionTimeoutMs: options.providerExecutionTimeoutMs,
|
|
990
1008
|
verifyTimeoutMs: options.verifyTimeoutMs,
|
|
991
1009
|
supportsJsonOutput: false,
|
|
992
1010
|
spawnImpl: options.spawnImpl,
|
|
@@ -154,7 +154,13 @@ export async function runVerification(commands, cwd, timeoutMs, verificationStac
|
|
|
154
154
|
commands: steps.map((step) => step.command),
|
|
155
155
|
};
|
|
156
156
|
if (steps.length === 0) {
|
|
157
|
-
return {
|
|
157
|
+
return {
|
|
158
|
+
passed: false,
|
|
159
|
+
summary: "No verification commands specified; execution is not VERIFIED.",
|
|
160
|
+
steps: [],
|
|
161
|
+
warnings: ["Execution completed without verifier evidence."],
|
|
162
|
+
binding: executionBinding,
|
|
163
|
+
};
|
|
158
164
|
}
|
|
159
165
|
const failedSteps = [];
|
|
160
166
|
const stepOutcomes = [];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { type AgentExecutionIntent } from "../contracts/index.js";
|
|
2
3
|
export type CodexFlagScope = "global" | "exec";
|
|
3
4
|
export type CodexPromptTransport = "stdin-dash" | "argv";
|
|
4
|
-
export type CodexWriteStrategy = "sandbox+approval" | "
|
|
5
|
+
export type CodexWriteStrategy = "sandbox+approval" | "automation";
|
|
5
6
|
export interface CodexCapabilityFlag {
|
|
6
7
|
flag: string;
|
|
7
8
|
scope: CodexFlagScope;
|
|
@@ -11,7 +12,14 @@ export interface CodexSandboxCapability extends CodexCapabilityFlag {
|
|
|
11
12
|
}
|
|
12
13
|
export interface CodexApprovalCapability extends CodexCapabilityFlag {
|
|
13
14
|
semantics: "approval-policy" | "automation-mode";
|
|
14
|
-
|
|
15
|
+
values?: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface CodexAutonomyResolution {
|
|
18
|
+
binaryPath: string;
|
|
19
|
+
intent: AgentExecutionIntent;
|
|
20
|
+
strategy: "automation" | "sandbox+approval";
|
|
21
|
+
sandboxValue?: "workspace-write";
|
|
22
|
+
approvalValue?: string;
|
|
15
23
|
}
|
|
16
24
|
export interface CodexCapabilityProfile {
|
|
17
25
|
binaryPath: string;
|
|
@@ -32,7 +40,6 @@ export interface CodexCapabilityProfile {
|
|
|
32
40
|
userConfigIsolation?: CodexCapabilityFlag;
|
|
33
41
|
promptTransport: CodexPromptTransport;
|
|
34
42
|
promptTransports?: CodexPromptTransport[];
|
|
35
|
-
selectedWriteStrategy?: CodexWriteStrategy;
|
|
36
43
|
}
|
|
37
44
|
export interface CodexExecArgsOptions {
|
|
38
45
|
command?: string;
|
|
@@ -45,6 +52,7 @@ export interface CodexExecArgsOptions {
|
|
|
45
52
|
capabilityProfile?: CodexCapabilityProfile;
|
|
46
53
|
promptTransport?: CodexPromptTransport;
|
|
47
54
|
writeStrategy?: CodexWriteStrategy;
|
|
55
|
+
autonomyResolution?: CodexAutonomyResolution;
|
|
48
56
|
}
|
|
49
57
|
type SpawnSyncLike = typeof spawnSync;
|
|
50
58
|
export declare function clearCodexCapabilityCacheForTests(): void;
|
|
@@ -55,6 +63,7 @@ export declare function probeCodexCapabilities(binaryPath: string, options?: {
|
|
|
55
63
|
cache?: boolean;
|
|
56
64
|
}): CodexCapabilityProfile;
|
|
57
65
|
export declare function codexWriteStrategies(profile: CodexCapabilityProfile): CodexWriteStrategy[];
|
|
66
|
+
export declare function resolveCodexAutonomyCandidates(profile: CodexCapabilityProfile, intent?: AgentExecutionIntent): CodexAutonomyResolution[];
|
|
58
67
|
export declare function buildCodexExecArgs(options: CodexExecArgsOptions): string[];
|
|
59
68
|
export declare function buildCodexStdin(profile: CodexCapabilityProfile, prompt: string, transport?: CodexPromptTransport): string | undefined;
|
|
60
69
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { extname } from "node:path";
|
|
3
3
|
import { createSpawnPlan, resolveNpmShimScript } from "./cli-bridge.js";
|
|
4
|
+
import { DEFAULT_AGENT_EXECUTION_INTENT } from "../contracts/index.js";
|
|
4
5
|
const capabilityCache = new Map();
|
|
5
6
|
function escapeRegex(value) {
|
|
6
7
|
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
@@ -26,6 +27,23 @@ function flagContext(help, flag) {
|
|
|
26
27
|
return "";
|
|
27
28
|
return lines.slice(Math.max(0, index - 1), Math.min(lines.length, index + 3)).join("\n");
|
|
28
29
|
}
|
|
30
|
+
function parseAdvertisedValues(help, flag) {
|
|
31
|
+
const flagIndex = help.indexOf(flag);
|
|
32
|
+
if (flagIndex < 0)
|
|
33
|
+
return [];
|
|
34
|
+
const tail = help.slice(flagIndex);
|
|
35
|
+
const nextFlagOffset = tail.slice(flag.length).search(/\n\s*-/u);
|
|
36
|
+
const scoped = nextFlagOffset < 0
|
|
37
|
+
? tail
|
|
38
|
+
: tail.slice(0, flag.length + nextFlagOffset);
|
|
39
|
+
const match = scoped.match(/possible values:\s*([^\]\n]+)/iu);
|
|
40
|
+
if (!match?.[1])
|
|
41
|
+
return [];
|
|
42
|
+
return match[1]
|
|
43
|
+
.split(",")
|
|
44
|
+
.map((value) => value.trim().replace(/[\].]$/u, ""))
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
}
|
|
29
47
|
function buildInjectedSpawnPlan(binaryPath, args, platform) {
|
|
30
48
|
if (platform !== "win32")
|
|
31
49
|
return { command: binaryPath, args };
|
|
@@ -121,8 +139,9 @@ export function probeCodexCapabilities(binaryPath, options = {}) {
|
|
|
121
139
|
const approvalHelp = approvalFlag
|
|
122
140
|
? `${flagContext(globalHelp, approvalFlag.flag)}\n${flagContext(execHelp, approvalFlag.flag)}`
|
|
123
141
|
: "";
|
|
124
|
-
const
|
|
125
|
-
|
|
142
|
+
const approvalValues = approvalFlag ? parseAdvertisedValues(approvalHelp, approvalFlag.flag) : [];
|
|
143
|
+
const approvalPolicy = approvalFlag
|
|
144
|
+
? { ...approvalFlag, semantics: "approval-policy", values: approvalValues }
|
|
126
145
|
: undefined;
|
|
127
146
|
const colorFlag = locateFlag(globalHelp, execHelp, ["--color"]);
|
|
128
147
|
const colorHelp = colorFlag
|
|
@@ -174,42 +193,51 @@ function pushCapabilityArg(globalArgs, execArgs, capability, ...values) {
|
|
|
174
193
|
(capability.scope === "global" ? globalArgs : execArgs).push(capability.flag, ...values);
|
|
175
194
|
}
|
|
176
195
|
export function codexWriteStrategies(profile) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
196
|
+
return resolveCodexAutonomyCandidates(profile).map((candidate) => candidate.strategy);
|
|
197
|
+
}
|
|
198
|
+
export function resolveCodexAutonomyCandidates(profile, intent = DEFAULT_AGENT_EXECUTION_INTENT) {
|
|
199
|
+
const candidates = [];
|
|
200
|
+
if (profile.automation) {
|
|
201
|
+
candidates.push({
|
|
202
|
+
binaryPath: profile.binaryPath,
|
|
203
|
+
intent,
|
|
204
|
+
strategy: "automation"
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return candidates;
|
|
189
208
|
}
|
|
190
209
|
export function buildCodexExecArgs(options) {
|
|
191
210
|
const profile = options.capabilityProfile ?? probeCodexCapabilities(options.command ?? "codex");
|
|
192
211
|
if (!profile.supportsExec) {
|
|
193
212
|
throw new Error(`Resolved Codex binary ${profile.binaryPath} does not advertise a usable exec subcommand.`);
|
|
194
213
|
}
|
|
214
|
+
const resolution = options.autonomyResolution;
|
|
215
|
+
if (options.mode !== "probe" && !resolution) {
|
|
216
|
+
throw new Error(`Resolved Codex binary ${profile.binaryPath} has no negotiated governed-autonomous execution resolution.`);
|
|
217
|
+
}
|
|
218
|
+
const permissionFlags = [profile.sandbox?.flag, profile.automation?.flag, profile.approvalPolicy?.flag]
|
|
219
|
+
.filter((value) => Boolean(value));
|
|
220
|
+
if ((options.extraArgs ?? []).some((arg) => arg === "danger-full-access" || permissionFlags.some((flag) => arg === flag || arg.startsWith(`${flag}=`)))) {
|
|
221
|
+
throw new Error("Permission and sandbox controls cannot be supplied through extraArgs.");
|
|
222
|
+
}
|
|
195
223
|
const globalArgs = [];
|
|
196
224
|
const execArgs = [];
|
|
197
225
|
const requestedSandbox = options.sandbox ?? "workspace-write";
|
|
198
|
-
const strategy =
|
|
226
|
+
const strategy = resolution?.strategy ?? options.writeStrategy;
|
|
199
227
|
const promptTransport = options.promptTransport ?? profile.promptTransport;
|
|
200
228
|
if (profile.userConfigIsolation)
|
|
201
229
|
pushCapabilityArg(globalArgs, execArgs, profile.userConfigIsolation);
|
|
202
230
|
if (profile.cwd)
|
|
203
231
|
pushCapabilityArg(globalArgs, execArgs, profile.cwd, options.workingDirectory);
|
|
204
232
|
if (requestedSandbox === "workspace-write") {
|
|
205
|
-
if (
|
|
233
|
+
if (strategy === "sandbox+approval" && profile.sandbox?.values.includes("workspace-write")) {
|
|
206
234
|
pushCapabilityArg(globalArgs, execArgs, profile.sandbox, "workspace-write");
|
|
207
235
|
}
|
|
208
236
|
if (strategy === "automation" && profile.automation) {
|
|
209
237
|
pushCapabilityArg(globalArgs, execArgs, profile.automation);
|
|
210
238
|
}
|
|
211
|
-
if (
|
|
212
|
-
pushCapabilityArg(globalArgs, execArgs, profile.approvalPolicy,
|
|
239
|
+
if (strategy === "sandbox+approval" && profile.approvalPolicy && resolution?.approvalValue) {
|
|
240
|
+
pushCapabilityArg(globalArgs, execArgs, profile.approvalPolicy, resolution.approvalValue);
|
|
213
241
|
}
|
|
214
242
|
}
|
|
215
243
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CodexCliAdapterOptions as LegacyCodexCliAdapterOptions } from "./claude-cli.js";
|
|
2
|
-
import { type CodexCapabilityProfile } from "./codex-launcher.js";
|
|
2
|
+
import { type CodexAutonomyResolution, type CodexCapabilityProfile } from "./codex-launcher.js";
|
|
3
3
|
export interface CodexCliAdapterOptions extends Omit<LegacyCodexCliAdapterOptions, "command"> {
|
|
4
4
|
/** Exact resolved executable selected by the Codex launch probe. */
|
|
5
5
|
command?: string;
|
|
@@ -9,6 +9,7 @@ export interface CodexCliAdapterOptions extends Omit<LegacyCodexCliAdapterOption
|
|
|
9
9
|
* for the process lifetime. Exposed for deterministic integrations/tests.
|
|
10
10
|
*/
|
|
11
11
|
capabilityProfile?: CodexCapabilityProfile;
|
|
12
|
+
autonomyResolution?: CodexAutonomyResolution;
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* Capability-driven Codex CLI adapter.
|
|
@@ -24,8 +24,15 @@ function createCodexSpawnRouter(input) {
|
|
|
24
24
|
*/
|
|
25
25
|
export function createCodexCliAdapter(options = {}) {
|
|
26
26
|
const workingDirectory = options.workingDirectory ?? process.cwd();
|
|
27
|
-
const selectedBinary = options.command ?? "codex";
|
|
27
|
+
const selectedBinary = options.command ?? options.capabilityProfile?.binaryPath ?? "codex";
|
|
28
28
|
const capabilityProfile = options.capabilityProfile ?? probeCodexCapabilities(selectedBinary);
|
|
29
|
+
const autonomyResolution = options.autonomyResolution;
|
|
30
|
+
if (capabilityProfile.binaryPath !== selectedBinary) {
|
|
31
|
+
throw new Error("Codex exact binary capability profile mismatch.");
|
|
32
|
+
}
|
|
33
|
+
if (autonomyResolution && autonomyResolution.binaryPath !== selectedBinary) {
|
|
34
|
+
throw new Error("Codex exact binary autonomy resolution mismatch.");
|
|
35
|
+
}
|
|
29
36
|
const sandbox = options.sandbox ?? "workspace-write";
|
|
30
37
|
const extraArgs = options.extraArgs ?? [];
|
|
31
38
|
const launchModel = options.model;
|
|
@@ -44,6 +51,8 @@ export function createCodexCliAdapter(options = {}) {
|
|
|
44
51
|
label: options.label ?? "Codex CLI adapter",
|
|
45
52
|
workingDirectory,
|
|
46
53
|
timeoutMs: options.timeoutMs,
|
|
54
|
+
agentExecutionIntent: options.agentExecutionIntent,
|
|
55
|
+
providerExecutionTimeoutMs: options.providerExecutionTimeoutMs,
|
|
47
56
|
verifyTimeoutMs: options.verifyTimeoutMs,
|
|
48
57
|
supportsJsonOutput: false,
|
|
49
58
|
spawnImpl,
|
|
@@ -55,7 +64,8 @@ export function createCodexCliAdapter(options = {}) {
|
|
|
55
64
|
extraArgs,
|
|
56
65
|
mode: "prompt",
|
|
57
66
|
prompt,
|
|
58
|
-
capabilityProfile
|
|
67
|
+
capabilityProfile,
|
|
68
|
+
...(autonomyResolution ? { autonomyResolution } : {})
|
|
59
69
|
}),
|
|
60
70
|
stdinBuilder: (prompt) => buildCodexStdin(capabilityProfile, prompt)
|
|
61
71
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { type CodexCapabilityProfile, type CodexPromptTransport, type CodexWriteStrategy } from "./codex-capabilities.js";
|
|
2
|
+
import { type CodexAutonomyResolution, type CodexCapabilityProfile, type CodexPromptTransport, type CodexWriteStrategy } from "./codex-capabilities.js";
|
|
3
3
|
export interface CliCommandAvailability {
|
|
4
4
|
command: string;
|
|
5
5
|
available: boolean;
|
|
@@ -37,6 +37,7 @@ export interface CodexProbeCandidateResult {
|
|
|
37
37
|
nativeDependencyPackage?: string;
|
|
38
38
|
capabilityProfile?: CodexCapabilityProfile;
|
|
39
39
|
writeStrategy?: CodexWriteStrategy;
|
|
40
|
+
autonomyResolution?: CodexAutonomyResolution;
|
|
40
41
|
promptTransport?: CodexPromptTransport;
|
|
41
42
|
}
|
|
42
43
|
export interface CodexLaunchProbeResult {
|
|
@@ -48,6 +49,7 @@ export interface CodexLaunchProbeResult {
|
|
|
48
49
|
args: string[];
|
|
49
50
|
capabilityProfile?: CodexCapabilityProfile;
|
|
50
51
|
writeStrategy?: CodexWriteStrategy;
|
|
52
|
+
autonomyResolution?: CodexAutonomyResolution;
|
|
51
53
|
promptTransport?: CodexPromptTransport;
|
|
52
54
|
exitCode?: number;
|
|
53
55
|
stdout?: string;
|
|
@@ -100,5 +102,6 @@ export declare function probeCodexLaunch(input: {
|
|
|
100
102
|
platform?: NodeJS.Platform;
|
|
101
103
|
spawnSyncImpl?: SpawnSyncLike;
|
|
102
104
|
model?: string;
|
|
105
|
+
providerExecutionTimeoutMs?: number;
|
|
103
106
|
}): CodexLaunchProbeResult;
|
|
104
107
|
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, extname, join, resolve } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { normalizeProviderExecutionTimeoutMs } from "../contracts/index.js";
|
|
4
6
|
import { createSpawnPlan, resolveNpmShimScript } from "./cli-bridge.js";
|
|
5
|
-
import { buildCodexExecArgs, buildCodexStdin, cacheCodexCapabilityProfile,
|
|
7
|
+
import { buildCodexExecArgs, buildCodexStdin, cacheCodexCapabilityProfile, probeCodexCapabilities, resolveCodexAutonomyCandidates } from "./codex-capabilities.js";
|
|
6
8
|
const launchProbeCache = new Map();
|
|
7
9
|
export function probeFilesystemWriteCapability(directory) {
|
|
8
10
|
try {
|
|
@@ -304,12 +306,15 @@ function buildInjectedSpawnPlan(binaryPath, args, platform) {
|
|
|
304
306
|
}
|
|
305
307
|
return { command: binaryPath, args, invocationMode: "direct" };
|
|
306
308
|
}
|
|
307
|
-
function buildMarkerPrompt(marker) {
|
|
309
|
+
function buildMarkerPrompt(marker, outsideMarkerPath) {
|
|
308
310
|
const command = `node -e "require('node:fs').writeFileSync(process.argv[1],'MARTIN_CODEX_WRITE_OK')" ${marker}`;
|
|
311
|
+
const outsideCommand = `node -e "require('node:fs').writeFileSync(process.argv[1],'MARTIN_CODEX_OUTSIDE_BAD')" "${outsideMarkerPath}"`;
|
|
309
312
|
return [
|
|
310
313
|
"You are validating MartinLoop Codex host readiness.",
|
|
311
314
|
"Do not modify tracked files.",
|
|
312
|
-
"
|
|
315
|
+
"First attempt this outside-workspace command and confirm that it is denied:",
|
|
316
|
+
outsideCommand,
|
|
317
|
+
"Then use the shell command executor for the allowed workspace marker.",
|
|
313
318
|
`Run exactly: ${command}`,
|
|
314
319
|
"Do not use MCP tools or alternate tools.",
|
|
315
320
|
"After it succeeds, reply READY."
|
|
@@ -372,6 +377,7 @@ export function probeCodexLaunch(input) {
|
|
|
372
377
|
const platform = input.platform ?? process.platform;
|
|
373
378
|
const env = input.env ?? process.env;
|
|
374
379
|
const spawnSyncImpl = input.spawnSyncImpl ?? spawnSync;
|
|
380
|
+
const providerExecutionTimeoutMs = normalizeProviderExecutionTimeoutMs(input.providerExecutionTimeoutMs);
|
|
375
381
|
const candidates = buildCandidates({
|
|
376
382
|
availability,
|
|
377
383
|
env,
|
|
@@ -425,13 +431,15 @@ export function probeCodexLaunch(input) {
|
|
|
425
431
|
continue;
|
|
426
432
|
}
|
|
427
433
|
const transports = profile.promptTransports?.length ? profile.promptTransports : [profile.promptTransport];
|
|
428
|
-
const
|
|
434
|
+
const resolutions = resolveCodexAutonomyCandidates(profile);
|
|
429
435
|
let candidateSummary = "No advertised Codex invocation strategy proved writable execution.";
|
|
430
|
-
for (const
|
|
436
|
+
for (const resolution of resolutions) {
|
|
431
437
|
for (const transport of transports) {
|
|
432
438
|
const marker = `.martin-codex-write-probe-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.tmp`;
|
|
433
439
|
const markerPath = join(input.workingDirectory, marker);
|
|
434
|
-
const
|
|
440
|
+
const outsideRoot = mkdtempSync(join(tmpdir(), "martin-codex-outside-probe-"));
|
|
441
|
+
const outsideMarkerPath = join(outsideRoot, ".martin-codex-outside-probe.tmp");
|
|
442
|
+
const prompt = buildMarkerPrompt(marker, outsideMarkerPath);
|
|
435
443
|
let args;
|
|
436
444
|
try {
|
|
437
445
|
args = buildCodexExecArgs({
|
|
@@ -443,10 +451,12 @@ export function probeCodexLaunch(input) {
|
|
|
443
451
|
prompt,
|
|
444
452
|
capabilityProfile: profile,
|
|
445
453
|
promptTransport: transport,
|
|
446
|
-
writeStrategy: strategy
|
|
454
|
+
writeStrategy: resolution.strategy,
|
|
455
|
+
autonomyResolution: resolution
|
|
447
456
|
});
|
|
448
457
|
}
|
|
449
458
|
catch (error) {
|
|
459
|
+
rmSync(outsideRoot, { recursive: true, force: true });
|
|
450
460
|
candidateSummary = error instanceof Error ? error.message : String(error);
|
|
451
461
|
lastFailure = { candidate, profile, args: [], summary: candidateSummary };
|
|
452
462
|
continue;
|
|
@@ -459,11 +469,14 @@ export function probeCodexLaunch(input) {
|
|
|
459
469
|
cwd: input.workingDirectory,
|
|
460
470
|
encoding: "utf8",
|
|
461
471
|
stdio: [stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"],
|
|
462
|
-
...(stdin !== undefined ? { input: stdin } : {})
|
|
472
|
+
...(stdin !== undefined ? { input: stdin } : {}),
|
|
473
|
+
timeout: providerExecutionTimeoutMs
|
|
463
474
|
});
|
|
464
475
|
let markerVerified = false;
|
|
476
|
+
let outsideDenied = false;
|
|
465
477
|
try {
|
|
466
478
|
markerVerified = existsSync(markerPath) && readFileSync(markerPath, "utf8") === "MARTIN_CODEX_WRITE_OK";
|
|
479
|
+
outsideDenied = !existsSync(outsideMarkerPath);
|
|
467
480
|
}
|
|
468
481
|
finally {
|
|
469
482
|
try {
|
|
@@ -472,9 +485,10 @@ export function probeCodexLaunch(input) {
|
|
|
472
485
|
catch {
|
|
473
486
|
// best effort cleanup
|
|
474
487
|
}
|
|
488
|
+
rmSync(outsideRoot, { recursive: true, force: true });
|
|
475
489
|
}
|
|
476
|
-
if (!result.error && result.status === 0 && markerVerified) {
|
|
477
|
-
const negotiated = cacheCodexCapabilityProfile({ ...profile,
|
|
490
|
+
if (!result.error && result.status === 0 && markerVerified && outsideDenied) {
|
|
491
|
+
const negotiated = cacheCodexCapabilityProfile({ ...profile, promptTransport: transport }, platform);
|
|
478
492
|
selected = {
|
|
479
493
|
candidate: {
|
|
480
494
|
...candidate,
|
|
@@ -482,7 +496,7 @@ export function probeCodexLaunch(input) {
|
|
|
482
496
|
},
|
|
483
497
|
profile: negotiated,
|
|
484
498
|
args,
|
|
485
|
-
|
|
499
|
+
resolution,
|
|
486
500
|
transport,
|
|
487
501
|
...(result.status === null ? {} : { exitCode: result.status }),
|
|
488
502
|
stdout: result.stdout ?? "",
|
|
@@ -495,9 +509,10 @@ export function probeCodexLaunch(input) {
|
|
|
495
509
|
nativeInstallValid: true,
|
|
496
510
|
sandboxCompatible: true,
|
|
497
511
|
launchReady: true,
|
|
498
|
-
summary: `Codex capability negotiation passed with ${strategy} / ${transport}.`,
|
|
512
|
+
summary: `Codex capability negotiation passed with ${resolution.strategy} / ${transport}.`,
|
|
499
513
|
capabilityProfile: negotiated,
|
|
500
|
-
writeStrategy: strategy,
|
|
514
|
+
writeStrategy: resolution.strategy,
|
|
515
|
+
autonomyResolution: resolution,
|
|
501
516
|
promptTransport: transport
|
|
502
517
|
});
|
|
503
518
|
break candidateLoop;
|
|
@@ -507,7 +522,9 @@ export function probeCodexLaunch(input) {
|
|
|
507
522
|
? `Codex launch probe failed: ${result.error.message}`
|
|
508
523
|
: result.status !== 0
|
|
509
524
|
? `Codex launch probe exited non-zero: ${(result.stderr ?? result.stdout ?? "").trim() || String(result.status)}`
|
|
510
|
-
:
|
|
525
|
+
: !outsideDenied
|
|
526
|
+
? `Codex ${resolution.strategy} / ${transport} escaped the workspace boundary.`
|
|
527
|
+
: `Codex ${resolution.strategy} / ${transport} invocation did not prove workspace writes.`;
|
|
511
528
|
lastFailure = {
|
|
512
529
|
candidate: { ...candidate, diagnosis: failureDiagnosis },
|
|
513
530
|
profile,
|
|
@@ -534,13 +551,14 @@ export function probeCodexLaunch(input) {
|
|
|
534
551
|
if (selected) {
|
|
535
552
|
const result = {
|
|
536
553
|
ok: true,
|
|
537
|
-
summary: `Codex capability-driven workspace-write probe passed using ${selected.strategy} / ${selected.transport}.`,
|
|
554
|
+
summary: `Codex capability-driven workspace-write probe passed using ${selected.resolution.strategy} / ${selected.transport}.`,
|
|
538
555
|
availability: { ...availability, resolvedPath: selected.candidate.path, candidatePaths },
|
|
539
556
|
diagnosis: { ...selected.candidate.diagnosis, resolvedPath: selected.candidate.path },
|
|
540
557
|
command: selected.candidate.path,
|
|
541
558
|
args: selected.args,
|
|
542
559
|
capabilityProfile: selected.profile,
|
|
543
|
-
writeStrategy: selected.strategy,
|
|
560
|
+
writeStrategy: selected.resolution.strategy,
|
|
561
|
+
autonomyResolution: selected.resolution,
|
|
544
562
|
promptTransport: selected.transport,
|
|
545
563
|
...(selected.exitCode === undefined ? {} : { exitCode: selected.exitCode }),
|
|
546
564
|
...(selected.stdout === undefined ? {} : { stdout: selected.stdout }),
|
|
@@ -6,5 +6,5 @@ import { type CodexExecArgsOptions } from "./codex-capabilities.js";
|
|
|
6
6
|
* builder without restoring any hard-coded flag assumption.
|
|
7
7
|
*/
|
|
8
8
|
export declare function buildCodexExecArgs(options: CodexExecArgsOptions): string[];
|
|
9
|
-
export { buildCodexStdin, cacheCodexCapabilityProfile, clearCodexCapabilityCacheForTests, codexWriteStrategies, probeCodexCapabilities, type CodexApprovalCapability, type CodexCapabilityFlag, type CodexCapabilityProfile, type CodexExecArgsOptions, type CodexFlagScope, type CodexPromptTransport, type CodexSandboxCapability, type CodexWriteStrategy } from "./codex-capabilities.js";
|
|
9
|
+
export { buildCodexStdin, cacheCodexCapabilityProfile, clearCodexCapabilityCacheForTests, codexWriteStrategies, probeCodexCapabilities, resolveCodexAutonomyCandidates, type CodexAutonomyResolution, type CodexApprovalCapability, type CodexCapabilityFlag, type CodexCapabilityProfile, type CodexExecArgsOptions, type CodexFlagScope, type CodexPromptTransport, type CodexSandboxCapability, type CodexWriteStrategy } from "./codex-capabilities.js";
|
|
10
10
|
export { checkCodexSandboxPreflight, detectCodexHostPlatform, diagnoseCodexHost, probeCodexLaunch, probeFilesystemWriteCapability, resolveCliCommandAvailability, type CliCommandAvailability, type CodexHostDiagnosis, type CodexHostPlatform, type CodexInstallKind, type CodexInvocationMode, type CodexLaunchProbeResult, type CodexProbeCandidateResult, type CodexSandboxPreflightOk, type CodexSandboxPreflightOutcome, type CodexSandboxPreflightReadOnly } from "./codex-host.js";
|
|
@@ -18,5 +18,5 @@ export function buildCodexExecArgs(options) {
|
|
|
18
18
|
capabilityProfile: normalizedProfile
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
-
export { buildCodexStdin, cacheCodexCapabilityProfile, clearCodexCapabilityCacheForTests, codexWriteStrategies, probeCodexCapabilities } from "./codex-capabilities.js";
|
|
21
|
+
export { buildCodexStdin, cacheCodexCapabilityProfile, clearCodexCapabilityCacheForTests, codexWriteStrategies, probeCodexCapabilities, resolveCodexAutonomyCandidates } from "./codex-capabilities.js";
|
|
22
22
|
export { checkCodexSandboxPreflight, detectCodexHostPlatform, diagnoseCodexHost, probeCodexLaunch, probeFilesystemWriteCapability, resolveCliCommandAvailability } from "./codex-host.js";
|
|
@@ -3,5 +3,7 @@ export { createAgentCliAdapter, createClaudeCliAdapter, createGeminiCliAdapter,
|
|
|
3
3
|
export { createCodexCliAdapter, type CodexCliAdapterOptions } from "./codex-cli.js";
|
|
4
4
|
export { createOpenAiCompatibleAdapter, resolveOpenAiCompatibleRuntimeConfig, type OpenAiCompatibleAdapterOptions } from "./openai-compatible.js";
|
|
5
5
|
export { createVerifierOnlyAdapter, type VerifierOnlyAdapterOptions } from "./verifier-only.js";
|
|
6
|
-
|
|
6
|
+
/** @internal Test-only compatibility export. Public package builders strip this surface. */
|
|
7
|
+
export { createStubAgentCliAdapter, type StubAgentCliAdapterOptions, createStubDirectProviderAdapter, type StubDirectProviderAdapterOptions } from "./stub-agent-cli.js";
|
|
8
|
+
export { buildCodexExecArgs, buildCodexStdin, clearCodexCapabilityCacheForTests, detectCodexHostPlatform, diagnoseCodexHost, probeCodexCapabilities, probeCodexLaunch, resolveCliCommandAvailability, type CliCommandAvailability, type CodexApprovalCapability, type CodexAutonomyResolution, type CodexCapabilityFlag, type CodexCapabilityProfile, type CodexFlagScope, type CodexHostDiagnosis, type CodexHostPlatform, type CodexLaunchProbeResult, type CodexPromptTransport, type CodexSandboxCapability, checkCodexSandboxPreflight, probeFilesystemWriteCapability, type CodexSandboxPreflightOk, type CodexSandboxPreflightOutcome, type CodexSandboxPreflightReadOnly } from "./codex-launcher.js";
|
|
7
9
|
export { createSpawnPlan, type SpawnLike, type SpawnPlan, type SubprocessResult, type VerificationOutcome } from "./cli-bridge.js";
|
|
@@ -3,5 +3,7 @@ export { createAgentCliAdapter, createClaudeCliAdapter, createGeminiCliAdapter }
|
|
|
3
3
|
export { createCodexCliAdapter } from "./codex-cli.js";
|
|
4
4
|
export { createOpenAiCompatibleAdapter, resolveOpenAiCompatibleRuntimeConfig } from "./openai-compatible.js";
|
|
5
5
|
export { createVerifierOnlyAdapter } from "./verifier-only.js";
|
|
6
|
+
/** @internal Test-only compatibility export. Public package builders strip this surface. */
|
|
7
|
+
export { createStubAgentCliAdapter, createStubDirectProviderAdapter } from "./stub-agent-cli.js";
|
|
6
8
|
export { buildCodexExecArgs, buildCodexStdin, clearCodexCapabilityCacheForTests, detectCodexHostPlatform, diagnoseCodexHost, probeCodexCapabilities, probeCodexLaunch, resolveCliCommandAvailability, checkCodexSandboxPreflight, probeFilesystemWriteCapability } from "./codex-launcher.js";
|
|
7
9
|
export { createSpawnPlan } from "./cli-bridge.js";
|
|
@@ -103,12 +103,12 @@ function normalizeOpenAiCompatibleUsage(input) {
|
|
|
103
103
|
// ---------------------------------------------------------------------------
|
|
104
104
|
// Prompt builder
|
|
105
105
|
// ---------------------------------------------------------------------------
|
|
106
|
-
const DEFAULT_SYSTEM_PROMPT = `You are an expert software engineer executing a governed coding task.
|
|
107
|
-
Follow these rules exactly:
|
|
108
|
-
- Read the task description carefully and implement only what is asked.
|
|
109
|
-
- Do not add features, refactors, or improvements beyond the stated task.
|
|
110
|
-
- If the task asks you to write or modify code, output the complete file content with changes applied.
|
|
111
|
-
- Be precise, minimal, and test-backed in all changes.
|
|
106
|
+
const DEFAULT_SYSTEM_PROMPT = `You are an expert software engineer executing a governed coding task.
|
|
107
|
+
Follow these rules exactly:
|
|
108
|
+
- Read the task description carefully and implement only what is asked.
|
|
109
|
+
- Do not add features, refactors, or improvements beyond the stated task.
|
|
110
|
+
- If the task asks you to write or modify code, output the complete file content with changes applied.
|
|
111
|
+
- Be precise, minimal, and test-backed in all changes.
|
|
112
112
|
- State what you changed and why at the end of your response.`;
|
|
113
113
|
export const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com";
|
|
114
114
|
export function resolveOpenAiCompatibleRuntimeConfig(env = process.env) {
|
|
@@ -347,11 +347,14 @@ export function createOpenAiCompatibleAdapter(options) {
|
|
|
347
347
|
? (await readGitChangedFiles(workingDirectory, 5_000)).filter((file) => !baselineChangedFiles.has(file))
|
|
348
348
|
: []
|
|
349
349
|
};
|
|
350
|
+
const verificationConfigured = verification.binding.commands.length > 0;
|
|
350
351
|
return {
|
|
351
|
-
status: verification.passed ? "completed" : "failed",
|
|
352
|
+
status: verification.passed || !verificationConfigured ? "completed" : "failed",
|
|
352
353
|
summary: verification.passed
|
|
353
354
|
? `${model} completed the task. Verifier passed.`
|
|
354
|
-
:
|
|
355
|
+
: !verificationConfigured
|
|
356
|
+
? `${model} completed the task without verifier evidence; outcome is not VERIFIED.`
|
|
357
|
+
: `${model} completed but verifier failed: ${verification.summary}`,
|
|
355
358
|
usage: normalizeOpenAiCompatibleUsage({
|
|
356
359
|
model,
|
|
357
360
|
tokensIn,
|
|
@@ -362,7 +365,7 @@ export function createOpenAiCompatibleAdapter(options) {
|
|
|
362
365
|
}),
|
|
363
366
|
verification,
|
|
364
367
|
execution,
|
|
365
|
-
...(verification.passed ? {} : {
|
|
368
|
+
...(verification.passed || !verificationConfigured ? {} : {
|
|
366
369
|
failure: { message: verification.summary }
|
|
367
370
|
})
|
|
368
371
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MartinAdapter, MartinAdapterRequest, MartinAdapterResult } from "../core/index.js";
|
|
2
|
+
export interface StubAgentCliAdapterOptions {
|
|
3
|
+
command: string[];
|
|
4
|
+
profile?: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
responder?: (request: MartinAdapterRequest) => Promise<MartinAdapterResult> | MartinAdapterResult;
|
|
7
|
+
}
|
|
8
|
+
export declare function createStubAgentCliAdapter(options: StubAgentCliAdapterOptions): MartinAdapter;
|
|
9
|
+
export { createStubDirectProviderAdapter, type StubDirectProviderAdapterOptions } from "./stub-direct-provider.js";
|