open-agents-ai 0.187.528 → 0.187.530
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/index.js +268 -105
- package/npm-shrinkwrap.json +15 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -526701,6 +526701,123 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
|
|
|
526701
526701
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
526702
526702
|
});
|
|
526703
526703
|
}
|
|
526704
|
+
/**
|
|
526705
|
+
* DECOMP-2 PRE-dispatch enforcement check. Returns a synthetic block-message
|
|
526706
|
+
* string when the gate should reject this dispatch; null to proceed normally.
|
|
526707
|
+
*
|
|
526708
|
+
* Caller logic differs between main-loop and brute-force dispatchers:
|
|
526709
|
+
* - Main loop returns the block as a synthetic { tc, output } result.
|
|
526710
|
+
* - Brute-force emits tool_result + pushes tool message + `continue`.
|
|
526711
|
+
* Both invoke this method to compute the decision.
|
|
526712
|
+
*
|
|
526713
|
+
* Conditions for blocking:
|
|
526714
|
+
* - `_decomp2GateActive` is true (set by `_trackDecomp2` when threshold crossed)
|
|
526715
|
+
* - tool is one of the 4 creative-edit tools
|
|
526716
|
+
* - the path is NOT in `_decomp2MainContextFiles` (i.e. it's a NEW file)
|
|
526717
|
+
* - kill-switch `OA_DISABLE_DECOMP2` is not set
|
|
526718
|
+
*
|
|
526719
|
+
* Already-touched paths pass through (current-module finishing work allowed).
|
|
526720
|
+
* sub_agent / web_search / task_complete pass through (not creative-edit tools).
|
|
526721
|
+
*/
|
|
526722
|
+
_maybeDecomp2Block(tc, turn) {
|
|
526723
|
+
if (!this._decomp2GateActive)
|
|
526724
|
+
return null;
|
|
526725
|
+
if (process.env["OA_DISABLE_DECOMP2"] === "1")
|
|
526726
|
+
return null;
|
|
526727
|
+
const _editTools = /* @__PURE__ */ new Set(["file_write", "file_edit", "batch_edit", "file_patch"]);
|
|
526728
|
+
if (!_editTools.has(tc.name))
|
|
526729
|
+
return null;
|
|
526730
|
+
const _editPath = tc.arguments?.["path"] ?? "";
|
|
526731
|
+
if (!_editPath || this._decomp2MainContextFiles.has(_editPath))
|
|
526732
|
+
return null;
|
|
526733
|
+
const _filesList = [...this._decomp2MainContextFiles].slice(0, 8).map((p2) => ` • ${p2}`).join("\n");
|
|
526734
|
+
const _moreFiles = this._decomp2MainContextFiles.size > 8 ? `
|
|
526735
|
+
... +${this._decomp2MainContextFiles.size - 8} more` : "";
|
|
526736
|
+
const decomp2Msg = [
|
|
526737
|
+
`[BLOCKED — DECOMP-2 main-context exhaustion]`,
|
|
526738
|
+
``,
|
|
526739
|
+
`You have already edited ${this._decomp2MainContextFiles.size} distinct files in main context without invoking sub_agent. Continuing to edit ANOTHER new file ('${_editPath}') will keep your context window saturated and trigger compaction thrashing.`,
|
|
526740
|
+
``,
|
|
526741
|
+
`Files you've already edited (will accept further edits to these):`,
|
|
526742
|
+
_filesList,
|
|
526743
|
+
_moreFiles,
|
|
526744
|
+
``,
|
|
526745
|
+
`For the next module, you MUST use sub_agent. Workflow:`,
|
|
526746
|
+
` 1. Pick a pending todo (the orchestrator pre-populated module todos via DECOMP-1).`,
|
|
526747
|
+
` 2. Call sub_agent({`,
|
|
526748
|
+
` subagent_type: "general",`,
|
|
526749
|
+
` prompt: "Implement <module-path> per spec",`,
|
|
526750
|
+
` relevantFiles: [{path: "<module-path>", content: "" /* or existing content */}],`,
|
|
526751
|
+
` constraints: ["Stay within <module-path>; integration verification happens later"],`,
|
|
526752
|
+
` })`,
|
|
526753
|
+
` 3. After sub_agent returns, mark the todo completed.`,
|
|
526754
|
+
``,
|
|
526755
|
+
`Why this matters: spreading edits across N files in main context burns ~N × file_size tokens. sub_agent gives the next module a focused context window.`,
|
|
526756
|
+
``,
|
|
526757
|
+
`If you have ALREADY edited '${_editPath}' (this is a continuation), the orchestrator's set must have missed it — call file_read to verify, then re-edit. Otherwise, dispatch sub_agent now.`
|
|
526758
|
+
].join("\n");
|
|
526759
|
+
this.emit({
|
|
526760
|
+
type: "status",
|
|
526761
|
+
content: `DECOMP-2 NEW-FILE BLOCK — rejected ${tc.name}('${_editPath}') at turn ${turn}; gate stays active until sub_agent is invoked`,
|
|
526762
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
526763
|
+
});
|
|
526764
|
+
this._tagSyntheticFailure({
|
|
526765
|
+
mode: "step_repetition",
|
|
526766
|
+
rationale: `DECOMP-2 new-file block on '${tc.name}'(${_editPath}) — agent has spread edits across ${this._decomp2MainContextFiles.size} files without sub_agent`
|
|
526767
|
+
});
|
|
526768
|
+
return decomp2Msg;
|
|
526769
|
+
}
|
|
526770
|
+
/**
|
|
526771
|
+
* DECOMP-2 post-dispatch tracking. Refactored from inline so both the
|
|
526772
|
+
* main turn loop AND the brute-force re-engagement inner loop record
|
|
526773
|
+
* edits / sub_agent calls and check the gate-activation threshold.
|
|
526774
|
+
* Without this method on both paths, batch532 measured 14 distinct
|
|
526775
|
+
* files edited but DECOMP-2 never activated — because the main loop
|
|
526776
|
+
* exited via blocked task_complete and all subsequent edits flowed
|
|
526777
|
+
* through the brute-force dispatch which had no tracking.
|
|
526778
|
+
*
|
|
526779
|
+
* Side effects when fired:
|
|
526780
|
+
* - On successful creative edit: adds path to `_decomp2MainContextFiles`,
|
|
526781
|
+
* possibly activates `_decomp2GateActive` (emits status).
|
|
526782
|
+
* - On sub_agent / priority_delegate / background_run: increments
|
|
526783
|
+
* counter, clears gate (emits status).
|
|
526784
|
+
*
|
|
526785
|
+
* Pure post-dispatch: caller invokes AFTER the tool result is in hand,
|
|
526786
|
+
* regardless of which loop the dispatch happened in.
|
|
526787
|
+
*/
|
|
526788
|
+
_trackDecomp2(tc, result, turn) {
|
|
526789
|
+
if (process.env["OA_DISABLE_DECOMP2"] === "1")
|
|
526790
|
+
return;
|
|
526791
|
+
if (result && result.success !== false) {
|
|
526792
|
+
const _editTools = /* @__PURE__ */ new Set(["file_write", "file_edit", "batch_edit", "file_patch"]);
|
|
526793
|
+
if (_editTools.has(tc.name)) {
|
|
526794
|
+
const _editPath = tc.arguments?.["path"] ?? "";
|
|
526795
|
+
if (_editPath && typeof _editPath === "string") {
|
|
526796
|
+
this._decomp2MainContextFiles.add(_editPath);
|
|
526797
|
+
const DECOMP2_FILE_SPREAD_THRESHOLD = 5;
|
|
526798
|
+
if (!this._decomp2GateActive && this._decomp2MainContextFiles.size >= DECOMP2_FILE_SPREAD_THRESHOLD && this._decomp2SubAgentCalls === 0) {
|
|
526799
|
+
this._decomp2GateActive = true;
|
|
526800
|
+
this.emit({
|
|
526801
|
+
type: "status",
|
|
526802
|
+
content: `DECOMP-2 NEW-FILE GATE ACTIVATED — ${this._decomp2MainContextFiles.size} distinct files edited in main context, 0 sub_agent calls; further edits to NEW files will be blocked until sub_agent is invoked`,
|
|
526803
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
526804
|
+
});
|
|
526805
|
+
}
|
|
526806
|
+
}
|
|
526807
|
+
}
|
|
526808
|
+
}
|
|
526809
|
+
if (tc.name === "sub_agent" || tc.name === "priority_delegate" || tc.name === "background_run") {
|
|
526810
|
+
this._decomp2SubAgentCalls++;
|
|
526811
|
+
if (this._decomp2GateActive) {
|
|
526812
|
+
this._decomp2GateActive = false;
|
|
526813
|
+
this.emit({
|
|
526814
|
+
type: "status",
|
|
526815
|
+
content: `DECOMP-2 GATE CLEARED — '${tc.name}' satisfied delegation directive at turn ${turn}`,
|
|
526816
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
526817
|
+
});
|
|
526818
|
+
}
|
|
526819
|
+
}
|
|
526820
|
+
}
|
|
526704
526821
|
readSessionTodos() {
|
|
526705
526822
|
try {
|
|
526706
526823
|
const sid = process.env["OA_SESSION_ID"] || this._sessionId || "default";
|
|
@@ -530669,69 +530786,19 @@ ${memoryLines.join("\n")}`
|
|
|
530669
530786
|
});
|
|
530670
530787
|
return { tc, output: reg61BlockMsg };
|
|
530671
530788
|
}
|
|
530672
|
-
|
|
530673
|
-
const
|
|
530674
|
-
|
|
530675
|
-
"
|
|
530676
|
-
|
|
530677
|
-
|
|
530678
|
-
|
|
530679
|
-
|
|
530680
|
-
|
|
530681
|
-
|
|
530682
|
-
|
|
530683
|
-
|
|
530684
|
-
|
|
530685
|
-
toolName: tc.name,
|
|
530686
|
-
toolArgs: tc.arguments,
|
|
530687
|
-
turn,
|
|
530688
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530689
|
-
});
|
|
530690
|
-
const _filesList = [...this._decomp2MainContextFiles].slice(0, 8).map((p2) => ` • ${p2}`).join("\n");
|
|
530691
|
-
const _moreFiles = this._decomp2MainContextFiles.size > 8 ? `
|
|
530692
|
-
... +${this._decomp2MainContextFiles.size - 8} more` : "";
|
|
530693
|
-
const decomp2Msg = [
|
|
530694
|
-
`[BLOCKED — DECOMP-2 main-context exhaustion]`,
|
|
530695
|
-
``,
|
|
530696
|
-
`You have already edited ${this._decomp2MainContextFiles.size} distinct files in main context without invoking sub_agent. Continuing to edit ANOTHER new file ('${_editPath}') will keep your context window saturated and trigger compaction thrashing.`,
|
|
530697
|
-
``,
|
|
530698
|
-
`Files you've already edited (will accept further edits to these):`,
|
|
530699
|
-
_filesList,
|
|
530700
|
-
_moreFiles,
|
|
530701
|
-
``,
|
|
530702
|
-
`For the next module, you MUST use sub_agent. Workflow:`,
|
|
530703
|
-
` 1. Pick a pending todo (the orchestrator pre-populated module todos via DECOMP-1).`,
|
|
530704
|
-
` 2. Call sub_agent({`,
|
|
530705
|
-
` subagent_type: "general",`,
|
|
530706
|
-
` prompt: "Implement <module-path> per spec",`,
|
|
530707
|
-
` relevantFiles: [{path: "<module-path>", content: "" /* or existing content */}],`,
|
|
530708
|
-
` constraints: ["Stay within <module-path>; integration verification happens later"],`,
|
|
530709
|
-
` })`,
|
|
530710
|
-
` 3. After sub_agent returns, mark the todo completed.`,
|
|
530711
|
-
``,
|
|
530712
|
-
`Why this matters: spreading edits across N files in main context burns ~N × file_size tokens. sub_agent gives the next module a focused context window.`,
|
|
530713
|
-
``,
|
|
530714
|
-
`If you have ALREADY edited '${_editPath}' (this is a continuation), the orchestrator's set must have missed it — call file_read to verify, then re-edit. Otherwise, dispatch sub_agent now.`
|
|
530715
|
-
].join("\n");
|
|
530716
|
-
this.emit({
|
|
530717
|
-
type: "tool_result",
|
|
530718
|
-
toolName: tc.name,
|
|
530719
|
-
success: false,
|
|
530720
|
-
content: decomp2Msg.slice(0, 120),
|
|
530721
|
-
turn,
|
|
530722
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530723
|
-
});
|
|
530724
|
-
this.emit({
|
|
530725
|
-
type: "status",
|
|
530726
|
-
content: `DECOMP-2 NEW-FILE BLOCK — rejected ${tc.name}('${_editPath}') at turn ${turn}; gate stays active until sub_agent is invoked`,
|
|
530727
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530728
|
-
});
|
|
530729
|
-
this._tagSyntheticFailure({
|
|
530730
|
-
mode: "step_repetition",
|
|
530731
|
-
rationale: `DECOMP-2 new-file block on '${tc.name}'(${_editPath}) — agent has spread edits across ${this._decomp2MainContextFiles.size} files without sub_agent`
|
|
530732
|
-
});
|
|
530733
|
-
return { tc, output: decomp2Msg };
|
|
530734
|
-
}
|
|
530789
|
+
{
|
|
530790
|
+
const _decomp2Block = this._maybeDecomp2Block(tc, turn);
|
|
530791
|
+
if (_decomp2Block) {
|
|
530792
|
+
this.emit({ type: "tool_call", toolName: tc.name, toolArgs: tc.arguments, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
530793
|
+
this.emit({
|
|
530794
|
+
type: "tool_result",
|
|
530795
|
+
toolName: tc.name,
|
|
530796
|
+
success: false,
|
|
530797
|
+
content: _decomp2Block.slice(0, 120),
|
|
530798
|
+
turn,
|
|
530799
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
530800
|
+
});
|
|
530801
|
+
return { tc, output: _decomp2Block };
|
|
530735
530802
|
}
|
|
530736
530803
|
}
|
|
530737
530804
|
const PROGRESS_GATE_BYPASS_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -531841,32 +531908,9 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
531841
531908
|
if (this._fileWriteTimestamps.length > 200) {
|
|
531842
531909
|
this._fileWriteTimestamps.shift();
|
|
531843
531910
|
}
|
|
531844
|
-
const _editPath = tc.arguments?.["path"] ?? "";
|
|
531845
|
-
if (_editPath && typeof _editPath === "string") {
|
|
531846
|
-
this._decomp2MainContextFiles.add(_editPath);
|
|
531847
|
-
const DECOMP2_FILE_SPREAD_THRESHOLD = 5;
|
|
531848
|
-
if (!this._decomp2GateActive && this._decomp2MainContextFiles.size >= DECOMP2_FILE_SPREAD_THRESHOLD && this._decomp2SubAgentCalls === 0 && process.env["OA_DISABLE_DECOMP2"] !== "1") {
|
|
531849
|
-
this._decomp2GateActive = true;
|
|
531850
|
-
this.emit({
|
|
531851
|
-
type: "status",
|
|
531852
|
-
content: `DECOMP-2 NEW-FILE GATE ACTIVATED — ${this._decomp2MainContextFiles.size} distinct files edited in main context, 0 sub_agent calls; further edits to NEW files will be blocked until sub_agent is invoked`,
|
|
531853
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
531854
|
-
});
|
|
531855
|
-
}
|
|
531856
|
-
}
|
|
531857
|
-
}
|
|
531858
|
-
}
|
|
531859
|
-
if (tc.name === "sub_agent" || tc.name === "priority_delegate" || tc.name === "background_run") {
|
|
531860
|
-
this._decomp2SubAgentCalls++;
|
|
531861
|
-
if (this._decomp2GateActive) {
|
|
531862
|
-
this._decomp2GateActive = false;
|
|
531863
|
-
this.emit({
|
|
531864
|
-
type: "status",
|
|
531865
|
-
content: `DECOMP-2 GATE CLEARED — '${tc.name}' satisfied delegation directive at turn ${turn}`,
|
|
531866
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
531867
|
-
});
|
|
531868
531911
|
}
|
|
531869
531912
|
}
|
|
531913
|
+
this._trackDecomp2(tc, result, turn);
|
|
531870
531914
|
if (result && result.success === false) {
|
|
531871
531915
|
this._runErrorCount++;
|
|
531872
531916
|
const errMsg = result.error || "";
|
|
@@ -532782,6 +532826,12 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
532782
532826
|
}
|
|
532783
532827
|
}
|
|
532784
532828
|
this.emit({ type: "tool_call", toolName: tc.name, toolArgs: tc.arguments, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
532829
|
+
const _decomp2BFBlock = this._maybeDecomp2Block(tc, turn);
|
|
532830
|
+
if (_decomp2BFBlock) {
|
|
532831
|
+
this.emit({ type: "tool_result", toolName: tc.name, content: _decomp2BFBlock.slice(0, 200), success: false, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
532832
|
+
messages2.push(this.buildToolMessage(_decomp2BFBlock, tc.id));
|
|
532833
|
+
continue;
|
|
532834
|
+
}
|
|
532785
532835
|
const tool = this.tools.get(tc.name);
|
|
532786
532836
|
let result;
|
|
532787
532837
|
if (!tool) {
|
|
@@ -532830,6 +532880,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
532830
532880
|
output = modelContent2;
|
|
532831
532881
|
}
|
|
532832
532882
|
this.emit({ type: "tool_result", toolName: tc.name, content: output.slice(0, 200), success: result.success, turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
532883
|
+
this._trackDecomp2(tc, result, turn);
|
|
532833
532884
|
const enoentTools2 = /* @__PURE__ */ new Set(["file_read", "list_directory", "find_files"]);
|
|
532834
532885
|
if (!result.success && enoentTools2.has(tc.name) && /ENOENT|no such file|does not exist|not found/i.test(result.error ?? result.output)) {
|
|
532835
532886
|
this._consecutiveEnoent++;
|
|
@@ -593871,44 +593922,156 @@ function openSettingsPane(name) {
|
|
|
593871
593922
|
if (name === 'profiles') { try { loadSettingsProfiles(); } catch {} }
|
|
593872
593923
|
}
|
|
593873
593924
|
|
|
593874
|
-
//
|
|
593925
|
+
// ────────────────────────────────────────────────────────────────────
|
|
593926
|
+
// Connections settings — TUI /endpoint command parity.
|
|
593927
|
+
//
|
|
593928
|
+
// Reads /v1/config + /v1/config/endpoint. Renders an editor with:
|
|
593929
|
+
// - Backend URL (editable)
|
|
593930
|
+
// - Backend type (auto-detected, editable: ollama / vllm / openai / unknown)
|
|
593931
|
+
// - Auth key (Bearer token, masked, editable)
|
|
593932
|
+
// - Test connection button — fetches the URL's models endpoint
|
|
593933
|
+
// - Save button — PUT /v1/config/endpoint with {url, backendType, auth}
|
|
593934
|
+
// - Endpoint history (loaded from /v1/config — recently-used URLs)
|
|
593935
|
+
//
|
|
593936
|
+
// The previous implementation had two bugs that broke the entire feature:
|
|
593937
|
+
// 1. POST instead of PUT (server only accepts PUT on /v1/config/endpoint)
|
|
593938
|
+
// 2. Body field was {endpoint} not {url} (server validates field name)
|
|
593939
|
+
// Save button silently failed for every user. Fixed.
|
|
593940
|
+
// ────────────────────────────────────────────────────────────────────
|
|
593875
593941
|
async function loadSettingsConnections() {
|
|
593876
593942
|
const host = document.getElementById('settings-connections-host');
|
|
593877
593943
|
if (!host) return;
|
|
593878
593944
|
host.innerHTML = '<div style="color:var(--color-fg-muted);font-size:0.74rem">loading...</div>';
|
|
593879
593945
|
try {
|
|
593880
|
-
const
|
|
593881
|
-
|
|
593882
|
-
|
|
593883
|
-
|
|
593884
|
-
}
|
|
593885
|
-
|
|
593886
|
-
const
|
|
593946
|
+
const [cfgR, epR] = await Promise.all([
|
|
593947
|
+
fetch('/v1/config', { headers: headers() }).then(r => r.json()).catch(() => ({})),
|
|
593948
|
+
fetch('/v1/config/endpoint', { headers: headers() }).then(r => r.json()).catch(() => ({})),
|
|
593949
|
+
]);
|
|
593950
|
+
// /v1/config returns { config: {...}, settings: {...} } — prefer config (live runtime),
|
|
593951
|
+
// fall back to settings (file-persisted), then top-level fields for older daemons.
|
|
593952
|
+
const liveCfg = (cfgR && cfgR.config) || cfgR || {};
|
|
593953
|
+
const persistedCfg = (cfgR && cfgR.settings) || {};
|
|
593954
|
+
// /v1/config/endpoint returns { url, backendType, auth } directly.
|
|
593955
|
+
const ep = (epR && epR.url) || liveCfg.backendUrl || persistedCfg.backendUrl || '';
|
|
593956
|
+
const bt = (epR && epR.backendType) || liveCfg.backendType || persistedCfg.backendType || '';
|
|
593957
|
+
const authSet = (epR && epR.auth === '[set]') || (liveCfg.apiKey && liveCfg.apiKey !== '[redacted]');
|
|
593887
593958
|
const safeEp = String(ep).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
593959
|
+
const safeBt = String(bt).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
593888
593960
|
host.innerHTML =
|
|
593889
|
-
'<
|
|
593890
|
-
|
|
593891
|
-
|
|
593892
|
-
|
|
593961
|
+
'<div style="display:flex;flex-direction:column;gap:14px">' +
|
|
593962
|
+
'<div>' +
|
|
593963
|
+
'<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Backend URL</label>' +
|
|
593964
|
+
'<input id="settings-conn-endpoint" type="text" value="' + safeEp + '" placeholder="http://127.0.0.1:11434 or https://api.openai.com/v1" ' +
|
|
593965
|
+
'style="width:100%;background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-fg);padding:8px 12px;border-radius:var(--radius-sm);font-size:0.82rem;font-family:var(--font-mono)" ' +
|
|
593966
|
+
'oninput="autoDetectBackendType(this.value)">' +
|
|
593967
|
+
'<p style="font-size:0.7rem;color:var(--color-fg-muted);margin:4px 0 0">Examples: <code>http://127.0.0.1:11434</code> (Ollama) · <code>https://api.openai.com/v1</code> · <code>https://llm.chutes.ai/v1/chat/completions</code> (auto-strips path)</p>' +
|
|
593968
|
+
'</div>' +
|
|
593969
|
+
'<div>' +
|
|
593970
|
+
'<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Backend type</label>' +
|
|
593971
|
+
'<select id="settings-conn-backend-type" style="width:200px;background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-fg);padding:6px 10px;border-radius:var(--radius-sm);font-size:0.78rem">' +
|
|
593972
|
+
['ollama','vllm','openai','unknown'].map(t => '<option value="' + t + '"' + (t===safeBt?' selected':'') + '>' + t + '</option>').join('') +
|
|
593973
|
+
'</select>' +
|
|
593974
|
+
'<p style="font-size:0.7rem;color:var(--color-fg-muted);margin:4px 0 0">Auto-detected from URL on input. Override if needed.</p>' +
|
|
593975
|
+
'</div>' +
|
|
593976
|
+
'<div>' +
|
|
593977
|
+
'<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Auth key (Bearer)</label>' +
|
|
593978
|
+
'<input id="settings-conn-auth" type="password" value="" placeholder="' + (authSet ? '••••••••• (set — leave blank to keep)' : 'leave blank for none') + '" ' +
|
|
593979
|
+
'autocomplete="off" spellcheck="false" ' +
|
|
593980
|
+
'style="width:100%;background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-fg);padding:8px 12px;border-radius:var(--radius-sm);font-size:0.82rem;font-family:var(--font-mono)">' +
|
|
593981
|
+
'<p style="font-size:0.7rem;color:var(--color-fg-muted);margin:4px 0 0">' + (authSet ? 'A key is currently set. Leave blank to preserve, or enter a new one to replace.' : 'Required for OpenAI / Chutes / Groq / etc. Leave blank for local Ollama.') + '</p>' +
|
|
593982
|
+
'</div>' +
|
|
593983
|
+
'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">' +
|
|
593984
|
+
'<button class="oa-btn-secondary" onclick="testSettingsConnections()">test connection</button>' +
|
|
593985
|
+
'<button class="oa-btn-secondary" onclick="saveSettingsConnections()" style="background:var(--color-accent);color:#fff;border-color:var(--color-accent)">save</button>' +
|
|
593986
|
+
'<span id="settings-conn-status" style="font-size:0.74rem;color:var(--color-fg-muted)"></span>' +
|
|
593987
|
+
'</div>' +
|
|
593988
|
+
'</div>';
|
|
593893
593989
|
} catch (e) {
|
|
593894
593990
|
host.innerHTML = '<div style="color:var(--color-error);font-size:0.74rem">' + e.message + '</div>';
|
|
593895
593991
|
}
|
|
593896
593992
|
}
|
|
593993
|
+
|
|
593994
|
+
// Heuristic: pick a backend type from the URL pattern. Mirrors detectProvider()
|
|
593995
|
+
// in packages/backend-vllm/src/normalizeUrl.ts so the browser feels coherent
|
|
593996
|
+
// with the TUI / CLI provider auto-detect.
|
|
593997
|
+
function autoDetectBackendType(url) {
|
|
593998
|
+
const sel = document.getElementById('settings-conn-backend-type');
|
|
593999
|
+
if (!sel) return;
|
|
594000
|
+
const u = String(url || '').toLowerCase();
|
|
594001
|
+
let detected = 'unknown';
|
|
594002
|
+
if (u.includes('11434') || u.includes('ollama')) detected = 'ollama';
|
|
594003
|
+
else if (u.includes('openai.com') || u.includes('api.anthropic.com')) detected = 'openai';
|
|
594004
|
+
else if (u.includes('vllm') || u.includes('chutes') || u.includes('groq') || u.includes('deepinfra') || u.includes('/v1')) detected = 'vllm';
|
|
594005
|
+
if (sel.value === '' || sel.value === 'unknown') sel.value = detected;
|
|
594006
|
+
}
|
|
594007
|
+
|
|
594008
|
+
async function testSettingsConnections() {
|
|
594009
|
+
const inp = document.getElementById('settings-conn-endpoint');
|
|
594010
|
+
const auth = document.getElementById('settings-conn-auth');
|
|
594011
|
+
const status = document.getElementById('settings-conn-status');
|
|
594012
|
+
if (!inp || !status) return;
|
|
594013
|
+
status.textContent = 'testing...';
|
|
594014
|
+
status.style.color = 'var(--color-fg-muted)';
|
|
594015
|
+
// Strip /v1/chat/completions or /v1/* path so we can hit /v1/models — same as normalizeBaseUrl.
|
|
594016
|
+
let base = String(inp.value || '').trim().replace(//$/, '');
|
|
594017
|
+
base = base.replace(//v1/chat/completions$/i, '').replace(//v1/models$/i, '');
|
|
594018
|
+
const url = base.endsWith('/v1') ? base + '/models' : base + '/v1/models';
|
|
594019
|
+
try {
|
|
594020
|
+
const opts = { headers: { 'Accept': 'application/json' } };
|
|
594021
|
+
const a = auth && auth.value ? auth.value : '';
|
|
594022
|
+
if (a) opts.headers['Authorization'] = 'Bearer ' + a;
|
|
594023
|
+
const r = await fetch(url, opts);
|
|
594024
|
+
if (r.status === 200) {
|
|
594025
|
+
const j = await r.json().catch(() => ({}));
|
|
594026
|
+
const data = (j && j.data) || (j && j.models) || (Array.isArray(j) ? j : []);
|
|
594027
|
+
const count = Array.isArray(data) ? data.length : 0;
|
|
594028
|
+
status.textContent = '✓ ok — ' + count + ' model(s) reachable';
|
|
594029
|
+
status.style.color = 'var(--color-success)';
|
|
594030
|
+
} else if (r.status === 401 || r.status === 403) {
|
|
594031
|
+
status.textContent = '✗ unauthorized (' + r.status + ') — auth key required or wrong';
|
|
594032
|
+
status.style.color = 'var(--color-error)';
|
|
594033
|
+
} else {
|
|
594034
|
+
status.textContent = '✗ HTTP ' + r.status;
|
|
594035
|
+
status.style.color = 'var(--color-error)';
|
|
594036
|
+
}
|
|
594037
|
+
} catch (e) {
|
|
594038
|
+
status.textContent = '✗ ' + (e && e.message ? e.message : 'connection failed');
|
|
594039
|
+
status.style.color = 'var(--color-error)';
|
|
594040
|
+
}
|
|
594041
|
+
}
|
|
594042
|
+
|
|
593897
594043
|
async function saveSettingsConnections() {
|
|
593898
594044
|
const inp = document.getElementById('settings-conn-endpoint');
|
|
594045
|
+
const bt = document.getElementById('settings-conn-backend-type');
|
|
594046
|
+
const auth = document.getElementById('settings-conn-auth');
|
|
593899
594047
|
const status = document.getElementById('settings-conn-status');
|
|
593900
594048
|
if (!inp || !status) return;
|
|
593901
594049
|
status.textContent = 'saving...';
|
|
594050
|
+
status.style.color = 'var(--color-fg-muted)';
|
|
593902
594051
|
try {
|
|
594052
|
+
// Server expects PUT /v1/config/endpoint with body {url, backendType?, auth?}.
|
|
594053
|
+
// Previous code POSTed with {endpoint:...} and got silently 404'd.
|
|
594054
|
+
const body = { url: String(inp.value || '').trim() };
|
|
594055
|
+
if (bt && bt.value && bt.value !== 'unknown') body.backendType = bt.value;
|
|
594056
|
+
if (auth && auth.value) body.auth = auth.value;
|
|
593903
594057
|
const r = await fetch('/v1/config/endpoint', {
|
|
593904
|
-
method: '
|
|
593905
|
-
headers: headers(),
|
|
593906
|
-
body: JSON.stringify(
|
|
594058
|
+
method: 'PUT',
|
|
594059
|
+
headers: { ...headers(), 'Content-Type': 'application/json' },
|
|
594060
|
+
body: JSON.stringify(body),
|
|
593907
594061
|
});
|
|
593908
|
-
if (r.status === 200)
|
|
593909
|
-
|
|
594062
|
+
if (r.status === 200) {
|
|
594063
|
+
status.textContent = '✓ saved — refresh model list to pick up the change';
|
|
594064
|
+
status.style.color = 'var(--color-success)';
|
|
594065
|
+
// Clear the auth input so it doesn't visually persist after save.
|
|
594066
|
+
if (auth) auth.value = '';
|
|
594067
|
+
} else {
|
|
594068
|
+
const errBody = await r.json().catch(() => ({}));
|
|
594069
|
+
status.textContent = '✗ failed (' + r.status + ')' + (errBody.error ? ': ' + errBody.error : '');
|
|
594070
|
+
status.style.color = 'var(--color-error)';
|
|
594071
|
+
}
|
|
593910
594072
|
} catch (e) {
|
|
593911
|
-
status.textContent = '
|
|
594073
|
+
status.textContent = '✗ ' + (e && e.message ? e.message : 'error');
|
|
594074
|
+
status.style.color = 'var(--color-error)';
|
|
593912
594075
|
}
|
|
593913
594076
|
}
|
|
593914
594077
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-agents-ai",
|
|
3
|
-
"version": "0.187.
|
|
3
|
+
"version": "0.187.530",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "open-agents-ai",
|
|
9
|
-
"version": "0.187.
|
|
9
|
+
"version": "0.187.530",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "CC-BY-NC-4.0",
|
|
12
12
|
"dependencies": {
|
|
@@ -1138,9 +1138,9 @@
|
|
|
1138
1138
|
}
|
|
1139
1139
|
},
|
|
1140
1140
|
"node_modules/@libp2p/webrtc": {
|
|
1141
|
-
"version": "6.0.
|
|
1142
|
-
"resolved": "https://registry.npmjs.org/@libp2p/webrtc/-/webrtc-6.0.
|
|
1143
|
-
"integrity": "sha512-
|
|
1141
|
+
"version": "6.0.21",
|
|
1142
|
+
"resolved": "https://registry.npmjs.org/@libp2p/webrtc/-/webrtc-6.0.21.tgz",
|
|
1143
|
+
"integrity": "sha512-q7Qiqs/vrdECNRmOfLuYvcH7gLOk94vO8tHpkaIDJv2OxRLDcwAGqQ51K0932shU4DozDJ6203HdWaRJs3MMzg==",
|
|
1144
1144
|
"license": "Apache-2.0 OR MIT",
|
|
1145
1145
|
"dependencies": {
|
|
1146
1146
|
"@chainsafe/is-ip": "^2.1.0",
|
|
@@ -1163,7 +1163,7 @@
|
|
|
1163
1163
|
"it-stream-types": "^2.0.2",
|
|
1164
1164
|
"main-event": "^1.0.1",
|
|
1165
1165
|
"multiformats": "^13.4.0",
|
|
1166
|
-
"node-datachannel": "^0.
|
|
1166
|
+
"node-datachannel": "^0.32.3",
|
|
1167
1167
|
"p-defer": "^4.0.1",
|
|
1168
1168
|
"p-event": "^7.0.0",
|
|
1169
1169
|
"p-timeout": "^7.0.0",
|
|
@@ -3179,9 +3179,9 @@
|
|
|
3179
3179
|
}
|
|
3180
3180
|
},
|
|
3181
3181
|
"node_modules/fast-uri": {
|
|
3182
|
-
"version": "3.1.
|
|
3183
|
-
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.
|
|
3184
|
-
"integrity": "sha512-
|
|
3182
|
+
"version": "3.1.1",
|
|
3183
|
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.1.tgz",
|
|
3184
|
+
"integrity": "sha512-h2r7rcm6Ee/J8o0LD5djLuFVcfbZxhvho4vvsbeV0aMvXjUgqv4YpxpkEx0d68l6+IleVfLAdVEfhR7QNMkGHQ==",
|
|
3185
3185
|
"funding": [
|
|
3186
3186
|
{
|
|
3187
3187
|
"type": "github",
|
|
@@ -4558,9 +4558,9 @@
|
|
|
4558
4558
|
}
|
|
4559
4559
|
},
|
|
4560
4560
|
"node_modules/lru-cache": {
|
|
4561
|
-
"version": "11.3.
|
|
4562
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.
|
|
4563
|
-
"integrity": "sha512-
|
|
4561
|
+
"version": "11.3.6",
|
|
4562
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
|
|
4563
|
+
"integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
|
|
4564
4564
|
"license": "BlueOak-1.0.0",
|
|
4565
4565
|
"engines": {
|
|
4566
4566
|
"node": "20 || >=22"
|
|
@@ -4949,9 +4949,9 @@
|
|
|
4949
4949
|
"optional": true
|
|
4950
4950
|
},
|
|
4951
4951
|
"node_modules/node-datachannel": {
|
|
4952
|
-
"version": "0.
|
|
4953
|
-
"resolved": "https://registry.npmjs.org/node-datachannel/-/node-datachannel-0.
|
|
4954
|
-
"integrity": "sha512-
|
|
4952
|
+
"version": "0.32.3",
|
|
4953
|
+
"resolved": "https://registry.npmjs.org/node-datachannel/-/node-datachannel-0.32.3.tgz",
|
|
4954
|
+
"integrity": "sha512-Aok1ZhLsll472lRefgWYuWJ0070jh0ecHravTdRyZEmoESumebMEQV8Y+poBwSW2ZbEwAokAOGsK5Cu8pDDT2g==",
|
|
4955
4955
|
"hasInstallScript": true,
|
|
4956
4956
|
"license": "MPL 2.0",
|
|
4957
4957
|
"dependencies": {
|
package/package.json
CHANGED