@artinet/sdk
Version:
A TypeScript SDK for building collaborative AI agents.
87 lines (86 loc) • 3.25 kB
JavaScript
/**
* Copyright 2025 The Artinet Project
* SPDX-License-Identifier: Apache-2.0
*/
import { Tasks } from "../services/a2a/managers.js";
import { eq, like, or /*Table, TableConfig*/ } from 'drizzle-orm';
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { logger } from "../config/index.js";
export const TABLE_NAME = 'artinet_tasks';
const CREATE_TASKS_TABLE_SQL = (tableName = TABLE_NAME) => `CREATE TABLE IF NOT EXISTS ${tableName}\
(id TEXT PRIMARY KEY, contextId TEXT NOT NULL,\
kind TEXT NOT NULL, status TEXT NOT NULL,\
history TEXT NOT NULL,\
artifacts TEXT NOT NULL,\
metadata TEXT NOT NULL)`;
export const createTaskTable = async (db, tableName = TABLE_NAME) => {
await db.run(CREATE_TASKS_TABLE_SQL(tableName));
};
/*export type TTable = Table<TableConfig>; //TODO: Unwind Config/Column types */
export const TaskTable = sqliteTable(TABLE_NAME, {
id: text().primaryKey(),
contextId: text().notNull(),
kind: text('kind').$type().notNull(),
status: text('status', { mode: 'json' }).$type().notNull(),
history: text('history', { mode: 'json' }).$type().notNull().default([]),
artifacts: text('artifacts', { mode: 'json' }).$type().notNull().default([]),
metadata: text('metadata', { mode: 'json' }).$type().notNull().default({}),
});
export class SQLiteStore extends Tasks {
db;
//TODO: better for this to be a factory function? We're forcing the table/table name onto the user.
constructor(db, tasks = new Map(), tableName = TABLE_NAME) {
//TODO: we're inverting the dependency injection pattern here. Tasks should take the storage instance
super(tasks);
this.db = db;
createTaskTable(db, tableName);
}
async has(id) {
return ((await super.has(id)) ||
(await this.db.select().from(TaskTable).where(eq(TaskTable.id, id)).get()) !== undefined);
}
async list() {
return await this.db.select().from(TaskTable).execute();
}
async get(id) {
let task = await super.get(id);
if (task) {
return task;
}
task = await this.db.select().from(TaskTable).where(eq(TaskTable.id, id)).get();
if (task) {
await super.set(id, task);
}
return task;
}
async set(id, data) {
if (!data) {
return;
}
if (id !== data.id) {
logger.warn('SQLiteStore', `Task ID mismatch: ${id} !== ${data.id}`);
throw new Error('Task ID mismatch');
}
await this.db
.insert(TaskTable)
.values({ ...data, id })
.onConflictDoUpdate({
target: [TaskTable.id],
set: { ...data },
})
.execute();
await super.set(id, data);
}
async delete(id) {
await this.db.delete(TaskTable).where(eq(TaskTable.id, id)).execute();
await super.delete(id);
}
async search(query) {
const trimmedQuery = query.trim();
return await this.db
.select()
.from(TaskTable)
.where(or(eq(TaskTable.id, trimmedQuery), eq(TaskTable.contextId, trimmedQuery), like(TaskTable.status, `%${trimmedQuery}%`)))
.execute();
}
}