0xkobold 0.7.2 → 0.8.0
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/HEARTBEAT.md +239 -0
- package/IDENTITY.md +12 -0
- package/README.md +138 -4
- package/SOUL.md +21 -0
- package/dist/package.json +10 -5
- package/dist/src/agent/bootstrap-loader.js +295 -66
- package/dist/src/agent/bootstrap-loader.js.map +1 -1
- package/dist/src/agent/context-pruning.js +10 -5
- package/dist/src/agent/context-pruning.js.map +1 -1
- package/dist/src/agent/embedded-runner.js +29 -15
- package/dist/src/agent/embedded-runner.js.map +1 -1
- package/dist/src/agent/index.js +5 -2
- package/dist/src/agent/index.js.map +1 -1
- package/dist/src/agent/system-prompt.js +167 -20
- package/dist/src/agent/system-prompt.js.map +1 -1
- package/dist/src/agent/tools/spawn-agent.js +72 -5
- package/dist/src/agent/tools/spawn-agent.js.map +1 -1
- package/dist/src/channels/slack/webhook.js +2 -2
- package/dist/src/channels/slack/webhook.js.map +1 -1
- package/dist/src/channels/telegram/bot.js +4 -4
- package/dist/src/channels/telegram/bot.js.map +1 -1
- package/dist/src/channels/whatsapp/integration.js +4 -4
- package/dist/src/channels/whatsapp/integration.js.map +1 -1
- package/dist/src/cli/commands/gateway.js +9 -10
- package/dist/src/cli/commands/gateway.js.map +1 -1
- package/dist/src/cli/commands/init.js +90 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/setup.js +53 -0
- package/dist/src/cli/commands/setup.js.map +1 -1
- package/dist/src/cli/index.js +0 -0
- package/dist/src/config/unified-config.js +5 -0
- package/dist/src/config/unified-config.js.map +1 -1
- package/dist/src/cron/index.js +2 -0
- package/dist/src/cron/index.js.map +1 -1
- package/dist/src/cron/nl-parser.js +522 -0
- package/dist/src/cron/nl-parser.js.map +1 -0
- package/dist/src/cron/runner.js +6 -31
- package/dist/src/cron/runner.js.map +1 -1
- package/dist/src/event-bus/index.js.map +1 -1
- package/dist/src/extensions/core/agent-orchestrator-extension.js +200 -148
- package/dist/src/extensions/core/agent-orchestrator-extension.js.map +1 -1
- package/dist/src/extensions/core/diagnostics-extension.js +93 -56
- package/dist/src/extensions/core/diagnostics-extension.js.map +1 -1
- package/dist/src/extensions/core/draconic-safety-extension.js +256 -3
- package/dist/src/extensions/core/draconic-safety-extension.js.map +1 -1
- package/dist/src/extensions/core/heartbeat-extension.js +416 -150
- package/dist/src/extensions/core/heartbeat-extension.js.map +1 -1
- package/dist/src/extensions/core/{generative-agents-extension.js → learning-extension.js} +90 -128
- package/dist/src/extensions/core/learning-extension.js.map +1 -0
- package/dist/src/extensions/core/perennial-memory-extension.js +884 -87
- package/dist/src/extensions/core/perennial-memory-extension.js.map +1 -1
- package/dist/src/extensions/core/routed-ollama-extension.js +345 -0
- package/dist/src/extensions/core/routed-ollama-extension.js.map +1 -0
- package/dist/src/extensions/core/task-manager-extension.js +25 -2
- package/dist/src/extensions/core/task-manager-extension.js.map +1 -1
- package/dist/src/extensions/core/websearch-enhanced-extension.js +81 -23
- package/dist/src/extensions/core/websearch-enhanced-extension.js.map +1 -1
- package/dist/src/extensions/core/workspace-footer-extension.js +40 -63
- package/dist/src/extensions/core/workspace-footer-extension.js.map +1 -1
- package/dist/src/extensions/loader.js +5 -1
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/gateway/gateway-server.js +74 -3
- package/dist/src/gateway/gateway-server.js.map +1 -1
- package/dist/src/gateway/index.js +2 -2
- package/dist/src/gateway/index.js.map +1 -1
- package/dist/src/gateway/methods/agent.js +1 -1
- package/dist/src/gateway/methods/agent.js.map +1 -1
- package/dist/src/gateway/methods/index.js +4 -0
- package/dist/src/gateway/methods/index.js.map +1 -1
- package/dist/src/gateway/methods/node.js +261 -0
- package/dist/src/gateway/methods/node.js.map +1 -0
- package/dist/src/gateway/queue-modes.js +356 -0
- package/dist/src/gateway/queue-modes.js.map +1 -0
- package/dist/src/index.js +47 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/llm/community-analytics.js +569 -0
- package/dist/src/llm/community-analytics.js.map +1 -0
- package/dist/src/llm/index.js +28 -4
- package/dist/src/llm/index.js.map +1 -1
- package/dist/src/llm/model-discovery.js +335 -0
- package/dist/src/llm/model-discovery.js.map +1 -0
- package/dist/src/llm/model-popularity.js +566 -0
- package/dist/src/llm/model-popularity.js.map +1 -0
- package/dist/src/llm/model-scoring-db.js +553 -0
- package/dist/src/llm/model-scoring-db.js.map +1 -0
- package/dist/src/llm/multi-provider.js +258 -0
- package/dist/src/llm/multi-provider.js.map +1 -0
- package/dist/src/llm/ollama.js +133 -187
- package/dist/src/llm/ollama.js.map +1 -1
- package/dist/src/llm/router-commands.js +773 -0
- package/dist/src/llm/router-commands.js.map +1 -0
- package/dist/src/llm/router-core.js +600 -0
- package/dist/src/llm/router-core.js.map +1 -0
- package/dist/src/memory/checkpoint-manager.js +278 -0
- package/dist/src/memory/checkpoint-manager.js.map +1 -0
- package/dist/src/memory/conflict-detector.js +279 -0
- package/dist/src/memory/conflict-detector.js.map +1 -0
- package/dist/src/memory/context-graph.js +360 -0
- package/dist/src/memory/context-graph.js.map +1 -0
- package/dist/src/memory/dialectic/benchmark-cli.js +200 -0
- package/dist/src/memory/dialectic/benchmark-cli.js.map +1 -0
- package/dist/src/memory/dialectic/debug-reasoning.js +37 -0
- package/dist/src/memory/dialectic/debug-reasoning.js.map +1 -0
- package/dist/src/memory/dialectic/index.js +135 -0
- package/dist/src/memory/dialectic/index.js.map +1 -0
- package/dist/src/memory/dialectic/nudges.js +380 -0
- package/dist/src/memory/dialectic/nudges.js.map +1 -0
- package/dist/src/memory/dialectic/reasoning-engine.js +607 -0
- package/dist/src/memory/dialectic/reasoning-engine.js.map +1 -0
- package/dist/src/memory/dialectic/reasoning.js +390 -0
- package/dist/src/memory/dialectic/reasoning.js.map +1 -0
- package/dist/src/memory/dialectic/skill-creation.js +481 -0
- package/dist/src/memory/dialectic/skill-creation.js.map +1 -0
- package/dist/src/memory/dialectic/store.js +663 -0
- package/dist/src/memory/dialectic/store.js.map +1 -0
- package/dist/src/memory/dialectic/types.js +11 -0
- package/dist/src/memory/dialectic/types.js.map +1 -0
- package/dist/src/memory/index.js +24 -2
- package/dist/src/memory/index.js.map +1 -1
- package/dist/src/memory/memory-decay.js +350 -0
- package/dist/src/memory/memory-decay.js.map +1 -0
- package/dist/src/memory/memory-integration.js +5 -5
- package/dist/src/memory/memory-integration.js.map +1 -1
- package/dist/src/memory/migrate-memory-stream.js +97 -0
- package/dist/src/memory/migrate-memory-stream.js.map +1 -0
- package/dist/src/memory/session-memory-bridge.js +49 -5
- package/dist/src/memory/session-memory-bridge.js.map +1 -1
- package/dist/src/memory/session-store.js +123 -0
- package/dist/src/memory/session-store.js.map +1 -1
- package/dist/src/memory/smart-write-rules.js +164 -0
- package/dist/src/memory/smart-write-rules.js.map +1 -0
- package/dist/src/memory/tiered-memory.js +436 -0
- package/dist/src/memory/tiered-memory.js.map +1 -0
- package/dist/src/memory/types.js +6 -0
- package/dist/src/memory/types.js.map +1 -0
- package/dist/src/memory/verify-migration.js +99 -0
- package/dist/src/memory/verify-migration.js.map +1 -0
- package/dist/src/pi-config.js +11 -9
- package/dist/src/pi-config.js.map +1 -1
- package/dist/src/skills/conditional-skills.js +464 -0
- package/dist/src/skills/conditional-skills.js.map +1 -0
- package/dist/src/skills/index.js +5 -0
- package/dist/src/skills/index.js.map +1 -1
- package/dist/src/skills/loader.js +56 -0
- package/dist/src/skills/loader.js.map +1 -1
- package/dist/src/skills/skill-manage.js +417 -0
- package/dist/src/skills/skill-manage.js.map +1 -0
- package/dist/src/tui/commands/orchestration-commands.js +62 -0
- package/dist/src/tui/commands/orchestration-commands.js.map +1 -1
- package/package.json +10 -5
- package/skills/model-router-test.ts +65 -0
- package/dist/src/extensions/core/auto-security-scan-extension.js +0 -41
- package/dist/src/extensions/core/auto-security-scan-extension.js.map +0 -1
- package/dist/src/extensions/core/cloudflare-browser-extension.js +0 -389
- package/dist/src/extensions/core/cloudflare-browser-extension.js.map +0 -1
- package/dist/src/extensions/core/compaction-safeguard.js +0 -223
- package/dist/src/extensions/core/compaction-safeguard.js.map +0 -1
- package/dist/src/extensions/core/generative-agents-extension.js.map +0 -1
- package/dist/src/extensions/core/obsidian-bridge-extension.js +0 -488
- package/dist/src/extensions/core/obsidian-bridge-extension.js.map +0 -1
- package/dist/src/llm/router.js +0 -145
- package/dist/src/llm/router.js.map +0 -1
- package/skills/kobold-scan-skill/node_modules/.package-lock.json +0 -172
- package/skills/kobold-scan-skill/node_modules/ansi-styles/index.d.ts +0 -345
- package/skills/kobold-scan-skill/node_modules/ansi-styles/index.js +0 -163
- package/skills/kobold-scan-skill/node_modules/ansi-styles/license +0 -9
- package/skills/kobold-scan-skill/node_modules/ansi-styles/package.json +0 -56
- package/skills/kobold-scan-skill/node_modules/ansi-styles/readme.md +0 -152
- package/skills/kobold-scan-skill/node_modules/balanced-match/.github/FUNDING.yml +0 -2
- package/skills/kobold-scan-skill/node_modules/balanced-match/LICENSE.md +0 -21
- package/skills/kobold-scan-skill/node_modules/balanced-match/README.md +0 -97
- package/skills/kobold-scan-skill/node_modules/balanced-match/index.js +0 -62
- package/skills/kobold-scan-skill/node_modules/balanced-match/package.json +0 -48
- package/skills/kobold-scan-skill/node_modules/brace-expansion/.github/FUNDING.yml +0 -2
- package/skills/kobold-scan-skill/node_modules/brace-expansion/LICENSE +0 -21
- package/skills/kobold-scan-skill/node_modules/brace-expansion/README.md +0 -135
- package/skills/kobold-scan-skill/node_modules/brace-expansion/index.js +0 -203
- package/skills/kobold-scan-skill/node_modules/brace-expansion/package.json +0 -49
- package/skills/kobold-scan-skill/node_modules/chalk/index.d.ts +0 -415
- package/skills/kobold-scan-skill/node_modules/chalk/license +0 -9
- package/skills/kobold-scan-skill/node_modules/chalk/package.json +0 -68
- package/skills/kobold-scan-skill/node_modules/chalk/readme.md +0 -341
- package/skills/kobold-scan-skill/node_modules/chalk/source/index.js +0 -229
- package/skills/kobold-scan-skill/node_modules/chalk/source/templates.js +0 -134
- package/skills/kobold-scan-skill/node_modules/chalk/source/util.js +0 -39
- package/skills/kobold-scan-skill/node_modules/color-convert/CHANGELOG.md +0 -54
- package/skills/kobold-scan-skill/node_modules/color-convert/LICENSE +0 -21
- package/skills/kobold-scan-skill/node_modules/color-convert/README.md +0 -68
- package/skills/kobold-scan-skill/node_modules/color-convert/conversions.js +0 -839
- package/skills/kobold-scan-skill/node_modules/color-convert/index.js +0 -81
- package/skills/kobold-scan-skill/node_modules/color-convert/package.json +0 -48
- package/skills/kobold-scan-skill/node_modules/color-convert/route.js +0 -97
- package/skills/kobold-scan-skill/node_modules/color-name/LICENSE +0 -8
- package/skills/kobold-scan-skill/node_modules/color-name/README.md +0 -11
- package/skills/kobold-scan-skill/node_modules/color-name/index.js +0 -152
- package/skills/kobold-scan-skill/node_modules/color-name/package.json +0 -28
- package/skills/kobold-scan-skill/node_modules/commander/LICENSE +0 -22
- package/skills/kobold-scan-skill/node_modules/commander/Readme.md +0 -1129
- package/skills/kobold-scan-skill/node_modules/commander/esm.mjs +0 -16
- package/skills/kobold-scan-skill/node_modules/commander/index.js +0 -27
- package/skills/kobold-scan-skill/node_modules/commander/lib/argument.js +0 -147
- package/skills/kobold-scan-skill/node_modules/commander/lib/command.js +0 -2179
- package/skills/kobold-scan-skill/node_modules/commander/lib/error.js +0 -45
- package/skills/kobold-scan-skill/node_modules/commander/lib/help.js +0 -461
- package/skills/kobold-scan-skill/node_modules/commander/lib/option.js +0 -326
- package/skills/kobold-scan-skill/node_modules/commander/lib/suggestSimilar.js +0 -100
- package/skills/kobold-scan-skill/node_modules/commander/package-support.json +0 -16
- package/skills/kobold-scan-skill/node_modules/commander/package.json +0 -80
- package/skills/kobold-scan-skill/node_modules/commander/typings/index.d.ts +0 -891
- package/skills/kobold-scan-skill/node_modules/fs.realpath/LICENSE +0 -43
- package/skills/kobold-scan-skill/node_modules/fs.realpath/README.md +0 -33
- package/skills/kobold-scan-skill/node_modules/fs.realpath/index.js +0 -66
- package/skills/kobold-scan-skill/node_modules/fs.realpath/old.js +0 -303
- package/skills/kobold-scan-skill/node_modules/fs.realpath/package.json +0 -26
- package/skills/kobold-scan-skill/node_modules/glob/LICENSE +0 -15
- package/skills/kobold-scan-skill/node_modules/glob/README.md +0 -399
- package/skills/kobold-scan-skill/node_modules/glob/common.js +0 -244
- package/skills/kobold-scan-skill/node_modules/glob/glob.js +0 -790
- package/skills/kobold-scan-skill/node_modules/glob/package.json +0 -55
- package/skills/kobold-scan-skill/node_modules/glob/sync.js +0 -486
- package/skills/kobold-scan-skill/node_modules/has-flag/index.d.ts +0 -39
- package/skills/kobold-scan-skill/node_modules/has-flag/index.js +0 -8
- package/skills/kobold-scan-skill/node_modules/has-flag/license +0 -9
- package/skills/kobold-scan-skill/node_modules/has-flag/package.json +0 -46
- package/skills/kobold-scan-skill/node_modules/has-flag/readme.md +0 -89
- package/skills/kobold-scan-skill/node_modules/inflight/LICENSE +0 -15
- package/skills/kobold-scan-skill/node_modules/inflight/README.md +0 -37
- package/skills/kobold-scan-skill/node_modules/inflight/inflight.js +0 -54
- package/skills/kobold-scan-skill/node_modules/inflight/package.json +0 -29
- package/skills/kobold-scan-skill/node_modules/inherits/LICENSE +0 -16
- package/skills/kobold-scan-skill/node_modules/inherits/README.md +0 -42
- package/skills/kobold-scan-skill/node_modules/inherits/inherits.js +0 -9
- package/skills/kobold-scan-skill/node_modules/inherits/inherits_browser.js +0 -27
- package/skills/kobold-scan-skill/node_modules/inherits/package.json +0 -29
- package/skills/kobold-scan-skill/node_modules/minimatch/LICENSE +0 -15
- package/skills/kobold-scan-skill/node_modules/minimatch/README.md +0 -259
- package/skills/kobold-scan-skill/node_modules/minimatch/lib/path.js +0 -4
- package/skills/kobold-scan-skill/node_modules/minimatch/minimatch.js +0 -944
- package/skills/kobold-scan-skill/node_modules/minimatch/package.json +0 -35
- package/skills/kobold-scan-skill/node_modules/once/LICENSE +0 -15
- package/skills/kobold-scan-skill/node_modules/once/README.md +0 -79
- package/skills/kobold-scan-skill/node_modules/once/once.js +0 -42
- package/skills/kobold-scan-skill/node_modules/once/package.json +0 -33
- package/skills/kobold-scan-skill/node_modules/supports-color/browser.js +0 -5
- package/skills/kobold-scan-skill/node_modules/supports-color/index.js +0 -135
- package/skills/kobold-scan-skill/node_modules/supports-color/license +0 -9
- package/skills/kobold-scan-skill/node_modules/supports-color/package.json +0 -53
- package/skills/kobold-scan-skill/node_modules/supports-color/readme.md +0 -76
- package/skills/kobold-scan-skill/node_modules/wrappy/LICENSE +0 -15
- package/skills/kobold-scan-skill/node_modules/wrappy/README.md +0 -36
- package/skills/kobold-scan-skill/node_modules/wrappy/package.json +0 -29
- package/skills/kobold-scan-skill/node_modules/wrappy/wrappy.js +0 -33
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Provider Router
|
|
3
|
+
*
|
|
4
|
+
* Extends AdaptiveModelRouter to support multiple LLM providers.
|
|
5
|
+
* Routes requests to the appropriate provider based on model prefix.
|
|
6
|
+
*
|
|
7
|
+
* Model prefixes:
|
|
8
|
+
* - ollama/* → OllamaProvider (local or cloud)
|
|
9
|
+
* - claude/* → AnthropicProvider
|
|
10
|
+
* - anthropic/* → AnthropicProvider (alias)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* const router = await getMultiProviderRouter();
|
|
14
|
+
* const response = await router.chat({ model: 'claude/claude-3-5-sonnet', ... });
|
|
15
|
+
*/
|
|
16
|
+
import { createRouter } from './router-core';
|
|
17
|
+
import { getOllamaProvider } from './ollama';
|
|
18
|
+
import { createAnthropicProvider } from './anthropic';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Provider Registry
|
|
21
|
+
// ============================================================================
|
|
22
|
+
const DEFAULT_PROVIDERS = [
|
|
23
|
+
{
|
|
24
|
+
name: 'ollama',
|
|
25
|
+
prefix: 'ollama/',
|
|
26
|
+
create: () => getOllamaProvider(),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'claude',
|
|
30
|
+
prefix: 'claude/',
|
|
31
|
+
create: () => createAnthropicProvider(),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'anthropic',
|
|
35
|
+
prefix: 'anthropic/',
|
|
36
|
+
create: () => createAnthropicProvider(), // Alias
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
class ProviderRegistry {
|
|
40
|
+
providers = new Map();
|
|
41
|
+
configs;
|
|
42
|
+
status = new Map();
|
|
43
|
+
constructor(configs = DEFAULT_PROVIDERS) {
|
|
44
|
+
this.configs = configs;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get provider for a model
|
|
48
|
+
*/
|
|
49
|
+
getProvider(model) {
|
|
50
|
+
// Extract prefix (e.g., "ollama/", "claude/")
|
|
51
|
+
const prefixMatch = this.configs.find(cfg => model.startsWith(cfg.prefix));
|
|
52
|
+
if (prefixMatch) {
|
|
53
|
+
const providerName = prefixMatch.name;
|
|
54
|
+
// Cache provider instance
|
|
55
|
+
if (!this.providers.has(providerName)) {
|
|
56
|
+
this.providers.set(providerName, prefixMatch.create());
|
|
57
|
+
}
|
|
58
|
+
return this.providers.get(providerName);
|
|
59
|
+
}
|
|
60
|
+
// Default to Ollama if no prefix
|
|
61
|
+
if (!this.providers.has('ollama')) {
|
|
62
|
+
this.providers.set('ollama', getOllamaProvider());
|
|
63
|
+
}
|
|
64
|
+
return this.providers.get('ollama');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get provider name from model
|
|
68
|
+
*/
|
|
69
|
+
getProviderName(model) {
|
|
70
|
+
const prefixMatch = this.configs.find(cfg => model.startsWith(cfg.prefix));
|
|
71
|
+
return prefixMatch?.name ?? 'ollama';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Strip provider prefix from model name
|
|
75
|
+
*/
|
|
76
|
+
stripPrefix(model) {
|
|
77
|
+
const prefixMatch = this.configs.find(cfg => model.startsWith(cfg.prefix));
|
|
78
|
+
if (prefixMatch) {
|
|
79
|
+
return model.slice(prefixMatch.prefix.length);
|
|
80
|
+
}
|
|
81
|
+
return model;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if provider is available
|
|
85
|
+
*/
|
|
86
|
+
async checkAvailability(providerName) {
|
|
87
|
+
const config = this.configs.find(cfg => cfg.name === providerName);
|
|
88
|
+
if (!config)
|
|
89
|
+
return false;
|
|
90
|
+
try {
|
|
91
|
+
const provider = this.getProvider(`${config.prefix}test`);
|
|
92
|
+
// Try to list models or make a minimal call
|
|
93
|
+
if (provider.listModels) {
|
|
94
|
+
const models = await provider.listModels();
|
|
95
|
+
return models.length > 0;
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get all provider statuses
|
|
105
|
+
*/
|
|
106
|
+
async getStatuses() {
|
|
107
|
+
const statuses = [];
|
|
108
|
+
for (const config of this.configs) {
|
|
109
|
+
const available = await this.checkAvailability(config.name);
|
|
110
|
+
const provider = this.providers.get(config.name);
|
|
111
|
+
statuses.push({
|
|
112
|
+
name: config.name,
|
|
113
|
+
available,
|
|
114
|
+
modelCount: available ? (await provider?.listModels?.() ?? []).length : 0,
|
|
115
|
+
lastChecked: Date.now(),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return statuses;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Register a new provider
|
|
122
|
+
*/
|
|
123
|
+
register(config) {
|
|
124
|
+
this.configs.push(config);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* List configured providers
|
|
128
|
+
*/
|
|
129
|
+
listProviders() {
|
|
130
|
+
return this.configs.map(cfg => cfg.name);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Multi-Provider Router
|
|
135
|
+
// ============================================================================
|
|
136
|
+
let registryInstance = null;
|
|
137
|
+
let multiProviderRouter = null;
|
|
138
|
+
export class MultiProviderRouter {
|
|
139
|
+
name = 'multi-provider';
|
|
140
|
+
registry;
|
|
141
|
+
defaultProvider = 'ollama';
|
|
142
|
+
routers = new Map();
|
|
143
|
+
constructor(registry) {
|
|
144
|
+
this.registry = registry;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Chat using appropriate provider
|
|
148
|
+
*/
|
|
149
|
+
async chat(options) {
|
|
150
|
+
const providerName = this.registry.getProviderName(options.model);
|
|
151
|
+
const provider = this.registry.getProvider(options.model);
|
|
152
|
+
const modelName = this.registry.stripPrefix(options.model);
|
|
153
|
+
// Adapt ChatOptions for the provider
|
|
154
|
+
const providerOptions = {
|
|
155
|
+
...options,
|
|
156
|
+
model: modelName,
|
|
157
|
+
};
|
|
158
|
+
console.log(`[MultiProvider] Routing to ${providerName}: ${modelName}`);
|
|
159
|
+
// Track timing for performance
|
|
160
|
+
const startTime = Date.now();
|
|
161
|
+
try {
|
|
162
|
+
const response = await provider.chat(providerOptions);
|
|
163
|
+
const duration = Date.now() - startTime;
|
|
164
|
+
console.log(`[MultiProvider] ${providerName}/${modelName} completed in ${duration}ms`);
|
|
165
|
+
// Add provider info to response
|
|
166
|
+
return {
|
|
167
|
+
...response,
|
|
168
|
+
model: `${providerName}/${modelName}`,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const duration = Date.now() - startTime;
|
|
173
|
+
console.error(`[MultiProvider] ${providerName}/${modelName} failed after ${duration}ms:`, error);
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* List models from all providers
|
|
179
|
+
*/
|
|
180
|
+
async listModels() {
|
|
181
|
+
const allModels = [];
|
|
182
|
+
for (const providerName of this.registry.listProviders()) {
|
|
183
|
+
try {
|
|
184
|
+
const provider = this.registry.getProvider(`${providerName}/test`);
|
|
185
|
+
if (provider.listModels) {
|
|
186
|
+
const models = await provider.listModels();
|
|
187
|
+
for (const model of models) {
|
|
188
|
+
allModels.push(`${providerName}/${model}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
console.warn(`[MultiProvider] Failed to list models from ${providerName}:`, error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return allModels;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get provider registry
|
|
200
|
+
*/
|
|
201
|
+
getRegistry() {
|
|
202
|
+
return this.registry;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get adaptive router for a specific provider
|
|
206
|
+
*/
|
|
207
|
+
async getRouterForProvider(providerName) {
|
|
208
|
+
if (this.routers.has(providerName)) {
|
|
209
|
+
return this.routers.get(providerName);
|
|
210
|
+
}
|
|
211
|
+
const config = this.registry.listProviders().includes(providerName);
|
|
212
|
+
if (!config)
|
|
213
|
+
return null;
|
|
214
|
+
const provider = this.registry.getProvider(`${providerName}/default`);
|
|
215
|
+
const router = await createRouter(provider, 'default');
|
|
216
|
+
this.routers.set(providerName, router);
|
|
217
|
+
return router;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// Singleton Access
|
|
222
|
+
// ============================================================================
|
|
223
|
+
export function getProviderRegistry() {
|
|
224
|
+
if (!registryInstance) {
|
|
225
|
+
registryInstance = new ProviderRegistry();
|
|
226
|
+
}
|
|
227
|
+
return registryInstance;
|
|
228
|
+
}
|
|
229
|
+
export async function getMultiProviderRouter() {
|
|
230
|
+
if (!multiProviderRouter) {
|
|
231
|
+
const registry = getProviderRegistry();
|
|
232
|
+
multiProviderRouter = new MultiProviderRouter(registry);
|
|
233
|
+
console.log('[MultiProvider] Initialized with providers:', registry.listProviders());
|
|
234
|
+
}
|
|
235
|
+
return multiProviderRouter;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Convenience: Chat with automatic provider routing
|
|
239
|
+
*/
|
|
240
|
+
export async function chat(options) {
|
|
241
|
+
const router = await getMultiProviderRouter();
|
|
242
|
+
return router.chat(options);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Convenience: List all available models with provider prefixes
|
|
246
|
+
*/
|
|
247
|
+
export async function listAllModels() {
|
|
248
|
+
const router = await getMultiProviderRouter();
|
|
249
|
+
return router.listModels();
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Convenience: Get provider statuses
|
|
253
|
+
*/
|
|
254
|
+
export async function getProviderStatuses() {
|
|
255
|
+
const registry = getProviderRegistry();
|
|
256
|
+
return registry.getStatuses();
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=multi-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-provider.js","sourceRoot":"","sources":["../../../src/llm/multi-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/src/llm/ollama.js
CHANGED
|
@@ -1,243 +1,179 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ollama LLM Provider
|
|
3
3
|
*
|
|
4
|
-
* Unified local + cloud support
|
|
5
|
-
*
|
|
6
|
-
* just makes the actual API calls.
|
|
4
|
+
* Unified local + cloud support using official Ollama client.
|
|
5
|
+
* Uses OpenAI-compatible endpoints (/v1) for pi-coding-agent compatibility.
|
|
7
6
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Helper functions (previously imported from extension)
|
|
11
|
-
async function checkLocalOllama() {
|
|
12
|
-
try {
|
|
13
|
-
const res = await fetch('http://localhost:11434/api/tags', {
|
|
14
|
-
method: 'GET',
|
|
15
|
-
signal: AbortSignal.timeout(5000)
|
|
16
|
-
});
|
|
17
|
-
return res.ok;
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function getOllamaBaseUrl(modelId) {
|
|
24
|
-
// If model has cloud/ prefix or no local Ollama, use cloud
|
|
25
|
-
if (modelId.includes('cloud/'))
|
|
26
|
-
return CLOUD_URL;
|
|
27
|
-
return 'http://localhost:11434';
|
|
28
|
-
}
|
|
29
|
-
function getOllamaApiKey() {
|
|
30
|
-
return process.env.OLLAMA_API_KEY;
|
|
31
|
-
}
|
|
32
|
-
function modelRequiresApiKey(modelId) {
|
|
33
|
-
// Cloud models require API key
|
|
34
|
-
return modelId.includes('cloud/') || modelId.startsWith('cloud-');
|
|
35
|
-
}
|
|
7
|
+
import { Ollama } from 'ollama';
|
|
8
|
+
import { loadConfigFromEnv, DEFAULT_CONFIG, } from '@0xkobold/pi-ollama/shared';
|
|
36
9
|
/**
|
|
37
10
|
* Ollama Provider
|
|
38
|
-
* Supports both local and cloud modes
|
|
11
|
+
* Supports both local and cloud modes using official client
|
|
39
12
|
*/
|
|
40
13
|
export class OllamaProvider {
|
|
41
14
|
name = 'ollama';
|
|
42
|
-
|
|
15
|
+
clients;
|
|
43
16
|
cloudOnly = false;
|
|
44
17
|
constructor() {
|
|
45
|
-
//
|
|
18
|
+
// Merge env config with defaults
|
|
19
|
+
const envConfig = loadConfigFromEnv();
|
|
20
|
+
const config = {
|
|
21
|
+
baseUrl: envConfig.baseUrl ?? process.env.OLLAMA_BASE_URL ?? DEFAULT_CONFIG.baseUrl,
|
|
22
|
+
cloudUrl: envConfig.cloudUrl ?? process.env.OLLAMA_CLOUD_URL ?? DEFAULT_CONFIG.cloudUrl,
|
|
23
|
+
apiKey: envConfig.apiKey ?? process.env.OLLAMA_API_KEY ?? DEFAULT_CONFIG.apiKey,
|
|
24
|
+
};
|
|
25
|
+
// Create clients
|
|
26
|
+
this.clients = {
|
|
27
|
+
local: new Ollama({ host: config.baseUrl }),
|
|
28
|
+
cloud: config.apiKey
|
|
29
|
+
? new Ollama({ host: config.cloudUrl, headers: { Authorization: `Bearer ${config.apiKey}` } })
|
|
30
|
+
: null,
|
|
31
|
+
};
|
|
46
32
|
this.detectMode();
|
|
47
33
|
}
|
|
48
34
|
async detectMode() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
updateBaseUrl(modelId) {
|
|
57
|
-
// Use the extension's routing logic
|
|
58
|
-
this.baseUrl = getOllamaBaseUrl(modelId);
|
|
35
|
+
try {
|
|
36
|
+
await this.clients.local.list();
|
|
37
|
+
this.cloudOnly = false;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
this.cloudOnly = true;
|
|
41
|
+
}
|
|
59
42
|
}
|
|
60
43
|
/**
|
|
61
|
-
*
|
|
44
|
+
* Get the appropriate client for a model
|
|
62
45
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
46
|
+
getClient(model) {
|
|
47
|
+
// If model has :cloud suffix, use cloud client
|
|
48
|
+
if (model.endsWith(':cloud') && this.clients.cloud) {
|
|
49
|
+
return { client: this.clients.cloud, isCloud: true };
|
|
50
|
+
}
|
|
51
|
+
// If local is unavailable, use cloud
|
|
52
|
+
if (this.cloudOnly && this.clients.cloud) {
|
|
53
|
+
return { client: this.clients.cloud, isCloud: true };
|
|
54
|
+
}
|
|
55
|
+
// Default to local
|
|
56
|
+
return { client: this.clients.local, isCloud: false };
|
|
65
57
|
}
|
|
66
58
|
async chat(options) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// Get model name (strip prefix)
|
|
71
|
-
const model = options.model.replace(/^ollama\//, '').replace(/^cloud\//, '');
|
|
72
|
-
// Build messages
|
|
59
|
+
const { client, isCloud } = this.getClient(options.model);
|
|
60
|
+
const model = options.model.replace(':cloud', '');
|
|
61
|
+
// Convert messages to OpenAI format
|
|
73
62
|
const messages = options.messages.map((m) => ({
|
|
74
63
|
role: m.role,
|
|
75
64
|
content: m.content,
|
|
76
65
|
}));
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const headers = {
|
|
96
|
-
'Content-Type': 'application/json',
|
|
97
|
-
};
|
|
98
|
-
// Add auth for cloud mode
|
|
99
|
-
if (isCloud || modelRequiresApiKey(options.model)) {
|
|
100
|
-
const apiKey = getOllamaApiKey();
|
|
101
|
-
if (apiKey) {
|
|
102
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
103
|
-
}
|
|
66
|
+
try {
|
|
67
|
+
// Use the chat API
|
|
68
|
+
const response = await client.chat({
|
|
69
|
+
model,
|
|
70
|
+
messages,
|
|
71
|
+
options: {
|
|
72
|
+
temperature: options.temperature ?? 0.7,
|
|
73
|
+
num_predict: options.maxTokens ?? 4096,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
content: response.message.content,
|
|
78
|
+
usage: {
|
|
79
|
+
inputTokens: response.prompt_eval_count ?? 0,
|
|
80
|
+
outputTokens: response.eval_count ?? 0,
|
|
81
|
+
},
|
|
82
|
+
model: options.model,
|
|
83
|
+
};
|
|
104
84
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
headers,
|
|
108
|
-
body: JSON.stringify(body),
|
|
109
|
-
signal: options.signal,
|
|
110
|
-
});
|
|
111
|
-
if (!res.ok) {
|
|
112
|
-
const err = await res.text().catch(() => res.statusText);
|
|
113
|
-
throw new Error(`Ollama ${isCloud ? 'Cloud' : 'Local'} error: ${err}`);
|
|
85
|
+
catch (err) {
|
|
86
|
+
throw new Error(`Ollama ${isCloud ? 'Cloud' : 'Local'} error: ${err.message}`);
|
|
114
87
|
}
|
|
115
|
-
const data = await res.json();
|
|
116
|
-
// Parse tool calls from response
|
|
117
|
-
const toolCalls = data.message?.tool_calls?.map((tc) => ({
|
|
118
|
-
id: `call-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
119
|
-
function: {
|
|
120
|
-
name: tc.function?.name ?? tc.function,
|
|
121
|
-
arguments: typeof tc.function?.arguments === 'string'
|
|
122
|
-
? JSON.parse(tc.function.arguments)
|
|
123
|
-
: tc.function?.arguments ?? {},
|
|
124
|
-
},
|
|
125
|
-
}));
|
|
126
|
-
// Calculate usage (Ollama provides eval counts)
|
|
127
|
-
const usage = {
|
|
128
|
-
inputTokens: data.prompt_eval_count ?? 0,
|
|
129
|
-
outputTokens: data.eval_count ?? 0,
|
|
130
|
-
};
|
|
131
|
-
return {
|
|
132
|
-
content: data.message?.content ?? '',
|
|
133
|
-
toolCalls,
|
|
134
|
-
model: options.model,
|
|
135
|
-
usage,
|
|
136
|
-
};
|
|
137
88
|
}
|
|
138
89
|
async *chatStream(options) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// Get model name (strip prefix)
|
|
143
|
-
const model = options.model.replace(/^ollama\//, '').replace(/^cloud\//, '');
|
|
144
|
-
// Build messages
|
|
90
|
+
const { client, isCloud } = this.getClient(options.model);
|
|
91
|
+
const model = options.model.replace(':cloud', '');
|
|
92
|
+
// Convert messages to OpenAI format
|
|
145
93
|
const messages = options.messages.map((m) => ({
|
|
146
94
|
role: m.role,
|
|
147
95
|
content: m.content,
|
|
148
96
|
}));
|
|
149
|
-
const body = {
|
|
150
|
-
model,
|
|
151
|
-
messages,
|
|
152
|
-
stream: true,
|
|
153
|
-
options: {
|
|
154
|
-
temperature: options.temperature ?? 0.7,
|
|
155
|
-
num_predict: options.maxTokens ?? 4096,
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
// Build headers
|
|
159
|
-
const headers = {
|
|
160
|
-
'Content-Type': 'application/json',
|
|
161
|
-
};
|
|
162
|
-
// Add auth for cloud mode
|
|
163
|
-
if (isCloud || modelRequiresApiKey(options.model)) {
|
|
164
|
-
const apiKey = getOllamaApiKey();
|
|
165
|
-
if (apiKey) {
|
|
166
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const res = await fetch(`${this.baseUrl}/api/chat`, {
|
|
170
|
-
method: 'POST',
|
|
171
|
-
headers,
|
|
172
|
-
body: JSON.stringify(body),
|
|
173
|
-
signal: options.signal,
|
|
174
|
-
});
|
|
175
|
-
if (!res.ok) {
|
|
176
|
-
const err = await res.text().catch(() => res.statusText);
|
|
177
|
-
throw new Error(`Ollama ${isCloud ? 'Cloud' : 'Local'} error: ${err}`);
|
|
178
|
-
}
|
|
179
|
-
if (!res.body) {
|
|
180
|
-
throw new Error('No response body');
|
|
181
|
-
}
|
|
182
|
-
// Process stream
|
|
183
|
-
const reader = res.body.getReader();
|
|
184
|
-
const decoder = new TextDecoder();
|
|
185
97
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
catch {
|
|
200
|
-
// Ignore parse errors
|
|
201
|
-
}
|
|
98
|
+
const stream = await client.chat({
|
|
99
|
+
model,
|
|
100
|
+
messages,
|
|
101
|
+
stream: true,
|
|
102
|
+
options: {
|
|
103
|
+
temperature: options.temperature ?? 0.7,
|
|
104
|
+
num_predict: options.maxTokens ?? 4096,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
for await (const chunk of stream) {
|
|
108
|
+
if (chunk.message?.content) {
|
|
109
|
+
yield chunk.message.content;
|
|
202
110
|
}
|
|
203
111
|
}
|
|
204
112
|
}
|
|
205
|
-
|
|
206
|
-
|
|
113
|
+
catch (err) {
|
|
114
|
+
throw new Error(`Ollama stream error: ${err.message}`);
|
|
207
115
|
}
|
|
208
116
|
}
|
|
209
117
|
async listModels() {
|
|
210
|
-
// Try local first
|
|
211
|
-
const hasLocal = await checkLocalOllama();
|
|
212
118
|
try {
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
if
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
119
|
+
const { models } = await this.clients.local.list();
|
|
120
|
+
const modelNames = models.map(m => m.name);
|
|
121
|
+
// Also list cloud models if available
|
|
122
|
+
if (this.clients.cloud && !this.cloudOnly) {
|
|
123
|
+
try {
|
|
124
|
+
const { models: cloudModels } = await this.clients.cloud.list();
|
|
125
|
+
const cloudNames = cloudModels.map(m => `${m.name}:cloud`);
|
|
126
|
+
return [...modelNames, ...cloudNames];
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Cloud unavailable, just return local
|
|
130
|
+
}
|
|
219
131
|
}
|
|
220
|
-
|
|
221
|
-
if (!res.ok)
|
|
222
|
-
return [];
|
|
223
|
-
const data = await res.json();
|
|
224
|
-
return (data.models ?? []).map((m) => m.name);
|
|
132
|
+
return modelNames;
|
|
225
133
|
}
|
|
226
134
|
catch {
|
|
135
|
+
// If local fails, try cloud
|
|
136
|
+
if (this.clients.cloud) {
|
|
137
|
+
const { models } = await this.clients.cloud.list();
|
|
138
|
+
return models.map(m => `${m.name}:cloud`);
|
|
139
|
+
}
|
|
227
140
|
return [];
|
|
228
141
|
}
|
|
229
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Check if Ollama is running (local mode)
|
|
145
|
+
*/
|
|
146
|
+
async isLocalRunning() {
|
|
147
|
+
try {
|
|
148
|
+
await this.clients.local.list();
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if running in cloud-only mode
|
|
157
|
+
*/
|
|
158
|
+
isCloudOnly() {
|
|
159
|
+
return this.cloudOnly;
|
|
160
|
+
}
|
|
230
161
|
}
|
|
231
162
|
/**
|
|
232
163
|
* Check if Ollama is running (local mode)
|
|
233
|
-
* Re-exported from extension for compatibility
|
|
234
164
|
*/
|
|
235
165
|
export async function isOllamaRunning() {
|
|
236
|
-
|
|
166
|
+
try {
|
|
167
|
+
const client = new Ollama({ host: process.env.OLLAMA_HOST || 'http://localhost:11434' });
|
|
168
|
+
await client.list();
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
237
174
|
}
|
|
238
175
|
/**
|
|
239
176
|
* List available Ollama models
|
|
240
|
-
* Re-exported from extension for compatibility
|
|
241
177
|
*/
|
|
242
178
|
export async function listOllamaModels() {
|
|
243
179
|
const provider = new OllamaProvider();
|
|
@@ -249,5 +185,15 @@ export async function listOllamaModels() {
|
|
|
249
185
|
export function createOllamaProvider() {
|
|
250
186
|
return new OllamaProvider();
|
|
251
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Get singleton Ollama provider instance
|
|
190
|
+
*/
|
|
191
|
+
let ollamaProviderInstance = null;
|
|
192
|
+
export function getOllamaProvider() {
|
|
193
|
+
if (!ollamaProviderInstance) {
|
|
194
|
+
ollamaProviderInstance = new OllamaProvider();
|
|
195
|
+
}
|
|
196
|
+
return ollamaProviderInstance;
|
|
197
|
+
}
|
|
252
198
|
export default createOllamaProvider;
|
|
253
199
|
//# sourceMappingURL=ollama.js.map
|