feat(ai): support opencode variant setting

This commit is contained in:
Guillaume ARM 2026-06-11 23:28:41 +02:00
parent 3cea167261
commit 93a4ad2395
7 changed files with 102 additions and 5 deletions

View File

@ -9,6 +9,7 @@ local DEFAULT_LUA_EXEC_MAX_RETRIES = 2;
local DEFAULT_LUA_EXEC_TIMEOUT_SECONDS = 5;
local DEFAULT_SESSION_SETTING_KEY = 'opencc.session_id';
local DEFAULT_AGENT_SETTING_KEY = 'opencc.agent';
local DEFAULT_VARIANT_SETTING_KEY = 'opencc.variant';
local createHttp = require('/apis/libhttp');
@ -216,6 +217,13 @@ local function createAi(opts)
return agent;
end
local function resolveVariant(options)
local variant = options.variant;
if variant == nil then variant = settingsLib.get(DEFAULT_VARIANT_SETTING_KEY); end
if isBlank(variant) then return nil; end
return variant;
end
local function resolveConfig(options)
local url = options.serverUrl or settingsLib.get('opencc.server_url');
if not url or url == '' then
@ -233,6 +241,7 @@ local function createAi(opts)
providerID = providerId,
modelID = modelId,
agent = resolveAgent(options),
variant = resolveVariant(options),
timeoutSeconds = resolveTimeout(options),
pollTimeoutSeconds = resolvePollTimeout(options),
pollIntervalSeconds = resolvePollInterval(options),
@ -250,6 +259,9 @@ local function createAi(opts)
if cfg.agent then
body.agent = cfg.agent;
end
if cfg.variant then
body.variant = cfg.variant;
end
return body;
end
@ -263,6 +275,9 @@ local function createAi(opts)
if cfg.agent then
body.agent = cfg.agent;
end
if cfg.variant then
body.variant = cfg.variant;
end
return body;
end
@ -677,6 +692,7 @@ local function createAi(opts)
providerID = options.providerID,
modelID = options.modelID,
agent = options.agent,
variant = options.variant,
timeoutSeconds = options.timeoutSeconds,
};
end

View File

@ -1,6 +1,6 @@
{
"name": "TrapOS",
"version": "0.8.15",
"version": "0.8.16",
"branch": "next",
"packages": [
"trapos"

View File

@ -5,8 +5,8 @@
"trapos-boot": "0.3.2",
"trapos-net": "0.3.0",
"trapos-ui": "0.2.2",
"trapos-ai": "0.6.13",
"trapos-ai": "0.6.14",
"trapos-sandbox": "0.2.2",
"trapos": "0.8.15"
"trapos": "0.8.16"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "trapos-ai",
"version": "0.6.13",
"version": "0.6.14",
"description": "TrapOS AI client for opencode serve",
"dependencies": ["trapos-core"],
"files": [

View File

@ -1,6 +1,6 @@
{
"name": "trapos",
"version": "0.8.15",
"version": "0.8.16",
"description": "TrapOS full install meta-package",
"dependencies": [
"trapos-boot",

View File

@ -50,6 +50,7 @@ local function printUsage()
print(' opencc.session_id (auto-managed)');
print(' opencc.directory (optional session list scope)');
print(' opencc.agent (e.g. atm10-expert)');
print(' opencc.variant (e.g. low)');
print(' opencc.provider_id (e.g. anthropic)');
print(' opencc.model_id (e.g. claude-opus-4-7)');
print(' opencc.timeout_seconds (per HTTP call, max 60)');

View File

@ -588,6 +588,42 @@ testlib.test('ask omits blank agent setting', function()
testlib.assertEquals(body.agent, nil);
end);
testlib.test('ask includes variant when setting is set', function()
local httpStub = fakeHttp(
{ messageResp('reply') },
{}
);
local settingsStub = fakeSettings({
['opencc.server_url'] = 'http://host',
['opencc.session_id'] = 'ses_1',
['opencc.variant'] = 'low',
});
local ai = createAi({ http = httpStub, settings = settingsStub });
ai.ask('hello');
local body = textutils.unserializeJSON(httpStub.postCalls[1].body);
testlib.assertEquals(body.variant, 'low');
end);
testlib.test('ask omits blank variant setting', function()
local httpStub = fakeHttp(
{ messageResp('reply') },
{}
);
local settingsStub = fakeSettings({
['opencc.server_url'] = 'http://host',
['opencc.session_id'] = 'ses_1',
['opencc.variant'] = ' ',
});
local ai = createAi({ http = httpStub, settings = settingsStub });
ai.ask('hello');
local body = textutils.unserializeJSON(httpStub.postCalls[1].body);
testlib.assertEquals(body.variant, nil);
end);
testlib.test('ask includes model when provider_id and model_id are set', function()
local httpStub = fakeHttp(
{ messageResp('reply') },
@ -681,6 +717,24 @@ testlib.test('ask options providerID/modelID override settings', function()
testlib.assertEquals(body.model.modelID, 'gpt-5');
end);
testlib.test('ask options variant overrides setting', function()
local httpStub = fakeHttp(
{ messageResp('reply') },
{}
);
local settingsStub = fakeSettings({
['opencc.server_url'] = 'http://host',
['opencc.session_id'] = 'ses_1',
['opencc.variant'] = 'high',
});
local ai = createAi({ http = httpStub, settings = settingsStub });
ai.ask('hello', { variant = 'low' });
local body = textutils.unserializeJSON(httpStub.postCalls[1].body);
testlib.assertEquals(body.variant, 'low');
end);
testlib.test('ask generates opencode-compatible message ids', function()
local httpStub = fakeHttp(
{ messageResp('reply') },
@ -727,6 +781,32 @@ testlib.test('ask includes agent in async prompts', function()
testlib.assertEquals(body.agent, 'atm10-expert');
end);
testlib.test('ask includes variant in async prompts', function()
local httpStub = fakeHttp(
{ asyncResp() },
{
messageListResp({ assistantMessage('msg_1', 'reply', true) }),
}
);
local settingsStub = fakeAsyncSettings({
['opencc.session_id'] = 'ses_1',
['opencc.variant'] = 'low',
});
local elFactory = fakeEventloopFactory();
local ai = createAi({
http = httpStub,
settings = settingsStub,
now = function() return 10; end,
eventloop = elFactory,
});
local ok = ai.ask('hello', { messageId = 'msg_1' });
testlib.assertTrue(ok);
local body = textutils.unserializeJSON(httpStub.postCalls[1].body);
testlib.assertEquals(body.variant, 'low');
end);
testlib.test('ask includes caller context in async prompts', function()
local httpStub = fakeHttp(
{ asyncResp() },