ada-agent 0.2.0 → 0.3.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/README.md +262 -263
- package/bench/README.md +88 -88
- package/bench/swebench.mjs +242 -242
- package/docs/architecture.md +163 -163
- package/docs/architecture.svg +73 -73
- package/docs/cloudflare.md +81 -81
- package/docs/connectors.md +49 -49
- package/docs/integrations.md +62 -62
- package/package.json +66 -65
- package/skills/aesthetic-direction/SKILL.md +24 -24
- package/skills/color-palette/SKILL.md +24 -24
- package/skills/component-library/SKILL.md +23 -23
- package/skills/dark-mode/SKILL.md +24 -24
- package/skills/dashboard-ui/SKILL.md +23 -23
- package/skills/design-system/SKILL.md +24 -24
- package/skills/design-tokens/SKILL.md +24 -24
- package/skills/empty-states/SKILL.md +23 -23
- package/skills/hero-section/SKILL.md +23 -23
- package/skills/micro-interactions/SKILL.md +23 -23
- package/skills/motion-design/SKILL.md +23 -23
- package/skills/page-transitions/SKILL.md +23 -23
- package/skills/pricing-page/SKILL.md +23 -23
- package/skills/scroll-animation/SKILL.md +23 -23
- package/skills/skeleton-loader/SKILL.md +23 -23
- package/skills/tailwind-theme/SKILL.md +24 -24
- package/skills/typography/SKILL.md +24 -24
- package/skills/ui-polish/SKILL.md +24 -24
- package/skills/ui-review/SKILL.md +24 -24
- package/skills/web-fonts/SKILL.md +24 -24
- package/src/client/autostart.ts +93 -0
- package/src/client/catalog.json +1 -1
- package/src/client/cli.ts +1275 -1262
- package/src/client/models-dev.ts +106 -106
- package/src/selfcheck.ts +404 -390
- package/src/server/config.ts +65 -65
- package/src/server/providers/openai-compat.ts +78 -78
- package/src/server/providers/registry.ts +32 -32
- package/src/server/router.ts +33 -33
- package/src/shared/types.ts +21 -21
package/src/client/models-dev.ts
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
// models.dev catalog — model metadata (context limits, pricing, capabilities). The cache is seeded
|
|
2
|
-
// at load from a baked, curated subset (catalog.json — popular providers, generated by
|
|
3
|
-
// `npm run catalog:refresh`) so pricing/limits work offline; a live prefetch() then overlays the
|
|
4
|
-
// full models.dev catalog. Reads are synchronous from the in-memory cache.
|
|
5
|
-
|
|
6
|
-
import { readFileSync } from "node:fs";
|
|
7
|
-
|
|
8
|
-
interface Info {
|
|
9
|
-
context?: number;
|
|
10
|
-
output?: number;
|
|
11
|
-
inputCost?: number; // $ per 1M input tokens
|
|
12
|
-
outputCost?: number; // $ per 1M output tokens
|
|
13
|
-
reasoning?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface CatalogModel {
|
|
17
|
-
name: string;
|
|
18
|
-
context: number | null;
|
|
19
|
-
output: number | null;
|
|
20
|
-
in: number | null;
|
|
21
|
-
out: number | null;
|
|
22
|
-
reasoning?: boolean;
|
|
23
|
-
cacheRead?: number;
|
|
24
|
-
toolCall?: boolean;
|
|
25
|
-
}
|
|
26
|
-
interface Catalog {
|
|
27
|
-
providers: Record<string, { name: string; npm?: string; models: Record<string, CatalogModel> }>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const cache = new Map<string, Info>();
|
|
31
|
-
let fetchedAt = 0;
|
|
32
|
-
|
|
33
|
-
// The baked offline catalog (curated popular providers). Seeds the cache; live prefetch overlays it.
|
|
34
|
-
const CATALOG: Catalog = (() => {
|
|
35
|
-
try {
|
|
36
|
-
return JSON.parse(readFileSync(new URL("./catalog.json", import.meta.url), "utf8")) as Catalog;
|
|
37
|
-
} catch {
|
|
38
|
-
return { providers: {} };
|
|
39
|
-
}
|
|
40
|
-
})();
|
|
41
|
-
for (const prov of Object.values(CATALOG.providers)) {
|
|
42
|
-
for (const [id, m] of Object.entries(prov.models)) {
|
|
43
|
-
cache.set(id, { context: m.context ?? undefined, output: m.output ?? undefined, inputCost: m.in ?? undefined, outputCost: m.out ?? undefined, reasoning: m.reasoning });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Fetch and cache the models.dev catalog (no-op if fetched within the last hour). */
|
|
48
|
-
export async function prefetch(): Promise<void> {
|
|
49
|
-
if (cache.size && Date.now() - fetchedAt < 3_600_000) return;
|
|
50
|
-
try {
|
|
51
|
-
const res = await fetch("https://models.dev/api.json", { signal: AbortSignal.timeout(10_000) });
|
|
52
|
-
if (!res.ok) return;
|
|
53
|
-
const data = (await res.json()) as Record<string, { models?: Record<string, { limit?: { context?: number; output?: number }; cost?: { input?: number; output?: number }; reasoning?: boolean }> }>;
|
|
54
|
-
cache.clear();
|
|
55
|
-
for (const prov of Object.values(data)) {
|
|
56
|
-
for (const [id, m] of Object.entries(prov.models ?? {})) {
|
|
57
|
-
cache.set(id, { context: m.limit?.context, output: m.limit?.output, inputCost: m.cost?.input, outputCost: m.cost?.output, reasoning: m.reasoning });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
fetchedAt = Date.now();
|
|
61
|
-
} catch {
|
|
62
|
-
/* offline — keep whatever's cached */
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function lookup(modelId: string): Info | null {
|
|
67
|
-
return cache.get(modelId) ?? cache.get(modelId.split("/").pop() ?? "") ?? cache.get(modelId.split(":")[0] ?? "") ?? null;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** [inputCostPer1M, outputCostPer1M] from models.dev, or null. */
|
|
71
|
-
export function priceOf(modelId: string): [number, number] | null {
|
|
72
|
-
const i = lookup(modelId);
|
|
73
|
-
return i && i.inputCost != null && i.outputCost != null ? [i.inputCost, i.outputCost] : null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Context-window limit (tokens) from models.dev, or null. */
|
|
77
|
-
export function contextOf(modelId: string): number | null {
|
|
78
|
-
return lookup(modelId)?.context ?? null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function catalogSize(): number {
|
|
82
|
-
return cache.size;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Human-readable listing of the baked offline catalog. No filter → provider summary; a filter
|
|
86
|
-
* (provider id/name substring) → that provider's models with context + price. */
|
|
87
|
-
export function catalogText(filter?: string): string {
|
|
88
|
-
const f = filter?.toLowerCase();
|
|
89
|
-
const out: string[] = [];
|
|
90
|
-
for (const [pid, prov] of Object.entries(CATALOG.providers)) {
|
|
91
|
-
const models = Object.entries(prov.models);
|
|
92
|
-
if (!f) {
|
|
93
|
-
out.push(`${pid.padEnd(24)} ${String(models.length).padStart(3)} models \x1b[2m${prov.name}\x1b[0m`);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (!pid.toLowerCase().includes(f) && !prov.name.toLowerCase().includes(f)) continue;
|
|
97
|
-
out.push(`\n\x1b[1m${prov.name}\x1b[0m \x1b[2m(${pid})\x1b[0m`);
|
|
98
|
-
for (const [id, m] of models) {
|
|
99
|
-
const price = m.in != null && m.out != null ? `$${m.in}/$${m.out}` : "—";
|
|
100
|
-
const ctx = m.context ? `${Math.round(m.context / 1000)}k` : "—";
|
|
101
|
-
out.push(` ${id.padEnd(40)} ${ctx.padStart(6)} ctx · ${price}/1M${m.reasoning ? " · reasoning" : ""}`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (!out.length) return `no providers match "${filter}". Try /catalog with no argument for the list.`;
|
|
105
|
-
return f ? out.join("\n") : `${out.join("\n")}\n\x1b[2m/catalog <provider> for models · npm run catalog:refresh to update\x1b[0m`;
|
|
106
|
-
}
|
|
1
|
+
// models.dev catalog — model metadata (context limits, pricing, capabilities). The cache is seeded
|
|
2
|
+
// at load from a baked, curated subset (catalog.json — popular providers, generated by
|
|
3
|
+
// `npm run catalog:refresh`) so pricing/limits work offline; a live prefetch() then overlays the
|
|
4
|
+
// full models.dev catalog. Reads are synchronous from the in-memory cache.
|
|
5
|
+
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
|
|
8
|
+
interface Info {
|
|
9
|
+
context?: number;
|
|
10
|
+
output?: number;
|
|
11
|
+
inputCost?: number; // $ per 1M input tokens
|
|
12
|
+
outputCost?: number; // $ per 1M output tokens
|
|
13
|
+
reasoning?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface CatalogModel {
|
|
17
|
+
name: string;
|
|
18
|
+
context: number | null;
|
|
19
|
+
output: number | null;
|
|
20
|
+
in: number | null;
|
|
21
|
+
out: number | null;
|
|
22
|
+
reasoning?: boolean;
|
|
23
|
+
cacheRead?: number;
|
|
24
|
+
toolCall?: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface Catalog {
|
|
27
|
+
providers: Record<string, { name: string; npm?: string; models: Record<string, CatalogModel> }>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const cache = new Map<string, Info>();
|
|
31
|
+
let fetchedAt = 0;
|
|
32
|
+
|
|
33
|
+
// The baked offline catalog (curated popular providers). Seeds the cache; live prefetch overlays it.
|
|
34
|
+
const CATALOG: Catalog = (() => {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(readFileSync(new URL("./catalog.json", import.meta.url), "utf8")) as Catalog;
|
|
37
|
+
} catch {
|
|
38
|
+
return { providers: {} };
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
for (const prov of Object.values(CATALOG.providers)) {
|
|
42
|
+
for (const [id, m] of Object.entries(prov.models)) {
|
|
43
|
+
cache.set(id, { context: m.context ?? undefined, output: m.output ?? undefined, inputCost: m.in ?? undefined, outputCost: m.out ?? undefined, reasoning: m.reasoning });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Fetch and cache the models.dev catalog (no-op if fetched within the last hour). */
|
|
48
|
+
export async function prefetch(): Promise<void> {
|
|
49
|
+
if (cache.size && Date.now() - fetchedAt < 3_600_000) return;
|
|
50
|
+
try {
|
|
51
|
+
const res = await fetch("https://models.dev/api.json", { signal: AbortSignal.timeout(10_000) });
|
|
52
|
+
if (!res.ok) return;
|
|
53
|
+
const data = (await res.json()) as Record<string, { models?: Record<string, { limit?: { context?: number; output?: number }; cost?: { input?: number; output?: number }; reasoning?: boolean }> }>;
|
|
54
|
+
cache.clear();
|
|
55
|
+
for (const prov of Object.values(data)) {
|
|
56
|
+
for (const [id, m] of Object.entries(prov.models ?? {})) {
|
|
57
|
+
cache.set(id, { context: m.limit?.context, output: m.limit?.output, inputCost: m.cost?.input, outputCost: m.cost?.output, reasoning: m.reasoning });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
fetchedAt = Date.now();
|
|
61
|
+
} catch {
|
|
62
|
+
/* offline — keep whatever's cached */
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function lookup(modelId: string): Info | null {
|
|
67
|
+
return cache.get(modelId) ?? cache.get(modelId.split("/").pop() ?? "") ?? cache.get(modelId.split(":")[0] ?? "") ?? null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** [inputCostPer1M, outputCostPer1M] from models.dev, or null. */
|
|
71
|
+
export function priceOf(modelId: string): [number, number] | null {
|
|
72
|
+
const i = lookup(modelId);
|
|
73
|
+
return i && i.inputCost != null && i.outputCost != null ? [i.inputCost, i.outputCost] : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Context-window limit (tokens) from models.dev, or null. */
|
|
77
|
+
export function contextOf(modelId: string): number | null {
|
|
78
|
+
return lookup(modelId)?.context ?? null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function catalogSize(): number {
|
|
82
|
+
return cache.size;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Human-readable listing of the baked offline catalog. No filter → provider summary; a filter
|
|
86
|
+
* (provider id/name substring) → that provider's models with context + price. */
|
|
87
|
+
export function catalogText(filter?: string): string {
|
|
88
|
+
const f = filter?.toLowerCase();
|
|
89
|
+
const out: string[] = [];
|
|
90
|
+
for (const [pid, prov] of Object.entries(CATALOG.providers)) {
|
|
91
|
+
const models = Object.entries(prov.models);
|
|
92
|
+
if (!f) {
|
|
93
|
+
out.push(`${pid.padEnd(24)} ${String(models.length).padStart(3)} models \x1b[2m${prov.name}\x1b[0m`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!pid.toLowerCase().includes(f) && !prov.name.toLowerCase().includes(f)) continue;
|
|
97
|
+
out.push(`\n\x1b[1m${prov.name}\x1b[0m \x1b[2m(${pid})\x1b[0m`);
|
|
98
|
+
for (const [id, m] of models) {
|
|
99
|
+
const price = m.in != null && m.out != null ? `$${m.in}/$${m.out}` : "—";
|
|
100
|
+
const ctx = m.context ? `${Math.round(m.context / 1000)}k` : "—";
|
|
101
|
+
out.push(` ${id.padEnd(40)} ${ctx.padStart(6)} ctx · ${price}/1M${m.reasoning ? " · reasoning" : ""}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!out.length) return `no providers match "${filter}". Try /catalog with no argument for the list.`;
|
|
105
|
+
return f ? out.join("\n") : `${out.join("\n")}\n\x1b[2m/catalog <provider> for models · npm run catalog:refresh to update\x1b[0m`;
|
|
106
|
+
}
|