vibeoscore 1.0.2 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.js +1 -0
- package/client.ts +2 -0
- package/lib/logger.js +27 -0
- package/mcp-server.js +5 -4
- package/mcp-server.ts +4 -3
- package/package.json +12 -10
- package/dashboard/dist/assets/index-BnPt1Fii.js +0 -1
- package/dashboard/dist/assets/index-CfH00tOL.css +0 -1
- package/dashboard/dist/index.html +0 -3
- package/lib/blackbox-rf.js +0 -1099
- package/lib/blackbox.js +0 -137
- package/lib/compression.js +0 -119
- package/lib/db.js +0 -106
- package/lib/db.ts +0 -113
- package/lib/delegation.js +0 -137
- package/lib/meta-controller.js +0 -418
- package/lib/meta-controller.mjs +0 -499
- package/lib/patterns.js +0 -150
- package/lib/resolution-tracker.js +0 -486
- package/lib/stress.js +0 -84
- package/lib/tdd.js +0 -218
- package/lib/tier-routing.js +0 -48
- package/middleware/auth.js +0 -75
- package/middleware/auth.ts +0 -87
- package/middleware/usage-logging.js +0 -29
- package/middleware/usage-logging.ts +0 -41
- package/nginx-vibetheog-api.conf +0 -64
- package/routes/admin.js +0 -93
- package/routes/admin.ts +0 -107
- package/routes/blackbox.js +0 -463
- package/routes/compression.js +0 -12
- package/routes/delegation.js +0 -30
- package/routes/patterns.js +0 -53
- package/routes/pricing.js +0 -62
- package/routes/stress.js +0 -30
- package/routes/tdd.js +0 -68
- package/routes/tier-routing.js +0 -31
- package/scripts/dashboard-server.mjs +0 -246
- package/scripts/deploy-zero-downtime.sh +0 -77
- package/scripts/deploy.sh +0 -68
- package/scripts/release.mjs +0 -30
- package/scripts/seed-master-token.js +0 -29
- package/scripts/start-all.mjs +0 -34
- package/server.js +0 -88
- package/vibeos-api.service +0 -19
package/routes/admin.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { getDb } from "../lib/db.js"
|
|
2
|
-
import { randomBytes } from "node:crypto"
|
|
3
|
-
|
|
4
|
-
function generateToken() {
|
|
5
|
-
return "vos_" + randomBytes(32).toString("hex")
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export async function adminRoutes(fastify: any) {
|
|
9
|
-
fastify.post("/admin/seats", async (request: any, reply: any) => {
|
|
10
|
-
const { name, email } = request.body || {}
|
|
11
|
-
if (!name) {
|
|
12
|
-
return reply.code(400).send({ error: "name is required" })
|
|
13
|
-
}
|
|
14
|
-
const db = getDb()
|
|
15
|
-
const result = db.prepare("INSERT INTO seats (name, email) VALUES (?, ?)").run(name, email || null)
|
|
16
|
-
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(result.lastInsertRowid)
|
|
17
|
-
return { ok: true, seat }
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
fastify.get("/admin/seats", async (request: any, reply: any) => {
|
|
21
|
-
const db = getDb()
|
|
22
|
-
const seats = db.prepare("SELECT * FROM seats ORDER BY created_at DESC").all()
|
|
23
|
-
return { seats, count: seats.length }
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
fastify.patch("/admin/seats/:id", async (request: any, reply: any) => {
|
|
27
|
-
const { id } = request.params
|
|
28
|
-
const { status } = request.body || {}
|
|
29
|
-
if (!status || !["active", "suspended", "cancelled"].includes(status)) {
|
|
30
|
-
return reply.code(400).send({ error: "valid status is required (active, suspended, cancelled)" })
|
|
31
|
-
}
|
|
32
|
-
const db = getDb()
|
|
33
|
-
const result = db.prepare("UPDATE seats SET status = ?, updated_at = datetime('now') WHERE id = ?").run(status, id)
|
|
34
|
-
if (result.changes === 0) {
|
|
35
|
-
return reply.code(404).send({ error: "seat not found" })
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (status !== "active") {
|
|
39
|
-
db.prepare("UPDATE api_tokens SET status = 'revoked', revoked_at = datetime('now') WHERE seat_id = ? AND status = 'active'").run(id)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(id)
|
|
43
|
-
return { ok: true, seat }
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
fastify.post("/admin/tokens", async (request: any, reply: any) => {
|
|
47
|
-
const { seat_id, label, expires_at } = request.body || {}
|
|
48
|
-
if (!seat_id) {
|
|
49
|
-
return reply.code(400).send({ error: "seat_id is required" })
|
|
50
|
-
}
|
|
51
|
-
const db = getDb()
|
|
52
|
-
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(seat_id)
|
|
53
|
-
if (!seat) {
|
|
54
|
-
return reply.code(404).send({ error: "seat not found" })
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const token = generateToken()
|
|
58
|
-
const result = db.prepare(
|
|
59
|
-
"INSERT INTO api_tokens (token, seat_id, label, expires_at) VALUES (?, ?, ?, ?)"
|
|
60
|
-
).run(token, seat_id, label || null, expires_at || null)
|
|
61
|
-
|
|
62
|
-
const tokenRow = db.prepare("SELECT * FROM api_tokens WHERE id = ?").get(result.lastInsertRowid)
|
|
63
|
-
return { ok: true, token: tokenRow }
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
fastify.get("/admin/tokens", async (request: any, reply: any) => {
|
|
67
|
-
const db = getDb()
|
|
68
|
-
const tokens = db.prepare(`
|
|
69
|
-
SELECT t.*, s.name as seat_name, s.email as seat_email, s.status as seat_status
|
|
70
|
-
FROM api_tokens t
|
|
71
|
-
JOIN seats s ON t.seat_id = s.id
|
|
72
|
-
ORDER BY t.created_at DESC
|
|
73
|
-
`).all()
|
|
74
|
-
return { tokens, count: tokens.length }
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
fastify.patch("/admin/tokens/:id", async (request: any, reply: any) => {
|
|
78
|
-
const { id } = request.params
|
|
79
|
-
const { status } = request.body || {}
|
|
80
|
-
if (!status || !["active", "revoked", "expired"].includes(status)) {
|
|
81
|
-
return reply.code(400).send({ error: "valid status is required (active, revoked, expired)" })
|
|
82
|
-
}
|
|
83
|
-
const db = getDb()
|
|
84
|
-
const update = status === "revoked"
|
|
85
|
-
? "UPDATE api_tokens SET status = ?, revoked_at = datetime('now') WHERE id = ?"
|
|
86
|
-
: "UPDATE api_tokens SET status = ? WHERE id = ?"
|
|
87
|
-
const result = db.prepare(update).run(status, id)
|
|
88
|
-
if (result.changes === 0) {
|
|
89
|
-
return reply.code(404).send({ error: "token not found" })
|
|
90
|
-
}
|
|
91
|
-
const token = db.prepare("SELECT * FROM api_tokens WHERE id = ?").get(id)
|
|
92
|
-
return { ok: true, token }
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
fastify.get("/admin/usage", async (request: any, reply: any) => {
|
|
96
|
-
const { days: daysRaw } = request.query || {}
|
|
97
|
-
const days = Number(daysRaw)
|
|
98
|
-
if (daysRaw !== undefined && (isNaN(days) || !Number.isFinite(days) || !Number.isInteger(days) || days < 1 || days > 365)) {
|
|
99
|
-
return reply.code(400).send({ error: "days must be a positive integer between 1 and 365" })
|
|
100
|
-
}
|
|
101
|
-
const effectiveDays = days || 30
|
|
102
|
-
const db = getDb()
|
|
103
|
-
const sql = "SELECT t.token, t.label, s.name as seat_name, COUNT(*) as request_count, AVG(l.latency_ms) as avg_latency_ms, MIN(l.created_at) as first_used, MAX(l.created_at) as last_used FROM usage_log l JOIN api_tokens t ON l.token_id = t.id JOIN seats s ON t.seat_id = s.id WHERE l.created_at >= datetime('now', ?) GROUP BY t.id ORDER BY request_count DESC"
|
|
104
|
-
const usage = db.prepare(sql).all("-" + effectiveDays + " days")
|
|
105
|
-
return { usage, count: usage.length, days: effectiveDays }
|
|
106
|
-
})
|
|
107
|
-
}
|
package/routes/blackbox.js
DELETED
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, mkdirSync } from "node:fs"
|
|
2
|
-
import { dirname, resolve } from "node:path"
|
|
3
|
-
import { fileURLToPath } from "node:url"
|
|
4
|
-
import { ResolutionTracker, SUB_REGIMES, extractFeatures } from "../lib/blackbox.js"
|
|
5
|
-
import { computeControlVector } from "../lib/meta-controller.js"
|
|
6
|
-
import { getDb } from "../lib/db.js"
|
|
7
|
-
import {
|
|
8
|
-
getBlackboxRoutingModelMeta,
|
|
9
|
-
rebuildBlackboxRoutingModel,
|
|
10
|
-
selectBlackboxMode,
|
|
11
|
-
} from "../lib/blackbox-rf.js"
|
|
12
|
-
|
|
13
|
-
const trackers = new Map()
|
|
14
|
-
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
15
|
-
const TELEMETRY_PATH = process.env.VIBEOS_BLACKBOX_TELEMETRY_PATH || resolve(__dirname, "..", "data", "blackbox-telemetry.jsonl")
|
|
16
|
-
|
|
17
|
-
function readSessionStateRow(sessionId) {
|
|
18
|
-
try {
|
|
19
|
-
const db = getDb()
|
|
20
|
-
return db.prepare("SELECT state_json FROM blackbox_sessions WHERE session_id = ? ORDER BY updated_at DESC LIMIT 1").get(sessionId) || null
|
|
21
|
-
} catch (err) {
|
|
22
|
-
console.error(`[blackbox] readSessionStateRow failed for ${sessionId}: ${err.message}`)
|
|
23
|
-
return null
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function parseStateJson(row) {
|
|
28
|
-
if (!row?.state_json) return null
|
|
29
|
-
try {
|
|
30
|
-
return JSON.parse(row.state_json)
|
|
31
|
-
} catch (err) {
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function loadTrackerFromDb(sessionId) {
|
|
37
|
-
try {
|
|
38
|
-
const data = parseStateJson(readSessionStateRow(sessionId))
|
|
39
|
-
if (data) {
|
|
40
|
-
return ResolutionTracker.deserialize(data)
|
|
41
|
-
}
|
|
42
|
-
} catch (err) {
|
|
43
|
-
console.error(`[blackbox] loadTrackerFromDb failed for ${sessionId}: ${err.message}`)
|
|
44
|
-
}
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function appendTelemetryLog(record) {
|
|
49
|
-
try {
|
|
50
|
-
mkdirSync(dirname(TELEMETRY_PATH), { recursive: true })
|
|
51
|
-
appendFileSync(TELEMETRY_PATH, `${JSON.stringify(record)}\n`, "utf-8")
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.error(`[blackbox] appendTelemetryLog failed: ${err.message}`)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function saveTrackerToDb(sessionId, projectId, tracker, telemetry = null) {
|
|
58
|
-
try {
|
|
59
|
-
const db = getDb()
|
|
60
|
-
const existing = parseStateJson(readSessionStateRow(sessionId))
|
|
61
|
-
const serialized = tracker.serialize()
|
|
62
|
-
const mergedTelemetry = {
|
|
63
|
-
...(existing?.telemetry && typeof existing.telemetry === "object" ? existing.telemetry : {}),
|
|
64
|
-
...(telemetry && typeof telemetry === "object" ? telemetry : {}),
|
|
65
|
-
}
|
|
66
|
-
const payload = {
|
|
67
|
-
...(existing && typeof existing === "object" ? existing : {}),
|
|
68
|
-
...serialized,
|
|
69
|
-
}
|
|
70
|
-
if (Object.keys(mergedTelemetry).length > 0) {
|
|
71
|
-
payload.telemetry = mergedTelemetry
|
|
72
|
-
}
|
|
73
|
-
const stateJson = JSON.stringify(payload)
|
|
74
|
-
const outcome = tracker.getOutcomeHistory().slice(-1)[0]?.outcome || null
|
|
75
|
-
const now = new Date().toISOString()
|
|
76
|
-
db.prepare(`
|
|
77
|
-
INSERT INTO blackbox_sessions (session_id, project_id, state_json, outcome, created_at, updated_at)
|
|
78
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
79
|
-
ON CONFLICT(session_id) DO UPDATE SET
|
|
80
|
-
state_json = excluded.state_json,
|
|
81
|
-
project_id = COALESCE(excluded.project_id, blackbox_sessions.project_id),
|
|
82
|
-
outcome = COALESCE(excluded.outcome, blackbox_sessions.outcome),
|
|
83
|
-
updated_at = excluded.updated_at
|
|
84
|
-
`).run(sessionId, projectId || null, stateJson, outcome, now, now)
|
|
85
|
-
if (Object.keys(mergedTelemetry).length > 0) {
|
|
86
|
-
appendTelemetryLog({
|
|
87
|
-
session_id: sessionId,
|
|
88
|
-
project_id: projectId || null,
|
|
89
|
-
event: "session_save",
|
|
90
|
-
created_at: now,
|
|
91
|
-
telemetry: mergedTelemetry,
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
} catch (err) {
|
|
95
|
-
console.error(`[blackbox] saveTrackerToDb failed for ${sessionId}: ${err.message}`)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function getOrCreateTracker(sessionId, projectId) {
|
|
100
|
-
let tracker = trackers.get(sessionId)
|
|
101
|
-
if (!tracker) {
|
|
102
|
-
tracker = loadTrackerFromDb(sessionId) || new ResolutionTracker(sessionId, projectId)
|
|
103
|
-
trackers.set(sessionId, tracker)
|
|
104
|
-
}
|
|
105
|
-
if (projectId && !tracker.projectId) {
|
|
106
|
-
tracker.projectId = projectId
|
|
107
|
-
}
|
|
108
|
-
return tracker
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export async function blackboxRoutes(fastify) {
|
|
112
|
-
fastify.post("/api/v1/blackbox/analyze", async (request, reply) => {
|
|
113
|
-
const {
|
|
114
|
-
session_id,
|
|
115
|
-
project_id,
|
|
116
|
-
user_text,
|
|
117
|
-
prompt,
|
|
118
|
-
features,
|
|
119
|
-
action,
|
|
120
|
-
entropy,
|
|
121
|
-
uncertainty,
|
|
122
|
-
embedding,
|
|
123
|
-
latest_stress_multiplier,
|
|
124
|
-
stress_multiplier,
|
|
125
|
-
outcome,
|
|
126
|
-
} = request.body || {}
|
|
127
|
-
|
|
128
|
-
if (!user_text && !features && !action) {
|
|
129
|
-
return reply.code(400).send({ error: "user_text is required" })
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const sid = session_id || "default"
|
|
133
|
-
const tracker = getOrCreateTracker(sid, project_id)
|
|
134
|
-
|
|
135
|
-
const derivedFeatures = typeof features === "object" && !Array.isArray(features) && Object.keys(features || {}).length > 0
|
|
136
|
-
? features
|
|
137
|
-
: extractFeatures(user_text)
|
|
138
|
-
|
|
139
|
-
const state = tracker.update({
|
|
140
|
-
userText: user_text || "",
|
|
141
|
-
features: derivedFeatures,
|
|
142
|
-
actions: typeof action === "string" ? [action] : (Array.isArray(action) ? action : []),
|
|
143
|
-
entropy: entropy ?? 1.0,
|
|
144
|
-
uncertainty: uncertainty ?? 50,
|
|
145
|
-
embedding: embedding || null,
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
const selectionInput = {
|
|
149
|
-
session_id: sid,
|
|
150
|
-
project_id: project_id || tracker.projectId || null,
|
|
151
|
-
user_text: user_text || "",
|
|
152
|
-
prompt: prompt || "",
|
|
153
|
-
features: derivedFeatures,
|
|
154
|
-
state,
|
|
155
|
-
pivot_detected: state.pivot_detected,
|
|
156
|
-
pivot_score: state.pivot_score,
|
|
157
|
-
resolution: state.resolution,
|
|
158
|
-
continuity_state: state.continuity_state,
|
|
159
|
-
is_looping: state.is_looping,
|
|
160
|
-
loop_count: state.loop_consecutive,
|
|
161
|
-
loop_consecutive: state.loop_consecutive,
|
|
162
|
-
loop_intervention_level: state.loop_intervention_level,
|
|
163
|
-
outcome: outcome || state.outcome || null,
|
|
164
|
-
signals: state.signals,
|
|
165
|
-
stress_multiplier: latest_stress_multiplier ?? stress_multiplier ?? 0,
|
|
166
|
-
latest_stress_multiplier: latest_stress_multiplier ?? stress_multiplier ?? 0,
|
|
167
|
-
}
|
|
168
|
-
const selected = selectBlackboxMode(selectionInput)
|
|
169
|
-
const controlVector = computeControlVector({
|
|
170
|
-
...state,
|
|
171
|
-
user_text: user_text || "",
|
|
172
|
-
prompt: prompt || "",
|
|
173
|
-
features: derivedFeatures,
|
|
174
|
-
latest_stress_multiplier: latest_stress_multiplier ?? stress_multiplier ?? 0,
|
|
175
|
-
}, action, selected.mode)
|
|
176
|
-
const telemetry = {
|
|
177
|
-
observed_at: new Date().toISOString(),
|
|
178
|
-
input: {
|
|
179
|
-
user_text: user_text || "",
|
|
180
|
-
prompt: prompt || "",
|
|
181
|
-
action: typeof action === "string" ? action : Array.isArray(action) ? action[0] || null : null,
|
|
182
|
-
entropy: entropy ?? 1.0,
|
|
183
|
-
uncertainty: uncertainty ?? 50,
|
|
184
|
-
latest_stress_multiplier: latest_stress_multiplier ?? stress_multiplier ?? 0,
|
|
185
|
-
},
|
|
186
|
-
selection: {
|
|
187
|
-
optimization_mode: selected.mode,
|
|
188
|
-
source: selected.source,
|
|
189
|
-
confidence: selected.confidence,
|
|
190
|
-
probabilities: selected.probabilities || {},
|
|
191
|
-
},
|
|
192
|
-
context_packet: controlVector.context_packet,
|
|
193
|
-
control_vector: controlVector,
|
|
194
|
-
signals: {
|
|
195
|
-
sub_regime: state.sub_regime,
|
|
196
|
-
resolution: state.resolution,
|
|
197
|
-
continuity_state: state.continuity_state,
|
|
198
|
-
pivot_detected: state.pivot_detected,
|
|
199
|
-
pivot_score: state.pivot_score,
|
|
200
|
-
is_looping: state.is_looping,
|
|
201
|
-
loop_intervention_level: state.loop_intervention_level,
|
|
202
|
-
loop_consecutive: state.loop_consecutive,
|
|
203
|
-
action_consistency: state.signals?.action_consistency,
|
|
204
|
-
n_interactions: state.n_interactions,
|
|
205
|
-
outcome: outcome || state.outcome || null,
|
|
206
|
-
},
|
|
207
|
-
features: derivedFeatures,
|
|
208
|
-
feature_vector: selected.features || [],
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
tracker.annotateLastTurn(telemetry)
|
|
212
|
-
saveTrackerToDb(sid, project_id, tracker, telemetry)
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
...state,
|
|
216
|
-
session_id: sid,
|
|
217
|
-
project_id: project_id || tracker.projectId || null,
|
|
218
|
-
features: derivedFeatures,
|
|
219
|
-
optimization_mode: selected.mode,
|
|
220
|
-
optimization_source: selected.source,
|
|
221
|
-
optimization_confidence: selected.confidence,
|
|
222
|
-
context_packet: controlVector.context_packet,
|
|
223
|
-
control_vector: controlVector,
|
|
224
|
-
}
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
fastify.post("/api/v1/blackbox/state", async (request, reply) => {
|
|
228
|
-
const { session_id, project_id } = request.body || {}
|
|
229
|
-
const sid = session_id || "default"
|
|
230
|
-
const tracker = getOrCreateTracker(sid, project_id)
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
...tracker.getState(),
|
|
234
|
-
session_id: sid,
|
|
235
|
-
project_id: project_id || tracker.projectId || null,
|
|
236
|
-
}
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
fastify.post("/api/v1/blackbox/reset", async (request, reply) => {
|
|
240
|
-
const { session_id } = request.body || {}
|
|
241
|
-
const sid = session_id || "default"
|
|
242
|
-
trackers.delete(sid)
|
|
243
|
-
try {
|
|
244
|
-
getDb().prepare("DELETE FROM blackbox_sessions WHERE session_id = ?").run(sid)
|
|
245
|
-
} catch {}
|
|
246
|
-
return { ok: true, message: "tracker reset" }
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
fastify.get("/api/v1/blackbox/regimes", async (request, reply) => {
|
|
250
|
-
return { regimes: SUB_REGIMES }
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
fastify.get("/api/v1/blackbox/project-sessions", async (request, reply) => {
|
|
254
|
-
const { project_id } = request.query || {}
|
|
255
|
-
if (!project_id) {
|
|
256
|
-
return reply.code(400).send({ error: "project_id query parameter is required" })
|
|
257
|
-
}
|
|
258
|
-
try {
|
|
259
|
-
const db = getDb()
|
|
260
|
-
const rows = db.prepare(
|
|
261
|
-
"SELECT session_id, created_at, updated_at, outcome FROM blackbox_sessions WHERE project_id = ? ORDER BY updated_at DESC LIMIT 50"
|
|
262
|
-
).all(project_id)
|
|
263
|
-
return { project_id, sessions: rows }
|
|
264
|
-
} catch (err) {
|
|
265
|
-
return reply.code(500).send({ error: "failed to query sessions" })
|
|
266
|
-
}
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
fastify.post("/api/v1/blackbox/outcome", async (request, reply) => {
|
|
270
|
-
const { session_id, outcome } = request.body || {}
|
|
271
|
-
if (!session_id || !outcome) {
|
|
272
|
-
return reply.code(400).send({ error: "session_id and outcome are required" })
|
|
273
|
-
}
|
|
274
|
-
const sid = session_id
|
|
275
|
-
const tracker = trackers.get(sid) || loadTrackerFromDb(sid)
|
|
276
|
-
if (tracker) {
|
|
277
|
-
tracker.recordOutcome(outcome)
|
|
278
|
-
tracker.annotateLastTurn({
|
|
279
|
-
observed_at: new Date().toISOString(),
|
|
280
|
-
outcome,
|
|
281
|
-
})
|
|
282
|
-
}
|
|
283
|
-
try {
|
|
284
|
-
const db = getDb()
|
|
285
|
-
db.prepare("UPDATE blackbox_sessions SET outcome = ?, updated_at = ? WHERE session_id = ?")
|
|
286
|
-
.run(outcome, new Date().toISOString(), sid)
|
|
287
|
-
if (tracker) {
|
|
288
|
-
saveTrackerToDb(sid, tracker.projectId || null, tracker, {
|
|
289
|
-
observed_at: new Date().toISOString(),
|
|
290
|
-
outcome,
|
|
291
|
-
})
|
|
292
|
-
}
|
|
293
|
-
} catch {}
|
|
294
|
-
return { ok: true, session_id: sid, outcome }
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
fastify.post("/api/v1/blackbox/calibrate", async (request, reply) => {
|
|
298
|
-
const { project_id } = request.body || {}
|
|
299
|
-
const pid = project_id || "global"
|
|
300
|
-
try {
|
|
301
|
-
const db = getDb()
|
|
302
|
-
const sessions = db.prepare(
|
|
303
|
-
"SELECT state_json, outcome FROM blackbox_sessions WHERE project_id = ? AND outcome IS NOT NULL"
|
|
304
|
-
).all(pid)
|
|
305
|
-
|
|
306
|
-
if (sessions.length < 3) {
|
|
307
|
-
return reply.code(400).send({
|
|
308
|
-
error: "need at least 3 sessions with outcomes to calibrate",
|
|
309
|
-
samples: sessions.length,
|
|
310
|
-
})
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const outcomes = sessions.map(s => JSON.parse(s.state_json))
|
|
314
|
-
const loopSessions = outcomes.filter(o => {
|
|
315
|
-
try {
|
|
316
|
-
const state = typeof o === "string" ? JSON.parse(o) : o
|
|
317
|
-
return state?.is_looping
|
|
318
|
-
} catch { return false }
|
|
319
|
-
})
|
|
320
|
-
const positiveOutcomes = sessions.filter(s => s.outcome === "positive").length
|
|
321
|
-
const total = sessions.length
|
|
322
|
-
|
|
323
|
-
const weights = {
|
|
324
|
-
momentum: [-0.3, 0.5, 0.2],
|
|
325
|
-
subRegime: {
|
|
326
|
-
CONVERGING: -0.10,
|
|
327
|
-
CLOSED: -0.10,
|
|
328
|
-
DIVERGENT: +0.15,
|
|
329
|
-
REFINING: 0.00,
|
|
330
|
-
EXPLORING: +0.10,
|
|
331
|
-
LOOPING: +0.15,
|
|
332
|
-
INIT: +0.05,
|
|
333
|
-
},
|
|
334
|
-
loopJaccard: loopSessions.length > 0 ? 0.6 - (loopSessions.length / total) * 0.1 : 0.6,
|
|
335
|
-
closureConfidence: positiveOutcomes > 0 ? 0.7 - (positiveOutcomes / total) * 0.1 : 0.7,
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
db.prepare(`
|
|
339
|
-
INSERT INTO blackbox_calibration (project_id, weights_json, samples_used, updated_at)
|
|
340
|
-
VALUES (?, ?, ?, ?)
|
|
341
|
-
ON CONFLICT(project_id) DO UPDATE SET
|
|
342
|
-
weights_json = excluded.weights_json,
|
|
343
|
-
samples_used = excluded.samples_used,
|
|
344
|
-
updated_at = excluded.updated_at
|
|
345
|
-
`).run(pid, JSON.stringify(weights), total, new Date().toISOString())
|
|
346
|
-
|
|
347
|
-
const tracker = [...trackers.values()].find(t => t.projectId === pid)
|
|
348
|
-
if (tracker) {
|
|
349
|
-
tracker.setCalibratedWeights(weights)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return { ok: true, project_id: pid, samples: total, weights }
|
|
353
|
-
} catch (err) {
|
|
354
|
-
return reply.code(500).send({ error: `calibration failed: ${err.message}` })
|
|
355
|
-
}
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
fastify.get("/api/v1/blackbox/calibration", async (request, reply) => {
|
|
359
|
-
const { project_id } = request.query || {}
|
|
360
|
-
const pid = project_id || "global"
|
|
361
|
-
try {
|
|
362
|
-
const db = getDb()
|
|
363
|
-
const row = db.prepare(
|
|
364
|
-
"SELECT weights_json, samples_used, updated_at FROM blackbox_calibration WHERE project_id = ?"
|
|
365
|
-
).get(pid)
|
|
366
|
-
if (!row) {
|
|
367
|
-
return { project_id: pid, calibrated: false, message: "no calibration data yet" }
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
project_id: pid,
|
|
371
|
-
calibrated: true,
|
|
372
|
-
weights: JSON.parse(row.weights_json),
|
|
373
|
-
samples_used: row.samples_used,
|
|
374
|
-
updated_at: row.updated_at,
|
|
375
|
-
}
|
|
376
|
-
} catch (err) {
|
|
377
|
-
return reply.code(500).send({ error: `failed to read calibration: ${err.message}` })
|
|
378
|
-
}
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
fastify.post("/api/v1/blackbox/control-vector", async (request, reply) => {
|
|
382
|
-
const {
|
|
383
|
-
sub_regime,
|
|
384
|
-
is_looping,
|
|
385
|
-
loop_intervention_level,
|
|
386
|
-
momentum,
|
|
387
|
-
n_interactions,
|
|
388
|
-
latest_stress_multiplier,
|
|
389
|
-
action,
|
|
390
|
-
optimization_mode,
|
|
391
|
-
user_text,
|
|
392
|
-
prompt,
|
|
393
|
-
features,
|
|
394
|
-
pivot_detected,
|
|
395
|
-
pivot_score,
|
|
396
|
-
resolution,
|
|
397
|
-
continuity_state,
|
|
398
|
-
outcome,
|
|
399
|
-
signals,
|
|
400
|
-
} = request.body || {}
|
|
401
|
-
const state = {
|
|
402
|
-
sub_regime,
|
|
403
|
-
is_looping,
|
|
404
|
-
loop_intervention_level,
|
|
405
|
-
momentum,
|
|
406
|
-
n_interactions,
|
|
407
|
-
latest_stress_multiplier,
|
|
408
|
-
user_text,
|
|
409
|
-
prompt,
|
|
410
|
-
features,
|
|
411
|
-
pivot_detected,
|
|
412
|
-
pivot_score,
|
|
413
|
-
resolution,
|
|
414
|
-
continuity_state,
|
|
415
|
-
outcome,
|
|
416
|
-
signals,
|
|
417
|
-
}
|
|
418
|
-
const cv = computeControlVector(state, action, optimization_mode)
|
|
419
|
-
return { ok: true, control_vector: cv }
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
fastify.post("/api/v1/blackbox/select-mode", async (request, reply) => {
|
|
423
|
-
const result = selectBlackboxMode(request.body || {})
|
|
424
|
-
return { ok: true, mode: result.mode, ...result }
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
fastify.get("/api/v1/blackbox/model", async () => {
|
|
428
|
-
return { ok: true, ...getBlackboxRoutingModelMeta() }
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
fastify.post("/api/v1/blackbox/model/rebuild", async (request, reply) => {
|
|
432
|
-
const {
|
|
433
|
-
project_id,
|
|
434
|
-
limit,
|
|
435
|
-
include_bootstrap,
|
|
436
|
-
seed,
|
|
437
|
-
tree_count,
|
|
438
|
-
max_depth,
|
|
439
|
-
min_samples_split,
|
|
440
|
-
min_samples_leaf,
|
|
441
|
-
feature_subsample,
|
|
442
|
-
confidence_threshold,
|
|
443
|
-
} = request.body || {}
|
|
444
|
-
|
|
445
|
-
const result = rebuildBlackboxRoutingModel({
|
|
446
|
-
projectId: project_id || null,
|
|
447
|
-
limit: Number.isFinite(Number(limit)) ? Number(limit) : 5000,
|
|
448
|
-
includeBootstrap: include_bootstrap !== false,
|
|
449
|
-
seed: Number.isFinite(Number(seed)) ? Number(seed) : 42,
|
|
450
|
-
treeCount: Number.isFinite(Number(tree_count)) ? Number(tree_count) : undefined,
|
|
451
|
-
maxDepth: Number.isFinite(Number(max_depth)) ? Number(max_depth) : undefined,
|
|
452
|
-
minSamplesSplit: Number.isFinite(Number(min_samples_split)) ? Number(min_samples_split) : undefined,
|
|
453
|
-
minSamplesLeaf: Number.isFinite(Number(min_samples_leaf)) ? Number(min_samples_leaf) : undefined,
|
|
454
|
-
featureSubsample: Number.isFinite(Number(feature_subsample)) ? Number(feature_subsample) : undefined,
|
|
455
|
-
confidenceThreshold: Number.isFinite(Number(confidence_threshold)) ? Number(confidence_threshold) : undefined,
|
|
456
|
-
})
|
|
457
|
-
|
|
458
|
-
if (!result.ok) {
|
|
459
|
-
return reply.code(400).send(result)
|
|
460
|
-
}
|
|
461
|
-
return result
|
|
462
|
-
})
|
|
463
|
-
}
|
package/routes/compression.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { compressToolOutput, COMPRESS_THRESHOLD } from "../lib/compression.js"
|
|
2
|
-
|
|
3
|
-
export async function compressionRoutes(fastify) {
|
|
4
|
-
fastify.post("/api/v1/compress/context", async (request, reply) => {
|
|
5
|
-
const { text, threshold } = request.body || {}
|
|
6
|
-
if (!text) {
|
|
7
|
-
return reply.code(400).send({ error: "text is required" })
|
|
8
|
-
}
|
|
9
|
-
const result = compressToolOutput(text, threshold || COMPRESS_THRESHOLD)
|
|
10
|
-
return result
|
|
11
|
-
})
|
|
12
|
-
}
|
package/routes/delegation.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { checkDelegation, checkSoftQuota, modelCostPerTurn, normalizeModelId } from "../lib/delegation.js"
|
|
2
|
-
|
|
3
|
-
export async function delegationRoutes(fastify) {
|
|
4
|
-
fastify.post("/api/v1/delegate/check", async (request, reply) => {
|
|
5
|
-
const { tool, tier, model, prompt, dynamic_cache } = request.body || {}
|
|
6
|
-
if (!tool || !tier) {
|
|
7
|
-
return reply.code(400).send({ error: "tool and tier are required" })
|
|
8
|
-
}
|
|
9
|
-
const result = checkDelegation(tool, tier, model, prompt, dynamic_cache || {})
|
|
10
|
-
return result
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
fastify.post("/api/v1/delegate/soft-quota", async (request, reply) => {
|
|
14
|
-
const { tool, current_count, limit } = request.body || {}
|
|
15
|
-
if (!tool) {
|
|
16
|
-
return reply.code(400).send({ error: "tool is required" })
|
|
17
|
-
}
|
|
18
|
-
const result = checkSoftQuota(tool, current_count || 0, limit)
|
|
19
|
-
return result
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
fastify.post("/api/v1/delegation/cost", async (request, reply) => {
|
|
23
|
-
const { model, dynamic_cache } = request.body || {}
|
|
24
|
-
if (!model) {
|
|
25
|
-
return reply.code(400).send({ error: "model is required" })
|
|
26
|
-
}
|
|
27
|
-
const cost = modelCostPerTurn(model, dynamic_cache || {})
|
|
28
|
-
return { model: normalizeModelId(model), cost_per_turn: cost }
|
|
29
|
-
})
|
|
30
|
-
}
|
package/routes/patterns.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { PatternStore } from "../lib/patterns.js"
|
|
2
|
-
|
|
3
|
-
const stores = new Map()
|
|
4
|
-
|
|
5
|
-
function getStore(sessionId = "default") {
|
|
6
|
-
if (!stores.has(sessionId)) {
|
|
7
|
-
stores.set(sessionId, new PatternStore())
|
|
8
|
-
}
|
|
9
|
-
return stores.get(sessionId)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function patternRoutes(fastify) {
|
|
13
|
-
fastify.post("/api/v1/patterns/observe", async (request, reply) => {
|
|
14
|
-
const { session_id, tool_name, input, output, directory } = request.body || {}
|
|
15
|
-
if (!tool_name) {
|
|
16
|
-
return reply.code(400).send({ error: "tool_name is required" })
|
|
17
|
-
}
|
|
18
|
-
const store = getStore(session_id)
|
|
19
|
-
const patterns = store.observeToolEvent(tool_name, input, output, directory)
|
|
20
|
-
return { patterns_detected: patterns.length, patterns }
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
fastify.post("/api/v1/patterns/record", async (request, reply) => {
|
|
24
|
-
const { session_id, kind, key, summary, meta } = request.body || {}
|
|
25
|
-
if (!kind || !key || !summary) {
|
|
26
|
-
return reply.code(400).send({ error: "kind, key, and summary are required" })
|
|
27
|
-
}
|
|
28
|
-
const store = getStore(session_id)
|
|
29
|
-
const pattern = store.recordPattern(kind, key, summary, meta || {})
|
|
30
|
-
return pattern
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
fastify.get("/api/v1/patterns/query", async (request, reply) => {
|
|
34
|
-
const { session_id, kind } = request.query || {}
|
|
35
|
-
const store = getStore(session_id)
|
|
36
|
-
const patterns = store.getPatterns(kind || null)
|
|
37
|
-
return { patterns, count: patterns.length }
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
fastify.get("/api/v1/patterns/exploratory-words", async (request, reply) => {
|
|
41
|
-
const { session_id } = request.query || {}
|
|
42
|
-
const store = getStore(session_id)
|
|
43
|
-
const words = store.getLearnedExploratoryWords()
|
|
44
|
-
return { words }
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
fastify.post("/api/v1/patterns/clear", async (request, reply) => {
|
|
48
|
-
const { session_id } = request.body || {}
|
|
49
|
-
const store = getStore(session_id)
|
|
50
|
-
store.clear()
|
|
51
|
-
return { ok: true }
|
|
52
|
-
})
|
|
53
|
-
}
|