open-agents-ai 0.103.37 → 0.103.38

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.
Files changed (2) hide show
  1. package/dist/index.js +107 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12607,30 +12607,74 @@ async function handleCmd(cmd) {
12607
12607
  dlog('expose: auth key configured (' + exposeAuthKey.length + ' chars)');
12608
12608
  }
12609
12609
 
12610
- // Query Ollama for available models
12610
+ // Passthrough mode: forward from a remote /endpoint (Chutes, Groq, etc.)
12611
+ var isPassthrough = args.passthrough === 'true';
12612
+ var endpointAuth = args.endpoint_auth || '';
12613
+ if (isPassthrough) {
12614
+ dlog('expose: PASSTHROUGH mode \u2014 forwarding from upstream endpoint');
12615
+ }
12616
+
12617
+ // Query models from the backend
12611
12618
  const ollamaUrl = args.ollama_url || process.env.OLLAMA_URL || 'http://localhost:11434';
12612
12619
  let models = [];
12613
- try {
12614
- const tagsResp = await fetch(ollamaUrl + '/api/tags');
12615
- if (tagsResp.ok) {
12616
- const tagsData = await tagsResp.json();
12617
- models = (tagsData.models || []).map(m => ({
12618
- name: m.name,
12619
- size: m.size || 0,
12620
- parameterSize: m.details?.parameter_size || '',
12621
- family: m.details?.family || '',
12622
- quantization: m.details?.quantization_level || '',
12623
- }));
12620
+
12621
+ if (isPassthrough) {
12622
+ // Passthrough: query /v1/models from the upstream endpoint (OpenAI-compatible)
12623
+ try {
12624
+ var modelsHeaders = { 'Content-Type': 'application/json' };
12625
+ if (endpointAuth) modelsHeaders['Authorization'] = 'Bearer ' + endpointAuth;
12626
+ var modelsUrl = ollamaUrl.replace(/\\/+$/, '') + '/v1/models';
12627
+ dlog('expose: passthrough querying models from ' + modelsUrl);
12628
+ const modelsResp = await fetch(modelsUrl, { headers: modelsHeaders });
12629
+ if (modelsResp.ok) {
12630
+ const modelsData = await modelsResp.json();
12631
+ var modelList = modelsData.data || modelsData.models || [];
12632
+ models = modelList.map(function(m) {
12633
+ return {
12634
+ name: m.id || m.name || 'unknown',
12635
+ size: 0,
12636
+ parameterSize: '',
12637
+ family: m.owned_by || '',
12638
+ quantization: '',
12639
+ };
12640
+ });
12641
+ } else {
12642
+ var errText = '';
12643
+ try { errText = await modelsResp.text(); } catch {}
12644
+ writeResp(id, { ok: false, output: 'Upstream /v1/models returned ' + modelsResp.status + ': ' + errText.slice(0, 200) });
12645
+ return;
12646
+ }
12647
+ } catch (e) {
12648
+ writeResp(id, { ok: false, output: 'Cannot reach upstream endpoint at ' + ollamaUrl + ': ' + e.message });
12649
+ return;
12650
+ }
12651
+ } else {
12652
+ // Local Ollama: query /api/tags
12653
+ try {
12654
+ const tagsResp = await fetch(ollamaUrl + '/api/tags');
12655
+ if (tagsResp.ok) {
12656
+ const tagsData = await tagsResp.json();
12657
+ models = (tagsData.models || []).map(function(m) {
12658
+ return {
12659
+ name: m.name,
12660
+ size: m.size || 0,
12661
+ parameterSize: m.details ? m.details.parameter_size || '' : '',
12662
+ family: m.details ? m.details.family || '' : '',
12663
+ quantization: m.details ? m.details.quantization_level || '' : '',
12664
+ };
12665
+ });
12666
+ }
12667
+ } catch (e) {
12668
+ writeResp(id, { ok: false, output: 'Cannot reach Ollama at ' + ollamaUrl + ': ' + e.message });
12669
+ return;
12624
12670
  }
12625
- } catch (e) {
12626
- writeResp(id, { ok: false, output: 'Cannot reach Ollama at ' + ollamaUrl + ': ' + e.message });
12627
- return;
12628
12671
  }
12629
12672
 
12630
12673
  if (models.length === 0) {
12631
- writeResp(id, { ok: false, output: 'No models found on Ollama. Pull a model first.' });
12674
+ writeResp(id, { ok: false, output: isPassthrough ? 'No models found on upstream endpoint.' : 'No models found on Ollama. Pull a model first.' });
12632
12675
  return;
12633
12676
  }
12677
+ dlog('expose: found ' + models.length + ' models' + (isPassthrough ? ' (passthrough)' : ''));
12634
12678
 
12635
12679
  // Fetch market rates from OpenRouter (free, no auth)
12636
12680
  let marketRates = {};
@@ -12782,10 +12826,12 @@ async function handleCmd(cmd) {
12782
12826
  if (parsedReq.temperature !== undefined) chatBody.temperature = parsedReq.temperature;
12783
12827
  if (parsedReq.max_tokens) chatBody.max_tokens = parsedReq.max_tokens;
12784
12828
 
12785
- dlog('expose: calling /v1/chat/completions with ' + chatBody.messages.length + ' messages, tools=' + (chatBody.tools ? chatBody.tools.length : 0));
12829
+ var chatHeaders = { 'Content-Type': 'application/json' };
12830
+ if (isPassthrough && endpointAuth) chatHeaders['Authorization'] = 'Bearer ' + endpointAuth;
12831
+ dlog('expose: calling /v1/chat/completions with ' + chatBody.messages.length + ' messages, tools=' + (chatBody.tools ? chatBody.tools.length : 0) + (isPassthrough ? ' (passthrough)' : ''));
12786
12832
  genResp = await fetch(ollamaUrl + '/v1/chat/completions', {
12787
12833
  method: 'POST',
12788
- headers: { 'Content-Type': 'application/json' },
12834
+ headers: chatHeaders,
12789
12835
  body: JSON.stringify(chatBody),
12790
12836
  });
12791
12837
  genData = await genResp.json();
@@ -12816,8 +12862,36 @@ async function handleCmd(cmd) {
12816
12862
  usage: { input_tokens: inputTokens, output_tokens: outputTokens },
12817
12863
  pricing: entry.pricing,
12818
12864
  };
12865
+ } else if (isPassthrough) {
12866
+ // Passthrough flat prompt \u2014 convert to /v1/chat/completions (upstream has no /api/generate)
12867
+ var flatPrompt = parsedReq && parsedReq.prompt ? parsedReq.prompt : (prompt || 'Hello');
12868
+ var ptHeaders = { 'Content-Type': 'application/json' };
12869
+ if (endpointAuth) ptHeaders['Authorization'] = 'Bearer ' + endpointAuth;
12870
+ genResp = await fetch(ollamaUrl + '/v1/chat/completions', {
12871
+ method: 'POST',
12872
+ headers: ptHeaders,
12873
+ body: JSON.stringify({
12874
+ model: model.name,
12875
+ messages: [{ role: 'user', content: flatPrompt }],
12876
+ stream: false,
12877
+ }),
12878
+ });
12879
+ genData = await genResp.json();
12880
+ var ptChoices = genData.choices || [];
12881
+ var ptMsg = (ptChoices[0] || {}).message || {};
12882
+ output = (ptMsg.content || '').replace(/<think>[\\s\\S]*?<\\/think>/g, '').trim();
12883
+ inputTokens = (genData.usage || {}).prompt_tokens || 0;
12884
+ outputTokens = (genData.usage || {}).completion_tokens || 0;
12885
+
12886
+ responsePayload = {
12887
+ model: model.name,
12888
+ response: output,
12889
+ choices: ptChoices,
12890
+ usage: { input_tokens: inputTokens, output_tokens: outputTokens },
12891
+ pricing: entry.pricing,
12892
+ };
12819
12893
  } else {
12820
- // Flat prompt \u2014 use /api/generate (original behavior)
12894
+ // Flat prompt \u2014 use /api/generate (local Ollama)
12821
12895
  var flatPrompt = parsedReq && parsedReq.prompt ? parsedReq.prompt : (prompt || 'Hello');
12822
12896
  genResp = await fetch(ollamaUrl + '/api/generate', {
12823
12897
  method: 'POST',
@@ -28358,6 +28432,7 @@ ${this.formatConnectionInfo()}`);
28358
28432
  _margin;
28359
28433
  _passthrough = false;
28360
28434
  _loadbalance = false;
28435
+ _endpointAuth;
28361
28436
  _pollTimer = null;
28362
28437
  _stats = {
28363
28438
  status: "standby",
@@ -28402,6 +28477,7 @@ ${this.formatConnectionInfo()}`);
28402
28477
  this._margin = options.margin ?? 0.5;
28403
28478
  this._passthrough = options.passthrough ?? false;
28404
28479
  this._loadbalance = options.loadbalance ?? false;
28480
+ this._endpointAuth = options.endpointAuth;
28405
28481
  this._onInfo = options.onInfo;
28406
28482
  this._onError = options.onError;
28407
28483
  if (options.authKey === void 0 || options.authKey === "") {
@@ -28421,21 +28497,23 @@ ${this.formatConnectionInfo()}`);
28421
28497
  throw new Error(`Nexus daemon connect failed: ${connectResult.error}`);
28422
28498
  }
28423
28499
  await new Promise((r) => setTimeout(r, 500));
28424
- this._onInfo?.("Registering inference capabilities...");
28425
- let exposeResult = await this._nexusTool.execute({
28500
+ this._onInfo?.(this._passthrough ? `Registering passthrough capabilities (\u2192 ${this._targetUrl})...` : "Registering inference capabilities...");
28501
+ const exposeArgs = {
28426
28502
  action: "expose",
28427
28503
  ollama_url: this._targetUrl,
28428
28504
  margin: String(this._margin),
28429
28505
  auth_key: this._authKey
28430
- });
28506
+ };
28507
+ if (this._passthrough) {
28508
+ exposeArgs.passthrough = "true";
28509
+ if (this._endpointAuth) {
28510
+ exposeArgs.endpoint_auth = this._endpointAuth;
28511
+ }
28512
+ }
28513
+ let exposeResult = await this._nexusTool.execute(exposeArgs);
28431
28514
  if (!exposeResult.success && exposeResult.error?.includes("not running")) {
28432
28515
  await new Promise((r) => setTimeout(r, 1500));
28433
- exposeResult = await this._nexusTool.execute({
28434
- action: "expose",
28435
- ollama_url: this._targetUrl,
28436
- margin: String(this._margin),
28437
- auth_key: this._authKey
28438
- });
28516
+ exposeResult = await this._nexusTool.execute(exposeArgs);
28439
28517
  }
28440
28518
  if (!exposeResult.success) {
28441
28519
  throw new Error(`Expose failed: ${exposeResult.error}`);
@@ -46917,6 +46995,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
46917
46995
  stateDir: join50(repoRoot, ".oa"),
46918
46996
  passthrough: passthrough ?? false,
46919
46997
  loadbalance: loadbalance ?? false,
46998
+ endpointAuth: passthrough ? config.apiKey : void 0,
46920
46999
  onInfo: (msg) => {
46921
47000
  exposeSpinnerMsg = msg;
46922
47001
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.103.37",
3
+ "version": "0.103.38",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",