open-agents-ai 0.187.221 → 0.187.222
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 +151 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -317580,6 +317580,10 @@ const conv = document.getElementById('conversation');
|
|
|
317580
317580
|
const input = document.getElementById('input-area');
|
|
317581
317581
|
const sendBtn = document.getElementById('send-btn');
|
|
317582
317582
|
const modelSelect = document.getElementById('model-select');
|
|
317583
|
+
// Persist the selected model on every change so a browser refresh /
|
|
317584
|
+
// daemon restart can recall it. The change handler is added immediately
|
|
317585
|
+
// because modelSelect already exists in the DOM at this point.
|
|
317586
|
+
modelSelect.addEventListener('change', () => persistSelectedModel());
|
|
317583
317587
|
const statusEl = document.getElementById('status');
|
|
317584
317588
|
let apiKey = localStorage.getItem('oa-api-key') || '';
|
|
317585
317589
|
let streaming = false;
|
|
@@ -317619,25 +317623,66 @@ async function checkHealth() {
|
|
|
317619
317623
|
}
|
|
317620
317624
|
}
|
|
317621
317625
|
|
|
317622
|
-
// Load models
|
|
317626
|
+
// Load models. Recall the previously-selected model in this priority:
|
|
317627
|
+
// 1. Daemon's persisted config.model (server-side, survives daemon restart)
|
|
317628
|
+
// 2. localStorage 'oa.selectedModel' (client-side, survives browser refresh
|
|
317629
|
+
// even before the daemon answers /v1/config)
|
|
317630
|
+
// 3. First model whose name contains "9b" (sensible default)
|
|
317631
|
+
// 4. First model overall
|
|
317623
317632
|
async function loadModels() {
|
|
317624
317633
|
try {
|
|
317625
|
-
const
|
|
317626
|
-
|
|
317634
|
+
const [modelsResp, cfgResp] = await Promise.all([
|
|
317635
|
+
fetch('/v1/models', { headers: headers() }).then(r => r.json()).catch(() => ({})),
|
|
317636
|
+
fetch('/v1/config', { headers: headers() }).then(r => r.json()).catch(() => ({})),
|
|
317637
|
+
]);
|
|
317627
317638
|
modelSelect.innerHTML = '';
|
|
317628
|
-
for (const m of (
|
|
317639
|
+
for (const m of (modelsResp.data || [])) {
|
|
317629
317640
|
const opt = document.createElement('option');
|
|
317630
317641
|
// Strip "local/" prefix for cleaner display
|
|
317631
317642
|
opt.value = m.id.replace(/^local\\//, '');
|
|
317632
317643
|
opt.textContent = m.id.replace(/^local\\//, '');
|
|
317633
317644
|
modelSelect.appendChild(opt);
|
|
317634
317645
|
}
|
|
317635
|
-
//
|
|
317636
|
-
const
|
|
317637
|
-
|
|
317646
|
+
// Resolve the recalled model in priority order
|
|
317647
|
+
const daemonModel = (cfgResp && cfgResp.config && cfgResp.config.model) || '';
|
|
317648
|
+
let cachedModel = '';
|
|
317649
|
+
try { cachedModel = localStorage.getItem('oa.selectedModel') || ''; } catch {}
|
|
317650
|
+
const candidates = [daemonModel, cachedModel].filter(Boolean);
|
|
317651
|
+
let recalled = null;
|
|
317652
|
+
for (const c of candidates) {
|
|
317653
|
+
const stripped = c.replace(/^local\\//, '');
|
|
317654
|
+
const hit = Array.from(modelSelect.options).find(o => o.value === stripped);
|
|
317655
|
+
if (hit) { recalled = hit.value; break; }
|
|
317656
|
+
}
|
|
317657
|
+
if (recalled) {
|
|
317658
|
+
modelSelect.value = recalled;
|
|
317659
|
+
} else {
|
|
317660
|
+
// Fall back to first 9b model, then first overall
|
|
317661
|
+
const preferred = Array.from(modelSelect.options).find(o => /9b/i.test(o.value));
|
|
317662
|
+
if (preferred) modelSelect.value = preferred.value;
|
|
317663
|
+
}
|
|
317664
|
+
// Persist the resolved value back to localStorage so a subsequent
|
|
317665
|
+
// refresh (before /v1/config has answered) can recall it instantly.
|
|
317666
|
+
try { localStorage.setItem('oa.selectedModel', modelSelect.value); } catch {}
|
|
317638
317667
|
} catch { modelSelect.innerHTML = '<option>error loading models</option>'; }
|
|
317639
317668
|
}
|
|
317640
317669
|
|
|
317670
|
+
// Persist user changes immediately and push to the daemon so a daemon
|
|
317671
|
+
// restart also recalls the same model. The change handler is wired
|
|
317672
|
+
// after DOMContentLoaded — see the addEventListener call further down.
|
|
317673
|
+
function persistSelectedModel() {
|
|
317674
|
+
const v = modelSelect.value;
|
|
317675
|
+
if (!v) return;
|
|
317676
|
+
try { localStorage.setItem('oa.selectedModel', v); } catch {}
|
|
317677
|
+
// Best-effort: push to /v1/config/model so the daemon also persists it.
|
|
317678
|
+
// Don't await — we don't want to block the UI on a slow daemon write.
|
|
317679
|
+
fetch('/v1/config/model', {
|
|
317680
|
+
method: 'PUT',
|
|
317681
|
+
headers: headers(),
|
|
317682
|
+
body: JSON.stringify({ model: v }),
|
|
317683
|
+
}).catch(() => { /* offline / read-only — localStorage still saved */ });
|
|
317684
|
+
}
|
|
317685
|
+
|
|
317641
317686
|
function addMessage(role, content) {
|
|
317642
317687
|
const div = document.createElement('div');
|
|
317643
317688
|
div.className = 'msg ' + role;
|
|
@@ -317759,6 +317804,45 @@ function escHtml(s) {
|
|
|
317759
317804
|
return String(s == null ? '' : s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');
|
|
317760
317805
|
}
|
|
317761
317806
|
|
|
317807
|
+
// Append text content to a parent element with a "Show more" / "Hide"
|
|
317808
|
+
// toggle when the text exceeds truncateAt characters. The truncated
|
|
317809
|
+
// preview is shown by default; the toggle button sits UNDERNEATH the
|
|
317810
|
+
// content (per user request) and swaps between expand/collapse states.
|
|
317811
|
+
// Returns the wrapper div so callers can chain styles.
|
|
317812
|
+
function appendExpandableContent(parent, fullText, opts) {
|
|
317813
|
+
opts = opts || {};
|
|
317814
|
+
const truncateAt = typeof opts.truncateAt === 'number' ? opts.truncateAt : 500;
|
|
317815
|
+
const monospace = opts.monospace !== false; // default true
|
|
317816
|
+
const baseStyle = (opts.baseStyle || '') +
|
|
317817
|
+
(monospace ? 'font-family:monospace;white-space:pre-wrap;word-break:break-word;' : 'white-space:pre-wrap;');
|
|
317818
|
+
const wrapper = document.createElement('div');
|
|
317819
|
+
wrapper.style.cssText = 'display:flex;flex-direction:column;gap:2px;';
|
|
317820
|
+
const text = String(fullText == null ? '' : fullText);
|
|
317821
|
+
const isLong = text.length > truncateAt;
|
|
317822
|
+
|
|
317823
|
+
const contentEl = document.createElement('div');
|
|
317824
|
+
contentEl.style.cssText = baseStyle;
|
|
317825
|
+
contentEl.textContent = isLong ? text.slice(0, truncateAt) + '\\u2026' : text;
|
|
317826
|
+
wrapper.appendChild(contentEl);
|
|
317827
|
+
|
|
317828
|
+
if (isLong) {
|
|
317829
|
+
const btn = document.createElement('button');
|
|
317830
|
+
btn.type = 'button';
|
|
317831
|
+
btn.style.cssText = 'align-self:flex-start;margin-top:2px;padding:2px 8px;background:#2a2a30;border:1px solid #3a3a42;color:#b2920a;font-size:0.6rem;border-radius:2px;cursor:pointer;font-family:inherit;';
|
|
317832
|
+
btn.textContent = 'Show more (' + text.length + ' chars)';
|
|
317833
|
+
let expanded = false;
|
|
317834
|
+
btn.addEventListener('click', (e) => {
|
|
317835
|
+
e.stopPropagation();
|
|
317836
|
+
expanded = !expanded;
|
|
317837
|
+
contentEl.textContent = expanded ? text : (text.slice(0, truncateAt) + '\\u2026');
|
|
317838
|
+
btn.textContent = expanded ? 'Hide' : 'Show more (' + text.length + ' chars)';
|
|
317839
|
+
});
|
|
317840
|
+
wrapper.appendChild(btn);
|
|
317841
|
+
}
|
|
317842
|
+
parent.appendChild(wrapper);
|
|
317843
|
+
return wrapper;
|
|
317844
|
+
}
|
|
317845
|
+
|
|
317762
317846
|
async function sendMessage() {
|
|
317763
317847
|
const text = input.value.trim();
|
|
317764
317848
|
if (!text || streaming) return;
|
|
@@ -317855,6 +317939,27 @@ async function sendMessage() {
|
|
|
317855
317939
|
try {
|
|
317856
317940
|
const chunk = JSON.parse(data);
|
|
317857
317941
|
|
|
317942
|
+
// task_complete promotion: surface its summary as the final
|
|
317943
|
+
// assistant message instead of leaving it stuck inside the
|
|
317944
|
+
// tool dropdown. The agent uses task_complete to deliver its
|
|
317945
|
+
// final answer; without this hoist the user sees an empty
|
|
317946
|
+
// assistant bubble and a collapsed details element they have
|
|
317947
|
+
// to expand to read the result.
|
|
317948
|
+
if (chunk.type === 'tool_call' && chunk.tool === 'task_complete') {
|
|
317949
|
+
const ta = (chunk.args && typeof chunk.args === 'object') ? chunk.args : {};
|
|
317950
|
+
const summaryText = (typeof ta.summary === 'string' && ta.summary)
|
|
317951
|
+
|| (typeof ta.message === 'string' && ta.message)
|
|
317952
|
+
|| (typeof ta.result === 'string' && ta.result)
|
|
317953
|
+
|| '';
|
|
317954
|
+
if (summaryText) {
|
|
317955
|
+
if (fullContent && !fullContent.endsWith('\\n')) fullContent += '\\n\\n';
|
|
317956
|
+
fullContent += summaryText;
|
|
317957
|
+
contentDiv.innerHTML = renderMarkdown(fullContent);
|
|
317958
|
+
conv.scrollTop = conv.scrollHeight;
|
|
317959
|
+
}
|
|
317960
|
+
// fall through so the dropdown still renders for inspection
|
|
317961
|
+
}
|
|
317962
|
+
|
|
317858
317963
|
// Tool call event — show live as expandable section
|
|
317859
317964
|
if (chunk.type === 'tool_call') {
|
|
317860
317965
|
chatTools.push(chunk);
|
|
@@ -317936,14 +318041,26 @@ async function sendMessage() {
|
|
|
317936
318041
|
} else {
|
|
317937
318042
|
for (const [k, v] of Object.entries(chunk.args)) {
|
|
317938
318043
|
const row = document.createElement('div');
|
|
317939
|
-
row.style.cssText = 'padding:2px 0;display:flex;gap:8px';
|
|
318044
|
+
row.style.cssText = 'padding:2px 0;display:flex;gap:8px;align-items:flex-start';
|
|
318045
|
+
// Convert value to a displayable string with proper typing
|
|
317940
318046
|
let vs;
|
|
317941
318047
|
if (v === null || v === undefined) vs = String(v);
|
|
317942
318048
|
else if (typeof v === 'string') vs = v;
|
|
317943
318049
|
else if (typeof v === 'number' || typeof v === 'boolean') vs = String(v);
|
|
317944
318050
|
else { try { vs = JSON.stringify(v, null, 2); } catch { vs = '[object]'; } }
|
|
317945
|
-
|
|
317946
|
-
|
|
318051
|
+
|
|
318052
|
+
const keyEl = document.createElement('span');
|
|
318053
|
+
keyEl.style.cssText = 'color:#b2920a;min-width:60px;flex-shrink:0';
|
|
318054
|
+
keyEl.textContent = k;
|
|
318055
|
+
row.appendChild(keyEl);
|
|
318056
|
+
|
|
318057
|
+
const valWrap = document.createElement('div');
|
|
318058
|
+
valWrap.style.cssText = 'flex:1;min-width:0;color:#b0b0b0';
|
|
318059
|
+
// Use the show-more helper so long values are collapsed
|
|
318060
|
+
// by default and the user can expand inline.
|
|
318061
|
+
appendExpandableContent(valWrap, vs, { truncateAt: 500, baseStyle: 'color:#b0b0b0;' });
|
|
318062
|
+
row.appendChild(valWrap);
|
|
318063
|
+
|
|
317947
318064
|
argsDiv.appendChild(row);
|
|
317948
318065
|
}
|
|
317949
318066
|
}
|
|
@@ -317954,11 +318071,13 @@ async function sendMessage() {
|
|
|
317954
318071
|
continue;
|
|
317955
318072
|
}
|
|
317956
318073
|
|
|
317957
|
-
// Tool result
|
|
318074
|
+
// Tool result — render with show-more/hide so the user can
|
|
318075
|
+
// expand to see the FULL output instead of being capped at
|
|
318076
|
+
// 150 chars. The button sits underneath the result block.
|
|
317958
318077
|
if (chunk.type === 'tool_result') {
|
|
317959
318078
|
const resultEl = document.createElement('div');
|
|
317960
|
-
resultEl.style.cssText = 'background:#1e1e22;padding:
|
|
317961
|
-
resultEl
|
|
318079
|
+
resultEl.style.cssText = 'background:#1e1e22;padding:4px 8px 4px 18px;margin:0 0 2px 0;color:#888;font-size:0.65rem';
|
|
318080
|
+
appendExpandableContent(resultEl, chunk.output || '', { truncateAt: 150, baseStyle: 'color:#888;' });
|
|
317962
318081
|
toolsContainer.appendChild(resultEl);
|
|
317963
318082
|
continue;
|
|
317964
318083
|
}
|
|
@@ -322452,6 +322571,15 @@ ${task}` : task;
|
|
|
322452
322571
|
done: false,
|
|
322453
322572
|
_oa: { type: "tool_call", tool: evt.tool, args: evt.args }
|
|
322454
322573
|
}) + "\n");
|
|
322574
|
+
try {
|
|
322575
|
+
const evtType = evt.tool === "sub_agent" || evt.tool === "full_sub_agent" ? "run.started" : "tool.called";
|
|
322576
|
+
publishEvent(evtType, {
|
|
322577
|
+
run_id: `ollama-${evt.tool}-${Date.now()}`,
|
|
322578
|
+
tool: evt.tool,
|
|
322579
|
+
parent: "chat"
|
|
322580
|
+
});
|
|
322581
|
+
} catch {
|
|
322582
|
+
}
|
|
322455
322583
|
} else {
|
|
322456
322584
|
finalLines.push(line);
|
|
322457
322585
|
}
|
|
@@ -323757,6 +323885,16 @@ ${historyLines}
|
|
|
323757
323885
|
tool: evt.tool,
|
|
323758
323886
|
args: evt.args
|
|
323759
323887
|
}) + "\n\n");
|
|
323888
|
+
try {
|
|
323889
|
+
const evtType = evt.tool === "sub_agent" || evt.tool === "full_sub_agent" ? "run.started" : "tool.called";
|
|
323890
|
+
publishEvent(evtType, {
|
|
323891
|
+
run_id: `${session.id.slice(0, 12)}-${evt.tool}-${Date.now()}`,
|
|
323892
|
+
tool: evt.tool,
|
|
323893
|
+
session_id: session.id,
|
|
323894
|
+
parent: "chat"
|
|
323895
|
+
}, { subject: session.id });
|
|
323896
|
+
} catch {
|
|
323897
|
+
}
|
|
323760
323898
|
} else {
|
|
323761
323899
|
finalLines.push(line);
|
|
323762
323900
|
}
|
package/package.json
CHANGED