smartcontext-proxy 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 (166) hide show
  1. package/PLAN.md +406 -0
  2. package/PROGRESS.md +60 -0
  3. package/README.md +99 -0
  4. package/SPEC.md +915 -0
  5. package/adapters/openclaw/embedding.d.ts +8 -0
  6. package/adapters/openclaw/embedding.js +16 -0
  7. package/adapters/openclaw/embedding.ts +15 -0
  8. package/adapters/openclaw/index.d.ts +18 -0
  9. package/adapters/openclaw/index.js +42 -0
  10. package/adapters/openclaw/index.ts +43 -0
  11. package/adapters/openclaw/session-importer.d.ts +22 -0
  12. package/adapters/openclaw/session-importer.js +99 -0
  13. package/adapters/openclaw/session-importer.ts +105 -0
  14. package/adapters/openclaw/storage.d.ts +26 -0
  15. package/adapters/openclaw/storage.js +177 -0
  16. package/adapters/openclaw/storage.ts +183 -0
  17. package/dist/adapters/openclaw/embedding.d.ts +8 -0
  18. package/dist/adapters/openclaw/embedding.js +16 -0
  19. package/dist/adapters/openclaw/index.d.ts +18 -0
  20. package/dist/adapters/openclaw/index.js +42 -0
  21. package/dist/adapters/openclaw/session-importer.d.ts +22 -0
  22. package/dist/adapters/openclaw/session-importer.js +99 -0
  23. package/dist/adapters/openclaw/storage.d.ts +26 -0
  24. package/dist/adapters/openclaw/storage.js +177 -0
  25. package/dist/config/auto-detect.d.ts +3 -0
  26. package/dist/config/auto-detect.js +48 -0
  27. package/dist/config/defaults.d.ts +2 -0
  28. package/dist/config/defaults.js +28 -0
  29. package/dist/config/schema.d.ts +30 -0
  30. package/dist/config/schema.js +3 -0
  31. package/dist/context/budget.d.ts +25 -0
  32. package/dist/context/budget.js +85 -0
  33. package/dist/context/canonical.d.ts +39 -0
  34. package/dist/context/canonical.js +12 -0
  35. package/dist/context/chunker.d.ts +9 -0
  36. package/dist/context/chunker.js +148 -0
  37. package/dist/context/optimizer.d.ts +31 -0
  38. package/dist/context/optimizer.js +163 -0
  39. package/dist/context/retriever.d.ts +29 -0
  40. package/dist/context/retriever.js +103 -0
  41. package/dist/daemon/process.d.ts +6 -0
  42. package/dist/daemon/process.js +76 -0
  43. package/dist/daemon/service.d.ts +2 -0
  44. package/dist/daemon/service.js +99 -0
  45. package/dist/embedding/ollama.d.ts +11 -0
  46. package/dist/embedding/ollama.js +72 -0
  47. package/dist/embedding/types.d.ts +6 -0
  48. package/dist/embedding/types.js +3 -0
  49. package/dist/index.d.ts +2 -0
  50. package/dist/index.js +190 -0
  51. package/dist/metrics/collector.d.ts +43 -0
  52. package/dist/metrics/collector.js +72 -0
  53. package/dist/providers/anthropic.d.ts +15 -0
  54. package/dist/providers/anthropic.js +109 -0
  55. package/dist/providers/google.d.ts +13 -0
  56. package/dist/providers/google.js +40 -0
  57. package/dist/providers/ollama.d.ts +13 -0
  58. package/dist/providers/ollama.js +82 -0
  59. package/dist/providers/openai.d.ts +15 -0
  60. package/dist/providers/openai.js +115 -0
  61. package/dist/providers/types.d.ts +18 -0
  62. package/dist/providers/types.js +3 -0
  63. package/dist/proxy/router.d.ts +12 -0
  64. package/dist/proxy/router.js +46 -0
  65. package/dist/proxy/server.d.ts +25 -0
  66. package/dist/proxy/server.js +265 -0
  67. package/dist/proxy/stream.d.ts +8 -0
  68. package/dist/proxy/stream.js +32 -0
  69. package/dist/src/config/auto-detect.d.ts +3 -0
  70. package/dist/src/config/auto-detect.js +48 -0
  71. package/dist/src/config/defaults.d.ts +2 -0
  72. package/dist/src/config/defaults.js +28 -0
  73. package/dist/src/config/schema.d.ts +30 -0
  74. package/dist/src/config/schema.js +3 -0
  75. package/dist/src/context/budget.d.ts +25 -0
  76. package/dist/src/context/budget.js +85 -0
  77. package/dist/src/context/canonical.d.ts +39 -0
  78. package/dist/src/context/canonical.js +12 -0
  79. package/dist/src/context/chunker.d.ts +9 -0
  80. package/dist/src/context/chunker.js +148 -0
  81. package/dist/src/context/optimizer.d.ts +31 -0
  82. package/dist/src/context/optimizer.js +163 -0
  83. package/dist/src/context/retriever.d.ts +29 -0
  84. package/dist/src/context/retriever.js +103 -0
  85. package/dist/src/daemon/process.d.ts +6 -0
  86. package/dist/src/daemon/process.js +76 -0
  87. package/dist/src/daemon/service.d.ts +2 -0
  88. package/dist/src/daemon/service.js +99 -0
  89. package/dist/src/embedding/ollama.d.ts +11 -0
  90. package/dist/src/embedding/ollama.js +72 -0
  91. package/dist/src/embedding/types.d.ts +6 -0
  92. package/dist/src/embedding/types.js +3 -0
  93. package/dist/src/index.d.ts +2 -0
  94. package/dist/src/index.js +190 -0
  95. package/dist/src/metrics/collector.d.ts +43 -0
  96. package/dist/src/metrics/collector.js +72 -0
  97. package/dist/src/providers/anthropic.d.ts +15 -0
  98. package/dist/src/providers/anthropic.js +109 -0
  99. package/dist/src/providers/google.d.ts +13 -0
  100. package/dist/src/providers/google.js +40 -0
  101. package/dist/src/providers/ollama.d.ts +13 -0
  102. package/dist/src/providers/ollama.js +82 -0
  103. package/dist/src/providers/openai.d.ts +15 -0
  104. package/dist/src/providers/openai.js +115 -0
  105. package/dist/src/providers/types.d.ts +18 -0
  106. package/dist/src/providers/types.js +3 -0
  107. package/dist/src/proxy/router.d.ts +12 -0
  108. package/dist/src/proxy/router.js +46 -0
  109. package/dist/src/proxy/server.d.ts +25 -0
  110. package/dist/src/proxy/server.js +265 -0
  111. package/dist/src/proxy/stream.d.ts +8 -0
  112. package/dist/src/proxy/stream.js +32 -0
  113. package/dist/src/storage/lancedb.d.ts +21 -0
  114. package/dist/src/storage/lancedb.js +158 -0
  115. package/dist/src/storage/types.d.ts +52 -0
  116. package/dist/src/storage/types.js +3 -0
  117. package/dist/src/test/context.test.d.ts +1 -0
  118. package/dist/src/test/context.test.js +141 -0
  119. package/dist/src/test/dashboard.test.d.ts +1 -0
  120. package/dist/src/test/dashboard.test.js +85 -0
  121. package/dist/src/test/proxy.test.d.ts +1 -0
  122. package/dist/src/test/proxy.test.js +188 -0
  123. package/dist/src/ui/dashboard.d.ts +2 -0
  124. package/dist/src/ui/dashboard.js +183 -0
  125. package/dist/storage/lancedb.d.ts +21 -0
  126. package/dist/storage/lancedb.js +158 -0
  127. package/dist/storage/types.d.ts +52 -0
  128. package/dist/storage/types.js +3 -0
  129. package/dist/test/context.test.d.ts +1 -0
  130. package/dist/test/context.test.js +141 -0
  131. package/dist/test/dashboard.test.d.ts +1 -0
  132. package/dist/test/dashboard.test.js +85 -0
  133. package/dist/test/proxy.test.d.ts +1 -0
  134. package/dist/test/proxy.test.js +188 -0
  135. package/dist/ui/dashboard.d.ts +2 -0
  136. package/dist/ui/dashboard.js +183 -0
  137. package/package.json +38 -0
  138. package/src/config/auto-detect.ts +51 -0
  139. package/src/config/defaults.ts +26 -0
  140. package/src/config/schema.ts +33 -0
  141. package/src/context/budget.ts +126 -0
  142. package/src/context/canonical.ts +50 -0
  143. package/src/context/chunker.ts +165 -0
  144. package/src/context/optimizer.ts +201 -0
  145. package/src/context/retriever.ts +123 -0
  146. package/src/daemon/process.ts +70 -0
  147. package/src/daemon/service.ts +103 -0
  148. package/src/embedding/ollama.ts +68 -0
  149. package/src/embedding/types.ts +6 -0
  150. package/src/index.ts +176 -0
  151. package/src/metrics/collector.ts +114 -0
  152. package/src/providers/anthropic.ts +117 -0
  153. package/src/providers/google.ts +42 -0
  154. package/src/providers/ollama.ts +87 -0
  155. package/src/providers/openai.ts +127 -0
  156. package/src/providers/types.ts +20 -0
  157. package/src/proxy/router.ts +48 -0
  158. package/src/proxy/server.ts +315 -0
  159. package/src/proxy/stream.ts +39 -0
  160. package/src/storage/lancedb.ts +169 -0
  161. package/src/storage/types.ts +47 -0
  162. package/src/test/context.test.ts +165 -0
  163. package/src/test/dashboard.test.ts +94 -0
  164. package/src/test/proxy.test.ts +218 -0
  165. package/src/ui/dashboard.ts +184 -0
  166. package/tsconfig.json +18 -0
