synapse-gateway 2.0.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 (135) hide show
  1. package/README.md +385 -0
  2. package/bin/synapse.js +242 -0
  3. package/docs/PLAN.md +1723 -0
  4. package/docs/PRD.md +1799 -0
  5. package/drizzle.config.ts +12 -0
  6. package/next.config.ts +8 -0
  7. package/package.json +82 -0
  8. package/postcss.config.mjs +7 -0
  9. package/public/file.svg +1 -0
  10. package/public/globe.svg +1 -0
  11. package/public/next.svg +1 -0
  12. package/public/vercel.svg +1 -0
  13. package/public/window.svg +1 -0
  14. package/src/app/api/analytics/cost/route.ts +13 -0
  15. package/src/app/api/analytics/usage/route.ts +16 -0
  16. package/src/app/api/auth/login/route.ts +42 -0
  17. package/src/app/api/cache/route.ts +19 -0
  18. package/src/app/api/dashboard/route.ts +35 -0
  19. package/src/app/api/distill/route.ts +10 -0
  20. package/src/app/api/events/route.ts +54 -0
  21. package/src/app/api/health/route.ts +10 -0
  22. package/src/app/api/intelligence/forensics/route.ts +23 -0
  23. package/src/app/api/intelligence/neural-router/route.ts +23 -0
  24. package/src/app/api/keys/route.ts +34 -0
  25. package/src/app/api/mcp/route.ts +49 -0
  26. package/src/app/api/memory/route.ts +10 -0
  27. package/src/app/api/models/benchmark/route.ts +13 -0
  28. package/src/app/api/models/route.ts +39 -0
  29. package/src/app/api/namespace/route.ts +25 -0
  30. package/src/app/api/plugins/route.ts +41 -0
  31. package/src/app/api/providers/accounts/route.ts +91 -0
  32. package/src/app/api/providers/fetch-models/route.ts +52 -0
  33. package/src/app/api/providers/health/route.ts +10 -0
  34. package/src/app/api/providers/route.ts +46 -0
  35. package/src/app/api/routes/pipeline/route.ts +20 -0
  36. package/src/app/api/settings/route.ts +33 -0
  37. package/src/app/api/skills/route.ts +39 -0
  38. package/src/app/api/v1/chat/completions/route.ts +156 -0
  39. package/src/app/api/v1/models/route.ts +44 -0
  40. package/src/app/dashboard/intelligence/loading.tsx +14 -0
  41. package/src/app/dashboard/intelligence/page.tsx +125 -0
  42. package/src/app/dashboard/layout.tsx +143 -0
  43. package/src/app/dashboard/loading.tsx +17 -0
  44. package/src/app/dashboard/memory/loading.tsx +15 -0
  45. package/src/app/dashboard/memory/page.tsx +71 -0
  46. package/src/app/dashboard/models/loading.tsx +13 -0
  47. package/src/app/dashboard/models/page.tsx +107 -0
  48. package/src/app/dashboard/page.tsx +183 -0
  49. package/src/app/dashboard/playground/loading.tsx +17 -0
  50. package/src/app/dashboard/playground/page.tsx +212 -0
  51. package/src/app/dashboard/providers/loading.tsx +15 -0
  52. package/src/app/dashboard/providers/page.tsx +248 -0
  53. package/src/app/dashboard/routes/loading.tsx +15 -0
  54. package/src/app/dashboard/routes/page.tsx +72 -0
  55. package/src/app/dashboard/settings/loading.tsx +20 -0
  56. package/src/app/dashboard/settings/page.tsx +208 -0
  57. package/src/app/dashboard/skills/loading.tsx +26 -0
  58. package/src/app/dashboard/skills/page.tsx +137 -0
  59. package/src/app/dashboard/vault/loading.tsx +18 -0
  60. package/src/app/dashboard/vault/page.tsx +139 -0
  61. package/src/app/favicon.ico +0 -0
  62. package/src/app/globals.css +59 -0
  63. package/src/app/layout.tsx +32 -0
  64. package/src/app/login/page.tsx +87 -0
  65. package/src/app/page.tsx +5 -0
  66. package/src/components/ui/badge.tsx +32 -0
  67. package/src/components/ui/button.tsx +38 -0
  68. package/src/components/ui/card.tsx +50 -0
  69. package/src/components/ui/error-boundary.tsx +47 -0
  70. package/src/components/ui/index.ts +11 -0
  71. package/src/components/ui/input.tsx +26 -0
  72. package/src/components/ui/select.tsx +24 -0
  73. package/src/components/ui/skeleton.tsx +53 -0
  74. package/src/components/ui/toast.tsx +51 -0
  75. package/src/instrumentation.ts +6 -0
  76. package/src/lib/__tests__/auth.test.ts +42 -0
  77. package/src/lib/__tests__/format.test.ts +94 -0
  78. package/src/lib/__tests__/namespace.test.ts +102 -0
  79. package/src/lib/__tests__/squeezer.test.ts +93 -0
  80. package/src/lib/__tests__/utils.test.ts +28 -0
  81. package/src/lib/analytics/index.ts +187 -0
  82. package/src/lib/auth/guard.tsx +71 -0
  83. package/src/lib/auth/index.ts +105 -0
  84. package/src/lib/auth/middleware.ts +64 -0
  85. package/src/lib/benchmark/index.ts +137 -0
  86. package/src/lib/bootstrap.ts +122 -0
  87. package/src/lib/cache/index.ts +1 -0
  88. package/src/lib/cache/semantic.ts +211 -0
  89. package/src/lib/config/defaults.ts +61 -0
  90. package/src/lib/config/index.ts +72 -0
  91. package/src/lib/config/schema.ts +63 -0
  92. package/src/lib/db/index.ts +22 -0
  93. package/src/lib/db/migrate.ts +327 -0
  94. package/src/lib/db/schema.ts +303 -0
  95. package/src/lib/distiller/index.ts +331 -0
  96. package/src/lib/fallback/index.ts +153 -0
  97. package/src/lib/forensics/index.ts +188 -0
  98. package/src/lib/format/anthropic.ts +139 -0
  99. package/src/lib/format/gemini.ts +130 -0
  100. package/src/lib/format/index.ts +3 -0
  101. package/src/lib/format/openai.ts +78 -0
  102. package/src/lib/health/index.ts +158 -0
  103. package/src/lib/mcp/builtin.ts +83 -0
  104. package/src/lib/mcp/index.ts +1 -0
  105. package/src/lib/mcp/registry.ts +49 -0
  106. package/src/lib/memory/index.ts +3 -0
  107. package/src/lib/memory/store.ts +215 -0
  108. package/src/lib/memory/types.ts +56 -0
  109. package/src/lib/namespace/index.ts +89 -0
  110. package/src/lib/neural/features.ts +74 -0
  111. package/src/lib/neural/index.ts +85 -0
  112. package/src/lib/neural/strategies.ts +124 -0
  113. package/src/lib/pipeline/index.ts +84 -0
  114. package/src/lib/pipeline/types.ts +77 -0
  115. package/src/lib/plugins/builtin.ts +79 -0
  116. package/src/lib/plugins/index.ts +65 -0
  117. package/src/lib/prediction/index.ts +113 -0
  118. package/src/lib/providers/api-key/anthropic.ts +96 -0
  119. package/src/lib/providers/api-key/deepseek.ts +108 -0
  120. package/src/lib/providers/api-key/gemini.ts +112 -0
  121. package/src/lib/providers/api-key/openai.ts +122 -0
  122. package/src/lib/providers/api-key/openrouter.ts +112 -0
  123. package/src/lib/providers/base-adapter.ts +122 -0
  124. package/src/lib/providers/registry.ts +46 -0
  125. package/src/lib/providers/types.ts +121 -0
  126. package/src/lib/router/index.ts +82 -0
  127. package/src/lib/skills/forge.ts +57 -0
  128. package/src/lib/skills/index.ts +3 -0
  129. package/src/lib/skills/registry.ts +195 -0
  130. package/src/lib/skills/types.ts +44 -0
  131. package/src/lib/squeezer/index.ts +158 -0
  132. package/src/lib/utils/cn.ts +6 -0
  133. package/src/lib/utils/logger.ts +16 -0
  134. package/src/middleware.ts +60 -0
  135. package/tsconfig.json +34 -0
