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
18 changes: 18 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.

8 changes: 8 additions & 0 deletions apps/worker/src/run-task/agent-home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as path from 'node:path';
import {
createRoomoteAdvisorAgentPrompt,
createRoomoteJudgeAgentPrompt,
OPENCODE_IDENTITY_PLUGIN_SCRIPT,
ROOMOTE_OPENCODE_ADVISOR_AGENT_DESCRIPTION,
ROOMOTE_OPENCODE_ADVISOR_AGENT_NAME,
ROOMOTE_OPENCODE_JUDGE_AGENT_DESCRIPTION,
Expand Down Expand Up @@ -180,6 +181,8 @@ const ROOMOTE_OPENCODE_CHATGPT_GATEWAY_PLUGIN_FILE_NAME =

const ROOMOTE_OPENCODE_TOOL_SAFETY_PLUGIN_FILE_NAME = 'roomote-tool-safety.js';

const ROOMOTE_OPENCODE_IDENTITY_PLUGIN_FILE_NAME = 'roomote-identity.js';

const OPENCODE_ALLOW_ALL_PERMISSION = {
read: 'allow',
edit: 'allow',
Expand Down Expand Up @@ -653,6 +656,10 @@ function writeOpenCodeManagedFiles(openCodeConfigDir: string): void {
pluginsDir,
ROOMOTE_OPENCODE_TOOL_SAFETY_PLUGIN_FILE_NAME,
);
const identityPluginPath = path.join(
pluginsDir,
ROOMOTE_OPENCODE_IDENTITY_PLUGIN_FILE_NAME,
);
const silenceHookPath = path.join(
openCodeConfigDir,
ROOMOTE_OPENCODE_SLACK_SILENCE_HOOK_FILE_NAME,
Expand All @@ -674,6 +681,7 @@ function writeOpenCodeManagedFiles(openCodeConfigDir: string): void {
OPENCODE_TOOL_SAFETY_PLUGIN_SCRIPT,
'utf8',
);
fs.writeFileSync(identityPluginPath, OPENCODE_IDENTITY_PLUGIN_SCRIPT, 'utf8');
fs.writeFileSync(silenceHookPath, SLACK_SILENCE_HOOK_SCRIPT, 'utf8');
fs.writeFileSync(stopHookPath, SLACK_STOP_HOOK_SCRIPT, 'utf8');
fs.chmodSync(silenceHookPath, 0o755);
Expand Down

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

1 change: 1 addition & 0 deletions packages/cloud-agents/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export {
export { resolveRoomoteReleaseVersion } from './release-version';
export * from './style-guidance';
export * from './opencode-prompt-subagents';
export { OPENCODE_IDENTITY_PLUGIN_SCRIPT } from './opencode-identity-plugin';
export {
DEFAULT_STANDARD_TASK_MODEL,
DEFAULT_STANDARD_TASK_MODEL_PROVIDER,
Expand Down
13 changes: 13 additions & 0 deletions packages/cloud-agents/src/opencode-identity-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* OpenCode 1.18.10 prefixes its model-specific system prompt with its own
* product identity. Roomote supplies the product identity in later prompt
* layers, so remove only that prefix and preserve the remaining instructions.
*/
export const OPENCODE_IDENTITY_PLUGIN_SCRIPT = `export const RoomoteOpenCodeIdentity = async () => ({
'experimental.chat.system.transform': async (_input, output) => {
if (typeof output.system?.[0] === 'string') {
output.system[0] = output.system[0].replace(/^You are OpenCode,\\s*/iu, '');
}
},
});
`;

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

23 changes: 23 additions & 0 deletions packages/cloud-agents/src/server/opencode-runtime.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { execFileSync, spawn, type ChildProcess } from 'node:child_process';
import { createHash } from 'node:crypto';
import { mkdtempSync, writeFileSync } from 'node:fs';
import { createServer } from 'node:net';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';

import {
collectOpenRouterVariantModelAlias,
Expand Down Expand Up @@ -28,6 +32,7 @@ import {
ROOMOTE_OPENCODE_JUDGE_AGENT_DESCRIPTION,
ROOMOTE_OPENCODE_JUDGE_AGENT_NAME,
} from '../opencode-prompt-subagents';
import { OPENCODE_IDENTITY_PLUGIN_SCRIPT } from '../opencode-identity-plugin';
import { FAST_AGENT_SUBAGENT_TOOL_FILTER } from './fast-agent/fast-agent-tool-policy';

const ESCAPE_CHARACTER = String.fromCharCode(27);
Expand Down Expand Up @@ -221,6 +226,23 @@ type NonTaskOpenCodeRuntimeOptions = {
promptOnlySubagents?: boolean;
};

let openCodeIdentityPluginUrl: string | undefined;

function getOpenCodeIdentityPluginUrl(): string {
if (openCodeIdentityPluginUrl) {
return openCodeIdentityPluginUrl;
}

const directory = mkdtempSync(join(tmpdir(), 'roomote-opencode-identity-'));
const pluginPath = join(directory, 'roomote-identity.mjs');
writeFileSync(pluginPath, OPENCODE_IDENTITY_PLUGIN_SCRIPT, {
encoding: 'utf8',
mode: 0o600,
});
openCodeIdentityPluginUrl = pathToFileURL(pluginPath).href;
return openCodeIdentityPluginUrl;
}

function buildRestrictedNonTaskConfig(
options: NonTaskOpenCodeRuntimeOptions,
): Record<string, unknown> {
Expand All @@ -230,6 +252,7 @@ function buildRestrictedNonTaskConfig(

return {
agent: PROMPT_ONLY_SUBAGENTS,
plugin: [getOpenCodeIdentityPluginUrl()],
Comment thread
roomote-roomote[bot] marked this conversation as resolved.
permission: { ...NON_TASK_TOOL_PERMISSION_DENIALS, task: 'allow' },
};
}
Expand Down
Loading