@aiaiaichain/agent 0.1.2 → 0.1.4

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.
@@ -1,70 +1,45 @@
1
1
  /**
2
- * ModelRegistry — discovers available models via OpenRouter API.
3
- * Caches results and provides tiered model pools.
2
+ * ModelRegistry — discovers available models from any configured provider.
3
+ * Supports all 29 providers via their API keys.
4
4
  */
5
5
  import type { ToolResult } from "../api/ExtensionAPI.js";
6
6
  export type ModelTier = "orchestrator" | "analyst" | "worker" | "free";
7
- export interface OpenRouterModel {
7
+ export interface ModelInfo {
8
8
  id: string;
9
9
  name: string;
10
- created: number;
11
- description: string;
10
+ provider: string;
12
11
  context_length: number;
13
- architecture: {
14
- modality: string;
15
- tokenizer: string;
16
- instruct_type: string | null;
17
- };
18
- pricing: {
19
- prompt: string;
20
- completion: string;
21
- image: string;
22
- request: string;
23
- };
24
- top_provider: {
25
- max_completion_tokens: number | null;
26
- is_moderated: boolean;
27
- };
28
- per_request_limits: {
29
- prompt_tokens: number | null;
30
- completion_tokens: number | null;
31
- };
12
+ max_tokens: number;
32
13
  }
33
14
  export interface TieredModel {
34
- model: OpenRouterModel;
15
+ model: ModelInfo;
35
16
  tier: ModelTier;
36
17
  available: boolean;
37
18
  failures: number;
38
19
  }
39
- export interface TieredPool {
40
- tier: ModelTier;
41
- models: TieredModel[];
42
- }
43
- export declare function classifyModel(model: OpenRouterModel): ModelTier;
20
+ export declare function classifyModel(model: ModelInfo): ModelTier;
44
21
  export declare class ModelRegistry {
45
22
  private models;
46
23
  private tiered;
24
+ private providerModels;
47
25
  private initialized;
48
26
  initialise(): Promise<void>;
27
+ private buildTiers;
49
28
  get modelCount(): number;
29
+ getProviderCount(): number;
30
+ getProviderModels(providerId: string): ModelInfo[];
31
+ getAllModels(): ModelInfo[];
50
32
  getPool(tier: ModelTier): TieredModel[];
51
- getAllModels(): OpenRouterModel[];
52
33
  getTier(modelId: string): ModelTier | undefined;
53
34
  resolvePrimary(): string;
54
35
  listModelsParams: import("@sinclair/typebox").TObject<{
55
36
  query: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
37
+ provider: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
56
38
  limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
57
39
  available_only: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
58
40
  }>;
59
- pickModelParams: import("@sinclair/typebox").TObject<{
60
- tier: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
61
- min_context: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
62
- }>;
63
- summaryParams: import("@sinclair/typebox").TObject<{}>;
64
41
  listModelsTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
65
- pickModelTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
66
- summaryTool(): Promise<ToolResult>;
67
- private getFallbackModels;
42
+ modelSummaryTool(): Promise<ToolResult>;
68
43
  }
69
44
  export declare const modelRegistry: ModelRegistry;
70
45
  //# sourceMappingURL=ModelRegistry.d.ts.map
@@ -1,144 +1,151 @@
1
1
  /**
2
- * ModelRegistry — discovers available models via OpenRouter API.
3
- * Caches results and provides tiered model pools.
2
+ * ModelRegistry — discovers available models from any configured provider.
3
+ * Supports all 29 providers via their API keys.
4
4
  */
5
5
  import { env } from "../core/EnvLoader.js";
6
6
  import { Type } from "@sinclair/typebox";
7
- const DEFAULT_PRICING = {
8
- prompt: 0.000001,
9
- completion: 0.000002,
10
- };
11
- // ── Tier classification logic ─────────────────────────────────────────────────
7
+ const PROVIDERS_WITH_MODELS = [
8
+ { id: "openrouter", envVar: "OPENROUTER_API_KEY", baseUrl: "https://openrouter.ai/api/v1/models", mapper: (m) => ({ id: m.id, name: m.name, context: m.context_length ?? 131072, max: m.top_provider?.max_completion_tokens ?? 4096 }) },
9
+ { id: "anthropic", envVar: "ANTHROPIC_API_KEY", baseUrl: "https://api.anthropic.com/v1/models", mapper: (m) => ({ id: m.id, name: m.name, context: m.context_length ?? 200000, max: m.top_provider?.max_completion_tokens ?? 8192 }) },
10
+ { id: "openai", envVar: "OPENAI_API_KEY", baseUrl: "https://api.openai.com/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 128000, max: 4096 }) },
11
+ { id: "google", envVar: "GOOGLE_API_KEY", baseUrl: "https://generativelanguage.googleapis.com/v1beta/models", mapper: (m) => ({ id: m.name, name: m.displayName ?? m.name, context: m.contextLength ?? 1048576, max: 8192 }) },
12
+ { id: "deepseek", envVar: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 65536, max: 8192 }) },
13
+ { id: "groq", envVar: "GROQ_API_KEY", baseUrl: "https://api.groq.com/openai/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 131072, max: 4096 }) },
14
+ { id: "mistral", envVar: "MISTRAL_API_KEY", baseUrl: "https://api.mistral.ai/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 32000, max: 8192 }) },
15
+ { id: "together", envVar: "TOGETHER_API_KEY", baseUrl: "https://api.together.xyz/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 131072, max: 4096 }) },
16
+ { id: "fireworks", envVar: "FIREWORKS_API_KEY", baseUrl: "https://api.fireworks.ai/inference/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 131072, max: 4096 }) },
17
+ { id: "cerebras", envVar: "CEREBRAS_API_KEY", baseUrl: "https://api.cerebras.ai/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 131072, max: 4096 }) },
18
+ { id: "nvidia", envVar: "NVIDIA_NIM_API_KEY", baseUrl: "https://integrate.api.nvidia.com/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 131072, max: 4096 }) },
19
+ { id: "xai", envVar: "XAI_API_KEY", baseUrl: "https://api.x.ai/v1/models", mapper: (m) => ({ id: m.id, name: m.name ?? m.id, context: m.context_length ?? 131072, max: 4096 }) },
20
+ { id: "huggingface", envVar: "HUGGINGFACE_API_KEY", baseUrl: "https://huggingface.co/api/models?limit=100&inference_provider=auto", mapper: (m) => ({ id: m.id, name: m.id, context: 131072, max: 4096 }) },
21
+ ];
12
22
  export function classifyModel(model) {
13
23
  const id = model.id.toLowerCase();
14
24
  const name = model.name.toLowerCase();
15
- // High-end reasoning / largest models
16
- if (id.includes("o1") || id.includes("o3") || id.includes("claude-3.5-sonnet") ||
17
- id.includes("claude-4") || id.includes("gemini-2.5-pro") ||
18
- id.includes("gpt-4o") || !id.includes("mini") && (id.includes("gpt-4") || id.includes("chatgpt-4o")))
25
+ if (id.includes("o1") || id.includes("o3") || id.includes("claude-3.5-sonnet") || id.includes("claude-4") || id.includes("gemini-2.5-pro") || (id.includes("gpt-4o") && !id.includes("mini")))
19
26
  return "orchestrator";
20
- // Mid-range capable models
21
- if (id.includes("sonnet") || id.includes("gpt-4o-mini") || id.includes("claude-3-haiku") ||
22
- id.includes("gemini-2.0-flash") || id.includes("gemini-1.5-pro") ||
23
- id.includes("mistral-large") || id.includes("llama-3.1-70b") || id.includes("llama-3.3-70b") ||
24
- id.includes("command-r-plus") || id.includes("deepseek-v2") || id.includes("qwen-2.5-72b") ||
25
- id.includes("mixtral-8x22b"))
27
+ if (id.includes("sonnet") || id.includes("gpt-4o-mini") || id.includes("claude-3-haiku") || id.includes("gemini-2.0-flash") || id.includes("gemini-1.5-pro") || id.includes("mistral-large") || id.includes("llama-3.1-70b") || id.includes("llama-3.3-70b") || id.includes("command-r-plus") || id.includes("deepseek-v2") || id.includes("qwen-2.5-72b") || id.includes("mixtral-8x22b"))
26
28
  return "analyst";
27
- // Small, fast, cheap models
28
- if (id.includes("haiku") || id.includes("flash") || id.includes("mistral-7b") ||
29
- id.includes("llama-3.1-8b") || id.includes("llama-3.2") || id.includes("phi-3") ||
30
- id.includes("qwen-2.5-7b") || id.includes("gemma-2") || id.includes("deepseek-v2-lite") ||
31
- id.includes("ministral-3b") || id.includes("command-r-08-2024") ||
32
- id.includes("mixtral-8x7b") || id.includes("nemotron-4") || id.includes("claude-3-opus"))
29
+ if (id.includes("haiku") || id.includes("flash") || id.includes("mistral-7b") || id.includes("llama-3.1-8b") || id.includes("llama-3.2") || id.includes("phi-3") || id.includes("qwen-2.5-7b") || id.includes("gemma-2") || id.includes("deepseek-v2-lite") || id.includes("ministral-3b") || id.includes("command-r-08-2024") || id.includes("mixtral-8x7b") || id.includes("nemotron-4") || id.includes("claude-3-opus"))
33
30
  return "worker";
34
31
  return "free";
35
32
  }
36
- // ── Model Registry ────────────────────────────────────────────────────────────
37
33
  export class ModelRegistry {
38
34
  models = [];
39
35
  tiered = new Map();
36
+ providerModels = new Map();
40
37
  initialized = false;
41
38
  async initialise() {
42
39
  if (this.initialized)
43
40
  return;
44
- const apiKey = env.get("OPENROUTER_API_KEY");
45
- try {
46
- const response = await fetch("https://openrouter.ai/api/v1/models", {
47
- headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
48
- });
49
- if (response.ok) {
50
- const data = (await response.json());
51
- this.models = (data.data ?? []).filter(m => m.id && m.name);
41
+ this.models = [];
42
+ this.providerModels.clear();
43
+ for (const provider of PROVIDERS_WITH_MODELS) {
44
+ const apiKey = env.get(provider.envVar);
45
+ if (!apiKey)
46
+ continue;
47
+ try {
48
+ const headers = { "Content-Type": "application/json" };
49
+ if (provider.id === "openrouter")
50
+ headers["Authorization"] = `Bearer ${apiKey}`;
51
+ else if (provider.id === "anthropic")
52
+ headers["x-api-key"] = apiKey;
53
+ else
54
+ headers["Authorization"] = `Bearer ${apiKey}`;
55
+ let url = provider.baseUrl;
56
+ if (provider.id === "google") {
57
+ url = `${provider.baseUrl}?key=${apiKey}`;
58
+ }
59
+ const res = await fetch(url, { headers });
60
+ if (!res.ok)
61
+ continue;
62
+ const data = await res.json();
63
+ const items = data.data ?? data.models ?? data;
64
+ if (!Array.isArray(items))
65
+ continue;
66
+ for (const item of items) {
67
+ try {
68
+ const m = provider.mapper(item);
69
+ if (!m || !m.id)
70
+ continue;
71
+ const model = {
72
+ id: m.id,
73
+ name: m.name ?? m.id,
74
+ provider: provider.id,
75
+ context_length: m.context ?? 131072,
76
+ max_tokens: m.max ?? 4096,
77
+ };
78
+ this.models.push(model);
79
+ if (!this.providerModels.has(provider.id))
80
+ this.providerModels.set(provider.id, []);
81
+ this.providerModels.get(provider.id).push(model);
82
+ }
83
+ catch { /* skip bad entries */ }
84
+ }
52
85
  }
86
+ catch { /* skip this provider */ }
53
87
  }
54
- catch {
55
- // Fallback: use a curated list of known models
56
- this.models = this.getFallbackModels();
57
- }
58
- // Build tiered pools
88
+ this.buildTiers();
89
+ this.initialized = true;
90
+ }
91
+ buildTiers() {
59
92
  this.tiered.clear();
60
93
  const tiers = ["orchestrator", "analyst", "worker", "free"];
61
94
  for (const tier of tiers)
62
95
  this.tiered.set(tier, []);
63
96
  for (const model of this.models) {
64
97
  const tier = classifyModel(model);
65
- this.tiered.get(tier)?.push({
66
- model,
67
- tier,
68
- available: true,
69
- failures: 0,
70
- });
98
+ this.tiered.get(tier)?.push({ model, tier, available: true, failures: 0 });
71
99
  }
72
- this.initialized = true;
73
100
  }
74
101
  get modelCount() { return this.models.length; }
75
- getPool(tier) {
76
- return this.tiered.get(tier) ?? [];
77
- }
78
- getAllModels() {
79
- return [...this.models];
80
- }
81
- getTier(modelId) {
82
- const model = this.models.find(m => m.id === modelId);
83
- if (!model)
84
- return undefined;
85
- return classifyModel(model);
86
- }
102
+ getProviderCount() { return this.providerModels.size; }
103
+ getProviderModels(providerId) { return this.providerModels.get(providerId) ?? []; }
104
+ getAllModels() { return [...this.models]; }
105
+ getPool(tier) { return this.tiered.get(tier) ?? []; }
106
+ getTier(modelId) { const m = this.models.find(m => m.id === modelId); return m ? classifyModel(m) : undefined; }
87
107
  resolvePrimary() {
88
- const tier = "orchestrator";
89
- const pool = this.tiered.get(tier) ?? [];
90
- const available = pool.filter(tm => tm.available && tm.failures < 3);
91
- if (available.length > 0)
92
- return available[0].model.id;
93
- // Fall through tiers
94
- for (const t of ["analyst", "worker", "free"]) {
95
- const fallback = (this.tiered.get(t) ?? []).filter(tm => tm.available && tm.failures < 3);
96
- if (fallback.length > 0)
97
- return fallback[0].model.id;
108
+ for (const tier of ["orchestrator", "analyst", "worker", "free"]) {
109
+ const pool = this.tiered.get(tier) ?? [];
110
+ const avail = pool.filter(tm => tm.available && tm.failures < 3);
111
+ if (avail.length > 0)
112
+ return avail[0].model.id;
98
113
  }
99
114
  return "openai/gpt-4o-mini";
100
115
  }
101
- // ── Tools exposed to the agent ──────────────────────────────────────────
116
+ // Tools
102
117
  listModelsParams = Type.Object({
103
- query: Type.Optional(Type.String({ description: "Search query (name/provider)" })),
104
- limit: Type.Optional(Type.Number({ description: "Max results", default: 20 })),
118
+ query: Type.Optional(Type.String()),
119
+ provider: Type.Optional(Type.String()),
120
+ limit: Type.Optional(Type.Number({ default: 30 })),
105
121
  available_only: Type.Optional(Type.Boolean({ default: true })),
106
122
  });
107
- pickModelParams = Type.Object({
108
- tier: Type.Optional(Type.String({ description: "Tier: orchestrator, analyst, worker, free" })),
109
- min_context: Type.Optional(Type.Number({ description: "Minimum context length in tokens" })),
110
- });
111
- summaryParams = Type.Object({});
112
123
  async listModelsTool(_id, params) {
113
124
  let items = [...this.models];
114
125
  const query = (params.query || "").toLowerCase();
115
126
  if (query)
116
127
  items = items.filter(m => m.id.toLowerCase().includes(query) || m.name.toLowerCase().includes(query));
117
- const limit = params.limit || 20;
128
+ const provider = (params.provider || "").toLowerCase();
129
+ if (provider)
130
+ items = items.filter(m => m.provider === provider);
131
+ const limit = params.limit || 30;
118
132
  const top = items.slice(0, limit);
119
133
  const lines = top.map(m => {
120
134
  const tier = classifyModel(m);
121
- const tierIcon = { orchestrator: "⭐", analyst: "🔬", worker: "⚡", free: "🆓" }[tier] ?? "";
122
- return `${tierIcon} ${m.id} — ${m.name}`;
135
+ const tierIcon = { orchestrator: "⭐", analyst: "🔬", worker: "⚡", free: "🆓" }[tier] ?? "";
136
+ return `${tierIcon} [${m.provider}] ${m.id} — ${m.name} (${m.context_length}t)`;
123
137
  });
124
- return {
125
- content: [{ type: "text", text: `Models (${items.length} matching):\n${lines.join("\n")}` }],
126
- };
127
- }
128
- async pickModelTool(_id, params) {
129
- const tier = params.tier || "worker";
130
- const minCtx = params.min_context || 0;
131
- const pool = this.tiered.get(tier) ?? [];
132
- const available = pool.filter(tm => tm.available && tm.failures < 3 && tm.model.context_length >= minCtx);
133
- if (available.length === 0) {
134
- return { content: [{ type: "text", text: `No available models in tier "${tier}"${minCtx > 0 ? ` with ${minCtx}+ context` : ""}` }] };
135
- }
136
- const pick = available[0];
137
- return { content: [{ type: "text", text: `Selected: ${pick.model.id} (${pick.model.name}) — tier: ${tier}` }] };
138
+ return { content: [{ type: "text", text: `Models (${items.length} from ${this.providerModels.size} providers):\n${lines.join("\n")}` }] };
138
139
  }
139
- async summaryTool() {
140
+ async modelSummaryTool() {
140
141
  const pool = this.tiered;
141
- const lines = [`Total models: ${this.models.length}`];
142
+ const lines = [`Total: ${this.models.length} models from ${this.providerModels.size} providers`];
143
+ lines.push("");
144
+ lines.push("Providers:");
145
+ for (const [id, models] of this.providerModels) {
146
+ lines.push(` ${id}: ${models.length} models`);
147
+ }
148
+ lines.push("");
142
149
  for (const tier of ["orchestrator", "analyst", "worker", "free"]) {
143
150
  const p = pool.get(tier) ?? [];
144
151
  const avail = p.filter(tm => tm.available).length;
@@ -146,18 +153,6 @@ export class ModelRegistry {
146
153
  }
147
154
  return { content: [{ type: "text", text: lines.join("\n") }] };
148
155
  }
149
- // ── Fallback models ─────────────────────────────────────────────────────
150
- getFallbackModels() {
151
- return [
152
- { id: "openai/gpt-4o", name: "GPT-4o", created: 2024, description: "OpenAI GPT-4o", context_length: 128000, architecture: { modality: "text+image", tokenizer: "cl100k_base", instruct_type: null }, pricing: { prompt: "2.5e-6", completion: "1e-5", image: "0", request: "0" }, top_provider: { max_completion_tokens: 4096, is_moderated: true }, per_request_limits: null },
153
- { id: "openai/gpt-4o-mini", name: "GPT-4o Mini", created: 2024, description: "OpenAI GPT-4o Mini", context_length: 128000, architecture: { modality: "text+image", tokenizer: "cl100k_base", instruct_type: null }, pricing: { prompt: "1.5e-7", completion: "6e-7", image: "0", request: "0" }, top_provider: { max_completion_tokens: 4096, is_moderated: true }, per_request_limits: null },
154
- { id: "anthropic/claude-3.5-sonnet", name: "Claude 3.5 Sonnet", created: 2024, description: "Anthropic Claude 3.5 Sonnet", context_length: 200000, architecture: { modality: "text", tokenizer: "claude", instruct_type: null }, pricing: { prompt: "3e-6", completion: "1.5e-5", image: "0", request: "0" }, top_provider: { max_completion_tokens: 8192, is_moderated: true }, per_request_limits: null },
155
- { id: "anthropic/claude-3-haiku", name: "Claude 3 Haiku", created: 2024, description: "Anthropic Claude 3 Haiku", context_length: 200000, architecture: { modality: "text", tokenizer: "claude", instruct_type: null }, pricing: { prompt: "2.5e-7", completion: "1.25e-6", image: "0", request: "0" }, top_provider: { max_completion_tokens: 4096, is_moderated: true }, per_request_limits: null },
156
- { id: "google/gemini-2.0-flash-001", name: "Gemini 2.0 Flash", created: 2024, description: "Google Gemini 2.0 Flash", context_length: 1048576, architecture: { modality: "text+image", tokenizer: "gemini", instruct_type: null }, pricing: { prompt: "1e-7", completion: "4e-7", image: "0", request: "0" }, top_provider: { max_completion_tokens: 8192, is_moderated: false }, per_request_limits: null },
157
- { id: "meta-llama/llama-3.1-8b-instruct", name: "Llama 3.1 8B", created: 2024, description: "Meta Llama 3.1 8B", context_length: 131072, architecture: { modality: "text", tokenizer: "tiktoken", instruct_type: null }, pricing: { prompt: "2e-8", completion: "2e-8", image: "0", request: "0" }, top_provider: { max_completion_tokens: 4096, is_moderated: false }, per_request_limits: null },
158
- { id: "mistralai/mistral-small", name: "Mistral Small", created: 2024, description: "Mistral Small", context_length: 32000, architecture: { modality: "text", tokenizer: "mistral", instruct_type: null }, pricing: { prompt: "1e-7", completion: "3e-7", image: "0", request: "0" }, top_provider: { max_completion_tokens: 8192, is_moderated: true }, per_request_limits: null },
159
- ];
160
- }
161
156
  }
162
157
  export const modelRegistry = new ModelRegistry();
163
158
  //# sourceMappingURL=ModelRegistry.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ProviderRegistry — all 29 AI model providers with their env vars and model fetch endpoints.
3
+ */
4
+ export interface Provider {
5
+ id: string;
6
+ name: string;
7
+ envVar: string;
8
+ baseUrl: string;
9
+ modelsEndpoint: string;
10
+ docsUrl: string;
11
+ }
12
+ export declare const PROVIDERS: Provider[];
13
+ export declare function getConfiguredCount(env: Record<string, string | undefined>): number;
14
+ export declare function getConfigured(env: Record<string, string | undefined>): Provider[];
15
+ export declare function getUnconfigured(env: Record<string, string | undefined>): Provider[];
16
+ //# sourceMappingURL=ProviderRegistry.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ProviderRegistry — all 29 AI model providers with their env vars and model fetch endpoints.
3
+ */
4
+ export const PROVIDERS = [
5
+ { id: "openrouter", name: "OpenRouter", envVar: "OPENROUTER_API_KEY", baseUrl: "https://openrouter.ai/api/v1", modelsEndpoint: "https://openrouter.ai/api/v1/models", docsUrl: "https://openrouter.ai/keys" },
6
+ { id: "anthropic", name: "Anthropic", envVar: "ANTHROPIC_API_KEY", baseUrl: "https://api.anthropic.com/v1", modelsEndpoint: "https://api.anthropic.com/v1/models", docsUrl: "https://console.anthropic.com" },
7
+ { id: "openai", name: "OpenAI", envVar: "OPENAI_API_KEY", baseUrl: "https://api.openai.com/v1", modelsEndpoint: "https://api.openai.com/v1/models", docsUrl: "https://platform.openai.com/api-keys" },
8
+ { id: "google", name: "Google Gemini", envVar: "GOOGLE_API_KEY", baseUrl: "https://generativelanguage.googleapis.com/v1beta", modelsEndpoint: "https://generativelanguage.googleapis.com/v1beta/models", docsUrl: "https://aistudio.google.com/apikey" },
9
+ { id: "deepseek", name: "DeepSeek", envVar: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com/v1", modelsEndpoint: "https://api.deepseek.com/v1/models", docsUrl: "https://platform.deepseek.com/api-docs/api-key" },
10
+ { id: "groq", name: "Groq", envVar: "GROQ_API_KEY", baseUrl: "https://api.groq.com/openai/v1", modelsEndpoint: "https://api.groq.com/openai/v1/models", docsUrl: "https://console.groq.com/keys" },
11
+ { id: "mistral", name: "Mistral", envVar: "MISTRAL_API_KEY", baseUrl: "https://api.mistral.ai/v1", modelsEndpoint: "https://api.mistral.ai/v1/models", docsUrl: "https://console.mistral.ai/api-keys" },
12
+ { id: "together", name: "Together AI", envVar: "TOGETHER_API_KEY", baseUrl: "https://api.together.xyz/v1", modelsEndpoint: "https://api.together.xyz/v1/models", docsUrl: "https://api.together.xyz/settings/api-keys" },
13
+ { id: "fireworks", name: "Fireworks", envVar: "FIREWORKS_API_KEY", baseUrl: "https://api.fireworks.ai/inference/v1", modelsEndpoint: "https://api.fireworks.ai/inference/v1/models", docsUrl: "https://fireworks.ai/api-keys" },
14
+ { id: "cerebras", name: "Cerebras", envVar: "CEREBRAS_API_KEY", baseUrl: "https://api.cerebras.ai/v1", modelsEndpoint: "https://api.cerebras.ai/v1/models", docsUrl: "https://api.cerebras.ai/api-keys" },
15
+ { id: "bedrock", name: "Amazon Bedrock", envVar: "AWS_ACCESS_KEY_ID", baseUrl: "", modelsEndpoint: "", docsUrl: "https://console.aws.amazon.com/iam" },
16
+ { id: "vertex", name: "Google Vertex AI", envVar: "GOOGLE_APPLICATION_CREDENTIALS", baseUrl: "", modelsEndpoint: "", docsUrl: "https://console.cloud.google.com/apis/credentials" },
17
+ { id: "azure", name: "Azure OpenAI Responses", envVar: "AZURE_OPENAI_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://portal.azure.com" },
18
+ { id: "huggingface", name: "Hugging Face", envVar: "HUGGINGFACE_API_KEY", baseUrl: "https://api-inference.huggingface.co", modelsEndpoint: "https://huggingface.co/api/models", docsUrl: "https://huggingface.co/settings/tokens" },
19
+ { id: "nvidia", name: "NVIDIA NIM", envVar: "NVIDIA_NIM_API_KEY", baseUrl: "https://integrate.api.nvidia.com/v1", modelsEndpoint: "https://integrate.api.nvidia.com/v1/models", docsUrl: "https://integrate.api.nvidia.com" },
20
+ { id: "xai", name: "xAI", envVar: "XAI_API_KEY", baseUrl: "https://api.x.ai/v1", modelsEndpoint: "https://api.x.ai/v1/models", docsUrl: "https://console.x.ai" },
21
+ { id: "moonshot", name: "Moonshot AI", envVar: "MOONSHOT_API_KEY", baseUrl: "https://api.moonshot.cn/v1", modelsEndpoint: "https://api.moonshot.cn/v1/models", docsUrl: "https://platform.moonshot.cn/docs/api/chat-completion" },
22
+ { id: "moonshot_china", name: "Moonshot AI China", envVar: "MOONSHOT_CHINA_API_KEY", baseUrl: "https://api.moonshot.cn/v1", modelsEndpoint: "https://api.moonshot.cn/v1/models", docsUrl: "https://platform.moonshot.cn" },
23
+ { id: "minimax", name: "MiniMax", envVar: "MINIMAX_API_KEY", baseUrl: "https://api.minimax.chat/v1", modelsEndpoint: "https://api.minimax.chat/v1/models", docsUrl: "https://www.minimax.chat/document/embedding" },
24
+ { id: "minimax_china", name: "MiniMax China", envVar: "MINIMAX_CHINA_API_KEY", baseUrl: "https://api.minimax.chat/v1", modelsEndpoint: "https://api.minimax.chat/v1/models", docsUrl: "https://www.minimax.chat" },
25
+ { id: "kimi", name: "Kimi For Coding", envVar: "KIMI_API_KEY", baseUrl: "https://api.moonshot.cn/v1", modelsEndpoint: "https://api.moonshot.cn/v1/models", docsUrl: "https://platform.moonshot.cn" },
26
+ { id: "antling", name: "Ant Ling", envVar: "ANTLING_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://antling.ai" },
27
+ { id: "cloudflare_gateway", name: "Cloudflare AI Gateway", envVar: "CF_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://dash.cloudflare.com" },
28
+ { id: "cloudflare_workers", name: "Cloudflare Workers AI", envVar: "CF_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://dash.cloudflare.com" },
29
+ { id: "vercel", name: "Vercel AI Gateway", envVar: "VERCEL_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://vercel.com" },
30
+ { id: "opencode_go", name: "OpenCode Go", envVar: "OPENCODE_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://opencode.ai" },
31
+ { id: "opencode_zen", name: "OpenCode Zen", envVar: "OPENCODE_ZEN_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://opencode.ai" },
32
+ { id: "xiaomi", name: "Xiaomi MiMo", envVar: "XIAOMI_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://xiaomi.com" },
33
+ { id: "xiaomi_token", name: "Xiaomi MiMo Token Plan", envVar: "XIAOMI_TOKEN_API_KEY", baseUrl: "", modelsEndpoint: "", docsUrl: "https://xiaomi.com" },
34
+ ];
35
+ export function getConfiguredCount(env) {
36
+ return PROVIDERS.filter(p => p.envVar && env[p.envVar] && env[p.envVar].trim() !== "").length;
37
+ }
38
+ export function getConfigured(env) {
39
+ return PROVIDERS.filter(p => p.envVar && env[p.envVar] && env[p.envVar].trim() !== "");
40
+ }
41
+ export function getUnconfigured(env) {
42
+ return PROVIDERS.filter(p => !p.envVar || !env[p.envVar] || env[p.envVar].trim() === "");
43
+ }
44
+ //# sourceMappingURL=ProviderRegistry.js.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * SessionStore — saves/loads conversation sessions.
3
+ * Sessions stored as JSON in ~/.aiaiai/sessions/
4
+ */
5
+ import type { ChatMessage } from '../tui/REPL.js';
6
+ export interface SessionMeta {
7
+ id: string;
8
+ title: string;
9
+ createdAt: number;
10
+ updatedAt: number;
11
+ messageCount: number;
12
+ model: string;
13
+ }
14
+ export interface Session {
15
+ id: string;
16
+ title: string;
17
+ createdAt: number;
18
+ updatedAt: number;
19
+ messages: ChatMessage[];
20
+ model: string;
21
+ chain: string;
22
+ }
23
+ export declare class SessionStore {
24
+ private currentId;
25
+ private autoSaveInterval;
26
+ constructor();
27
+ /** Start auto-saving every 30s */
28
+ startAutoSave(getMessages: () => ChatMessage[]): void;
29
+ stopAutoSave(): void;
30
+ /** Save current session */
31
+ save(messages: ChatMessage[], title?: string): string;
32
+ /** Load a session by ID */
33
+ load(id: string): Session | null;
34
+ /** List all sessions (most recent first) */
35
+ list(): SessionMeta[];
36
+ /** Delete a session */
37
+ delete(id: string): boolean;
38
+ /** Set current session ID (for resuming) */
39
+ setCurrentId(id: string): void;
40
+ getCurrentId(): string;
41
+ /** Generate a title from first user message */
42
+ private generateTitle;
43
+ }
44
+ export declare const sessionStore: SessionStore;
45
+ //# sourceMappingURL=SessionStore.d.ts.map
@@ -0,0 +1,123 @@
1
+ /**
2
+ * SessionStore — saves/loads conversation sessions.
3
+ * Sessions stored as JSON in ~/.aiaiai/sessions/
4
+ */
5
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, unlinkSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+ import { homedir } from 'node:os';
8
+ const SESSIONS_DIR = resolve(homedir(), '.aiaiai', 'sessions');
9
+ function ensureDir() {
10
+ if (!existsSync(SESSIONS_DIR))
11
+ mkdirSync(SESSIONS_DIR, { recursive: true });
12
+ }
13
+ function sessionId() {
14
+ return `session-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
15
+ }
16
+ export class SessionStore {
17
+ currentId;
18
+ autoSaveInterval = null;
19
+ constructor() {
20
+ ensureDir();
21
+ this.currentId = sessionId();
22
+ }
23
+ /** Start auto-saving every 30s */
24
+ startAutoSave(getMessages) {
25
+ this.stopAutoSave();
26
+ this.autoSaveInterval = setInterval(() => {
27
+ const msgs = getMessages();
28
+ if (msgs.length > 0)
29
+ this.save(msgs, 'current');
30
+ }, 30_000);
31
+ }
32
+ stopAutoSave() {
33
+ if (this.autoSaveInterval) {
34
+ clearInterval(this.autoSaveInterval);
35
+ this.autoSaveInterval = null;
36
+ }
37
+ }
38
+ /** Save current session */
39
+ save(messages, title) {
40
+ ensureDir();
41
+ const id = this.currentId;
42
+ const existing = this.load(id);
43
+ const session = {
44
+ id,
45
+ title: title || existing?.title || this.generateTitle(messages),
46
+ createdAt: existing?.createdAt || Date.now(),
47
+ updatedAt: Date.now(),
48
+ messages,
49
+ model: process.env.DEFAULT_MODEL || 'unknown',
50
+ chain: 'solana',
51
+ };
52
+ try {
53
+ writeFileSync(resolve(SESSIONS_DIR, `${id}.json`), JSON.stringify(session, null, 2), 'utf-8');
54
+ }
55
+ catch { /* non-fatal */ }
56
+ return id;
57
+ }
58
+ /** Load a session by ID */
59
+ load(id) {
60
+ try {
61
+ const path = resolve(SESSIONS_DIR, `${id}.json`);
62
+ if (!existsSync(path))
63
+ return null;
64
+ return JSON.parse(readFileSync(path, 'utf-8'));
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ /** List all sessions (most recent first) */
71
+ list() {
72
+ ensureDir();
73
+ try {
74
+ const files = readdirSync(SESSIONS_DIR).filter(f => f.endsWith('.json'));
75
+ const sessions = [];
76
+ for (const file of files) {
77
+ try {
78
+ const data = JSON.parse(readFileSync(resolve(SESSIONS_DIR, file), 'utf-8'));
79
+ sessions.push({
80
+ id: data.id,
81
+ title: data.title,
82
+ createdAt: data.createdAt,
83
+ updatedAt: data.updatedAt,
84
+ messageCount: data.messages.length,
85
+ model: data.model,
86
+ });
87
+ }
88
+ catch { /* skip bad files */ }
89
+ }
90
+ return sessions.sort((a, b) => b.updatedAt - a.updatedAt);
91
+ }
92
+ catch {
93
+ return [];
94
+ }
95
+ }
96
+ /** Delete a session */
97
+ delete(id) {
98
+ try {
99
+ unlinkSync(resolve(SESSIONS_DIR, `${id}.json`));
100
+ return true;
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ /** Set current session ID (for resuming) */
107
+ setCurrentId(id) {
108
+ this.currentId = id;
109
+ }
110
+ getCurrentId() {
111
+ return this.currentId;
112
+ }
113
+ /** Generate a title from first user message */
114
+ generateTitle(messages) {
115
+ const firstUser = messages.find(m => m.role === 'user');
116
+ if (!firstUser)
117
+ return 'New Session';
118
+ const text = firstUser.content.trim();
119
+ return text.length > 40 ? text.slice(0, 37) + '…' : text;
120
+ }
121
+ }
122
+ export const sessionStore = new SessionStore();
123
+ //# sourceMappingURL=SessionStore.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * CrossTools — automation tools that combine multiple data sources.
3
+ * Watch tokens, compare, portfolio tracking, price alerts.
4
+ */
5
+ import type { ToolResult } from "../api/ExtensionAPI.js";
6
+ interface PriceAlert {
7
+ id: string;
8
+ token: string;
9
+ type: 'above' | 'below';
10
+ price: number;
11
+ active: boolean;
12
+ createdAt: number;
13
+ triggeredAt?: number;
14
+ }
15
+ export declare function addAlert(token: string, type: 'above' | 'below', price: number): PriceAlert;
16
+ export declare function checkAlerts(currentPrice: number, token: string): PriceAlert[];
17
+ export declare function getActiveAlerts(): PriceAlert[];
18
+ export declare function addToWatchList(tokenAddress: string): void;
19
+ export declare function removeFromWatchList(tokenAddress: string): void;
20
+ export declare function getWatchList(): string[];
21
+ export declare const watchTokenParams: import("@sinclair/typebox").TObject<{
22
+ address: import("@sinclair/typebox").TString;
23
+ }>;
24
+ export declare const removeWatchParams: import("@sinclair/typebox").TObject<{
25
+ address: import("@sinclair/typebox").TString;
26
+ }>;
27
+ export declare const listWatchParams: import("@sinclair/typebox").TObject<{}>;
28
+ export declare const addAlertParams: import("@sinclair/typebox").TObject<{
29
+ token: import("@sinclair/typebox").TString;
30
+ type: import("@sinclair/typebox").TString;
31
+ price: import("@sinclair/typebox").TNumber;
32
+ }>;
33
+ export declare const checkAlertsParams: import("@sinclair/typebox").TObject<{}>;
34
+ export declare const compareTokensParams: import("@sinclair/typebox").TObject<{
35
+ address1: import("@sinclair/typebox").TString;
36
+ address2: import("@sinclair/typebox").TString;
37
+ }>;
38
+ export declare function watchTokenTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
39
+ export declare function removeWatchTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
40
+ export declare function listWatchTool(): Promise<ToolResult>;
41
+ export declare function addAlertTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
42
+ export declare function checkAlertsTool(): Promise<ToolResult>;
43
+ export declare function compareTokensTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
44
+ export declare const portfolioParams: import("@sinclair/typebox").TObject<{
45
+ address: import("@sinclair/typebox").TString;
46
+ }>;
47
+ export declare function portfolioTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
48
+ export declare const COLD_WALLET = "A11iZoqEt6hU7HyggqC67ee4AtYmaJjwKCvJLerJRV2J";
49
+ export declare const ACTION_WALLET = "BygDYM1ZXLQNC1HXLhnd1rHZ7E5XjioqT3vPjJFfjnU2";
50
+ export declare const DEPOSIT_WALLET = "FBMDYpG9WXKy4SgxuATQdB2sCyzHsJWPrEr45z3TgL2e";
51
+ export {};
52
+ //# sourceMappingURL=CrossTools.d.ts.map