@@ -0,0 +1,327 @@
1
+ import { db } from './index'
2
+ import { sql } from 'drizzle-orm'
3
+ import { logger } from '../utils/logger'
4
+
5
+ const CREATE_TABLES = [
6
+ `CREATE TABLE IF NOT EXISTS providers (
7
+ id TEXT PRIMARY KEY,
8
+ name TEXT NOT NULL,
9
+ prefix TEXT NOT NULL UNIQUE,
10
+ type TEXT NOT NULL CHECK(type IN ('oauth','api_key','none','service_account')),
11
+ config TEXT NOT NULL DEFAULT '{}',
12
+ enabled INTEGER NOT NULL DEFAULT 1,
13
+ priority INTEGER NOT NULL DEFAULT 0,
14
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
15
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
16
+ )`,
17
+
18
+ `CREATE TABLE IF NOT EXISTS provider_accounts (
19
+ id TEXT PRIMARY KEY,
20
+ provider_id TEXT NOT NULL REFERENCES providers(id),
21
+ label TEXT,
22
+ auth_data TEXT NOT NULL DEFAULT '{}',
23
+ enabled INTEGER NOT NULL DEFAULT 1,
24
+ priority INTEGER NOT NULL DEFAULT 0,
25
+ quota_used_tokens INTEGER NOT NULL DEFAULT 0,
26
+ quota_limit_tokens INTEGER,
27
+ quota_reset_at TEXT,
28
+ last_used_at TEXT,
29
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
30
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
31
+ )`,
32
+
33
+ `CREATE TABLE IF NOT EXISTS models (
34
+ id TEXT PRIMARY KEY,
35
+ provider_id TEXT NOT NULL REFERENCES providers(id),
36
+ name TEXT NOT NULL,
37
+ display_name TEXT,
38
+ pricing_tier TEXT CHECK(pricing_tier IN ('free','cheap','subscription','pay_per_use')),
39
+ cost_per_1m_input REAL,
40
+ cost_per_1m_output REAL,
41
+ context_window INTEGER,
42
+ capabilities TEXT DEFAULT '[]',
43
+ available INTEGER NOT NULL DEFAULT 1,
44
+ last_checked_at TEXT,
45
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
46
+ )`,
47
+
48
+ `CREATE TABLE IF NOT EXISTS combos (
49
+ id TEXT PRIMARY KEY,
50
+ name TEXT NOT NULL UNIQUE,
51
+ description TEXT,
52
+ models TEXT NOT NULL DEFAULT '[]',
53
+ routing_strategy TEXT NOT NULL DEFAULT 'priority',
54
+ fallback_enabled INTEGER NOT NULL DEFAULT 1,
55
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
56
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
57
+ )`,
58
+
59
+ `CREATE TABLE IF NOT EXISTS request_logs (
60
+ id TEXT PRIMARY KEY,
61
+ request_id TEXT NOT NULL,
62
+ model TEXT NOT NULL,
63
+ provider_id TEXT,
64
+ account_id TEXT,
65
+ combo_id TEXT,
66
+ input_tokens INTEGER,
67
+ output_tokens INTEGER,
68
+ tokens_saved INTEGER DEFAULT 0,
69
+ cost REAL DEFAULT 0,
70
+ latency_ms INTEGER,
71
+ status_code INTEGER,
72
+ error_message TEXT,
73
+ fallback_used INTEGER DEFAULT 0,
74
+ cached INTEGER DEFAULT 0,
75
+ skill_id TEXT,
76
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
77
+ )`,
78
+
79
+ `CREATE TABLE IF NOT EXISTS provider_health (
80
+ id TEXT PRIMARY KEY,
81
+ provider_id TEXT NOT NULL REFERENCES providers(id),
82
+ status TEXT NOT NULL DEFAULT 'healthy' CHECK(status IN ('healthy','degraded','down','disabled')),
83
+ avg_latency_ms INTEGER,
84
+ p95_latency_ms INTEGER,
85
+ error_rate REAL DEFAULT 0,
86
+ success_rate REAL DEFAULT 1,
87
+ consecutive_failures INTEGER DEFAULT 0,
88
+ last_success_at TEXT,
89
+ last_check_at TEXT,
90
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
91
+ )`,
92
+
93
+ `CREATE TABLE IF NOT EXISTS usage_daily (
94
+ id TEXT PRIMARY KEY,
95
+ date TEXT NOT NULL,
96
+ provider_id TEXT,
97
+ model TEXT,
98
+ total_requests INTEGER DEFAULT 0,
99
+ total_input_tokens INTEGER DEFAULT 0,
100
+ total_output_tokens INTEGER DEFAULT 0,
101
+ total_tokens_saved INTEGER DEFAULT 0,
102
+ total_cost REAL DEFAULT 0,
103
+ total_errors INTEGER DEFAULT 0,
104
+ total_fallbacks INTEGER DEFAULT 0,
105
+ total_cache_hits INTEGER DEFAULT 0
106
+ )`,
107
+
108
+ `CREATE TABLE IF NOT EXISTS settings (
109
+ key TEXT PRIMARY KEY,
110
+ value TEXT NOT NULL,
111
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
112
+ )`,
113
+
114
+ `CREATE TABLE IF NOT EXISTS api_keys (
115
+ id TEXT PRIMARY KEY,
116
+ name TEXT NOT NULL,
117
+ key_hash TEXT NOT NULL UNIQUE,
118
+ permissions TEXT DEFAULT '{}',
119
+ last_used_at TEXT,
120
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
121
+ )`,
122
+
123
+ `CREATE TABLE IF NOT EXISTS semantic_cache (
124
+ id TEXT PRIMARY KEY,
125
+ embedding BLOB NOT NULL,
126
+ prompt_hash TEXT NOT NULL,
127
+ prompt_text TEXT NOT NULL,
128
+ response_text TEXT NOT NULL,
129
+ model TEXT NOT NULL,
130
+ input_tokens INTEGER,
131
+ output_tokens INTEGER,
132
+ similarity_threshold REAL DEFAULT 0.95,
133
+ hits INTEGER DEFAULT 0,
134
+ quality_score REAL,
135
+ expires_at TEXT NOT NULL,
136
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
137
+ )`,
138
+
139
+ `CREATE TABLE IF NOT EXISTS router_training_data (
140
+ id TEXT PRIMARY KEY,
141
+ features TEXT NOT NULL DEFAULT '{}',
142
+ selected_provider TEXT NOT NULL,
143
+ selected_model TEXT NOT NULL,
144
+ outcome TEXT NOT NULL CHECK(outcome IN ('success','timeout','error','rate_limited')),
145
+ latency_ms INTEGER,
146
+ cost REAL,
147
+ quality_score REAL,
148
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
149
+ )`,
150
+
151
+ `CREATE TABLE IF NOT EXISTS model_benchmarks (
152
+ id TEXT PRIMARY KEY,
153
+ model TEXT NOT NULL,
154
+ task_type TEXT NOT NULL,
155
+ latency_ms INTEGER,
156
+ tokens_used INTEGER,
157
+ quality_score REAL,
158
+ cost REAL,
159
+ provider_id TEXT,
160
+ is_shadow INTEGER DEFAULT 0,
161
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
162
+ )`,
163
+
164
+ `CREATE TABLE IF NOT EXISTS pipelines (
165
+ id TEXT PRIMARY KEY,
166
+ name TEXT NOT NULL UNIQUE,
167
+ description TEXT,
168
+ nodes TEXT NOT NULL DEFAULT '[]',
169
+ connections TEXT NOT NULL DEFAULT '[]',
170
+ is_default INTEGER DEFAULT 0,
171
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
172
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
173
+ )`,
174
+
175
+ `CREATE TABLE IF NOT EXISTS skills (
176
+ id TEXT PRIMARY KEY,
177
+ name TEXT NOT NULL UNIQUE,
178
+ description TEXT,
179
+ version TEXT NOT NULL DEFAULT '1.0.0',
180
+ author TEXT NOT NULL DEFAULT 'user',
181
+ system_prompt TEXT NOT NULL,
182
+ behavior TEXT NOT NULL DEFAULT '{}',
183
+ rotation_config TEXT NOT NULL DEFAULT '{}',
184
+ group_id TEXT,
185
+ tags TEXT NOT NULL DEFAULT '[]',
186
+ quality_score REAL DEFAULT 0,
187
+ usage_count INTEGER DEFAULT 0,
188
+ last_used_at TEXT,
189
+ enabled INTEGER NOT NULL DEFAULT 1,
190
+ source TEXT NOT NULL DEFAULT 'user',
191
+ source_url TEXT,
192
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
193
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
194
+ )`,
195
+
196
+ `CREATE TABLE IF NOT EXISTS skill_groups (
197
+ id TEXT PRIMARY KEY,
198
+ name TEXT NOT NULL UNIQUE,
199
+ description TEXT,
200
+ rotation_strategy TEXT NOT NULL DEFAULT 'round_robin',
201
+ task_types TEXT NOT NULL DEFAULT '[]',
202
+ active_skill_id TEXT,
203
+ rotation_index INTEGER DEFAULT 0,
204
+ enabled INTEGER NOT NULL DEFAULT 1,
205
+ last_rotated_at TEXT NOT NULL DEFAULT (datetime('now')),
206
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
207
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
208
+ )`,
209
+
210
+ `CREATE TABLE IF NOT EXISTS skill_quality (
211
+ id TEXT PRIMARY KEY,
212
+ skill_id TEXT NOT NULL REFERENCES skills(id),
213
+ task_type TEXT NOT NULL,
214
+ total_requests INTEGER DEFAULT 0,
215
+ avg_quality_score REAL DEFAULT 0,
216
+ avg_latency_ms REAL DEFAULT 0,
217
+ user_acceptance_rate REAL DEFAULT 0,
218
+ last_updated TEXT NOT NULL DEFAULT (datetime('now'))
219
+ )`,
220
+
221
+ `CREATE TABLE IF NOT EXISTS skill_rotation_log (
222
+ id TEXT PRIMARY KEY,
223
+ from_skill_id TEXT,
224
+ to_skill_id TEXT NOT NULL,
225
+ group_id TEXT,
226
+ trigger_type TEXT NOT NULL,
227
+ request_id TEXT,
228
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
229
+ )`,
230
+
231
+ `CREATE TABLE IF NOT EXISTS episodes (
232
+ id TEXT PRIMARY KEY,
233
+ timestamp TEXT NOT NULL,
234
+ event_type TEXT NOT NULL,
235
+ model TEXT,
236
+ provider TEXT,
237
+ task_type TEXT,
238
+ input_tokens INTEGER,
239
+ output_tokens INTEGER,
240
+ tokens_saved INTEGER DEFAULT 0,
241
+ latency_ms INTEGER,
242
+ cost REAL DEFAULT 0,
243
+ quality_score REAL,
244
+ outcome TEXT,
245
+ metadata TEXT DEFAULT '{}',
246
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
247
+ )`,
248
+
249
+ `CREATE TABLE IF NOT EXISTS knowledge (
250
+ id TEXT PRIMARY KEY,
251
+ category TEXT NOT NULL,
252
+ subject TEXT NOT NULL,
253
+ key TEXT NOT NULL,
254
+ value TEXT NOT NULL DEFAULT '{}',
255
+ confidence REAL DEFAULT 0,
256
+ sample_count INTEGER DEFAULT 0,
257
+ source TEXT NOT NULL DEFAULT 'distilled',
258
+ last_updated TEXT NOT NULL DEFAULT (datetime('now'))
259
+ )`,
260
+
261
+ `CREATE TABLE IF NOT EXISTS procedural_rules (
262
+ id TEXT PRIMARY KEY,
263
+ category TEXT NOT NULL,
264
+ condition TEXT NOT NULL,
265
+ action TEXT NOT NULL,
266
+ confidence REAL DEFAULT 0,
267
+ sample_count INTEGER DEFAULT 0,
268
+ status TEXT NOT NULL DEFAULT 'auto_generated',
269
+ priority INTEGER DEFAULT 0,
270
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
271
+ verified_at TEXT,
272
+ last_applied_at TEXT,
273
+ apply_count INTEGER DEFAULT 0,
274
+ success_count INTEGER DEFAULT 0
275
+ )`,
276
+
277
+ `CREATE TABLE IF NOT EXISTS distillation_log (
278
+ id TEXT PRIMARY KEY,
279
+ started_at TEXT NOT NULL,
280
+ completed_at TEXT,
281
+ episodes_processed INTEGER DEFAULT 0,
282
+ patterns_found INTEGER DEFAULT 0,
283
+ rules_generated INTEGER DEFAULT 0,
284
+ rules_updated INTEGER DEFAULT 0,
285
+ model_retrained INTEGER DEFAULT 0,
286
+ model_accuracy_before REAL,
287
+ model_accuracy_after REAL,
288
+ knowledge_entries_added INTEGER DEFAULT 0,
289
+ knowledge_entries_updated INTEGER DEFAULT 0,
290
+ status TEXT NOT NULL DEFAULT 'running',
291
+ error_message TEXT,
292
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
293
+ )`,
294
+ ]
295
+
296
+ const CREATE_INDEXES = [
297
+ `CREATE INDEX IF NOT EXISTS idx_episodes_timestamp ON episodes(timestamp)`,
298
+ `CREATE INDEX IF NOT EXISTS idx_episodes_model ON episodes(model)`,
299
+ `CREATE INDEX IF NOT EXISTS idx_episodes_provider ON episodes(provider)`,
300
+ `CREATE UNIQUE INDEX IF NOT EXISTS knowledge_unique ON knowledge(category, subject, key)`,
301
+ `CREATE INDEX IF NOT EXISTS knowledge_lookup ON knowledge(category, subject, key)`,
302
+ `CREATE INDEX IF NOT EXISTS idx_rules_category ON procedural_rules(category, status)`,
303
+ `CREATE UNIQUE INDEX IF NOT EXISTS usage_daily_unique ON usage_daily(date, provider_id, model)`,
304
+ `CREATE UNIQUE INDEX IF NOT EXISTS skill_quality_unique ON skill_quality(skill_id, task_type)`,
305
+ ]
306
+
307
+ export async function migrate() {
308
+ logger.info('Running database migration...')
309
+
310
+ for (const stmt of CREATE_TABLES) {
311
+ try {
312
+ db.run(sql.raw(stmt))
313
+ } catch (err) {
314
+ logger.warn({ error: (err as Error).message, table: stmt.match(/CREATE TABLE IF NOT EXISTS (\w+)/)?.[1] }, 'Migration warning')
315
+ }
316
+ }
317
+
318
+ for (const stmt of CREATE_INDEXES) {
319
+ try {
320
+ db.run(sql.raw(stmt))
321
+ } catch (err) {
322
+ logger.warn({ error: (err as Error).message }, 'Index creation warning')
323
+ }
324
+ }
325
+
326
+ logger.info({ tables: CREATE_TABLES.length, indexes: CREATE_INDEXES.length }, 'Migration complete')
327
+ }
@@ -0,0 +1,303 @@
1
+ import { sqliteTable, text, integer, real, blob, index, uniqueIndex } from 'drizzle-orm/sqlite-core'
2
+
3
+ export const providers = sqliteTable('providers', {
4
+ id: text('id').primaryKey(),
5
+ name: text('name').notNull(),
6
+ prefix: text('prefix').notNull().unique(),
7
+ type: text('type', { enum: ['oauth', 'api_key', 'none', 'service_account'] }).notNull(),
8
+ config: text('config').notNull().default('{}'),
9
+ enabled: integer('enabled', { mode: 'boolean' }).notNull().default(true),
10
+ priority: integer('priority').notNull().default(0),
11
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
12
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
13
+ })
14
+
15
+ export const providerAccounts = sqliteTable('provider_accounts', {
16
+ id: text('id').primaryKey(),
17
+ providerId: text('provider_id').notNull().references(() => providers.id),
18
+ label: text('label'),
19
+ authData: text('auth_data').notNull().default('{}'),
20
+ enabled: integer('enabled', { mode: 'boolean' }).notNull().default(true),
21
+ priority: integer('priority').notNull().default(0),
22
+ quotaUsedTokens: integer('quota_used_tokens').notNull().default(0),
23
+ quotaLimitTokens: integer('quota_limit_tokens'),
24
+ quotaResetAt: text('quota_reset_at'),
25
+ lastUsedAt: text('last_used_at'),
26
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
27
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
28
+ })
29
+
30
+ export const models = sqliteTable('models', {
31
+ id: text('id').primaryKey(),
32
+ providerId: text('provider_id').notNull().references(() => providers.id),
33
+ name: text('name').notNull(),
34
+ displayName: text('display_name'),
35
+ pricingTier: text('pricing_tier', { enum: ['free', 'cheap', 'subscription', 'pay_per_use'] }),
36
+ costPer1mInput: real('cost_per_1m_input'),
37
+ costPer1mOutput: real('cost_per_1m_output'),
38
+ contextWindow: integer('context_window'),
39
+ capabilities: text('capabilities').default('[]'),
40
+ available: integer('available', { mode: 'boolean' }).notNull().default(true),
41
+ lastCheckedAt: text('last_checked_at'),
42
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
43
+ })
44
+
45
+ export const combos = sqliteTable('combos', {
46
+ id: text('id').primaryKey(),
47
+ name: text('name').notNull().unique(),
48
+ description: text('description'),
49
+ models: text('models').notNull().default('[]'),
50
+ routingStrategy: text('routing_strategy').notNull().default('priority'),
51
+ fallbackEnabled: integer('fallback_enabled', { mode: 'boolean' }).notNull().default(true),
52
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
53
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
54
+ })
55
+
56
+ export const requestLogs = sqliteTable('request_logs', {
57
+ id: text('id').primaryKey(),
58
+ requestId: text('request_id').notNull(),
59
+ model: text('model').notNull(),
60
+ providerId: text('provider_id'),
61
+ accountId: text('account_id'),
62
+ comboId: text('combo_id'),
63
+ inputTokens: integer('input_tokens'),
64
+ outputTokens: integer('output_tokens'),
65
+ tokensSaved: integer('tokens_saved').default(0),
66
+ cost: real('cost').default(0),
67
+ latencyMs: integer('latency_ms'),
68
+ statusCode: integer('status_code'),
69
+ errorMessage: text('error_message'),
70
+ fallbackUsed: integer('fallback_used', { mode: 'boolean' }).default(false),
71
+ cached: integer('cached', { mode: 'boolean' }).default(false),
72
+ skillId: text('skill_id'),
73
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
74
+ })
75
+
76
+ export const providerHealth = sqliteTable('provider_health', {
77
+ id: text('id').primaryKey(),
78
+ providerId: text('provider_id').notNull().references(() => providers.id),
79
+ status: text('status', { enum: ['healthy', 'degraded', 'down', 'disabled'] }).notNull().default('healthy'),
80
+ avgLatencyMs: integer('avg_latency_ms'),
81
+ p95LatencyMs: integer('p95_latency_ms'),
82
+ errorRate: real('error_rate').default(0),
83
+ successRate: real('success_rate').default(1),
84
+ consecutiveFailures: integer('consecutive_failures').default(0),
85
+ lastSuccessAt: text('last_success_at'),
86
+ lastCheckAt: text('last_check_at'),
87
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
88
+ })
89
+
90
+ export const usageDaily = sqliteTable('usage_daily', {
91
+ id: text('id').primaryKey(),
92
+ date: text('date').notNull(),
93
+ providerId: text('provider_id'),
94
+ model: text('model'),
95
+ totalRequests: integer('total_requests').default(0),
96
+ totalInputTokens: integer('total_input_tokens').default(0),
97
+ totalOutputTokens: integer('total_output_tokens').default(0),
98
+ totalTokensSaved: integer('total_tokens_saved').default(0),
99
+ totalCost: real('total_cost').default(0),
100
+ totalErrors: integer('total_errors').default(0),
101
+ totalFallbacks: integer('total_fallbacks').default(0),
102
+ totalCacheHits: integer('total_cache_hits').default(0),
103
+ }, (t) => [
104
+ uniqueIndex('usage_daily_unique').on(t.date, t.providerId, t.model),
105
+ ])
106
+
107
+ export const settings = sqliteTable('settings', {
108
+ key: text('key').primaryKey(),
109
+ value: text('value').notNull(),
110
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
111
+ })
112
+
113
+ export const apiKeys = sqliteTable('api_keys', {
114
+ id: text('id').primaryKey(),
115
+ name: text('name').notNull(),
116
+ keyHash: text('key_hash').notNull().unique(),
117
+ permissions: text('permissions').default('{}'),
118
+ lastUsedAt: text('last_used_at'),
119
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
120
+ })
121
+
122
+ export const semanticCache = sqliteTable('semantic_cache', {
123
+ id: text('id').primaryKey(),
124
+ embedding: blob('embedding').notNull(),
125
+ promptHash: text('prompt_hash').notNull(),
126
+ promptText: text('prompt_text').notNull(),
127
+ responseText: text('response_text').notNull(),
128
+ model: text('model').notNull(),
129
+ inputTokens: integer('input_tokens'),
130
+ outputTokens: integer('output_tokens'),
131
+ similarityThreshold: real('similarity_threshold').default(0.95),
132
+ hits: integer('hits').default(0),
133
+ qualityScore: real('quality_score'),
134
+ expiresAt: text('expires_at').notNull(),
135
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
136
+ })
137
+
138
+ export const routerTrainingData = sqliteTable('router_training_data', {
139
+ id: text('id').primaryKey(),
140
+ features: text('features').notNull().default('{}'),
141
+ selectedProvider: text('selected_provider').notNull(),
142
+ selectedModel: text('selected_model').notNull(),
143
+ outcome: text('outcome', { enum: ['success', 'timeout', 'error', 'rate_limited'] }).notNull(),
144
+ latencyMs: integer('latency_ms'),
145
+ cost: real('cost'),
146
+ qualityScore: real('quality_score'),
147
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
148
+ })
149
+
150
+ export const modelBenchmarks = sqliteTable('model_benchmarks', {
151
+ id: text('id').primaryKey(),
152
+ model: text('model').notNull(),
153
+ taskType: text('task_type').notNull(),
154
+ latencyMs: integer('latency_ms'),
155
+ tokensUsed: integer('tokens_used'),
156
+ qualityScore: real('quality_score'),
157
+ cost: real('cost'),
158
+ providerId: text('provider_id'),
159
+ isShadow: integer('is_shadow', { mode: 'boolean' }).default(false),
160
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
161
+ })
162
+
163
+ export const pipelines = sqliteTable('pipelines', {
164
+ id: text('id').primaryKey(),
165
+ name: text('name').notNull().unique(),
166
+ description: text('description'),
167
+ nodes: text('nodes').notNull().default('[]'),
168
+ connections: text('connections').notNull().default('[]'),
169
+ isDefault: integer('is_default', { mode: 'boolean' }).default(false),
170
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
171
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
172
+ })
173
+
174
+ export const skills = sqliteTable('skills', {
175
+ id: text('id').primaryKey(),
176
+ name: text('name').notNull().unique(),
177
+ description: text('description'),
178
+ version: text('version').notNull().default('1.0.0'),
179
+ author: text('author').notNull().default('user'),
180
+ systemPrompt: text('system_prompt').notNull(),
181
+ behavior: text('behavior').notNull().default('{}'),
182
+ rotationConfig: text('rotation_config').notNull().default('{}'),
183
+ groupId: text('group_id'),
184
+ tags: text('tags').notNull().default('[]'),
185
+ qualityScore: real('quality_score').default(0),
186
+ usageCount: integer('usage_count').default(0),
187
+ lastUsedAt: text('last_used_at'),
188
+ enabled: integer('enabled', { mode: 'boolean' }).notNull().default(true),
189
+ source: text('source').notNull().default('user'),
190
+ sourceUrl: text('source_url'),
191
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
192
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
193
+ })
194
+
195
+ export const skillGroups = sqliteTable('skill_groups', {
196
+ id: text('id').primaryKey(),
197
+ name: text('name').notNull().unique(),
198
+ description: text('description'),
199
+ rotationStrategy: text('rotation_strategy').notNull().default('round_robin'),
200
+ taskTypes: text('task_types').notNull().default('[]'),
201
+ activeSkillId: text('active_skill_id'),
202
+ rotationIndex: integer('rotation_index').default(0),
203
+ enabled: integer('enabled', { mode: 'boolean' }).notNull().default(true),
204
+ lastRotatedAt: text('last_rotated_at').notNull().$defaultFn(() => new Date().toISOString()),
205
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
206
+ updatedAt: text('updated_at').notNull().$defaultFn(() => new Date().toISOString()),
207
+ })
208
+
209
+ export const skillQuality = sqliteTable('skill_quality', {
210
+ id: text('id').primaryKey(),
211
+ skillId: text('skill_id').notNull().references(() => skills.id),
212
+ taskType: text('task_type').notNull(),
213
+ totalRequests: integer('total_requests').default(0),
214
+ avgQualityScore: real('avg_quality_score').default(0),
215
+ avgLatencyMs: real('avg_latency_ms').default(0),
216
+ userAcceptanceRate: real('user_acceptance_rate').default(0),
217
+ lastUpdated: text('last_updated').notNull().$defaultFn(() => new Date().toISOString()),
218
+ }, (t) => [
219
+ uniqueIndex('skill_quality_unique').on(t.skillId, t.taskType),
220
+ ])
221
+
222
+ export const skillRotationLog = sqliteTable('skill_rotation_log', {
223
+ id: text('id').primaryKey(),
224
+ fromSkillId: text('from_skill_id'),
225
+ toSkillId: text('to_skill_id').notNull(),
226
+ groupId: text('group_id'),
227
+ triggerType: text('trigger_type').notNull(),
228
+ requestId: text('request_id'),
229
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
230
+ })
231
+
232
+ export const episodes = sqliteTable('episodes', {
233
+ id: text('id').primaryKey(),
234
+ timestamp: text('timestamp').notNull(),
235
+ eventType: text('event_type').notNull(),
236
+ model: text('model'),
237
+ provider: text('provider'),
238
+ taskType: text('task_type'),
239
+ inputTokens: integer('input_tokens'),
240
+ outputTokens: integer('output_tokens'),
241
+ tokensSaved: integer('tokens_saved').default(0),
242
+ latencyMs: integer('latency_ms'),
243
+ cost: real('cost').default(0),
244
+ qualityScore: real('quality_score'),
245
+ outcome: text('outcome'),
246
+ metadata: text('metadata').default('{}'),
247
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
248
+ }, (t) => [
249
+ index('idx_episodes_timestamp').on(t.timestamp),
250
+ index('idx_episodes_model').on(t.model),
251
+ index('idx_episodes_provider').on(t.provider),
252
+ ])
253
+
254
+ export const knowledge = sqliteTable('knowledge', {
255
+ id: text('id').primaryKey(),
256
+ category: text('category').notNull(),
257
+ subject: text('subject').notNull(),
258
+ key: text('key').notNull(),
259
+ value: text('value').notNull().default('{}'),
260
+ confidence: real('confidence').default(0),
261
+ sampleCount: integer('sample_count').default(0),
262
+ source: text('source').notNull().default('distilled'),
263
+ lastUpdated: text('last_updated').notNull().$defaultFn(() => new Date().toISOString()),
264
+ }, (t) => [
265
+ uniqueIndex('knowledge_unique').on(t.category, t.subject, t.key),
266
+ index('knowledge_lookup').on(t.category, t.subject, t.key),
267
+ ])
268
+
269
+ export const proceduralRules = sqliteTable('procedural_rules', {
270
+ id: text('id').primaryKey(),
271
+ category: text('category').notNull(),
272
+ condition: text('condition').notNull(),
273
+ action: text('action').notNull(),
274
+ confidence: real('confidence').default(0),
275
+ sampleCount: integer('sample_count').default(0),
276
+ status: text('status').notNull().default('auto_generated'),
277
+ priority: integer('priority').default(0),
278
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
279
+ verifiedAt: text('verified_at'),
280
+ lastAppliedAt: text('last_applied_at'),
281
+ applyCount: integer('apply_count').default(0),
282
+ successCount: integer('success_count').default(0),
283
+ }, (t) => [
284
+ index('idx_rules_category').on(t.category, t.status),
285
+ ])
286
+
287
+ export const distillationLog = sqliteTable('distillation_log', {
288
+ id: text('id').primaryKey(),
289
+ startedAt: text('started_at').notNull(),
290
+ completedAt: text('completed_at'),
291
+ episodesProcessed: integer('episodes_processed').default(0),
292
+ patternsFound: integer('patterns_found').default(0),
293
+ rulesGenerated: integer('rules_generated').default(0),
294
+ rulesUpdated: integer('rules_updated').default(0),
295
+ modelRetrained: integer('model_retrained', { mode: 'boolean' }).default(false),
296
+ modelAccuracyBefore: real('model_accuracy_before'),
297
+ modelAccuracyAfter: real('model_accuracy_after'),
298
+ knowledgeEntriesAdded: integer('knowledge_entries_added').default(0),
299
+ knowledgeEntriesUpdated: integer('knowledge_entries_updated').default(0),
300
+ status: text('status').notNull().default('running'),
301
+ errorMessage: text('error_message'),
302
+ createdAt: text('created_at').notNull().$defaultFn(() => new Date().toISOString()),
303
+ })