Skip to content

Commit e6e221b

Browse files
committed
index on ai-agent: cf8bac5 Merge remote-tracking branch 'upstream/ai-agent' into ai-agent
1 parent cf8bac5 commit e6e221b

File tree

3 files changed

+122
-4
lines changed

3 files changed

+122
-4
lines changed

src/pages/aiAssistant/assistant.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { isAIMessageChunk } from "@langchain/core/messages";
22
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
33
import { MemorySaver } from "@langchain/langgraph-checkpoint";
4+
import { CordovaSqliteCheckpointSaver } from "./checkpoint"; // IMPORT THE CUSTOM SAVER
45
import { createReactAgent } from "@langchain/langgraph/prebuilt";
56
import confirm from "dialogs/confirm";
67
import select from "dialogs/select";

src/pages/aiAssistant/db.js

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// src/pages/aiAssistant/db.js (or a more general lib folder)
21

32
const DB_NAME = "AIAssistant.db"; // SQLite convention for .db extension
43
const DB_LOCATION = "default"; // Standard location
@@ -61,13 +60,27 @@ function initializeTables() {
6160
FOREIGN KEY (conversationId) REFERENCES conversations(id) ON DELETE CASCADE
6261
)
6362
`);
64-
// Index for faster querying of messages by conversationId and sorting
63+
// LangGraph Checkpoints Table
64+
tx.executeSql(`
65+
CREATE TABLE IF NOT EXISTS langgraph_checkpoints (
66+
thread_id TEXT NOT NULL,
67+
checkpoint_id TEXT NOT NULL,
68+
parent_checkpoint_id TEXT,
69+
checkpoint TEXT,
70+
updated_at INTEGER,
71+
PRIMARY KEY (thread_id, checkpoint_id)
72+
)
73+
`);
74+
// Indexes
6575
tx.executeSql(
6676
`CREATE INDEX IF NOT EXISTS idx_messages_conversationId_timestamp ON messages (conversationId, timestamp)`,
6777
);
6878
tx.executeSql(
6979
`CREATE INDEX IF NOT EXISTS idx_conversations_lastModifiedAt ON conversations (lastModifiedAt)`,
7080
);
81+
tx.executeSql(
82+
`CREATE INDEX IF NOT EXISTS idx_lg_checkpoints_thread_id_updated_at ON langgraph_checkpoints (thread_id, updated_at DESC)`);
83+
7184
},
7285
(error) => {
7386
console.error(
@@ -264,4 +277,108 @@ export async function deleteConversation(conversationId) {
264277
});
265278
}
266279

267-
// Ensure DB is opened and tables initialized when module loads or on first call
280+
// --- LangGraph Checkpoint DB Functions ---
281+
export async function getLangGraphCheckpointFromDB(threadId, checkpointId = null) {
282+
await openDB();
283+
return new Promise((resolve, reject) => {
284+
db.readTransaction(async (tx) => {
285+
try {
286+
let sql = "SELECT checkpoint FROM langgraph_checkpoints WHERE thread_id = ?";
287+
const params = [threadId];
288+
if (checkpointId) {
289+
sql += " AND checkpoint_id = ?";
290+
params.push(checkpointId);
291+
} else {
292+
sql += " ORDER BY updated_at DESC LIMIT 1"; // Get latest for the thread
293+
}
294+
const resultSet = await executeSqlAsync(tx, sql, params);
295+
if (resultSet.rows.length > 0) {
296+
const checkpointStr = resultSet.rows.item(0).checkpoint;
297+
resolve(checkpointStr ? JSON.parse(checkpointStr) : null);
298+
} else {
299+
resolve(null);
300+
}
301+
} catch (error) {
302+
console.error(`[DB] Error getting LangGraph checkpoint (thread: ${threadId}, ckpt: ${checkpointId}):`, error);
303+
reject(error);
304+
}
305+
});
306+
});
307+
}
308+
309+
export async function putLangGraphCheckpointInDB(threadId, checkpointTuple) {
310+
await openDB();
311+
const checkpointId = checkpointTuple?.config?.configurable?.checkpoint_id;
312+
const parentCheckpointId = checkpointTuple?.parent_config?.configurable?.checkpoint_id || null;
313+
314+
if (!checkpointId) {
315+
console.error("[DB] Cannot save LangGraph checkpoint: checkpoint_id missing from checkpointTuple.config");
316+
return Promise.reject(new Error("Missing checkpoint_id in checkpoint config"));
317+
}
318+
const checkpointStr = JSON.stringify(checkpointTuple);
319+
const updatedAt = Date.parse(checkpointTuple.config?.configurable?.checkpoint_id?.split("T")[0] || checkpointTuple.ts || new Date().toISOString());
320+
321+
322+
return new Promise((resolve, reject) => {
323+
db.transaction(async (tx) => {
324+
try {
325+
await executeSqlAsync(tx,
326+
"INSERT OR REPLACE INTO langgraph_checkpoints (thread_id, checkpoint_id, parent_checkpoint_id, checkpoint, updated_at) VALUES (?, ?, ?, ?, ?)",
327+
[threadId, checkpointId, parentCheckpointId, checkpointStr, updatedAt]
328+
);
329+
resolve();
330+
} catch (error) {
331+
console.error(`[DB] Error putting LangGraph checkpoint (thread: ${threadId}, ckpt: ${checkpointId}):`, error);
332+
reject(error);
333+
}
334+
});
335+
});
336+
}
337+
338+
export async function listLangGraphCheckpointsFromDB(threadId, limit, beforeConfig = null) {
339+
await openDB();
340+
return new Promise((resolve, reject) => {
341+
db.readTransaction(async (tx) => {
342+
try {
343+
let sql = "SELECT checkpoint FROM langgraph_checkpoints WHERE thread_id = ?";
344+
const params = [threadId];
345+
let beforeTimestamp = null;
346+
347+
if (beforeConfig?.configurable?.checkpoint_id) {
348+
// Attempt to get the timestamp of the 'before' checkpoint to filter accurately
349+
const beforeCheckpointTuple = await getLangGraphCheckpointFromDB(threadId, beforeConfig.configurable.checkpoint_id);
350+
if (beforeCheckpointTuple) {
351+
beforeTimestamp = Date.parse(beforeCheckpointTuple.ts || beforeCheckpointTuple.config?.configurable?.checkpoint_id?.split("T")[0] || new Date(0).toISOString());
352+
if (beforeTimestamp) {
353+
sql += " AND updated_at < ?";
354+
params.push(beforeTimestamp);
355+
} else {
356+
console.warn("[DB] list: Could not determine timestamp for 'before' checkpoint_id:", beforeConfig.configurable.checkpoint_id);
357+
}
358+
} else {
359+
console.warn("[DB] list: 'before' checkpoint_id not found:", beforeConfig.configurable.checkpoint_id);
360+
}
361+
}
362+
363+
sql += " ORDER BY updated_at DESC";
364+
if (limit) {
365+
sql += " LIMIT ?";
366+
params.push(limit);
367+
}
368+
369+
const resultSet = await executeSqlAsync(tx, sql, params);
370+
const checkpoints = [];
371+
for (let i = 0; i < resultSet.rows.length; i++) {
372+
const checkpointStr = resultSet.rows.item(i).checkpoint;
373+
if (checkpointStr) {
374+
checkpoints.push(JSON.parse(checkpointStr));
375+
}
376+
}
377+
resolve(checkpoints);
378+
} catch (error) {
379+
console.error(`[DB] Error listing LangGraph checkpoints (thread: ${threadId}):`, error);
380+
reject(error);
381+
}
382+
});
383+
});
384+
}

utils/scripts/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ NC=''
3333
script1="node ./utils/config.js $mode $app"
3434
script2="webpack --progress --mode $webpackmode "
3535
script3="node ./utils/loadStyles.js"
36-
script4="cordova build $platform $cordovamode"
36+
script4="cordova build android -- --gradleArg="-PcdvBuildToolsVersion=34.0.0"
3737
eval "
3838
echo \"${RED}$script1${NC}\";
3939
$script1;

0 commit comments

Comments
 (0)