@plurnk/plurnk-service 0.2.0 → 0.3.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.
- package/SPEC.md +67 -90
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +172 -82
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/ProviderRegistry.d.ts +1 -1
- package/dist/core/ProviderRegistry.d.ts.map +1 -1
- package/dist/core/ProviderRegistry.js.map +1 -1
- package/dist/core/packet-wire.js +94 -29
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/providers/Mock.d.ts +2 -2
- package/dist/providers/Mock.d.ts.map +1 -1
- package/dist/providers/Mock.js.map +1 -1
- package/dist/schemes/File.d.ts +4 -4
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +79 -47
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Known.js +1 -1
- package/dist/schemes/Known.js.map +1 -1
- package/dist/schemes/Log.d.ts +7 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +41 -9
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Plurnk.d.ts +15 -1
- package/dist/schemes/Plurnk.d.ts.map +1 -1
- package/dist/schemes/Plurnk.js +50 -8
- package/dist/schemes/Plurnk.js.map +1 -1
- package/dist/schemes/Skill.js +1 -1
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Unknown.js +1 -1
- package/dist/schemes/Unknown.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +3 -3
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +2 -18
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/server/ClientConnection.d.ts.map +1 -1
- package/dist/server/ClientConnection.js +6 -1
- package/dist/server/ClientConnection.js.map +1 -1
- package/dist/server/envelope.d.ts +2 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +11 -8
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/logEntry.d.ts +9 -9
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +10 -10
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/methods/_dispatchAsClient.d.ts.map +1 -1
- package/dist/server/methods/_dispatchAsClient.js +7 -2
- package/dist/server/methods/_dispatchAsClient.js.map +1 -1
- package/dist/server/methods/loop_run.d.ts.map +1 -1
- package/dist/server/methods/loop_run.js +7 -2
- package/dist/server/methods/loop_run.js.map +1 -1
- package/migrations/001_schema.sql +324 -0
- package/package.json +18 -12
- package/migrations/001_sessions.sql +0 -11
- package/migrations/002_runs.sql +0 -16
- package/migrations/003_loops.sql +0 -12
- package/migrations/004_turns.sql +0 -18
- package/migrations/005_entries.sql +0 -44
- package/migrations/006_log_entries.sql +0 -51
- package/migrations/007_visibility.sql +0 -10
- package/migrations/008_schemes_providers.sql +0 -25
- package/migrations/009_cost_rollups.sql +0 -44
- package/migrations/010_subscriptions.sql +0 -36
- package/migrations/011_turn_call_metadata.sql +0 -7
- package/migrations/012_proposal_lifecycle.sql +0 -22
- package/migrations/013_log_entries_lifecycle_columns.sql +0 -22
- package/migrations/014_loop_flags.sql +0 -9
- package/migrations/015_sessions_project_root.sql +0 -6
- package/migrations/016_persona_columns.sql +0 -11
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
-- INIT: sessions
|
|
2
|
+
-- project_root: workspace pointer. NULL = headless (no disk side-effects);
|
|
3
|
+
-- non-null = absolute path to the client's source tree, supplied at
|
|
4
|
+
-- session.create or session.set_root.
|
|
5
|
+
-- persona: head of the persona cascade (loops.persona > runs.persona >
|
|
6
|
+
-- sessions.persona > PATHS.defaultPersona). Nullable; null falls through.
|
|
7
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
8
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
9
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
10
|
+
name TEXT NOT NULL UNIQUE CHECK (length(name) > 0),
|
|
11
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
12
|
+
cost_pico INTEGER NOT NULL DEFAULT 0 CHECK (cost_pico >= 0),
|
|
13
|
+
scheme_registry_additions TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(scheme_registry_additions)),
|
|
14
|
+
project_root TEXT,
|
|
15
|
+
persona TEXT
|
|
16
|
+
) STRICT;
|
|
17
|
+
|
|
18
|
+
CREATE INDEX IF NOT EXISTS sessions_created_at ON sessions (created_at);
|
|
19
|
+
|
|
20
|
+
-- INIT: runs
|
|
21
|
+
-- persona: middle of the persona cascade (loops > runs > sessions > default).
|
|
22
|
+
-- Nullable; null falls through to the session level.
|
|
23
|
+
CREATE TABLE IF NOT EXISTS runs (
|
|
24
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
25
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
26
|
+
session_id INTEGER NOT NULL,
|
|
27
|
+
name TEXT NOT NULL CHECK (length(name) > 0),
|
|
28
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
29
|
+
parent_run_id INTEGER CHECK (parent_run_id IS NULL OR parent_run_id != id),
|
|
30
|
+
cost_pico INTEGER NOT NULL DEFAULT 0 CHECK (cost_pico >= 0),
|
|
31
|
+
persona TEXT,
|
|
32
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,
|
|
33
|
+
FOREIGN KEY (parent_run_id) REFERENCES runs(id) ON DELETE CASCADE
|
|
34
|
+
) STRICT;
|
|
35
|
+
|
|
36
|
+
CREATE INDEX IF NOT EXISTS runs_session_id_created_at ON runs (session_id, created_at);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS runs_parent_run_id ON runs (parent_run_id);
|
|
38
|
+
CREATE UNIQUE INDEX IF NOT EXISTS runs_session_name ON runs (session_id, name);
|
|
39
|
+
|
|
40
|
+
-- INIT: loops
|
|
41
|
+
-- flags: per-loop runtime flags (yolo, noProposals, noWeb, noInteraction,
|
|
42
|
+
-- mode). JSON column, merged over DEFAULT_LOOP_FLAGS in code so missing
|
|
43
|
+
-- keys read as their defaults. SchemeRegistry.resolveForLoop gates schemes
|
|
44
|
+
-- by manifest affinity (proposes / excludedInAsk / requiresWeb / etc).
|
|
45
|
+
-- persona: head of the cascade (loops > runs > sessions > default).
|
|
46
|
+
CREATE TABLE IF NOT EXISTS loops (
|
|
47
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
48
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
49
|
+
run_id INTEGER NOT NULL,
|
|
50
|
+
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
51
|
+
status INTEGER NOT NULL DEFAULT 102 CHECK (status IN (102, 200, 499)),
|
|
52
|
+
prompt TEXT NOT NULL,
|
|
53
|
+
flags TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(flags)),
|
|
54
|
+
persona TEXT,
|
|
55
|
+
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE
|
|
56
|
+
) STRICT;
|
|
57
|
+
|
|
58
|
+
CREATE UNIQUE INDEX IF NOT EXISTS loops_run_id_sequence ON loops (run_id, sequence);
|
|
59
|
+
|
|
60
|
+
-- INIT: turns
|
|
61
|
+
-- finish_reason / model: provider-call metadata (plurnk-grammar Turn.json).
|
|
62
|
+
-- Properties of the call, not of the model's emission payload — kept on
|
|
63
|
+
-- the Turn row alongside usage rather than nested into packet.assistant.
|
|
64
|
+
CREATE TABLE IF NOT EXISTS turns (
|
|
65
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
66
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
67
|
+
loop_id INTEGER NOT NULL,
|
|
68
|
+
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
69
|
+
timestamp TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
70
|
+
status INTEGER NOT NULL CHECK (status BETWEEN 100 AND 599),
|
|
71
|
+
usage_prompt INTEGER NOT NULL DEFAULT 0 CHECK (usage_prompt >= 0),
|
|
72
|
+
usage_completion INTEGER NOT NULL DEFAULT 0 CHECK (usage_completion >= 0),
|
|
73
|
+
usage_cached INTEGER NOT NULL DEFAULT 0 CHECK (usage_cached >= 0),
|
|
74
|
+
usage_cost_pico INTEGER NOT NULL DEFAULT 0 CHECK (usage_cost_pico >= 0),
|
|
75
|
+
packet TEXT NOT NULL CHECK (json_valid(packet)),
|
|
76
|
+
finish_reason TEXT,
|
|
77
|
+
model TEXT NOT NULL DEFAULT 'unknown' CHECK (length(model) >= 1),
|
|
78
|
+
FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE
|
|
79
|
+
) STRICT;
|
|
80
|
+
|
|
81
|
+
CREATE UNIQUE INDEX IF NOT EXISTS turns_loop_id_sequence ON turns (loop_id, sequence);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS turns_timestamp ON turns (timestamp);
|
|
83
|
+
|
|
84
|
+
-- INIT: entries
|
|
85
|
+
-- The canonical addressable store. (scope, scheme, pathname) is the
|
|
86
|
+
-- identity tuple. scheme is nullable: the `file` scheme is a routing
|
|
87
|
+
-- internal only, never stored here; bare/file paths land with scheme=NULL.
|
|
88
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
89
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
90
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
91
|
+
scope TEXT NOT NULL CHECK (scope IN ('agent', 'session')),
|
|
92
|
+
session_id INTEGER,
|
|
93
|
+
scheme TEXT CHECK (scheme IS NULL OR length(scheme) > 0),
|
|
94
|
+
username TEXT,
|
|
95
|
+
password TEXT,
|
|
96
|
+
hostname TEXT,
|
|
97
|
+
port INTEGER CHECK (port IS NULL OR (port BETWEEN 0 AND 65535)),
|
|
98
|
+
pathname TEXT NOT NULL,
|
|
99
|
+
params TEXT CHECK (params IS NULL OR json_valid(params)),
|
|
100
|
+
attributes TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attributes)),
|
|
101
|
+
CHECK ((scope = 'agent' AND session_id IS NULL)
|
|
102
|
+
OR (scope = 'session' AND session_id IS NOT NULL)),
|
|
103
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
104
|
+
) STRICT;
|
|
105
|
+
|
|
106
|
+
CREATE UNIQUE INDEX IF NOT EXISTS entries_agent_identity ON entries (scheme, pathname) WHERE scope = 'agent';
|
|
107
|
+
CREATE UNIQUE INDEX IF NOT EXISTS entries_session_identity ON entries (session_id, scheme, pathname) WHERE scope = 'session';
|
|
108
|
+
|
|
109
|
+
-- The ONE engine-imposed constraint (SPEC §7.8): 100 MiB char-length cap
|
|
110
|
+
-- per channel content body. All other limits are extrinsic.
|
|
111
|
+
CREATE TABLE IF NOT EXISTS entry_channels (
|
|
112
|
+
entry_id INTEGER NOT NULL,
|
|
113
|
+
name TEXT NOT NULL CHECK (length(name) > 0),
|
|
114
|
+
content TEXT NOT NULL CHECK (length(content) <= 104857600),
|
|
115
|
+
mimetype TEXT NOT NULL CHECK (length(mimetype) > 0),
|
|
116
|
+
tokens INTEGER NOT NULL DEFAULT 0 CHECK (tokens >= 0),
|
|
117
|
+
state TEXT NOT NULL DEFAULT 'static' CHECK (state IN ('static', 'active', 'closed', 'errored')),
|
|
118
|
+
PRIMARY KEY (entry_id, name),
|
|
119
|
+
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
120
|
+
) STRICT, WITHOUT ROWID;
|
|
121
|
+
|
|
122
|
+
CREATE TABLE IF NOT EXISTS entry_tags (
|
|
123
|
+
entry_id INTEGER NOT NULL,
|
|
124
|
+
tag TEXT NOT NULL CHECK (length(tag) > 0),
|
|
125
|
+
PRIMARY KEY (entry_id, tag),
|
|
126
|
+
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
127
|
+
) STRICT, WITHOUT ROWID;
|
|
128
|
+
|
|
129
|
+
CREATE INDEX IF NOT EXISTS entry_tags_tag ON entry_tags (tag);
|
|
130
|
+
|
|
131
|
+
-- INIT: log_entries
|
|
132
|
+
-- Chronological event store. sequence is 1-based, scoped to the turn —
|
|
133
|
+
-- resets at each new turn. URI-bit columns are unprefixed (scheme,
|
|
134
|
+
-- pathname, …). state/outcome/attrs carry the proposal lifecycle —
|
|
135
|
+
-- status⊥state: status is the HTTP outcome, state is where in the
|
|
136
|
+
-- lifecycle the entry sits. Most rows write 'resolved' directly;
|
|
137
|
+
-- proposing schemes transition 'proposed' → resolved/failed/cancelled.
|
|
138
|
+
-- indexed: per-row visibility for SHOW/HIDE via the log:// scheme.
|
|
139
|
+
CREATE TABLE IF NOT EXISTS log_entries (
|
|
140
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
141
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
142
|
+
|
|
143
|
+
run_id INTEGER NOT NULL,
|
|
144
|
+
loop_id INTEGER NOT NULL,
|
|
145
|
+
turn_id INTEGER NOT NULL,
|
|
146
|
+
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
147
|
+
at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
148
|
+
origin TEXT NOT NULL CHECK (origin IN ('model', 'client', 'system', 'plugin')),
|
|
149
|
+
|
|
150
|
+
op TEXT NOT NULL CHECK (op IN ('FIND', 'READ', 'EDIT', 'COPY', 'MOVE', 'SHOW', 'HIDE', 'SEND', 'EXEC')),
|
|
151
|
+
suffix TEXT NOT NULL DEFAULT '',
|
|
152
|
+
signal TEXT CHECK (signal IS NULL OR json_valid(signal)),
|
|
153
|
+
|
|
154
|
+
scheme TEXT CHECK (scheme IS NULL OR length(scheme) > 0),
|
|
155
|
+
username TEXT,
|
|
156
|
+
password TEXT,
|
|
157
|
+
hostname TEXT,
|
|
158
|
+
port INTEGER CHECK (port IS NULL OR (port BETWEEN 0 AND 65535)),
|
|
159
|
+
pathname TEXT,
|
|
160
|
+
params TEXT CHECK (params IS NULL OR json_valid(params)),
|
|
161
|
+
fragment TEXT,
|
|
162
|
+
|
|
163
|
+
lineMarker TEXT CHECK (lineMarker IS NULL OR json_valid(lineMarker)),
|
|
164
|
+
|
|
165
|
+
tx TEXT NOT NULL,
|
|
166
|
+
mimetype_tx TEXT NOT NULL CHECK (length(mimetype_tx) > 0),
|
|
167
|
+
|
|
168
|
+
rx TEXT NOT NULL,
|
|
169
|
+
mimetype_rx TEXT NOT NULL CHECK (length(mimetype_rx) > 0),
|
|
170
|
+
status_rx INTEGER NOT NULL CHECK (status_rx BETWEEN 100 AND 599),
|
|
171
|
+
|
|
172
|
+
tokens INTEGER NOT NULL DEFAULT 0 CHECK (tokens >= 0),
|
|
173
|
+
|
|
174
|
+
state TEXT NOT NULL DEFAULT 'resolved'
|
|
175
|
+
CHECK (state IN ('proposed', 'resolved', 'failed', 'cancelled')),
|
|
176
|
+
outcome TEXT,
|
|
177
|
+
attrs TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attrs)),
|
|
178
|
+
|
|
179
|
+
indexed INTEGER NOT NULL DEFAULT 1 CHECK (indexed IN (0, 1)),
|
|
180
|
+
|
|
181
|
+
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE,
|
|
182
|
+
FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE,
|
|
183
|
+
FOREIGN KEY (turn_id) REFERENCES turns(id) ON DELETE CASCADE
|
|
184
|
+
) STRICT;
|
|
185
|
+
|
|
186
|
+
CREATE UNIQUE INDEX IF NOT EXISTS log_entries_turn_id_sequence ON log_entries (turn_id, sequence);
|
|
187
|
+
CREATE INDEX IF NOT EXISTS log_entries_run_id ON log_entries (run_id);
|
|
188
|
+
CREATE INDEX IF NOT EXISTS log_entries_loop_id ON log_entries (loop_id);
|
|
189
|
+
CREATE INDEX IF NOT EXISTS log_entries_at ON log_entries (at);
|
|
190
|
+
|
|
191
|
+
-- Column-scoped immutability: the original action's identity and target
|
|
192
|
+
-- never change; the proposal lifecycle is allowed to mutate state,
|
|
193
|
+
-- outcome, status_rx, rx, indexed.
|
|
194
|
+
CREATE TRIGGER IF NOT EXISTS log_entries_immutable_core
|
|
195
|
+
BEFORE UPDATE OF
|
|
196
|
+
run_id, loop_id, turn_id, sequence, at, origin,
|
|
197
|
+
op, suffix, signal,
|
|
198
|
+
scheme, username, password, hostname,
|
|
199
|
+
port, pathname, params, fragment,
|
|
200
|
+
lineMarker, tx, mimetype_tx, mimetype_rx, attrs
|
|
201
|
+
ON log_entries
|
|
202
|
+
BEGIN
|
|
203
|
+
SELECT RAISE(ABORT, 'log_entries core fields are immutable; only state/outcome/status_rx/rx/indexed may change');
|
|
204
|
+
END;
|
|
205
|
+
|
|
206
|
+
-- INIT: visibility
|
|
207
|
+
-- Per-(run, entry, channel) visibility for the index. SHOW/HIDE toggle
|
|
208
|
+
-- the indexed bit; render-time queries filter where indexed=1.
|
|
209
|
+
CREATE TABLE IF NOT EXISTS visibility (
|
|
210
|
+
run_id INTEGER NOT NULL,
|
|
211
|
+
entry_id INTEGER NOT NULL,
|
|
212
|
+
channel TEXT NOT NULL CHECK (length(channel) > 0),
|
|
213
|
+
indexed INTEGER NOT NULL DEFAULT 1 CHECK (indexed IN (0, 1)),
|
|
214
|
+
PRIMARY KEY (run_id, entry_id, channel),
|
|
215
|
+
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE,
|
|
216
|
+
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
217
|
+
) STRICT, WITHOUT ROWID;
|
|
218
|
+
|
|
219
|
+
-- INIT: schemes_providers
|
|
220
|
+
-- Scheme/provider catalog. Schemes are static (registered at boot);
|
|
221
|
+
-- providers carry per-model metadata for cost accounting and selection.
|
|
222
|
+
CREATE TABLE IF NOT EXISTS schemes (
|
|
223
|
+
name TEXT NOT NULL PRIMARY KEY CHECK (length(name) > 0),
|
|
224
|
+
model_visible INTEGER NOT NULL CHECK (model_visible IN (0, 1)),
|
|
225
|
+
category TEXT NOT NULL CHECK (length(category) > 0),
|
|
226
|
+
default_scope TEXT NOT NULL CHECK (default_scope IN ('agent', 'session')),
|
|
227
|
+
default_channel TEXT NOT NULL CHECK (length(default_channel) > 0),
|
|
228
|
+
channel_orientations TEXT CHECK (channel_orientations IS NULL OR json_valid(channel_orientations)),
|
|
229
|
+
writable_by TEXT NOT NULL CHECK (json_valid(writable_by)),
|
|
230
|
+
volatile INTEGER NOT NULL CHECK (volatile IN (0, 1)),
|
|
231
|
+
handler TEXT
|
|
232
|
+
) STRICT, WITHOUT ROWID;
|
|
233
|
+
|
|
234
|
+
CREATE TABLE IF NOT EXISTS providers (
|
|
235
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
236
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
237
|
+
provider TEXT NOT NULL CHECK (length(provider) > 0),
|
|
238
|
+
family TEXT NOT NULL CHECK (length(family) > 0),
|
|
239
|
+
model TEXT NOT NULL CHECK (length(model) > 0),
|
|
240
|
+
contextSize INTEGER NOT NULL CHECK (contextSize >= 1),
|
|
241
|
+
currency TEXT NOT NULL CHECK (length(currency) = 3),
|
|
242
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
243
|
+
) STRICT;
|
|
244
|
+
|
|
245
|
+
CREATE INDEX IF NOT EXISTS providers_created_at ON providers (created_at);
|
|
246
|
+
|
|
247
|
+
-- INIT: cost_rollups
|
|
248
|
+
-- Triggers maintaining denormalized cost_pico totals on runs and sessions
|
|
249
|
+
-- as turns insert/update. Pure denormalization (textbook trigger use);
|
|
250
|
+
-- no branching state-machine logic lives here.
|
|
251
|
+
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_insert_run
|
|
252
|
+
AFTER INSERT ON turns
|
|
253
|
+
BEGIN
|
|
254
|
+
UPDATE runs
|
|
255
|
+
SET cost_pico = cost_pico + NEW.usage_cost_pico
|
|
256
|
+
WHERE id = (SELECT run_id FROM loops WHERE id = NEW.loop_id);
|
|
257
|
+
END;
|
|
258
|
+
|
|
259
|
+
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_insert_session
|
|
260
|
+
AFTER INSERT ON turns
|
|
261
|
+
BEGIN
|
|
262
|
+
UPDATE sessions
|
|
263
|
+
SET cost_pico = cost_pico + NEW.usage_cost_pico
|
|
264
|
+
WHERE id = (
|
|
265
|
+
SELECT r.session_id
|
|
266
|
+
FROM runs r
|
|
267
|
+
JOIN loops l ON l.run_id = r.id
|
|
268
|
+
WHERE l.id = NEW.loop_id
|
|
269
|
+
);
|
|
270
|
+
END;
|
|
271
|
+
|
|
272
|
+
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_update_run
|
|
273
|
+
AFTER UPDATE OF usage_cost_pico ON turns
|
|
274
|
+
WHEN NEW.usage_cost_pico != OLD.usage_cost_pico
|
|
275
|
+
BEGIN
|
|
276
|
+
UPDATE runs
|
|
277
|
+
SET cost_pico = cost_pico + NEW.usage_cost_pico - OLD.usage_cost_pico
|
|
278
|
+
WHERE id = (SELECT run_id FROM loops WHERE id = NEW.loop_id);
|
|
279
|
+
END;
|
|
280
|
+
|
|
281
|
+
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_update_session
|
|
282
|
+
AFTER UPDATE OF usage_cost_pico ON turns
|
|
283
|
+
WHEN NEW.usage_cost_pico != OLD.usage_cost_pico
|
|
284
|
+
BEGIN
|
|
285
|
+
UPDATE sessions
|
|
286
|
+
SET cost_pico = cost_pico + NEW.usage_cost_pico - OLD.usage_cost_pico
|
|
287
|
+
WHERE id = (
|
|
288
|
+
SELECT r.session_id
|
|
289
|
+
FROM runs r
|
|
290
|
+
JOIN loops l ON l.run_id = r.id
|
|
291
|
+
WHERE l.id = NEW.loop_id
|
|
292
|
+
);
|
|
293
|
+
END;
|
|
294
|
+
|
|
295
|
+
-- INIT: subscriptions
|
|
296
|
+
-- Subscription registry per SPEC §7.1. Exists ONLY for cancellation
|
|
297
|
+
-- routing (SEND[499] → lookup → scheme teardown). Closed rows persist
|
|
298
|
+
-- for forensics; partial unique index enforces one active subscription
|
|
299
|
+
-- per (run, entry).
|
|
300
|
+
CREATE TABLE IF NOT EXISTS subscriptions (
|
|
301
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
302
|
+
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
303
|
+
run_id INTEGER NOT NULL,
|
|
304
|
+
entry_id INTEGER NOT NULL,
|
|
305
|
+
scheme TEXT NOT NULL CHECK (length(scheme) > 0),
|
|
306
|
+
handle TEXT NOT NULL CHECK (length(handle) > 0),
|
|
307
|
+
opened_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
308
|
+
closed_at TEXT,
|
|
309
|
+
close_status INTEGER CHECK (close_status IS NULL OR (close_status BETWEEN 100 AND 599)),
|
|
310
|
+
CHECK ((closed_at IS NULL AND close_status IS NULL)
|
|
311
|
+
OR (closed_at IS NOT NULL AND close_status IS NOT NULL)),
|
|
312
|
+
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE,
|
|
313
|
+
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
314
|
+
) STRICT;
|
|
315
|
+
|
|
316
|
+
CREATE UNIQUE INDEX IF NOT EXISTS subscriptions_active_one_per_entry
|
|
317
|
+
ON subscriptions (run_id, entry_id)
|
|
318
|
+
WHERE closed_at IS NULL;
|
|
319
|
+
|
|
320
|
+
CREATE INDEX IF NOT EXISTS subscriptions_scheme_active
|
|
321
|
+
ON subscriptions (scheme)
|
|
322
|
+
WHERE closed_at IS NULL;
|
|
323
|
+
|
|
324
|
+
CREATE INDEX IF NOT EXISTS subscriptions_opened_at ON subscriptions (opened_at);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-service",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Plurnk agent runtime — the server / engine / core. Implements the @plurnk/plurnk-grammar contract.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"test:lint": "tsc --noEmit",
|
|
33
|
-
"test:unit": "node --test src/**/*.test.ts",
|
|
34
|
-
"test:intg": "node --env-file-if-exists=.env --test test/intg/*.test.ts",
|
|
35
|
-
"test:live": "node --env-file-if-exists=.env --test test/live/*.test.ts",
|
|
36
|
-
"test:demo": "node --env-file-if-exists=.env --test test/demo/*.test.ts",
|
|
33
|
+
"test:unit": "node --env-file-if-exists=.env.example --env-file-if-exists=.env --env-file-if-exists=.env.test --test src/**/*.test.ts",
|
|
34
|
+
"test:intg": "node --env-file-if-exists=.env.example --env-file-if-exists=.env --env-file-if-exists=.env.test --test test/intg/*.test.ts",
|
|
35
|
+
"test:live": "node --env-file-if-exists=.env.example --env-file-if-exists=.env --env-file-if-exists=.env.test --test test/live/*.test.ts",
|
|
36
|
+
"test:demo": "node --env-file-if-exists=.env.example --env-file-if-exists=.env --env-file-if-exists=.env.test --test test/demo/*.test.ts",
|
|
37
37
|
"test:all": "npm run test:lint && npm run test:unit && npm run test:intg && npm run test:demo",
|
|
38
38
|
"test:digest": "node bin/digest.js",
|
|
39
39
|
"dev:digest": "node bin/digest.js",
|
|
@@ -42,17 +42,23 @@
|
|
|
42
42
|
"prepare": "npm run build"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@plurnk/plurnk-grammar": "^0.
|
|
45
|
+
"@plurnk/plurnk-grammar": "^0.9.0",
|
|
46
46
|
"@plurnk/plurnk-mimetypes": "^0.3.1",
|
|
47
47
|
"@plurnk/plurnk-mimetypes-application-json": "^0.2.0",
|
|
48
|
+
"@plurnk/plurnk-mimetypes-application-pdf": "^0.3.0",
|
|
49
|
+
"@plurnk/plurnk-mimetypes-application-toml": "^0.1.0",
|
|
50
|
+
"@plurnk/plurnk-mimetypes-application-yaml": "^0.1.0",
|
|
51
|
+
"@plurnk/plurnk-mimetypes-text-csv": "^0.1.0",
|
|
52
|
+
"@plurnk/plurnk-mimetypes-text-html": "^0.1.0",
|
|
48
53
|
"@plurnk/plurnk-mimetypes-text-markdown": "^0.2.0",
|
|
49
54
|
"@plurnk/plurnk-mimetypes-text-plain": "^0.2.0",
|
|
50
|
-
"@plurnk/plurnk-
|
|
51
|
-
"@plurnk/plurnk-providers-
|
|
52
|
-
"@plurnk/plurnk-providers-
|
|
53
|
-
"@plurnk/plurnk-providers-
|
|
54
|
-
"@plurnk/plurnk-providers-
|
|
55
|
-
"@plurnk/plurnk-providers-
|
|
55
|
+
"@plurnk/plurnk-mimetypes-text-typescript": "^0.1.0",
|
|
56
|
+
"@plurnk/plurnk-providers-cloudflare": "^0.2.0",
|
|
57
|
+
"@plurnk/plurnk-providers-google": "^0.2.0",
|
|
58
|
+
"@plurnk/plurnk-providers-ollama": "^0.2.0",
|
|
59
|
+
"@plurnk/plurnk-providers-openai": "^0.2.0",
|
|
60
|
+
"@plurnk/plurnk-providers-openrouter": "^0.2.0",
|
|
61
|
+
"@plurnk/plurnk-providers-xai": "^0.2.0",
|
|
56
62
|
"@possumtech/sqlrite": "^3.1.0",
|
|
57
63
|
"diff": "^7.0.0",
|
|
58
64
|
"ws": "^8.20.1"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
-- INIT: sessions
|
|
2
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
3
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
4
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
5
|
-
name TEXT NOT NULL UNIQUE CHECK (length(name) > 0),
|
|
6
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
7
|
-
cost_pico INTEGER NOT NULL DEFAULT 0 CHECK (cost_pico >= 0),
|
|
8
|
-
scheme_registry_additions TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(scheme_registry_additions))
|
|
9
|
-
) STRICT;
|
|
10
|
-
|
|
11
|
-
CREATE INDEX IF NOT EXISTS sessions_created_at ON sessions (created_at);
|
package/migrations/002_runs.sql
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
-- INIT: runs
|
|
2
|
-
CREATE TABLE IF NOT EXISTS runs (
|
|
3
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
4
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
5
|
-
session_id INTEGER NOT NULL,
|
|
6
|
-
name TEXT NOT NULL CHECK (length(name) > 0),
|
|
7
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
8
|
-
parent_run_id INTEGER CHECK (parent_run_id IS NULL OR parent_run_id != id),
|
|
9
|
-
cost_pico INTEGER NOT NULL DEFAULT 0 CHECK (cost_pico >= 0),
|
|
10
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,
|
|
11
|
-
FOREIGN KEY (parent_run_id) REFERENCES runs(id) ON DELETE CASCADE
|
|
12
|
-
) STRICT;
|
|
13
|
-
|
|
14
|
-
CREATE INDEX IF NOT EXISTS runs_session_id_created_at ON runs (session_id, created_at);
|
|
15
|
-
CREATE INDEX IF NOT EXISTS runs_parent_run_id ON runs (parent_run_id);
|
|
16
|
-
CREATE UNIQUE INDEX IF NOT EXISTS runs_session_name ON runs (session_id, name);
|
package/migrations/003_loops.sql
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
-- INIT: loops
|
|
2
|
-
CREATE TABLE IF NOT EXISTS loops (
|
|
3
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
4
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
5
|
-
run_id INTEGER NOT NULL,
|
|
6
|
-
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
7
|
-
status INTEGER NOT NULL DEFAULT 102 CHECK (status IN (102, 200, 499)),
|
|
8
|
-
prompt TEXT NOT NULL,
|
|
9
|
-
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE
|
|
10
|
-
) STRICT;
|
|
11
|
-
|
|
12
|
-
CREATE UNIQUE INDEX IF NOT EXISTS loops_run_id_sequence ON loops (run_id, sequence);
|
package/migrations/004_turns.sql
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
-- INIT: turns
|
|
2
|
-
CREATE TABLE IF NOT EXISTS turns (
|
|
3
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
4
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
5
|
-
loop_id INTEGER NOT NULL,
|
|
6
|
-
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
7
|
-
timestamp TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
8
|
-
status INTEGER NOT NULL CHECK (status BETWEEN 100 AND 599),
|
|
9
|
-
usage_prompt INTEGER NOT NULL DEFAULT 0 CHECK (usage_prompt >= 0),
|
|
10
|
-
usage_completion INTEGER NOT NULL DEFAULT 0 CHECK (usage_completion >= 0),
|
|
11
|
-
usage_cached INTEGER NOT NULL DEFAULT 0 CHECK (usage_cached >= 0),
|
|
12
|
-
usage_cost_pico INTEGER NOT NULL DEFAULT 0 CHECK (usage_cost_pico >= 0),
|
|
13
|
-
packet TEXT NOT NULL CHECK (json_valid(packet)),
|
|
14
|
-
FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE
|
|
15
|
-
) STRICT;
|
|
16
|
-
|
|
17
|
-
CREATE UNIQUE INDEX IF NOT EXISTS turns_loop_id_sequence ON turns (loop_id, sequence);
|
|
18
|
-
CREATE INDEX IF NOT EXISTS turns_timestamp ON turns (timestamp);
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
-- INIT: entries
|
|
2
|
-
CREATE TABLE IF NOT EXISTS entries (
|
|
3
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
4
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
5
|
-
scope TEXT NOT NULL CHECK (scope IN ('agent', 'session')),
|
|
6
|
-
session_id INTEGER,
|
|
7
|
-
scheme TEXT CHECK (scheme IS NULL OR length(scheme) > 0),
|
|
8
|
-
username TEXT,
|
|
9
|
-
password TEXT,
|
|
10
|
-
hostname TEXT,
|
|
11
|
-
port INTEGER CHECK (port IS NULL OR (port BETWEEN 0 AND 65535)),
|
|
12
|
-
pathname TEXT NOT NULL,
|
|
13
|
-
params TEXT CHECK (params IS NULL OR json_valid(params)),
|
|
14
|
-
attributes TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attributes)),
|
|
15
|
-
CHECK ((scope = 'agent' AND session_id IS NULL)
|
|
16
|
-
OR (scope = 'session' AND session_id IS NOT NULL)),
|
|
17
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
18
|
-
) STRICT;
|
|
19
|
-
|
|
20
|
-
CREATE UNIQUE INDEX IF NOT EXISTS entries_agent_identity ON entries (scheme, pathname) WHERE scope = 'agent';
|
|
21
|
-
CREATE UNIQUE INDEX IF NOT EXISTS entries_session_identity ON entries (session_id, scheme, pathname) WHERE scope = 'session';
|
|
22
|
-
|
|
23
|
-
-- SPEC §7.8: the ONE engine-imposed constraint — 100 MiB char-length cap per
|
|
24
|
-
-- channel content body. All other limits (rate, burst, per-call budget, etc.)
|
|
25
|
-
-- are extrinsic — providers, schemes, and mimetypes own their own constraints.
|
|
26
|
-
CREATE TABLE IF NOT EXISTS entry_channels (
|
|
27
|
-
entry_id INTEGER NOT NULL,
|
|
28
|
-
name TEXT NOT NULL CHECK (length(name) > 0),
|
|
29
|
-
content TEXT NOT NULL CHECK (length(content) <= 104857600),
|
|
30
|
-
mimetype TEXT NOT NULL CHECK (length(mimetype) > 0),
|
|
31
|
-
tokens INTEGER NOT NULL DEFAULT 0 CHECK (tokens >= 0),
|
|
32
|
-
state TEXT NOT NULL DEFAULT 'static' CHECK (state IN ('static', 'active', 'closed', 'errored')),
|
|
33
|
-
PRIMARY KEY (entry_id, name),
|
|
34
|
-
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
35
|
-
) STRICT, WITHOUT ROWID;
|
|
36
|
-
|
|
37
|
-
CREATE TABLE IF NOT EXISTS entry_tags (
|
|
38
|
-
entry_id INTEGER NOT NULL,
|
|
39
|
-
tag TEXT NOT NULL CHECK (length(tag) > 0),
|
|
40
|
-
PRIMARY KEY (entry_id, tag),
|
|
41
|
-
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
42
|
-
) STRICT, WITHOUT ROWID;
|
|
43
|
-
|
|
44
|
-
CREATE INDEX IF NOT EXISTS entry_tags_tag ON entry_tags (tag);
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
-- INIT: log_entries
|
|
2
|
-
CREATE TABLE IF NOT EXISTS log_entries (
|
|
3
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
4
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
5
|
-
|
|
6
|
-
run_id INTEGER NOT NULL,
|
|
7
|
-
loop_id INTEGER NOT NULL,
|
|
8
|
-
turn_id INTEGER NOT NULL,
|
|
9
|
-
action_index INTEGER NOT NULL CHECK (action_index >= 0),
|
|
10
|
-
at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
11
|
-
origin TEXT NOT NULL CHECK (origin IN ('model', 'client', 'system', 'plugin')),
|
|
12
|
-
|
|
13
|
-
op TEXT NOT NULL CHECK (op IN ('FIND', 'READ', 'EDIT', 'COPY', 'MOVE', 'SHOW', 'HIDE', 'SEND', 'EXEC')),
|
|
14
|
-
suffix TEXT NOT NULL DEFAULT '',
|
|
15
|
-
signal TEXT CHECK (signal IS NULL OR json_valid(signal)),
|
|
16
|
-
|
|
17
|
-
target_scheme TEXT CHECK (target_scheme IS NULL OR length(target_scheme) > 0),
|
|
18
|
-
target_username TEXT,
|
|
19
|
-
target_password TEXT,
|
|
20
|
-
target_hostname TEXT,
|
|
21
|
-
target_port INTEGER CHECK (target_port IS NULL OR (target_port BETWEEN 0 AND 65535)),
|
|
22
|
-
target_pathname TEXT,
|
|
23
|
-
target_params TEXT CHECK (target_params IS NULL OR json_valid(target_params)),
|
|
24
|
-
target_fragment TEXT,
|
|
25
|
-
|
|
26
|
-
lineMarker TEXT CHECK (lineMarker IS NULL OR json_valid(lineMarker)),
|
|
27
|
-
|
|
28
|
-
tx TEXT NOT NULL,
|
|
29
|
-
mimetype_tx TEXT NOT NULL CHECK (length(mimetype_tx) > 0),
|
|
30
|
-
|
|
31
|
-
rx TEXT NOT NULL,
|
|
32
|
-
mimetype_rx TEXT NOT NULL CHECK (length(mimetype_rx) > 0),
|
|
33
|
-
status_rx INTEGER NOT NULL CHECK (status_rx BETWEEN 100 AND 599),
|
|
34
|
-
|
|
35
|
-
tokens INTEGER NOT NULL DEFAULT 0 CHECK (tokens >= 0),
|
|
36
|
-
|
|
37
|
-
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE,
|
|
38
|
-
FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE,
|
|
39
|
-
FOREIGN KEY (turn_id) REFERENCES turns(id) ON DELETE CASCADE
|
|
40
|
-
) STRICT;
|
|
41
|
-
|
|
42
|
-
CREATE UNIQUE INDEX IF NOT EXISTS log_entries_turn_id_action_index ON log_entries (turn_id, action_index);
|
|
43
|
-
CREATE INDEX IF NOT EXISTS log_entries_run_id ON log_entries (run_id);
|
|
44
|
-
CREATE INDEX IF NOT EXISTS log_entries_loop_id ON log_entries (loop_id);
|
|
45
|
-
CREATE INDEX IF NOT EXISTS log_entries_at ON log_entries (at);
|
|
46
|
-
|
|
47
|
-
CREATE TRIGGER IF NOT EXISTS log_entries_immutable
|
|
48
|
-
BEFORE UPDATE ON log_entries
|
|
49
|
-
BEGIN
|
|
50
|
-
SELECT RAISE(ABORT, 'log_entries are append-only; INSERT new rows instead of UPDATE');
|
|
51
|
-
END;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
-- INIT: visibility
|
|
2
|
-
CREATE TABLE IF NOT EXISTS visibility (
|
|
3
|
-
run_id INTEGER NOT NULL,
|
|
4
|
-
entry_id INTEGER NOT NULL,
|
|
5
|
-
channel TEXT NOT NULL CHECK (length(channel) > 0),
|
|
6
|
-
indexed INTEGER NOT NULL DEFAULT 1 CHECK (indexed IN (0, 1)),
|
|
7
|
-
PRIMARY KEY (run_id, entry_id, channel),
|
|
8
|
-
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE,
|
|
9
|
-
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
10
|
-
) STRICT, WITHOUT ROWID;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
-- INIT: schemes_providers
|
|
2
|
-
CREATE TABLE IF NOT EXISTS schemes (
|
|
3
|
-
name TEXT NOT NULL PRIMARY KEY CHECK (length(name) > 0),
|
|
4
|
-
model_visible INTEGER NOT NULL CHECK (model_visible IN (0, 1)),
|
|
5
|
-
category TEXT NOT NULL CHECK (length(category) > 0),
|
|
6
|
-
default_scope TEXT NOT NULL CHECK (default_scope IN ('agent', 'session')),
|
|
7
|
-
default_channel TEXT NOT NULL CHECK (length(default_channel) > 0),
|
|
8
|
-
channel_orientations TEXT CHECK (channel_orientations IS NULL OR json_valid(channel_orientations)),
|
|
9
|
-
writable_by TEXT NOT NULL CHECK (json_valid(writable_by)),
|
|
10
|
-
volatile INTEGER NOT NULL CHECK (volatile IN (0, 1)),
|
|
11
|
-
handler TEXT
|
|
12
|
-
) STRICT, WITHOUT ROWID;
|
|
13
|
-
|
|
14
|
-
CREATE TABLE IF NOT EXISTS providers (
|
|
15
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
16
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
17
|
-
provider TEXT NOT NULL CHECK (length(provider) > 0),
|
|
18
|
-
family TEXT NOT NULL CHECK (length(family) > 0),
|
|
19
|
-
model TEXT NOT NULL CHECK (length(model) > 0),
|
|
20
|
-
contextSize INTEGER NOT NULL CHECK (contextSize >= 1),
|
|
21
|
-
currency TEXT NOT NULL CHECK (length(currency) = 3),
|
|
22
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
23
|
-
) STRICT;
|
|
24
|
-
|
|
25
|
-
CREATE INDEX IF NOT EXISTS providers_created_at ON providers (created_at);
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
-- INIT: cost_rollups
|
|
2
|
-
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_insert_run
|
|
3
|
-
AFTER INSERT ON turns
|
|
4
|
-
BEGIN
|
|
5
|
-
UPDATE runs
|
|
6
|
-
SET cost_pico = cost_pico + NEW.usage_cost_pico
|
|
7
|
-
WHERE id = (SELECT run_id FROM loops WHERE id = NEW.loop_id);
|
|
8
|
-
END;
|
|
9
|
-
|
|
10
|
-
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_insert_session
|
|
11
|
-
AFTER INSERT ON turns
|
|
12
|
-
BEGIN
|
|
13
|
-
UPDATE sessions
|
|
14
|
-
SET cost_pico = cost_pico + NEW.usage_cost_pico
|
|
15
|
-
WHERE id = (
|
|
16
|
-
SELECT r.session_id
|
|
17
|
-
FROM runs r
|
|
18
|
-
JOIN loops l ON l.run_id = r.id
|
|
19
|
-
WHERE l.id = NEW.loop_id
|
|
20
|
-
);
|
|
21
|
-
END;
|
|
22
|
-
|
|
23
|
-
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_update_run
|
|
24
|
-
AFTER UPDATE OF usage_cost_pico ON turns
|
|
25
|
-
WHEN NEW.usage_cost_pico != OLD.usage_cost_pico
|
|
26
|
-
BEGIN
|
|
27
|
-
UPDATE runs
|
|
28
|
-
SET cost_pico = cost_pico + NEW.usage_cost_pico - OLD.usage_cost_pico
|
|
29
|
-
WHERE id = (SELECT run_id FROM loops WHERE id = NEW.loop_id);
|
|
30
|
-
END;
|
|
31
|
-
|
|
32
|
-
CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_update_session
|
|
33
|
-
AFTER UPDATE OF usage_cost_pico ON turns
|
|
34
|
-
WHEN NEW.usage_cost_pico != OLD.usage_cost_pico
|
|
35
|
-
BEGIN
|
|
36
|
-
UPDATE sessions
|
|
37
|
-
SET cost_pico = cost_pico + NEW.usage_cost_pico - OLD.usage_cost_pico
|
|
38
|
-
WHERE id = (
|
|
39
|
-
SELECT r.session_id
|
|
40
|
-
FROM runs r
|
|
41
|
-
JOIN loops l ON l.run_id = r.id
|
|
42
|
-
WHERE l.id = NEW.loop_id
|
|
43
|
-
);
|
|
44
|
-
END;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
-- Subscription registry per SPEC §7.1.
|
|
2
|
-
-- Exists ONLY for cancellation routing: SEND[499](path) → lookup → scheme teardown.
|
|
3
|
-
-- Not for lifecycle tracking (log_entries carry that) or state coordination
|
|
4
|
-
-- (channel state column carries that).
|
|
5
|
-
-- Closed rows persist for forensics. Partial unique index enforces one active
|
|
6
|
-
-- subscription per (run, entry).
|
|
7
|
-
|
|
8
|
-
-- INIT: subscriptions
|
|
9
|
-
CREATE TABLE IF NOT EXISTS subscriptions (
|
|
10
|
-
id INTEGER NOT NULL PRIMARY KEY,
|
|
11
|
-
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
12
|
-
run_id INTEGER NOT NULL,
|
|
13
|
-
entry_id INTEGER NOT NULL,
|
|
14
|
-
scheme TEXT NOT NULL CHECK (length(scheme) > 0),
|
|
15
|
-
handle TEXT NOT NULL CHECK (length(handle) > 0),
|
|
16
|
-
opened_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
17
|
-
closed_at TEXT,
|
|
18
|
-
close_status INTEGER CHECK (close_status IS NULL OR (close_status BETWEEN 100 AND 599)),
|
|
19
|
-
CHECK ((closed_at IS NULL AND close_status IS NULL)
|
|
20
|
-
OR (closed_at IS NOT NULL AND close_status IS NOT NULL)),
|
|
21
|
-
FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE,
|
|
22
|
-
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
23
|
-
) STRICT;
|
|
24
|
-
|
|
25
|
-
-- One active subscription per (run_id, entry_id) — closed records don't block re-subscription.
|
|
26
|
-
CREATE UNIQUE INDEX IF NOT EXISTS subscriptions_active_one_per_entry
|
|
27
|
-
ON subscriptions (run_id, entry_id)
|
|
28
|
-
WHERE closed_at IS NULL;
|
|
29
|
-
|
|
30
|
-
-- Scheme-keyed lookup for "which scheme owns active subscriptions?" queries.
|
|
31
|
-
CREATE INDEX IF NOT EXISTS subscriptions_scheme_active
|
|
32
|
-
ON subscriptions (scheme)
|
|
33
|
-
WHERE closed_at IS NULL;
|
|
34
|
-
|
|
35
|
-
-- Forensic / time-window queries on opened_at.
|
|
36
|
-
CREATE INDEX IF NOT EXISTS subscriptions_opened_at ON subscriptions (opened_at);
|