@ykurilov/agent-chat-background 0.0.0-stage → 0.56.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/CHANGELOG.md +376 -0
- package/LICENSE +21 -0
- package/README.md +92 -2
- package/dist/chunk-4RA3JT6K.js +9 -0
- package/dist/chunk-4RA3JT6K.js.map +1 -0
- package/dist/chunk-4XFSUFM6.js +53 -0
- package/dist/chunk-4XFSUFM6.js.map +1 -0
- package/dist/index.js +756 -0
- package/dist/index.js.map +1 -0
- package/dist/labels.js +14 -0
- package/dist/labels.js.map +1 -0
- package/dist/postgres.js +212 -0
- package/dist/postgres.js.map +1 -0
- package/dist/sqlite.js +184 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/types/background-tasks.d.ts +18 -0
- package/dist/types/background-tool.d.ts +16 -0
- package/dist/types/helper-task.d.ts +17 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/keyed-lock.d.ts +3 -0
- package/dist/types/labels.d.ts +10 -0
- package/dist/types/postgres.d.ts +9 -0
- package/dist/types/sqlite.d.ts +8 -0
- package/dist/types/store/memory.d.ts +3 -0
- package/dist/types/store/migration-settings.d.ts +4 -0
- package/dist/types/store/postgres-schema.d.ts +406 -0
- package/dist/types/store/postgres.d.ts +12 -0
- package/dist/types/store/sqlite-schema.d.ts +431 -0
- package/dist/types/store/sqlite.d.ts +6 -0
- package/dist/types/store/task-store.d.ts +23 -0
- package/dist/types/task-delivery.d.ts +24 -0
- package/dist/types/task-runner.d.ts +51 -0
- package/dist/types/task-tools.d.ts +13 -0
- package/dist/types/types.d.ts +97 -0
- package/drizzle/postgres/0000_init.sql +28 -0
- package/drizzle/postgres/0001_delivery_key.sql +1 -0
- package/drizzle/postgres/meta/0000_snapshot.json +229 -0
- package/drizzle/postgres/meta/0001_snapshot.json +235 -0
- package/drizzle/postgres/meta/_journal.json +20 -0
- package/drizzle/sqlite/0000_init.sql +28 -0
- package/drizzle/sqlite/0001_delivery_key.sql +1 -0
- package/drizzle/sqlite/meta/0000_snapshot.json +208 -0
- package/drizzle/sqlite/meta/0001_snapshot.json +215 -0
- package/drizzle/sqlite/meta/_journal.json +20 -0
- package/package.json +75 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sqlite.ts","../src/store/sqlite.ts","../src/store/sqlite-schema.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport type { TaskStore } from \"./types\";\nimport { createSqliteTaskStore } from \"./store/sqlite\";\n\nexport { BACKGROUND_MIGRATIONS_TABLE } from \"./store/migration-settings\";\nexport { backgroundTasks } from \"./store/sqlite-schema\";\n\n/** Миграции лежат в пакете рядом с `dist`: `drizzle/sqlite`. */\nconst MIGRATIONS_FOLDER = fileURLToPath(new URL(\"../drizzle/sqlite\", import.meta.url));\n\n/**\n * Задачи фона в файле SQLite; файл может быть общим с хранилищем чатов (`createSqliteChatStorage`).\n * Таблица приводится к последней миграции при открытии.\n */\nexport function sqliteTaskStore(filePath: string): TaskStore {\n return createSqliteTaskStore(filePath, MIGRATIONS_FOLDER);\n}\n","import Database from \"better-sqlite3\";\nimport { and, asc, eq, inArray, isNull, lt, or, sql } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { migrate } from \"drizzle-orm/better-sqlite3/migrator\";\nimport type { TaskCondition, TaskPatch, TaskRecord, TaskStore } from \"../types\";\nimport { BACKGROUND_MIGRATIONS_TABLE } from \"./migration-settings\";\nimport { backgroundTasks } from \"./sqlite-schema\";\nimport { meetsCondition, NOTICE_STATUSES, patchEntries, RUNNING_STATUSES, withoutEmptyFields } from \"./task-store\";\n\ntype Row = typeof backgroundTasks.$inferSelect;\n\nconst TIME_FIELDS = [\"leaseUntil\", \"createdAt\", \"startedAt\", \"finishedAt\", \"deliveredAt\"] as const;\nconst toMs = (iso: string | undefined | null) => (iso === undefined || iso === null ? null : Date.parse(iso));\nconst toIso = (ms: number | null) => (ms === null ? undefined : new Date(ms).toISOString());\n\nfunction toRecord(row: Row): TaskRecord {\n return withoutEmptyFields({\n ...row,\n leaseUntil: toIso(row.leaseUntil),\n createdAt: toIso(row.createdAt)!,\n startedAt: toIso(row.startedAt),\n finishedAt: toIso(row.finishedAt),\n deliveredAt: toIso(row.deliveredAt),\n } as TaskRecord);\n}\n\n/** Запись или правка как колонки таблицы: времена — миллисекунды. */\nfunction toColumns(patch: TaskPatch | TaskRecord): Record<string, unknown> {\n const columns: Record<string, unknown> = {};\n for (const [key, value] of patchEntries(patch)) {\n columns[key] = (TIME_FIELDS as readonly string[]).includes(key) ? toMs(value as string | null) : value;\n }\n return columns;\n}\n\n/**\n * Хранилище задач в файле SQLite. Схема приводится к последней миграции при открытии; файл может быть общим\n * с хранилищем чатов. Две копии сервера на одном файле делят задачи через аренду.\n */\nexport function createSqliteTaskStore(filePath: string, migrationsFolder: string): TaskStore {\n const sqlite = new Database(filePath);\n sqlite.pragma(\"journal_mode = WAL\");\n sqlite.pragma(\"busy_timeout = 5000\");\n const db = drizzle(sqlite);\n migrate(db, { migrationsFolder, migrationsTable: BACKGROUND_MIGRATIONS_TABLE });\n const owned = (ownerId: string, taskId: string) => and(eq(backgroundTasks.id, taskId), eq(backgroundTasks.ownerId, ownerId));\n const isRunning = inArray(backgroundTasks.status, [...RUNNING_STATUSES]);\n /** Условие записи — в том же `update … where`: проверка и запись одним действием базы. */\n const condition = (when: TaskCondition | undefined) =>\n and(\n when?.leaseOwner !== undefined ? eq(backgroundTasks.leaseOwner, when.leaseOwner) : undefined,\n when?.statuses !== undefined ? inArray(backgroundTasks.status, [...when.statuses]) : undefined,\n when?.pendingApprovalId !== undefined ? sql`json_extract(${backgroundTasks.progress}, '$.pendingApproval.approvalId') = ${when.pendingApprovalId}` : undefined,\n );\n\n async function get(ownerId: string, taskId: string): Promise<TaskRecord | null> {\n const row = db.select().from(backgroundTasks).where(owned(ownerId, taskId)).get();\n return row ? toRecord(row) : null;\n }\n\n return {\n async create(task) {\n db.insert(backgroundTasks).values(toColumns(task) as Row).run();\n },\n get,\n async update(ownerId, taskId, patch, when) {\n const columns = toColumns(patch);\n if (Object.keys(columns).length === 0) {\n const task = await get(ownerId, taskId);\n return task && meetsCondition(task, when) ? task : null;\n }\n const row = db.update(backgroundTasks).set(columns).where(and(owned(ownerId, taskId), condition(when))).returning().get();\n return row ? toRecord(row) : null;\n },\n async listForChat(ownerId, chatId) {\n const rows = db\n .select()\n .from(backgroundTasks)\n .where(and(eq(backgroundTasks.ownerId, ownerId), eq(backgroundTasks.chatId, chatId)))\n .orderBy(asc(backgroundTasks.createdAt), asc(backgroundTasks.id))\n .all();\n return rows.map(toRecord);\n },\n async countActive(ownerId) {\n const row = db\n .select({ count: sql<number>`count(*)` })\n .from(backgroundTasks)\n .where(and(eq(backgroundTasks.ownerId, ownerId), isRunning))\n .get();\n return Number(row?.count ?? 0);\n },\n async claim(taskId, leaseOwner, leaseUntil, now) {\n const nowMs = toMs(now)!;\n // Одно условное обновление: из двух копий, пришедших одновременно, условие выполнится только у первой.\n const row = db\n .update(backgroundTasks)\n .set({\n leaseOwner,\n leaseUntil: toMs(leaseUntil),\n status: sql`case when ${isRunning} then 'running' else ${backgroundTasks.status} end`,\n attempt: sql`case when ${isRunning} then ${backgroundTasks.attempt} + 1 else ${backgroundTasks.attempt} end`,\n startedAt: sql`case when ${isRunning} then coalesce(${backgroundTasks.startedAt}, ${nowMs}) else ${backgroundTasks.startedAt} end`,\n })\n .where(\n and(\n eq(backgroundTasks.id, taskId),\n isNull(backgroundTasks.deliveredAt),\n or(eq(backgroundTasks.leaseOwner, leaseOwner), isNull(backgroundTasks.leaseUntil), lt(backgroundTasks.leaseUntil, nowMs)),\n ),\n )\n .returning()\n .get();\n return row ? toRecord(row) : null;\n },\n async renewLease(taskId, leaseOwner, leaseUntil) {\n const renewed = db\n .update(backgroundTasks)\n .set({ leaseUntil: toMs(leaseUntil) })\n .where(and(eq(backgroundTasks.id, taskId), eq(backgroundTasks.leaseOwner, leaseOwner), isNull(backgroundTasks.deliveredAt)))\n .run();\n return renewed.changes > 0;\n },\n async listExpired(now) {\n const rows = db\n .select()\n .from(backgroundTasks)\n .where(and(isNull(backgroundTasks.deliveredAt), or(isNull(backgroundTasks.leaseUntil), lt(backgroundTasks.leaseUntil, toMs(now)!))))\n .orderBy(asc(backgroundTasks.createdAt))\n .all();\n return rows.map(toRecord);\n },\n async listUndelivered(ownerId, chatId) {\n const rows = db\n .select()\n .from(backgroundTasks)\n .where(\n and(\n eq(backgroundTasks.ownerId, ownerId),\n eq(backgroundTasks.chatId, chatId),\n isNull(backgroundTasks.deliveredAt),\n inArray(backgroundTasks.status, [...NOTICE_STATUSES]),\n ),\n )\n .orderBy(asc(backgroundTasks.createdAt), asc(backgroundTasks.id))\n .all();\n return rows.map(toRecord);\n },\n async markDelivered(taskIds, deliveryKey, at) {\n if (taskIds.length === 0) return;\n db.update(backgroundTasks)\n .set({ deliveredAt: toMs(at), leaseOwner: null, leaseUntil: null })\n .where(\n and(\n inArray(backgroundTasks.id, [...taskIds]),\n eq(backgroundTasks.deliveryKey, deliveryKey),\n inArray(backgroundTasks.status, [...NOTICE_STATUSES]),\n ),\n )\n .run();\n },\n async deleteForChat(ownerId, chatId) {\n db.delete(backgroundTasks)\n .where(and(eq(backgroundTasks.ownerId, ownerId), eq(backgroundTasks.chatId, chatId)))\n .run();\n },\n async close() {\n sqlite.close();\n },\n };\n}\n","import type { HelperProgress, TaskStatus } from \"@ykurilov/agent-chat-core\";\nimport type { ModelMessage } from \"ai\";\nimport { index, integer, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\n\nexport const backgroundTasks = sqliteTable(\n \"background_tasks\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n chatId: text(\"chat_id\").notNull(),\n messageId: text(\"message_id\").notNull(),\n toolCallId: text(\"tool_call_id\").notNull(),\n channel: text(\"channel\", { enum: [\"web\", \"telegram\", \"vk\", \"max\"] }).notNull(),\n kind: text(\"kind\", { enum: [\"tool\", \"helper\"] }).notNull(),\n name: text(\"name\").notNull(),\n input: text(\"input\", { mode: \"json\" }),\n title: text(\"title\").notNull(),\n status: text(\"status\").$type<TaskStatus>().notNull(),\n /** Шаги помощника: с них задача продолжается после перезапуска. */\n helperMessages: text(\"helper_messages\", { mode: \"json\" }).$type<ModelMessage[]>(),\n progress: text(\"progress\", { mode: \"json\" }).$type<HelperProgress>(),\n result: text(\"result\", { mode: \"json\" }),\n error: text(\"error\"),\n leaseOwner: text(\"lease_owner\"),\n leaseUntil: integer(\"lease_until\"),\n attempt: integer(\"attempt\").notNull().default(0),\n createdAt: integer(\"created_at\").notNull(),\n startedAt: integer(\"started_at\"),\n finishedAt: integer(\"finished_at\"),\n deliveredAt: integer(\"delivered_at\"),\n /** Ключ служебного сообщения, с которым задачу начали доставлять. */\n deliveryKey: text(\"delivery_key\"),\n },\n (table) => [\n index(\"background_tasks_status_lease_idx\").on(table.status, table.leaseUntil),\n index(\"background_tasks_owner_status_idx\").on(table.ownerId, table.status),\n index(\"background_tasks_chat_delivered_idx\").on(table.chatId, table.deliveredAt),\n ],\n);\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BackgroundTasks } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import type { BackgroundToolDefinition, TaskStore } from "./types.js";
|
|
3
|
+
export interface BackgroundTasksOptions {
|
|
4
|
+
/** `memoryTaskStore()`, `sqliteTaskStore(path)`, `postgresTaskStore(pool)`. */
|
|
5
|
+
store: TaskStore;
|
|
6
|
+
tools?: Record<string, BackgroundToolDefinition>;
|
|
7
|
+
/** Сколько задач человека идёт одновременно; по умолчанию 3. */
|
|
8
|
+
maxRunningPerUser?: number;
|
|
9
|
+
/** Предел времени задачи; по умолчанию 30 минут. */
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
/** Аренда задачи; по умолчанию 30 с, продление раз в треть аренды. */
|
|
12
|
+
leaseMs?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Фоновые задачи для службы чата: агент запускает долгую работу, разговор идёт дальше, итог приходит служебным
|
|
16
|
+
* сообщением. Задачи переживают перезапуск сервера; несколько копий сервера на одной базе делят их по аренде.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createBackgroundTasks(options: BackgroundTasksOptions): BackgroundTasks;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentToolsModel } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import type { Tool } from "ai";
|
|
3
|
+
import type { NewTask, RunControl, TaskOutcome, TaskRunner } from "./task-runner.js";
|
|
4
|
+
import type { BackgroundToolDefinition, TaskRecord } from "./types.js";
|
|
5
|
+
/** Фоновый инструмент: агент запускает его, ход идёт дальше, итог придёт служебным сообщением. */
|
|
6
|
+
export declare function backgroundTool<Input, Output>(definition: BackgroundToolDefinition<Input, Output>): BackgroundToolDefinition;
|
|
7
|
+
/** Поля хода для записи задачи; без номера ответа и канала (вызов вне хода) — пустой номер и веб. */
|
|
8
|
+
export declare function turnFields(model: AgentToolsModel): Pick<NewTask, "ownerId" | "chatId" | "messageId" | "channel">;
|
|
9
|
+
export declare const TOO_MANY_TASKS: (max: number) => string;
|
|
10
|
+
/** Инструмент хода для фонового инструмента: запись задачи и ответ «запущена» сразу, без ожидания итога. */
|
|
11
|
+
export declare function backgroundToolForTurn(name: string, definition: BackgroundToolDefinition, model: AgentToolsModel, service: {
|
|
12
|
+
runner(): TaskRunner;
|
|
13
|
+
maxRunningPerUser: number;
|
|
14
|
+
}): Tool;
|
|
15
|
+
/** Работа фонового инструмента в бегунке: итог — `done`, ошибка — `failed`. */
|
|
16
|
+
export declare function runBackgroundTool(definition: BackgroundToolDefinition, record: TaskRecord, control: RunControl): Promise<TaskOutcome>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentHelper, AgentToolsModel, BackgroundPort } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import type { Tool } from "ai";
|
|
3
|
+
import type { RunControl, TaskOutcome, TaskRunner } from "./task-runner.js";
|
|
4
|
+
import type { TaskRecord } from "./types.js";
|
|
5
|
+
export declare const HELPER_TOOL_PREFIX = "helper_";
|
|
6
|
+
/** Фоновые помощники из настроек службы: ядро отдаёт их в порте. */
|
|
7
|
+
export declare function backgroundHelpers(port: BackgroundPort | undefined): Record<string, AgentHelper>;
|
|
8
|
+
/** `helper_<имя>` фонового помощника: создаёт задачу и сразу отвечает «работает в фоне». */
|
|
9
|
+
export declare function helperToolForTurn(name: string, helper: AgentHelper, model: AgentToolsModel, service: {
|
|
10
|
+
runner(): TaskRunner;
|
|
11
|
+
maxRunningPerUser: number;
|
|
12
|
+
}): Tool;
|
|
13
|
+
/**
|
|
14
|
+
* Работа фонового помощника в бегунке: цикл ядра (`port.runHelper`) с сохранёнными шагами. После каждого шага шаги и ход
|
|
15
|
+
* пишутся в задачу: после перезапуска цикл продолжит с них, траты за старые шаги не повторятся.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runHelperTask(port: BackgroundPort, helper: AgentHelper, record: TaskRecord, control: RunControl): Promise<TaskOutcome>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { BackgroundRunContext, BackgroundToolDefinition, TaskPatch, TaskRecord, TaskStore } from "./types.js";
|
|
2
|
+
export { backgroundTool } from "./background-tool.js";
|
|
3
|
+
export { createBackgroundTasks } from "./background-tasks.js";
|
|
4
|
+
export type { BackgroundTasksOptions } from "./background-tasks.js";
|
|
5
|
+
export { memoryTaskStore } from "./store/memory.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Понятные фразы инструментов фоновых задач для простого вида чата (`stepPhrases` у `AgentChat`). Без импортов: файл безопасно подключать в браузерной сборке. */
|
|
2
|
+
export declare const backgroundStepPhrases: Record<string, {
|
|
3
|
+
running: string;
|
|
4
|
+
done: string;
|
|
5
|
+
}>;
|
|
6
|
+
/** Те же фразы по-английски. */
|
|
7
|
+
export declare const englishBackgroundStepPhrases: Record<string, {
|
|
8
|
+
running: string;
|
|
9
|
+
done: string;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
import type { TaskStore } from "./types.js";
|
|
3
|
+
export { BACKGROUND_MIGRATIONS_TABLE, BACKGROUND_MIGRATION_LOCK_KEY } from "./store/migration-settings.js";
|
|
4
|
+
export { backgroundTasks } from "./store/postgres-schema.js";
|
|
5
|
+
/**
|
|
6
|
+
* Задачи фона в PostgreSQL на пуле приложения (схема `agent_chat`, та же база, что у хранилища чатов).
|
|
7
|
+
* Таблица приводится к последней миграции при первом обращении. Пул закрывает приложение.
|
|
8
|
+
*/
|
|
9
|
+
export declare function postgresTaskStore(pool: Pool): TaskStore;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TaskStore } from "./types.js";
|
|
2
|
+
export { BACKGROUND_MIGRATIONS_TABLE } from "./store/migration-settings.js";
|
|
3
|
+
export { backgroundTasks } from "./store/sqlite-schema.js";
|
|
4
|
+
/**
|
|
5
|
+
* Задачи фона в файле SQLite; файл может быть общим с хранилищем чатов (`createSqliteChatStorage`).
|
|
6
|
+
* Таблица приводится к последней миграции при открытии.
|
|
7
|
+
*/
|
|
8
|
+
export declare function sqliteTaskStore(filePath: string): TaskStore;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Своя таблица учёта: хранилище чатов и песочница живут в той же базе и ведут свои. */
|
|
2
|
+
export declare const BACKGROUND_MIGRATIONS_TABLE = "__background_migrations";
|
|
3
|
+
/** Постоянное число для блокировки базы миграциями фона; не совпадает с ключами ядра (…443 — песочница) и мессенджеров (…445). */
|
|
4
|
+
export declare const BACKGROUND_MIGRATION_LOCK_KEY = 7311900444;
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import type { HelperProgress, TaskStatus } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import type { ModelMessage } from "ai";
|
|
3
|
+
export declare const backgroundTasks: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
4
|
+
name: "background_tasks";
|
|
5
|
+
schema: "agent_chat";
|
|
6
|
+
columns: {
|
|
7
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
8
|
+
name: "id";
|
|
9
|
+
tableName: "background_tasks";
|
|
10
|
+
dataType: "string";
|
|
11
|
+
columnType: "PgText";
|
|
12
|
+
data: string;
|
|
13
|
+
driverParam: string;
|
|
14
|
+
notNull: true;
|
|
15
|
+
hasDefault: false;
|
|
16
|
+
isPrimaryKey: true;
|
|
17
|
+
isAutoincrement: false;
|
|
18
|
+
hasRuntimeDefault: false;
|
|
19
|
+
enumValues: [string, ...string[]];
|
|
20
|
+
baseColumn: never;
|
|
21
|
+
identity: undefined;
|
|
22
|
+
generated: undefined;
|
|
23
|
+
}, {}, {}>;
|
|
24
|
+
ownerId: import("drizzle-orm/pg-core").PgColumn<{
|
|
25
|
+
name: "owner_id";
|
|
26
|
+
tableName: "background_tasks";
|
|
27
|
+
dataType: "string";
|
|
28
|
+
columnType: "PgText";
|
|
29
|
+
data: string;
|
|
30
|
+
driverParam: string;
|
|
31
|
+
notNull: true;
|
|
32
|
+
hasDefault: false;
|
|
33
|
+
isPrimaryKey: false;
|
|
34
|
+
isAutoincrement: false;
|
|
35
|
+
hasRuntimeDefault: false;
|
|
36
|
+
enumValues: [string, ...string[]];
|
|
37
|
+
baseColumn: never;
|
|
38
|
+
identity: undefined;
|
|
39
|
+
generated: undefined;
|
|
40
|
+
}, {}, {}>;
|
|
41
|
+
chatId: import("drizzle-orm/pg-core").PgColumn<{
|
|
42
|
+
name: "chat_id";
|
|
43
|
+
tableName: "background_tasks";
|
|
44
|
+
dataType: "string";
|
|
45
|
+
columnType: "PgText";
|
|
46
|
+
data: string;
|
|
47
|
+
driverParam: string;
|
|
48
|
+
notNull: true;
|
|
49
|
+
hasDefault: false;
|
|
50
|
+
isPrimaryKey: false;
|
|
51
|
+
isAutoincrement: false;
|
|
52
|
+
hasRuntimeDefault: false;
|
|
53
|
+
enumValues: [string, ...string[]];
|
|
54
|
+
baseColumn: never;
|
|
55
|
+
identity: undefined;
|
|
56
|
+
generated: undefined;
|
|
57
|
+
}, {}, {}>;
|
|
58
|
+
messageId: import("drizzle-orm/pg-core").PgColumn<{
|
|
59
|
+
name: "message_id";
|
|
60
|
+
tableName: "background_tasks";
|
|
61
|
+
dataType: "string";
|
|
62
|
+
columnType: "PgText";
|
|
63
|
+
data: string;
|
|
64
|
+
driverParam: string;
|
|
65
|
+
notNull: true;
|
|
66
|
+
hasDefault: false;
|
|
67
|
+
isPrimaryKey: false;
|
|
68
|
+
isAutoincrement: false;
|
|
69
|
+
hasRuntimeDefault: false;
|
|
70
|
+
enumValues: [string, ...string[]];
|
|
71
|
+
baseColumn: never;
|
|
72
|
+
identity: undefined;
|
|
73
|
+
generated: undefined;
|
|
74
|
+
}, {}, {}>;
|
|
75
|
+
toolCallId: import("drizzle-orm/pg-core").PgColumn<{
|
|
76
|
+
name: "tool_call_id";
|
|
77
|
+
tableName: "background_tasks";
|
|
78
|
+
dataType: "string";
|
|
79
|
+
columnType: "PgText";
|
|
80
|
+
data: string;
|
|
81
|
+
driverParam: string;
|
|
82
|
+
notNull: true;
|
|
83
|
+
hasDefault: false;
|
|
84
|
+
isPrimaryKey: false;
|
|
85
|
+
isAutoincrement: false;
|
|
86
|
+
hasRuntimeDefault: false;
|
|
87
|
+
enumValues: [string, ...string[]];
|
|
88
|
+
baseColumn: never;
|
|
89
|
+
identity: undefined;
|
|
90
|
+
generated: undefined;
|
|
91
|
+
}, {}, {}>;
|
|
92
|
+
channel: import("drizzle-orm/pg-core").PgColumn<{
|
|
93
|
+
name: "channel";
|
|
94
|
+
tableName: "background_tasks";
|
|
95
|
+
dataType: "string";
|
|
96
|
+
columnType: "PgText";
|
|
97
|
+
data: "max" | "telegram" | "vk" | "web";
|
|
98
|
+
driverParam: string;
|
|
99
|
+
notNull: true;
|
|
100
|
+
hasDefault: false;
|
|
101
|
+
isPrimaryKey: false;
|
|
102
|
+
isAutoincrement: false;
|
|
103
|
+
hasRuntimeDefault: false;
|
|
104
|
+
enumValues: ["web", "telegram", "vk", "max"];
|
|
105
|
+
baseColumn: never;
|
|
106
|
+
identity: undefined;
|
|
107
|
+
generated: undefined;
|
|
108
|
+
}, {}, {}>;
|
|
109
|
+
kind: import("drizzle-orm/pg-core").PgColumn<{
|
|
110
|
+
name: "kind";
|
|
111
|
+
tableName: "background_tasks";
|
|
112
|
+
dataType: "string";
|
|
113
|
+
columnType: "PgText";
|
|
114
|
+
data: "helper" | "tool";
|
|
115
|
+
driverParam: string;
|
|
116
|
+
notNull: true;
|
|
117
|
+
hasDefault: false;
|
|
118
|
+
isPrimaryKey: false;
|
|
119
|
+
isAutoincrement: false;
|
|
120
|
+
hasRuntimeDefault: false;
|
|
121
|
+
enumValues: ["tool", "helper"];
|
|
122
|
+
baseColumn: never;
|
|
123
|
+
identity: undefined;
|
|
124
|
+
generated: undefined;
|
|
125
|
+
}, {}, {}>;
|
|
126
|
+
name: import("drizzle-orm/pg-core").PgColumn<{
|
|
127
|
+
name: "name";
|
|
128
|
+
tableName: "background_tasks";
|
|
129
|
+
dataType: "string";
|
|
130
|
+
columnType: "PgText";
|
|
131
|
+
data: string;
|
|
132
|
+
driverParam: string;
|
|
133
|
+
notNull: true;
|
|
134
|
+
hasDefault: false;
|
|
135
|
+
isPrimaryKey: false;
|
|
136
|
+
isAutoincrement: false;
|
|
137
|
+
hasRuntimeDefault: false;
|
|
138
|
+
enumValues: [string, ...string[]];
|
|
139
|
+
baseColumn: never;
|
|
140
|
+
identity: undefined;
|
|
141
|
+
generated: undefined;
|
|
142
|
+
}, {}, {}>;
|
|
143
|
+
input: import("drizzle-orm/pg-core").PgColumn<{
|
|
144
|
+
name: "input";
|
|
145
|
+
tableName: "background_tasks";
|
|
146
|
+
dataType: "json";
|
|
147
|
+
columnType: "PgJsonb";
|
|
148
|
+
data: unknown;
|
|
149
|
+
driverParam: unknown;
|
|
150
|
+
notNull: false;
|
|
151
|
+
hasDefault: false;
|
|
152
|
+
isPrimaryKey: false;
|
|
153
|
+
isAutoincrement: false;
|
|
154
|
+
hasRuntimeDefault: false;
|
|
155
|
+
enumValues: undefined;
|
|
156
|
+
baseColumn: never;
|
|
157
|
+
identity: undefined;
|
|
158
|
+
generated: undefined;
|
|
159
|
+
}, {}, {}>;
|
|
160
|
+
title: import("drizzle-orm/pg-core").PgColumn<{
|
|
161
|
+
name: "title";
|
|
162
|
+
tableName: "background_tasks";
|
|
163
|
+
dataType: "string";
|
|
164
|
+
columnType: "PgText";
|
|
165
|
+
data: string;
|
|
166
|
+
driverParam: string;
|
|
167
|
+
notNull: true;
|
|
168
|
+
hasDefault: false;
|
|
169
|
+
isPrimaryKey: false;
|
|
170
|
+
isAutoincrement: false;
|
|
171
|
+
hasRuntimeDefault: false;
|
|
172
|
+
enumValues: [string, ...string[]];
|
|
173
|
+
baseColumn: never;
|
|
174
|
+
identity: undefined;
|
|
175
|
+
generated: undefined;
|
|
176
|
+
}, {}, {}>;
|
|
177
|
+
status: import("drizzle-orm/pg-core").PgColumn<{
|
|
178
|
+
name: "status";
|
|
179
|
+
tableName: "background_tasks";
|
|
180
|
+
dataType: "string";
|
|
181
|
+
columnType: "PgText";
|
|
182
|
+
data: TaskStatus;
|
|
183
|
+
driverParam: string;
|
|
184
|
+
notNull: true;
|
|
185
|
+
hasDefault: false;
|
|
186
|
+
isPrimaryKey: false;
|
|
187
|
+
isAutoincrement: false;
|
|
188
|
+
hasRuntimeDefault: false;
|
|
189
|
+
enumValues: [string, ...string[]];
|
|
190
|
+
baseColumn: never;
|
|
191
|
+
identity: undefined;
|
|
192
|
+
generated: undefined;
|
|
193
|
+
}, {}, {
|
|
194
|
+
$type: TaskStatus;
|
|
195
|
+
}>;
|
|
196
|
+
helperMessages: import("drizzle-orm/pg-core").PgColumn<{
|
|
197
|
+
name: "helper_messages";
|
|
198
|
+
tableName: "background_tasks";
|
|
199
|
+
dataType: "json";
|
|
200
|
+
columnType: "PgJsonb";
|
|
201
|
+
data: ModelMessage[];
|
|
202
|
+
driverParam: unknown;
|
|
203
|
+
notNull: false;
|
|
204
|
+
hasDefault: false;
|
|
205
|
+
isPrimaryKey: false;
|
|
206
|
+
isAutoincrement: false;
|
|
207
|
+
hasRuntimeDefault: false;
|
|
208
|
+
enumValues: undefined;
|
|
209
|
+
baseColumn: never;
|
|
210
|
+
identity: undefined;
|
|
211
|
+
generated: undefined;
|
|
212
|
+
}, {}, {
|
|
213
|
+
$type: ModelMessage[];
|
|
214
|
+
}>;
|
|
215
|
+
progress: import("drizzle-orm/pg-core").PgColumn<{
|
|
216
|
+
name: "progress";
|
|
217
|
+
tableName: "background_tasks";
|
|
218
|
+
dataType: "json";
|
|
219
|
+
columnType: "PgJsonb";
|
|
220
|
+
data: HelperProgress;
|
|
221
|
+
driverParam: unknown;
|
|
222
|
+
notNull: false;
|
|
223
|
+
hasDefault: false;
|
|
224
|
+
isPrimaryKey: false;
|
|
225
|
+
isAutoincrement: false;
|
|
226
|
+
hasRuntimeDefault: false;
|
|
227
|
+
enumValues: undefined;
|
|
228
|
+
baseColumn: never;
|
|
229
|
+
identity: undefined;
|
|
230
|
+
generated: undefined;
|
|
231
|
+
}, {}, {
|
|
232
|
+
$type: HelperProgress;
|
|
233
|
+
}>;
|
|
234
|
+
result: import("drizzle-orm/pg-core").PgColumn<{
|
|
235
|
+
name: "result";
|
|
236
|
+
tableName: "background_tasks";
|
|
237
|
+
dataType: "json";
|
|
238
|
+
columnType: "PgJsonb";
|
|
239
|
+
data: unknown;
|
|
240
|
+
driverParam: unknown;
|
|
241
|
+
notNull: false;
|
|
242
|
+
hasDefault: false;
|
|
243
|
+
isPrimaryKey: false;
|
|
244
|
+
isAutoincrement: false;
|
|
245
|
+
hasRuntimeDefault: false;
|
|
246
|
+
enumValues: undefined;
|
|
247
|
+
baseColumn: never;
|
|
248
|
+
identity: undefined;
|
|
249
|
+
generated: undefined;
|
|
250
|
+
}, {}, {}>;
|
|
251
|
+
error: import("drizzle-orm/pg-core").PgColumn<{
|
|
252
|
+
name: "error";
|
|
253
|
+
tableName: "background_tasks";
|
|
254
|
+
dataType: "string";
|
|
255
|
+
columnType: "PgText";
|
|
256
|
+
data: string;
|
|
257
|
+
driverParam: string;
|
|
258
|
+
notNull: false;
|
|
259
|
+
hasDefault: false;
|
|
260
|
+
isPrimaryKey: false;
|
|
261
|
+
isAutoincrement: false;
|
|
262
|
+
hasRuntimeDefault: false;
|
|
263
|
+
enumValues: [string, ...string[]];
|
|
264
|
+
baseColumn: never;
|
|
265
|
+
identity: undefined;
|
|
266
|
+
generated: undefined;
|
|
267
|
+
}, {}, {}>;
|
|
268
|
+
leaseOwner: import("drizzle-orm/pg-core").PgColumn<{
|
|
269
|
+
name: "lease_owner";
|
|
270
|
+
tableName: "background_tasks";
|
|
271
|
+
dataType: "string";
|
|
272
|
+
columnType: "PgText";
|
|
273
|
+
data: string;
|
|
274
|
+
driverParam: string;
|
|
275
|
+
notNull: false;
|
|
276
|
+
hasDefault: false;
|
|
277
|
+
isPrimaryKey: false;
|
|
278
|
+
isAutoincrement: false;
|
|
279
|
+
hasRuntimeDefault: false;
|
|
280
|
+
enumValues: [string, ...string[]];
|
|
281
|
+
baseColumn: never;
|
|
282
|
+
identity: undefined;
|
|
283
|
+
generated: undefined;
|
|
284
|
+
}, {}, {}>;
|
|
285
|
+
leaseUntil: import("drizzle-orm/pg-core").PgColumn<{
|
|
286
|
+
name: string;
|
|
287
|
+
tableName: "background_tasks";
|
|
288
|
+
dataType: "date";
|
|
289
|
+
columnType: "PgTimestamp";
|
|
290
|
+
data: Date;
|
|
291
|
+
driverParam: string;
|
|
292
|
+
notNull: false;
|
|
293
|
+
hasDefault: false;
|
|
294
|
+
isPrimaryKey: false;
|
|
295
|
+
isAutoincrement: false;
|
|
296
|
+
hasRuntimeDefault: false;
|
|
297
|
+
enumValues: undefined;
|
|
298
|
+
baseColumn: never;
|
|
299
|
+
identity: undefined;
|
|
300
|
+
generated: undefined;
|
|
301
|
+
}, {}, {}>;
|
|
302
|
+
attempt: import("drizzle-orm/pg-core").PgColumn<{
|
|
303
|
+
name: "attempt";
|
|
304
|
+
tableName: "background_tasks";
|
|
305
|
+
dataType: "number";
|
|
306
|
+
columnType: "PgInteger";
|
|
307
|
+
data: number;
|
|
308
|
+
driverParam: string | number;
|
|
309
|
+
notNull: true;
|
|
310
|
+
hasDefault: true;
|
|
311
|
+
isPrimaryKey: false;
|
|
312
|
+
isAutoincrement: false;
|
|
313
|
+
hasRuntimeDefault: false;
|
|
314
|
+
enumValues: undefined;
|
|
315
|
+
baseColumn: never;
|
|
316
|
+
identity: undefined;
|
|
317
|
+
generated: undefined;
|
|
318
|
+
}, {}, {}>;
|
|
319
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
320
|
+
name: string;
|
|
321
|
+
tableName: "background_tasks";
|
|
322
|
+
dataType: "date";
|
|
323
|
+
columnType: "PgTimestamp";
|
|
324
|
+
data: Date;
|
|
325
|
+
driverParam: string;
|
|
326
|
+
notNull: true;
|
|
327
|
+
hasDefault: false;
|
|
328
|
+
isPrimaryKey: false;
|
|
329
|
+
isAutoincrement: false;
|
|
330
|
+
hasRuntimeDefault: false;
|
|
331
|
+
enumValues: undefined;
|
|
332
|
+
baseColumn: never;
|
|
333
|
+
identity: undefined;
|
|
334
|
+
generated: undefined;
|
|
335
|
+
}, {}, {}>;
|
|
336
|
+
startedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
337
|
+
name: string;
|
|
338
|
+
tableName: "background_tasks";
|
|
339
|
+
dataType: "date";
|
|
340
|
+
columnType: "PgTimestamp";
|
|
341
|
+
data: Date;
|
|
342
|
+
driverParam: string;
|
|
343
|
+
notNull: false;
|
|
344
|
+
hasDefault: false;
|
|
345
|
+
isPrimaryKey: false;
|
|
346
|
+
isAutoincrement: false;
|
|
347
|
+
hasRuntimeDefault: false;
|
|
348
|
+
enumValues: undefined;
|
|
349
|
+
baseColumn: never;
|
|
350
|
+
identity: undefined;
|
|
351
|
+
generated: undefined;
|
|
352
|
+
}, {}, {}>;
|
|
353
|
+
finishedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
354
|
+
name: string;
|
|
355
|
+
tableName: "background_tasks";
|
|
356
|
+
dataType: "date";
|
|
357
|
+
columnType: "PgTimestamp";
|
|
358
|
+
data: Date;
|
|
359
|
+
driverParam: string;
|
|
360
|
+
notNull: false;
|
|
361
|
+
hasDefault: false;
|
|
362
|
+
isPrimaryKey: false;
|
|
363
|
+
isAutoincrement: false;
|
|
364
|
+
hasRuntimeDefault: false;
|
|
365
|
+
enumValues: undefined;
|
|
366
|
+
baseColumn: never;
|
|
367
|
+
identity: undefined;
|
|
368
|
+
generated: undefined;
|
|
369
|
+
}, {}, {}>;
|
|
370
|
+
deliveredAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
371
|
+
name: string;
|
|
372
|
+
tableName: "background_tasks";
|
|
373
|
+
dataType: "date";
|
|
374
|
+
columnType: "PgTimestamp";
|
|
375
|
+
data: Date;
|
|
376
|
+
driverParam: string;
|
|
377
|
+
notNull: false;
|
|
378
|
+
hasDefault: false;
|
|
379
|
+
isPrimaryKey: false;
|
|
380
|
+
isAutoincrement: false;
|
|
381
|
+
hasRuntimeDefault: false;
|
|
382
|
+
enumValues: undefined;
|
|
383
|
+
baseColumn: never;
|
|
384
|
+
identity: undefined;
|
|
385
|
+
generated: undefined;
|
|
386
|
+
}, {}, {}>;
|
|
387
|
+
deliveryKey: import("drizzle-orm/pg-core").PgColumn<{
|
|
388
|
+
name: "delivery_key";
|
|
389
|
+
tableName: "background_tasks";
|
|
390
|
+
dataType: "string";
|
|
391
|
+
columnType: "PgText";
|
|
392
|
+
data: string;
|
|
393
|
+
driverParam: string;
|
|
394
|
+
notNull: false;
|
|
395
|
+
hasDefault: false;
|
|
396
|
+
isPrimaryKey: false;
|
|
397
|
+
isAutoincrement: false;
|
|
398
|
+
hasRuntimeDefault: false;
|
|
399
|
+
enumValues: [string, ...string[]];
|
|
400
|
+
baseColumn: never;
|
|
401
|
+
identity: undefined;
|
|
402
|
+
generated: undefined;
|
|
403
|
+
}, {}, {}>;
|
|
404
|
+
};
|
|
405
|
+
dialect: 'pg';
|
|
406
|
+
}>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
import type { TaskStore } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Приводит таблицу задач к последней миграции. Идёт на одном соединении под блокировкой базы:
|
|
5
|
+
* если несколько серверов стартуют сразу, второй ждёт первого и видит применённые миграции.
|
|
6
|
+
*/
|
|
7
|
+
export declare function migrateBackgroundTasksToLatest(pool: Pool, migrationsFolder: string): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Хранилище задач в PostgreSQL (схема `agent_chat`) на пуле приложения. Миграция идёт при первом обращении,
|
|
10
|
+
* каждая операция её дожидается. Закрытие пул не закрывает: он принадлежит приложению.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createPostgresTaskStore(pool: Pool, migrationsFolder: string): TaskStore;
|