spidersan 0.20.1 → 0.20.2
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/CHANGELOG.md +8 -0
- package/dist/bin/command-registry.d.ts +25 -0
- package/dist/bin/command-registry.d.ts.map +1 -0
- package/dist/bin/command-registry.js +29 -0
- package/dist/bin/command-registry.js.map +1 -0
- package/dist/bin/spidersan.d.ts +16 -0
- package/dist/bin/spidersan.d.ts.map +1 -0
- package/dist/bin/spidersan.js +98 -0
- package/dist/bin/spidersan.js.map +1 -0
- package/dist/commands/abandon.d.ts +8 -0
- package/dist/commands/abandon.d.ts.map +1 -0
- package/dist/commands/abandon.js +43 -0
- package/dist/commands/abandon.js.map +1 -0
- package/dist/commands/cleanup.d.ts +8 -0
- package/dist/commands/cleanup.d.ts.map +1 -0
- package/dist/commands/cleanup.js +50 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/config.d.ts +15 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +309 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/conflicts.d.ts +34 -0
- package/dist/commands/conflicts.d.ts.map +1 -0
- package/dist/commands/conflicts.js +773 -0
- package/dist/commands/conflicts.js.map +1 -0
- package/dist/commands/context.d.ts +8 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +104 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/cross-conflicts.d.ts +17 -0
- package/dist/commands/cross-conflicts.d.ts.map +1 -0
- package/dist/commands/cross-conflicts.js +273 -0
- package/dist/commands/cross-conflicts.js.map +1 -0
- package/dist/commands/depends.d.ts +11 -0
- package/dist/commands/depends.d.ts.map +1 -0
- package/dist/commands/depends.js +63 -0
- package/dist/commands/depends.js.map +1 -0
- package/dist/commands/doctor.d.ts +30 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +558 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/git-watch.d.ts +24 -0
- package/dist/commands/git-watch.d.ts.map +1 -0
- package/dist/commands/git-watch.js +84 -0
- package/dist/commands/git-watch.js.map +1 -0
- package/dist/commands/github-sync.d.ts +42 -0
- package/dist/commands/github-sync.d.ts.map +1 -0
- package/dist/commands/github-sync.js +191 -0
- package/dist/commands/github-sync.js.map +1 -0
- package/dist/commands/index.d.ts +25 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +29 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +23 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +45 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/log.d.ts +7 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +110 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/merge-order.d.ts +9 -0
- package/dist/commands/merge-order.d.ts.map +1 -0
- package/dist/commands/merge-order.js +100 -0
- package/dist/commands/merge-order.js.map +1 -0
- package/dist/commands/merged.d.ts +8 -0
- package/dist/commands/merged.d.ts.map +1 -0
- package/dist/commands/merged.js +37 -0
- package/dist/commands/merged.js.map +1 -0
- package/dist/commands/pr-check.d.ts +24 -0
- package/dist/commands/pr-check.d.ts.map +1 -0
- package/dist/commands/pr-check.js +85 -0
- package/dist/commands/pr-check.js.map +1 -0
- package/dist/commands/ready-check.d.ts +11 -0
- package/dist/commands/ready-check.d.ts.map +1 -0
- package/dist/commands/ready-check.js +150 -0
- package/dist/commands/ready-check.js.map +1 -0
- package/dist/commands/rebase-helper.d.ts +3 -0
- package/dist/commands/rebase-helper.d.ts.map +1 -0
- package/dist/commands/rebase-helper.js +52 -0
- package/dist/commands/rebase-helper.js.map +1 -0
- package/dist/commands/register.d.ts +10 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +176 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/registry-sync.d.ts +9 -0
- package/dist/commands/registry-sync.d.ts.map +1 -0
- package/dist/commands/registry-sync.js +129 -0
- package/dist/commands/registry-sync.js.map +1 -0
- package/dist/commands/stale.d.ts +17 -0
- package/dist/commands/stale.d.ts.map +1 -0
- package/dist/commands/stale.js +136 -0
- package/dist/commands/stale.js.map +1 -0
- package/dist/commands/sync.d.ts +21 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +78 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/verify-trunk.d.ts +18 -0
- package/dist/commands/verify-trunk.d.ts.map +1 -0
- package/dist/commands/verify-trunk.js +77 -0
- package/dist/commands/verify-trunk.js.map +1 -0
- package/dist/commands/watch.d.ts +8 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +509 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/activity.d.ts +53 -0
- package/dist/lib/activity.d.ts.map +1 -0
- package/dist/lib/activity.js +271 -0
- package/dist/lib/activity.js.map +1 -0
- package/dist/lib/agent-errors.d.ts +41 -0
- package/dist/lib/agent-errors.d.ts.map +1 -0
- package/dist/lib/agent-errors.js +145 -0
- package/dist/lib/agent-errors.js.map +1 -0
- package/dist/lib/ai/context-builder.d.ts +16 -0
- package/dist/lib/ai/context-builder.d.ts.map +1 -0
- package/dist/lib/ai/context-builder.js +229 -0
- package/dist/lib/ai/context-builder.js.map +1 -0
- package/dist/lib/ai/event-handler.d.ts +21 -0
- package/dist/lib/ai/event-handler.d.ts.map +1 -0
- package/dist/lib/ai/event-handler.js +111 -0
- package/dist/lib/ai/event-handler.js.map +1 -0
- package/dist/lib/ai/index.d.ts +13 -0
- package/dist/lib/ai/index.d.ts.map +1 -0
- package/dist/lib/ai/index.js +11 -0
- package/dist/lib/ai/index.js.map +1 -0
- package/dist/lib/ai/llm-client.d.ts +37 -0
- package/dist/lib/ai/llm-client.d.ts.map +1 -0
- package/dist/lib/ai/llm-client.js +225 -0
- package/dist/lib/ai/llm-client.js.map +1 -0
- package/dist/lib/ai/reasoner.d.ts +11 -0
- package/dist/lib/ai/reasoner.d.ts.map +1 -0
- package/dist/lib/ai/reasoner.js +227 -0
- package/dist/lib/ai/reasoner.js.map +1 -0
- package/dist/lib/ai/setup.d.ts +40 -0
- package/dist/lib/ai/setup.d.ts.map +1 -0
- package/dist/lib/ai/setup.js +154 -0
- package/dist/lib/ai/setup.js.map +1 -0
- package/dist/lib/ai/types.d.ts +135 -0
- package/dist/lib/ai/types.d.ts.map +1 -0
- package/dist/lib/ai/types.js +42 -0
- package/dist/lib/ai/types.js.map +1 -0
- package/dist/lib/ast.d.ts +44 -0
- package/dist/lib/ast.d.ts.map +1 -0
- package/dist/lib/ast.js +160 -0
- package/dist/lib/ast.js.map +1 -0
- package/dist/lib/carries.d.ts +22 -0
- package/dist/lib/carries.d.ts.map +1 -0
- package/dist/lib/carries.js +56 -0
- package/dist/lib/carries.js.map +1 -0
- package/dist/lib/colony-subscriber.d.ts +56 -0
- package/dist/lib/colony-subscriber.d.ts.map +1 -0
- package/dist/lib/colony-subscriber.js +265 -0
- package/dist/lib/colony-subscriber.js.map +1 -0
- package/dist/lib/config.d.ts +62 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +235 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/conflict-analyzer.d.ts +33 -0
- package/dist/lib/conflict-analyzer.d.ts.map +1 -0
- package/dist/lib/conflict-analyzer.js +114 -0
- package/dist/lib/conflict-analyzer.js.map +1 -0
- package/dist/lib/conflict-renderer.d.ts +7 -0
- package/dist/lib/conflict-renderer.d.ts.map +1 -0
- package/dist/lib/conflict-renderer.js +145 -0
- package/dist/lib/conflict-renderer.js.map +1 -0
- package/dist/lib/conflict-tier.d.ts +20 -0
- package/dist/lib/conflict-tier.d.ts.map +1 -0
- package/dist/lib/conflict-tier.js +49 -0
- package/dist/lib/conflict-tier.js.map +1 -0
- package/dist/lib/crypto.d.ts +71 -0
- package/dist/lib/crypto.d.ts.map +1 -0
- package/dist/lib/crypto.js +176 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/ecosystem-env.d.ts +33 -0
- package/dist/lib/ecosystem-env.d.ts.map +1 -0
- package/dist/lib/ecosystem-env.js +62 -0
- package/dist/lib/ecosystem-env.js.map +1 -0
- package/dist/lib/errors.d.ts +35 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +71 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/git-events-subscriber.d.ts +86 -0
- package/dist/lib/git-events-subscriber.d.ts.map +1 -0
- package/dist/lib/git-events-subscriber.js +870 -0
- package/dist/lib/git-events-subscriber.js.map +1 -0
- package/dist/lib/git-merge-analyzer.d.ts +38 -0
- package/dist/lib/git-merge-analyzer.d.ts.map +1 -0
- package/dist/lib/git-merge-analyzer.js +23 -0
- package/dist/lib/git-merge-analyzer.js.map +1 -0
- package/dist/lib/git.d.ts +103 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +670 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/github.d.ts +151 -0
- package/dist/lib/github.d.ts.map +1 -0
- package/dist/lib/github.js +425 -0
- package/dist/lib/github.js.map +1 -0
- package/dist/lib/graph.d.ts +38 -0
- package/dist/lib/graph.d.ts.map +1 -0
- package/dist/lib/graph.js +165 -0
- package/dist/lib/graph.js.map +1 -0
- package/dist/lib/machine.d.ts +14 -0
- package/dist/lib/machine.d.ts.map +1 -0
- package/dist/lib/machine.js +38 -0
- package/dist/lib/machine.js.map +1 -0
- package/dist/lib/notify.d.ts +68 -0
- package/dist/lib/notify.d.ts.map +1 -0
- package/dist/lib/notify.js +111 -0
- package/dist/lib/notify.js.map +1 -0
- package/dist/lib/outline.d.ts +6 -0
- package/dist/lib/outline.d.ts.map +1 -0
- package/dist/lib/outline.js +60 -0
- package/dist/lib/outline.js.map +1 -0
- package/dist/lib/push-registry.d.ts +22 -0
- package/dist/lib/push-registry.d.ts.map +1 -0
- package/dist/lib/push-registry.js +21 -0
- package/dist/lib/push-registry.js.map +1 -0
- package/dist/lib/reconcile.d.ts +100 -0
- package/dist/lib/reconcile.d.ts.map +1 -0
- package/dist/lib/reconcile.js +121 -0
- package/dist/lib/reconcile.js.map +1 -0
- package/dist/lib/regex-utils.d.ts +6 -0
- package/dist/lib/regex-utils.d.ts.map +1 -0
- package/dist/lib/regex-utils.js +24 -0
- package/dist/lib/regex-utils.js.map +1 -0
- package/dist/lib/register-renderer.d.ts +10 -0
- package/dist/lib/register-renderer.d.ts.map +1 -0
- package/dist/lib/register-renderer.js +19 -0
- package/dist/lib/register-renderer.js.map +1 -0
- package/dist/lib/remote-drift.d.ts +61 -0
- package/dist/lib/remote-drift.d.ts.map +1 -0
- package/dist/lib/remote-drift.js +227 -0
- package/dist/lib/remote-drift.js.map +1 -0
- package/dist/lib/security.d.ts +72 -0
- package/dist/lib/security.d.ts.map +1 -0
- package/dist/lib/security.js +180 -0
- package/dist/lib/security.js.map +1 -0
- package/dist/lib/semantic-analysis.d.ts +31 -0
- package/dist/lib/semantic-analysis.d.ts.map +1 -0
- package/dist/lib/semantic-analysis.js +120 -0
- package/dist/lib/semantic-analysis.js.map +1 -0
- package/dist/lib/supabase-credentials.d.ts +36 -0
- package/dist/lib/supabase-credentials.d.ts.map +1 -0
- package/dist/lib/supabase-credentials.js +43 -0
- package/dist/lib/supabase-credentials.js.map +1 -0
- package/dist/lib/trunk.d.ts +39 -0
- package/dist/lib/trunk.d.ts.map +1 -0
- package/dist/lib/trunk.js +116 -0
- package/dist/lib/trunk.js.map +1 -0
- package/dist/lib/update-check.d.ts +11 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +113 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/watch-renderer.d.ts +13 -0
- package/dist/lib/watch-renderer.d.ts.map +1 -0
- package/dist/lib/watch-renderer.js +35 -0
- package/dist/lib/watch-renderer.js.map +1 -0
- package/dist/storage/adapter.d.ts +81 -0
- package/dist/storage/adapter.d.ts.map +1 -0
- package/dist/storage/adapter.js +8 -0
- package/dist/storage/adapter.js.map +1 -0
- package/dist/storage/branch-registry-store.d.ts +13 -0
- package/dist/storage/branch-registry-store.d.ts.map +1 -0
- package/dist/storage/branch-registry-store.js +2 -0
- package/dist/storage/branch-registry-store.js.map +1 -0
- package/dist/storage/factory.d.ts +6 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/factory.js +14 -0
- package/dist/storage/factory.js.map +1 -0
- package/dist/storage/index.d.ts +10 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +11 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/json-branch-registry-store.d.ts +19 -0
- package/dist/storage/json-branch-registry-store.d.ts.map +1 -0
- package/dist/storage/json-branch-registry-store.js +138 -0
- package/dist/storage/json-branch-registry-store.js.map +1 -0
- package/dist/storage/local.d.ts +20 -0
- package/dist/storage/local.d.ts.map +1 -0
- package/dist/storage/local.js +40 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/storage/memory-branch-registry-store.d.ts +16 -0
- package/dist/storage/memory-branch-registry-store.d.ts.map +1 -0
- package/dist/storage/memory-branch-registry-store.js +68 -0
- package/dist/storage/memory-branch-registry-store.js.map +1 -0
- package/dist/storage/supabase-registry-sync-client-impl.d.ts +40 -0
- package/dist/storage/supabase-registry-sync-client-impl.d.ts.map +1 -0
- package/dist/storage/supabase-registry-sync-client-impl.js +278 -0
- package/dist/storage/supabase-registry-sync-client-impl.js.map +1 -0
- package/dist/storage/supabase-registry-sync-client.d.ts +9 -0
- package/dist/storage/supabase-registry-sync-client.d.ts.map +1 -0
- package/dist/storage/supabase-registry-sync-client.js +2 -0
- package/dist/storage/supabase-registry-sync-client.js.map +1 -0
- package/dist/storage/supabase.d.ts +28 -0
- package/dist/storage/supabase.d.ts.map +1 -0
- package/dist/storage/supabase.js +56 -0
- package/dist/storage/supabase.js.map +1 -0
- package/dist/types/cloud.d.ts +102 -0
- package/dist/types/cloud.d.ts.map +1 -0
- package/dist/types/cloud.js +13 -0
- package/dist/types/cloud.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spidersan AI Core — LLM Client
|
|
3
|
+
*
|
|
4
|
+
* Unified interface for LLM providers with automatic fallback chain:
|
|
5
|
+
* LM Studio (Gemma 4) → Ollama → Hosted API (api.spidersan.net) → GitHub Copilot
|
|
6
|
+
*
|
|
7
|
+
* Tier routing (auto, no explicit provider):
|
|
8
|
+
* Tier 1: localhost:1234 / :8082 (lmstudio)
|
|
9
|
+
* Tier 2: localhost:11434 (ollama)
|
|
10
|
+
* Tier 3: api.spidersan.net (hosted) — requires API key
|
|
11
|
+
* Remote: copilot — only with allowRemoteFallback or explicit config
|
|
12
|
+
*/
|
|
13
|
+
import { execFile } from 'child_process';
|
|
14
|
+
import { promisify } from 'util';
|
|
15
|
+
import { DEFAULT_LLM_CONFIGS } from './types.js';
|
|
16
|
+
import { loadAiConfig } from './setup.js';
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
18
|
+
export function resolveConfig(overrides) {
|
|
19
|
+
const providerEnv = process.env['SPIDERSAN_LLM'];
|
|
20
|
+
const provider = overrides?.provider ?? providerEnv ?? 'lmstudio';
|
|
21
|
+
const base = DEFAULT_LLM_CONFIGS[provider] ?? DEFAULT_LLM_CONFIGS.lmstudio;
|
|
22
|
+
return {
|
|
23
|
+
...base,
|
|
24
|
+
...overrides,
|
|
25
|
+
provider,
|
|
26
|
+
model: overrides?.model ?? process.env['SPIDERSAN_LLM_MODEL'] ?? base.model,
|
|
27
|
+
baseUrl: overrides?.baseUrl ?? process.env['SPIDERSAN_LLM_URL'] ?? base.baseUrl,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function getGitHubToken() {
|
|
31
|
+
try {
|
|
32
|
+
const { stdout } = await execFileAsync('gh', ['auth', 'token'], { timeout: 5000 });
|
|
33
|
+
return stdout.trim();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error('GitHub CLI not authenticated. Run `gh auth login` first.');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function chatOpenAICompatible(config, messages, apiKey) {
|
|
40
|
+
// Normalize: strip trailing /v1 so we always build the full path ourselves.
|
|
41
|
+
// Handles both http://host:port (env var form) and http://host:port/v1 (default form).
|
|
42
|
+
const base = config.baseUrl.replace(/\/v1\/?$/, '');
|
|
43
|
+
const url = `${base}/v1/chat/completions`;
|
|
44
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
45
|
+
if (apiKey)
|
|
46
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
47
|
+
const resp = await fetch(url, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers,
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
model: config.model,
|
|
52
|
+
messages,
|
|
53
|
+
temperature: config.temperature,
|
|
54
|
+
max_tokens: config.maxTokens,
|
|
55
|
+
}),
|
|
56
|
+
signal: AbortSignal.timeout(60_000),
|
|
57
|
+
});
|
|
58
|
+
if (!resp.ok) {
|
|
59
|
+
const body = await resp.text().catch(() => '');
|
|
60
|
+
throw new Error(`LLM ${config.provider} returned ${resp.status}: ${body.slice(0, 200)}`);
|
|
61
|
+
}
|
|
62
|
+
const data = await resp.json();
|
|
63
|
+
return {
|
|
64
|
+
content: data.choices[0]?.message?.content ?? '',
|
|
65
|
+
model: data.model ?? config.model,
|
|
66
|
+
provider: config.provider,
|
|
67
|
+
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
68
|
+
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function chatOllama(config, messages) {
|
|
72
|
+
const url = `${config.baseUrl}/api/chat`;
|
|
73
|
+
const resp = await fetch(url, {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers: { 'Content-Type': 'application/json' },
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
model: config.model,
|
|
78
|
+
messages,
|
|
79
|
+
stream: false,
|
|
80
|
+
options: { temperature: config.temperature, num_predict: config.maxTokens },
|
|
81
|
+
}),
|
|
82
|
+
signal: AbortSignal.timeout(120_000),
|
|
83
|
+
});
|
|
84
|
+
if (!resp.ok) {
|
|
85
|
+
throw new Error(`Ollama returned ${resp.status}`);
|
|
86
|
+
}
|
|
87
|
+
const data = await resp.json();
|
|
88
|
+
return {
|
|
89
|
+
content: data.message?.content ?? '',
|
|
90
|
+
model: data.model ?? config.model,
|
|
91
|
+
provider: 'ollama',
|
|
92
|
+
promptTokens: data.prompt_eval_count ?? 0,
|
|
93
|
+
completionTokens: data.eval_count ?? 0,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function chatWithProvider(config, messages, apiKey) {
|
|
97
|
+
switch (config.provider) {
|
|
98
|
+
case 'lmstudio':
|
|
99
|
+
return chatOpenAICompatible(config, messages);
|
|
100
|
+
case 'copilot': {
|
|
101
|
+
const token = await getGitHubToken();
|
|
102
|
+
return chatOpenAICompatible(config, messages, token);
|
|
103
|
+
}
|
|
104
|
+
case 'ollama':
|
|
105
|
+
return chatOllama(config, messages);
|
|
106
|
+
case 'hosted': {
|
|
107
|
+
const key = apiKey ?? config.apiKey;
|
|
108
|
+
if (!key)
|
|
109
|
+
throw new Error('No API key for hosted tier. Run: spidersan ai-setup');
|
|
110
|
+
return chatOpenAICompatible(config, messages, key);
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
throw new Error(`Unknown LLM provider: ${config.provider}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Local-first fallback: never send repo context to remote without opt-in
|
|
117
|
+
const LOCAL_FALLBACK = ['lmstudio', 'ollama'];
|
|
118
|
+
const REMOTE_PROVIDERS = ['hosted', 'copilot'];
|
|
119
|
+
/** Resolve the hosted API key from env var or persisted config. */
|
|
120
|
+
async function resolveHostedApiKey() {
|
|
121
|
+
const envKey = process.env['SPIDERSAN_API_KEY'];
|
|
122
|
+
if (envKey)
|
|
123
|
+
return envKey;
|
|
124
|
+
const config = await loadAiConfig();
|
|
125
|
+
return config?.apiKey ?? undefined;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Send a chat completion request with automatic fallback.
|
|
129
|
+
*
|
|
130
|
+
* Priority order (auto-routing when no explicit provider set):
|
|
131
|
+
* 1. lmstudio (local)
|
|
132
|
+
* 2. ollama (local)
|
|
133
|
+
* 3. hosted (api.spidersan.net) — only if API key available
|
|
134
|
+
* 4. copilot — only if allowRemoteFallback or explicitly configured
|
|
135
|
+
*/
|
|
136
|
+
export async function chat(messages, configOverrides) {
|
|
137
|
+
const { allowRemoteFallback, ...llmOverrides } = configOverrides ?? {};
|
|
138
|
+
const config = resolveConfig(llmOverrides);
|
|
139
|
+
const isRemote = REMOTE_PROVIDERS.includes(config.provider);
|
|
140
|
+
const errors = [];
|
|
141
|
+
// Resolve hosted API key once (avoid repeated config reads in fallback loop)
|
|
142
|
+
const hostedApiKey = await resolveHostedApiKey();
|
|
143
|
+
// Try configured provider first
|
|
144
|
+
try {
|
|
145
|
+
return await chatWithProvider(config, messages, config.provider === 'hosted' ? hostedApiKey : undefined);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
errors.push({ provider: config.provider, error: err.message });
|
|
149
|
+
}
|
|
150
|
+
// Local fallback chain
|
|
151
|
+
for (const fallback of LOCAL_FALLBACK) {
|
|
152
|
+
if (fallback === config.provider)
|
|
153
|
+
continue;
|
|
154
|
+
try {
|
|
155
|
+
const result = await chatWithProvider(DEFAULT_LLM_CONFIGS[fallback], messages);
|
|
156
|
+
result.provider = fallback;
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
errors.push({ provider: fallback, error: err.message });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Remote fallback: hosted (if key available + tier allows), then copilot (if opted in)
|
|
164
|
+
//
|
|
165
|
+
// Tier routing: if the user configured free/contributor tier via ai-setup, hosted is
|
|
166
|
+
// always a valid fallback when local is unavailable — no explicit allowRemoteFallback needed.
|
|
167
|
+
const savedConfig = await loadAiConfig();
|
|
168
|
+
const tierAllowsHosted = savedConfig?.tier === 'free' || savedConfig?.tier === 'contributor';
|
|
169
|
+
if (allowRemoteFallback || isRemote || tierAllowsHosted) {
|
|
170
|
+
// hosted — only if we have a key
|
|
171
|
+
if (config.provider !== 'hosted' && hostedApiKey) {
|
|
172
|
+
try {
|
|
173
|
+
const result = await chatWithProvider(DEFAULT_LLM_CONFIGS.hosted, messages, hostedApiKey);
|
|
174
|
+
result.provider = 'hosted';
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
errors.push({ provider: 'hosted', error: err.message });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// copilot — only with explicit allowRemoteFallback (never auto-routed)
|
|
182
|
+
if (allowRemoteFallback || isRemote) {
|
|
183
|
+
for (const fallback of ['copilot']) {
|
|
184
|
+
if (fallback === config.provider)
|
|
185
|
+
continue;
|
|
186
|
+
try {
|
|
187
|
+
const result = await chatWithProvider(DEFAULT_LLM_CONFIGS[fallback], messages);
|
|
188
|
+
result.provider = fallback;
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
errors.push({ provider: fallback, error: err.message });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const summary = errors.map(e => ` ${e.provider}: ${e.error}`).join('\n');
|
|
198
|
+
throw new Error(`All LLM providers failed:\n${summary}`);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Quick health check — can we reach the configured provider?
|
|
202
|
+
*/
|
|
203
|
+
export async function ping(configOverrides) {
|
|
204
|
+
const config = resolveConfig(configOverrides);
|
|
205
|
+
const start = Date.now();
|
|
206
|
+
try {
|
|
207
|
+
const result = await chat([{ role: 'user', content: 'Reply with just "ok".' }], { ...config, maxTokens: 10 });
|
|
208
|
+
return {
|
|
209
|
+
ok: true,
|
|
210
|
+
provider: result.provider,
|
|
211
|
+
model: result.model,
|
|
212
|
+
latencyMs: Date.now() - start,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
return {
|
|
217
|
+
ok: false,
|
|
218
|
+
provider: config.provider,
|
|
219
|
+
model: config.model,
|
|
220
|
+
latencyMs: Date.now() - start,
|
|
221
|
+
error: err.message,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=llm-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-client.js","sourceRoot":"","sources":["../../../src/lib/ai/llm-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spidersan AI Core — Reasoner
|
|
3
|
+
*
|
|
4
|
+
* Sends SpiderContext + user question to LLM with spidersan-aware system prompt.
|
|
5
|
+
* The scenario playbook is embedded as a TS constant (no file I/O at runtime).
|
|
6
|
+
*/
|
|
7
|
+
import type { LLMConfig, ReasoningRequest, ReasoningResult } from './types.js';
|
|
8
|
+
export declare function reason(request: ReasoningRequest, llmOverrides?: Partial<LLMConfig> & {
|
|
9
|
+
allowRemoteFallback?: boolean;
|
|
10
|
+
}): Promise<ReasoningResult>;
|
|
11
|
+
//# sourceMappingURL=reasoner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner.d.ts","sourceRoot":"","sources":["../../../src/lib/ai/reasoner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,SAAS,EAGT,gBAAgB,EAChB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAgKpB,wBAAsB,MAAM,CAC1B,OAAO,EAAE,gBAAgB,EACzB,YAAY,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAE,GACpE,OAAO,CAAC,eAAe,CAAC,CAqF1B"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spidersan AI Core — Reasoner
|
|
3
|
+
*
|
|
4
|
+
* Sends SpiderContext + user question to LLM with spidersan-aware system prompt.
|
|
5
|
+
* The scenario playbook is embedded as a TS constant (no file I/O at runtime).
|
|
6
|
+
*/
|
|
7
|
+
import { chat } from './llm-client.js';
|
|
8
|
+
// ─── Known Command Registry ──────────────────────────────────
|
|
9
|
+
// Must equal the CLI's registered commands (src/bin/command-registry.ts); tests/reasoner.validator.test.ts
|
|
10
|
+
// checks both directions. Used to flag model hallucinations at output time.
|
|
11
|
+
const KNOWN_SPIDERSAN_COMMANDS = new Set([
|
|
12
|
+
'abandon', 'cleanup', 'config', 'conflicts', 'context', 'cross-conflicts', 'depends',
|
|
13
|
+
'doctor', 'git-watch', 'github-sync', 'init', 'list', 'log', 'merge-order', 'merged',
|
|
14
|
+
'pr-check', 'ready-check', 'rebase-helper', 'register', 'registry-sync', 'stale',
|
|
15
|
+
'sync', 'verify-trunk', 'watch',
|
|
16
|
+
]);
|
|
17
|
+
// ─── Embedded Scenario Playbook ─────────────────────────────
|
|
18
|
+
// Optimized via PHC: Sonnet 4.6 proposer + Gemma 4 executor (score: 0.9718), measured before the
|
|
19
|
+
// 0.20.0 trim removed the scenarios for dropped commands; the trimmed text is unscored.
|
|
20
|
+
// Source: promptclimb/prompt_sonnet_spidersan.md
|
|
21
|
+
const SCENARIO_PLAYBOOK = `## Spidersan Command Reference & Scenarios
|
|
22
|
+
|
|
23
|
+
### SCENARIO 1: New Repo Setup
|
|
24
|
+
Situation: Starting work in a new or uninitialized repository.
|
|
25
|
+
Commands: spidersan init → register --files "f1,f2" --agent <id> → doctor → list
|
|
26
|
+
Reminder: Always verify repo health with \`doctor\` before proceeding.
|
|
27
|
+
|
|
28
|
+
### SCENARIO 2: Ghost/Abandoned Branches
|
|
29
|
+
Situation: Unregistered branches drifting — some with salvageable code, others dead.
|
|
30
|
+
Commands: sync → stale → log --branch <branch> → abandon <branch>
|
|
31
|
+
Decision: If the branch has unique commits worth keeping → cherry-pick them onto a fresh branch. If empty/WIP → abandon.
|
|
32
|
+
|
|
33
|
+
### SCENARIO 3: File Conflicts (Tier System)
|
|
34
|
+
- TIER 3 (BLOCK): Critical file (auth, secrets, env) — halt, coordinate immediately.
|
|
35
|
+
- TIER 2 (PAUSE): Important file (package.json, config, server) — coordinate before merging.
|
|
36
|
+
- TIER 1 (WARN): Adjacent/related files — proceed with caution.
|
|
37
|
+
Commands: conflicts → conflicts --tier 3 → conflicts --strict → conflicts --json → conflicts --notify
|
|
38
|
+
Reminder: Tier escalation is mandatory for TIER 3 conflicts. Always reference the TIER level when reporting conflicts.
|
|
39
|
+
|
|
40
|
+
### SCENARIO 4: WIP / Not-Ready Code
|
|
41
|
+
Situation: Branch has TODO, FIXME, HACK, WIP, SPIDER_TRAP, UNFINISHED markers.
|
|
42
|
+
Commands: ready-check → ready-check --json
|
|
43
|
+
Rule: Never merge a branch that fails \`ready-check\`. All markers must be resolved first.
|
|
44
|
+
|
|
45
|
+
### SCENARIO 5: Real-Time Monitoring
|
|
46
|
+
Commands: watch --agent <id>
|
|
47
|
+
Warning: Watch CPU loop if ghost branches claim same files. Fix: sync first.
|
|
48
|
+
|
|
49
|
+
### SCENARIO 6: Tangled Dependencies
|
|
50
|
+
Commands: merge-order → merge-order --json → merge-order --blocking-count → depends <branch> → conflicts --notify
|
|
51
|
+
Pattern: Merge foundation first → resolve blockers → re-check dependencies → merge dependents.
|
|
52
|
+
|
|
53
|
+
### SCENARIO 7: Stale Branch Cleanup
|
|
54
|
+
Commands: stale → cleanup → abandon <branch> → merged <branch> → sync
|
|
55
|
+
Triage: sync → stale → cleanup → verify with \`list\`.
|
|
56
|
+
|
|
57
|
+
### SCENARIO 8: Cross-Machine Conflicts
|
|
58
|
+
Commands: registry-sync --pull → cross-conflicts → cross-conflicts --local → doctor --remote
|
|
59
|
+
Pattern: Pull the shared registry first, then resolve the conflicts it shows.
|
|
60
|
+
|
|
61
|
+
### SCENARIO 9: Activity & Context
|
|
62
|
+
Situation: Investigating recent activity, mysterious branches, or understanding what happened over a time period.
|
|
63
|
+
IMPORTANT: When investigating recent or mysterious activity, ALWAYS start with \`log\` first — it gives you the evidence base before taking any action.
|
|
64
|
+
Commands: log → log --since 7d → log --branch <name> → context → context --json
|
|
65
|
+
|
|
66
|
+
### SCENARIO 10: Suspicious / Unknown Branch Investigation
|
|
67
|
+
Situation: A branch with an unknown owner, suspicious name (e.g. shadow/, unknown-agent), or no clear origin.
|
|
68
|
+
IMPORTANT: For any unknown or suspicious branch, start with \`log --branch <branch>\` and \`context\` before acting on it.
|
|
69
|
+
Commands: log --branch <branch> → context → abandon <branch>
|
|
70
|
+
Decision: If it holds work someone owns → contact them. If empty/dead → abandon.
|
|
71
|
+
|
|
72
|
+
### SCENARIO 11: Branch Abandonment & Rebase Recovery
|
|
73
|
+
Situation: Dead branches (0 commits ahead) cluttering registry, or a branch stuck mid-rebase.
|
|
74
|
+
Commands: abandon <branch> → list --status abandoned → rebase-helper
|
|
75
|
+
Decision: If branch has 0 unique commits → abandon. If \`.git/rebase-merge\` exists → use \`rebase-helper\` to diagnose. After resolution → register updated files.
|
|
76
|
+
|
|
77
|
+
### SCENARIO 12: Remote Sync & GitHub Integration
|
|
78
|
+
Situation: Local registry out of sync with remote. Need to see GitHub PR/CI state.
|
|
79
|
+
Commands: github-sync → pr-check <n> → registry-sync --pull → registry-sync --push
|
|
80
|
+
Decision: Use \`github-sync\` for remote branch/PR overview. \`pr-check\` for one PR's merge readiness. \`registry-sync\` to align local ↔ Supabase registry.
|
|
81
|
+
|
|
82
|
+
### SCENARIO 13: Configuration
|
|
83
|
+
Situation: Changing LLM or stale settings.
|
|
84
|
+
Commands: config list → config set llm.provider <provider> → config set stale.days <n>
|
|
85
|
+
Decision: Set \`llm.provider\` to lmstudio (local), ollama (local), or copilot (remote, opt-in).
|
|
86
|
+
|
|
87
|
+
### SCENARIO 14: Dependency Management
|
|
88
|
+
Situation: Multiple branches with merge-order dependencies that must be respected.
|
|
89
|
+
IMPORTANT: When dealing with a dependency chain across branches, ALWAYS use \`depends <branch>\` to declare dependencies first, then \`merge-order\` to determine the correct merge sequence. Missing \`depends\` leads to broken merge order.
|
|
90
|
+
Commands: depends <branch> --on <other> → depends --show → merge-order
|
|
91
|
+
Decision: Set dependencies before merging. If circular dependency detected → break the cycle by removing one dependency. \`merge-order\` respects the dependency graph.
|
|
92
|
+
|
|
93
|
+
### Decision Tree
|
|
94
|
+
Starting new work? → spidersan init → register + doctor
|
|
95
|
+
Found unknown/suspicious branch? → log --branch <branch> → context
|
|
96
|
+
About to merge? → conflicts → ready-check → depends --show → merge-order
|
|
97
|
+
Branches piling up? → stale → cleanup → sync
|
|
98
|
+
Blocked by another? → conflicts --notify → depends → merge-order
|
|
99
|
+
Cross-machine issues? → registry-sync --pull → cross-conflicts → doctor --remote
|
|
100
|
+
Investigating recent activity? → log → log --since 7d → context
|
|
101
|
+
Dead branches? → abandon + list --status abandoned
|
|
102
|
+
Stuck rebase? → rebase-helper
|
|
103
|
+
Remote out of sync? → github-sync → registry-sync
|
|
104
|
+
Setting up for first time? → spidersan init → config
|
|
105
|
+
Dependency chain? → depends <branch> --on <other> → depends --show → merge-order`;
|
|
106
|
+
// ─── System Prompt Builder ──────────────────────────────────
|
|
107
|
+
function buildSystemPrompt(mode) {
|
|
108
|
+
const persona = `You are Spidersan — the gitops coordinator for a multi-agent AI development fleet called 'the flock'. You speak with authority: direct, structured, actionable. Use real spidersan commands. Reference tier levels. Give git commands where needed. Never speculate — if you don't have enough context, say so.`;
|
|
109
|
+
const modeInstructions = {
|
|
110
|
+
ask: 'Answer the user\'s question using the repository context provided. Recommend specific commands. Structure your response with clear action items per agent if applicable.',
|
|
111
|
+
advise: 'Analyze the current repository state and proactively recommend what should be done next. Prioritize: TIER 3 blocks first, then stale cleanup, then merge ordering. Be concise.',
|
|
112
|
+
explain: 'Explain the branch\'s purpose, owner, status, and any conflicts. Use activity log and daily collab entries if available. Be factual.',
|
|
113
|
+
};
|
|
114
|
+
return `${persona}\n\n${modeInstructions[mode]}\n\n${SCENARIO_PLAYBOOK}`;
|
|
115
|
+
}
|
|
116
|
+
// ─── Context Serializer ─────────────────────────────────────
|
|
117
|
+
function serializeContext(context, verbose) {
|
|
118
|
+
const sections = [
|
|
119
|
+
`## Repository State (${context.timestamp})`,
|
|
120
|
+
`Repo: ${context.repo} | Branch: ${context.branch}`,
|
|
121
|
+
`Git: ${context.gitStatus.ahead} ahead, ${context.gitStatus.behind} behind${context.gitStatus.dirty.length > 0 ? `, ${context.gitStatus.dirty.length} dirty files` : ''}`,
|
|
122
|
+
'',
|
|
123
|
+
`## Registry: ${context.registry.active} active, ${context.registry.stale} stale`,
|
|
124
|
+
];
|
|
125
|
+
if (context.registry.branches.length > 0) {
|
|
126
|
+
for (const b of context.registry.branches.slice(0, 15)) {
|
|
127
|
+
sections.push(` - ${b.name} [${b.status}] agent=${b.agent ?? 'unknown'} files=${b.files.length}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
sections.push('', `## Conflicts: ${context.conflicts.tier3} BLOCK, ${context.conflicts.tier2} PAUSE, ${context.conflicts.tier1} WARN`);
|
|
131
|
+
if (context.conflicts.details.length > 0) {
|
|
132
|
+
for (const c of context.conflicts.details) {
|
|
133
|
+
sections.push(` - TIER ${c.tier}: ${c.branch} ↔ ${c.otherBranch} on [${c.files.join(', ')}]`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
sections.push('', `## Colony: ${context.colony.online ? 'online' : 'offline'}, ${context.colony.activeAgents.length} agents`);
|
|
137
|
+
if (context.colony.inProgress.length > 0) {
|
|
138
|
+
for (const w of context.colony.inProgress) {
|
|
139
|
+
sections.push(` - ${w.agent}: ${w.task} (${w.status})`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (verbose && context.activityLog && context.activityLog.length > 0) {
|
|
143
|
+
sections.push('', '## Recent Activity (last 24h)');
|
|
144
|
+
for (const a of context.activityLog.slice(0, 10)) {
|
|
145
|
+
sections.push(` - [${a.event}] ${a.branch ?? ''} by ${a.agent ?? 'unknown'} at ${a.timestamp}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return sections.join('\n');
|
|
149
|
+
}
|
|
150
|
+
// ─── Main Reasoning Function ────────────────────────────────
|
|
151
|
+
export async function reason(request, llmOverrides) {
|
|
152
|
+
const systemPrompt = buildSystemPrompt(request.mode);
|
|
153
|
+
const contextText = serializeContext(request.context, request.verbose);
|
|
154
|
+
let userMessage;
|
|
155
|
+
switch (request.mode) {
|
|
156
|
+
case 'ask':
|
|
157
|
+
userMessage = `${contextText}\n\n## Question\n${request.question}`;
|
|
158
|
+
break;
|
|
159
|
+
case 'advise':
|
|
160
|
+
userMessage = `${contextText}\n\nWhat should I do next? Prioritize by urgency.`;
|
|
161
|
+
break;
|
|
162
|
+
case 'explain':
|
|
163
|
+
userMessage = `${contextText}\n\nExplain branch: ${request.branch}`;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
const messages = [
|
|
167
|
+
{ role: 'system', content: systemPrompt },
|
|
168
|
+
{ role: 'user', content: userMessage },
|
|
169
|
+
];
|
|
170
|
+
const response = await chat(messages, llmOverrides);
|
|
171
|
+
// Extract commands from response (lines starting with spidersan/git/envoak/toak)
|
|
172
|
+
const commandPattern = /^\s*(?:spidersan|git|envoak|toak|npx spidersan)\s+.+/gm;
|
|
173
|
+
const commands = (response.content.match(commandPattern) ?? []).map(c => c.trim());
|
|
174
|
+
// Validate spidersan sub-commands against the known registry
|
|
175
|
+
const spidersanSubcommandPattern = /^(?:spidersan|npx spidersan)\s+(\S+)/;
|
|
176
|
+
const unknownCommands = commands.filter(cmd => {
|
|
177
|
+
const m = cmd.match(spidersanSubcommandPattern);
|
|
178
|
+
return m !== null && !m[1].startsWith('-') && !KNOWN_SPIDERSAN_COMMANDS.has(m[1]);
|
|
179
|
+
});
|
|
180
|
+
// Estimate categorical confidence from context quality
|
|
181
|
+
const hasConflicts = request.context.conflicts.tier3 > 0 || request.context.conflicts.tier2 > 0;
|
|
182
|
+
const hasRegistry = request.context.registry.active > 0;
|
|
183
|
+
const confidence = hasRegistry
|
|
184
|
+
? (hasConflicts ? 'high' : 'medium')
|
|
185
|
+
: 'low';
|
|
186
|
+
// Numeric trust score: multi-signal composite (0.0–1.0).
|
|
187
|
+
// Base from categorical label, then adjusted by context richness and output quality.
|
|
188
|
+
const CONFIDENCE_SCORES = { high: 0.9, medium: 0.7, low: 0.3 };
|
|
189
|
+
let confidenceScore = CONFIDENCE_SCORES[confidence];
|
|
190
|
+
// Try to parse numeric confidence from structured JSON response (P2A-1 model format)
|
|
191
|
+
const jsonMatch = response.content.match(/^\s*\{[\s\S]*?"confidence"\s*:\s*(0(?:\.\d+)?|1(?:\.0+)?)/m);
|
|
192
|
+
if (jsonMatch?.[1]) {
|
|
193
|
+
const parsed = parseFloat(jsonMatch[1]);
|
|
194
|
+
if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {
|
|
195
|
+
confidenceScore = parsed;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Context-richness adjustments (additive, capped at 1.0):
|
|
199
|
+
// +0.05 if colony is online with active agents (live fleet state available)
|
|
200
|
+
// +0.05 if activity log is present and non-empty (recent history available)
|
|
201
|
+
// -0.10 per unknown spidersan command in output (model hallucinated a command)
|
|
202
|
+
// -0.15 if tier-3 conflict exists and mode is 'advise' (high stakes, lower certainty)
|
|
203
|
+
if (request.context.colony.online && request.context.colony.activeAgents.length > 0) {
|
|
204
|
+
confidenceScore = Math.min(1.0, confidenceScore + 0.05);
|
|
205
|
+
}
|
|
206
|
+
if (request.context.activityLog && request.context.activityLog.length > 0) {
|
|
207
|
+
confidenceScore = Math.min(1.0, confidenceScore + 0.05);
|
|
208
|
+
}
|
|
209
|
+
if (unknownCommands.length > 0) {
|
|
210
|
+
confidenceScore = Math.max(0.0, confidenceScore - 0.10 * unknownCommands.length);
|
|
211
|
+
}
|
|
212
|
+
if (request.context.conflicts.tier3 > 0 && request.mode === 'advise') {
|
|
213
|
+
confidenceScore = Math.max(0.0, confidenceScore - 0.15);
|
|
214
|
+
}
|
|
215
|
+
confidenceScore = Math.round(confidenceScore * 100) / 100;
|
|
216
|
+
return {
|
|
217
|
+
advice: response.content,
|
|
218
|
+
commands,
|
|
219
|
+
unknownCommands,
|
|
220
|
+
confidence: confidence,
|
|
221
|
+
confidenceScore,
|
|
222
|
+
mode: request.mode,
|
|
223
|
+
provider: response.provider,
|
|
224
|
+
tokensUsed: response.promptTokens + response.completionTokens,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=reasoner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner.js","sourceRoot":"","sources":["../../../src/lib/ai/reasoner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spidersan AI Setup — tier config, server probe, BYOM URL validation
|
|
3
|
+
*
|
|
4
|
+
* Manages ~/.spidersan/config.json (AI-specific config, separate from .spidersanrc)
|
|
5
|
+
* Per spec: SPEC_spidersan_byom_telemetry.md §1.2, §1.3, §1.5, §2.1
|
|
6
|
+
*/
|
|
7
|
+
export type AiTier = 'free' | 'contributor' | 'byom' | 'local';
|
|
8
|
+
export interface AiSetupConfig {
|
|
9
|
+
/** How the AI layer routes LLM requests */
|
|
10
|
+
tier: AiTier;
|
|
11
|
+
/** Saved BYOM URL (only when tier=byom or explicit BYOM preference alongside hosted) */
|
|
12
|
+
byomUrl?: string;
|
|
13
|
+
/** User explicitly confirmed the BYOM URL is external — skip future prompts */
|
|
14
|
+
byomConfirmed?: boolean;
|
|
15
|
+
/** API key for hosted tier (free or contributor) */
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
/** Whether the user has seen and responded to the consent wizard */
|
|
18
|
+
consentGiven?: boolean;
|
|
19
|
+
/** ISO timestamp of first setup */
|
|
20
|
+
setupAt?: string;
|
|
21
|
+
/** ISO timestamp of last update */
|
|
22
|
+
updatedAt?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function loadAiConfig(): Promise<AiSetupConfig | null>;
|
|
25
|
+
export declare function saveAiConfig(config: AiSetupConfig): Promise<void>;
|
|
26
|
+
export declare function appendByomAudit(source: 'local_probe' | 'env_var' | 'hosted_api' | 'byom_config', url: string, confirmed: 'implicit' | 'explicit'): Promise<void>;
|
|
27
|
+
export interface ProbeResult {
|
|
28
|
+
url: string;
|
|
29
|
+
port: number;
|
|
30
|
+
label: string;
|
|
31
|
+
responding: boolean;
|
|
32
|
+
models?: string[];
|
|
33
|
+
}
|
|
34
|
+
export declare function probeLocalServers(timeoutMs?: number): Promise<ProbeResult[]>;
|
|
35
|
+
/** Probe the hosted API tier. Returns a ProbeResult. */
|
|
36
|
+
export declare function probeHostedTier(apiKey: string, timeoutMs?: number): Promise<ProbeResult>;
|
|
37
|
+
export type UrlClass = 'local' | 'lan' | 'external';
|
|
38
|
+
export declare function classifyUrl(rawUrl: string): UrlClass;
|
|
39
|
+
export declare function isLocalOrLan(url: string): boolean;
|
|
40
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/lib/ai/setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAQlE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvE;AAID,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,GAAG,aAAa,EAChE,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,GAAG,UAAU,GACjC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAID,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AASD,wBAAsB,iBAAiB,CAAC,SAAS,SAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA8B/E;AAED,wDAAwD;AACxD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAiC5F;AAID,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,CAAC;AAMpD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAWpD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|