anorion 0.1.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.
Files changed (53) hide show
  1. package/README.md +87 -0
  2. package/agents/001.yaml +32 -0
  3. package/agents/example.yaml +6 -0
  4. package/bin/anorion.js +8093 -0
  5. package/package.json +72 -0
  6. package/scripts/cli.ts +182 -0
  7. package/scripts/postinstall.js +6 -0
  8. package/scripts/setup.ts +255 -0
  9. package/src/agents/pipeline.ts +231 -0
  10. package/src/agents/registry.ts +153 -0
  11. package/src/agents/runtime.ts +593 -0
  12. package/src/agents/session.ts +338 -0
  13. package/src/agents/subagent.ts +185 -0
  14. package/src/bridge/client.ts +221 -0
  15. package/src/bridge/federator.ts +221 -0
  16. package/src/bridge/protocol.ts +88 -0
  17. package/src/bridge/server.ts +221 -0
  18. package/src/channels/base.ts +43 -0
  19. package/src/channels/router.ts +122 -0
  20. package/src/channels/telegram.ts +592 -0
  21. package/src/channels/webhook.ts +143 -0
  22. package/src/cli/index.ts +1036 -0
  23. package/src/cli/interactive.ts +26 -0
  24. package/src/gateway/routes-v2.ts +165 -0
  25. package/src/gateway/server.ts +512 -0
  26. package/src/gateway/ws.ts +75 -0
  27. package/src/index.ts +182 -0
  28. package/src/llm/provider.ts +243 -0
  29. package/src/llm/providers.ts +381 -0
  30. package/src/memory/context.ts +125 -0
  31. package/src/memory/store.ts +214 -0
  32. package/src/scheduler/cron.ts +239 -0
  33. package/src/shared/audit.ts +231 -0
  34. package/src/shared/config.ts +129 -0
  35. package/src/shared/db/index.ts +165 -0
  36. package/src/shared/db/prepared.ts +111 -0
  37. package/src/shared/db/schema.ts +84 -0
  38. package/src/shared/events.ts +79 -0
  39. package/src/shared/logger.ts +10 -0
  40. package/src/shared/metrics.ts +190 -0
  41. package/src/shared/rbac.ts +151 -0
  42. package/src/shared/token-budget.ts +157 -0
  43. package/src/shared/types.ts +166 -0
  44. package/src/tools/builtin/echo.ts +19 -0
  45. package/src/tools/builtin/file-read.ts +78 -0
  46. package/src/tools/builtin/file-write.ts +64 -0
  47. package/src/tools/builtin/http-request.ts +63 -0
  48. package/src/tools/builtin/memory.ts +71 -0
  49. package/src/tools/builtin/shell.ts +94 -0
  50. package/src/tools/builtin/web-search.ts +22 -0
  51. package/src/tools/executor.ts +126 -0
  52. package/src/tools/registry.ts +56 -0
  53. package/src/tools/skill-manager.ts +252 -0
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "anorion",
3
+ "version": "0.1.0",
4
+ "description": "The open-source agent gateway — connect any LLM to any channel",
5
+ "keywords": [
6
+ "ai",
7
+ "agent",
8
+ "gateway",
9
+ "llm",
10
+ "telegram",
11
+ "chatbot",
12
+ "orchestration",
13
+ "openai",
14
+ "anthropic",
15
+ "claude",
16
+ "gpt"
17
+ ],
18
+ "license": "MIT",
19
+ "type": "module",
20
+ "module": "src/index.ts",
21
+ "bin": {
22
+ "anorion": "./bin/anorion.js"
23
+ },
24
+ "files": [
25
+ "bin/",
26
+ "dist/",
27
+ "src/",
28
+ "scripts/",
29
+ "agents/",
30
+ "README.md"
31
+ ],
32
+ "engines": {
33
+ "node": ">=18.0.0",
34
+ "bun": ">=1.0.0"
35
+ },
36
+ "scripts": {
37
+ "start": "bun run src/index.ts",
38
+ "dev": "bun --watch src/index.ts",
39
+ "build": "bun build src/index.ts --outdir dist --target bun",
40
+ "build:cli": "bun build src/cli/index.ts --outfile bin/anorion.js --target node",
41
+ "postinstall": "node scripts/postinstall.js",
42
+ "prepublishOnly": "bun run build:cli",
43
+ "cli": "bun run src/cli/index.ts",
44
+ "setup": "bun run scripts/setup.ts",
45
+ "doctor": "bun run scripts/cli.ts doctor"
46
+ },
47
+ "dependencies": {
48
+ "@ai-sdk/anthropic": "^3.0.58",
49
+ "@ai-sdk/google": "^3.0.53",
50
+ "@ai-sdk/mistral": "^3.0.27",
51
+ "@ai-sdk/openai": "^3.0.41",
52
+ "ai": "^6.0.116",
53
+ "drizzle-kit": "^0.31.9",
54
+ "drizzle-orm": "^0.45.1",
55
+ "grammy": "^1.41.1",
56
+ "hono": "^4.12.8",
57
+ "nanoid": "^5.1.6",
58
+ "node-cron": "^4.2.1",
59
+ "picocolors": "^1.1.1",
60
+ "pino": "^10.3.1",
61
+ "pino-pretty": "^13.1.3",
62
+ "yaml": "^2.8.2",
63
+ "zod": "^4.3.6"
64
+ },
65
+ "devDependencies": {
66
+ "@types/bun": "latest",
67
+ "@types/node": "^22.0.0"
68
+ },
69
+ "peerDependencies": {
70
+ "typescript": "^5"
71
+ }
72
+ }
package/scripts/cli.ts ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env bun
2
+ // Anorion CLI — management commands
3
+ // Usage: bun run scripts/cli.ts <command> [args]
4
+
5
+ import { existsSync, mkdirSync } from 'fs';
6
+ import { PROVIDERS, listConfiguredProviders, testProvider } from '../src/llm/providers';
7
+
8
+ const command = process.argv[2];
9
+
10
+ // ── Helpers ──
11
+
12
+ function formatUptime(seconds: number): string {
13
+ const h = Math.floor(seconds / 3600);
14
+ const m = Math.floor((seconds % 3600) / 60);
15
+ const s = Math.floor(seconds % 60);
16
+ if (h > 0) return `${h}h ${m}m ${s}s`;
17
+ if (m > 0) return `${m}m ${s}s`;
18
+ return `${s}s`;
19
+ }
20
+
21
+ function formatBytes(bytes: number): string {
22
+ if (bytes < 1024) return `${bytes}B`;
23
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
24
+ return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
25
+ }
26
+
27
+ // ── Commands ──
28
+
29
+ async function status() {
30
+ console.log('🔥 Anorion Gateway Status\n');
31
+ try {
32
+ const res = await fetch('http://localhost:4250/health');
33
+ const data = (await res.json()) as any;
34
+ console.log(` Status: ✅ Running`);
35
+ console.log(` Uptime: ${formatUptime(data.uptime)}`);
36
+ console.log(` Agents: ${data.agents}`);
37
+ console.log(` Timestamp: ${data.timestamp}`);
38
+ try {
39
+ const metrics = await fetch('http://localhost:4250/metrics');
40
+ if (metrics.ok) {
41
+ const text = await metrics.text();
42
+ const memMatch = text.match(/anorion_memory_rss_bytes (\d+)/);
43
+ if (memMatch) console.log(` Memory: ${formatBytes(parseInt(memMatch[1]))}`);
44
+ }
45
+ } catch {}
46
+ } catch {
47
+ console.log(' Status: ❌ Not running');
48
+ console.log(' Start with: bun run index.ts');
49
+ }
50
+ }
51
+
52
+ async function doctor() {
53
+ console.log('🔥 Anorion Doctor — Diagnostic Check\n');
54
+ let issues = 0;
55
+
56
+ // 1. Bun
57
+ console.log(' [1/6] Runtime...');
58
+ try {
59
+ const proc = Bun.spawn(['bun', '--version'], { stdout: 'pipe' });
60
+ const version = await new Response(proc.stdout).text();
61
+ console.log(` ✅ Bun ${version.trim()}`);
62
+ } catch {
63
+ console.log(' ❌ Bun not found');
64
+ issues++;
65
+ }
66
+
67
+ // 2. Config
68
+ console.log(' [2/6] Configuration...');
69
+ if (existsSync('anorion.yaml')) {
70
+ console.log(' ✅ anorion.yaml found');
71
+ } else {
72
+ console.log(' ⚠️ No anorion.yaml — run: bun run scripts/setup.ts');
73
+ issues++;
74
+ }
75
+
76
+ // 3. Dependencies
77
+ console.log(' [3/6] Dependencies...');
78
+ if (existsSync('node_modules')) {
79
+ console.log(' ✅ node_modules exists');
80
+ } else {
81
+ console.log(' ⚠️ No node_modules — run: bun install');
82
+ issues++;
83
+ }
84
+
85
+ // 4. Data dir
86
+ console.log(' [4/6] Data directory...');
87
+ mkdirSync('./data', { recursive: true });
88
+ console.log(' ✅ ./data ready');
89
+
90
+ // 5. LLM providers
91
+ console.log(' [5/6] LLM Providers...');
92
+ const providers = listConfiguredProviders();
93
+ const configured = providers.filter((p) => p.configured);
94
+ if (configured.length === 0) {
95
+ console.log(' ⚠️ No LLM providers configured. Set an API key:');
96
+ providers.slice(0, 5).forEach((p) => {
97
+ console.log(` export ${p.id.toUpperCase().replace(/-/g, '_')}_API_KEY=...`);
98
+ });
99
+ issues++;
100
+ } else {
101
+ configured.forEach((p) => {
102
+ console.log(` ✅ ${p.icon} ${p.name} (${p.models.length} models)`);
103
+ });
104
+ }
105
+
106
+ // 6. Connection test
107
+ console.log(' [6/6] Connection test...');
108
+ for (const p of configured.slice(0, 3)) {
109
+ const result = await testProvider(p.id);
110
+ if (result.ok) {
111
+ console.log(` ✅ ${p.icon} ${p.name}: ${result.latencyMs}ms`);
112
+ } else {
113
+ console.log(` ❌ ${p.icon} ${p.name}: ${result.error}`);
114
+ issues++;
115
+ }
116
+ }
117
+
118
+ console.log('');
119
+ if (issues === 0) {
120
+ console.log(' 🎉 All checks passed! Ready to go.');
121
+ } else {
122
+ console.log(` ⚠️ ${issues} issue(s) found. Fix them above.`);
123
+ }
124
+ }
125
+
126
+ async function providers() {
127
+ console.log('🔥 LLM Provider Status\n');
128
+ const all = listConfiguredProviders();
129
+ for (const p of all) {
130
+ const status = p.configured ? '✅' : '⬜';
131
+ console.log(` ${status} ${p.icon} ${p.name}`);
132
+ if (p.configured) {
133
+ console.log(` Key: ${p.id.toUpperCase()}_API_KEY`);
134
+ console.log(` Models: ${p.models.join(', ') || 'custom'}`);
135
+ } else {
136
+ console.log(` Set: export ${p.id.toUpperCase()}_API_KEY=<key>`);
137
+ }
138
+ console.log('');
139
+ }
140
+ console.log(` Total: ${all.filter((p) => p.configured).length}/${all.length} configured`);
141
+ }
142
+
143
+ async function models() {
144
+ console.log('🔥 Available Models\n');
145
+ for (const p of PROVIDERS) {
146
+ if (!process.env[p.envKey]) continue;
147
+ console.log(` ${p.icon} ${p.name}:`);
148
+ for (const m of p.popularModels) {
149
+ console.log(` • ${m}`);
150
+ }
151
+ console.log('');
152
+ }
153
+ console.log(' Usage: "provider/model" e.g. "openai/gpt-4o", "zai/glm-5.1"');
154
+ }
155
+
156
+ async function help() {
157
+ console.log('🔥 Anorion CLI\n');
158
+ console.log('Usage: bun run scripts/cli.ts <command>\n');
159
+ console.log('Commands:');
160
+ console.log(' status Check if gateway is running');
161
+ console.log(' doctor Run diagnostic checks');
162
+ console.log(' providers List LLM provider status');
163
+ console.log(' models List available models');
164
+ console.log(' help Show this help');
165
+ console.log('');
166
+ console.log('Setup:');
167
+ console.log(' bun run scripts/setup.ts First-time setup wizard');
168
+ }
169
+
170
+ // ── Router ──
171
+
172
+ const commands: Record<string, () => Promise<void>> = { status, doctor, providers, models };
173
+
174
+ if (!command || command === 'help' || command === '--help') {
175
+ help();
176
+ } else if (commands[command]) {
177
+ commands[command]();
178
+ } else {
179
+ console.log(`Unknown command: ${command}`);
180
+ help();
181
+ process.exit(1);
182
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ // Post-install message
3
+ console.log('\n 🔥 Thanks for installing Anorion!\n');
4
+ console.log(' Get started with:');
5
+ console.log(' npx anorion init\n');
6
+ console.log(' Docs: https://docs.anorion.ai\n');
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env bun
2
+ // anorion setup — CLI onboarding wizard
3
+ // Run: bun run scripts/setup.ts (or `anorion setup`)
4
+
5
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
6
+ import { resolve } from 'path';
7
+ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
8
+ import { PROVIDERS, testProvider, listConfiguredProviders, resolveModel } from '../src/llm/providers';
9
+
10
+ // ── TTY helpers ──
11
+
12
+ async function prompt(question: string, defaultValue?: string): Promise<string> {
13
+ process.stdout.write(`\n${question}${defaultValue ? ` [${defaultValue}]` : ''}: `);
14
+ const line = await readline();
15
+ return line.trim() || defaultValue || '';
16
+ }
17
+
18
+ async function confirm(question: string, defaultYes = true): Promise<boolean> {
19
+ const answer = await prompt(`${question} (${defaultYes ? 'Y/n' : 'y/N'})`);
20
+ if (!answer) return defaultYes;
21
+ return answer.toLowerCase().startsWith('y');
22
+ }
23
+
24
+ async function choose(question: string, options: string[]): Promise<number> {
25
+ console.log(`\n${question}`);
26
+ options.forEach((opt, i) => console.log(` ${i + 1}) ${opt}`));
27
+ const answer = parseInt(await prompt('Choose'));
28
+ return isNaN(answer) ? 0 : answer - 1;
29
+ }
30
+
31
+ function readline(): Promise<string> {
32
+ return new Promise((resolve) => {
33
+ process.stdin.once('data', (data) => resolve(data.toString().trim()));
34
+ });
35
+ }
36
+
37
+ function banner(text: string) {
38
+ const line = '═'.repeat(text.length + 4);
39
+ console.log(`\n╔${line}╗`);
40
+ console.log(`║ ${text} ║`);
41
+ console.log(`╚${line}╝\n`);
42
+ }
43
+
44
+ function section(title: string) {
45
+ console.log(`\n── ${title} ${'─'.repeat(Math.max(0, 50 - title.length))}`);
46
+ }
47
+
48
+ // ── Main Flow ──
49
+
50
+ async function main() {
51
+ banner('ANORION SETUP');
52
+ console.log('Welcome to Anorion — the open-source agent gateway.');
53
+ console.log('This wizard will help you get started in under 2 minutes.\n');
54
+
55
+ const config: Record<string, any> = {};
56
+
57
+ // ── Step 1: Gateway Basics ──
58
+ section('1. Gateway Configuration');
59
+ config.gateway = {
60
+ host: await prompt('Host', '0.0.0.0'),
61
+ port: parseInt(await prompt('Port', '4250')),
62
+ apiKeys: [],
63
+ database: './data/anorion.db',
64
+ };
65
+
66
+ // ── Step 2: LLM Provider ──
67
+ section('2. LLM Provider');
68
+ console.log('Available providers:\n');
69
+
70
+ const configured = listConfiguredProviders();
71
+ for (const p of configured) {
72
+ console.log(` ${p.icon} ${p.name.padEnd(20)} ${p.configured ? '✅ configured' : '⬜ no API key'}`);
73
+ }
74
+
75
+ const providerNames = PROVIDERS.map((p) => `${p.icon} ${p.name}`);
76
+ const providerIdx = await choose('Select your primary LLM provider:', providerNames);
77
+ const selectedProvider = PROVIDERS[providerIdx];
78
+
79
+ if (!process.env[selectedProvider.envKey]) {
80
+ const key = await prompt(`Enter your ${selectedProvider.name} API key (${selectedProvider.envKey})`);
81
+ if (key) {
82
+ config.gateway._envHints = config.gateway._envHints || {};
83
+ config.gateway._envHints[selectedProvider.envKey] = key;
84
+ }
85
+ }
86
+
87
+ // Model selection
88
+ if (selectedProvider.popularModels.length > 0) {
89
+ const modelIdx = await choose(
90
+ `Select model for ${selectedProvider.name}:`,
91
+ selectedProvider.popularModels,
92
+ );
93
+ config.agents = {
94
+ defaultModel: `${selectedProvider.id}/${selectedProvider.popularModels[modelIdx] || selectedProvider.defaultModel}`,
95
+ };
96
+ } else {
97
+ const model = await prompt(`Model name for ${selectedProvider.name}`, selectedProvider.defaultModel);
98
+ config.agents = { defaultModel: `${selectedProvider.id}/${model}` };
99
+ }
100
+
101
+ // ── Step 3: Agent Defaults ──
102
+ section('3. Agent Defaults');
103
+ config.agents = {
104
+ ...config.agents,
105
+ dir: './agents',
106
+ defaultTimeoutMs: parseInt(await prompt('Default agent timeout (ms)', '120000')),
107
+ maxSubagents: parseInt(await prompt('Max concurrent sub-agents', '5')),
108
+ idleTimeoutMs: 1800000,
109
+ };
110
+
111
+ // Fallback model
112
+ if (await confirm('Configure a fallback model?', false)) {
113
+ const fbProviderIdx = await choose('Fallback provider:', providerNames);
114
+ const fbProvider = PROVIDERS[fbProviderIdx];
115
+ const fbModelIdx = await choose(`Fallback model for ${fbProvider.name}:`, fbProvider.popularModels);
116
+ config.agents.fallbackModel = `${fbProvider.id}/${fbProvider.popularModels[fbModelIdx] || fbProvider.defaultModel}`;
117
+ }
118
+
119
+ // ── Step 4: Channels ──
120
+ section('4. Channels');
121
+ config.channels = {};
122
+
123
+ if (await confirm('Enable Telegram channel?', false)) {
124
+ config.channels.telegram = {
125
+ enabled: true,
126
+ botToken: await prompt('Telegram bot token'),
127
+ allowedUsers: (await prompt('Allowed user IDs (comma-separated)')).split(',').map((s) => s.trim()).filter(Boolean),
128
+ defaultAgent: 'example',
129
+ };
130
+ }
131
+
132
+ if (await confirm('Enable Webhook channel?', false)) {
133
+ config.channels.webhook = {
134
+ enabled: true,
135
+ inboundSecret: await prompt('Webhook secret', 'anorion-webhook-' + Math.random().toString(36).slice(2, 10)),
136
+ outboundUrls: [],
137
+ allowedIps: [],
138
+ };
139
+ }
140
+
141
+ // ── Step 5: Features ──
142
+ section('5. Features');
143
+ config.tokenBudget = {
144
+ enabled: await confirm('Enable token budgets?', true),
145
+ sessionLimit: 500000,
146
+ dailyLimit: 2000000,
147
+ globalDailyLimit: 10000000,
148
+ mode: 'enforce',
149
+ };
150
+
151
+ config.audit = {
152
+ enabled: await confirm('Enable audit logging?', true),
153
+ retentionDays: 90,
154
+ };
155
+
156
+ config.metrics = {
157
+ enabled: await confirm('Enable Prometheus metrics (/metrics)?', true),
158
+ };
159
+
160
+ config.skills = {
161
+ dir: './skills',
162
+ watch: await confirm('Enable skill hot-reload?', true),
163
+ };
164
+
165
+ config.pipelines = {
166
+ dir: './pipelines.yaml',
167
+ };
168
+
169
+ // ── Step 6: Create example agent ──
170
+ section('6. Example Agent');
171
+
172
+ if (await confirm('Create an example agent?', true)) {
173
+ const agentName = await prompt('Agent name', 'assistant');
174
+ const agentPrompt = await prompt('System prompt', 'You are a helpful AI assistant with access to tools. Be concise and direct.');
175
+
176
+ if (!existsSync('./agents')) mkdirSync('./agents', { recursive: true });
177
+
178
+ const agentYaml = stringifyYaml({
179
+ name: agentName,
180
+ model: config.agents.defaultModel,
181
+ fallbackModel: config.agents.fallbackModel || undefined,
182
+ systemPrompt: agentPrompt,
183
+ tools: ['echo', 'shell', 'http-request', 'file-read', 'file-write', 'web-search', 'memory-save', 'memory-search', 'memory-list'],
184
+ maxIterations: 10,
185
+ timeoutMs: config.agents.defaultTimeoutMs,
186
+ });
187
+
188
+ writeFileSync(`./agents/${agentName}.yaml`, agentYaml);
189
+ console.log(` ✅ Created agents/${agentName}.yaml`);
190
+ }
191
+
192
+ // ── Step 7: Test Connection ──
193
+ section('7. Connection Test');
194
+
195
+ if (await confirm('Test LLM connection now?', true)) {
196
+ console.log(` Testing ${selectedProvider.name}...`);
197
+ const result = await testProvider(selectedProvider.id, config.agents.defaultModel.split('/').pop());
198
+ if (result.ok) {
199
+ console.log(` ✅ Connected! Latency: ${result.latencyMs}ms`);
200
+ } else {
201
+ console.log(` ❌ Failed: ${result.error}`);
202
+ }
203
+ }
204
+
205
+ // ── Step 8: Write Config ──
206
+ section('8. Save Configuration');
207
+
208
+ // Clean up internal fields
209
+ delete config.gateway._envHints;
210
+
211
+ const outputPath = resolve(process.cwd(), 'anorion.yaml');
212
+ const yaml = stringifyYaml({
213
+ gateway: config.gateway,
214
+ agents: config.agents,
215
+ channels: config.channels,
216
+ scheduler: { enabled: true },
217
+ bridge: { enabled: false },
218
+ memory: { provider: 'sqlite', directory: './data/memory' },
219
+ tokenBudget: config.tokenBudget,
220
+ audit: config.audit,
221
+ metrics: config.metrics,
222
+ skills: config.skills,
223
+ pipelines: config.pipelines,
224
+ });
225
+
226
+ writeFileSync(outputPath, yaml);
227
+ console.log(` ✅ Configuration saved to ${outputPath}`);
228
+
229
+ // ── Done ──
230
+ banner('SETUP COMPLETE');
231
+ console.log(' Next steps:');
232
+ console.log('');
233
+ console.log(' 1. Set your API key:');
234
+ console.log(` export ${selectedProvider.envKey}=<your-key>`);
235
+ console.log('');
236
+ console.log(' 2. Start the gateway:');
237
+ console.log(' bun run index.ts');
238
+ console.log('');
239
+ console.log(' 3. Send a message:');
240
+ console.log(` curl -X POST http://localhost:${config.gateway.port}/api/v1/agents/${config.agents.defaultModel.includes('example') ? 'example' : 'assistant'}/messages \\`);
241
+ console.log(` -H "Content-Type: application/json" \\`);
242
+ console.log(` -H "X-API-Key: anorion-dev-key" \\`);
243
+ console.log(` -d '{"text": "Hello!"}'`);
244
+ console.log('');
245
+ console.log(` 📖 Docs: https://docs.anorion.ai`);
246
+ console.log(` 💬 Discord: https://discord.gg/anorion`);
247
+ console.log('');
248
+
249
+ process.exit(0);
250
+ }
251
+
252
+ main().catch((err) => {
253
+ console.error('Setup failed:', err.message);
254
+ process.exit(1);
255
+ });