orquesta-cli 0.2.88 → 0.2.90
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/cli.js +9 -0
- package/dist/core/llm/llm-client.d.ts +2 -0
- package/dist/core/llm/llm-client.js +45 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -120,6 +120,7 @@ program
|
|
|
120
120
|
.option('-p, --print [prompt]', 'Execute a prompt and exit (non-interactive mode). Omit the value to read the prompt from stdin — orquesta-agent uses this on Windows to dodge the cmd.exe command-line length limit.')
|
|
121
121
|
.option('--dangerously-skip-permissions', 'Skip all permission prompts (auto-approve)')
|
|
122
122
|
.option('--append-system-prompt <prompt>', 'Append text to the system prompt (parity with claude CLI; used by orquesta-agent sessions)')
|
|
123
|
+
.option('--append-system-prompt-file <path>', 'Read the appended system prompt from a file (orquesta-agent uses this to keep a large ~38KB system prompt out of argv — Windows CreateProcess caps the command line at 32767 chars)')
|
|
123
124
|
.option('--verbose', 'Enable verbose logging')
|
|
124
125
|
.option('--debug', 'Enable debug logging')
|
|
125
126
|
.option('--llm-log', 'Enable LLM logging')
|
|
@@ -138,6 +139,14 @@ program
|
|
|
138
139
|
.option('--update', 'Update orquesta-cli to the latest published version and exit')
|
|
139
140
|
.option('-c, --continue', 'Resume the most recent conversation session')
|
|
140
141
|
.action(async (options) => {
|
|
142
|
+
if (options.appendSystemPromptFile) {
|
|
143
|
+
try {
|
|
144
|
+
const { readFileSync } = await import('fs');
|
|
145
|
+
setAppendedSystemPrompt(readFileSync(options.appendSystemPromptFile, 'utf-8'));
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
}
|
|
149
|
+
}
|
|
141
150
|
if (options.appendSystemPrompt) {
|
|
142
151
|
setAppendedSystemPrompt(options.appendSystemPrompt);
|
|
143
152
|
}
|
|
@@ -96,7 +96,9 @@ export declare class LLMClient {
|
|
|
96
96
|
healthy: boolean;
|
|
97
97
|
latency?: number;
|
|
98
98
|
error?: string;
|
|
99
|
+
switchedToBatuta?: boolean;
|
|
99
100
|
}>;
|
|
101
|
+
private static probeEndpoint;
|
|
100
102
|
static testConnection(baseUrl: string, apiKey: string, model: string): Promise<{
|
|
101
103
|
success: boolean;
|
|
102
104
|
latency?: number;
|
|
@@ -6,6 +6,22 @@ import { LLMError, TokenLimitError, RateLimitError, ContextLengthError, } from '
|
|
|
6
6
|
import { logger, isLLMLogEnabled } from '../../utils/logger.js';
|
|
7
7
|
import { usageTracker } from '../usage-tracker.js';
|
|
8
8
|
import { getForcedTier, getBatutaSessionId, setLastBatutaRoute } from '../routing-state.js';
|
|
9
|
+
function safeStringify(value, space) {
|
|
10
|
+
const seen = new WeakSet();
|
|
11
|
+
try {
|
|
12
|
+
return JSON.stringify(value, (_key, val) => {
|
|
13
|
+
if (typeof val === 'object' && val !== null) {
|
|
14
|
+
if (seen.has(val))
|
|
15
|
+
return '[Circular]';
|
|
16
|
+
seen.add(val);
|
|
17
|
+
}
|
|
18
|
+
return val;
|
|
19
|
+
}, space);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return String(value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
9
25
|
function extractTopLevelJsonObjects(s) {
|
|
10
26
|
const objects = [];
|
|
11
27
|
let depth = 0;
|
|
@@ -972,11 +988,11 @@ export class LLMClient {
|
|
|
972
988
|
errorMessage,
|
|
973
989
|
errorType,
|
|
974
990
|
errorCode,
|
|
975
|
-
responseBody:
|
|
991
|
+
responseBody: safeStringify(data, 2),
|
|
976
992
|
requestMethod: requestContext?.method,
|
|
977
993
|
requestUrl: requestContext?.url,
|
|
978
994
|
requestBody: requestContext?.body
|
|
979
|
-
?
|
|
995
|
+
? safeStringify(requestContext.body, 2).substring(0, 5000)
|
|
980
996
|
: undefined,
|
|
981
997
|
responseHeaders: axiosError.response.headers,
|
|
982
998
|
});
|
|
@@ -1033,6 +1049,16 @@ export class LLMClient {
|
|
|
1033
1049
|
},
|
|
1034
1050
|
});
|
|
1035
1051
|
}
|
|
1052
|
+
if (status === 402) {
|
|
1053
|
+
logger.error('Batuta not available (402)', { errorMessage });
|
|
1054
|
+
return new APIError(errorMessage || 'Payment required', 402, this.baseUrl, {
|
|
1055
|
+
isRecoverable: false,
|
|
1056
|
+
cause: axiosError,
|
|
1057
|
+
userMessage: `Batuta isn't available for this account (402): ${errorMessage || 'add-on required'}.\n` +
|
|
1058
|
+
`Enable the Batuta add-on for your organization in the Orquesta dashboard, or point the CLI at a local LLM provider.`,
|
|
1059
|
+
details: { endpoint: this.baseUrl, fullError: data },
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1036
1062
|
if (status === 401) {
|
|
1037
1063
|
logger.error('Authentication Failed', {
|
|
1038
1064
|
endpoint: this.baseUrl,
|
|
@@ -1276,6 +1302,22 @@ export class LLMClient {
|
|
|
1276
1302
|
if (!endpoint || !model) {
|
|
1277
1303
|
return { healthy: false, error: 'No endpoint/model configured' };
|
|
1278
1304
|
}
|
|
1305
|
+
const first = await LLMClient.probeEndpoint(endpoint, model.id);
|
|
1306
|
+
if (first.healthy)
|
|
1307
|
+
return first;
|
|
1308
|
+
const batuta = configManager.getAllEndpoints().find((e) => e.id === 'batuta-proxy' || e.provider === 'batuta');
|
|
1309
|
+
if (batuta && batuta.apiKey && batuta.id !== endpoint.id) {
|
|
1310
|
+
const m = batuta.models.find((x) => x.enabled) || batuta.models[0];
|
|
1311
|
+
if (m) {
|
|
1312
|
+
await configManager.setCurrentEndpoint(batuta.id);
|
|
1313
|
+
await configManager.setCurrentModel(m.id);
|
|
1314
|
+
const second = await LLMClient.probeEndpoint(batuta, m.id);
|
|
1315
|
+
return { ...second, switchedToBatuta: true };
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return first;
|
|
1319
|
+
}
|
|
1320
|
+
static async probeEndpoint(endpoint, modelId) {
|
|
1279
1321
|
const startTime = Date.now();
|
|
1280
1322
|
try {
|
|
1281
1323
|
const axiosInstance = axios.create({
|
|
@@ -1287,7 +1329,7 @@ export class LLMClient {
|
|
|
1287
1329
|
timeout: 10000,
|
|
1288
1330
|
});
|
|
1289
1331
|
const response = await axiosInstance.post('/chat/completions', {
|
|
1290
|
-
model:
|
|
1332
|
+
model: modelId,
|
|
1291
1333
|
messages: [{ role: 'user', content: 'ping' }],
|
|
1292
1334
|
max_tokens: 1,
|
|
1293
1335
|
});
|