agent-sh 0.12.9 → 0.12.11
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/agent/agent-loop.d.ts +4 -3
- package/dist/agent/agent-loop.js +31 -16
- package/dist/agent/history-file.d.ts +30 -1
- package/dist/agent/history-file.js +40 -17
- package/dist/agent/nuclear-form.d.ts +7 -0
- package/dist/agent/nuclear-form.js +19 -0
- package/dist/core.d.ts +2 -0
- package/dist/core.js +4 -0
- package/dist/event-bus.d.ts +8 -1
- package/dist/extensions/agent-backend.js +16 -0
- package/dist/extensions/openai.d.ts +5 -3
- package/dist/extensions/openai.js +23 -20
- package/dist/extensions/openrouter.js +6 -0
- package/dist/extensions/slash-commands.js +15 -9
- package/dist/init.js +1 -3
- package/dist/settings.d.ts +5 -0
- package/dist/settings.js +1 -0
- package/dist/types.d.ts +9 -0
- package/examples/extensions/ollama.ts +96 -0
- package/examples/extensions/peer-mesh.ts +260 -248
- package/examples/extensions/rtk-proxy.ts +143 -0
- package/package.json +1 -1
- package/examples/extensions/openrouter.ts +0 -87
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama provider extension — local daemon and Ollama Cloud.
|
|
3
|
+
*
|
|
4
|
+
* OLLAMA_API_KEY → Ollama Cloud (https://ollama.com)
|
|
5
|
+
* OLLAMA_HOST → local host override (default http://localhost:11434)
|
|
6
|
+
*
|
|
7
|
+
* Catalog comes from /api/tags; per-model context length is fetched
|
|
8
|
+
* from /api/show (model_info["${arch}.context_length"]). Chat goes
|
|
9
|
+
* through the OpenAI-compatible /v1/chat/completions shim.
|
|
10
|
+
*
|
|
11
|
+
* Setup (cloud):
|
|
12
|
+
* export OLLAMA_API_KEY="your-key"
|
|
13
|
+
*
|
|
14
|
+
* Setup (local):
|
|
15
|
+
* ollama serve # default http://localhost:11434
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* agent-sh -e ./examples/extensions/ollama.ts
|
|
19
|
+
*
|
|
20
|
+
* # Or add to settings.json:
|
|
21
|
+
* { "extensions": ["./examples/extensions/ollama.ts"] }
|
|
22
|
+
*/
|
|
23
|
+
import type { ExtensionContext } from "agent-sh/types";
|
|
24
|
+
|
|
25
|
+
const ECHO_REASONING_PATTERNS: RegExp[] = [/deepseek/i];
|
|
26
|
+
|
|
27
|
+
export default function activate(ctx: ExtensionContext): void {
|
|
28
|
+
const apiKey = process.env.OLLAMA_API_KEY;
|
|
29
|
+
const host = apiKey
|
|
30
|
+
? "https://ollama.com"
|
|
31
|
+
: (process.env.OLLAMA_HOST ?? "http://localhost:11434").replace(/\/$/, "");
|
|
32
|
+
const id = apiKey ? "ollama-cloud" : "ollama";
|
|
33
|
+
|
|
34
|
+
// OpenAI SDK rejects an empty apiKey; the local daemon ignores the value.
|
|
35
|
+
const sdkKey = apiKey || "no-key";
|
|
36
|
+
const baseURL = `${host}/v1`;
|
|
37
|
+
const headers: Record<string, string> = {};
|
|
38
|
+
if (apiKey) headers.Authorization = `Bearer ${apiKey}`;
|
|
39
|
+
|
|
40
|
+
ctx.bus.emit("provider:register", { id, apiKey: sdkKey, baseURL, models: [] });
|
|
41
|
+
|
|
42
|
+
fetchCatalog(host, headers).then((models) => {
|
|
43
|
+
if (models.length === 0) return;
|
|
44
|
+
ctx.bus.emit("provider:register", {
|
|
45
|
+
id,
|
|
46
|
+
apiKey: sdkKey,
|
|
47
|
+
baseURL,
|
|
48
|
+
defaultModel: models[0]!.id,
|
|
49
|
+
models,
|
|
50
|
+
});
|
|
51
|
+
}).catch(() => { /* leave empty — user supplies via --model */ });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function fetchCatalog(
|
|
55
|
+
host: string,
|
|
56
|
+
headers: Record<string, string>,
|
|
57
|
+
): Promise<{ id: string; contextWindow?: number; echoReasoning: boolean }[]> {
|
|
58
|
+
const tagsRes = await fetch(`${host}/api/tags`, { headers });
|
|
59
|
+
if (!tagsRes.ok) return [];
|
|
60
|
+
const tagsData = await tagsRes.json() as { models?: { name: string }[] };
|
|
61
|
+
const names = (tagsData.models ?? []).map((m) => m.name);
|
|
62
|
+
if (names.length === 0) return [];
|
|
63
|
+
|
|
64
|
+
const ctxs = await Promise.all(
|
|
65
|
+
names.map((name) => fetchContextLength(host, headers, name).catch(() => undefined)),
|
|
66
|
+
);
|
|
67
|
+
return names.map((name, i) => ({
|
|
68
|
+
id: name,
|
|
69
|
+
contextWindow: ctxs[i],
|
|
70
|
+
echoReasoning: ECHO_REASONING_PATTERNS.some((re) => re.test(name)),
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function fetchContextLength(
|
|
75
|
+
host: string,
|
|
76
|
+
headers: Record<string, string>,
|
|
77
|
+
name: string,
|
|
78
|
+
): Promise<number | undefined> {
|
|
79
|
+
const res = await fetch(`${host}/api/show`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
82
|
+
body: JSON.stringify({ name }),
|
|
83
|
+
});
|
|
84
|
+
if (!res.ok) return undefined;
|
|
85
|
+
const data = await res.json() as { model_info?: Record<string, unknown> };
|
|
86
|
+
const info = data.model_info ?? {};
|
|
87
|
+
const arch = info["general.architecture"] as string | undefined;
|
|
88
|
+
if (arch) {
|
|
89
|
+
const ctx = info[`${arch}.context_length`];
|
|
90
|
+
if (typeof ctx === "number") return ctx;
|
|
91
|
+
}
|
|
92
|
+
for (const [k, v] of Object.entries(info)) {
|
|
93
|
+
if (k.endsWith(".context_length") && typeof v === "number") return v;
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|