@aria-cli/cli 1.0.15 → 1.0.19
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/README.md +56 -0
- package/bin/aria-dev.js +1 -14
- package/bin/aria.js +13 -365
- package/bin/install-owner-lease.js +1 -53
- package/dist/.aria-build-stamp.json +1 -1
- package/dist/cli-context.js +1 -1
- package/dist/commands/index.js +356 -1
- package/dist/config.js +1 -1
- package/dist/ensure-daemon.js +4 -1
- package/dist/history/index.js +321 -1
- package/dist/index.js +503 -1
- package/dist/ink-repl.js +491 -1
- package/dist/local-control-client.js +4 -1
- package/dist/release-notes.d.ts +1 -1
- package/dist/repl-cleanup.js +1 -1
- package/dist/session.js +1 -1
- package/package.json +30 -28
- package/dist/attached-local-control-client-2jz8vmjb.js +0 -1
- package/dist/daemon-service-esj85cr7.js +0 -1
- package/dist/index-00jaxgt2.js +0 -2
- package/dist/index-5v7br509.js +0 -2
- package/dist/index-718zvjhe.js +0 -12
- package/dist/index-76vaj0sr.js +0 -321
- package/dist/index-92syx5hd.js +0 -149
- package/dist/index-9j6r3gr8.js +0 -2
- package/dist/index-g5devafm.js +0 -0
- package/dist/index-j035n0mr.js +0 -2
- package/dist/index-nnqfqvqh.js +0 -2
- package/dist/index-sx36201d.js +0 -5
- package/dist/index-sxga6d5s.js +0 -2
- package/dist/index-wbm34jf5.js +0 -24
- package/dist/index-xjwfqz7t.js +0 -2
- package/dist/index-y2vy5jks.js +0 -4
- package/dist/kernel-0tytvcv0.js +0 -1
- package/dist/runtime-cutover-reset-0nywfrh6.js +0 -1
- package/dist/session-ybzq2j2n.js +0 -1
package/dist/index-76vaj0sr.js
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import s from"better-sqlite3";import p from"node:crypto";import{existsSync as P,copyFileSync as JJ,mkdirSync as C,readdirSync as KJ}from"node:fs";import j from"node:path";import{log as O}from"@aria-cli/types";var VJ=2000;var N=globalThis;function x(J){N.__aria_stall_phase=J,N.__aria_stall_phase_ts=performance.now()}function M(){N.__aria_stall_phase=void 0,N.__aria_stall_phase_ts=void 0}function FJ(){let{__aria_stall_phase:J,__aria_stall_phase_ts:K}=N;if(!J||typeof K!=="number")return;return{label:J,ageMs:performance.now()-K}}function GJ(J){let K=J.thresholdMs??2000,X=performance.now(),Y=process.cpuUsage(),Z=setInterval(()=>{let W=performance.now(),$=W-X,Q=process.cpuUsage(Y);if(X=W,Y=process.cpuUsage(),$>K)if((Q.user+Q.system)/1000/$<0.05)J.onSleep?.($);else J.onStall($)},500);if(typeof Z==="object"&&Z!==null&&"unref"in Z)Z.unref();return()=>clearInterval(Z)}import{z as H}from"zod";import{log as h}from"@aria-cli/types";var g=H.object({type:H.literal("text"),text:H.string()}),m=H.object({type:H.literal("thinking"),content:H.string(),wordCount:H.number(),durationMs:H.number().optional(),verb:H.string().optional()}),d=H.object({type:H.literal("tool_use"),id:H.string(),name:H.string(),arguments:H.record(H.string(),H.unknown()),thoughtSignature:H.string().optional()}),c=H.object({type:H.literal("tool_result"),toolUseId:H.string(),content:H.string(),status:H.enum(["success","error"]),durationMs:H.number().optional(),resultData:H.unknown().optional(),usage:H.object({inputTokens:H.number(),outputTokens:H.number(),totalTokens:H.number(),estimatedCost:H.number()}).optional()}),w=H.object({type:H.literal("handoff"),target:H.string(),direction:H.enum(["to","from"])}),a=H.object({type:H.literal("error"),content:H.string(),suggestion:H.string().optional()}),f=H.discriminatedUnion("type",[g,m,d,c,w,a]),l=["cyan","magenta","yellow","green","blue","red","white"],v=H.object({name:H.string(),emoji:H.string(),color:H.enum(l).optional()}),T=H.object({id:H.string(),role:H.enum(["user","assistant","system","tool"]),content:H.array(f),arion:v.optional(),costUSD:H.number().optional(),durationMs:H.number().optional(),tokenUsage:H.object({input:H.number(),output:H.number()}).optional(),createdAt:H.string()});function R(J){return{id:crypto.randomUUID(),role:"user",content:[{type:"text",text:J}],createdAt:new Date().toISOString()}}function i(J){return{id:crypto.randomUUID(),role:"system",content:[{type:"text",text:J}],createdAt:new Date().toISOString()}}function n(J,K,X,Y){let Z=`synthetic_inbox_${crypto.randomUUID().slice(0,8)}`,W=new Date().toISOString(),$={id:crypto.randomUUID(),role:"assistant",content:[{type:"tool_use",id:Z,name:"check_messages",arguments:{unreadOnly:!0}}],createdAt:W},Q={id:crypto.randomUUID(),role:"tool",content:[{type:"tool_result",toolUseId:Z,content:JSON.stringify({messages:[{id:Y||crypto.randomUUID(),from:J,address:K,content:X,type:"incoming"}]}),status:"success"}],createdAt:W};return[$,Q]}function r(J,K){return{id:crypto.randomUUID(),role:"system",content:[{type:"error",content:J,...K?{suggestion:K}:{}}],createdAt:new Date().toISOString()}}function t(J){let K=[];for(let X of J)switch(X.role){case"assistant":{let Y=[],Z=[];for(let $ of X.content)if($.type==="text")Y.push($.text);else if($.type==="tool_use")Z.push({id:$.id,name:$.name,arguments:$.arguments,...$.thoughtSignature?{thoughtSignature:$.thoughtSignature}:{}});let W={role:"assistant",content:Y.join("")};if(Z.length>0)W.toolCalls=Z;K.push(W);break}case"tool":{for(let Y of X.content)if(Y.type==="tool_result")K.push({role:"tool",content:Y.content,toolCallId:Y.toolUseId});break}case"user":case"system":{let Y=[];for(let Z of X.content)if(Z.type==="text")Y.push(Z.text);K.push({role:X.role,content:Y.join("")});break}}return K}function e(J,K){let X=[];for(let Y of J){let Z=[],W=Y;if(W.thinking)for(let $ of W.thinking){let Q=$.thinking?$.thinking.split(/\s+/).filter(Boolean).length:0;Z.push({type:"thinking",content:$.thinking,wordCount:Q})}if(Y.role==="assistant"&&Y.toolCalls){if(Y.content)Z.push({type:"text",text:Y.content});for(let $ of Y.toolCalls)Z.push({type:"tool_use",id:$.id,name:$.name,arguments:$.arguments,...$.thoughtSignature?{thoughtSignature:$.thoughtSignature}:{}})}else if(Y.role==="tool")Z.push({type:"tool_result",toolUseId:Y.toolCallId??"",content:Y.content,status:"success"});else if(Y.content)Z.push({type:"text",text:Y.content});if(Z.length===0)Z.push({type:"text",text:""});X.push({id:crypto.randomUUID(),role:Y.role,content:Z,arion:K?.arion,createdAt:new Date().toISOString()})}return X}function B(J){let K=[];if(J.thinking)try{let X=JSON.parse(J.thinking);for(let Y of X)K.push({type:"thinking",content:Y.content??"",wordCount:Y.wordCount??0})}catch{h.warn(`[fromV1Columns] Corrupted thinking JSON in message row ${J.id} (session ${J.session_id}), skipping`)}if(J.tool_calls)try{let X=JSON.parse(J.tool_calls);for(let Y of X)K.push({type:"tool_use",id:Y.id,name:Y.name,arguments:Y.arguments??{},...Y.thoughtSignature?{thoughtSignature:Y.thoughtSignature}:{}})}catch{h.warn(`[fromV1Columns] Corrupted tool_calls JSON in message row ${J.id} (session ${J.session_id}), skipping`)}if(J.role==="tool"&&J.tool_call_id)K.push({type:"tool_result",toolUseId:J.tool_call_id,content:J.content,status:"success"});if(J.role!=="tool"&&J.content)K.push({type:"text",text:J.content});return{id:crypto.randomUUID(),role:J.role,content:K.length>0?K:[{type:"text",text:J.content??""}],arion:J.arion?{name:J.arion,emoji:"",color:void 0}:void 0,createdAt:J.created_at}}function o(J){let K=[];for(let X of J)for(let Y of X.content)switch(Y.type){case"thinking":K.push({id:`thinking-${crypto.randomUUID()}`,role:"thinking_history",content:Y.content,wordCount:Y.wordCount,durationSeconds:Y.durationMs?Y.durationMs/1000:void 0,verb:Y.verb,arionName:X.arion?.name,arionEmoji:X.arion?.emoji,arionColor:X.arion?.color});break;case"tool_use":K.push({id:`tool-${crypto.randomUUID()}`,role:"tool_history",tool:{id:Y.id,name:Y.name,status:"complete",args:Y.arguments,result:void 0,startTime:void 0,endTime:void 0}});break;case"tool_result":{let Z;for(let W=K.length-1;W>=0;W--){let $=K[W];if($.role==="tool_history"&&$.tool.id===Y.toolUseId){Z=$;break}}if(Z){if(Z.tool.status=Y.status==="error"?"error":"complete",Y.status==="error")Z.tool.error=Y.content;else Z.tool.result=Y.content;if(Y.resultData!==void 0)Z.tool.resultData=Y.resultData;if(Y.durationMs!==void 0)Z.tool.durationMs=Y.durationMs;if(Y.usage!==void 0)Z.tool.usage=Y.usage}break}case"handoff":K.push({id:`handoff-${crypto.randomUUID()}`,role:"handoff_history",target:Y.target,direction:Y.direction});break;case"error":K.push({id:`error-${crypto.randomUUID()}`,role:"error",content:Y.content,suggestion:Y.suggestion});break;case"text":K.push({id:`msg-${crypto.randomUUID()}`,role:X.role,content:Y.text,arion:X.arion?{name:X.arion.name,emoji:X.arion.emoji,color:X.arion.color}:void 0});break}return K}function L(J){return J.content.filter((K)=>K.type==="text").map((K)=>K.text).join("")}function U(J){let K=J.content.filter((X)=>X.type==="tool_use");if(K.length===0)return null;return JSON.stringify(K.map((X)=>({id:X.id,name:X.name,arguments:X.arguments,...X.thoughtSignature?{thoughtSignature:X.thoughtSignature}:{}})))}function S(J){let K=J.content.filter((X)=>X.type==="thinking");if(K.length===0)return null;return JSON.stringify(K.map((X)=>({id:crypto.randomUUID(),content:X.content,wordCount:X.wordCount})))}function q(J){for(let K of J.content)if(K.type==="tool_result")return K.toolUseId;return null}class k{db;sessionFtsEnabled=!1;incrementalSessions=new Set;static resolvePerArionPath(J,K){let X=j.join(J,"arions",K),Y=j.join(X,"history.db");if(!P(Y))C(X,{recursive:!0});return Y}static migrateJsonlLogs(J,K){let X=j.join(J,"arions",K,"logs"),Y=j.join(J,"logs");if(!P(X)&&P(Y)){C(X,{recursive:!0});try{let Z=KJ(Y).filter((W)=>W.endsWith(".jsonl"));for(let W of Z){let $=j.join(Y,W),Q=j.join(X,W);if(!P(Q))JJ($,Q)}}catch{}}if(!P(X))C(X,{recursive:!0});return X}constructor(J){this.db=new s(J),this.db.pragma("journal_mode = WAL"),this.db.pragma("busy_timeout = 5000"),this.db.pragma("foreign_keys = ON"),this.initialize()}initialize(){this.db.exec(`
|
|
2
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
3
|
-
id TEXT PRIMARY KEY,
|
|
4
|
-
created_at TEXT NOT NULL,
|
|
5
|
-
updated_at TEXT NOT NULL,
|
|
6
|
-
completed_at TEXT,
|
|
7
|
-
title TEXT,
|
|
8
|
-
arion TEXT NOT NULL,
|
|
9
|
-
model TEXT NOT NULL,
|
|
10
|
-
message_count INTEGER DEFAULT 0
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
14
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
15
|
-
session_id TEXT NOT NULL,
|
|
16
|
-
role TEXT NOT NULL,
|
|
17
|
-
content TEXT NOT NULL,
|
|
18
|
-
arion TEXT,
|
|
19
|
-
created_at TEXT NOT NULL,
|
|
20
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
CREATE TABLE IF NOT EXISTS input_history (
|
|
24
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
25
|
-
content TEXT NOT NULL UNIQUE,
|
|
26
|
-
used_at TEXT NOT NULL
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
|
|
30
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
|
|
31
|
-
CREATE INDEX IF NOT EXISTS idx_input_history_used ON input_history(used_at DESC);
|
|
32
|
-
`);try{this.db.exec("ALTER TABLE sessions ADD COLUMN completed_at TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN tool_call_id TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN tool_calls TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN thinking TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN data TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}this.db.exec(`
|
|
33
|
-
CREATE TABLE IF NOT EXISTS run_metrics (
|
|
34
|
-
id TEXT PRIMARY KEY,
|
|
35
|
-
session_id TEXT NOT NULL,
|
|
36
|
-
turn_count INTEGER,
|
|
37
|
-
input_tokens INTEGER,
|
|
38
|
-
output_tokens INTEGER,
|
|
39
|
-
total_tokens INTEGER,
|
|
40
|
-
estimated_cost REAL,
|
|
41
|
-
wall_time_ms INTEGER,
|
|
42
|
-
tool_count INTEGER,
|
|
43
|
-
guardrail_fires INTEGER,
|
|
44
|
-
handoff_count INTEGER,
|
|
45
|
-
created_at TEXT DEFAULT (datetime('now')),
|
|
46
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
CREATE INDEX IF NOT EXISTS idx_run_metrics_session ON run_metrics(session_id);
|
|
50
|
-
`),this.db.exec(`
|
|
51
|
-
CREATE TABLE IF NOT EXISTS session_runtime_state (
|
|
52
|
-
session_id TEXT PRIMARY KEY,
|
|
53
|
-
state_status TEXT NOT NULL DEFAULT 'idle',
|
|
54
|
-
active_run_id TEXT,
|
|
55
|
-
paused_state_json TEXT,
|
|
56
|
-
policy_snapshot_json TEXT,
|
|
57
|
-
last_event_seq INTEGER NOT NULL DEFAULT 0,
|
|
58
|
-
revision INTEGER NOT NULL DEFAULT 0,
|
|
59
|
-
lease_owner TEXT,
|
|
60
|
-
lease_expires_at TEXT,
|
|
61
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
62
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
CREATE TABLE IF NOT EXISTS session_interactions (
|
|
66
|
-
interaction_id TEXT PRIMARY KEY,
|
|
67
|
-
session_id TEXT NOT NULL,
|
|
68
|
-
request_id TEXT NOT NULL,
|
|
69
|
-
source TEXT NOT NULL,
|
|
70
|
-
kind TEXT NOT NULL,
|
|
71
|
-
status TEXT NOT NULL,
|
|
72
|
-
prompt_json TEXT NOT NULL,
|
|
73
|
-
response_json TEXT,
|
|
74
|
-
created_at TEXT NOT NULL,
|
|
75
|
-
answered_at TEXT,
|
|
76
|
-
applied_at TEXT,
|
|
77
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
CREATE INDEX IF NOT EXISTS idx_session_runtime_state_status
|
|
81
|
-
ON session_runtime_state(state_status, updated_at DESC);
|
|
82
|
-
CREATE INDEX IF NOT EXISTS idx_session_interactions_session
|
|
83
|
-
ON session_interactions(session_id, created_at DESC);
|
|
84
|
-
CREATE INDEX IF NOT EXISTS idx_session_interactions_status
|
|
85
|
-
ON session_interactions(status, created_at DESC);
|
|
86
|
-
`),this.initializeSessionFts();try{this.db.pragma("wal_checkpoint(PASSIVE)")}catch{}}initializeSessionFts(){try{this.db.exec(`
|
|
87
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS fts_session_messages USING fts5(
|
|
88
|
-
message_id UNINDEXED,
|
|
89
|
-
session_id UNINDEXED,
|
|
90
|
-
content
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
CREATE TRIGGER IF NOT EXISTS trg_messages_ai_fts
|
|
94
|
-
AFTER INSERT ON messages BEGIN
|
|
95
|
-
INSERT INTO fts_session_messages (message_id, session_id, content)
|
|
96
|
-
VALUES (new.id, new.session_id, new.content);
|
|
97
|
-
END;
|
|
98
|
-
|
|
99
|
-
CREATE TRIGGER IF NOT EXISTS trg_messages_au_fts
|
|
100
|
-
AFTER UPDATE OF content, session_id ON messages BEGIN
|
|
101
|
-
DELETE FROM fts_session_messages WHERE message_id = old.id;
|
|
102
|
-
INSERT INTO fts_session_messages (message_id, session_id, content)
|
|
103
|
-
VALUES (new.id, new.session_id, new.content);
|
|
104
|
-
END;
|
|
105
|
-
|
|
106
|
-
CREATE TRIGGER IF NOT EXISTS trg_messages_ad_fts
|
|
107
|
-
AFTER DELETE ON messages BEGIN
|
|
108
|
-
DELETE FROM fts_session_messages WHERE message_id = old.id;
|
|
109
|
-
END;
|
|
110
|
-
`);let J=this.db.prepare("SELECT COUNT(*) as c FROM messages").get().c;if(this.db.prepare("SELECT COUNT(*) as c FROM fts_session_messages").get().c<J)this.db.exec(`
|
|
111
|
-
INSERT INTO fts_session_messages (message_id, session_id, content)
|
|
112
|
-
SELECT m.id, m.session_id, m.content
|
|
113
|
-
FROM messages m
|
|
114
|
-
LEFT JOIN fts_session_messages f ON f.message_id = m.id
|
|
115
|
-
WHERE f.message_id IS NULL;
|
|
116
|
-
`);this.sessionFtsEnabled=!0}catch(J){this.sessionFtsEnabled=!1,O.warn("[SessionHistory] Session FTS disabled:",J?.message??String(J))}}toFtsPrefixQuery(J){return J.trim().split(/\s+/).filter(Boolean).map((K)=>`"${K.replace(/"/g,'""')}"*`).join(" AND ")}withImmediateTransaction(J){this.db.exec("BEGIN IMMEDIATE");try{let K=J();return this.db.exec("COMMIT"),K}catch(K){try{this.db.exec("ROLLBACK")}catch{}throw K}}ensureSessionRuntimeRow(J){let K=new Date().toISOString();this.db.prepare(`INSERT INTO session_runtime_state (
|
|
117
|
-
session_id,
|
|
118
|
-
state_status,
|
|
119
|
-
last_event_seq,
|
|
120
|
-
revision,
|
|
121
|
-
updated_at
|
|
122
|
-
) VALUES (?, 'idle', 0, 0, ?)
|
|
123
|
-
ON CONFLICT(session_id) DO NOTHING`).run(J,K)}readSessionRuntimeStateRow(J){return this.ensureSessionRuntimeRow(J),this.db.prepare("SELECT * FROM session_runtime_state WHERE session_id = ?").get(J)??null}parseJsonColumn(J,K,X){if(!K)return X;try{return JSON.parse(K)}catch{return O.warn(`[SessionHistory] Corrupted ${J} JSON, using fallback value`),X}}toSessionRuntimeState(J){if(!J)return null;return{sessionId:J.session_id,stateStatus:J.state_status,activeRunId:J.active_run_id,pausedState:this.parseJsonColumn("paused_state_json",J.paused_state_json,null),policySnapshot:this.parseJsonColumn("policy_snapshot_json",J.policy_snapshot_json,null),lastEventSeq:J.last_event_seq,revision:J.revision,leaseOwner:J.lease_owner,leaseExpiresAt:J.lease_expires_at,updatedAt:J.updated_at}}toSessionInteractionRecord(J){if(!J)return null;return{interactionId:J.interaction_id,sessionId:J.session_id,requestId:J.request_id,source:J.source,kind:J.kind,status:J.status,prompt:this.parseJsonColumn("prompt_json",J.prompt_json,{}),response:this.parseJsonColumn("response_json",J.response_json,null),createdAt:J.created_at,answeredAt:J.answered_at,appliedAt:J.applied_at}}assertSessionMutationGuard(J,K,X){let Y=Date.now(),Z=J.lease_expires_at?Date.parse(J.lease_expires_at):null;if(K&&J.lease_owner&&J.lease_owner!==K&&Z!==null&&Number.isFinite(Z)&&Z>Y)throw Error(`Session ${J.session_id} is leased by ${J.lease_owner} until ${J.lease_expires_at}`);if(X!==void 0&&J.revision!==X)throw Error(`Session ${J.session_id} revision mismatch: expected ${X}, got ${J.revision}`)}createSession(J,K,X){X??=p.randomUUID();let Y=new Date().toISOString();return this.withImmediateTransaction(()=>{this.db.prepare(`
|
|
124
|
-
INSERT INTO sessions (id, created_at, updated_at, arion, model, message_count)
|
|
125
|
-
VALUES (?, ?, ?, ?, ?, 0)
|
|
126
|
-
`).run(X,Y,Y,J,K),this.db.prepare(`INSERT INTO session_runtime_state (
|
|
127
|
-
session_id,
|
|
128
|
-
state_status,
|
|
129
|
-
last_event_seq,
|
|
130
|
-
revision,
|
|
131
|
-
updated_at
|
|
132
|
-
) VALUES (?, 'idle', 0, 0, ?)`).run(X,Y)}),X}forkSession(J,K){let X=this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(J);if(!X)throw Error(`Source session not found: ${J}`);let Y=p.randomUUID(),Z=new Date().toISOString(),W=K?.title??(X.title?`\uD83C\uDF74 ${X.title}`:"\uD83C\uDF74 Forked session"),$=K?.messageLimit!==void 0&&K.messageLimit>=0?this.db.prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC LIMIT ?"):this.db.prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC"),Q=K?.messageLimit!==void 0&&K.messageLimit>=0?$.all(J,K.messageLimit):$.all(J);return this.withImmediateTransaction(()=>{if(this.db.prepare(`INSERT INTO sessions (id, created_at, updated_at, arion, model, message_count, title)
|
|
133
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(Y,Z,Z,X.arion,X.model,Q.length,W),this.db.prepare(`INSERT INTO session_runtime_state (
|
|
134
|
-
session_id, state_status, last_event_seq, revision, updated_at
|
|
135
|
-
) VALUES (?, 'idle', 0, 0, ?)`).run(Y,Z),Q.length>0){let F=this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
136
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(let G of Q)F.run(Y,G.role,G.content,G.arion,G.tool_call_id,G.tool_calls,G.thinking,G.data,G.created_at)}}),{newSessionId:Y,sourceSessionId:J,messagesCopied:Q.length,title:W}}addMessage(J,K,X,Y){try{let Z=new Date().toISOString(),W=Y?.arion??null,$=Y?.toolCallId??null,Q=Y?.toolCalls?JSON.stringify(Y.toolCalls):null,F=Y?.thinking?JSON.stringify(Y.thinking):null;this.db.transaction(()=>{this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, created_at)
|
|
137
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(J,K,X,W,$,Q,F,Z),this.db.prepare(`UPDATE sessions
|
|
138
|
-
SET updated_at = ?,
|
|
139
|
-
message_count = message_count + 1,
|
|
140
|
-
title = COALESCE(title, CASE WHEN ? = 'user' THEN substr(?, 1, 60) END)
|
|
141
|
-
WHERE id = ?`).run(Z,K,X,J)})()}catch(Z){O.warn("[SessionHistory] Failed to persist message:",Z?.message??Z)}}addConversationMessage(J,K){try{let X=new Date().toISOString(),Y=L(K);if(K.role==="tool"&&!Y){let V=K.content.find((E)=>E.type==="tool_result");if(V&&V.type==="tool_result")Y=V.content}let Z=K.arion?.name??null,W=q(K),$=U(K),Q=S(K),F=JSON.stringify(K);this.db.transaction(()=>{this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
142
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(J,K.role,Y,Z,W,$,Q,F,X),this.db.prepare(`UPDATE sessions
|
|
143
|
-
SET updated_at = ?,
|
|
144
|
-
message_count = message_count + 1,
|
|
145
|
-
title = COALESCE(title, CASE WHEN ? = 'user' THEN substr(?, 1, 60) END)
|
|
146
|
-
WHERE id = ?`).run(X,K.role,Y,J)})(),this.incrementalSessions.add(J)}catch(X){O.warn("[SessionHistory] Failed to persist conversation message:",X?.message??X)}}addConversationMessages(J,K){if(K.length===0)return;if(K.length===1){this.addConversationMessage(J,K[0]);return}try{let X=new Date().toISOString(),Y=this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
147
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),Z=this.db.prepare(`UPDATE sessions
|
|
148
|
-
SET updated_at = ?,
|
|
149
|
-
message_count = message_count + ?,
|
|
150
|
-
title = COALESCE(title, CASE WHEN ? = 'user' THEN substr(?, 1, 60) END)
|
|
151
|
-
WHERE id = ?`);this.db.transaction(()=>{let $=null;for(let Q of K){let F=L(Q);if(Q.role==="tool"&&!F){let y=Q.content.find((I)=>I.type==="tool_result");if(y&&y.type==="tool_result")F=y.content}if(Q.role==="user"&&!$)$=F;let G=Q.arion?.name??null,V=q(Q),E=U(Q),_=S(Q),A=JSON.stringify(Q);Y.run(J,Q.role,F,G,V,E,_,A,X)}Z.run(X,K.length,$?"user":"assistant",$??"",J)})()}catch(X){O.warn("[SessionHistory] Failed to persist conversation messages batch:",X?.message??X)}}replaceConversationMessages(J,K){if(this.incrementalSessions.has(J))return;try{let X=performance.now(),Y=this.db.prepare("SELECT COUNT(*) as cnt FROM messages WHERE session_id = ?").get(J)?.cnt??0,Z=performance.now();x(`SessionHistory:replaceConversationMessages(del=${Y},ins=${K.length})`);let W=new Date().toISOString(),$=this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
152
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);this.db.transaction(()=>{this.db.prepare("DELETE FROM messages WHERE session_id = ?").run(J);let G=null;for(let V of K){let E=L(V);if(V.role==="tool"&&!E){let _=V.content.find((A)=>A.type==="tool_result");if(_&&_.type==="tool_result")E=_.content}if(V.role==="user"&&!G)G=E;$.run(J,V.role,E,V.arion?.name??null,q(V),U(V),S(V),JSON.stringify(V),W)}this.db.prepare(`UPDATE sessions
|
|
153
|
-
SET updated_at = ?,
|
|
154
|
-
message_count = ?,
|
|
155
|
-
title = CASE
|
|
156
|
-
WHEN ? IS NOT NULL AND length(?) > 0 THEN substr(?, 1, 60)
|
|
157
|
-
ELSE title
|
|
158
|
-
END
|
|
159
|
-
WHERE id = ?`).run(W,K.length,G,G,G,J)})();let F=performance.now()-X;if(M(),process.env.DEBUG&&(F>200||Y>500))try{process.stderr.write(`[SessionHistory][DIAG] replaceConversationMessages: total=${F.toFixed(0)}ms (count=${(Z-X).toFixed(0)}ms txn=${(F-(Z-X)).toFixed(0)}ms) existingRows=${Y} newRows=${K.length} session=${J}
|
|
160
|
-
`)}catch{}}catch(X){M(),O.warn("[SessionHistory] Failed to replace conversation messages batch:",X?.message??X)}}loadSessionMessages(J){let K=this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(J);if(!K)return null;let Y=this.db.prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC").all(J).map((Z)=>{if(Z.data)try{let W=JSON.parse(Z.data),$=T.safeParse(W);if($.success)return $.data;return O.warn(`[loadSessionMessages] Schema validation failed for message row ${Z.id} (session ${J}), falling back to v1 columns`),B(Z)}catch{return O.warn(`[loadSessionMessages] Corrupted data column in message row ${Z.id} (session ${J}), falling back to v1 columns`),B(Z)}return B(Z)});return{id:K.id,arion:K.arion,model:K.model,messages:Y}}loadSession(J){let K=this.loadSessionMessages(J);if(!K)return null;let X=this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J)),Y=this.db.prepare(`SELECT * FROM session_interactions
|
|
161
|
-
WHERE session_id = ?
|
|
162
|
-
AND status = 'pending'
|
|
163
|
-
ORDER BY created_at DESC
|
|
164
|
-
LIMIT 1`).get(J)??null;return{session:K,runtimeState:X,pendingInteraction:this.toSessionInteractionRecord(Y)}}getSessionRuntimeState(J){return this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))}getInteraction(J){let K=this.db.prepare("SELECT * FROM session_interactions WHERE interaction_id = ?").get(J)??null;return this.toSessionInteractionRecord(K)}claimSessionForMutation(J,K,X){if(!K.trim())throw Error("claimSessionForMutation requires a non-empty ownerId");if(!Number.isFinite(X)||X<=0)throw Error("claimSessionForMutation requires a positive staleAfterMs");return this.withImmediateTransaction(()=>{let Y=this.readSessionRuntimeStateRow(J);if(!Y)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Y,K);let Z=new Date().toISOString(),W=new Date(Date.now()+X).toISOString();return this.db.prepare(`UPDATE session_runtime_state
|
|
165
|
-
SET lease_owner = ?,
|
|
166
|
-
lease_expires_at = ?,
|
|
167
|
-
updated_at = ?
|
|
168
|
-
WHERE session_id = ?`).run(K,W,Z,J),this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))})}recordPausedRun(J,K,X,Y,Z,W){return this.withImmediateTransaction(()=>{let $=this.readSessionRuntimeStateRow(J);if(!$)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard($,W?.ownerId,W?.expectedRevision);let Q=new Date().toISOString(),F=$.revision+1;if(this.db.prepare(`UPDATE session_runtime_state
|
|
169
|
-
SET state_status = 'paused',
|
|
170
|
-
active_run_id = ?,
|
|
171
|
-
paused_state_json = ?,
|
|
172
|
-
policy_snapshot_json = ?,
|
|
173
|
-
last_event_seq = ?,
|
|
174
|
-
revision = ?,
|
|
175
|
-
updated_at = ?
|
|
176
|
-
WHERE session_id = ?`).run(K,JSON.stringify(X),JSON.stringify(Y),W?.lastEventSeq??$.last_event_seq,F,Q,J),Z)this.db.prepare(`INSERT INTO session_interactions (
|
|
177
|
-
interaction_id,
|
|
178
|
-
session_id,
|
|
179
|
-
request_id,
|
|
180
|
-
source,
|
|
181
|
-
kind,
|
|
182
|
-
status,
|
|
183
|
-
prompt_json,
|
|
184
|
-
created_at
|
|
185
|
-
) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)`).run(Z.interactionId,J,Z.requestId,Z.source,Z.kind,JSON.stringify(Z.prompt),Q);return this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))})}recordInteractionResponse(J,K,X,Y){return this.withImmediateTransaction(()=>{let Z=this.readSessionRuntimeStateRow(J);if(!Z)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Z,Y?.ownerId,Y?.expectedRevision);let W=this.db.prepare(`SELECT * FROM session_interactions
|
|
186
|
-
WHERE session_id = ?
|
|
187
|
-
AND interaction_id = ?`).get(J,K)??null;if(!W)throw Error(`Interaction ${K} not found for session ${J}`);if(W.status!=="pending")throw Error(`Interaction ${K} is not pending (current status: ${W.status})`);let $=new Date().toISOString();this.db.prepare(`UPDATE session_interactions
|
|
188
|
-
SET status = 'answered',
|
|
189
|
-
response_json = ?,
|
|
190
|
-
answered_at = ?
|
|
191
|
-
WHERE interaction_id = ?`).run(JSON.stringify(X),$,K),this.db.prepare(`UPDATE session_runtime_state
|
|
192
|
-
SET revision = revision + 1,
|
|
193
|
-
updated_at = ?
|
|
194
|
-
WHERE session_id = ?`).run($,J);let Q=this.db.prepare("SELECT * FROM session_interactions WHERE interaction_id = ?").get(K)??null;return this.toSessionInteractionRecord(Q)})}cancelInteraction(J,K,X){return this.withImmediateTransaction(()=>{let Y=this.readSessionRuntimeStateRow(J);if(!Y)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Y,X?.ownerId,X?.expectedRevision);let Z=this.db.prepare(`SELECT * FROM session_interactions
|
|
195
|
-
WHERE session_id = ?
|
|
196
|
-
AND interaction_id = ?`).get(J,K)??null;if(!Z)throw Error(`Interaction ${K} not found for session ${J}`);if(Z.status!=="pending")throw Error(`Interaction ${K} is not pending (current status: ${Z.status})`);let W=new Date().toISOString();this.db.prepare(`UPDATE session_interactions
|
|
197
|
-
SET status = 'canceled',
|
|
198
|
-
answered_at = ?
|
|
199
|
-
WHERE interaction_id = ?`).run(W,K),this.db.prepare(`UPDATE session_runtime_state
|
|
200
|
-
SET state_status = 'completed',
|
|
201
|
-
active_run_id = NULL,
|
|
202
|
-
paused_state_json = NULL,
|
|
203
|
-
policy_snapshot_json = NULL,
|
|
204
|
-
revision = revision + 1,
|
|
205
|
-
updated_at = ?
|
|
206
|
-
WHERE session_id = ?`).run(W,J),this.db.prepare(`UPDATE sessions
|
|
207
|
-
SET completed_at = COALESCE(completed_at, ?),
|
|
208
|
-
updated_at = ?
|
|
209
|
-
WHERE id = ?`).run(W,W,J);let $=this.db.prepare("SELECT * FROM session_interactions WHERE interaction_id = ?").get(K)??null;return this.toSessionInteractionRecord($)})}completeRun(J,K,X){return this.withImmediateTransaction(()=>{let Y=this.readSessionRuntimeStateRow(J);if(!Y)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Y,X?.ownerId,X?.expectedRevision);let Z=new Date().toISOString();return this.db.prepare(`UPDATE session_runtime_state
|
|
210
|
-
SET state_status = 'completed',
|
|
211
|
-
active_run_id = NULL,
|
|
212
|
-
paused_state_json = NULL,
|
|
213
|
-
policy_snapshot_json = NULL,
|
|
214
|
-
revision = revision + 1,
|
|
215
|
-
updated_at = ?
|
|
216
|
-
WHERE session_id = ?`).run(Z,J),this.db.prepare(`UPDATE session_interactions
|
|
217
|
-
SET status = CASE WHEN response_json IS NULL THEN 'expired' ELSE 'applied' END,
|
|
218
|
-
answered_at = COALESCE(answered_at, ?),
|
|
219
|
-
applied_at = CASE WHEN response_json IS NULL THEN applied_at ELSE ? END
|
|
220
|
-
WHERE session_id = ?
|
|
221
|
-
AND status IN ('pending', 'answered')`).run(Z,Z,J),this.db.prepare(`UPDATE sessions
|
|
222
|
-
SET completed_at = COALESCE(completed_at, ?),
|
|
223
|
-
updated_at = ?
|
|
224
|
-
WHERE id = ?`).run(Z,Z,J),this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))})}releaseSessionClaim(J,K){this.withImmediateTransaction(()=>{let X=this.readSessionRuntimeStateRow(J);if(!X)throw Error(`Session ${J} not found`);if(X.lease_owner&&X.lease_owner!==K)throw Error(`Cannot release session ${J} lease owned by ${X.lease_owner} with ${K}`);let Y=new Date().toISOString();this.db.prepare(`UPDATE session_runtime_state
|
|
225
|
-
SET lease_owner = NULL,
|
|
226
|
-
lease_expires_at = NULL,
|
|
227
|
-
updated_at = ?
|
|
228
|
-
WHERE session_id = ?`).run(Y,J)})}listSessions(J=20,K=0){return this.db.prepare(`
|
|
229
|
-
SELECT
|
|
230
|
-
s.*,
|
|
231
|
-
COALESCE(s.title, '') as preview
|
|
232
|
-
FROM sessions s
|
|
233
|
-
WHERE s.message_count > 0
|
|
234
|
-
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
235
|
-
LIMIT ? OFFSET ?
|
|
236
|
-
`).all(J,K).map((Y)=>({id:Y.id,createdAt:new Date(Y.created_at),updatedAt:new Date(Y.updated_at),completedAt:Y.completed_at?new Date(Y.completed_at):void 0,title:Y.title,arion:Y.arion,model:Y.model,messageCount:Y.message_count,preview:this.truncatePreview(Y.preview??"",60)}))}searchSessions(J,K=20,X=0){let Z=`%${J.replace(/[%_\\]/g,"\\$&")}%`;return this.db.prepare(`
|
|
237
|
-
SELECT DISTINCT
|
|
238
|
-
s.*,
|
|
239
|
-
(SELECT content FROM messages WHERE session_id = s.id AND role = 'user' ORDER BY id LIMIT 1) as preview
|
|
240
|
-
FROM sessions s
|
|
241
|
-
LEFT JOIN messages m ON m.session_id = s.id
|
|
242
|
-
WHERE s.message_count > 0
|
|
243
|
-
AND (s.title LIKE ? ESCAPE '\\' OR m.content LIKE ? ESCAPE '\\')
|
|
244
|
-
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
245
|
-
LIMIT ? OFFSET ?
|
|
246
|
-
`).all(Z,Z,K,X).map(($)=>({id:$.id,createdAt:new Date($.created_at),updatedAt:new Date($.updated_at),completedAt:$.completed_at?new Date($.completed_at):void 0,title:$.title,arion:$.arion,model:$.model,messageCount:$.message_count,preview:this.truncatePreview($.preview??"",60)}))}searchSessionsFts(J,K=100,X=0){let Y=J.trim();if(!Y)return[];if(!this.sessionFtsEnabled)return this.searchSessions(Y,K,X);let Z=this.toFtsPrefixQuery(Y);if(!Z)return[];try{return this.db.prepare(`
|
|
247
|
-
WITH matched AS (
|
|
248
|
-
SELECT session_id, MIN(bm25(fts_session_messages)) as rank
|
|
249
|
-
FROM fts_session_messages
|
|
250
|
-
WHERE fts_session_messages MATCH ?
|
|
251
|
-
GROUP BY session_id
|
|
252
|
-
)
|
|
253
|
-
SELECT
|
|
254
|
-
s.*,
|
|
255
|
-
COALESCE(s.title, '') as preview
|
|
256
|
-
FROM matched m
|
|
257
|
-
JOIN sessions s ON s.id = m.session_id
|
|
258
|
-
WHERE s.message_count > 0
|
|
259
|
-
ORDER BY m.rank ASC, s.updated_at DESC, s.rowid DESC
|
|
260
|
-
LIMIT ? OFFSET ?
|
|
261
|
-
`).all(Z,K,X).map(($)=>({id:$.id,createdAt:new Date($.created_at),updatedAt:new Date($.updated_at),completedAt:$.completed_at?new Date($.completed_at):void 0,title:$.title,arion:$.arion,model:$.model,messageCount:$.message_count,preview:this.truncatePreview($.preview??"",60)}))}catch(W){return this.searchSessions(Y,K,X)}}searchSessionSummaries(J,K=100,X=0){let Z=`%${J.replace(/[%_\\]/g,"\\$&")}%`;return this.db.prepare(`
|
|
262
|
-
SELECT
|
|
263
|
-
s.*,
|
|
264
|
-
COALESCE(s.title, '') as preview
|
|
265
|
-
FROM sessions s
|
|
266
|
-
WHERE s.message_count > 0
|
|
267
|
-
AND (
|
|
268
|
-
s.title LIKE ? ESCAPE '\\'
|
|
269
|
-
OR s.arion LIKE ? ESCAPE '\\'
|
|
270
|
-
OR s.model LIKE ? ESCAPE '\\'
|
|
271
|
-
OR s.id LIKE ? ESCAPE '\\'
|
|
272
|
-
)
|
|
273
|
-
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
274
|
-
LIMIT ? OFFSET ?
|
|
275
|
-
`).all(Z,Z,Z,Z,K,X).map(($)=>({id:$.id,createdAt:new Date($.created_at),updatedAt:new Date($.updated_at),completedAt:$.completed_at?new Date($.completed_at):void 0,title:$.title,arion:$.arion,model:$.model,messageCount:$.message_count,preview:this.truncatePreview($.preview??"",60)}))}getSession(J){let K=this.db.prepare(`
|
|
276
|
-
SELECT * FROM sessions WHERE id = ?
|
|
277
|
-
`).get(J);if(!K)return null;let X=this.db.prepare(`
|
|
278
|
-
SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC
|
|
279
|
-
`).all(J);return{id:K.id,arion:K.arion,model:K.model,messages:X.map((Y)=>({id:Y.id,role:Y.role,content:Y.content,arion:Y.arion??void 0,toolCallId:Y.tool_call_id??void 0,toolCalls:Y.tool_calls?(()=>{try{return JSON.parse(Y.tool_calls)}catch{O.warn(`[getSession] Corrupted tool_calls JSON in message row ${Y.id} (session ${J})`);return}})():void 0,thinking:Y.thinking?(()=>{try{return JSON.parse(Y.thinking)}catch{O.warn(`[getSession] Corrupted thinking JSON in message row ${Y.id} (session ${J})`);return}})():void 0,createdAt:new Date(Y.created_at)}))}}deleteSession(J){this.db.prepare("DELETE FROM sessions WHERE id = ?").run(J)}setSessionTitle(J,K){try{this.db.prepare("UPDATE sessions SET title = ? WHERE id = ?").run(K,J)}catch(X){O.warn("[SessionHistory] Failed to set session title:",X?.message??X)}}markCompleted(J){try{let K=new Date().toISOString();this.withImmediateTransaction(()=>{this.db.prepare(`UPDATE sessions
|
|
280
|
-
SET completed_at = COALESCE(completed_at, ?),
|
|
281
|
-
updated_at = ?
|
|
282
|
-
WHERE id = ?`).run(K,K,J),this.ensureSessionRuntimeRow(J),this.db.prepare(`UPDATE session_runtime_state
|
|
283
|
-
SET state_status = 'completed',
|
|
284
|
-
active_run_id = NULL,
|
|
285
|
-
paused_state_json = NULL,
|
|
286
|
-
policy_snapshot_json = NULL,
|
|
287
|
-
lease_owner = NULL,
|
|
288
|
-
lease_expires_at = NULL,
|
|
289
|
-
revision = revision + 1,
|
|
290
|
-
updated_at = ?
|
|
291
|
-
WHERE session_id = ?`).run(K,J)})}catch(K){O.warn("[SessionHistory] Failed to mark session completed:",K?.message??K)}}markStaleSessionsCompleted(J){try{let K=new Date(Date.now()-J*86400000).toISOString(),X=new Date().toISOString();return this.db.prepare(`UPDATE sessions
|
|
292
|
-
SET completed_at = COALESCE(completed_at, ?),
|
|
293
|
-
updated_at = ?
|
|
294
|
-
WHERE completed_at IS NULL
|
|
295
|
-
AND message_count > 0
|
|
296
|
-
AND updated_at < ?`).run(X,X,K).changes}catch(K){return O.warn("[SessionHistory] Failed to mark stale sessions completed:",K?.message??K),0}}getIncompleteSessions(J=10){return this.db.prepare(`
|
|
297
|
-
SELECT
|
|
298
|
-
s.*,
|
|
299
|
-
(SELECT content FROM messages WHERE session_id = s.id AND role = 'user' ORDER BY id LIMIT 1) as preview
|
|
300
|
-
FROM sessions s
|
|
301
|
-
WHERE s.message_count > 0
|
|
302
|
-
AND s.completed_at IS NULL
|
|
303
|
-
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
304
|
-
LIMIT ?
|
|
305
|
-
`).all(J).map((X)=>({id:X.id,createdAt:new Date(X.created_at),updatedAt:new Date(X.updated_at),completedAt:X.completed_at?new Date(X.completed_at):void 0,title:X.title,arion:X.arion,model:X.model,messageCount:X.message_count,preview:this.truncatePreview(X.preview??"",60)}))}findSessionByPrefix(J){if(J.length===36)return this.db.prepare("SELECT id FROM sessions WHERE id = ? AND message_count > 0").get(J)?.id??null;if(J.length<8)return null;let K=this.db.prepare("SELECT id FROM sessions WHERE id LIKE ? AND message_count > 0 LIMIT 2").all(`${J}%`);return K.length===1?K[0].id:null}getSessionCount(){return this.db.prepare("SELECT COUNT(*) as count FROM sessions WHERE message_count > 0").get()?.count??0}truncatePreview(J,K){if(J.length<=K)return J;return J.slice(0,K-3)+"..."}addInputHistory(J){try{let K=new Date().toISOString();this.db.prepare(`
|
|
306
|
-
INSERT INTO input_history (content, used_at)
|
|
307
|
-
VALUES (?, ?)
|
|
308
|
-
ON CONFLICT(content) DO UPDATE SET used_at = excluded.used_at
|
|
309
|
-
`).run(J,K),this.db.prepare(`
|
|
310
|
-
DELETE FROM input_history
|
|
311
|
-
WHERE id NOT IN (
|
|
312
|
-
SELECT id FROM input_history ORDER BY used_at DESC LIMIT 500
|
|
313
|
-
)
|
|
314
|
-
`).run()}catch(K){O.warn("[SessionHistory] Failed to save input history:",K?.message??K)}}getInputHistory(J=100){return this.db.prepare(`
|
|
315
|
-
SELECT content FROM input_history
|
|
316
|
-
ORDER BY used_at DESC
|
|
317
|
-
LIMIT ?
|
|
318
|
-
`).all(J).map((X)=>X.content)}saveRunMetrics(J,K){try{this.db.prepare(`INSERT INTO run_metrics (id, session_id, turn_count, input_tokens, output_tokens, total_tokens, estimated_cost, wall_time_ms, tool_count, guardrail_fires, handoff_count)
|
|
319
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(K.id,J,K.turnCount??null,K.inputTokens??null,K.outputTokens??null,K.totalTokens??null,K.estimatedCost??null,K.wallTimeMs??null,K.toolCount??null,K.guardrailFires??null,K.handoffCount??null)}catch(X){O.warn("[SessionHistory] Failed to save run metrics:",X?.message??X)}}getRunMetrics(J){return this.db.prepare("SELECT * FROM run_metrics WHERE session_id = ? ORDER BY created_at ASC").all(J).map((X)=>({id:X.id,sessionId:X.session_id,turnCount:X.turn_count??void 0,inputTokens:X.input_tokens??void 0,outputTokens:X.output_tokens??void 0,totalTokens:X.total_tokens??void 0,estimatedCost:X.estimated_cost??void 0,wallTimeMs:X.wall_time_ms??void 0,toolCount:X.tool_count??void 0,guardrailFires:X.guardrail_fires??void 0,handoffCount:X.handoff_count??void 0,createdAt:X.created_at}))}close(){try{this.db.pragma("wal_checkpoint(TRUNCATE)")}catch{}this.db.close()}}function XJ(J){return typeof J!=="string"||J.trim().length>0}function YJ(J){let{toolCalls:K,...X}=J;return X}function ZJ(J,K,X){for(let Y=K;Y<J.length;Y++){let Z=J[Y];if(Z.role==="tool"&&Z.toolCallId===X)return!0}return!1}function $J(J){let K=[];for(let X=0;X<J.length;X++){let Y=J[X];if(Y.role==="assistant"&&Y.toolCalls?.length){let Z=new Set(Y.toolCalls.map((V)=>V.id)),W=new Set,$=[],Q=X+1;while(Q<J.length&&J[Q].role==="tool"){let V=J[Q];if(V.toolCallId&&Z.has(V.toolCallId)&&!W.has(V.toolCallId))W.add(V.toolCallId),$.push(V);Q++}let F=Y.toolCalls.filter((V)=>{if(W.has(V.id))return!0;return!ZJ(J,Q,V.id)}),G=F.filter((V)=>!W.has(V.id));if(F.length===Y.toolCalls.length)K.push(Y);else if(F.length>0)K.push({...Y,toolCalls:F});else if(XJ(Y.content))K.push(YJ(Y));K.push(...$);for(let V of G)K.push({role:"tool",content:`[Tool execution interrupted — no result for ${V.name}]`,toolCallId:V.id});X=Q-1;continue}if(Y.role==="tool")continue;K.push(Y)}return K}class D{textParts=[];thinkingBlocks=[];toolUseBlocks=[];handoffBlocks=[];toolResultMessages=[];seenToolIds=new Set;toolArgsAccumulator=new Map;thinkingInProgress=!1;pendingThinkingContent="";arion;verb;tokenUsage;snapshotMessages;previewAssistantId=`preview-${Date.now()}`;ingest(J){switch(J.type){case"text_delta":return this.textParts.push(J.content),"continue";case"thinking_start":return this.thinkingInProgress=!0,this.pendingThinkingContent="","continue";case"thinking_delta":return this.pendingThinkingContent+=J.content,"continue";case"thinking_end":{this.thinkingInProgress=!1;let K=Array.isArray(J.blocks)&&J.blocks.length>0?J.blocks[0]:void 0,X=typeof K?.thinking==="string"?K.thinking:this.pendingThinkingContent,Y=X.split(/\s+/).filter(Boolean).length,Z={type:"thinking",content:X,wordCount:Y,durationMs:J.durationMs,verb:this.verb};return this.thinkingBlocks.push(Z),this.pendingThinkingContent="","continue"}case"tool_start":{if(this.seenToolIds.has(J.id))return"continue";this.seenToolIds.add(J.id);let K={type:"tool_use",id:J.id,name:J.name,arguments:J.input??{}};return this.toolUseBlocks.push(K),"continue"}case"tool_args_delta":{let X=(this.toolArgsAccumulator.get(J.id)??"")+J.args;this.toolArgsAccumulator.set(J.id,X);try{let Y=JSON.parse(X),Z=this.toolUseBlocks.find((W)=>W.type==="tool_use"&&W.id===J.id);if(Z)Z.arguments=Y}catch{}return"continue"}case"tool_result":{if(J.input){let W=this.toolUseBlocks.find(($)=>$.type==="tool_use"&&$.id===J.id);if(W){let $=typeof J.input==="object"&&!Array.isArray(J.input)?J.input:{};if(Object.keys(W.arguments).length===0)W.arguments=$}}let K=J.result,X="usage"in J&&J.usage&&typeof J.usage==="object"&&typeof J.usage.inputTokens==="number"&&typeof J.usage.outputTokens==="number"&&typeof J.usage.totalTokens==="number"&&typeof J.usage.estimatedCost==="number"?J.usage:void 0,Y={type:"tool_result",toolUseId:J.id,content:typeof K.message==="string"?K.message:"",status:K.success===!0?"success":"error",durationMs:J.durationMs,resultData:K.data,usage:X},Z={id:crypto.randomUUID(),role:"tool",content:[Y],arion:this.arion,createdAt:new Date().toISOString()};return this.toolResultMessages.push(Z),"continue"}case"handoff_start":{let K={type:"handoff",target:J.target,direction:"to"};return this.handoffBlocks.push(K),"continue"}case"handoff_result":{let K={type:"handoff",target:J.target,direction:"from"};return this.handoffBlocks.push(K),"continue"}case"turn_complete":return"flush";case"messages_snapshot":return this.snapshotMessages=J.messages,"continue";default:return"continue"}}flush(){let J=[];if(this.thinkingInProgress&&this.pendingThinkingContent){let Y=this.pendingThinkingContent.trim(),Z=Y.length===0?0:Y.split(/\s+/).length,W={type:"thinking",content:this.pendingThinkingContent,wordCount:Z,verb:this.verb};this.thinkingBlocks.push(W)}let K=[];K.push(...this.thinkingBlocks);let X=this.textParts.join("");if(X)K.push({type:"text",text:X});if(K.push(...this.toolUseBlocks),K.push(...this.handoffBlocks),K.length>0){let Y={id:crypto.randomUUID(),role:"assistant",content:K,arion:this.arion,tokenUsage:this.tokenUsage,createdAt:new Date().toISOString()};J.push(Y)}if(J.push(...this.toolResultMessages),this.toolResultMessages.length>0&&this.toolUseBlocks.length>0){let Y=new Set(this.toolResultMessages.flatMap((Z)=>Z.content.filter((W)=>W.type==="tool_result").map((W)=>W.toolUseId)));for(let Z of this.toolUseBlocks){let W=Z.id;if(W&&!Y.has(W)){let $={id:crypto.randomUUID(),role:"tool",content:[{type:"tool_result",toolUseId:W,content:"Tool execution cancelled by user.",status:"error"}],arion:this.arion,createdAt:new Date().toISOString()};J.push($)}}}return this.textParts=[],this.thinkingBlocks=[],this.toolUseBlocks=[],this.handoffBlocks=[],this.toolResultMessages=[],this.seenToolIds=new Set,this.toolArgsAccumulator=new Map,this.thinkingInProgress=!1,this.pendingThinkingContent="",this.tokenUsage=void 0,this.verb=void 0,this.previewAssistantId=`preview-${Date.now()}`,J}snapshot(){let J=[];if(J.push(...this.thinkingBlocks.map((Y)=>({...Y}))),this.thinkingInProgress&&this.pendingThinkingContent){let Y=this.pendingThinkingContent,Z={type:"thinking",content:Y,wordCount:Y.split(/\s+/).filter(Boolean).length,verb:this.verb};J.push(Z)}let K=this.textParts.join("");if(K){let Y=K.lastIndexOf(`
|
|
320
|
-
`);if(Y>=0)J.push({type:"text",text:K.slice(0,Y+1)})}for(let Y of this.toolUseBlocks){let Z={...Y};if(Z.type==="tool_use"&&Object.keys(Z.arguments).length===0){let W=this.toolArgsAccumulator.get(Z.id);if(W){let $=D.tryParsePartialArgs(W);if($)Z.arguments=$}}J.push(Z)}J.push(...this.handoffBlocks.map((Y)=>({...Y})));let X=[];if(J.length>0)X.push({id:this.previewAssistantId,role:"assistant",content:J,arion:this.arion,createdAt:new Date().toISOString()});return X.push(...this.toolResultMessages.map((Y)=>({...Y,content:[...Y.content]}))),X}getSnapshotMessages(){return this.snapshotMessages}hasPendingContent(){return this.textParts.length>0||this.thinkingBlocks.length>0||this.toolUseBlocks.length>0||this.handoffBlocks.length>0||this.toolResultMessages.length>0||this.thinkingInProgress}setArion(J){this.arion=J}setVerb(J){this.verb=J}setTokenUsage(J){if(this.tokenUsage)this.tokenUsage={input:this.tokenUsage.input+J.input,output:this.tokenUsage.output+J.output};else this.tokenUsage={...J}}static tryParsePartialArgs(J){let K=J.trim();if(!K.startsWith("{")||K.length<4)return;try{return JSON.parse(K)}catch{}try{let X=JSON.parse(K+"}");if(Object.keys(X).length>0)return X}catch{}try{let X=JSON.parse(K+'"}');if(Object.keys(X).length>0)return X}catch{}for(let X=K.length-1;X>0;X--)if(K[X]===",")try{let Y=JSON.parse(K.slice(0,X)+"}");if(Object.keys(Y).length>0)return Y}catch{}return}}import{readFileSync as WJ,existsSync as z}from"node:fs";function b(J){if(!z(J))return[];let X=WJ(J,"utf-8").split(`
|
|
321
|
-
`).filter((W)=>W.trim().length>0),Y=new D,Z=[];for(let W of X){let $;try{$=JSON.parse(W)}catch{continue}if(!$.event||typeof $.event.type!=="string")continue;if($.event.type==="user_message"){if(Y.hasPendingContent())Z.push(...Y.flush());let F=$.event.content??"",G=$.event.id,V=R(F);if(G)V.id=G;Z.push(V);continue}if(Y.ingest($.event)==="flush"){let F=Y.flush();Z.push(...F)}}if(Y.hasPendingContent()){let W=Y.flush();Z.push(...W)}return Z}function u(J){for(let X of J.content){if(X.type==="tool_use"&&X.id)return`tool_use:${X.id}`;if(X.type==="tool_result"&&X.toolUseId)return`tool_result:${X.toolUseId}`}let K=J.content.filter((X)=>X.type==="text").map((X)=>X.text).join("");return`${J.role}:${K}`}function HJ(J,K){if(!K)return{messages:J,backfillMessages:[]};let X;try{X=b(K)}catch{return{messages:J,backfillMessages:[]}}if(X.length===0)return{messages:J,backfillMessages:[]};if(J.length>=X.length)return{messages:J,backfillMessages:[]};let Y=new Set(J.map(u)),Z=[];for(let $ of X){let Q=u($);if(!Y.has(Q))Z.push($)}return{messages:[...J,...Z],backfillMessages:Z}}function QJ(J,K,X){let Y=`${J}/arions/${K}/logs/${X}.jsonl`;if(z(Y))return Y;let Z=`${J}/logs/${X}.jsonl`;if(z(Z))return Z;return null}export{VJ as C,x as D,M as E,FJ as F,GJ as G,f as H,v as I,T as J,R as K,i as L,n as M,r as N,t as O,e as P,B as Q,o as R,L as S,U as T,S as U,q as V,k as W,$J as X,D as Y,b as Z,HJ as _,QJ as $};
|