@sweny-ai/core 0.1.133 → 0.1.135
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/dist/claude.d.ts +3 -230
- package/dist/claude.js +3 -1049
- package/dist/cli/e2e.js +2 -2
- package/dist/cli/main.js +9 -9
- package/dist/cli/new.js +3 -3
- package/dist/cli/run-history.d.ts +5 -0
- package/dist/cli/run-history.js +2 -0
- package/dist/eval/index.js +7 -4
- package/dist/executor.d.ts +11 -2
- package/dist/executor.js +7 -1
- package/dist/harness/capabilities.d.ts +7 -0
- package/dist/harness/capabilities.js +17 -0
- package/dist/harness/claude-code.d.ts +228 -0
- package/dist/harness/claude-code.js +1020 -0
- package/dist/harness/compat.d.ts +18 -0
- package/dist/harness/compat.js +62 -0
- package/dist/harness/index.d.ts +17 -0
- package/dist/harness/index.js +24 -0
- package/dist/harness/policy.d.ts +8 -0
- package/dist/harness/policy.js +33 -0
- package/dist/harness/prompts.d.ts +59 -0
- package/dist/harness/prompts.js +107 -0
- package/dist/harness/types.d.ts +111 -0
- package/dist/harness/types.js +11 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +7 -5
- package/dist/testing.d.ts +23 -5
- package/dist/testing.js +29 -1
- package/dist/types.d.ts +14 -0
- package/package.json +1 -1
package/dist/cli/e2e.js
CHANGED
|
@@ -10,7 +10,7 @@ import * as p from "@clack/prompts";
|
|
|
10
10
|
import chalk from "chalk";
|
|
11
11
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
12
12
|
import { execute } from "../executor.js";
|
|
13
|
-
import {
|
|
13
|
+
import { createHarness } from "../harness/index.js";
|
|
14
14
|
import { createSkillMap } from "../skills/index.js";
|
|
15
15
|
import { configuredSkills } from "../skills/custom-loader.js";
|
|
16
16
|
import { consoleLogger } from "../types.js";
|
|
@@ -906,7 +906,7 @@ export async function runE2eRun(options) {
|
|
|
906
906
|
}
|
|
907
907
|
// Build skills + Claude client
|
|
908
908
|
const skills = createSkillMap(configuredSkills(process.env, cwd));
|
|
909
|
-
const claude =
|
|
909
|
+
const claude = createHarness("claude-code", {
|
|
910
910
|
maxTurns: 80,
|
|
911
911
|
cwd,
|
|
912
912
|
logger: consoleLogger,
|
package/dist/cli/main.js
CHANGED
|
@@ -9,7 +9,7 @@ import chalk from "chalk";
|
|
|
9
9
|
import { execute } from "../executor.js";
|
|
10
10
|
import { triageWorkflow, implementWorkflow, seedContentWorkflow } from "../workflows/index.js";
|
|
11
11
|
import { consoleLogger } from "../types.js";
|
|
12
|
-
import {
|
|
12
|
+
import { createHarness } from "../harness/index.js";
|
|
13
13
|
import { builtinSkills, createSkillMap, validateWorkflowSkills } from "../skills/index.js";
|
|
14
14
|
import { formatMissingSkillLines, skillEnvWarnings } from "./skill-env.js";
|
|
15
15
|
import { configuredSkills, configuredSkillsWithDiagnostics } from "../skills/custom-loader.js";
|
|
@@ -203,7 +203,7 @@ triageCmd.action(async (options) => {
|
|
|
203
203
|
const skills = createSkillMap(triageSkillDiscovery.skills);
|
|
204
204
|
const mcpAutoConfig = buildMcpAutoConfig(config);
|
|
205
205
|
const mcpServers = buildAutoMcpServers(mcpAutoConfig);
|
|
206
|
-
const claude =
|
|
206
|
+
const claude = createHarness("claude-code", {
|
|
207
207
|
maxTurns: config.maxInvestigateTurns || 50,
|
|
208
208
|
cwd: process.cwd(),
|
|
209
209
|
logger: consoleLogger,
|
|
@@ -380,7 +380,7 @@ triageCmd.action(async (options) => {
|
|
|
380
380
|
try {
|
|
381
381
|
const { results, trace } = await execute(triageWorkflow, workflowInput, {
|
|
382
382
|
skills,
|
|
383
|
-
claude,
|
|
383
|
+
harness: claude,
|
|
384
384
|
observer,
|
|
385
385
|
logger: consoleLogger,
|
|
386
386
|
cwd: process.cwd(),
|
|
@@ -513,7 +513,7 @@ implementCmd.action(async (issueId, options) => {
|
|
|
513
513
|
const skills = createSkillMap(implementSkillDiscovery.skills);
|
|
514
514
|
const mcpAutoConfig = buildMcpAutoConfig(config);
|
|
515
515
|
const mcpServers = buildAutoMcpServers(mcpAutoConfig);
|
|
516
|
-
const claude =
|
|
516
|
+
const claude = createHarness("claude-code", {
|
|
517
517
|
maxTurns: config.maxImplementTurns || 40,
|
|
518
518
|
cwd: process.cwd(),
|
|
519
519
|
logger: consoleLogger,
|
|
@@ -584,7 +584,7 @@ implementCmd.action(async (issueId, options) => {
|
|
|
584
584
|
try {
|
|
585
585
|
const { results } = await execute(implementWorkflow, workflowInput, {
|
|
586
586
|
skills,
|
|
587
|
-
claude,
|
|
587
|
+
harness: claude,
|
|
588
588
|
observer,
|
|
589
589
|
logger: consoleLogger,
|
|
590
590
|
cwd: process.cwd(),
|
|
@@ -757,7 +757,7 @@ export async function workflowRunAction(file, options) {
|
|
|
757
757
|
});
|
|
758
758
|
// Raw [info]/[debug] lines are verbose-only; warnings are rendered (#383).
|
|
759
759
|
const runLogger = createRunLogger({ verbose: Boolean(options.verbose), tty: isTTY });
|
|
760
|
-
const claude =
|
|
760
|
+
const claude = createHarness("claude-code", {
|
|
761
761
|
maxTurns: config.maxInvestigateTurns || 50,
|
|
762
762
|
cwd: process.cwd(),
|
|
763
763
|
logger: runLogger,
|
|
@@ -926,7 +926,7 @@ export async function workflowRunAction(file, options) {
|
|
|
926
926
|
try {
|
|
927
927
|
const { results, trace } = await runWithWallClockBudget((signal) => execute(workflow, workflowInput, {
|
|
928
928
|
skills,
|
|
929
|
-
claude,
|
|
929
|
+
harness: claude,
|
|
930
930
|
observer,
|
|
931
931
|
logger: runLogger,
|
|
932
932
|
cwd: process.cwd(),
|
|
@@ -1101,7 +1101,7 @@ workflowCmd
|
|
|
1101
1101
|
console.warn("\x1B[33m ⚠ `sweny workflow create` is deprecated. Use `sweny new` instead.\x1B[0m\n");
|
|
1102
1102
|
}
|
|
1103
1103
|
const skills = configuredSkills();
|
|
1104
|
-
const claude =
|
|
1104
|
+
const claude = createHarness("claude-code", {
|
|
1105
1105
|
maxTurns: 3,
|
|
1106
1106
|
cwd: process.cwd(),
|
|
1107
1107
|
logger: consoleLogger,
|
|
@@ -1168,7 +1168,7 @@ workflowCmd
|
|
|
1168
1168
|
return;
|
|
1169
1169
|
}
|
|
1170
1170
|
const skills = configuredSkills();
|
|
1171
|
-
const claude =
|
|
1171
|
+
const claude = createHarness("claude-code", {
|
|
1172
1172
|
maxTurns: 3,
|
|
1173
1173
|
cwd: process.cwd(),
|
|
1174
1174
|
logger: consoleLogger,
|
package/dist/cli/new.js
CHANGED
|
@@ -14,7 +14,7 @@ import chalk from "chalk";
|
|
|
14
14
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
15
15
|
import { WORKFLOW_TEMPLATES } from "./templates.js";
|
|
16
16
|
import { buildWorkflow, refineWorkflow } from "../workflow-builder.js";
|
|
17
|
-
import {
|
|
17
|
+
import { createHarness } from "../harness/index.js";
|
|
18
18
|
import { consoleLogger } from "../types.js";
|
|
19
19
|
import { configuredSkills } from "../skills/custom-loader.js";
|
|
20
20
|
import { builtinSkills } from "../skills/index.js";
|
|
@@ -541,7 +541,7 @@ export async function runNew(options) {
|
|
|
541
541
|
const { installMarketplaceWorkflow } = await import("./marketplace.js");
|
|
542
542
|
const allSkills = configuredSkills(process.env, cwd);
|
|
543
543
|
const hasAgent = !!process.env.ANTHROPIC_API_KEY;
|
|
544
|
-
const claude = hasAgent ?
|
|
544
|
+
const claude = hasAgent ? createHarness("claude-code", { maxTurns: 3, cwd, logger: consoleLogger }) : null;
|
|
545
545
|
if (!options.skipIntro)
|
|
546
546
|
p.intro(`Installing ${options.marketplaceId} from marketplace`);
|
|
547
547
|
// Pre-compute source-control from git-remote (same method as the wizard path).
|
|
@@ -833,7 +833,7 @@ async function runCustomWorkflowBuilder(skills) {
|
|
|
833
833
|
});
|
|
834
834
|
if (p.isCancel(description))
|
|
835
835
|
return null;
|
|
836
|
-
const claude =
|
|
836
|
+
const claude = createHarness("claude-code", {
|
|
837
837
|
maxTurns: 3,
|
|
838
838
|
cwd: process.cwd(),
|
|
839
839
|
logger: consoleLogger,
|
|
@@ -48,6 +48,11 @@ export interface RunRecord {
|
|
|
48
48
|
to: string;
|
|
49
49
|
}>;
|
|
50
50
|
totals: RunTotals;
|
|
51
|
+
/** Harness that ran the nodes (id + version). Absent for runs with no harness-tagged result. */
|
|
52
|
+
harness?: {
|
|
53
|
+
id: string;
|
|
54
|
+
version: string;
|
|
55
|
+
};
|
|
51
56
|
}
|
|
52
57
|
/** sha256 (hex) of the workflow as canonical JSON: keys sorted, undefined dropped. */
|
|
53
58
|
export declare function hashWorkflow(workflow: Workflow): string;
|
package/dist/cli/run-history.js
CHANGED
|
@@ -91,6 +91,7 @@ export function buildRunRecord(i) {
|
|
|
91
91
|
retries: retries.get(id) ?? 0,
|
|
92
92
|
};
|
|
93
93
|
});
|
|
94
|
+
const harness = [...i.results.values()].find((r) => r.harness)?.harness;
|
|
94
95
|
return {
|
|
95
96
|
schema_version: RUN_HISTORY_SCHEMA_VERSION,
|
|
96
97
|
run_id: i.runId,
|
|
@@ -109,6 +110,7 @@ export function buildRunRecord(i) {
|
|
|
109
110
|
tokens: summary.tokens ?? null,
|
|
110
111
|
cost_usd: summary.costUsd ?? null,
|
|
111
112
|
},
|
|
113
|
+
...(harness ? { harness: { id: harness.id, version: harness.version } } : {}),
|
|
112
114
|
};
|
|
113
115
|
}
|
|
114
116
|
// ── Write, prune, read ──────────────────────────────────────────
|
package/dist/eval/index.js
CHANGED
|
@@ -8,7 +8,10 @@ import { evaluateFunctionRule } from "./function.js";
|
|
|
8
8
|
import { evaluateJudge } from "./judge.js";
|
|
9
9
|
/** Reasoning cap, matching the spec's ~500-character ceiling. */
|
|
10
10
|
const MAX_REASONING_LENGTH = 500;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Judge model when neither evaluator, node, workflow nor the harness names one.
|
|
13
|
+
* Harnesses declare their own via `defaultJudgeModel` (Claude Code: this value).
|
|
14
|
+
*/
|
|
12
15
|
const DEFAULT_JUDGE_MODEL = "claude-haiku-4-5";
|
|
13
16
|
function capReasoning(reasoning) {
|
|
14
17
|
if (!reasoning)
|
|
@@ -17,8 +20,8 @@ function capReasoning(reasoning) {
|
|
|
17
20
|
return reasoning;
|
|
18
21
|
return reasoning.slice(0, MAX_REASONING_LENGTH - 1) + "…";
|
|
19
22
|
}
|
|
20
|
-
function resolveJudgeModel(evaluator, node, workflow) {
|
|
21
|
-
return evaluator.model ?? node?.judge_model ?? workflow?.judge_model ?? DEFAULT_JUDGE_MODEL;
|
|
23
|
+
function resolveJudgeModel(evaluator, node, workflow, harnessDefault) {
|
|
24
|
+
return evaluator.model ?? node?.judge_model ?? workflow?.judge_model ?? harnessDefault ?? DEFAULT_JUDGE_MODEL;
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
27
|
* Run every declared evaluator against the node's result and return one
|
|
@@ -56,7 +59,7 @@ export async function evaluateAll(evaluators, result, opts = {}) {
|
|
|
56
59
|
if (!opts.claude) {
|
|
57
60
|
throw new Error(`evaluator '${e.name}' is kind: judge but no Claude client was provided to evaluateAll`);
|
|
58
61
|
}
|
|
59
|
-
const model = resolveJudgeModel(e, opts.node, opts.workflow);
|
|
62
|
+
const model = resolveJudgeModel(e, opts.node, opts.workflow, opts.claude.defaultJudgeModel);
|
|
60
63
|
const verdict = await evaluateJudge(e, result, opts.claude, { model });
|
|
61
64
|
out.push({
|
|
62
65
|
name: e.name,
|
package/dist/executor.d.ts
CHANGED
|
@@ -13,13 +13,22 @@
|
|
|
13
13
|
* This replaces ~8k lines of engine + recipe step code.
|
|
14
14
|
*/
|
|
15
15
|
import type { Workflow, Skill, Tool, Claude, Observer, Logger, ExecutionResult } from "./types.js";
|
|
16
|
+
import type { AgentHarness } from "./harness/types.js";
|
|
16
17
|
export interface ExecuteOptions {
|
|
17
18
|
/** Registered skills (id → Skill) */
|
|
18
19
|
skills: Map<string, Skill>;
|
|
19
20
|
/** Config values — env vars + explicit overrides */
|
|
20
21
|
config?: Record<string, string>;
|
|
21
|
-
/**
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The agent harness that runs nodes (`createHarness("claude-code")`).
|
|
24
|
+
* Required unless the deprecated `claude` option is given.
|
|
25
|
+
*/
|
|
26
|
+
harness?: AgentHarness;
|
|
27
|
+
/**
|
|
28
|
+
* Claude client.
|
|
29
|
+
* @deprecated Pass `harness`. Still accepted (see `claudeCompat()`); when both are set, `harness` wins.
|
|
30
|
+
*/
|
|
31
|
+
claude?: Claude;
|
|
23
32
|
/** Event observer for streaming/logging */
|
|
24
33
|
observer?: Observer;
|
|
25
34
|
/** Logger */
|
package/dist/executor.js
CHANGED
|
@@ -22,6 +22,7 @@ import { buildToolAliases } from "./skills/index.js";
|
|
|
22
22
|
import { validateWorkflow } from "./schema.js";
|
|
23
23
|
import { resolveAgentAccess } from "./agent-env.js";
|
|
24
24
|
import { fenceUntrusted } from "./untrusted.js";
|
|
25
|
+
import { asClaude } from "./harness/compat.js";
|
|
25
26
|
/**
|
|
26
27
|
* Default workflow-level step budget. Counts total node executions across the
|
|
27
28
|
* whole run (loop iterations included). Generous enough for legitimate deep
|
|
@@ -47,7 +48,12 @@ function throwIfAborted(signal) {
|
|
|
47
48
|
* - `trace`: full ordered execution trace including loops and routing decisions
|
|
48
49
|
*/
|
|
49
50
|
export async function execute(workflow, input, options) {
|
|
50
|
-
const {
|
|
51
|
+
const { observer, signal, timeoutMs } = options;
|
|
52
|
+
// `harness` is the seam; a legacy `claude` object is used as-is (what `asClaude(claudeCompat(claude))` yields).
|
|
53
|
+
const claude = options.harness ? asClaude(options.harness) : options.claude;
|
|
54
|
+
if (!claude) {
|
|
55
|
+
throw new Error("execute() needs options.harness (or the deprecated options.claude)");
|
|
56
|
+
}
|
|
51
57
|
// If the caller already aborted before we started, fail fast.
|
|
52
58
|
throwIfAborted(signal);
|
|
53
59
|
const dryRun = isDryRunInput(input);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared capabilities per adapter. No runtime imports, so the executor can use
|
|
3
|
+
* them without pulling in an agent SDK.
|
|
4
|
+
*/
|
|
5
|
+
import type { HarnessCapabilities } from "./types.js";
|
|
6
|
+
/** Claude Code enforces every sweny opinion natively, so `policyGate` never degrades or refuses it. */
|
|
7
|
+
export declare const CLAUDE_CODE_CAPABILITIES: HarnessCapabilities;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared capabilities per adapter. No runtime imports, so the executor can use
|
|
3
|
+
* them without pulling in an agent SDK.
|
|
4
|
+
*/
|
|
5
|
+
/** Claude Code enforces every sweny opinion natively, so `policyGate` never degrades or refuses it. */
|
|
6
|
+
export const CLAUDE_CODE_CAPABILITIES = {
|
|
7
|
+
structuredOutput: "native",
|
|
8
|
+
toolTrace: "full",
|
|
9
|
+
builtinDeny: "by-name",
|
|
10
|
+
mcp: { inject: true, exclusive: "native" },
|
|
11
|
+
sandbox: { fs: true, network: true },
|
|
12
|
+
readOnly: "native",
|
|
13
|
+
turnLimit: "native",
|
|
14
|
+
usage: { tokens: true, costUsd: true, live: false },
|
|
15
|
+
cancel: "signal",
|
|
16
|
+
resume: false,
|
|
17
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Client - Headless Claude Code backend
|
|
3
|
+
*
|
|
4
|
+
* Uses the @anthropic-ai/claude-agent-sdk to run headless Claude Code
|
|
5
|
+
* as the LLM backend. Tools are exposed via an in-process MCP server
|
|
6
|
+
* that Claude Code calls during execution.
|
|
7
|
+
*
|
|
8
|
+
* This is the ONLY supported LLM backend. The whole point of sweny
|
|
9
|
+
* is to use headless Claude Code - never the raw Anthropic API.
|
|
10
|
+
*/
|
|
11
|
+
import type { Claude, ToolContext, Logger, McpServerConfig } from "../types.js";
|
|
12
|
+
import { type SandboxMode } from "../agent-env.js";
|
|
13
|
+
import type { AgentHarness, HarnessCapabilities, HarnessCompleteRequest, HarnessInfo, HarnessRunRequest, HarnessRunResult } from "./types.js";
|
|
14
|
+
import { CLAUDE_CODE_CAPABILITIES } from "./capabilities.js";
|
|
15
|
+
import { buildEvaluatePrompt } from "./prompts.js";
|
|
16
|
+
export { buildEvaluatePrompt, CLAUDE_CODE_CAPABILITIES };
|
|
17
|
+
/**
|
|
18
|
+
* Built-in tools disallowed for the route-evaluation (`evaluate`) and
|
|
19
|
+
* reflection/judge (`ask`) calls.
|
|
20
|
+
*
|
|
21
|
+
* These are pure classification calls over prior-node data that can be
|
|
22
|
+
* attacker-influenceable (a prior node summarizes an untrusted issue body,
|
|
23
|
+
* PR diff, log line, etc.). They must never be able to mutate the workspace
|
|
24
|
+
* or shell out, regardless of any node's own `disallowed_tools` policy.
|
|
25
|
+
* `maxTurns: 1` already bounds them; this removes the powerful built-ins
|
|
26
|
+
* from the model's context entirely as structural defense-in-depth.
|
|
27
|
+
*/
|
|
28
|
+
export declare const CLASSIFICATION_DISALLOWED_TOOLS: readonly ["Bash", "Write", "Edit", "MultiEdit", "NotebookEdit", "WebFetch", "WebSearch"];
|
|
29
|
+
/**
|
|
30
|
+
* Built-in tools disallowed for a node run with `readOnly: true` (dry run,
|
|
31
|
+
* #380): everything that can edit the workspace, shell out (and so reach
|
|
32
|
+
* `gh`, `curl`, `git push`), spawn a subagent that could, or fetch an
|
|
33
|
+
* arbitrary URL (a GET can still trigger a webhook or exfiltrate data).
|
|
34
|
+
* Read, Grep, Glob and WebSearch stay available for analysis.
|
|
35
|
+
*/
|
|
36
|
+
export declare const READ_ONLY_DISALLOWED_TOOLS: readonly ["Bash", "Write", "Edit", "MultiEdit", "NotebookEdit", "Task", "Agent", "WebFetch"];
|
|
37
|
+
/** How sweny resolves which credentials reach the Claude Code subprocess. */
|
|
38
|
+
export type SwenyAuthMode = "auto" | "api-key" | "oauth";
|
|
39
|
+
export interface ResolveAuthEnvOpts {
|
|
40
|
+
/** Explicit override; when absent, read from `env.SWENY_AUTH`. Test seam. */
|
|
41
|
+
mode?: SwenyAuthMode;
|
|
42
|
+
/** Logger for the debug line + invalid-value warning. */
|
|
43
|
+
logger?: Pick<Logger, "debug" | "warn">;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Decide which auth credentials survive into the Claude Code subprocess env.
|
|
47
|
+
*
|
|
48
|
+
* sweny does not select the winning credential (the spawned agent and any
|
|
49
|
+
* on-disk `~/.claude/.credentials.json` do that). This function only controls
|
|
50
|
+
* what is *present* in the env we hand the agent.
|
|
51
|
+
*
|
|
52
|
+
* Modes (`SWENY_AUTH`, default `auto`):
|
|
53
|
+
* - `auto` - today's protective behavior: when an OAuth token is present,
|
|
54
|
+
* strip `ANTHROPIC_API_KEY` so a stray `.env` key cannot
|
|
55
|
+
* silently bill a metered API account. `ANTHROPIC_AUTH_TOKEN`
|
|
56
|
+
* (a bearer token, not a console key) is never touched.
|
|
57
|
+
* - `api-key` - user explicitly authenticates a gateway with a key/bearer:
|
|
58
|
+
* preserve both even when an OAuth token is also present.
|
|
59
|
+
* - `oauth` - user explicitly wants subscription/OAuth: strip both
|
|
60
|
+
* `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` so a leftover
|
|
61
|
+
* credential cannot win at the agent. Fails closed.
|
|
62
|
+
*
|
|
63
|
+
* Base-URL presence is deliberately NOT a signal here: pass-through proxies
|
|
64
|
+
* (corporate egress, observability) set `ANTHROPIC_BASE_URL` while still
|
|
65
|
+
* billing the real key, so inferring "use the key" from a base URL would
|
|
66
|
+
* re-introduce a surprise-billing path. Intent must be explicit.
|
|
67
|
+
*
|
|
68
|
+
* An unrecognized `SWENY_AUTH` value falls back to `auto` with a warning
|
|
69
|
+
* (never throws - an env typo must not crash a CI run).
|
|
70
|
+
*
|
|
71
|
+
* Pure: returns a copy, never mutates the input.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveAuthEnv(env: Record<string, string>, opts?: ResolveAuthEnvOpts): Record<string, string>;
|
|
74
|
+
export interface ClaudeCodeHarnessOptions {
|
|
75
|
+
/** Model override */
|
|
76
|
+
model?: string;
|
|
77
|
+
/** Max turns for tool use loop (default: 20) */
|
|
78
|
+
maxTurns?: number;
|
|
79
|
+
/** Working directory for Claude Code (default: process.cwd()) */
|
|
80
|
+
cwd?: string;
|
|
81
|
+
/** Logger */
|
|
82
|
+
logger?: Logger;
|
|
83
|
+
/** Default tool context for standalone usage (not via executor) */
|
|
84
|
+
defaultContext?: ToolContext;
|
|
85
|
+
/** Catalog defaults, overridden by per-run skill servers and explicit mcpServers. */
|
|
86
|
+
defaultMcpServers?: Record<string, McpServerConfig>;
|
|
87
|
+
/** Explicit external MCP servers, overriding defaults and per-run skill servers. */
|
|
88
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
89
|
+
/**
|
|
90
|
+
* Extra env var names passed to the agent subprocess on top of the
|
|
91
|
+
* allowlist (see agent-env.ts). `"*"` inherits the full environment.
|
|
92
|
+
* Default: `SWENY_ENV_PASSTHROUGH` (comma-separated).
|
|
93
|
+
*/
|
|
94
|
+
envPassthrough?: string[];
|
|
95
|
+
/**
|
|
96
|
+
* Scope the agent env to the allowlist. Default: `SWENY_ENV_SCOPE`, else on
|
|
97
|
+
* when CI is truthy and off locally (full env).
|
|
98
|
+
*/
|
|
99
|
+
envScope?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* SDK sandbox for agent commands: `auto` (sandbox when the host supports
|
|
102
|
+
* it, else warn and run unsandboxed), `strict` (sandbox or fail), `off`.
|
|
103
|
+
* Default: `SWENY_SANDBOX`, else `auto` when CI is truthy, `off` otherwise.
|
|
104
|
+
*/
|
|
105
|
+
sandbox?: SandboxMode;
|
|
106
|
+
/** Extra hosts sandboxed commands may reach. Default: `SWENY_SANDBOX_ALLOWED_DOMAINS`. */
|
|
107
|
+
sandboxAllowedDomains?: string[];
|
|
108
|
+
/** Sandbox preflight probe (test seam). Returns a reason when the sandbox cannot run. */
|
|
109
|
+
sandboxProbe?: () => string | undefined;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wire an optional timeout + caller signal onto a single AbortController.
|
|
113
|
+
*
|
|
114
|
+
* Returns undefined when neither a timeout nor a signal is supplied so the
|
|
115
|
+
* default code path (no abortController, no timer) is byte-for-byte unchanged.
|
|
116
|
+
*
|
|
117
|
+
* `reason()` reports whether the abort came from the timeout timer or an
|
|
118
|
+
* external signal, so callers can log a distinct timeout message.
|
|
119
|
+
*/
|
|
120
|
+
export declare function makeAbort(timeoutMs?: number, signal?: AbortSignal): {
|
|
121
|
+
controller: AbortController;
|
|
122
|
+
clear: () => void;
|
|
123
|
+
reason: () => "timeout" | "signal" | undefined;
|
|
124
|
+
} | undefined;
|
|
125
|
+
export declare class ClaudeCodeHarness implements Claude, AgentHarness {
|
|
126
|
+
readonly id: "claude-code";
|
|
127
|
+
readonly capabilities: HarnessCapabilities;
|
|
128
|
+
readonly defaultJudgeModel = "claude-haiku-4-5";
|
|
129
|
+
private model;
|
|
130
|
+
private maxTurns;
|
|
131
|
+
private cwd;
|
|
132
|
+
readonly logger: Logger;
|
|
133
|
+
private defaultContext;
|
|
134
|
+
private mcpServers;
|
|
135
|
+
private defaultMcpServers;
|
|
136
|
+
private envPassthrough;
|
|
137
|
+
private sandboxMode;
|
|
138
|
+
private sandboxAllowedDomains;
|
|
139
|
+
private sandboxProbe;
|
|
140
|
+
private sandboxWarned;
|
|
141
|
+
private envScope;
|
|
142
|
+
constructor(opts?: ClaudeCodeHarnessOptions);
|
|
143
|
+
/**
|
|
144
|
+
* Build env for the Claude Code subprocess (#360). Applies auth precedence
|
|
145
|
+
* via {@link resolveAuthEnv} on the full process env (it reads
|
|
146
|
+
* `SWENY_AUTH`). When env scoping is on (default in CI, see
|
|
147
|
+
* {@link resolveEnvScope}) the result is narrowed to the allowlist plus
|
|
148
|
+
* `extraVars` (the node's declared skill env vars) and the operator
|
|
149
|
+
* passthrough list, and the withheld names (never values) are reported once
|
|
150
|
+
* per process ({@link reportWithheldEnv}). When off, the full env passes through as before.
|
|
151
|
+
*/
|
|
152
|
+
private buildEnv;
|
|
153
|
+
/** Which harness (and SDK version) produced a result. */
|
|
154
|
+
info(): HarnessInfo;
|
|
155
|
+
preflight(): Promise<{
|
|
156
|
+
ok: true;
|
|
157
|
+
version: string;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* Run a node. The query itself is unchanged by the harness seam; this only
|
|
161
|
+
* runs {@link policyGate} (always `degraded: []` for Claude Code) and tags
|
|
162
|
+
* the result with the harness id and version.
|
|
163
|
+
*/
|
|
164
|
+
run(req: HarnessRunRequest): Promise<HarnessRunResult>;
|
|
165
|
+
private runQuery;
|
|
166
|
+
/**
|
|
167
|
+
* Single completion: no tools, no MCP, one turn. Shared by core `ask()`
|
|
168
|
+
* (retry reflection, judge scoring) and `evaluate()` (route choice); the
|
|
169
|
+
* query options are the ones `ask` and `evaluate` used before the seam.
|
|
170
|
+
* Returns null when the query failed (SDK error, timeout, non-success
|
|
171
|
+
* subtype); callers fail closed.
|
|
172
|
+
*/
|
|
173
|
+
complete(req: HarnessCompleteRequest): Promise<string | null>;
|
|
174
|
+
/** Route evaluation. Delegates to core {@link coreEvaluate} over {@link complete}. */
|
|
175
|
+
evaluate(opts: {
|
|
176
|
+
question: string;
|
|
177
|
+
context: Record<string, unknown>;
|
|
178
|
+
choices: {
|
|
179
|
+
id: string;
|
|
180
|
+
description: string;
|
|
181
|
+
}[];
|
|
182
|
+
/** Abort the query after this many ms. Default: no timeout (back-compat). */
|
|
183
|
+
timeoutMs?: number;
|
|
184
|
+
/** Caller-supplied abort signal. Aborting it interrupts the query. */
|
|
185
|
+
signal?: AbortSignal;
|
|
186
|
+
}): Promise<string | null>;
|
|
187
|
+
/** Free-text completion. Delegates to core {@link coreAsk} over {@link complete}. */
|
|
188
|
+
ask(opts: {
|
|
189
|
+
instruction: string;
|
|
190
|
+
context: Record<string, unknown>;
|
|
191
|
+
model?: string;
|
|
192
|
+
/** Abort the query after this many ms. Default: no timeout (back-compat). */
|
|
193
|
+
timeoutMs?: number;
|
|
194
|
+
/** Caller-supplied abort signal. Aborting it interrupts the query. */
|
|
195
|
+
signal?: AbortSignal;
|
|
196
|
+
}): Promise<string>;
|
|
197
|
+
}
|
|
198
|
+
/** @deprecated Use {@link ClaudeCodeHarnessOptions}. */
|
|
199
|
+
export type ClaudeClientOptions = ClaudeCodeHarnessOptions;
|
|
200
|
+
/** @deprecated Use {@link ClaudeCodeHarness} (or `createHarness("claude-code")`). */
|
|
201
|
+
export declare const ClaudeClient: typeof ClaudeCodeHarness;
|
|
202
|
+
/** @deprecated Use {@link ClaudeCodeHarness}. */
|
|
203
|
+
export type ClaudeClient = ClaudeCodeHarness;
|
|
204
|
+
/**
|
|
205
|
+
* Best-effort recovery of typed output from a tool_result's `content`.
|
|
206
|
+
*
|
|
207
|
+
* The MCP protocol sends tool results as string content. Our in-process
|
|
208
|
+
* wrapper JSON-stringifies structured output before returning; external
|
|
209
|
+
* MCP servers generally do the same for JSON payloads. If the string
|
|
210
|
+
* looks like a JSON object or array and parses, return the parsed value
|
|
211
|
+
* so verify's output-path walks work against typed data.
|
|
212
|
+
*
|
|
213
|
+
* Raw strings are preserved verbatim. JSON-primitive strings (e.g. the
|
|
214
|
+
* literal four characters `"42"`) are intentionally NOT parsed - we
|
|
215
|
+
* cannot distinguish a tool that returned the number 42 (wrapper sends
|
|
216
|
+
* `"42"`) from a tool that returned the string "42" (wrapper also sends
|
|
217
|
+
* `"42"`). Preserving the string is safer than guessing.
|
|
218
|
+
*/
|
|
219
|
+
export declare function parseToolResultContent(content: unknown): unknown;
|
|
220
|
+
/**
|
|
221
|
+
* Produce a short, single-line description of a tool-error payload suitable
|
|
222
|
+
* for the CI log stream. The full parsed value stays on the ToolCall for
|
|
223
|
+
* verify and downstream tooling - this is only for inline observability.
|
|
224
|
+
*
|
|
225
|
+
* Collapses newlines, trims whitespace, and caps to 300 chars so a huge
|
|
226
|
+
* API response body doesn't flood the log.
|
|
227
|
+
*/
|
|
228
|
+
export declare function summarizeToolError(parsed: unknown): string;
|