Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions apps/api/src/handlers/tasks/__tests__/launchTask.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/worker/src/run-task/__tests__/create-harness.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions apps/worker/src/run-task/agent-home.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions apps/worker/src/run-task/agent-home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ interface GenerateOpenCodeConfigOptions {
developerInstructionsContent?: string;
mcpServers?: OpenCodeConfigMcpServer[];
model?: string;
reasoningEffortOverride?: ReasoningEffort;
}

interface GenerateOpenCodeConfigResult {
Expand Down Expand Up @@ -898,6 +899,7 @@ function createExploreAgentConfig(options: {
function resolveModelBackedOpenCodeConfig(
runtimeEnv: Record<string, string>,
modelOverride?: string,
reasoningEffortOverride?: ReasoningEffort,
): Record<string, unknown> | null {
const rawModel = runtimeEnv.R_MODEL?.trim();

Expand Down Expand Up @@ -1089,13 +1091,16 @@ function resolveModelBackedOpenCodeConfig(
// applied when the model in play is the one the role was configured with.
// Role precedence for a shared model: effective coding model first, then the
// persisted coding model, then a distinct helper model. The vision level is
// scoped to the visual subagent via agent-level options above.
// scoped to the visual subagent via agent-level options above. A per-task
// reasoning effort (stamped at launch for model overrides, or set
// explicitly via the public API) wins over the role-configured levels.
const effectiveCodingModelReasoningEffort: ReasoningEffort | null =
effectiveCodingModel === model
reasoningEffortOverride ??
(effectiveCodingModel === model
? modelReasoningEffort
: codeReviewModel && effectiveCodingModel === codeReviewModel
? codeReviewModelReasoningEffort
: null;
: null);
let providerReasoningConfig: Record<string, unknown> = {};

if (effectiveCodingModelReasoningEffort) {
Expand Down Expand Up @@ -1155,14 +1160,17 @@ function loadOperatorOpenCodeConfig({
runtimeEnv,
openCodeConfigDir,
modelOverride,
reasoningEffortOverride,
}: {
runtimeEnv: Record<string, string>;
openCodeConfigDir: string;
modelOverride?: string;
reasoningEffortOverride?: ReasoningEffort;
}): Record<string, unknown> {
const modelConfig = resolveModelBackedOpenCodeConfig(
runtimeEnv,
modelOverride,
reasoningEffortOverride,
);

if (modelConfig) {
Expand Down Expand Up @@ -1232,6 +1240,7 @@ export function generateOpenCodeConfig({
developerInstructionsContent,
mcpServers,
model,
reasoningEffortOverride,
}: GenerateOpenCodeConfigOptions): GenerateOpenCodeConfigResult {
const openCodeConfigDir = path.join(
homeDir,
Expand All @@ -1252,6 +1261,7 @@ export function generateOpenCodeConfig({
runtimeEnv,
openCodeConfigDir,
modelOverride: resolvedModel,
reasoningEffortOverride,
});
const instructions: string[] = [];

Expand Down
10 changes: 10 additions & 0 deletions apps/worker/src/run-task/create-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ResultPromise } from 'execa';
import { type DequeuedTaskRun, sdk } from '@roomote/sdk/client';
import {
getHarnessModelOverride,
isReasoningEffort,
type EnvironmentMcpServers,
type LaunchCodingHarness,
} from '@roomote/types';
Expand Down Expand Up @@ -97,6 +98,14 @@ export async function createHarness({
harnessType,
)
: undefined;
// Per-task reasoning effort stamped at launch (or set explicitly via the
// public API). Applied to the effective coding model, which per-role env
// levels do not cover when a launch-time model override is in play.
const reasoningEffortOverride = isReasoningEffort(
taskRun.payload?.reasoningEffort,
)
? taskRun.payload.reasoningEffort
: undefined;

const commonOptions = {
workspacePath,
Expand All @@ -110,6 +119,7 @@ export async function createHarness({
await prepareQueuedPromptActorScope(userId)
: undefined,
...(modelOverride ? { modelOverride } : {}),
...(reasoningEffortOverride ? { reasoningEffortOverride } : {}),
};

return await startOpenCodeServerHarness({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { HarnessLogger } from '../../../../logging';
import {
GOOGLE_APPLICATION_CREDENTIALS_ENV_VAR_NAME,
OPENCODE_AUTH_CONTENT_ENV_VAR_NAME,
type ReasoningEffort,
} from '@roomote/types';

import {
Expand Down Expand Up @@ -158,6 +159,7 @@ export async function prepareOpenCodeCommandEnv(options: {
workspacePath: string;
mcpServers?: Record<string, unknown>;
model?: string;
reasoningEffortOverride?: ReasoningEffort;
developerInstructionsContent?: string;
logger: HarnessLogger;
}): Promise<{ commandEnv: Record<string, string>; model?: string }> {
Expand Down Expand Up @@ -188,6 +190,7 @@ export async function prepareOpenCodeCommandEnv(options: {
developerInstructionsContent: options.developerInstructionsContent,
mcpServers: normalizeOpenCodeMcpServers(parsedMcpServers, commandEnv),
model: options.model,
reasoningEffortOverride: options.reasoningEffortOverride,
});
commandEnv.OPENCODE_CONFIG_CONTENT = configContent;
commandEnv.ROOMOTE_NODE_EXECUTABLE = process.execPath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import net from 'node:net';

import { execa, type ResultPromise } from 'execa';

import type { ReasoningEffort } from '@roomote/types';

import type { HarnessLogger } from '../../../../logging';

import { createPrefixedLogger, describeUnknownError } from '../logging';
Expand All @@ -24,6 +26,7 @@ interface StartOpenCodeServerHarnessOptions {
mcpServers: Record<string, unknown>;
initialSessionId?: string;
modelOverride?: string;
reasoningEffortOverride?: ReasoningEffort;
developerInstructionsContent?: string;
/**
* Invoked when the OpenCode server subprocess exits while the task was not
Expand Down Expand Up @@ -213,6 +216,7 @@ export async function startOpenCodeServerHarness({
mcpServers,
initialSessionId,
modelOverride,
reasoningEffortOverride,
developerInstructionsContent,
onUnexpectedExit,
onDiagnostic,
Expand All @@ -225,6 +229,7 @@ export async function startOpenCodeServerHarness({
workspacePath,
mcpServers,
model: modelOverride,
reasoningEffortOverride,
developerInstructionsContent,
logger,
});
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading