ucode-agent 1.1.0 → 1.2.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.
@@ -55,28 +55,28 @@ dotenv.config({ path: join(PACKAGE_ROOT, '.env'), quiet: true });
55
55
  */
56
56
  export const MODELS = {
57
57
  'nvidia/nemotron-3-ultra-550b-a55b:free': {
58
- name: 'Nemotron 3 Ultra (free)',
58
+ name: 'Nemotron 3 Ultra',
59
59
  context: 1_000_000,
60
60
  star: true,
61
61
  note: 'deepest reasoning, 1M context — the default',
62
62
  },
63
63
  'nvidia/nemotron-3.5-lightning:free': {
64
- name: 'Nemotron 3.5 Lightning (free)',
64
+ name: 'Nemotron 3.5 Lightning',
65
65
  context: 1_000_000,
66
66
  note: 'same huge window, answers much sooner',
67
67
  },
68
68
  'nvidia/nemotron-3-super-120b-a12b:free': {
69
- name: 'Nemotron 3 Super (free)',
69
+ name: 'Nemotron 3 Super',
70
70
  context: 262_144,
71
71
  note: 'strong all-rounder, quick to first token',
72
72
  },
73
73
  'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free': {
74
- name: 'Nemotron 3 Nano Omni (free)',
74
+ name: 'Nemotron 3 Nano Omni',
75
75
  context: 256_000,
76
76
  note: 'small and fast, reasoning tuned',
77
77
  },
78
78
  'cohere/north-mini-code:free': {
79
- name: 'North Mini Code (free)',
79
+ name: 'North Mini Code',
80
80
  context: 256_000,
81
81
  star: true,
82
82
  note: 'code and UI specialist — reach for it on frontend work',
@@ -121,7 +121,7 @@ export function setModel(id) {
121
121
  return current;
122
122
  }
123
123
 
124
- /** The short name for a model id: "Nemotron 3 Ultra (free)". */
124
+ /** The short name for a model id: "Nemotron 3 Ultra". */
125
125
  export function modelName(id = current) {
126
126
  return MODELS[id]?.name ?? id;
127
127
  }
@@ -179,16 +179,18 @@ export function estimateConversation(messages) {
179
179
  * of first-run convenience is worth handing out a live credential.
180
180
  */
181
181
  function apiKey() {
182
- const key = (process.env.OPENROUTER_API_KEY ?? '').trim();
182
+ // UCODE_API_KEY is the documented name. The provider's own variable name is
183
+ // still read, so a key set up for another tool keeps working here.
184
+ const key = (process.env.UCODE_API_KEY || process.env.OPENROUTER_API_KEY || '').trim();
183
185
  if (!key) {
184
186
  throw new Failure({
185
187
  kind: 'no_api_key',
186
- attempted: 'connecting to OpenRouter',
187
- failed: 'OPENROUTER_API_KEY is not set in the environment or in any .env file.',
188
+ attempted: 'connecting to the model',
189
+ failed: 'No API key is set - UCODE_API_KEY is missing from the environment and from every .env file.',
188
190
  fix:
189
- `Put OPENROUTER_API_KEY=your-key in ${ENV_FILE} — that applies to every ` +
191
+ `Put UCODE_API_KEY=your-key in ${ENV_FILE} — that applies to every ` +
190
192
  'project on this machine — or in a .env file beside your code. ' +
191
- 'Keys are free at https://openrouter.ai/keys',
193
+ 'Free keys: https://openrouter.ai/keys',
192
194
  });
193
195
  }
194
196
  return key;
@@ -349,10 +351,10 @@ export function explain(err, id) {
349
351
  return new Failure({
350
352
  kind: 'invalid_api_key',
351
353
  attempted,
352
- failed: `OpenRouter rejected the API key (HTTP ${status ?? 401}).`,
354
+ failed: `The API key was rejected (HTTP ${status ?? 401}).`,
353
355
  fix:
354
- 'Check OPENROUTER_API_KEY for a typo or trailing space, and confirm the key ' +
355
- 'is still active at https://openrouter.ai/keys',
356
+ 'Check UCODE_API_KEY in ~/.ucode/.env for a typo or trailing space, and ' +
357
+ 'confirm the key is still active in your account.',
356
358
  cause: err,
357
359
  });
358
360
  }
@@ -380,8 +382,8 @@ export function explain(err, id) {
380
382
  ? `The free daily request cap for ${modelName(id)} is used up.`
381
383
  : `Too many requests for ${modelName(id)} just now${wait ? ` — clear in ${wait}` : ''}.`,
382
384
  fix: daily
383
- ? 'Free caps reset each day. /model switches to another one, or add credit at ' +
384
- 'https://openrouter.ai/credits to lift the ceiling.'
385
+ ? 'Free caps reset each day. /model switches to another one, or add credit to ' +
386
+ 'your account to lift the ceiling.'
385
387
  : 'ucode waits these out on its own. Free endpoints are shared, so it usually ' +
386
388
  'clears in seconds; /model moves to a quieter one.',
387
389
  detail: { retryAfter, daily },
@@ -406,7 +408,7 @@ export function explain(err, id) {
406
408
  return new Failure({
407
409
  kind: 'bad_model',
408
410
  attempted,
409
- failed: `OpenRouter has no model "${id}" available to this key.`,
411
+ failed: `No model "${id}" is available to this key.`,
410
412
  fix: `Run /model. ucode ships with: ${Object.keys(MODELS).join(', ')}`,
411
413
  cause: err,
412
414
  });
@@ -435,7 +437,7 @@ export function explain(err, id) {
435
437
  attempted,
436
438
  failed: noTools
437
439
  ? `${modelName(id)} cannot call tools, which ucode needs for every task.`
438
- : `OpenRouter rejected the request as malformed (HTTP 400): ${detail}`,
440
+ : `The request was rejected as malformed (HTTP 400): ${detail}`,
439
441
  fix: noTools
440
442
  ? 'Run /model and pick another one.'
441
443
  : 'Usually an oversized conversation. /new starts a fresh one.',
@@ -497,7 +499,7 @@ export function explain(err, id) {
497
499
  return new Failure({
498
500
  kind: 'network',
499
501
  attempted,
500
- failed: `The connection to OpenRouter dropped: ${raw}`,
502
+ failed: `The connection to the model dropped: ${raw}`,
501
503
  fix:
502
504
  'ucode retries this by itself. If it keeps happening, check your connection, ' +
503
505
  'VPN and any corporate proxy (HTTPS_PROXY) — or /model to a lighter one, since ' +
@@ -0,0 +1,16 @@
1
+ /**
2
+ * version.js — the version, read from package.json rather than typed twice.
3
+ *
4
+ * package.json always ships in an npm package, so this is right wherever ucode
5
+ * is installed, and it can never drift from what `npm publish` released.
6
+ */
7
+
8
+ import { readFileSync } from 'node:fs';
9
+
10
+ export const VERSION = (() => {
11
+ try {
12
+ return JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version;
13
+ } catch {
14
+ return '';
15
+ }
16
+ })();