]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
fix(sandcastle): wire reasoning effort through to agent providers
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 8 May 2026 14:09:44 +0000 (16:09 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 8 May 2026 14:21:51 +0000 (16:21 +0200)
Pass AGENT_*_EFFORT constants through agentProvider() to the opencode
provider's variant flag. LoopStrategy gains actorEffort/criticEffort
optional overrides following the same pattern as actorModel/criticModel.

- opencode: effort mapped to --variant CLI flag
- pi: no effort support (provider limitation, param silently ignored)

.sandcastle/refinement-loop.ts
.sandcastle/task-source.ts
.sandcastle/types.ts
.sandcastle/utils.ts

index b29e63d71ae7d0f63e48ed5c1725b4c0a3a3094b..ad546ab528bff7e559fbd9a996a66525b6fa53b6 100644 (file)
@@ -14,7 +14,9 @@ import type {
 } from './types.js'
 
 import {
+  AGENT_ACTOR_EFFORT,
   AGENT_ACTOR_MODEL,
+  AGENT_CRITIC_EFFORT,
   AGENT_CRITIC_MODEL,
   AGENT_IDLE_TIMEOUT_S,
   AGENT_ITERATION_BUDGET,
@@ -460,7 +462,10 @@ async function executeRound (
   let actorResult: Awaited<ReturnType<typeof sandbox.run>>
   try {
     actorResult = await sandbox.run({
-      agent: agentProvider(strategy.actorModel ?? AGENT_ACTOR_MODEL),
+      agent: agentProvider(
+        strategy.actorModel ?? AGENT_ACTOR_MODEL,
+        strategy.actorEffort ?? AGENT_ACTOR_EFFORT
+      ),
       completionSignal: COMPLETION_SIGNAL,
       idleTimeoutSeconds: AGENT_IDLE_TIMEOUT_S,
       maxIterations: budget,
@@ -622,7 +627,10 @@ async function runCritic (
   const { baseBranch, sandbox, signal, spec, strategy } = ctx
 
   let critic = await sandbox.run({
-    agent: agentProvider(strategy.criticModel ?? AGENT_CRITIC_MODEL),
+    agent: agentProvider(
+      strategy.criticModel ?? AGENT_CRITIC_MODEL,
+      strategy.criticEffort ?? AGENT_CRITIC_EFFORT
+    ),
     completionSignal: COMPLETION_SIGNAL,
     idleTimeoutSeconds: AGENT_IDLE_TIMEOUT_S,
     maxIterations: 1,
@@ -637,7 +645,10 @@ async function runCritic (
   if (findings === null) {
     console.warn(`  #${spec.id}: Critic parse failed. Retrying.`)
     critic = await sandbox.run({
-      agent: agentProvider(strategy.criticModel ?? AGENT_CRITIC_MODEL),
+      agent: agentProvider(
+        strategy.criticModel ?? AGENT_CRITIC_MODEL,
+        strategy.criticEffort ?? AGENT_CRITIC_EFFORT
+      ),
       completionSignal: COMPLETION_SIGNAL,
       idleTimeoutSeconds: AGENT_IDLE_TIMEOUT_S,
       maxIterations: 1,
index a17dbb4349993ac5267f34891474aa6d39a6ceff..5452e8b990697a11927c867c0edc16fa5f79dd6c 100644 (file)
@@ -6,6 +6,7 @@ import type { TaskSpec } from './types.js'
 
 import {
   AGENT_IDLE_TIMEOUT_S,
+  AGENT_PLANNER_EFFORT,
   AGENT_PLANNER_MODEL,
   AGENT_TASK_TIMEOUT_MS,
   COMPLETION_SIGNAL,
@@ -97,7 +98,7 @@ export class GithubIssueSource implements TaskSource {
       let plan: Awaited<ReturnType<typeof sandcastle.run>>
       try {
         plan = await sandcastle.run({
-          agent: agentProvider(AGENT_PLANNER_MODEL),
+          agent: agentProvider(AGENT_PLANNER_MODEL, AGENT_PLANNER_EFFORT),
           completionSignal: COMPLETION_SIGNAL,
           hooks: SANDBOX_AUTH_HOOKS,
           idleTimeoutSeconds: AGENT_IDLE_TIMEOUT_S,
index ce0c002b5dcd2d1e0bf73f013e276211830e30d8..6688a97fad440264ad720c560cc0704d9b36b419 100644 (file)
@@ -66,6 +66,8 @@ export type LoopStatus = 'converged' | 'exhausted' | 'failed' | 'skipped'
  */
 // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 export type LoopStrategy = {
+  /** Reasoning effort for the actor agent. Defaults to AGENT_ACTOR_EFFORT constant. */
+  actorEffort?: string
   /** Model for the actor agent. Defaults to AGENT_ACTOR_MODEL constant. */
   actorModel?: string
   /** Path to the actor prompt file. */
@@ -74,6 +76,8 @@ export type LoopStrategy = {
   buildActorArgs: (spec: TaskSpec, findings: Finding[]) => Record<string, string>
   /** Builds promptArgs for the critic run from task spec and base branch. */
   buildCriticArgs: (spec: TaskSpec, baseBranch: string) => Record<string, string>
+  /** Reasoning effort for the critic agent. Defaults to AGENT_CRITIC_EFFORT constant. */
+  criticEffort?: string
   /** Model for the critic agent. Defaults to AGENT_CRITIC_MODEL constant. */
   criticModel?: string
   /** Path to the critic prompt file. */
index eefa48d9434b7f9262237e092203a842f3a03487..ec05d7c892b442748d60ec76d5bf2e3ef7eb0548 100644 (file)
@@ -12,12 +12,13 @@ export const execFileAsync = util.promisify(execFile)
 /**
  * Returns a sandcastle agent provider for the given model, selected by AGENT_PROVIDER constant.
  * @param model - The model identifier (e.g., 'github-copilot/claude-sonnet-4.6').
+ * @param effort - Reasoning effort level passed as `variant` to opencode.
  * @returns The configured agent provider.
  */
-export function agentProvider (model: string): AgentProvider {
+export function agentProvider (model: string, effort?: string): AgentProvider {
   switch (AGENT_PROVIDER) {
     case 'opencode':
-      return sandcastle.opencode(model)
+      return sandcastle.opencode(model, effort ? { variant: effort } : undefined)
     case 'pi':
       return sandcastle.pi(model)
   }