@@ -0,0 +1,184 @@
1
+ import type { MetricsCollector } from '../metrics/collector.js';
2
+ import type { StorageAdapter } from '../storage/types.js';
3
+
4
+ export function renderDashboard(metrics: MetricsCollector, paused: boolean): string {
5
+ const stats = metrics.getStats();
6
+ const recent = metrics.getRecent(20);
7
+ const uptime = metrics.getUptime();
8
+ const uptimeStr = formatDuration(uptime);
9
+
10
+ const statusBadge = paused
11
+ ? '<span class="badge paused">PAUSED</span>'
12
+ : '<span class="badge running">RUNNING</span>';
13
+
14
+ const savingsAmount = estimateCostSaved(stats.totalOriginalTokens - stats.totalOptimizedTokens);
15
+
16
+ return `<!DOCTYPE html>
17
+ <html lang="en">
18
+ <head>
19
+ <meta charset="utf-8">
20
+ <meta name="viewport" content="width=device-width, initial-scale=1">
21
+ <title>SmartContext Proxy</title>
22
+ <style>
23
+ * { margin: 0; padding: 0; box-sizing: border-box; }
24
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: #0f1117; color: #e1e4e8; }
25
+ .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
26
+ header { display: flex; justify-content: space-between; align-items: center; padding: 16px 0; border-bottom: 1px solid #21262d; margin-bottom: 24px; }
27
+ h1 { font-size: 20px; font-weight: 600; }
28
+ h2 { font-size: 16px; font-weight: 600; margin-bottom: 12px; color: #8b949e; }
29
+ .badge { padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 600; text-transform: uppercase; }
30
+ .badge.running { background: #238636; color: #fff; }
31
+ .badge.paused { background: #d29922; color: #000; }
32
+ .controls { display: flex; gap: 8px; }
33
+ .btn { padding: 6px 16px; border-radius: 6px; border: 1px solid #30363d; background: #21262d; color: #e1e4e8; cursor: pointer; font-size: 13px; }
34
+ .btn:hover { background: #30363d; }
35
+ .btn.primary { background: #238636; border-color: #238636; }
36
+ .btn.warn { background: #d29922; border-color: #d29922; color: #000; }
37
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 24px; }
38
+ .card { background: #161b22; border: 1px solid #21262d; border-radius: 8px; padding: 20px; }
39
+ .card .value { font-size: 32px; font-weight: 700; color: #58a6ff; }
40
+ .card .label { font-size: 13px; color: #8b949e; margin-top: 4px; }
41
+ .card.savings .value { color: #3fb950; }
42
+ table { width: 100%; border-collapse: collapse; }
43
+ th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid #21262d; font-size: 13px; }
44
+ th { color: #8b949e; font-weight: 600; }
45
+ .mono { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 12px; }
46
+ .savings-pct { color: #3fb950; font-weight: 600; }
47
+ .pass { color: #8b949e; }
48
+ .tab-bar { display: flex; gap: 0; border-bottom: 1px solid #21262d; margin-bottom: 16px; }
49
+ .tab { padding: 8px 16px; cursor: pointer; border-bottom: 2px solid transparent; color: #8b949e; font-size: 14px; }
50
+ .tab.active { color: #e1e4e8; border-bottom-color: #58a6ff; }
51
+ .tab-content { display: none; }
52
+ .tab-content.active { display: block; }
53
+ .refresh-note { font-size: 11px; color: #484f58; text-align: right; margin-top: 8px; }
54
+ </style>
55
+ </head>
56
+ <body>
57
+ <div class="container">
58
+ <header>
59
+ <h1>SmartContext Proxy ${statusBadge}</h1>
60
+ <div class="controls">
61
+ ${paused
62
+ ? '<button class="btn primary" onclick="api(\'/_sc/resume\')">Resume</button>'
63
+ : '<button class="btn warn" onclick="api(\'/_sc/pause\')">Pause</button>'}
64
+ </div>
65
+ </header>
66
+
67
+ <div class="grid">
68
+ <div class="card savings">
69
+ <div class="value">$${savingsAmount}</div>
70
+ <div class="label">Estimated Saved</div>
71
+ </div>
72
+ <div class="card">
73
+ <div class="value">${stats.totalRequests}</div>
74
+ <div class="label">Total Requests</div>
75
+ </div>
76
+ <div class="card">
77
+ <div class="value">${stats.totalSavingsPercent}%</div>
78
+ <div class="label">Avg Token Savings</div>
79
+ </div>
80
+ <div class="card">
81
+ <div class="value">${stats.avgLatencyOverheadMs}ms</div>
82
+ <div class="label">Avg Latency Overhead</div>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="tab-bar">
87
+ <div class="tab active" onclick="switchTab('feed')">Live Feed</div>
88
+ <div class="tab" onclick="switchTab('providers')">By Provider</div>
89
+ <div class="tab" onclick="switchTab('models')">By Model</div>
90
+ </div>
91
+
92
+ <div id="tab-feed" class="tab-content active">
93
+ <h2>Recent Requests</h2>
94
+ <table>
95
+ <thead><tr><th>ID</th><th>Time</th><th>Provider/Model</th><th>Original</th><th>Optimized</th><th>Savings</th><th>Chunks</th><th>Latency</th></tr></thead>
96
+ <tbody>
97
+ ${recent.reverse().map((r) => `
98
+ <tr>
99
+ <td class="mono">#${r.id}</td>
100
+ <td class="mono">${new Date(r.timestamp).toLocaleTimeString()}</td>
101
+ <td>${r.provider}/${r.model}</td>
102
+ <td class="mono">${formatTokens(r.originalTokens)}</td>
103
+ <td class="mono">${formatTokens(r.optimizedTokens)}</td>
104
+ <td class="${r.passThrough ? 'pass' : 'savings-pct'}">${r.passThrough ? 'pass' : `-${r.savingsPercent}%`}</td>
105
+ <td class="mono">${r.chunksRetrieved}</td>
106
+ <td class="mono">${r.latencyOverheadMs}ms</td>
107
+ </tr>
108
+ `).join('')}
109
+ </tbody>
110
+ </table>
111
+ </div>
112
+
113
+ <div id="tab-providers" class="tab-content">
114
+ <h2>Savings by Provider</h2>
115
+ <table>
116
+ <thead><tr><th>Provider</th><th>Requests</th><th>Tokens Saved</th><th>Savings %</th></tr></thead>
117
+ <tbody>
118
+ ${Object.entries(stats.byProvider).map(([name, s]) => `
119
+ <tr>
120
+ <td>${name}</td>
121
+ <td class="mono">${s.requests}</td>
122
+ <td class="mono">${formatTokens(s.tokensSaved)}</td>
123
+ <td class="savings-pct">${s.savingsPercent}%</td>
124
+ </tr>
125
+ `).join('')}
126
+ </tbody>
127
+ </table>
128
+ </div>
129
+
130
+ <div id="tab-models" class="tab-content">
131
+ <h2>Savings by Model</h2>
132
+ <table>
133
+ <thead><tr><th>Model</th><th>Requests</th><th>Tokens Saved</th><th>Savings %</th></tr></thead>
134
+ <tbody>
135
+ ${Object.entries(stats.byModel).map(([name, s]) => `
136
+ <tr>
137
+ <td>${name}</td>
138
+ <td class="mono">${s.requests}</td>
139
+ <td class="mono">${formatTokens(s.tokensSaved)}</td>
140
+ <td class="savings-pct">${s.savingsPercent}%</td>
141
+ </tr>
142
+ `).join('')}
143
+ </tbody>
144
+ </table>
145
+ </div>
146
+
147
+ <div class="refresh-note">Uptime: ${uptimeStr} | Auto-refresh: 10s</div>
148
+ </div>
149
+ <script>
150
+ function switchTab(name) {
151
+ document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
152
+ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
153
+ document.getElementById('tab-' + name).classList.add('active');
154
+ event.target.classList.add('active');
155
+ }
156
+ async function api(path) {
157
+ await fetch(path, { method: 'POST' });
158
+ location.reload();
159
+ }
160
+ setTimeout(() => location.reload(), 10000);
161
+ </script>
162
+ </body>
163
+ </html>`;
164
+ }
165
+
166
+ function formatTokens(n: number): string {
167
+ if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`;
168
+ if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;
169
+ return String(n);
170
+ }
171
+
172
+ function formatDuration(ms: number): string {
173
+ const s = Math.floor(ms / 1000);
174
+ if (s < 60) return `${s}s`;
175
+ if (s < 3600) return `${Math.floor(s / 60)}m ${s % 60}s`;
176
+ return `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m`;
177
+ }
178
+
179
+ /** Rough cost estimate based on Anthropic/OpenAI pricing */
180
+ function estimateCostSaved(tokensSaved: number): string {
181
+ // Assume avg $15/1M input tokens (Opus pricing)
182
+ const cost = (tokensSaved / 1000000) * 15;
183
+ return cost.toFixed(2);
184
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "dist",
7
+ "rootDir": ".",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "sourceMap": true,
14
+ "resolveJsonModule": true
15
+ },
16
+ "include": ["src/**/*", "adapters/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }