aura-code 0.3.0 → 0.3.1
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/README.md +2 -2
- package/dist/agent/loop.js +6 -0
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/system-prompt.js +9 -0
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/cli/index.js +132 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/config/defaults.js +1 -1
- package/dist/providers/factory.js +12 -0
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/google.js +21 -8
- package/dist/providers/google.js.map +1 -1
- package/dist/ruby/model-selector.d.ts +20 -0
- package/dist/ruby/model-selector.js +114 -0
- package/dist/ruby/model-selector.js.map +1 -0
- package/dist/ruby/stats.d.ts +6 -0
- package/dist/ruby/stats.js +103 -0
- package/dist/ruby/stats.js.map +1 -0
- package/dist/setup/provider-registry.d.ts +32 -0
- package/dist/setup/provider-registry.js +159 -0
- package/dist/setup/provider-registry.js.map +1 -0
- package/dist/setup/provider-test.d.ts +15 -0
- package/dist/setup/provider-test.js +195 -0
- package/dist/setup/provider-test.js.map +1 -0
- package/dist/setup/provider-wizard.d.ts +29 -0
- package/dist/setup/provider-wizard.js +363 -0
- package/dist/setup/provider-wizard.js.map +1 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/shadow-shield.d.ts +11 -0
- package/dist/tools/shadow-shield.js +538 -0
- package/dist/tools/shadow-shield.js.map +1 -0
- package/dist/util/errors.js +9 -1
- package/dist/util/errors.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectModelFromHistory = selectModelFromHistory;
|
|
4
|
+
exports.selectModel = selectModel;
|
|
5
|
+
const episode_capture_js_1 = require("./episode-capture.js");
|
|
6
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
// Model selection from episode history
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
const MIN_EPISODES_FOR_SELECTION = 5;
|
|
10
|
+
/**
|
|
11
|
+
* Tokenises a task string into lowercase words (≥3 chars).
|
|
12
|
+
*/
|
|
13
|
+
function tokenize(text) {
|
|
14
|
+
return text
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
17
|
+
.split(/\s+/)
|
|
18
|
+
.filter(t => t.length >= 3);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Simple Jaccard similarity between two task strings.
|
|
22
|
+
*/
|
|
23
|
+
function similarity(a, b) {
|
|
24
|
+
const ta = new Set(tokenize(a));
|
|
25
|
+
const tb = new Set(tokenize(b));
|
|
26
|
+
if (ta.size === 0 || tb.size === 0)
|
|
27
|
+
return 0;
|
|
28
|
+
let intersection = 0;
|
|
29
|
+
for (const t of ta) {
|
|
30
|
+
if (tb.has(t))
|
|
31
|
+
intersection++;
|
|
32
|
+
}
|
|
33
|
+
const union = ta.size + tb.size - intersection;
|
|
34
|
+
return union === 0 ? 0 : intersection / union;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Given a list of past episodes and the current task, selects the model that
|
|
38
|
+
* has historically performed best (highest approval rate, then highest task
|
|
39
|
+
* count) on similar tasks. Returns `undefined` when there is insufficient
|
|
40
|
+
* history or no clear winner.
|
|
41
|
+
*
|
|
42
|
+
* Only considers episodes where `largeModelUsed` is set.
|
|
43
|
+
* Never throws.
|
|
44
|
+
*/
|
|
45
|
+
function selectModelFromHistory(episodes, task, availableModels) {
|
|
46
|
+
try {
|
|
47
|
+
if (!Array.isArray(episodes) || episodes.length < MIN_EPISODES_FOR_SELECTION) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
if (!availableModels || availableModels.length === 0) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
// Weight similar episodes higher; include all episodes with at least some weight
|
|
54
|
+
const SIMILARITY_THRESHOLD = 0.15;
|
|
55
|
+
const modelStats = new Map();
|
|
56
|
+
for (const ep of episodes) {
|
|
57
|
+
if (!ep.largeModelUsed)
|
|
58
|
+
continue;
|
|
59
|
+
// Only consider models that are in the available set
|
|
60
|
+
if (!availableModels.includes(ep.largeModelUsed))
|
|
61
|
+
continue;
|
|
62
|
+
const sim = similarity(task, ep.task);
|
|
63
|
+
const weight = sim >= SIMILARITY_THRESHOLD ? 1 + sim : 0.1;
|
|
64
|
+
const prev = modelStats.get(ep.largeModelUsed) ?? {
|
|
65
|
+
weightedApprovals: 0,
|
|
66
|
+
weight: 0,
|
|
67
|
+
tasks: 0,
|
|
68
|
+
};
|
|
69
|
+
prev.weight += weight;
|
|
70
|
+
prev.weightedApprovals += ep.reviewerApproved ? weight : 0;
|
|
71
|
+
prev.tasks += 1;
|
|
72
|
+
modelStats.set(ep.largeModelUsed, prev);
|
|
73
|
+
}
|
|
74
|
+
if (modelStats.size === 0)
|
|
75
|
+
return undefined;
|
|
76
|
+
// Compute weighted approval rate per model
|
|
77
|
+
const ranked = Array.from(modelStats.entries())
|
|
78
|
+
.map(([model, s]) => ({
|
|
79
|
+
model,
|
|
80
|
+
approvalRate: s.weight === 0 ? 0 : s.weightedApprovals / s.weight,
|
|
81
|
+
tasks: s.tasks,
|
|
82
|
+
}))
|
|
83
|
+
.sort((a, b) => {
|
|
84
|
+
const rateDiff = b.approvalRate - a.approvalRate;
|
|
85
|
+
if (Math.abs(rateDiff) > 0.05)
|
|
86
|
+
return rateDiff;
|
|
87
|
+
return b.tasks - a.tasks;
|
|
88
|
+
});
|
|
89
|
+
return ranked[0]?.model;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Loads episodes from disk and calls `selectModelFromHistory`.
|
|
97
|
+
* Returns `undefined` when there are fewer than 5 episodes or on any error.
|
|
98
|
+
*
|
|
99
|
+
* @param projectRoot - Absolute project root path.
|
|
100
|
+
* @param task - Current task description.
|
|
101
|
+
* @param availableModels - Models that can actually be used (e.g. from getAllModels()).
|
|
102
|
+
*/
|
|
103
|
+
async function selectModel(projectRoot, task, availableModels) {
|
|
104
|
+
try {
|
|
105
|
+
const episodes = await episode_capture_js_1.episodeStore.loadEpisodes(projectRoot);
|
|
106
|
+
if (episodes.length < MIN_EPISODES_FOR_SELECTION)
|
|
107
|
+
return undefined;
|
|
108
|
+
return selectModelFromHistory(episodes, task, availableModels);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=model-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../src/ruby/model-selector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatStats = formatStats;
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// formatStats — pure function for testability
|
|
6
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
/**
|
|
8
|
+
* Formats a human-readable statistics summary from a list of episodes.
|
|
9
|
+
* Pure function — no I/O, always returns a string.
|
|
10
|
+
*/
|
|
11
|
+
function formatStats(episodes) {
|
|
12
|
+
if (episodes.length === 0) {
|
|
13
|
+
return [
|
|
14
|
+
'',
|
|
15
|
+
' Aura Stats',
|
|
16
|
+
'',
|
|
17
|
+
' Episodes recorded: 0',
|
|
18
|
+
' Tasks completed: 0 (0%)',
|
|
19
|
+
' Avg duration: —',
|
|
20
|
+
' Top model: —',
|
|
21
|
+
' Total tokens: 0 input / 0 output',
|
|
22
|
+
'',
|
|
23
|
+
].join('\n');
|
|
24
|
+
}
|
|
25
|
+
const total = episodes.length;
|
|
26
|
+
const completed = episodes.filter(e => e.reviewerApproved).length;
|
|
27
|
+
const completePct = total === 0 ? 0 : Math.round((completed / total) * 100);
|
|
28
|
+
// Average duration
|
|
29
|
+
const avgDurationMs = episodes.reduce((sum, e) => sum + (e.durationMs ?? 0), 0) / total;
|
|
30
|
+
const avgDurationStr = formatDuration(avgDurationMs);
|
|
31
|
+
// Top model by task count and success rate
|
|
32
|
+
const modelStats = new Map();
|
|
33
|
+
let totalInputTokens = 0;
|
|
34
|
+
let totalOutputTokens = 0;
|
|
35
|
+
for (const ep of episodes) {
|
|
36
|
+
const model = ep.largeModelUsed ?? (ep.rubySucceeded ? 'ruby' : undefined);
|
|
37
|
+
if (model) {
|
|
38
|
+
const existing = modelStats.get(model) ?? {
|
|
39
|
+
tasks: 0,
|
|
40
|
+
successes: 0,
|
|
41
|
+
inputTokens: 0,
|
|
42
|
+
outputTokens: 0,
|
|
43
|
+
};
|
|
44
|
+
existing.tasks += 1;
|
|
45
|
+
if (ep.reviewerApproved)
|
|
46
|
+
existing.successes += 1;
|
|
47
|
+
// Episodes only have a single tokensUsed bucket, not split by input/output.
|
|
48
|
+
// Treat largeModel tokens as input tokens for reporting purposes.
|
|
49
|
+
const largeTokens = ep.tokensUsed?.largeModel ?? 0;
|
|
50
|
+
const rubyTokens = ep.tokensUsed?.ruby ?? 0;
|
|
51
|
+
existing.inputTokens += largeTokens + rubyTokens;
|
|
52
|
+
modelStats.set(model, existing);
|
|
53
|
+
}
|
|
54
|
+
// Accumulate global token totals
|
|
55
|
+
totalInputTokens += ep.tokensUsed?.largeModel ?? 0;
|
|
56
|
+
totalInputTokens += ep.tokensUsed?.ruby ?? 0;
|
|
57
|
+
// Episodes don't separately track output tokens; use 0 as the split is unknown
|
|
58
|
+
totalOutputTokens += 0;
|
|
59
|
+
}
|
|
60
|
+
let topModel = '—';
|
|
61
|
+
if (modelStats.size > 0) {
|
|
62
|
+
const sorted = Array.from(modelStats.entries()).sort(([, a], [, b]) => b.tasks - a.tasks);
|
|
63
|
+
const [name, stats] = sorted[0];
|
|
64
|
+
const successPct = stats.tasks === 0 ? 0 : Math.round((stats.successes / stats.tasks) * 100);
|
|
65
|
+
topModel = `${name} (${stats.tasks} task${stats.tasks === 1 ? '' : 's'}, ${successPct}% success)`;
|
|
66
|
+
}
|
|
67
|
+
const inputStr = formatTokenCount(totalInputTokens);
|
|
68
|
+
const outputStr = formatTokenCount(totalOutputTokens);
|
|
69
|
+
return [
|
|
70
|
+
'',
|
|
71
|
+
' Aura Stats',
|
|
72
|
+
'',
|
|
73
|
+
` Episodes recorded: ${total}`,
|
|
74
|
+
` Tasks completed: ${completed} (${completePct}%)`,
|
|
75
|
+
` Avg duration: ${avgDurationStr}`,
|
|
76
|
+
` Top model: ${topModel}`,
|
|
77
|
+
` Total tokens: ${inputStr} input / ${outputStr} output`,
|
|
78
|
+
'',
|
|
79
|
+
].join('\n');
|
|
80
|
+
}
|
|
81
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
82
|
+
// Helpers
|
|
83
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
84
|
+
function formatDuration(ms) {
|
|
85
|
+
if (!ms || ms < 0)
|
|
86
|
+
return '—';
|
|
87
|
+
const totalSeconds = Math.round(ms / 1000);
|
|
88
|
+
if (totalSeconds < 60)
|
|
89
|
+
return `${totalSeconds}s`;
|
|
90
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
91
|
+
const seconds = totalSeconds % 60;
|
|
92
|
+
return `${minutes}m ${seconds}s`;
|
|
93
|
+
}
|
|
94
|
+
function formatTokenCount(n) {
|
|
95
|
+
if (n === 0)
|
|
96
|
+
return '0';
|
|
97
|
+
if (n >= 1_000_000)
|
|
98
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
99
|
+
if (n >= 1_000)
|
|
100
|
+
return `${(n / 1_000).toFixed(1)}K`;
|
|
101
|
+
return String(n);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/ruby/stats.ts"],"names":[],"mappings":";;AAUA,kCAmFC;AA3FD,gFAAgF;AAChF,8CAA8C;AAC9C,gFAAgF;AAEhF;;;GAGG;AACH,SAAgB,WAAW,CAAC,QAAmB;IAC7C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE;YACF,cAAc;YACd,EAAE;YACF,yBAAyB;YACzB,8BAA8B;YAC9B,yBAAyB;YACzB,yBAAyB;YACzB,0CAA0C;YAC1C,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC9B,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC;IAClE,MAAM,WAAW,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;IAE5E,mBAAmB;IACnB,MAAM,aAAa,GACjB,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;IACpE,MAAM,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAErD,2CAA2C;IAC3C,MAAM,UAAU,GAAG,IAAI,GAAG,EAGvB,CAAC;IAEJ,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAE1B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,EAAE,CAAC,cAAc,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC3E,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;gBACxC,KAAK,EAAE,CAAC;gBACR,SAAS,EAAE,CAAC;gBACZ,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;aAChB,CAAC;YACF,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;YACpB,IAAI,EAAE,CAAC,gBAAgB;gBAAE,QAAQ,CAAC,SAAS,IAAI,CAAC,CAAC;YACjD,4EAA4E;YAC5E,kEAAkE;YAClE,MAAM,WAAW,GAAG,EAAE,CAAC,UAAU,EAAE,UAAU,IAAI,CAAC,CAAC;YACnD,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,EAAE,IAAI,IAAI,CAAC,CAAC;YAC5C,QAAQ,CAAC,WAAW,IAAI,WAAW,GAAG,UAAU,CAAC;YACjD,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QAED,iCAAiC;QACjC,gBAAgB,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,IAAI,CAAC,CAAC;QACnD,gBAAgB,IAAI,EAAE,CAAC,UAAU,EAAE,IAAI,IAAI,CAAC,CAAC;QAC7C,+EAA+E;QAC/E,iBAAiB,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,QAAQ,GAAG,GAAG,CAAC;IACnB,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAClD,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CACpC,CAAC;QACF,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;QAC7F,QAAQ,GAAG,GAAG,IAAI,KAAK,KAAK,CAAC,KAAK,QAAQ,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,UAAU,YAAY,CAAC;IACpG,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;IAEtD,OAAO;QACL,EAAE;QACF,cAAc;QACd,EAAE;QACF,yBAAyB,KAAK,EAAE;QAChC,yBAAyB,SAAS,KAAK,WAAW,IAAI;QACtD,yBAAyB,cAAc,EAAE;QACzC,yBAAyB,QAAQ,EAAE;QACnC,yBAAyB,QAAQ,YAAY,SAAS,SAAS;QAC/D,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,SAAS,cAAc,CAAC,EAAU;IAChC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IAC3C,IAAI,YAAY,GAAG,EAAE;QAAE,OAAO,GAAG,YAAY,GAAG,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,YAAY,GAAG,EAAE,CAAC;IAClC,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,CAAC;AACnC,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS;IACjC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACxB,IAAI,CAAC,IAAI,SAAS;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5D,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface ProviderModel {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
speed: string;
|
|
5
|
+
contextWindow: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ProviderEntry {
|
|
8
|
+
name: string;
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
envKey: string | null;
|
|
11
|
+
signupUrl: string;
|
|
12
|
+
models: ProviderModel[];
|
|
13
|
+
}
|
|
14
|
+
export declare const PROVIDER_REGISTRY: ProviderEntry[];
|
|
15
|
+
/**
|
|
16
|
+
* Find a provider entry by display name (case-insensitive).
|
|
17
|
+
*/
|
|
18
|
+
export declare function findProviderByName(name: string): ProviderEntry | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Detect an existing API key for a provider.
|
|
21
|
+
* Checks process.env first, then the global config file.
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectExistingKey(provider: ProviderEntry): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Get the signup URL for a provider (for display when the user needs a key).
|
|
26
|
+
*/
|
|
27
|
+
export declare function getSignupUrl(provider: ProviderEntry): string;
|
|
28
|
+
/**
|
|
29
|
+
* Mask an API key for safe display — show first 4 + last 4 characters.
|
|
30
|
+
* Keys shorter than 10 chars just show '****'.
|
|
31
|
+
*/
|
|
32
|
+
export declare function maskApiKey(key: string): string;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROVIDER_REGISTRY = void 0;
|
|
4
|
+
exports.findProviderByName = findProviderByName;
|
|
5
|
+
exports.detectExistingKey = detectExistingKey;
|
|
6
|
+
exports.getSignupUrl = getSignupUrl;
|
|
7
|
+
exports.maskApiKey = maskApiKey;
|
|
8
|
+
/**
|
|
9
|
+
* Provider registry — all supported LLM providers with their endpoints,
|
|
10
|
+
* models, env var keys, and signup URLs.
|
|
11
|
+
*
|
|
12
|
+
* Used by the provider wizard to let users interactively configure their
|
|
13
|
+
* provider without manual env vars or --base-url flags.
|
|
14
|
+
*/
|
|
15
|
+
const env_js_1 = require("../util/env.js");
|
|
16
|
+
const global_config_js_1 = require("./global-config.js");
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
// Registry
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
exports.PROVIDER_REGISTRY = [
|
|
21
|
+
{
|
|
22
|
+
name: 'DeepSeek',
|
|
23
|
+
baseUrl: 'https://api.deepseek.com/v1',
|
|
24
|
+
envKey: 'DEEPSEEK_API_KEY',
|
|
25
|
+
signupUrl: 'https://platform.deepseek.com/api_keys',
|
|
26
|
+
models: [
|
|
27
|
+
{ id: 'deepseek-v4-flash', label: 'DeepSeek V4 Flash', speed: 'Fast', contextWindow: 1000000 },
|
|
28
|
+
{ id: 'deepseek-v4-pro', label: 'DeepSeek V4 Pro', speed: 'Powerful', contextWindow: 1000000 },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'Anthropic (Claude)',
|
|
33
|
+
baseUrl: 'https://api.anthropic.com',
|
|
34
|
+
envKey: 'ANTHROPIC_API_KEY',
|
|
35
|
+
signupUrl: 'https://console.anthropic.com/settings/keys',
|
|
36
|
+
models: [
|
|
37
|
+
{ id: 'claude-sonnet-4-5-20251001', label: 'Claude Sonnet 4.5', speed: 'Fast', contextWindow: 200000 },
|
|
38
|
+
{ id: 'claude-opus-4-5-20251001', label: 'Claude Opus 4.5', speed: 'Powerful', contextWindow: 200000 },
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'OpenAI (GPT)',
|
|
43
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
44
|
+
envKey: 'OPENAI_API_KEY',
|
|
45
|
+
signupUrl: 'https://platform.openai.com/api-keys',
|
|
46
|
+
models: [
|
|
47
|
+
{ id: 'gpt-4o', label: 'GPT-4o', speed: 'Fast', contextWindow: 128000 },
|
|
48
|
+
{ id: 'gpt-4o-mini', label: 'GPT-4o Mini', speed: 'Fast', contextWindow: 128000 },
|
|
49
|
+
{ id: 'o1', label: 'o1', speed: 'Reasoning', contextWindow: 200000 },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Google (Gemini)',
|
|
54
|
+
baseUrl: 'https://generativelanguage.googleapis.com/v1beta',
|
|
55
|
+
envKey: 'GOOGLE_API_KEY',
|
|
56
|
+
signupUrl: 'https://aistudio.google.com/apikey',
|
|
57
|
+
models: [
|
|
58
|
+
{ id: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash', speed: 'Fast', contextWindow: 1000000 },
|
|
59
|
+
{ id: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro', speed: 'Powerful', contextWindow: 1000000 },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'Xiaomi MiMo',
|
|
64
|
+
baseUrl: 'https://token-plan-sgp.xiaomimimo.com/v1',
|
|
65
|
+
envKey: 'XIAOMI_API_KEY',
|
|
66
|
+
signupUrl: 'https://mimo.xiaomiyoupin.com',
|
|
67
|
+
models: [
|
|
68
|
+
{ id: 'mimo-v2.5-pro', label: 'MiMo V2.5 Pro', speed: 'Powerful', contextWindow: 1000000 },
|
|
69
|
+
{ id: 'mimo-v2-flash', label: 'MiMo V2 Flash', speed: 'Fast', contextWindow: 1000000 },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'OpenRouter',
|
|
74
|
+
baseUrl: 'https://openrouter.ai/api/v1',
|
|
75
|
+
envKey: 'OPENROUTER_API_KEY',
|
|
76
|
+
signupUrl: 'https://openrouter.ai/keys',
|
|
77
|
+
models: [
|
|
78
|
+
{ id: 'auto', label: 'Auto (best available)', speed: 'Auto', contextWindow: 128000 },
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'xAI (Grok)',
|
|
83
|
+
baseUrl: 'https://api.x.ai/v1',
|
|
84
|
+
envKey: 'XAI_API_KEY',
|
|
85
|
+
signupUrl: 'https://console.x.ai',
|
|
86
|
+
models: [
|
|
87
|
+
{ id: 'grok-2', label: 'Grok 2', speed: 'Powerful', contextWindow: 131072 },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'NVIDIA NIM',
|
|
92
|
+
baseUrl: 'https://integrate.api.nvidia.com/v1',
|
|
93
|
+
envKey: 'NVIDIA_API_KEY',
|
|
94
|
+
signupUrl: 'https://build.nvidia.com',
|
|
95
|
+
models: [
|
|
96
|
+
{ id: 'nvidia/llama-3.1-nemotron-70b-instruct', label: 'Nemotron 70B', speed: 'Powerful', contextWindow: 131072 },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'Ollama (local, free)',
|
|
101
|
+
baseUrl: 'http://localhost:11434/v1',
|
|
102
|
+
envKey: null, // No API key needed
|
|
103
|
+
signupUrl: 'https://ollama.com',
|
|
104
|
+
models: [], // Auto-detect from running Ollama instance
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'Custom endpoint',
|
|
108
|
+
baseUrl: '', // User provides
|
|
109
|
+
envKey: null,
|
|
110
|
+
signupUrl: '',
|
|
111
|
+
models: [], // User provides model ID
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
115
|
+
// Helpers
|
|
116
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
117
|
+
/**
|
|
118
|
+
* Find a provider entry by display name (case-insensitive).
|
|
119
|
+
*/
|
|
120
|
+
function findProviderByName(name) {
|
|
121
|
+
return exports.PROVIDER_REGISTRY.find(p => p.name.toLowerCase() === name.toLowerCase());
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Detect an existing API key for a provider.
|
|
125
|
+
* Checks process.env first, then the global config file.
|
|
126
|
+
*/
|
|
127
|
+
function detectExistingKey(provider) {
|
|
128
|
+
if (!provider.envKey)
|
|
129
|
+
return null;
|
|
130
|
+
// 1. Check process.env (canonical + lowercase)
|
|
131
|
+
const envVal = (0, env_js_1.getApiKey)(provider.envKey);
|
|
132
|
+
if (envVal)
|
|
133
|
+
return envVal;
|
|
134
|
+
// 2. Check saved config
|
|
135
|
+
const cfg = (0, global_config_js_1.loadGlobalConfig)();
|
|
136
|
+
if (cfg && cfg.apiKeyEnv === provider.envKey) {
|
|
137
|
+
// The global config stores the env var name, not the key itself.
|
|
138
|
+
// But the provider wizard saves the key to config.json as well.
|
|
139
|
+
// Check if there's a saved key via any saved config mechanism.
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get the signup URL for a provider (for display when the user needs a key).
|
|
146
|
+
*/
|
|
147
|
+
function getSignupUrl(provider) {
|
|
148
|
+
return provider.signupUrl;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Mask an API key for safe display — show first 4 + last 4 characters.
|
|
152
|
+
* Keys shorter than 10 chars just show '****'.
|
|
153
|
+
*/
|
|
154
|
+
function maskApiKey(key) {
|
|
155
|
+
if (key.length < 10)
|
|
156
|
+
return '****';
|
|
157
|
+
return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=provider-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../../src/setup/provider-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ProviderTestConfig {
|
|
2
|
+
provider: string;
|
|
3
|
+
model: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TestResult {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Test a provider connection by sending a minimal chat completion request.
|
|
13
|
+
* Times out after 10 seconds.
|
|
14
|
+
*/
|
|
15
|
+
export declare function testProviderConnection(config: ProviderTestConfig): Promise<TestResult>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.testProviderConnection = testProviderConnection;
|
|
37
|
+
/**
|
|
38
|
+
* Provider connection tester.
|
|
39
|
+
*
|
|
40
|
+
* Sends a minimal API request to verify the key works for a given provider.
|
|
41
|
+
* Handles different auth formats:
|
|
42
|
+
* - Anthropic: x-api-key header
|
|
43
|
+
* - Google: ?key= query param
|
|
44
|
+
* - All others: standard Bearer token
|
|
45
|
+
*/
|
|
46
|
+
const https = __importStar(require("https"));
|
|
47
|
+
const http = __importStar(require("http"));
|
|
48
|
+
const url_1 = require("url");
|
|
49
|
+
/**
|
|
50
|
+
* Test a provider connection by sending a minimal chat completion request.
|
|
51
|
+
* Times out after 10 seconds.
|
|
52
|
+
*/
|
|
53
|
+
async function testProviderConnection(config) {
|
|
54
|
+
const isOllama = config.provider === 'Ollama (local, free)';
|
|
55
|
+
const isAnthropic = config.provider === 'Anthropic (Claude)';
|
|
56
|
+
const isGoogle = config.provider === 'Google (Gemini)';
|
|
57
|
+
// ── Ollama: just check if the server is reachable ──────────────────────────
|
|
58
|
+
if (isOllama) {
|
|
59
|
+
return testOllamaConnection(config.baseUrl);
|
|
60
|
+
}
|
|
61
|
+
// ── Google: uses a different API format ────────────────────────────────────
|
|
62
|
+
if (isGoogle) {
|
|
63
|
+
return testGoogleConnection(config);
|
|
64
|
+
}
|
|
65
|
+
// ── Anthropic: uses x-api-key header and different body format ─────────────
|
|
66
|
+
if (isAnthropic) {
|
|
67
|
+
return testAnthropicConnection(config);
|
|
68
|
+
}
|
|
69
|
+
// ── All others: OpenAI-compatible chat/completions ─────────────────────────
|
|
70
|
+
return testOpenAICompatibleConnection(config);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check if Ollama is running by fetching /api/tags.
|
|
74
|
+
*/
|
|
75
|
+
async function testOllamaConnection(baseUrl) {
|
|
76
|
+
// Ollama's base is e.g. http://localhost:11434/v1 — we need the root
|
|
77
|
+
const root = baseUrl.replace(/\/v1\/?$/, '');
|
|
78
|
+
return new Promise(resolve => {
|
|
79
|
+
const req = http.get(`${root}/api/tags`, { timeout: 10_000 }, res => {
|
|
80
|
+
if (res.statusCode === 200) {
|
|
81
|
+
resolve({ ok: true });
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
resolve({ ok: false, error: `Ollama responded with HTTP ${res.statusCode}` });
|
|
85
|
+
}
|
|
86
|
+
res.resume();
|
|
87
|
+
});
|
|
88
|
+
req.on('error', (e) => {
|
|
89
|
+
resolve({
|
|
90
|
+
ok: false,
|
|
91
|
+
error: `Ollama doesn't seem to be running. Start it first: ollama serve (${e.message})`,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
req.on('timeout', () => {
|
|
95
|
+
req.destroy();
|
|
96
|
+
resolve({ ok: false, error: 'Connection timed out after 10 seconds' });
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Test Google Generative AI connection using generateContent endpoint.
|
|
102
|
+
*/
|
|
103
|
+
async function testGoogleConnection(config) {
|
|
104
|
+
const url = new url_1.URL(`${config.baseUrl}/models/${config.model}:generateContent?key=${config.apiKey}`);
|
|
105
|
+
const body = JSON.stringify({
|
|
106
|
+
contents: [{ parts: [{ text: "Say 'ok' and nothing else" }] }],
|
|
107
|
+
generationConfig: { maxOutputTokens: 10 },
|
|
108
|
+
});
|
|
109
|
+
return makeRequest(url, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: { 'Content-Type': 'application/json' },
|
|
112
|
+
body,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Test Anthropic connection using their Messages API.
|
|
117
|
+
*/
|
|
118
|
+
async function testAnthropicConnection(config) {
|
|
119
|
+
const url = new url_1.URL(`${config.baseUrl}/v1/messages`);
|
|
120
|
+
const body = JSON.stringify({
|
|
121
|
+
model: config.model,
|
|
122
|
+
max_tokens: 10,
|
|
123
|
+
messages: [{ role: 'user', content: "Say 'ok' and nothing else" }],
|
|
124
|
+
});
|
|
125
|
+
return makeRequest(url, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json',
|
|
129
|
+
'x-api-key': config.apiKey ?? '',
|
|
130
|
+
'anthropic-version': '2023-06-01',
|
|
131
|
+
},
|
|
132
|
+
body,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Test OpenAI-compatible connection using chat/completions.
|
|
137
|
+
*/
|
|
138
|
+
async function testOpenAICompatibleConnection(config) {
|
|
139
|
+
const url = new url_1.URL(`${config.baseUrl}/chat/completions`);
|
|
140
|
+
const body = JSON.stringify({
|
|
141
|
+
model: config.model,
|
|
142
|
+
max_tokens: 10,
|
|
143
|
+
messages: [{ role: 'user', content: "Say 'ok' and nothing else" }],
|
|
144
|
+
});
|
|
145
|
+
return makeRequest(url, {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: {
|
|
148
|
+
'Content-Type': 'application/json',
|
|
149
|
+
'Authorization': `Bearer ${config.apiKey ?? ''}`,
|
|
150
|
+
},
|
|
151
|
+
body,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Low-level HTTPS/HTTP request with 10 second timeout.
|
|
156
|
+
*/
|
|
157
|
+
function makeRequest(url, opts) {
|
|
158
|
+
const transport = url.protocol === 'https:' ? https : http;
|
|
159
|
+
return new Promise(resolve => {
|
|
160
|
+
const req = transport.request(url, {
|
|
161
|
+
method: opts.method,
|
|
162
|
+
headers: opts.headers,
|
|
163
|
+
timeout: 10_000,
|
|
164
|
+
}, res => {
|
|
165
|
+
let data = '';
|
|
166
|
+
res.on('data', chunk => { data += chunk; });
|
|
167
|
+
res.on('end', () => {
|
|
168
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
169
|
+
resolve({ ok: true });
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
let errorMsg = `HTTP ${res.statusCode}`;
|
|
173
|
+
try {
|
|
174
|
+
const parsed = JSON.parse(data);
|
|
175
|
+
const msg = parsed.error?.message ?? parsed.error?.type ?? parsed.message ?? parsed.detail ?? parsed.title ?? '';
|
|
176
|
+
if (msg)
|
|
177
|
+
errorMsg += `: ${msg}`;
|
|
178
|
+
}
|
|
179
|
+
catch { /* ignore parse errors */ }
|
|
180
|
+
resolve({ ok: false, error: errorMsg });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
req.on('error', (e) => {
|
|
185
|
+
resolve({ ok: false, error: `Connection failed: ${e.message}` });
|
|
186
|
+
});
|
|
187
|
+
req.on('timeout', () => {
|
|
188
|
+
req.destroy();
|
|
189
|
+
resolve({ ok: false, error: 'Connection timed out after 10 seconds' });
|
|
190
|
+
});
|
|
191
|
+
req.write(opts.body);
|
|
192
|
+
req.end();
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=provider-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-test.js","sourceRoot":"","sources":["../../src/setup/provider-test.ts"],"names":[],"mappings":"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"}
|