open-agents-ai 0.187.235 → 0.187.237
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 +375 -15
- package/dist/scripts/.env +14 -0
- package/dist/scripts/.scrape_setup_complete +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -271575,6 +271575,7 @@ ${sr.result.output}`;
|
|
|
271575
271575
|
}
|
|
271576
271576
|
if (completed)
|
|
271577
271577
|
break;
|
|
271578
|
+
this.littlemanObserve(messages2, turn);
|
|
271578
271579
|
const currentRepScore = this.detectRepetition(toolCallLog);
|
|
271579
271580
|
if (currentRepScore > 0.4 && toolCallLog.length >= 4) {
|
|
271580
271581
|
const { repetitionWindow } = this.contextLimits();
|
|
@@ -271957,7 +271958,7 @@ ${result.output}`;
|
|
|
271957
271958
|
turn,
|
|
271958
271959
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
271959
271960
|
});
|
|
271960
|
-
output = `[
|
|
271961
|
+
output = `[${tc.name} succeeded — output externalized: ${result.output.length} chars, ${lineCount} lines]
|
|
271961
271962
|
Handle: ${handleId}
|
|
271962
271963
|
Preview: ${preview}...
|
|
271963
271964
|
Full content available via: repl_exec(code="data = retrieve('${handleId}')") or memex_retrieve(id="${handleId}")`;
|
|
@@ -272380,7 +272381,7 @@ ${errOutput}`;
|
|
|
272380
272381
|
${result.output}`, "utf-8");
|
|
272381
272382
|
} catch {
|
|
272382
272383
|
}
|
|
272383
|
-
return `[
|
|
272384
|
+
return `[${toolName} succeeded — output externalized: ${result.output.length} chars, ${lineCount} lines]
|
|
272384
272385
|
Handle: ${handleId}
|
|
272385
272386
|
Preview: ${preview}...
|
|
272386
272387
|
Full content available via: repl_exec(code="data = retrieve('${handleId}')") or memex_retrieve(id="${handleId}")`;
|
|
@@ -272882,6 +272883,99 @@ ${newerSummary}`;
|
|
|
272882
272883
|
|
|
272883
272884
|
${trimmedNew}`;
|
|
272884
272885
|
}
|
|
272886
|
+
// -------------------------------------------------------------------------
|
|
272887
|
+
// Littleman Observer — parallel meta-analysis of the main loop
|
|
272888
|
+
// -------------------------------------------------------------------------
|
|
272889
|
+
// Inspired by Hannover's fireCompanionObserver (src/buddy/observer.ts).
|
|
272890
|
+
// Runs after each tool turn to detect when the model has lost track of
|
|
272891
|
+
// what happened and inject corrections before the next inference.
|
|
272892
|
+
//
|
|
272893
|
+
// This is the architectural fix for the "I see both tools have been failing"
|
|
272894
|
+
// regression: instead of only fixing the data the model sees (mask/summary),
|
|
272895
|
+
// we add a second analysis path that catches mismatches in real-time.
|
|
272896
|
+
/** Track recent tool outcomes for the littleman observer */
|
|
272897
|
+
_littlemanToolOutcomes = [];
|
|
272898
|
+
/**
|
|
272899
|
+
* Littleman observer: post-turn meta-analysis.
|
|
272900
|
+
*
|
|
272901
|
+
* Examines the last few messages looking for contradictions between
|
|
272902
|
+
* actual tool outcomes and the model's stated understanding. When it
|
|
272903
|
+
* detects the model claiming failure after success (or vice versa),
|
|
272904
|
+
* it injects a corrective message.
|
|
272905
|
+
*
|
|
272906
|
+
* Also detects repeated actions — when the model re-does something
|
|
272907
|
+
* that already succeeded, the littleman nudges it to move on.
|
|
272908
|
+
*/
|
|
272909
|
+
littlemanObserve(messages2, turn) {
|
|
272910
|
+
if (this.options.modelTier === "large")
|
|
272911
|
+
return;
|
|
272912
|
+
const recent = messages2.slice(-6);
|
|
272913
|
+
for (const msg of recent) {
|
|
272914
|
+
if (msg.role === "tool" && typeof msg.content === "string") {
|
|
272915
|
+
const isError2 = msg.content.startsWith("Error:") || /^(FAIL|ERR!|TypeError)/i.test(msg.content);
|
|
272916
|
+
const succeeded = !isError2;
|
|
272917
|
+
const preview = msg.content.slice(0, 80);
|
|
272918
|
+
let toolName = "unknown";
|
|
272919
|
+
if (msg.tool_call_id) {
|
|
272920
|
+
for (const m2 of recent) {
|
|
272921
|
+
if (m2.tool_calls) {
|
|
272922
|
+
for (const tc of m2.tool_calls) {
|
|
272923
|
+
if (tc.id === msg.tool_call_id) {
|
|
272924
|
+
toolName = tc.function.name;
|
|
272925
|
+
}
|
|
272926
|
+
}
|
|
272927
|
+
}
|
|
272928
|
+
}
|
|
272929
|
+
}
|
|
272930
|
+
if (!this._littlemanToolOutcomes.some((o2) => o2.turn === turn && o2.tool === toolName)) {
|
|
272931
|
+
this._littlemanToolOutcomes.push({ turn, tool: toolName, succeeded, preview });
|
|
272932
|
+
}
|
|
272933
|
+
}
|
|
272934
|
+
}
|
|
272935
|
+
while (this._littlemanToolOutcomes.length > 20)
|
|
272936
|
+
this._littlemanToolOutcomes.shift();
|
|
272937
|
+
const lastAssistant = [...recent].reverse().find((m2) => m2.role === "assistant" && typeof m2.content === "string");
|
|
272938
|
+
if (lastAssistant && typeof lastAssistant.content === "string") {
|
|
272939
|
+
const text = lastAssistant.content.toLowerCase();
|
|
272940
|
+
const claimsFailure = /(?:fail|error|didn't work|not working|unable to|cannot|couldn't|both .* fail|tools? (?:have |has )?been fail)/i.test(text);
|
|
272941
|
+
if (claimsFailure) {
|
|
272942
|
+
const recentOutcomes = this._littlemanToolOutcomes.slice(-4);
|
|
272943
|
+
const successes = recentOutcomes.filter((o2) => o2.succeeded);
|
|
272944
|
+
if (successes.length >= 1) {
|
|
272945
|
+
const successList = successes.map((o2) => `${o2.tool}: ${o2.preview.slice(0, 60)}`).join("; ");
|
|
272946
|
+
this.pendingUserMessages.push(`[LITTLEMAN] Correction: your recent tools DID succeed. Do not retry them.
|
|
272947
|
+
Successful results: ${successList}
|
|
272948
|
+
Build on these results instead of retrying. What is your NEXT step toward the goal?`);
|
|
272949
|
+
this.emit({
|
|
272950
|
+
type: "status",
|
|
272951
|
+
content: `Littleman: corrected false failure claim (${successes.length} tools succeeded)`,
|
|
272952
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
272953
|
+
});
|
|
272954
|
+
}
|
|
272955
|
+
}
|
|
272956
|
+
}
|
|
272957
|
+
const lastToolCalls = recent.filter((m2) => m2.role === "assistant" && m2.tool_calls?.length).flatMap((m2) => m2.tool_calls ?? []);
|
|
272958
|
+
for (const tc of lastToolCalls) {
|
|
272959
|
+
const name10 = tc.function.name;
|
|
272960
|
+
let args = {};
|
|
272961
|
+
try {
|
|
272962
|
+
args = JSON.parse(tc.function.arguments);
|
|
272963
|
+
} catch {
|
|
272964
|
+
}
|
|
272965
|
+
const argsKey = name10 === "shell" ? String(args.command ?? "").slice(0, 60) : name10 === "web_fetch" ? String(args.url ?? "").slice(0, 80) : String(args.path ?? args.url ?? args.query ?? "").slice(0, 60);
|
|
272966
|
+
const prior = this._littlemanToolOutcomes.find((o2) => o2.succeeded && o2.tool === name10 && o2.preview.includes(argsKey.slice(0, 30)) && o2.turn < turn);
|
|
272967
|
+
if (prior) {
|
|
272968
|
+
this.pendingUserMessages.push(`[LITTLEMAN] You already ran ${name10} successfully on turn ${prior.turn} with similar arguments. Result was: ${prior.preview.slice(0, 100)}
|
|
272969
|
+
Do NOT re-run it. Use the result you already have and proceed to the next step.`);
|
|
272970
|
+
this.emit({
|
|
272971
|
+
type: "status",
|
|
272972
|
+
content: `Littleman: prevented redundant ${name10} call (succeeded on turn ${prior.turn})`,
|
|
272973
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
272974
|
+
});
|
|
272975
|
+
break;
|
|
272976
|
+
}
|
|
272977
|
+
}
|
|
272978
|
+
}
|
|
272885
272979
|
/**
|
|
272886
272980
|
* Infer what the model should do next from the most recent messages.
|
|
272887
272981
|
* Analyzes the last few tool calls, errors, and assistant text to produce
|
|
@@ -273030,18 +273124,37 @@ ${pathKeep}${omitted}` };
|
|
|
273030
273124
|
return { ...msg, content: `[directory listing: ${lines} entries — top entries preserved]
|
|
273031
273125
|
${dirKeep}${omitted}` };
|
|
273032
273126
|
}
|
|
273033
|
-
case "web_fetch":
|
|
273034
|
-
|
|
273035
|
-
|
|
273036
|
-
|
|
273127
|
+
case "web_fetch": {
|
|
273128
|
+
const webPreview = contentLines.slice(0, 5).join("\n");
|
|
273129
|
+
const webOmitted = lines > 5 ? `
|
|
273130
|
+
[... ${lines - 5} more lines omitted for compaction]` : "";
|
|
273131
|
+
return { ...msg, content: `[web_fetch succeeded: ${content.length} chars, ${lines} lines — preview preserved]
|
|
273132
|
+
${webPreview}${webOmitted}` };
|
|
273133
|
+
}
|
|
273134
|
+
case "web_search": {
|
|
273135
|
+
const searchPreview = contentLines.slice(0, 5).join("\n");
|
|
273136
|
+
const searchOmitted = lines > 5 ? `
|
|
273137
|
+
[... ${lines - 5} more results omitted]` : "";
|
|
273138
|
+
return { ...msg, content: `[web_search succeeded: ${lines} results — top results preserved]
|
|
273139
|
+
${searchPreview}${searchOmitted}` };
|
|
273140
|
+
}
|
|
273037
273141
|
case "shell":
|
|
273038
|
-
case "background_run":
|
|
273142
|
+
case "background_run": {
|
|
273039
273143
|
if (/PASS|FAIL|error|warning/i.test(content))
|
|
273040
273144
|
return msg;
|
|
273041
|
-
|
|
273145
|
+
const cmdPreview = contentLines.slice(0, 5).join("\n");
|
|
273146
|
+
const cmdOmitted = lines > 5 ? `
|
|
273147
|
+
[... ${lines - 5} more lines omitted for compaction]` : "";
|
|
273148
|
+
return { ...msg, content: `[shell succeeded: ${lines} lines, ${content.length} chars — preview preserved]
|
|
273149
|
+
${cmdPreview}${cmdOmitted}` };
|
|
273150
|
+
}
|
|
273042
273151
|
default:
|
|
273043
273152
|
if (content.length > 2e3) {
|
|
273044
|
-
|
|
273153
|
+
const genPreview = contentLines.slice(0, 3).join("\n");
|
|
273154
|
+
const genOmitted = lines > 3 ? `
|
|
273155
|
+
[... ${lines - 3} more lines omitted]` : "";
|
|
273156
|
+
return { ...msg, content: `[${toolName ?? "tool"} succeeded: ${content.length} chars — preview preserved]
|
|
273157
|
+
${genPreview}${genOmitted}` };
|
|
273045
273158
|
}
|
|
273046
273159
|
return msg;
|
|
273047
273160
|
}
|
|
@@ -273141,19 +273254,45 @@ ${headContent}${sigLines ? "\n[key signatures]: " + sigLines : ""}`;
|
|
|
273141
273254
|
const cmd = String(tc.args.command || "").slice(0, 100);
|
|
273142
273255
|
const hasError = content.startsWith("Error:") || /FAIL|ERR!/i.test(content);
|
|
273143
273256
|
const hasPass = /PASS|passed|✓|success/i.test(content);
|
|
273257
|
+
const hasMaskedSuccess = /^\[shell succeeded:|^\[.+ succeeded —/.test(content);
|
|
273144
273258
|
let outcome;
|
|
273145
273259
|
if (hasError) {
|
|
273146
273260
|
const errorLines = content.split("\n").filter((l2) => /error|FAIL|✗|×|ERR!/i.test(l2)).slice(0, 3);
|
|
273147
273261
|
outcome = errorLines.length > 0 ? errorLines.join("; ").slice(0, 200) : content.slice(0, 200);
|
|
273148
273262
|
errors.push(`\`${cmd}\`: ${outcome.slice(0, 150)}`);
|
|
273149
|
-
} else if (hasPass) {
|
|
273150
|
-
|
|
273263
|
+
} else if (hasPass || hasMaskedSuccess) {
|
|
273264
|
+
const previewLines = content.split("\n").slice(1, 4).join(" ").trim();
|
|
273265
|
+
outcome = previewLines ? `succeeded: ${previewLines.slice(0, 120)}` : "succeeded";
|
|
273151
273266
|
} else {
|
|
273152
273267
|
outcome = content.slice(0, 150);
|
|
273153
273268
|
}
|
|
273154
273269
|
commandResults.push({ cmd, outcome });
|
|
273155
273270
|
break;
|
|
273156
273271
|
}
|
|
273272
|
+
case "web_fetch": {
|
|
273273
|
+
const url = String(tc.args.url || "").slice(0, 120);
|
|
273274
|
+
if (content.startsWith("Error:")) {
|
|
273275
|
+
const errMsg = content.slice(0, 200);
|
|
273276
|
+
errors.push(`web_fetch \`${url}\`: ${errMsg}`);
|
|
273277
|
+
commandResults.push({ cmd: `web_fetch ${url}`, outcome: errMsg });
|
|
273278
|
+
} else {
|
|
273279
|
+
const preview = content.split("\n").slice(0, 3).join(" ").trim().slice(0, 150);
|
|
273280
|
+
commandResults.push({ cmd: `web_fetch ${url}`, outcome: `succeeded: ${preview || `${content.length} chars`}` });
|
|
273281
|
+
}
|
|
273282
|
+
break;
|
|
273283
|
+
}
|
|
273284
|
+
case "web_search": {
|
|
273285
|
+
const query = String(tc.args.query || "").slice(0, 80);
|
|
273286
|
+
if (content.startsWith("Error:")) {
|
|
273287
|
+
errors.push(`web_search "${query}": ${content.slice(0, 200)}`);
|
|
273288
|
+
commandResults.push({ cmd: `web_search "${query}"`, outcome: content.slice(0, 200) });
|
|
273289
|
+
} else {
|
|
273290
|
+
const resultCount = (content.match(/\n/g) || []).length;
|
|
273291
|
+
const preview = content.split("\n").slice(0, 2).join(" ").trim().slice(0, 100);
|
|
273292
|
+
commandResults.push({ cmd: `web_search "${query}"`, outcome: `${resultCount} results: ${preview}` });
|
|
273293
|
+
}
|
|
273294
|
+
break;
|
|
273295
|
+
}
|
|
273157
273296
|
case "grep_search": {
|
|
273158
273297
|
const pattern = String(tc.args.pattern || "");
|
|
273159
273298
|
const matchCount = (content.match(/\n/g) || []).length;
|
|
@@ -292355,11 +292494,11 @@ ${CONTENT_BG_SEQ}`);
|
|
|
292355
292494
|
self2.cycleFocus();
|
|
292356
292495
|
return;
|
|
292357
292496
|
}
|
|
292358
|
-
if (key?.ctrl && key?.shift && key?.name === "
|
|
292359
|
-
self2.
|
|
292497
|
+
if (key?.ctrl && key?.shift && key?.name === "c") {
|
|
292498
|
+
self2.copySelection();
|
|
292360
292499
|
return;
|
|
292361
292500
|
}
|
|
292362
|
-
if (
|
|
292501
|
+
if (key?.ctrl && key?.shift && key?.name === "b") {
|
|
292363
292502
|
self2.armBlockSelection();
|
|
292364
292503
|
return;
|
|
292365
292504
|
}
|
|
@@ -292475,6 +292614,8 @@ ${CONTENT_BG_SEQ}`);
|
|
|
292475
292614
|
di.on("shiftdown", () => self2.scrollContentDown(3));
|
|
292476
292615
|
di.on("tab-empty", () => self2.cycleFocus());
|
|
292477
292616
|
di.on("ctrl-backslash", () => self2.cycleFocus());
|
|
292617
|
+
di.on("ctrl-shift-c", () => self2.copySelection());
|
|
292618
|
+
di.on("ctrl-shift-b", () => self2.armBlockSelection());
|
|
292478
292619
|
di.on("up", () => {
|
|
292479
292620
|
if (self2._suggestions.length > 0) {
|
|
292480
292621
|
self2.suggestUp();
|
|
@@ -315053,8 +315194,28 @@ var init_direct_input = __esm({
|
|
|
315053
315194
|
return;
|
|
315054
315195
|
}
|
|
315055
315196
|
return;
|
|
315056
|
-
case "u":
|
|
315197
|
+
case "u": {
|
|
315198
|
+
const parts = params.split(";");
|
|
315199
|
+
const codepoint = parseInt(parts[0] ?? "0");
|
|
315200
|
+
const modifiers = parseInt(parts[1] ?? "1");
|
|
315201
|
+
const hasCtrl = modifiers - 1 & 4;
|
|
315202
|
+
const hasShift = modifiers - 1 & 1;
|
|
315203
|
+
if (hasCtrl && hasShift) {
|
|
315204
|
+
if (codepoint === 67) {
|
|
315205
|
+
this.emit("ctrl-shift-c");
|
|
315206
|
+
return;
|
|
315207
|
+
}
|
|
315208
|
+
if (codepoint === 66) {
|
|
315209
|
+
this.emit("ctrl-shift-b");
|
|
315210
|
+
return;
|
|
315211
|
+
}
|
|
315212
|
+
if (codepoint === 86) {
|
|
315213
|
+
this.emit("ctrl-shift-v");
|
|
315214
|
+
return;
|
|
315215
|
+
}
|
|
315216
|
+
}
|
|
315057
315217
|
return;
|
|
315218
|
+
}
|
|
315058
315219
|
}
|
|
315059
315220
|
}
|
|
315060
315221
|
/** Handle SS3 sequence: \x1BO {final} (some terminals use this for arrows/Home/End) */
|
|
@@ -323553,6 +323714,201 @@ function handleVersion(res) {
|
|
|
323553
323714
|
function handleMetrics(res) {
|
|
323554
323715
|
textResponse(res, 200, formatMetrics(), "text/plain; version=0.0.4; charset=utf-8");
|
|
323555
323716
|
}
|
|
323717
|
+
function handleHelp(req2, res) {
|
|
323718
|
+
const version4 = getVersion3();
|
|
323719
|
+
const host = req2.headers.host ?? "localhost:11435";
|
|
323720
|
+
const base3 = `http://${host}`;
|
|
323721
|
+
const help = {
|
|
323722
|
+
name: "Open Agents",
|
|
323723
|
+
version: version4,
|
|
323724
|
+
description: "AI coding agent powered entirely by open-weight models. OpenAI-compatible API with full agentic tool-calling, text selection, MCP integration, and multi-model orchestration. No API keys required for local use.",
|
|
323725
|
+
quickstart: {
|
|
323726
|
+
chat: `curl ${base3}/v1/chat/completions -d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}'`,
|
|
323727
|
+
models: `curl ${base3}/v1/models`,
|
|
323728
|
+
stream: `curl ${base3}/v1/chat/completions -d '{"model":"auto","stream":true,"messages":[{"role":"user","content":"List files in the project"}]}'`,
|
|
323729
|
+
run_task: `curl -X POST ${base3}/v1/run -d '{"task":"Fix the failing tests","model":"auto"}'`
|
|
323730
|
+
},
|
|
323731
|
+
endpoints: {
|
|
323732
|
+
discovery: {
|
|
323733
|
+
"GET /help": "This guide — human and agent-friendly API reference",
|
|
323734
|
+
"GET /docs": "Interactive Swagger UI (browser)",
|
|
323735
|
+
"GET /openapi.json": "Full OpenAPI 3.0 specification (machine-readable)",
|
|
323736
|
+
"GET /health": "Liveness probe",
|
|
323737
|
+
"GET /health/ready": "Readiness probe (checks backend reachability)",
|
|
323738
|
+
"GET /version": "Package version, Node.js version, platform",
|
|
323739
|
+
"GET /metrics": "Prometheus-format metrics"
|
|
323740
|
+
},
|
|
323741
|
+
inference: {
|
|
323742
|
+
"GET /v1/models": "List all available models (local + sponsored, with prefixes)",
|
|
323743
|
+
"POST /v1/chat/completions": "OpenAI-compatible chat completion (supports streaming via stream:true)",
|
|
323744
|
+
"POST /v1/embeddings": "Generate embeddings",
|
|
323745
|
+
"POST /v1/generate": "Ollama-compatible text generation",
|
|
323746
|
+
"GET /api/tags": "Ollama-compatible model listing",
|
|
323747
|
+
"POST /api/chat": "Ollama-compatible chat",
|
|
323748
|
+
"POST /api/embed": "Ollama-compatible embeddings"
|
|
323749
|
+
},
|
|
323750
|
+
agentic: {
|
|
323751
|
+
"POST /v1/chat": "Stateful agentic chat — full tool access (file_read, shell, grep, etc.), SSE streaming",
|
|
323752
|
+
"GET /v1/chat/sessions": "List active chat sessions",
|
|
323753
|
+
"POST /v1/run": "Spawn autonomous task execution",
|
|
323754
|
+
"GET /v1/runs": "List all runs",
|
|
323755
|
+
"GET /v1/runs/:id": "Get run status and details",
|
|
323756
|
+
"GET /v1/runs/:id/output": "Get run output/logs",
|
|
323757
|
+
"DELETE /v1/runs/:id": "Cancel a running task"
|
|
323758
|
+
},
|
|
323759
|
+
tools_and_skills: {
|
|
323760
|
+
"GET /v1/tools": "List available agentic tools",
|
|
323761
|
+
"GET /v1/skills": "List available skills (slash commands)",
|
|
323762
|
+
"GET /v1/skills/:name": "Get skill details and content",
|
|
323763
|
+
"GET /v1/commands": "List slash commands",
|
|
323764
|
+
"POST /v1/commands/:cmd": "Execute a slash command",
|
|
323765
|
+
"GET /v1/agents": "List available agent types"
|
|
323766
|
+
},
|
|
323767
|
+
mcp: {
|
|
323768
|
+
"GET /v1/mcps": "List connected MCP (Model Context Protocol) servers",
|
|
323769
|
+
"GET /v1/mcps/:name": "Get MCP server details and available tools",
|
|
323770
|
+
"POST /v1/mcps/:name/call": "Call a tool on an MCP server — body: {tool, args}"
|
|
323771
|
+
},
|
|
323772
|
+
memory: {
|
|
323773
|
+
"GET /v1/memory": "Memory system summary",
|
|
323774
|
+
"POST /v1/memory/search": "Search episodic memory",
|
|
323775
|
+
"POST /v1/memory/write": "Write to memory store",
|
|
323776
|
+
"GET /v1/memory/episodes": "List stored episodes",
|
|
323777
|
+
"GET /v1/memory/failures": "List failure patterns"
|
|
323778
|
+
},
|
|
323779
|
+
workspace: {
|
|
323780
|
+
"GET /v1/files": "List directory contents (query: ?path=src/)",
|
|
323781
|
+
"POST /v1/files/read": "Read file content — body: {path}",
|
|
323782
|
+
"GET /v1/system": "OS info, GPU detection, installed tools",
|
|
323783
|
+
"GET /v1/context": "Current conversation context",
|
|
323784
|
+
"POST /v1/context/compact": "Compact session history"
|
|
323785
|
+
},
|
|
323786
|
+
config: {
|
|
323787
|
+
"GET /v1/config": "Current daemon configuration",
|
|
323788
|
+
"PATCH /v1/config": "Update configuration (admin scope required)",
|
|
323789
|
+
"GET /v1/config/model": "Current model",
|
|
323790
|
+
"PUT /v1/config/model": "Set model — body: {model}",
|
|
323791
|
+
"GET /v1/config/endpoint": "Current backend endpoint",
|
|
323792
|
+
"PUT /v1/config/endpoint": "Set backend endpoint — body: {endpoint}"
|
|
323793
|
+
},
|
|
323794
|
+
monitoring: {
|
|
323795
|
+
"GET /v1/events": "Server-Sent Events stream (task lifecycle, todo changes)",
|
|
323796
|
+
"GET /v1/usage": "Token usage summary",
|
|
323797
|
+
"GET /v1/audit": "Query audit log (query: ?since=, ?action=, ?limit=)",
|
|
323798
|
+
"GET /v1/cost": "Cost tracking per endpoint"
|
|
323799
|
+
},
|
|
323800
|
+
voice_and_vision: {
|
|
323801
|
+
"POST /v1/voice/tts": "Text-to-speech synthesis",
|
|
323802
|
+
"POST /v1/voice/asr": "Automatic speech recognition",
|
|
323803
|
+
"POST /v1/vision/describe": "Describe an image (vision pipeline)"
|
|
323804
|
+
}
|
|
323805
|
+
},
|
|
323806
|
+
mcp_integration: {
|
|
323807
|
+
description: "Open Agents can act as an MCP client — connect to external MCP servers and expose their tools through the /v1/mcps/* endpoints. Any AI agent or IDE that speaks the Model Context Protocol can discover and invoke these tools remotely.",
|
|
323808
|
+
discovery: `curl ${base3}/v1/mcps`,
|
|
323809
|
+
call_tool: `curl -X POST ${base3}/v1/mcps/YOUR_SERVER/call -d '{"tool":"tool_name","args":{"key":"value"}}'`
|
|
323810
|
+
},
|
|
323811
|
+
for_ai_agents: {
|
|
323812
|
+
description: "If you are an AI agent or coding assistant consuming this API, here is how to get started:",
|
|
323813
|
+
steps: [
|
|
323814
|
+
`1. GET ${base3}/v1/models — discover available models`,
|
|
323815
|
+
`2. POST ${base3}/v1/chat/completions — send messages (OpenAI-compatible format)`,
|
|
323816
|
+
`3. GET ${base3}/v1/tools — see what agentic tools are available`,
|
|
323817
|
+
`4. POST ${base3}/v1/chat — use the agentic chat endpoint for tool-calling tasks`,
|
|
323818
|
+
`5. GET ${base3}/v1/mcps — discover connected MCP servers and their tools`,
|
|
323819
|
+
`6. GET ${base3}/v1/skills — browse available skills for specialized tasks`
|
|
323820
|
+
],
|
|
323821
|
+
tips: [
|
|
323822
|
+
"Set stream:true in chat requests for real-time token streaming via SSE",
|
|
323823
|
+
"Use model:'auto' to let the server pick the best available model",
|
|
323824
|
+
"The /v1/chat endpoint supports full agentic tool-calling (file I/O, shell, grep, etc.)",
|
|
323825
|
+
"Use /v1/events for real-time notifications of task progress and system events",
|
|
323826
|
+
"Bearer tokens are optional for localhost access; required for remote/LAN access"
|
|
323827
|
+
]
|
|
323828
|
+
},
|
|
323829
|
+
authentication: {
|
|
323830
|
+
local: "No authentication required for loopback (127.0.0.1) access",
|
|
323831
|
+
remote: "Set OA_API_KEY or OA_API_KEYS env var; pass as Authorization: Bearer <key>",
|
|
323832
|
+
scopes: {
|
|
323833
|
+
read: "GET endpoints — model listing, file browsing, status queries",
|
|
323834
|
+
run: "POST endpoints — task execution, chat, tool invocation",
|
|
323835
|
+
admin: "Config writes, profile management, audit access"
|
|
323836
|
+
}
|
|
323837
|
+
},
|
|
323838
|
+
links: {
|
|
323839
|
+
docs: `${base3}/docs`,
|
|
323840
|
+
openapi: `${base3}/openapi.json`,
|
|
323841
|
+
health: `${base3}/health`,
|
|
323842
|
+
web_ui: base3
|
|
323843
|
+
}
|
|
323844
|
+
};
|
|
323845
|
+
const accept = req2.headers.accept ?? "";
|
|
323846
|
+
if (accept.includes("text/plain") || accept.includes("text/markdown")) {
|
|
323847
|
+
const md = renderHelpMarkdown(help);
|
|
323848
|
+
textResponse(res, 200, md, "text/plain; charset=utf-8");
|
|
323849
|
+
} else {
|
|
323850
|
+
jsonResponse(res, 200, help);
|
|
323851
|
+
}
|
|
323852
|
+
}
|
|
323853
|
+
function renderHelpMarkdown(help) {
|
|
323854
|
+
const h = help;
|
|
323855
|
+
const version4 = h.version;
|
|
323856
|
+
const base3 = h.links?.web_ui ?? "http://localhost:11435";
|
|
323857
|
+
const qs = h.quickstart;
|
|
323858
|
+
const agents = h.for_ai_agents;
|
|
323859
|
+
let out = `# Open Agents v${version4}
|
|
323860
|
+
|
|
323861
|
+
`;
|
|
323862
|
+
out += `${h.description}
|
|
323863
|
+
|
|
323864
|
+
`;
|
|
323865
|
+
out += `## Quick Start
|
|
323866
|
+
|
|
323867
|
+
`;
|
|
323868
|
+
for (const [label, cmd] of Object.entries(qs)) {
|
|
323869
|
+
out += ` ${label}:
|
|
323870
|
+
${cmd}
|
|
323871
|
+
|
|
323872
|
+
`;
|
|
323873
|
+
}
|
|
323874
|
+
out += `## Endpoints
|
|
323875
|
+
|
|
323876
|
+
`;
|
|
323877
|
+
const endpoints = h.endpoints;
|
|
323878
|
+
for (const [category, routes] of Object.entries(endpoints)) {
|
|
323879
|
+
out += `### ${category}
|
|
323880
|
+
`;
|
|
323881
|
+
for (const [route, desc] of Object.entries(routes)) {
|
|
323882
|
+
out += ` ${route.padEnd(36)} ${desc}
|
|
323883
|
+
`;
|
|
323884
|
+
}
|
|
323885
|
+
out += `
|
|
323886
|
+
`;
|
|
323887
|
+
}
|
|
323888
|
+
out += `## For AI Agents
|
|
323889
|
+
|
|
323890
|
+
`;
|
|
323891
|
+
for (const step of agents.steps) out += ` ${step}
|
|
323892
|
+
`;
|
|
323893
|
+
out += `
|
|
323894
|
+
`;
|
|
323895
|
+
for (const tip of agents.tips) out += ` - ${tip}
|
|
323896
|
+
`;
|
|
323897
|
+
out += `
|
|
323898
|
+
`;
|
|
323899
|
+
out += `## Links
|
|
323900
|
+
|
|
323901
|
+
`;
|
|
323902
|
+
out += ` Interactive docs: ${base3}/docs
|
|
323903
|
+
`;
|
|
323904
|
+
out += ` OpenAPI spec: ${base3}/openapi.json
|
|
323905
|
+
`;
|
|
323906
|
+
out += ` Web UI: ${base3}
|
|
323907
|
+
`;
|
|
323908
|
+
out += ` Health check: ${base3}/health
|
|
323909
|
+
`;
|
|
323910
|
+
return out;
|
|
323911
|
+
}
|
|
323556
323912
|
async function handleV1Models(res, ollamaUrl) {
|
|
323557
323913
|
try {
|
|
323558
323914
|
const models = await fetchAggregatedModels();
|
|
@@ -325169,6 +325525,10 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
325169
325525
|
handleMetrics(res);
|
|
325170
325526
|
return;
|
|
325171
325527
|
}
|
|
325528
|
+
if (pathname === "/help" && method === "GET") {
|
|
325529
|
+
handleHelp(req2, res);
|
|
325530
|
+
return;
|
|
325531
|
+
}
|
|
325172
325532
|
if (pathname === "/openapi.json" && method === "GET") {
|
|
325173
325533
|
jsonResponse(res, 200, getOpenApiSpec());
|
|
325174
325534
|
return;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
SCRAPE_API_KEY=948a46e9c7b94025aba48cf43f823950
|
|
2
|
+
SCRAPE_BIND=0.0.0.0
|
|
3
|
+
SCRAPE_PORT=8130
|
|
4
|
+
SCRAPE_REQUIRE_AUTH=0
|
|
5
|
+
SCRAPE_MAX_CONCURRENCY=4
|
|
6
|
+
SCRAPE_QUEUE_TIMEOUT_S=0
|
|
7
|
+
SCRAPE_RATE_LIMIT_RPS=60
|
|
8
|
+
SCRAPE_RATE_LIMIT_BURST=180
|
|
9
|
+
SCRAPE_RATE_LIMIT_LOCAL_BYPASS=1
|
|
10
|
+
SCRAPE_RATE_LIMIT_DISABLED=0
|
|
11
|
+
SCRAPE_RATE_LIMIT_WHITELIST=
|
|
12
|
+
SCRAPE_FILE_TTL_S=900
|
|
13
|
+
SCRAPE_FRAME_KEEPALIVE_S=45
|
|
14
|
+
SCRAPE_HEADLESS_DEFAULT=1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ok
|
package/package.json
CHANGED