@game_ryo/lsji 1.2.0 → 1.2.2
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/AGENTS.md +90 -21
- package/README.md +15 -15
- package/package.json +3 -2
- package/src/cli.js +11 -4
- package/src/execution/budget/index.js +16 -0
- package/src/execution/hitl/approval-gate.js +3 -1
- package/src/execution/idempotency.js +4 -2
- package/src/index.js +1 -1
- package/src/llm/llm-agent.js +30 -7
- package/src/llm/memory/conversation.js +11 -10
- package/src/llm/prompt-manager.js +58 -139
- package/src/server/index.js +14 -16
- package/src/server/ui/dist/assets/{main-v74qobjz.js → main-49ugfY-s.js} +8 -8
- package/src/server/ui/dist/index.html +1 -1
- package/src/server/ui/src/components/NewRunModal.jsx +61 -35
- package/src/storage/better-sqlite.js +31 -0
- package/src/storage/index.js +50 -0
- package/src/storage/memory.js +188 -0
- package/src/storage/sqlite.js +31 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
9
9
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0d1117; color: #e6edf3; }
|
|
10
10
|
</style>
|
|
11
|
-
<script type="module" crossorigin src="/assets/main-
|
|
11
|
+
<script type="module" crossorigin src="/assets/main-49ugfY-s.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/main-DNMVBaZA.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
@@ -1,33 +1,32 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
// Fetch available models from Ollama
|
|
4
|
+
async function fetchLocalModels() {
|
|
5
|
+
try {
|
|
6
|
+
const res = await fetch('http://localhost:11434/api/tags');
|
|
7
|
+
if (res.ok) {
|
|
8
|
+
const data = await res.json();
|
|
9
|
+
return data.models?.map(m => ({ value: m.name, label: m.name })) || [];
|
|
10
|
+
}
|
|
11
|
+
} catch (e) {
|
|
12
|
+
// Ollama not running
|
|
13
|
+
}
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
|
|
3
17
|
// Model definitions per provider (as of 2024 - from official API docs)
|
|
4
18
|
// Source: https://ai.google.dev/gemini-api/docs/models?hl=ja
|
|
5
19
|
const MODELS_BY_PROVIDER = {
|
|
6
20
|
gemini: [
|
|
7
|
-
//
|
|
8
|
-
{ value: 'gemini-3.
|
|
9
|
-
{ value: 'gemini-3.5-
|
|
10
|
-
{ value: 'gemini-3-flash
|
|
21
|
+
// Current stable models (as of 2025)
|
|
22
|
+
{ value: 'gemini-3.5-flash', label: 'Gemini 3.5 Flash (Stable) - Best Price/Performance' },
|
|
23
|
+
{ value: 'gemini-3.5-pro', label: 'Gemini 3.5 Pro (Stable) - Best Reasoning' },
|
|
24
|
+
{ value: 'gemini-3.1-flash', label: 'Gemini 3.1 Flash (Preview)' },
|
|
25
|
+
{ value: 'gemini-3.1-pro', label: 'Gemini 3.1 Pro (Preview)' },
|
|
11
26
|
{ value: 'gemini-3.1-flash-lite', label: 'Gemini 3.1 Flash-Lite (Preview)' },
|
|
12
|
-
|
|
13
|
-
{ value: 'gemini-
|
|
14
|
-
{ value: 'gemini-
|
|
15
|
-
{ value: 'gemini-3.5-live-translate-preview', label: 'Gemini 3.5 Live Translate (Preview)' },
|
|
16
|
-
{ value: 'gemini-3.1-flash-live-preview', label: 'Gemini 3.1 Flash Live (Preview)' },
|
|
17
|
-
{ value: 'gemini-3.1-flash-tts-preview', label: 'Gemini 3.1 Flash TTS (Preview)' },
|
|
18
|
-
// Gemini 2.5 Flash
|
|
19
|
-
{ value: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash (Stable) - Best Price/Performance' },
|
|
20
|
-
{ value: 'gemini-2.5-flash-image', label: 'Nano Banana (Image Generation)' },
|
|
21
|
-
{ value: 'gemini-2.5-flash-native-audio-preview-12-2025', label: 'Gemini 2.5 Flash Live (Preview)' },
|
|
22
|
-
{ value: 'gemini-2.5-flash-preview-tts', label: 'Gemini 2.5 Flash TTS (Preview)' },
|
|
23
|
-
// Gemini 2.5 Flash-Lite
|
|
24
|
-
{ value: 'gemini-2.5-flash-lite', label: 'Gemini 2.5 Flash-Lite (Preview)' },
|
|
25
|
-
// Gemini 2.5 Pro
|
|
26
|
-
{ value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro (Stable) - Best Reasoning' },
|
|
27
|
-
{ value: 'gemini-2.5-pro-preview-tts', label: 'Gemini 2.5 Pro TTS (Preview)' },
|
|
28
|
-
// Legacy (Shutdown)
|
|
29
|
-
{ value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash (Shutdown)' },
|
|
30
|
-
{ value: 'gemini-2.0-flash-lite', label: 'Gemini 2.0 Flash-Lite (Shutdown)' },
|
|
27
|
+
// Legacy (deprecated)
|
|
28
|
+
{ value: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash (Deprecated)' },
|
|
29
|
+
{ value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro (Deprecated)' },
|
|
31
30
|
],
|
|
32
31
|
openai: [
|
|
33
32
|
{ value: 'gpt-4o', label: 'GPT-4o (Latest)' },
|
|
@@ -43,19 +42,13 @@ const MODELS_BY_PROVIDER = {
|
|
|
43
42
|
{ value: 'claude-3-sonnet-20240229', label: 'Claude 3 Sonnet' },
|
|
44
43
|
{ value: 'claude-3-haiku-20240307', label: 'Claude 3 Haiku' },
|
|
45
44
|
],
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{ value: 'llama3.1', label: 'Llama 3.1' },
|
|
49
|
-
{ value: 'mistral', label: 'Mistral' },
|
|
50
|
-
{ value: 'codellama', label: 'Code Llama' },
|
|
51
|
-
{ value: 'qwen2.5', label: 'Qwen 2.5' },
|
|
52
|
-
{ value: 'phi3.5', label: 'Phi 3.5' },
|
|
53
|
-
],
|
|
45
|
+
// Local models are fetched dynamically from Ollama
|
|
46
|
+
local: [],
|
|
54
47
|
};
|
|
55
48
|
|
|
56
49
|
// Default models per provider
|
|
57
50
|
const DEFAULT_MODELS = {
|
|
58
|
-
gemini: 'gemini-
|
|
51
|
+
gemini: 'gemini-3.5-flash', // Current stable
|
|
59
52
|
openai: 'gpt-4o-mini',
|
|
60
53
|
anthropic: 'claude-3-5-sonnet-20241022',
|
|
61
54
|
local: 'llama3.2',
|
|
@@ -64,8 +57,10 @@ const DEFAULT_MODELS = {
|
|
|
64
57
|
function NewRunModal({ onClose, onStart }) {
|
|
65
58
|
const [task, setTask] = useState('');
|
|
66
59
|
const [workflowId, setWorkflowId] = useState('');
|
|
67
|
-
const [provider, setProvider] = useState('gemini');
|
|
60
|
+
const [provider, setProvider] = useState('gemini');
|
|
68
61
|
const [model, setModel] = useState(DEFAULT_MODELS.gemini);
|
|
62
|
+
const [apiKey, setApiKey] = useState('');
|
|
63
|
+
const [localModels, setLocalModels] = useState([]);
|
|
69
64
|
const [maxCost, setMaxCost] = useState(10);
|
|
70
65
|
const [maxTokens, setMaxTokens] = useState(100000);
|
|
71
66
|
const [hitlEnabled, setHitlEnabled] = useState(true);
|
|
@@ -76,6 +71,18 @@ function NewRunModal({ onClose, onStart }) {
|
|
|
76
71
|
setModel(DEFAULT_MODELS[provider] || DEFAULT_MODELS.gemini);
|
|
77
72
|
}, [provider]);
|
|
78
73
|
|
|
74
|
+
// Fetch local models when provider is 'local'
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (provider === 'local') {
|
|
77
|
+
fetchLocalModels().then(models => {
|
|
78
|
+
if (models.length > 0) {
|
|
79
|
+
setLocalModels(models);
|
|
80
|
+
setModel(models[0].value);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}, [provider]);
|
|
85
|
+
|
|
79
86
|
const handleSubmit = async (e) => {
|
|
80
87
|
e.preventDefault();
|
|
81
88
|
if (!task.trim()) return;
|
|
@@ -85,7 +92,7 @@ function NewRunModal({ onClose, onStart }) {
|
|
|
85
92
|
await onStart({
|
|
86
93
|
task: task.trim(),
|
|
87
94
|
workflowId: workflowId.trim() || undefined,
|
|
88
|
-
llm: { provider, model },
|
|
95
|
+
llm: { provider, model, apiKey: apiKey || undefined },
|
|
89
96
|
budget: { maxCostPerRun: maxCost, maxTokensPerRun: maxTokens },
|
|
90
97
|
hitl: { enabled: hitlEnabled },
|
|
91
98
|
});
|
|
@@ -133,15 +140,34 @@ function NewRunModal({ onClose, onStart }) {
|
|
|
133
140
|
<option value="local">Local (Ollama)</option>
|
|
134
141
|
</select>
|
|
135
142
|
</div>
|
|
143
|
+
|
|
144
|
+
{provider !== 'local' && (
|
|
145
|
+
<div className="form-group">
|
|
146
|
+
<label className="form-label">API Key (or set env var)</label>
|
|
147
|
+
<input
|
|
148
|
+
type="password"
|
|
149
|
+
className="form-input"
|
|
150
|
+
placeholder={provider === 'gemini' ? 'GEMINI_API_KEY' : provider === 'openai' ? 'OPENAI_API_KEY' : 'ANTHROPIC_API_KEY'}
|
|
151
|
+
value={apiKey}
|
|
152
|
+
onChange={(e) => setApiKey(e.target.value)}
|
|
153
|
+
/>
|
|
154
|
+
<span className="form-hint">Leave empty to use environment variable</span>
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
136
157
|
<div className="form-group">
|
|
137
158
|
<label className="form-label">Model</label>
|
|
138
159
|
<select className="form-select" value={model} onChange={(e) => setModel(e.target.value)}>
|
|
139
|
-
{currentModels.map(m => (
|
|
160
|
+
{(provider === 'local' ? localModels : currentModels).map(m => (
|
|
140
161
|
<option key={m.value} value={m.value}>
|
|
141
162
|
{m.label}
|
|
142
163
|
</option>
|
|
143
164
|
))}
|
|
144
165
|
</select>
|
|
166
|
+
{provider === 'local' && localModels.length === 0 && (
|
|
167
|
+
<span className="form-hint" style={{color: 'var(--warning)'}}>
|
|
168
|
+
No local models found. Make sure Ollama is running at http://localhost:11434
|
|
169
|
+
</span>
|
|
170
|
+
)}
|
|
145
171
|
</div>
|
|
146
172
|
</div>
|
|
147
173
|
|
|
@@ -130,4 +130,35 @@ export class BetterSqliteStorage extends Storage {
|
|
|
130
130
|
`);
|
|
131
131
|
return stmt.all();
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
// ===== Generic SQL methods =====
|
|
135
|
+
|
|
136
|
+
async all(sql, params = []) {
|
|
137
|
+
const stmt = this.db.prepare(sql);
|
|
138
|
+
return stmt.all(...params);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async get(sql, params = []) {
|
|
142
|
+
const stmt = this.db.prepare(sql);
|
|
143
|
+
return stmt.get(...params);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async run(sql, params = []) {
|
|
147
|
+
const stmt = this.db.prepare(sql);
|
|
148
|
+
const result = stmt.run(...params);
|
|
149
|
+
return { changes: result.changes, lastInsertRowid: result.lastInsertRowid };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async exec(sql) {
|
|
153
|
+
this.db.exec(sql);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
prepare(sql) {
|
|
157
|
+
const stmt = this.db.prepare(sql);
|
|
158
|
+
return {
|
|
159
|
+
run: (...params) => stmt.run(...params),
|
|
160
|
+
get: (...params) => stmt.get(...params),
|
|
161
|
+
all: (...params) => stmt.all(...params),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
133
164
|
}
|
package/src/storage/index.js
CHANGED
|
@@ -114,6 +114,56 @@ export class Storage {
|
|
|
114
114
|
async getPerformanceStats() {
|
|
115
115
|
throw new Error('getPerformanceStats() must be implemented');
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
// ===== Generic SQL methods for custom queries =====
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Execute a SELECT query returning all rows
|
|
122
|
+
* @param {string} sql - SQL query
|
|
123
|
+
* @param {Array} params - Query parameters
|
|
124
|
+
* @returns {Promise<Array<Object>>}
|
|
125
|
+
*/
|
|
126
|
+
async all(sql, params = []) {
|
|
127
|
+
throw new Error('all() must be implemented');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Execute a SELECT query returning first row
|
|
132
|
+
* @param {string} sql - SQL query
|
|
133
|
+
* @param {Array} params - Query parameters
|
|
134
|
+
* @returns {Promise<Object|null>}
|
|
135
|
+
*/
|
|
136
|
+
async get(sql, params = []) {
|
|
137
|
+
throw new Error('get() must be implemented');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Execute an INSERT/UPDATE/DELETE query
|
|
142
|
+
* @param {string} sql - SQL query
|
|
143
|
+
* @param {Array} params - Query parameters
|
|
144
|
+
* @returns {Promise<{changes: number, lastInsertRowid: number|bigint}>}
|
|
145
|
+
*/
|
|
146
|
+
async run(sql, params = []) {
|
|
147
|
+
throw new Error('run() must be implemented');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Execute multiple SQL statements
|
|
152
|
+
* @param {string} sql - SQL statements
|
|
153
|
+
* @returns {Promise<void>}
|
|
154
|
+
*/
|
|
155
|
+
async exec(sql) {
|
|
156
|
+
throw new Error('exec() must be implemented');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Prepare a statement for repeated execution
|
|
161
|
+
* @param {string} sql - SQL query
|
|
162
|
+
* @returns {Object} Prepared statement with run(), get(), all() methods
|
|
163
|
+
*/
|
|
164
|
+
prepare(sql) {
|
|
165
|
+
throw new Error('prepare() must be implemented');
|
|
166
|
+
}
|
|
117
167
|
}
|
|
118
168
|
|
|
119
169
|
/**
|
package/src/storage/memory.js
CHANGED
|
@@ -17,6 +17,7 @@ export class MemoryStorage extends Storage {
|
|
|
17
17
|
this.settings = new Map();
|
|
18
18
|
this.battleHistory = [];
|
|
19
19
|
this.qTable = new Map(); // key: "state:action" -> q_value
|
|
20
|
+
this.conversations = []; // For conversation memory
|
|
20
21
|
this.initialized = false;
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -93,6 +94,193 @@ export class MemoryStorage extends Storage {
|
|
|
93
94
|
this.settings.clear();
|
|
94
95
|
this.battleHistory = [];
|
|
95
96
|
this.qTable.clear();
|
|
97
|
+
this.conversations = [];
|
|
96
98
|
this.settings.set('is_active', '1');
|
|
97
99
|
}
|
|
100
|
+
|
|
101
|
+
// ===== Generic SQL methods (in-memory implementation) =====
|
|
102
|
+
|
|
103
|
+
async all(sql, params = []) {
|
|
104
|
+
// Simple in-memory SQL-like query parser for basic SELECT queries
|
|
105
|
+
// This is a simplified implementation for testing
|
|
106
|
+
const lowerSql = sql.toLowerCase().trim();
|
|
107
|
+
|
|
108
|
+
if (lowerSql.startsWith('select')) {
|
|
109
|
+
if (lowerSql.includes('from conversations')) {
|
|
110
|
+
let results = [...this.conversations];
|
|
111
|
+
|
|
112
|
+
// Simple WHERE clause handling for session_id
|
|
113
|
+
const whereMatch = lowerSql.match(/where\s+session_id\s*=\s*\?/i);
|
|
114
|
+
if (whereMatch && params.length > 0) {
|
|
115
|
+
const sessionId = params[0];
|
|
116
|
+
results = results.filter(r => r.session_id === sessionId);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ORDER BY created_at ASC
|
|
120
|
+
results.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
|
|
121
|
+
|
|
122
|
+
return results;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (lowerSql.includes('from idempotency_keys')) {
|
|
126
|
+
// For idempotency store
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (lowerSql.includes('from checkpoints')) {
|
|
131
|
+
// For execution engine
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (lowerSql.includes('from approvals')) {
|
|
136
|
+
// For HITL
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async get(sql, params = []) {
|
|
145
|
+
const results = await this.all(sql, params);
|
|
146
|
+
return results[0] || null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async run(sql, params = []) {
|
|
150
|
+
const lowerSql = sql.toLowerCase().trim();
|
|
151
|
+
|
|
152
|
+
if (lowerSql.startsWith('insert')) {
|
|
153
|
+
if (lowerSql.includes('into conversations')) {
|
|
154
|
+
// INSERT INTO conversations (id, session_id, role, content, name, tool_call_id, tool_calls, tokens, created_at)
|
|
155
|
+
const id = params[0];
|
|
156
|
+
const sessionId = params[1];
|
|
157
|
+
const role = params[2];
|
|
158
|
+
const content = params[3];
|
|
159
|
+
const name = params[4];
|
|
160
|
+
const toolCallId = params[5];
|
|
161
|
+
const toolCalls = params[6];
|
|
162
|
+
const tokens = params[7];
|
|
163
|
+
const createdAt = params[8];
|
|
164
|
+
|
|
165
|
+
this.conversations.push({
|
|
166
|
+
id,
|
|
167
|
+
session_id: sessionId,
|
|
168
|
+
role,
|
|
169
|
+
content,
|
|
170
|
+
name,
|
|
171
|
+
tool_call_id: toolCallId,
|
|
172
|
+
tool_calls: toolCalls,
|
|
173
|
+
tokens,
|
|
174
|
+
created_at: createdAt,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (lowerSql.includes('into idempotency_keys')) {
|
|
179
|
+
// For idempotency store
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (lowerSql.includes('into checkpoints')) {
|
|
183
|
+
// For execution engine
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (lowerSql.includes('into approvals')) {
|
|
187
|
+
// For HITL
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (lowerSql.includes('into settings')) {
|
|
191
|
+
// Handled by setSetting
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (lowerSql.includes('into battle_history')) {
|
|
195
|
+
// Handled by addBattle
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (lowerSql.includes('into q_table')) {
|
|
199
|
+
// Handled by updateQ
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { changes: 1, lastInsertRowid: Date.now() };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (lowerSql.startsWith('update')) {
|
|
206
|
+
if (lowerSql.includes('idempotency_keys')) {
|
|
207
|
+
// For idempotency store
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (lowerSql.includes('approvals')) {
|
|
211
|
+
// For HITL
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return { changes: 1, lastInsertRowid: 0 };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (lowerSql.startsWith('delete')) {
|
|
218
|
+
if (lowerSql.includes('from conversations')) {
|
|
219
|
+
if (params[0]) {
|
|
220
|
+
this.conversations = this.conversations.filter(c => c.session_id !== params[0]);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (lowerSql.includes('from idempotency_keys')) {
|
|
225
|
+
// For idempotency store
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return { changes: 1, lastInsertRowid: 0 };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return { changes: 0, lastInsertRowid: 0 };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async exec(sql) {
|
|
235
|
+
// No-op for memory storage
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
prepare(sql) {
|
|
239
|
+
const self = this;
|
|
240
|
+
return {
|
|
241
|
+
run: async (...params) => (await self.run(sql, params)),
|
|
242
|
+
get: async (...params) => (await self.get(sql, params)),
|
|
243
|
+
all: async (...params) => (await self.all(sql, params)),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Helper methods for conversation memory
|
|
248
|
+
_addConversation(message) {
|
|
249
|
+
this.conversations.push(message);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
_getConversations(sessionId) {
|
|
253
|
+
return this.conversations.filter(c => c.session_id === sessionId);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
_clearConversations(sessionId) {
|
|
257
|
+
this.conversations = this.conversations.filter(c => c.session_id !== sessionId);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// For idempotency store
|
|
261
|
+
_getIdempotencyKeys() {
|
|
262
|
+
return this.idempotencyKeys || new Map();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
_setIdempotencyKeys(keys) {
|
|
266
|
+
this.idempotencyKeys = keys;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// For checkpoints
|
|
270
|
+
_getCheckpoints() {
|
|
271
|
+
return this.checkpoints || new Map();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
_setCheckpoints(checkpoints) {
|
|
275
|
+
this.checkpoints = checkpoints;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// For approvals
|
|
279
|
+
_getApprovals() {
|
|
280
|
+
return this.approvals || new Map();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
_setApprovals(approvals) {
|
|
284
|
+
this.approvals = approvals;
|
|
285
|
+
}
|
|
98
286
|
}
|
package/src/storage/sqlite.js
CHANGED
|
@@ -120,4 +120,35 @@ export class SqliteStorage extends Storage {
|
|
|
120
120
|
`);
|
|
121
121
|
return stmt.all();
|
|
122
122
|
}
|
|
123
|
+
|
|
124
|
+
// ===== Generic SQL methods =====
|
|
125
|
+
|
|
126
|
+
async all(sql, params = []) {
|
|
127
|
+
const stmt = this.db.prepare(sql);
|
|
128
|
+
return stmt.all(...params);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async get(sql, params = []) {
|
|
132
|
+
const stmt = this.db.prepare(sql);
|
|
133
|
+
return stmt.get(...params);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async run(sql, params = []) {
|
|
137
|
+
const stmt = this.db.prepare(sql);
|
|
138
|
+
const result = stmt.run(...params);
|
|
139
|
+
return { changes: result.changes, lastInsertRowid: result.lastInsertRowid };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async exec(sql) {
|
|
143
|
+
this.db.exec(sql);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
prepare(sql) {
|
|
147
|
+
const stmt = this.db.prepare(sql);
|
|
148
|
+
return {
|
|
149
|
+
run: (...params) => stmt.run(...params),
|
|
150
|
+
get: (...params) => stmt.get(...params),
|
|
151
|
+
all: (...params) => stmt.all(...params),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
123
154
|
}
|