@cloudcli-ai/cloudcli 1.35.1 → 1.36.0
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/api-docs.html +8 -2
- package/dist/assets/{index-D1IdCTT6.js → index-S6cIy7hj.js} +260 -260
- package/dist/assets/index-uLUE6Qt1.css +32 -0
- package/dist/index.html +2 -2
- package/dist-server/server/claude-sdk.js +25 -26
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +70 -1
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +52 -11
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +138 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js +5 -0
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-models.service.js +1 -1
- package/dist-server/server/modules/providers/tests/opencode-models.test.js +58 -1
- package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
- package/dist-server/server/openai-codex.js +9 -8
- package/dist-server/server/openai-codex.js.map +1 -1
- package/dist-server/server/opencode-cli.js +20 -2
- package/dist-server/server/opencode-cli.js.map +1 -1
- package/dist-server/server/routes/agent.js +14 -3
- package/dist-server/server/routes/agent.js.map +1 -1
- package/package.json +1 -1
- package/public/api-docs.html +8 -2
- package/server/claude-sdk.js +32 -26
- package/server/modules/providers/list/claude/claude-models.provider.ts +73 -1
- package/server/modules/providers/list/codex/codex-models.provider.ts +59 -11
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +180 -1
- package/server/modules/providers/services/provider-capabilities.service.ts +7 -0
- package/server/modules/providers/services/provider-models.service.ts +1 -1
- package/server/modules/providers/tests/opencode-models.test.ts +62 -0
- package/server/openai-codex.js +9 -7
- package/server/opencode-cli.js +21 -2
- package/server/routes/agent.js +14 -3
- package/server/shared/types.ts +7 -0
- package/dist/assets/index-BvX30NW5.css +0 -32
|
@@ -2,8 +2,10 @@ import assert from 'node:assert/strict';
|
|
|
2
2
|
import test from 'node:test';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
buildOpenCodeDefinitionFromVerboseModels,
|
|
5
6
|
buildOpenCodeDefinitionFromIds,
|
|
6
7
|
parseOpenCodeModelsStdout,
|
|
8
|
+
parseOpenCodeVerboseModelsStdout,
|
|
7
9
|
} from '@/modules/providers/list/opencode/opencode-models.provider.js';
|
|
8
10
|
|
|
9
11
|
test('OpenCode models provider parses plain CLI output and removes duplicates', () => {
|
|
@@ -71,3 +73,63 @@ test('OpenCode models provider formats frontend labels from provider-prefixed id
|
|
|
71
73
|
},
|
|
72
74
|
]);
|
|
73
75
|
});
|
|
76
|
+
|
|
77
|
+
test('OpenCode models provider maps verbose model variants to effort options', () => {
|
|
78
|
+
const models = parseOpenCodeVerboseModelsStdout(`
|
|
79
|
+
opencode/deepseek-v4-flash-free
|
|
80
|
+
{
|
|
81
|
+
"id": "deepseek-v4-flash-free",
|
|
82
|
+
"providerID": "opencode",
|
|
83
|
+
"name": "DeepSeek V4 Flash Free",
|
|
84
|
+
"variants": {
|
|
85
|
+
"low": {
|
|
86
|
+
"reasoningEffort": "low"
|
|
87
|
+
},
|
|
88
|
+
"high": {
|
|
89
|
+
"reasoningEffort": "high"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
anthropic/claude-sonnet-5
|
|
94
|
+
{
|
|
95
|
+
"id": "claude-sonnet-5",
|
|
96
|
+
"providerID": "anthropic",
|
|
97
|
+
"name": "Claude Sonnet 5",
|
|
98
|
+
"variants": {
|
|
99
|
+
"low": {
|
|
100
|
+
"effort": "low"
|
|
101
|
+
},
|
|
102
|
+
"max": {
|
|
103
|
+
"effort": "max"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`);
|
|
108
|
+
|
|
109
|
+
const definition = buildOpenCodeDefinitionFromVerboseModels(models);
|
|
110
|
+
|
|
111
|
+
assert.deepEqual(definition.OPTIONS, [
|
|
112
|
+
{
|
|
113
|
+
value: 'opencode/deepseek-v4-flash-free',
|
|
114
|
+
label: 'DeepSeek V4 Flash Free',
|
|
115
|
+
description: 'opencode - opencode/deepseek-v4-flash-free',
|
|
116
|
+
effort: {
|
|
117
|
+
values: [
|
|
118
|
+
{ value: 'low' },
|
|
119
|
+
{ value: 'high' },
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
value: 'anthropic/claude-sonnet-5',
|
|
125
|
+
label: 'Claude Sonnet 5',
|
|
126
|
+
description: 'anthropic - anthropic/claude-sonnet-5',
|
|
127
|
+
effort: {
|
|
128
|
+
values: [
|
|
129
|
+
{ value: 'low' },
|
|
130
|
+
{ value: 'max' },
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
]);
|
|
135
|
+
});
|
package/server/openai-codex.js
CHANGED
|
@@ -20,7 +20,6 @@ import { providerAuthService } from './modules/providers/services/provider-auth.
|
|
|
20
20
|
import { providerModelsService } from './modules/providers/services/provider-models.service.js';
|
|
21
21
|
import { createCompleteMessage, createNormalizedMessage } from './shared/utils.js';
|
|
22
22
|
|
|
23
|
-
// Track active sessions
|
|
24
23
|
const activeCodexSessions = new Map();
|
|
25
24
|
|
|
26
25
|
function readUsageNumber(value) {
|
|
@@ -228,6 +227,7 @@ export async function queryCodex(command, options = {}, ws) {
|
|
|
228
227
|
cwd,
|
|
229
228
|
projectPath,
|
|
230
229
|
model,
|
|
230
|
+
effort,
|
|
231
231
|
permissionMode = 'default'
|
|
232
232
|
} = options;
|
|
233
233
|
|
|
@@ -239,6 +239,12 @@ export async function queryCodex(command, options = {}, ws) {
|
|
|
239
239
|
|
|
240
240
|
const workingDirectory = cwd || projectPath || process.cwd();
|
|
241
241
|
const { sandboxMode, approvalPolicy } = mapPermissionModeToCodexOptions(permissionMode);
|
|
242
|
+
const catalog = (await providerModelsService.getProviderModels('codex')).models;
|
|
243
|
+
const selectedModel = catalog.OPTIONS.find((option) => option.value === resolvedModel) || null;
|
|
244
|
+
const allowedEfforts = selectedModel?.effort?.values?.map((value) => value.value) || [];
|
|
245
|
+
const resolvedEffort = typeof effort === 'string' && effort !== 'default' && allowedEfforts.includes(effort)
|
|
246
|
+
? effort
|
|
247
|
+
: undefined;
|
|
242
248
|
|
|
243
249
|
let codex;
|
|
244
250
|
let thread;
|
|
@@ -248,19 +254,17 @@ export async function queryCodex(command, options = {}, ws) {
|
|
|
248
254
|
const abortController = new AbortController();
|
|
249
255
|
|
|
250
256
|
try {
|
|
251
|
-
// Initialize Codex SDK
|
|
252
257
|
codex = new Codex();
|
|
253
258
|
|
|
254
|
-
// Thread options with sandbox and approval settings
|
|
255
259
|
const threadOptions = {
|
|
256
260
|
workingDirectory,
|
|
257
261
|
skipGitRepoCheck: true,
|
|
258
262
|
sandboxMode,
|
|
259
263
|
approvalPolicy,
|
|
260
|
-
model: resolvedModel
|
|
264
|
+
model: resolvedModel,
|
|
265
|
+
modelReasoningEffort: resolvedEffort,
|
|
261
266
|
};
|
|
262
267
|
|
|
263
|
-
// Start or resume thread
|
|
264
268
|
if (sessionId) {
|
|
265
269
|
thread = codex.resumeThread(sessionId, threadOptions);
|
|
266
270
|
} else {
|
|
@@ -280,12 +284,10 @@ export async function queryCodex(command, options = {}, ws) {
|
|
|
280
284
|
});
|
|
281
285
|
};
|
|
282
286
|
|
|
283
|
-
// Existing sessions can be tracked immediately; new sessions are tracked after thread.started.
|
|
284
287
|
if (capturedSessionId) {
|
|
285
288
|
registerSession(capturedSessionId);
|
|
286
289
|
}
|
|
287
290
|
|
|
288
|
-
// Execute with streaming
|
|
289
291
|
const streamedTurn = await thread.runStreamed(command, {
|
|
290
292
|
signal: abortController.signal
|
|
291
293
|
});
|
package/server/opencode-cli.js
CHANGED
|
@@ -14,6 +14,14 @@ const spawnFunction = process.platform === 'win32' ? crossSpawn : spawn;
|
|
|
14
14
|
|
|
15
15
|
const activeOpenCodeProcesses = new Map();
|
|
16
16
|
|
|
17
|
+
function resolveOpenCodeEffort(model, effort, modelsDefinition) {
|
|
18
|
+
const selectedModel = modelsDefinition?.OPTIONS?.find((option) => option.value === model);
|
|
19
|
+
const allowedEfforts = selectedModel?.effort?.values?.map((value) => value.value) || [];
|
|
20
|
+
return typeof effort === 'string' && effort !== 'default' && allowedEfforts.includes(effort)
|
|
21
|
+
? effort
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
function readOpenCodeSessionId(event) {
|
|
18
26
|
if (!event || typeof event !== 'object') {
|
|
19
27
|
return null;
|
|
@@ -84,7 +92,7 @@ function readOpenCodeTokenUsage(sessionId) {
|
|
|
84
92
|
|
|
85
93
|
async function spawnOpenCode(command, options = {}, ws) {
|
|
86
94
|
return new Promise((resolve, reject) => {
|
|
87
|
-
const { sessionId, projectPath, cwd, model, sessionSummary } = options;
|
|
95
|
+
const { sessionId, projectPath, cwd, model, effort, sessionSummary } = options;
|
|
88
96
|
const workingDir = cwd || projectPath || process.cwd();
|
|
89
97
|
const processKey = sessionId || Date.now().toString();
|
|
90
98
|
let capturedSessionId = sessionId || null;
|
|
@@ -192,7 +200,15 @@ async function spawnOpenCode(command, options = {}, ws) {
|
|
|
192
200
|
}
|
|
193
201
|
};
|
|
194
202
|
|
|
195
|
-
void providerModelsService.resolveResumeModel('opencode', sessionId, model).then((resolvedModel) => {
|
|
203
|
+
void providerModelsService.resolveResumeModel('opencode', sessionId, model).then(async (resolvedModel) => {
|
|
204
|
+
let effortModels = null;
|
|
205
|
+
try {
|
|
206
|
+
effortModels = (await providerModelsService.getProviderModels('opencode')).models;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.warn('[OpenCode] Unable to load provider models for effort validation:', error);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const resolvedEffort = resolveOpenCodeEffort(resolvedModel, effort, effortModels);
|
|
196
212
|
const args = ['run', '--format', 'json'];
|
|
197
213
|
// OpenCode's `run` command owns workspace selection through `--dir`.
|
|
198
214
|
// Relying on the child-process cwd alone is not enough on Linux, where
|
|
@@ -204,6 +220,9 @@ async function spawnOpenCode(command, options = {}, ws) {
|
|
|
204
220
|
if (resolvedModel) {
|
|
205
221
|
args.push('--model', resolvedModel);
|
|
206
222
|
}
|
|
223
|
+
if (resolvedEffort) {
|
|
224
|
+
args.push('--variant', resolvedEffort);
|
|
225
|
+
}
|
|
207
226
|
if (command && command.trim()) {
|
|
208
227
|
args.push(command.trim());
|
|
209
228
|
}
|
package/server/routes/agent.js
CHANGED
|
@@ -646,12 +646,17 @@ class ResponseCollector {
|
|
|
646
646
|
*
|
|
647
647
|
* @param {string} model - (Optional) Model identifier for providers.
|
|
648
648
|
*
|
|
649
|
-
* Claude models: 'sonnet'
|
|
649
|
+
* Claude models: 'default', 'sonnet', 'opus', 'haiku', 'sonnet[1m]', 'opus[1m]', 'fable'
|
|
650
650
|
* Cursor models: 'gpt-5' (default), 'gpt-5.2', 'gpt-5.2-high', 'sonnet-4.5', 'opus-4.5',
|
|
651
651
|
* 'gemini-3-pro', 'composer-1', 'auto', 'gpt-5.1', 'gpt-5.1-high',
|
|
652
652
|
* 'gpt-5.1-codex', 'gpt-5.1-codex-high', 'gpt-5.1-codex-max',
|
|
653
653
|
* 'gpt-5.1-codex-max-high', 'opus-4.1', 'grok', and thinking variants
|
|
654
|
-
* Codex models: 'gpt-5.
|
|
654
|
+
* Codex models: 'gpt-5.4' (default), 'gpt-5.5', 'gpt-5.4-mini'
|
|
655
|
+
*
|
|
656
|
+
* @param {string} effort - (Optional) Reasoning effort for providers/models that support it.
|
|
657
|
+
* Claude supports: 'low', 'medium', 'high', 'xhigh', 'max' depending on model.
|
|
658
|
+
* Codex supports: 'low', 'medium', 'high', 'xhigh'.
|
|
659
|
+
* 'default' or omission lets the provider decide.
|
|
655
660
|
*
|
|
656
661
|
* @param {boolean} cleanup - (Optional) Auto-cleanup project directory after completion.
|
|
657
662
|
* Default: true
|
|
@@ -844,6 +849,9 @@ class ResponseCollector {
|
|
|
844
849
|
*/
|
|
845
850
|
router.post('/', validateExternalApiKey, async (req, res) => {
|
|
846
851
|
const { githubUrl, projectPath, message, provider = 'claude', model, githubToken, branchName, sessionId } = req.body;
|
|
852
|
+
const effort = typeof req.body.effort === 'string' && req.body.effort.trim()
|
|
853
|
+
? req.body.effort.trim()
|
|
854
|
+
: undefined;
|
|
847
855
|
|
|
848
856
|
// Parse stream and cleanup as booleans (handle string "true"/"false" from curl)
|
|
849
857
|
const stream = req.body.stream === undefined ? true : (req.body.stream === true || req.body.stream === 'true');
|
|
@@ -954,6 +962,7 @@ router.post('/', validateExternalApiKey, async (req, res) => {
|
|
|
954
962
|
cwd: finalProjectPath,
|
|
955
963
|
sessionId: sessionId || null,
|
|
956
964
|
model: model,
|
|
965
|
+
effort,
|
|
957
966
|
permissionMode: 'bypassPermissions' // Bypass all permissions for API calls
|
|
958
967
|
}, writer);
|
|
959
968
|
|
|
@@ -975,6 +984,7 @@ router.post('/', validateExternalApiKey, async (req, res) => {
|
|
|
975
984
|
cwd: finalProjectPath,
|
|
976
985
|
sessionId: sessionId || null,
|
|
977
986
|
model: model || codexModels.DEFAULT,
|
|
987
|
+
effort,
|
|
978
988
|
permissionMode: 'bypassPermissions'
|
|
979
989
|
}, writer);
|
|
980
990
|
} else if (provider === 'gemini') {
|
|
@@ -994,7 +1004,8 @@ router.post('/', validateExternalApiKey, async (req, res) => {
|
|
|
994
1004
|
projectPath: finalProjectPath,
|
|
995
1005
|
cwd: finalProjectPath,
|
|
996
1006
|
sessionId: sessionId || null,
|
|
997
|
-
model: model || opencodeModels.DEFAULT
|
|
1007
|
+
model: model || opencodeModels.DEFAULT,
|
|
1008
|
+
effort
|
|
998
1009
|
}, writer);
|
|
999
1010
|
}
|
|
1000
1011
|
|
package/server/shared/types.ts
CHANGED