@data-club/ai-hub-server 0.0.1
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/dist/auth/argon2.d.ts +72 -0
- package/dist/auth/argon2.d.ts.map +1 -0
- package/dist/auth/argon2.js +145 -0
- package/dist/auth/argon2.js.map +1 -0
- package/dist/auth/encryption.d.ts +52 -0
- package/dist/auth/encryption.d.ts.map +1 -0
- package/dist/auth/encryption.js +98 -0
- package/dist/auth/encryption.js.map +1 -0
- package/dist/auth/jwt.d.ts +133 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +147 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +101 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +161 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/passwordPolicy.d.ts +72 -0
- package/dist/auth/passwordPolicy.d.ts.map +1 -0
- package/dist/auth/passwordPolicy.js +88 -0
- package/dist/auth/passwordPolicy.js.map +1 -0
- package/dist/auth/roleRules.d.ts +200 -0
- package/dist/auth/roleRules.d.ts.map +1 -0
- package/dist/auth/roleRules.js +365 -0
- package/dist/auth/roleRules.js.map +1 -0
- package/dist/auth/userView.d.ts +55 -0
- package/dist/auth/userView.d.ts.map +1 -0
- package/dist/auth/userView.js +77 -0
- package/dist/auth/userView.js.map +1 -0
- package/dist/bootstrap.d.ts +104 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +160 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/db/connection.d.ts +39 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +62 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrate.d.ts +31 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +197 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +1902 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +662 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/seed.d.ts +92 -0
- package/dist/db/seed.d.ts.map +1 -0
- package/dist/db/seed.js +160 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/handlers/fetch.d.ts +89 -0
- package/dist/handlers/fetch.d.ts.map +1 -0
- package/dist/handlers/fetch.js +173 -0
- package/dist/handlers/fetch.js.map +1 -0
- package/dist/handlers/nextjs.d.ts +40 -0
- package/dist/handlers/nextjs.d.ts.map +1 -0
- package/dist/handlers/nextjs.js +42 -0
- package/dist/handlers/nextjs.js.map +1 -0
- package/dist/handlers/responses.d.ts +46 -0
- package/dist/handlers/responses.d.ts.map +1 -0
- package/dist/handlers/responses.js +74 -0
- package/dist/handlers/responses.js.map +1 -0
- package/dist/handlers/routeTable.d.ts +21 -0
- package/dist/handlers/routeTable.d.ts.map +1 -0
- package/dist/handlers/routeTable.js +133 -0
- package/dist/handlers/routeTable.js.map +1 -0
- package/dist/handlers/router.d.ts +37 -0
- package/dist/handlers/router.d.ts.map +1 -0
- package/dist/handlers/router.js +82 -0
- package/dist/handlers/router.js.map +1 -0
- package/dist/handlers/sse.d.ts +38 -0
- package/dist/handlers/sse.d.ts.map +1 -0
- package/dist/handlers/sse.js +52 -0
- package/dist/handlers/sse.js.map +1 -0
- package/dist/handlers/types.d.ts +96 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/types.js +14 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/letta/client.d.ts +355 -0
- package/dist/letta/client.d.ts.map +1 -0
- package/dist/letta/client.js +529 -0
- package/dist/letta/client.js.map +1 -0
- package/dist/letta/eventTranslator.d.ts +166 -0
- package/dist/letta/eventTranslator.d.ts.map +1 -0
- package/dist/letta/eventTranslator.js +532 -0
- package/dist/letta/eventTranslator.js.map +1 -0
- package/dist/letta/index.d.ts +13 -0
- package/dist/letta/index.d.ts.map +1 -0
- package/dist/letta/index.js +12 -0
- package/dist/letta/index.js.map +1 -0
- package/dist/letta/modelSettings.d.ts +176 -0
- package/dist/letta/modelSettings.d.ts.map +1 -0
- package/dist/letta/modelSettings.js +314 -0
- package/dist/letta/modelSettings.js.map +1 -0
- package/dist/letta/promptWrapping.d.ts +141 -0
- package/dist/letta/promptWrapping.d.ts.map +1 -0
- package/dist/letta/promptWrapping.js +213 -0
- package/dist/letta/promptWrapping.js.map +1 -0
- package/dist/letta/sandbox.d.ts +100 -0
- package/dist/letta/sandbox.d.ts.map +1 -0
- package/dist/letta/sandbox.js +151 -0
- package/dist/letta/sandbox.js.map +1 -0
- package/dist/letta/settingsFileSeed.d.ts +146 -0
- package/dist/letta/settingsFileSeed.d.ts.map +1 -0
- package/dist/letta/settingsFileSeed.js +177 -0
- package/dist/letta/settingsFileSeed.js.map +1 -0
- package/dist/letta/subprocessThrottle.d.ts +151 -0
- package/dist/letta/subprocessThrottle.d.ts.map +1 -0
- package/dist/letta/subprocessThrottle.js +195 -0
- package/dist/letta/subprocessThrottle.js.map +1 -0
- package/dist/letta/tpmRecovery.d.ts +202 -0
- package/dist/letta/tpmRecovery.d.ts.map +1 -0
- package/dist/letta/tpmRecovery.js +314 -0
- package/dist/letta/tpmRecovery.js.map +1 -0
- package/dist/letta/types.d.ts +54 -0
- package/dist/letta/types.d.ts.map +1 -0
- package/dist/letta/types.js +16 -0
- package/dist/letta/types.js.map +1 -0
- package/dist/observability/logger.d.ts +48 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +81 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +53 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +92 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/routes/admin/agents.d.ts +63 -0
- package/dist/routes/admin/agents.d.ts.map +1 -0
- package/dist/routes/admin/agents.js +461 -0
- package/dist/routes/admin/agents.js.map +1 -0
- package/dist/routes/admin/rotatingMessages.d.ts +51 -0
- package/dist/routes/admin/rotatingMessages.d.ts.map +1 -0
- package/dist/routes/admin/rotatingMessages.js +292 -0
- package/dist/routes/admin/rotatingMessages.js.map +1 -0
- package/dist/routes/admin/sessions.d.ts +61 -0
- package/dist/routes/admin/sessions.d.ts.map +1 -0
- package/dist/routes/admin/sessions.js +232 -0
- package/dist/routes/admin/sessions.js.map +1 -0
- package/dist/routes/admin/settings.d.ts +110 -0
- package/dist/routes/admin/settings.d.ts.map +1 -0
- package/dist/routes/admin/settings.js +401 -0
- package/dist/routes/admin/settings.js.map +1 -0
- package/dist/routes/admin/users.d.ts +115 -0
- package/dist/routes/admin/users.d.ts.map +1 -0
- package/dist/routes/admin/users.js +374 -0
- package/dist/routes/admin/users.js.map +1 -0
- package/dist/routes/agents.d.ts +30 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +55 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/auth.d.ts +121 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +422 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/chat.d.ts +97 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +484 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/featureToggles.d.ts +34 -0
- package/dist/routes/featureToggles.d.ts.map +1 -0
- package/dist/routes/featureToggles.js +47 -0
- package/dist/routes/featureToggles.js.map +1 -0
- package/dist/routes/health.d.ts +24 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +37 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/metrics.d.ts +35 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +106 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/sessions.d.ts +161 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +1501 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stubs.d.ts +25 -0
- package/dist/routes/stubs.d.ts.map +1 -0
- package/dist/routes/stubs.js +25 -0
- package/dist/routes/stubs.js.map +1 -0
- package/dist/state/cron.d.ts +58 -0
- package/dist/state/cron.d.ts.map +1 -0
- package/dist/state/cron.js +160 -0
- package/dist/state/cron.js.map +1 -0
- package/dist/state/rotationRunner.d.ts +96 -0
- package/dist/state/rotationRunner.d.ts.map +1 -0
- package/dist/state/rotationRunner.js +246 -0
- package/dist/state/rotationRunner.js.map +1 -0
- package/dist/state/rotationScheduler.d.ts +76 -0
- package/dist/state/rotationScheduler.d.ts.map +1 -0
- package/dist/state/rotationScheduler.js +124 -0
- package/dist/state/rotationScheduler.js.map +1 -0
- package/dist/state/turnRegistry.d.ts +95 -0
- package/dist/state/turnRegistry.d.ts.map +1 -0
- package/dist/state/turnRegistry.js +149 -0
- package/dist/state/turnRegistry.js.map +1 -0
- package/dist/state/turnRunner.d.ts +134 -0
- package/dist/state/turnRunner.d.ts.map +1 -0
- package/dist/state/turnRunner.js +476 -0
- package/dist/state/turnRunner.js.map +1 -0
- package/package.json +47 -0
- package/src/auth/argon2.ts +152 -0
- package/src/auth/encryption.ts +110 -0
- package/src/auth/jwt.ts +217 -0
- package/src/auth/middleware.ts +250 -0
- package/src/auth/passwordPolicy.ts +99 -0
- package/src/auth/roleRules.ts +497 -0
- package/src/auth/userView.ts +88 -0
- package/src/bootstrap.ts +254 -0
- package/src/db/connection.ts +75 -0
- package/src/db/migrate.ts +212 -0
- package/src/db/schema.ts +750 -0
- package/src/db/seed.ts +236 -0
- package/src/handlers/fetch.ts +251 -0
- package/src/handlers/nextjs.ts +49 -0
- package/src/handlers/responses.ts +95 -0
- package/src/handlers/routeTable.ts +188 -0
- package/src/handlers/router.ts +96 -0
- package/src/handlers/sse.ts +55 -0
- package/src/handlers/types.ts +104 -0
- package/src/index.ts +60 -0
- package/src/letta/client.ts +860 -0
- package/src/letta/eventTranslator.ts +667 -0
- package/src/letta/index.ts +46 -0
- package/src/letta/lettaCliShim.mjs +40 -0
- package/src/letta/sandbox.ts +167 -0
- package/src/letta/settingsFileSeed.ts +254 -0
- package/src/letta/subprocessThrottle.ts +251 -0
- package/src/letta/types.ts +65 -0
- package/src/observability/logger.ts +103 -0
- package/src/observability/metrics.ts +114 -0
- package/src/routes/admin/agents.ts +574 -0
- package/src/routes/admin/rotatingMessages.ts +351 -0
- package/src/routes/admin/sessions.ts +283 -0
- package/src/routes/admin/settings.ts +463 -0
- package/src/routes/admin/users.ts +455 -0
- package/src/routes/agents.ts +66 -0
- package/src/routes/auth.ts +513 -0
- package/src/routes/chat.ts +534 -0
- package/src/routes/featureToggles.ts +52 -0
- package/src/routes/health.ts +44 -0
- package/src/routes/metrics.ts +111 -0
- package/src/routes/sessions.ts +1878 -0
- package/src/state/cron.ts +179 -0
- package/src/state/rotationRunner.ts +326 -0
- package/src/state/rotationScheduler.ts +164 -0
- package/src/state/turnRegistry.ts +210 -0
- package/src/state/turnRunner.ts +588 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory broadcaster for live turn streams.
|
|
3
|
+
*
|
|
4
|
+
* Every active turn has at most one writer (the runner) and zero-or-more
|
|
5
|
+
* subscribers (the original `POST /chat` connection + every
|
|
6
|
+
* `GET /chat/:turn_id/events?from_seq=N` resumption connection still
|
|
7
|
+
* running while the turn is live).
|
|
8
|
+
*
|
|
9
|
+
* Persistence lives in `turn_events` (§11) — the registry only handles the
|
|
10
|
+
* **live attach** part of resumption. The first half of a resumption read
|
|
11
|
+
* (replay from `from_seq`) is a plain DB query.
|
|
12
|
+
*
|
|
13
|
+
* The registry is process-local — this matches the single-customer
|
|
14
|
+
* deployment model (§1). When ai-hub scales to multiple replicas in a
|
|
15
|
+
* v1.x release, this gets a Redis-backed implementation behind the same
|
|
16
|
+
* interface; the wire protocol (§9) and the resumption contract (§6.3.2)
|
|
17
|
+
* stay unchanged.
|
|
18
|
+
*
|
|
19
|
+
* @see SPECIFICATIONS.md §6.3.2 — resumption endpoint
|
|
20
|
+
* @see SPECIFICATIONS.md §6.6 — server-authoritative state machine
|
|
21
|
+
* @see SPECIFICATIONS.md §11 — `turn_events` table
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Process-local map of live turn channels. The map prunes a channel on
|
|
25
|
+
* close as soon as every subscriber has unsubscribed (or immediately if
|
|
26
|
+
* no subscribers are attached).
|
|
27
|
+
*/
|
|
28
|
+
const channels = new Map();
|
|
29
|
+
/**
|
|
30
|
+
* Begins a new live turn channel.
|
|
31
|
+
*
|
|
32
|
+
* The runner calls this when it inserts the `turn` row, before it starts
|
|
33
|
+
* pumping events. Returns an opaque `TurnPublisher` the runner uses to
|
|
34
|
+
* publish + close.
|
|
35
|
+
*
|
|
36
|
+
* @param turnId - the freshly-created turn id.
|
|
37
|
+
* @returns the publisher handle.
|
|
38
|
+
*/
|
|
39
|
+
export function openTurnChannel(turnId) {
|
|
40
|
+
if (channels.has(turnId)) {
|
|
41
|
+
throw new Error(`Turn ${turnId} already has an open channel.`);
|
|
42
|
+
}
|
|
43
|
+
const channel = {
|
|
44
|
+
lastSeq: -1,
|
|
45
|
+
closed: false,
|
|
46
|
+
listeners: new Set(),
|
|
47
|
+
closeListeners: new Set(),
|
|
48
|
+
cancelController: new AbortController(),
|
|
49
|
+
};
|
|
50
|
+
channels.set(turnId, channel);
|
|
51
|
+
return {
|
|
52
|
+
cancelSignal: channel.cancelController.signal,
|
|
53
|
+
publish(event) {
|
|
54
|
+
channel.lastSeq = event.seq;
|
|
55
|
+
for (const listener of channel.listeners) {
|
|
56
|
+
try {
|
|
57
|
+
listener(event);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
/* swallow — a misbehaving listener cannot break the channel */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
close() {
|
|
65
|
+
if (channel.closed)
|
|
66
|
+
return;
|
|
67
|
+
channel.closed = true;
|
|
68
|
+
for (const cb of channel.closeListeners) {
|
|
69
|
+
try {
|
|
70
|
+
cb();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
/* ignored */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
channel.closeListeners.clear();
|
|
77
|
+
// Drop the channel once every subscriber unsubscribed. If nobody is
|
|
78
|
+
// listening at close time, prune immediately.
|
|
79
|
+
if (channel.listeners.size === 0) {
|
|
80
|
+
channels.delete(turnId);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Subscribes to a live turn channel.
|
|
87
|
+
*
|
|
88
|
+
* Returns `null` when the turn is not active (either never opened or
|
|
89
|
+
* already closed) — the caller should fall back to replaying persisted
|
|
90
|
+
* events from `turn_events` instead.
|
|
91
|
+
*
|
|
92
|
+
* @param turnId - the turn id to attach to.
|
|
93
|
+
* @param listener - called once per event (with `seq` already assigned).
|
|
94
|
+
* @param onClose - called once when the channel closes (after final event).
|
|
95
|
+
* @returns an unsubscribe function, or `null` when the channel is closed.
|
|
96
|
+
*/
|
|
97
|
+
export function subscribeToTurn(turnId, listener, onClose) {
|
|
98
|
+
const channel = channels.get(turnId);
|
|
99
|
+
if (!channel || channel.closed)
|
|
100
|
+
return null;
|
|
101
|
+
channel.listeners.add(listener);
|
|
102
|
+
channel.closeListeners.add(onClose);
|
|
103
|
+
return () => {
|
|
104
|
+
channel.listeners.delete(listener);
|
|
105
|
+
channel.closeListeners.delete(onClose);
|
|
106
|
+
if (channel.closed && channel.listeners.size === 0) {
|
|
107
|
+
channels.delete(turnId);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns `true` when the turn has an open channel right now.
|
|
113
|
+
*
|
|
114
|
+
* The chat handler uses this to disambiguate "turn is in flight" from
|
|
115
|
+
* "turn completed long ago" without having to query the DB twice.
|
|
116
|
+
*/
|
|
117
|
+
export function isTurnLive(turnId) {
|
|
118
|
+
const channel = channels.get(turnId);
|
|
119
|
+
return !!channel && !channel.closed;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Test-only utility — wipes the registry so tests can isolate from each
|
|
123
|
+
* other. Production code never calls this.
|
|
124
|
+
*/
|
|
125
|
+
export function _resetTurnRegistryForTests() {
|
|
126
|
+
channels.clear();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Triggers cancellation of the named turn. The runner is expected to
|
|
130
|
+
* have wired its run to the publisher's `cancelSignal`; firing it from
|
|
131
|
+
* here aborts the upstream Letta call and short-circuits the loop.
|
|
132
|
+
*
|
|
133
|
+
* Idempotent: calling on a closed / unknown turn is a no-op. The
|
|
134
|
+
* `POST /chat/:id/cancel` route's user-facing 200 response covers
|
|
135
|
+
* race-conditions where the turn terminated between the request and
|
|
136
|
+
* this call.
|
|
137
|
+
*
|
|
138
|
+
* @param turnId - the turn to cancel.
|
|
139
|
+
* @returns `true` if the signal was fired, `false` if the channel is
|
|
140
|
+
* closed or unknown.
|
|
141
|
+
*/
|
|
142
|
+
export function requestTurnCancellation(turnId) {
|
|
143
|
+
const channel = channels.get(turnId);
|
|
144
|
+
if (!channel || channel.closed)
|
|
145
|
+
return false;
|
|
146
|
+
channel.cancelController.abort();
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=turnRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turnRegistry.js","sourceRoot":"","sources":["../../src/state/turnRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-authoritative turn lifecycle (§6.6, §10).
|
|
3
|
+
*
|
|
4
|
+
* `runTurn(...)` is the one entry point that:
|
|
5
|
+
*
|
|
6
|
+
* 1. Inserts the `turn` row in status=running, phase=model_text.
|
|
7
|
+
* 2. Opens a live channel (`turnRegistry.openTurnChannel`) so concurrent
|
|
8
|
+
* resumption attempts can attach.
|
|
9
|
+
* 3. Emits `stream_start` (seq 0).
|
|
10
|
+
* 4. Calls `LettaClient.streamUserMessage(...)` which spawns a Letta
|
|
11
|
+
* Code subprocess, acquires the throttle lease, sends the user
|
|
12
|
+
* message. Returns a `ChatTurnHandle`.
|
|
13
|
+
* 5. Iterates the handle's `events` stream:
|
|
14
|
+
* - Non-terminal SDK messages → `translateSdkMessage(...)` →
|
|
15
|
+
* stamps + persists + broadcasts each emitted ai-hub event.
|
|
16
|
+
* - Terminal `result` SDK message → `finalizeTerminal(...)` →
|
|
17
|
+
* emits the closing `assistant_message_complete` + `stream_end`
|
|
18
|
+
* with the correct reason (`done` / `cancelled` / `error`).
|
|
19
|
+
* 6. On cancellation (caller signal OR `requestTurnCancellation`):
|
|
20
|
+
* calls `handle.abort()` to send `interrupt` to the CLI, keeps
|
|
21
|
+
* draining until terminal, then closes.
|
|
22
|
+
* 7. On throttle rejection (`ServerOverloadedError`): emits
|
|
23
|
+
* `error{code:"server_overloaded"}` + `stream_end{error}`.
|
|
24
|
+
* Transitions turn → failed.
|
|
25
|
+
* 8. On unhandled error: emits `error` + `stream_end{error}`,
|
|
26
|
+
* `turn.status = "failed"`.
|
|
27
|
+
* 9. Always calls `handle.close()` in finally (releases subprocess +
|
|
28
|
+
* throttle lease).
|
|
29
|
+
*
|
|
30
|
+
* @see SPECIFICATIONS.md §6.3.2 — chat / SSE
|
|
31
|
+
* @see SPECIFICATIONS.md §6.6 — state-machine ownership
|
|
32
|
+
* @see SPECIFICATIONS.md §6.9 — cancellation
|
|
33
|
+
* @see SPECIFICATIONS.md §9 — wire protocol
|
|
34
|
+
* @see SPECIFICATIONS.md §10 — state machine
|
|
35
|
+
*/
|
|
36
|
+
import type { AIHubEvent, TurnStatus } from "@data-club/ai-hub";
|
|
37
|
+
import type { DrizzleDB } from "../db/connection.js";
|
|
38
|
+
import { type LettaClient } from "../letta/client.js";
|
|
39
|
+
import type { Logger } from "../observability/logger.js";
|
|
40
|
+
/** The ai-hub SSE wire-protocol version this server speaks (§9.1). */
|
|
41
|
+
export declare const WIRE_PROTOCOL_VERSION = "1.0";
|
|
42
|
+
/** Parameters for `runTurn`. */
|
|
43
|
+
export interface RunTurnOpts {
|
|
44
|
+
/** Drizzle handle. */
|
|
45
|
+
db: DrizzleDB;
|
|
46
|
+
/** Letta client wrapper (production wraps the SDKs; tests mock). */
|
|
47
|
+
lettaClient: LettaClient;
|
|
48
|
+
/** Pino logger for this request. */
|
|
49
|
+
logger: Logger;
|
|
50
|
+
/** Per-request id for log correlation (stamped on `error` events). */
|
|
51
|
+
requestId: string;
|
|
52
|
+
/** Owner of the session. */
|
|
53
|
+
userId: string;
|
|
54
|
+
/** ai-hub session id this turn belongs to. */
|
|
55
|
+
sessionId: string;
|
|
56
|
+
/** The Letta conversation id stored on the session row. */
|
|
57
|
+
lettaConversationId: string;
|
|
58
|
+
/** The Letta agent id stored on the session row. */
|
|
59
|
+
lettaAgentId: string;
|
|
60
|
+
/**
|
|
61
|
+
* Step-12.5 — absolute path of the per-session sandbox folder, or
|
|
62
|
+
* `null` when the session has no sandbox (today's stateless shape).
|
|
63
|
+
* Threaded as `cwd` into the Letta Code subprocess spawn so the
|
|
64
|
+
* agent's filesystem tools operate inside the seeded folder. When
|
|
65
|
+
* non-null, also flips the disallowed-tools list to re-enable
|
|
66
|
+
* `Read` / `Write` / `Bash` / etc.
|
|
67
|
+
*/
|
|
68
|
+
sandboxDir: string | null;
|
|
69
|
+
/** The user's typed message. */
|
|
70
|
+
userMessage: string;
|
|
71
|
+
/** Optional idempotency key from the request body. */
|
|
72
|
+
idempotencyKey?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Listener that receives every event the runner emits. The chat
|
|
75
|
+
* handler subscribes its SSE writer here. `null` events signal
|
|
76
|
+
* "channel closed; no more events coming."
|
|
77
|
+
*/
|
|
78
|
+
onEvent: (event: AIHubEvent | null) => void;
|
|
79
|
+
/**
|
|
80
|
+
* Caller-supplied AbortSignal. When aborted, the runner calls
|
|
81
|
+
* `handle.abort()` on the spawned Letta Code subprocess and emits
|
|
82
|
+
* `stream_end{reason:"cancelled"}` after the upstream terminal
|
|
83
|
+
* `result` arrives.
|
|
84
|
+
*/
|
|
85
|
+
signal?: AbortSignal;
|
|
86
|
+
}
|
|
87
|
+
/** Returned by `runTurn`. The runner returns after `turn_event`s are committed. */
|
|
88
|
+
export interface RunTurnResult {
|
|
89
|
+
/** The new turn id (the `turn_id` carried in `stream_start`). */
|
|
90
|
+
turnId: string;
|
|
91
|
+
/** Terminal status (`done` / `cancelled` / `failed`). */
|
|
92
|
+
status: Exclude<TurnStatus, "idle" | "running">;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Runs one turn from "user pressed Send" to terminal status. Returns a
|
|
96
|
+
* promise that resolves when the runner has persisted the terminal
|
|
97
|
+
* event(s), closed the live channel, and torn down the Letta Code
|
|
98
|
+
* subprocess.
|
|
99
|
+
*
|
|
100
|
+
* The caller is expected to keep `onEvent` alive for the entire run.
|
|
101
|
+
*
|
|
102
|
+
* @param opts - see `RunTurnOpts`.
|
|
103
|
+
* @returns the turn id and terminal status.
|
|
104
|
+
*/
|
|
105
|
+
export declare function runTurn(opts: RunTurnOpts): Promise<RunTurnResult>;
|
|
106
|
+
/**
|
|
107
|
+
* Replays persisted `turn_event` rows newer than `fromSeq`, returned as
|
|
108
|
+
* ai-hub-shaped events. Used by `GET /chat/:turn_id/events?from_seq=N`
|
|
109
|
+
* for the replay half of resumption.
|
|
110
|
+
*
|
|
111
|
+
* @param db - Drizzle handle.
|
|
112
|
+
* @param turnId - the turn id.
|
|
113
|
+
* @param fromSeq - replays events with `seq > fromSeq`.
|
|
114
|
+
* @returns the persisted events.
|
|
115
|
+
*
|
|
116
|
+
* @see SPECIFICATIONS.md §6.3.2 — resumption
|
|
117
|
+
*/
|
|
118
|
+
export declare function replayPersistedEvents(db: DrizzleDB, turnId: string, fromSeq: number): ReadonlyArray<AIHubEvent>;
|
|
119
|
+
/**
|
|
120
|
+
* Idempotently marks a turn as cancelled in the DB. Returns the row's
|
|
121
|
+
* resulting status. Called by `POST /chat/:turn_id/cancel` after firing
|
|
122
|
+
* `requestTurnCancellation`. The runner's catch arm also persists
|
|
123
|
+
* `cancelled` via `syncTurnRow`; this helper just guarantees the row
|
|
124
|
+
* is updated when the runner has already exited (terminal-after-cancel
|
|
125
|
+
* race).
|
|
126
|
+
*
|
|
127
|
+
* Does not overwrite `done` / `failed` — those are terminal states.
|
|
128
|
+
*
|
|
129
|
+
* @param db - Drizzle handle.
|
|
130
|
+
* @param turnId - the turn to cancel.
|
|
131
|
+
* @returns the row's resulting status, or `null` if no such row.
|
|
132
|
+
*/
|
|
133
|
+
export declare function markCancelled(db: DrizzleDB, turnId: string): TurnStatus | null;
|
|
134
|
+
//# sourceMappingURL=turnRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turnRunner.d.ts","sourceRoot":"","sources":["../../src/state/turnRunner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH,OAAO,KAAK,EACV,UAAU,EAGV,UAAU,EACX,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAA8C,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AASlG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGzD,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAM3C,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,sBAAsB;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,oEAAoE;IACpE,WAAW,EAAE,WAAW,CAAC;IACzB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CACjD;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CA4VvE;AAuCD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,aAAa,CAAC,UAAU,CAAC,CAa3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,MAAM,GACb,UAAU,GAAG,IAAI,CAenB"}
|