aegra-hono 0.11.5 → 0.12.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/dist/cli.js +2 -2
- package/dist/cli.js.map +2 -2
- package/dist/index.js +105 -29
- package/dist/index.js.map +9 -8
- package/dist/runtime.js +105 -29
- package/dist/runtime.js.map +9 -8
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ var init_settings = __esm(() => {
|
|
|
23
23
|
booleanFromEnv = z.stringbool().default(false);
|
|
24
24
|
environmentShape = {
|
|
25
25
|
PROJECT_NAME: z.string().default("Aegra"),
|
|
26
|
-
VERSION: z.string().default("0.
|
|
26
|
+
VERSION: z.string().default("0.12.0"),
|
|
27
27
|
ENV_MODE: z.string().default("PRODUCTION"),
|
|
28
28
|
LOG_VERBOSITY: z.string().default("verbose"),
|
|
29
29
|
LOG_EXCLUDE_PATHS: z.string().default(""),
|
|
@@ -906,4 +906,4 @@ export {
|
|
|
906
906
|
main
|
|
907
907
|
};
|
|
908
908
|
|
|
909
|
-
//# debugId=
|
|
909
|
+
//# debugId=780939192C8D850764756E2164756E21
|
package/dist/cli.js.map
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/config/settings.ts", "../src/config/project.ts", "../src/core/schema.ts", "../src/core/database.ts", "../src/cli.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { z } from \"zod\";\n\nconst booleanFromEnv = z.stringbool().default(false);\nconst positiveIntFromEnv = (fallback: number) => z.coerce.number().int().positive().default(fallback);\n\nconst environmentShape = {\n PROJECT_NAME: z.string().default(\"Aegra\"),\n VERSION: z.string().default(\"0.
|
|
5
|
+
"import { z } from \"zod\";\n\nconst booleanFromEnv = z.stringbool().default(false);\nconst positiveIntFromEnv = (fallback: number) => z.coerce.number().int().positive().default(fallback);\n\nconst environmentShape = {\n PROJECT_NAME: z.string().default(\"Aegra\"),\n VERSION: z.string().default(\"0.12.0\"),\n ENV_MODE: z.string().default(\"PRODUCTION\"),\n LOG_VERBOSITY: z.string().default(\"verbose\"),\n LOG_EXCLUDE_PATHS: z.string().default(\"\"),\n HOST: z.string().default(\"0.0.0.0\"),\n PORT: z.coerce.number().int().min(1).max(65_535).default(2026),\n AEGRA_CONFIG: z.string().default(\"aegra.json\"),\n RUN_MIGRATIONS_ON_STARTUP: z.stringbool().default(true),\n DATABASE_URL: z.string().optional(),\n POSTGRES_USER: z.string().default(\"postgres\"),\n POSTGRES_PASSWORD: z.string().default(\"postgres\"),\n POSTGRES_HOST: z.string().default(\"localhost\"),\n POSTGRES_PORT: z.coerce.number().int().min(1).max(65_535).default(5432),\n POSTGRES_DB: z.string().default(\"aegra\"),\n REDIS_BROKER_ENABLED: booleanFromEnv,\n REDIS_URL: z.string().default(\"redis://localhost:6379/0\"),\n WORKER_COUNT: positiveIntFromEnv(3),\n N_JOBS_PER_WORKER: positiveIntFromEnv(10),\n WORKER_QUEUE_KEY: z.string().default(\"aegra:jobs\"),\n BG_JOB_TIMEOUT_SECS: positiveIntFromEnv(3600),\n BG_JOB_MAX_RETRIES: z.coerce.number().int().nonnegative().default(3),\n WORKER_DRAIN_TIMEOUT: z.coerce.number().nonnegative().default(30),\n STUCK_PENDING_THRESHOLD_SECONDS: positiveIntFromEnv(120),\n LEASE_DURATION_SECONDS: positiveIntFromEnv(30),\n HEARTBEAT_INTERVAL_SECONDS: positiveIntFromEnv(10),\n REAPER_INTERVAL_SECONDS: positiveIntFromEnv(15),\n POSTGRES_POLL_INTERVAL_SECONDS: positiveIntFromEnv(5),\n KEEPALIVE_INTERVAL_SECS: positiveIntFromEnv(5),\n CRON_ENABLED: z.stringbool().default(true),\n CRON_POLL_INTERVAL_SECONDS: positiveIntFromEnv(60),\n CRON_CLAIM_DURATION_SECONDS: positiveIntFromEnv(300),\n CRON_MAX_PER_USER: z.coerce.number().int().nonnegative().default(100),\n CRON_ALLOW_SECONDS_SCHEDULE: booleanFromEnv,\n CRON_TICK_BATCH_SIZE: positiveIntFromEnv(100),\n CRON_MAX_PAYLOAD_BYTES: positiveIntFromEnv(65_536),\n AEGRA_THREAD_TTL: z.string().optional(),\n LANGGRAPH_THREAD_TTL: z.string().optional(),\n MAX_SEARCH_LIMIT: positiveIntFromEnv(1000),\n ENABLE_PROMETHEUS_METRICS: booleanFromEnv,\n FF_V2_EVENT_STREAMING: z.stringbool().default(true),\n OTEL_SERVICE_NAME: z.string().default(\"aegra-backend\"),\n OTEL_TARGETS: z.string().default(\"\"),\n OTEL_CONSOLE_EXPORT: booleanFromEnv,\n OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),\n OTEL_EXPORTER_OTLP_HEADERS: z.string().optional(),\n LANGFUSE_BASE_URL: z.string().default(\"http://localhost:3000\"),\n LANGFUSE_PUBLIC_KEY: z.string().optional(),\n LANGFUSE_SECRET_KEY: z.string().optional(),\n PHOENIX_COLLECTOR_ENDPOINT: z.string().default(\"http://127.0.0.1:6006/v1/traces\"),\n PHOENIX_API_KEY: z.string().optional(),\n};\n\nexport const environmentVariableNames = Object.freeze(Object.keys(environmentShape));\n\nconst environmentSchema = z.object(environmentShape).superRefine((value, issue) => {\n if (value.LEASE_DURATION_SECONDS <= 2 * value.HEARTBEAT_INTERVAL_SECONDS) {\n issue.addIssue({ code: \"custom\", path: [\"LEASE_DURATION_SECONDS\"],\n message: \"LEASE_DURATION_SECONDS must exceed twice HEARTBEAT_INTERVAL_SECONDS\" });\n }\n});\n\nconst raw = environmentSchema.parse(process.env);\n\nexport const settings = {\n ...raw,\n DATABASE_URL:\n raw.DATABASE_URL ??\n `postgresql://${encodeURIComponent(raw.POSTGRES_USER)}:${encodeURIComponent(raw.POSTGRES_PASSWORD)}@${raw.POSTGRES_HOST}:${raw.POSTGRES_PORT}/${raw.POSTGRES_DB}`,\n} as const;\n\nexport type Settings = typeof settings;\n",
|
|
6
6
|
"import { readFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { z } from \"zod\";\nimport { settings } from \"./settings.ts\";\n\nconst corsSchema = z.object({\n allow_origins: z.array(z.string()).default([\"*\"]),\n allow_methods: z.array(z.string()).default([\"*\"]),\n allow_headers: z.array(z.string()).default([\"*\"]),\n allow_credentials: z.boolean().optional(),\n expose_headers: z.array(z.string()).default([\"Content-Location\", \"Location\"]),\n max_age: z.number().int().nonnegative().default(600),\n});\n\nconst configSchema = z.object({\n dependencies: z.array(z.string()).default([]),\n graphs: z.record(z.string(), z.string()).default({}),\n auth: z.object({ path: z.string(), disable_studio_auth: z.boolean().default(false) }).optional(),\n http: z\n .object({\n app: z.string().optional(),\n enable_custom_route_auth: z.boolean().default(false),\n cors: corsSchema.optional(),\n })\n .optional(),\n store: z\n .object({\n index: z\n .object({ dims: z.number().int().positive(), embed: z.string(), fields: z.array(z.string()).nullable().optional() })\n .nullable()\n .optional(),\n scopes: z.record(z.string(), z.array(z.string())).default({}),\n })\n .optional(),\n checkpointer: z\n .object({\n ttl: z\n .object({\n strategy: z.enum([\"delete\", \"keep_latest\"]).default(\"delete\"),\n default_ttl: z.number().positive().optional(),\n sweep_interval_minutes: z.number().positive().default(5),\n sweep_limit: z.number().int().positive().default(100),\n })\n .nullable()\n .optional(),\n })\n .optional(),\n});\n\nexport type AegraConfig = z.infer<typeof configSchema>;\n\nlet cachedConfig: AegraConfig | undefined;\n\nexport async function loadConfig(): Promise<AegraConfig> {\n if (cachedConfig) return cachedConfig;\n const configPath = resolve(settings.AEGRA_CONFIG);\n const content = await readFile(configPath, \"utf8\");\n cachedConfig = configSchema.parse(JSON.parse(content));\n return cachedConfig;\n}\n\nexport function configDirectory(): string {\n return dirname(resolve(settings.AEGRA_CONFIG));\n}\n\nexport function clearConfigCache(): void {\n cachedConfig = undefined;\n}\n",
|
|
7
7
|
"import { sql } from \"drizzle-orm\";\nimport { bigint, bigserial, boolean, doublePrecision, index, integer, jsonb, pgTable, primaryKey, text, timestamp, unique, uniqueIndex } from \"drizzle-orm/pg-core\";\nimport type { JsonObject, JsonValue } from \"../types.ts\";\n\nconst timestamps = {\n created_at: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updated_at: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n};\n\nexport const migrations = pgTable(\"aegra_migrations\", {\n version: integer(\"version\").primaryKey(),\n applied_at: timestamp(\"applied_at\", { withTimezone: true }).notNull().defaultNow(),\n});\n\nexport const assistants = pgTable(\"assistant\", {\n assistant_id: text(\"assistant_id\").primaryKey().default(sql`gen_random_uuid()::text`),\n name: text(\"name\").notNull(),\n description: text(\"description\"),\n graph_id: text(\"graph_id\").notNull(),\n config: jsonb(\"config\").$type<JsonObject>().notNull().default({}),\n context: jsonb(\"context\").$type<JsonObject>().notNull().default({}),\n user_id: text(\"user_id\").notNull(),\n version: integer(\"version\").notNull().default(1),\n metadata: jsonb(\"metadata\").$type<JsonObject>().notNull().default({}),\n ...timestamps,\n}, (table) => [\n index(\"idx_assistant_user\").on(table.user_id),\n unique(\"assistant_user_id_unique\").on(table.user_id, table.assistant_id),\n uniqueIndex(\"idx_assistant_user_graph_config\").on(table.user_id, table.graph_id, sql`md5(${table.config}::text)`),\n index(\"idx_assistant_metadata_gin\").using(\"gin\", sql`${table.metadata} jsonb_path_ops`),\n]);\n\nexport const assistantVersions = pgTable(\"assistant_versions\", {\n assistant_id: text(\"assistant_id\").notNull().references(() => assistants.assistant_id, { onDelete: \"cascade\" }),\n version: integer(\"version\").notNull(),\n graph_id: text(\"graph_id\").notNull(),\n config: jsonb(\"config\").$type<JsonObject>(),\n context: jsonb(\"context\").$type<JsonObject>(),\n metadata: jsonb(\"metadata\").$type<JsonObject>().notNull().default({}),\n name: text(\"name\"),\n description: text(\"description\"),\n created_at: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n}, (table) => [primaryKey({ columns: [table.assistant_id, table.version] })]);\n\nexport const threads = pgTable(\"thread\", {\n thread_id: text(\"thread_id\").primaryKey(),\n status: text(\"status\").notNull().default(\"idle\"),\n metadata_json: jsonb(\"metadata_json\").$type<JsonObject>().notNull().default({}),\n user_id: text(\"user_id\").notNull(),\n ...timestamps,\n}, (table) => [index(\"idx_thread_user\").on(table.user_id),\n index(\"idx_thread_metadata_gin\").using(\"gin\", sql`${table.metadata_json} jsonb_path_ops`)]);\n\nexport const runs = pgTable(\"runs\", {\n run_id: text(\"run_id\").primaryKey().default(sql`gen_random_uuid()::text`),\n thread_id: text(\"thread_id\").notNull().references(() => threads.thread_id, { onDelete: \"cascade\" }),\n assistant_id: text(\"assistant_id\").references(() => assistants.assistant_id, { onDelete: \"cascade\" }),\n status: text(\"status\").notNull().default(\"pending\"),\n input: jsonb(\"input\").$type<JsonObject>(),\n config: jsonb(\"config\").$type<JsonObject>(),\n context: jsonb(\"context\").$type<JsonObject>(),\n output: jsonb(\"output\").$type<JsonObject>(),\n error_message: text(\"error_message\"),\n user_id: text(\"user_id\").notNull(),\n execution_params: jsonb(\"execution_params\").$type<JsonObject>(),\n claimed_by: text(\"claimed_by\"),\n lease_expires_at: timestamp(\"lease_expires_at\", { withTimezone: true }),\n ...timestamps,\n}, (table) => [\n index(\"idx_runs_thread_id\").on(table.thread_id), index(\"idx_runs_status\").on(table.status),\n index(\"idx_runs_user\").on(table.user_id), index(\"idx_runs_assistant_id\").on(table.assistant_id),\n index(\"idx_runs_created_at\").on(table.created_at),\n index(\"idx_runs_lease_reaper\").on(table.status, table.lease_expires_at).where(sql`${table.status} = 'running'`),\n]);\n\nexport const threadEvents = pgTable(\"thread_events\", {\n seq: bigserial(\"seq\", { mode: \"number\" }).primaryKey(),\n thread_id: text(\"thread_id\").notNull().references(() => threads.thread_id, { onDelete: \"cascade\" }),\n run_id: text(\"run_id\").notNull().references(() => runs.run_id, { onDelete: \"cascade\" }),\n user_id: text(\"user_id\").notNull(),\n event_id: text(\"event_id\").notNull().unique(),\n method: text(\"method\").notNull(),\n namespace: text(\"namespace\").array().notNull().default(sql`'{}'::text[]`),\n event_data: jsonb(\"event_data\").$type<JsonValue>().notNull(),\n event_timestamp: bigint(\"event_timestamp\", { mode: \"number\" }).notNull(),\n created_at: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n}, (table) => [index(\"idx_thread_events_replay\").on(table.user_id, table.thread_id, table.seq)]);\n\nexport const crons = pgTable(\"crons\", {\n cron_id: text(\"cron_id\").primaryKey().default(sql`gen_random_uuid()::text`),\n assistant_id: text(\"assistant_id\").notNull().references(() => assistants.assistant_id, { onDelete: \"cascade\" }),\n thread_id: text(\"thread_id\").references(() => threads.thread_id, { onDelete: \"cascade\" }),\n user_id: text(\"user_id\").notNull(),\n schedule: text(\"schedule\").notNull(),\n payload: jsonb(\"payload\").$type<JsonObject>().notNull().default({}),\n metadata: jsonb(\"metadata\").$type<JsonObject>().notNull().default({}),\n on_run_completed: text(\"on_run_completed\"),\n enabled: boolean(\"enabled\").notNull().default(true),\n end_time: timestamp(\"end_time\", { withTimezone: true }),\n next_run_date: timestamp(\"next_run_date\", { withTimezone: true }),\n claimed_until: timestamp(\"claimed_until\", { withTimezone: true }),\n ...timestamps,\n}, (table) => [\n index(\"idx_cron_user\").on(table.user_id), index(\"idx_cron_assistant_id\").on(table.assistant_id),\n index(\"idx_cron_thread_id\").on(table.thread_id), index(\"idx_cron_next_run\").on(table.enabled, table.next_run_date),\n]);\n\nexport const storeItems = pgTable(\"store_items\", {\n user_id: text(\"user_id\").notNull(),\n namespace: text(\"namespace\").array().notNull(),\n key: text(\"key\").notNull(),\n value: jsonb(\"value\").$type<JsonObject>().notNull(),\n ...timestamps,\n}, (table) => [primaryKey({ columns: [table.namespace, table.key] })]);\n\nexport const threadTtl = pgTable(\"thread_ttl\", {\n thread_id: text(\"thread_id\").primaryKey().references(() => threads.thread_id, { onDelete: \"cascade\" }),\n strategy: text(\"strategy\").notNull().default(\"delete\"),\n ttl_minutes: doublePrecision(\"ttl_minutes\").notNull(),\n created_at: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n expires_at: timestamp(\"expires_at\", { withTimezone: true }).notNull(),\n}, (table) => [index(\"idx_thread_ttl_expires_at\").on(table.expires_at)]);\n",
|
|
8
8
|
"import postgres from \"postgres\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport { loadConfig } from \"../config/project.ts\";\nimport { settings } from \"../config/settings.ts\";\nimport * as schema from \"./schema.ts\";\n\nexport const client = postgres(settings.DATABASE_URL, {\n max: 20,\n idle_timeout: 30,\n connect_timeout: 10,\n transform: { undefined: null },\n // Bootstrap DDL raises \"already exists\" notices on every boot; keep them only\n // in verbose mode so the structured request log stays readable.\n onnotice: (notice) => {\n if (settings.LOG_VERBOSITY !== \"verbose\") return;\n console.log(JSON.stringify({ event: \"postgres_notice\", severity: notice.severity, code: notice.code, message: notice.message }));\n },\n});\nexport const db = drizzle({ client, schema });\n\nconst migrations = [\n `CREATE TABLE IF NOT EXISTS aegra_migrations (\n version integer PRIMARY KEY,\n applied_at timestamptz NOT NULL DEFAULT now()\n )`,\n `CREATE TABLE IF NOT EXISTS assistant (\n assistant_id text PRIMARY KEY DEFAULT gen_random_uuid()::text,\n name text NOT NULL,\n description text,\n graph_id text NOT NULL,\n config jsonb NOT NULL DEFAULT '{}'::jsonb,\n context jsonb NOT NULL DEFAULT '{}'::jsonb,\n user_id text NOT NULL,\n version integer NOT NULL DEFAULT 1,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE(user_id, assistant_id)\n )`,\n `CREATE UNIQUE INDEX IF NOT EXISTS idx_assistant_user_graph_config\n ON assistant(user_id, graph_id, md5(config::text))`,\n `CREATE INDEX IF NOT EXISTS idx_assistant_user ON assistant(user_id)`,\n `CREATE INDEX IF NOT EXISTS idx_assistant_metadata_gin ON assistant USING gin (metadata jsonb_path_ops)`,\n `CREATE TABLE IF NOT EXISTS assistant_versions (\n assistant_id text NOT NULL REFERENCES assistant(assistant_id) ON DELETE CASCADE,\n version integer NOT NULL,\n graph_id text NOT NULL,\n config jsonb,\n context jsonb,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n name text,\n description text,\n created_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY(assistant_id, version)\n )`,\n `CREATE TABLE IF NOT EXISTS thread (\n thread_id text PRIMARY KEY,\n status text NOT NULL DEFAULT 'idle',\n metadata_json jsonb NOT NULL DEFAULT '{}'::jsonb,\n user_id text NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n )`,\n `CREATE INDEX IF NOT EXISTS idx_thread_user ON thread(user_id)`,\n `CREATE INDEX IF NOT EXISTS idx_thread_metadata_gin ON thread USING gin (metadata_json jsonb_path_ops)`,\n `CREATE TABLE IF NOT EXISTS runs (\n run_id text PRIMARY KEY DEFAULT gen_random_uuid()::text,\n thread_id text NOT NULL REFERENCES thread(thread_id) ON DELETE CASCADE,\n assistant_id text REFERENCES assistant(assistant_id) ON DELETE CASCADE,\n status text NOT NULL DEFAULT 'pending',\n input jsonb,\n config jsonb,\n context jsonb,\n output jsonb,\n error_message text,\n user_id text NOT NULL,\n execution_params jsonb,\n claimed_by text,\n lease_expires_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n )`,\n `CREATE INDEX IF NOT EXISTS idx_runs_thread_id ON runs(thread_id)`,\n `CREATE INDEX IF NOT EXISTS idx_runs_status ON runs(status)`,\n `CREATE INDEX IF NOT EXISTS idx_runs_user ON runs(user_id)`,\n `CREATE INDEX IF NOT EXISTS idx_runs_assistant_id ON runs(assistant_id)`,\n `CREATE INDEX IF NOT EXISTS idx_runs_created_at ON runs(created_at)`,\n `CREATE INDEX IF NOT EXISTS idx_runs_lease_reaper ON runs(status, lease_expires_at) WHERE status = 'running'`,\n `CREATE TABLE IF NOT EXISTS thread_events (\n seq bigserial PRIMARY KEY,\n thread_id text NOT NULL REFERENCES thread(thread_id) ON DELETE CASCADE,\n run_id text NOT NULL REFERENCES runs(run_id) ON DELETE CASCADE,\n user_id text NOT NULL,\n event_id text NOT NULL UNIQUE,\n method text NOT NULL,\n namespace text[] NOT NULL DEFAULT '{}',\n event_data jsonb NOT NULL,\n event_timestamp bigint NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now()\n )`,\n `CREATE INDEX IF NOT EXISTS idx_thread_events_replay ON thread_events(user_id, thread_id, seq)`,\n `CREATE TABLE IF NOT EXISTS crons (\n cron_id text PRIMARY KEY DEFAULT gen_random_uuid()::text,\n assistant_id text NOT NULL REFERENCES assistant(assistant_id) ON DELETE CASCADE,\n thread_id text REFERENCES thread(thread_id) ON DELETE CASCADE,\n user_id text NOT NULL,\n schedule text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n on_run_completed text,\n enabled boolean NOT NULL DEFAULT true,\n end_time timestamptz,\n next_run_date timestamptz,\n claimed_until timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n )`,\n `CREATE TABLE IF NOT EXISTS store_items (\n user_id text NOT NULL,\n namespace text[] NOT NULL,\n key text NOT NULL,\n value jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n PRIMARY KEY(namespace, key)\n )`,\n // Store isolation lives in the namespace head ([\"users\", identity, ...]), so\n // the primary key must not include the writer. Older databases keyed on\n // user_id and are migrated in place; shared scopes otherwise duplicate rows.\n `DO $$\n DECLARE legacy_key boolean;\n BEGIN\n SELECT EXISTS (\n SELECT 1 FROM pg_constraint c\n JOIN pg_class t ON t.oid = c.conrelid\n WHERE t.relname = 'store_items' AND c.contype = 'p'\n AND pg_get_constraintdef(c.oid) = 'PRIMARY KEY (user_id, namespace, key)'\n ) INTO legacy_key;\n IF legacy_key THEN\n IF to_regclass('store_embeddings') IS NOT NULL THEN\n ALTER TABLE store_embeddings DROP CONSTRAINT IF EXISTS store_embeddings_user_id_namespace_key_fkey;\n ALTER TABLE store_embeddings DROP CONSTRAINT IF EXISTS store_embeddings_pkey;\n END IF;\n ALTER TABLE store_items DROP CONSTRAINT store_items_pkey;\n ALTER TABLE store_items ADD CONSTRAINT store_items_pkey PRIMARY KEY (namespace, key);\n IF to_regclass('store_embeddings') IS NOT NULL THEN\n ALTER TABLE store_embeddings ADD CONSTRAINT store_embeddings_pkey PRIMARY KEY (namespace, key);\n ALTER TABLE store_embeddings ADD CONSTRAINT store_embeddings_item_fkey\n FOREIGN KEY (namespace, key) REFERENCES store_items(namespace, key) ON DELETE CASCADE;\n END IF;\n END IF;\n END $$`,\n `CREATE INDEX IF NOT EXISTS idx_cron_user ON crons(user_id)`,\n `CREATE INDEX IF NOT EXISTS idx_cron_assistant_id ON crons(assistant_id)`,\n `CREATE INDEX IF NOT EXISTS idx_cron_thread_id ON crons(thread_id)`,\n `CREATE INDEX IF NOT EXISTS idx_cron_next_run ON crons(enabled, next_run_date)`,\n `CREATE TABLE IF NOT EXISTS thread_ttl (\n thread_id text PRIMARY KEY REFERENCES thread(thread_id) ON DELETE CASCADE,\n strategy text NOT NULL DEFAULT 'delete',\n ttl_minutes double precision NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n expires_at timestamptz NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS idx_thread_ttl_expires_at ON thread_ttl(expires_at)`,\n];\n\nexport async function migrate(): Promise<void> {\n for (const statement of migrations) await client.unsafe(statement);\n if ((await loadConfig()).store?.index) {\n await client.unsafe(\"CREATE EXTENSION IF NOT EXISTS vector\");\n await client.unsafe(`CREATE TABLE IF NOT EXISTS store_embeddings (\n user_id text NOT NULL,\n namespace text[] NOT NULL,\n key text NOT NULL,\n embedding vector NOT NULL,\n PRIMARY KEY(namespace, key),\n FOREIGN KEY(namespace, key) REFERENCES store_items(namespace, key) ON DELETE CASCADE\n )`);\n }\n}\n\nexport async function pingDatabase(): Promise<boolean> {\n try {\n await client`SELECT 1`;\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function closeDatabase(): Promise<void> {\n await client.end({ timeout: 5 });\n}\n",
|
|
9
9
|
"#!/usr/bin/env bun\nimport { mkdir } from \"node:fs/promises\";\nimport { basename, dirname, resolve } from \"node:path\";\n\ntype Options = Record<string, string | boolean>;\n\nfunction usage(exitCode = 1): never {\n console.log(`Usage: aegra <command> [options]\n\nCommands:\n init [path] Create a TypeScript Aegra project\n dev Start with Bun hot reload\n serve Start the production server\n up|down [args] Run Docker Compose\n db upgrade Apply database migrations\n version Print the version\n\nServer options: --host, --port, --config|-c, --env-file|-e\nInit options: --name|-n, --template|-t <basic|hono|auth|full>, --hono-version <version>, --force`);\n process.exit(exitCode);\n}\n\nfunction parseOptions(args: string[]): { positional: string[]; options: Options } {\n const positional: string[] = [];\n const options: Options = {};\n for (let index = 0; index < args.length; index++) {\n const value = args[index]!;\n if (!value.startsWith(\"-\")) { positional.push(value); continue; }\n const [rawName, inline] = value.split(\"=\", 2);\n const name = ({ \"-c\": \"config\", \"-e\": \"env-file\", \"-n\": \"name\", \"-t\": \"template\" } as Record<string, string>)[rawName!] ?? rawName!.replace(/^--/, \"\");\n if ([\"force\", \"help\", \"no-db-check\"].includes(name)) { options[name] = true; continue; }\n const next = inline ?? args[++index];\n if (!next) throw new Error(`Missing value for ${rawName}`);\n options[name] = next;\n }\n return { positional, options };\n}\n\nasync function loadEnv(path: string): Promise<void> {\n const file = Bun.file(path);\n if (!(await file.exists())) return;\n for (const line of (await file.text()).split(/\\r?\\n/)) {\n const match = line.match(/^\\s*(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*?)\\s*$/);\n if (!match || process.env[match[1]!] !== undefined) continue;\n process.env[match[1]!] = match[2]!.replace(/^(['\"])(.*)\\1$/, \"$2\");\n }\n}\n\nfunction run(command: string[], env?: Record<string, string | undefined>): void {\n const result = Bun.spawnSync(command, { stdin: \"inherit\", stdout: \"inherit\", stderr: \"inherit\", ...(env ? { env } : {}) });\n if (result.exitCode !== 0) process.exit(result.exitCode);\n}\n\nasync function serverEnvironment(options: Options): Promise<Record<string, string | undefined>> {\n await loadEnv(String(options[\"env-file\"] ?? resolve(\".env\")));\n if (options.host) process.env.HOST = String(options.host);\n if (options.port) process.env.PORT = String(options.port);\n if (options.config) process.env.AEGRA_CONFIG = resolve(String(options.config));\n else if (!process.env.AEGRA_CONFIG && await Bun.file(resolve(\"langgraph.json\")).exists()\n && !(await Bun.file(resolve(\"aegra.json\")).exists())) process.env.AEGRA_CONFIG = \"langgraph.json\";\n return process.env;\n}\n\nfunction slugify(value: string): string {\n return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, \"-\").replace(/^-|-$/g, \"\") || \"aegra-agent\";\n}\n\nfunction renderEnvironment(options: {\n name: string;\n version: string;\n withAuth: boolean;\n withRedis: boolean;\n}): string {\n return `# Application\nPROJECT_NAME=${options.name}\nVERSION=${options.version}\nENV_MODE=LOCAL\nLOG_VERBOSITY=verbose\nLOG_EXCLUDE_PATHS=/live\nHOST=0.0.0.0\nPORT=2026\nAEGRA_CONFIG=aegra.json\nRUN_MIGRATIONS_ON_STARTUP=true\n\n# PostgreSQL. DATABASE_URL takes precedence over the individual values.\nDATABASE_URL=postgresql://postgres:postgres@localhost:5432/aegra\nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=postgres\nPOSTGRES_HOST=localhost\nPOSTGRES_PORT=5432\nPOSTGRES_DB=aegra\n\n# Redis and distributed workers. Disabled means in-process execution.\nREDIS_BROKER_ENABLED=${options.withRedis}\nREDIS_URL=redis://localhost:6379/0\nWORKER_COUNT=3\nN_JOBS_PER_WORKER=10\nWORKER_QUEUE_KEY=aegra:jobs\nBG_JOB_TIMEOUT_SECS=3600\nBG_JOB_MAX_RETRIES=3\nWORKER_DRAIN_TIMEOUT=30\nSTUCK_PENDING_THRESHOLD_SECONDS=120\nLEASE_DURATION_SECONDS=30\nHEARTBEAT_INTERVAL_SECONDS=10\nREAPER_INTERVAL_SECONDS=15\nPOSTGRES_POLL_INTERVAL_SECONDS=5\nKEEPALIVE_INTERVAL_SECS=5\n\n# Scheduled runs\nCRON_ENABLED=true\nCRON_POLL_INTERVAL_SECONDS=60\nCRON_CLAIM_DURATION_SECONDS=300\nCRON_MAX_PER_USER=100\nCRON_ALLOW_SECONDS_SCHEDULE=false\nCRON_TICK_BATCH_SIZE=100\nCRON_MAX_PAYLOAD_BYTES=65536\n\n# Thread retention. Set one value to a number of minutes or a JSON TTL policy.\nAEGRA_THREAD_TTL=\nLANGGRAPH_THREAD_TTL=\n\n# Protocol and metrics\nMAX_SEARCH_LIMIT=1000\nENABLE_PROMETHEUS_METRICS=false\nFF_V2_EVENT_STREAMING=true\n\n# OpenTelemetry. OTEL_TARGETS accepts OTLP/GENERIC, LANGFUSE, and PHOENIX.\nOTEL_SERVICE_NAME=aegra-backend\nOTEL_TARGETS=\nOTEL_CONSOLE_EXPORT=false\nOTEL_EXPORTER_OTLP_ENDPOINT=\nOTEL_EXPORTER_OTLP_HEADERS=\nLANGFUSE_BASE_URL=http://localhost:3000\nLANGFUSE_PUBLIC_KEY=\nLANGFUSE_SECRET_KEY=\nPHOENIX_COLLECTOR_ENDPOINT=http://127.0.0.1:6006/v1/traces\nPHOENIX_API_KEY=\n\n# Generated graph and authentication examples\nOPENAI_API_KEY=\nAEGRA_AUTH_TOKEN=${options.withAuth ? \"replace-me\" : \"\"}\n`;\n}\n\nasync function writeProjectFile(root: string, path: string, content: string, force: boolean): Promise<\"created\" | \"skipped\"> {\n const target = resolve(root, path);\n if (!force && await Bun.file(target).exists()) return \"skipped\";\n await mkdir(dirname(target), { recursive: true });\n await Bun.write(target, content);\n return \"created\";\n}\n\nasync function initProject(args: string[]): Promise<void> {\n const { positional, options } = parseOptions(args);\n if (options.help) usage(0);\n const root = resolve(positional[0] ?? \".\");\n const name = String(options.name ?? basename(root));\n const slug = slugify(name);\n const requestedTemplate = String(options.template ?? \"basic\");\n const template = requestedTemplate === \"1\" ? \"basic\" : requestedTemplate;\n if (![\"basic\", \"hono\", \"auth\", \"full\"].includes(template)) {\n throw new Error(\"Template must be one of: basic, hono, auth, full\");\n }\n\n const pkg = await Bun.file(resolve(import.meta.dir, \"../package.json\")).json() as {\n name: string;\n version: string;\n peerDependencies: Record<string, string>;\n peerDependenciesMeta?: Record<string, { optional?: boolean }>;\n devDependencies: Record<string, string>;\n };\n const pinnedVersion = (name: string): string => {\n const version = pkg.devDependencies[name];\n if (!version) throw new Error(`Package metadata is missing ${name}`);\n return version;\n };\n const packageSpec = process.env.AEGRA_INIT_PACKAGE_SPEC?.trim() || pkg.version;\n const bunVersion = pinnedVersion(\"@types/bun\");\n const honoVersion = String(options[\"hono-version\"] ?? \"\").trim() || pinnedVersion(\"hono\");\n // aegra-hono keeps every third-party runtime library as a peer dependency so\n // projects own their versions. Only the required ones are declared, so a new\n // project never installs Redis, metrics, tracing, or embedding provider SDKs\n // it has not enabled.\n const runtimeDependencies: Record<string, string> = {};\n for (const name of Object.keys(pkg.peerDependencies).sort()) {\n if (pkg.peerDependenciesMeta?.[name]?.optional) continue;\n runtimeDependencies[name] = name === \"hono\" ? honoVersion : pinnedVersion(name);\n }\n const escapedName = JSON.stringify(`Hello from ${name}`);\n const graph = `import { AIMessage } from \"@langchain/core/messages\";\\nimport { MessagesAnnotation, StateGraph, START, END } from \"@langchain/langgraph\";\\nimport { defineGraph } from ${JSON.stringify(`${pkg.name}/graph`)};\\n\\nexport const graph = defineGraph(new StateGraph(MessagesAnnotation)\\n .addNode(\"reply\", async () => ({ messages: [new AIMessage(${escapedName})] }))\\n .addEdge(START, \"reply\").addEdge(\"reply\", END).compile());\\n`;\n const withHono = template === \"hono\" || template === \"full\";\n const withAuth = template === \"auth\" || template === \"full\";\n const withRedis = template === \"full\";\n const config = {\n name,\n dependencies: [\"./src\"],\n graphs: { [slug]: \"./src/graph.ts:graph\" },\n ...(withAuth ? { auth: { path: \"./src/auth.ts:auth\" } } : {}),\n ...(withHono ? { http: { app: \"./src/app.ts:app\", ...(withAuth ? { enable_custom_route_auth: true } : {}) } } : {}),\n };\n const redisService = withRedis ? ` redis:\\n image: redis:7-alpine\\n restart: unless-stopped\\n ports:\\n - \"\\${REDIS_PORT:-6379}:6379\"\\n volumes:\\n - redis-data:/data\\n healthcheck:\\n test: [\"CMD\", \"redis-cli\", \"ping\"]\\n interval: 5s\\n timeout: 5s\\n retries: 10\\n\\n` : \"\";\n const redisDependency = withRedis ? ` redis:\\n condition: service_healthy\\n` : \"\";\n const compose = `services:\\n postgres:\\n image: pgvector/pgvector:pg18\\n restart: unless-stopped\\n environment:\\n POSTGRES_USER: \\${POSTGRES_USER:-postgres}\\n POSTGRES_PASSWORD: \\${POSTGRES_PASSWORD:-postgres}\\n POSTGRES_DB: \\${POSTGRES_DB:-aegra}\\n ports:\\n - \"\\${POSTGRES_PORT:-5432}:5432\"\\n volumes:\\n - postgres-data:/var/lib/postgresql\\n healthcheck:\\n test: [\"CMD-SHELL\", \"pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB\"]\\n interval: 5s\\n timeout: 5s\\n retries: 10\\n\\n${redisService} api:\\n build: .\\n restart: unless-stopped\\n ports:\\n - \"\\${PORT:-2026}:2026\"\\n env_file:\\n - .env\\n environment:\\n DATABASE_URL: postgresql://\\${POSTGRES_USER:-postgres}:\\${POSTGRES_PASSWORD:-postgres}@postgres:5432/\\${POSTGRES_DB:-aegra}\\n PORT: \"2026\"\\n AEGRA_CONFIG: /app/aegra.json\\n REDIS_BROKER_ENABLED: \"${withRedis}\"\\n REDIS_URL: redis://redis:6379/0\\n depends_on:\\n postgres:\\n condition: service_healthy\\n${redisDependency} healthcheck:\\n test: [\"CMD\", \"bun\", \"-e\", \"const r=await fetch('http://localhost:2026/health');process.exit(r.ok?0:1)\"]\\n interval: 30s\\n timeout: 10s\\n retries: 3\\n start_period: 10s\\n\\nvolumes:\\n postgres-data:\\n${withRedis ? \" redis-data:\\n\" : \"\"}`;\n const dockerfile = `FROM oven/bun:${bunVersion}-alpine AS install\\nWORKDIR /app\\nCOPY package.json bun.lock ./\\nRUN bun install --frozen-lockfile --production\\n\\nFROM oven/bun:${bunVersion}-alpine AS runtime\\nWORKDIR /app\\nENV NODE_ENV=production\\nCOPY --from=install /app/node_modules ./node_modules\\nCOPY package.json aegra.json ./\\nCOPY src ./src\\nUSER bun\\nEXPOSE 2026\\nCMD [\"bun\", \"run\", \"start\"]\\n`;\n const localServices = `docker compose up -d postgres${withRedis ? \" redis\" : \"\"}`;\n // Redis is the only optional integration the templates switch on. Prometheus\n // metrics, OpenTelemetry tracing, and store embedding providers stay\n // uninstalled until a project enables them and adds the packages itself.\n if (withRedis) runtimeDependencies.ioredis = pinnedVersion(\"ioredis\");\n const packageJson = {\n name: slug,\n private: true,\n type: \"module\",\n scripts: {\n dev: \"aegra dev\",\n start: \"aegra serve\",\n check: \"tsc --noEmit\",\n db: \"aegra db upgrade\",\n \"services:up\": localServices,\n \"services:down\": \"docker compose down\",\n \"docker:up\": \"docker compose up --build -d\",\n \"docker:down\": \"docker compose down\",\n },\n dependencies: {\n [pkg.name]: packageSpec,\n ...runtimeDependencies,\n },\n devDependencies: {\n \"@types/bun\": bunVersion,\n typescript: pinnedVersion(\"typescript\"),\n },\n engines: { bun: `>=${bunVersion}` },\n packageManager: `bun@${bunVersion}`,\n };\n const files: Record<string, string> = {\n \"aegra.json\": `${JSON.stringify(config, null, 2)}\\n`,\n \"package.json\": `${JSON.stringify(packageJson, null, 2)}\\n`,\n \"tsconfig.json\": `${JSON.stringify({ compilerOptions: { target: \"ES2023\", module: \"Preserve\", moduleResolution: \"bundler\", strict: true, noUncheckedIndexedAccess: true, exactOptionalPropertyTypes: true, noEmit: true, types: [\"bun\"], skipLibCheck: true }, include: [\"src\"] }, null, 2)}\\n`,\n \"src/graph.ts\": graph,\n \".env.example\": renderEnvironment({ name, version: pkg.version, withAuth, withRedis }),\n \".gitignore\": `node_modules\\n.env\\ndist\\n*.tsbuildinfo\\n`,\n \".dockerignore\": `node_modules\\n.env\\ndist\\n.git\\n*.log\\n`,\n \"Dockerfile\": dockerfile,\n \"docker-compose.yml\": compose,\n \"README.md\": `# ${name}\\n\\nTypeScript Aegra backend generated with \\`${pkg.name}\\`.\\n\\n## Local development\\n\\n\\`\\`\\`bash\\nbun install\\ncp .env.example .env\\nbun run services:up\\nbun run db\\nbun run dev\\n\\`\\`\\`\\n\\nThe API listens on http://localhost:2026 and exposes its API reference at http://localhost:2026/docs.\\n\\n## Docker\\n\\n\\`\\`\\`bash\\nbun install\\ncp .env.example .env\\nbun run docker:up\\n\\`\\`\\`\\n`,\n };\n if (withHono) files[\"src/app.ts\"] = `import { Hono } from \"hono\";\\nimport { defineApp } from ${JSON.stringify(`${pkg.name}/hono`)};\\nimport type { AppVariables } from ${JSON.stringify(`${pkg.name}/types`)};\\n\\nexport const app = defineApp(new Hono<{ Variables: AppVariables }>().get(\"/hello\", (context) => context.json({ message: ${escapedName} })));\\n`;\n if (withAuth) files[\"src/auth.ts\"] = `import { Auth } from ${JSON.stringify(`${pkg.name}/auth`)};\\n\\nexport const auth = new Auth();\\nauth.authenticate((request) => {\\n const token = process.env.AEGRA_AUTH_TOKEN;\\n if (!token || request.headers.get(\"authorization\") !== \\`Bearer \\${token}\\`) throw new Error(\"Invalid bearer token\");\\n return { identity: request.headers.get(\"x-user-id\")?.trim() || \"authenticated-user\", isAuthenticated: true, permissions: [] };\\n});\\n`;\n let created = 0;\n let skipped = 0;\n for (const [path, content] of Object.entries(files)) {\n if (await writeProjectFile(root, path, content, Boolean(options.force)) === \"created\") created++;\n else skipped++;\n }\n console.log(`Created ${created} files in ${root}${skipped ? ` (${skipped} skipped; use --force to overwrite)` : \"\"}`);\n if (!skipped) {\n const changeDirectory = root === resolve(\".\") ? \"\" : ` cd ${JSON.stringify(root)}\\n`;\n console.log(`\\nNext steps:\\n${changeDirectory} bun install\\n cp .env.example .env\\n bun run services:up\\n bun run db\\n bun run dev`);\n }\n}\n\nexport async function main(argv = process.argv.slice(2)): Promise<void> {\n const [command, ...args] = argv;\n if (!command || command === \"help\" || command === \"--help\") usage(command ? 0 : 1);\n if (command === \"init\") return initProject(args);\n if (command === \"version\" || command === \"--version\") {\n const pkg = await Bun.file(resolve(import.meta.dir, \"../package.json\")).json() as { version: string };\n console.log(pkg.version);\n return;\n }\n if (command === \"dev\" || command === \"serve\") {\n const { options } = parseOptions(args);\n if (options.help) usage(0);\n const env = await serverEnvironment(options);\n const builtEntrypoint = resolve(import.meta.dir, \"index.js\");\n const entrypoint = await Bun.file(builtEntrypoint).exists() ? builtEntrypoint : resolve(import.meta.dir, \"index.ts\");\n if (command === \"dev\") run([\"bun\", \"--hot\", entrypoint], env);\n else await import(entrypoint);\n return;\n }\n if (command === \"up\" || command === \"down\") return run([\"docker\", \"compose\", command, ...args]);\n if (command === \"db\" && args[0] === \"upgrade\") {\n const { options } = parseOptions(args.slice(1));\n await serverEnvironment(options);\n const { migrate, closeDatabase } = await import(\"./core/database.ts\");\n await migrate();\n await closeDatabase();\n console.log(\"Database is up to date\");\n return;\n }\n usage();\n}\n\nif (import.meta.main) main().catch((error: unknown) => { console.error(error instanceof Error ? error.message : error); process.exit(1); });\n"
|
|
10
10
|
],
|
|
11
11
|
"mappings": "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",
|
|
12
|
-
"debugId": "
|
|
12
|
+
"debugId": "780939192C8D850764756E2164756E21",
|
|
13
13
|
"names": []
|
|
14
14
|
}
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var init_settings = __esm(() => {
|
|
|
22
22
|
booleanFromEnv = z.stringbool().default(false);
|
|
23
23
|
environmentShape = {
|
|
24
24
|
PROJECT_NAME: z.string().default("Aegra"),
|
|
25
|
-
VERSION: z.string().default("0.
|
|
25
|
+
VERSION: z.string().default("0.12.0"),
|
|
26
26
|
ENV_MODE: z.string().default("PRODUCTION"),
|
|
27
27
|
LOG_VERBOSITY: z.string().default("verbose"),
|
|
28
28
|
LOG_EXCLUDE_PATHS: z.string().default(""),
|
|
@@ -598,6 +598,9 @@ var jsonObjectSchema = z3.record(z3.string(), z3.json());
|
|
|
598
598
|
function getAuthorizationValue(context) {
|
|
599
599
|
return context.get("authorizationValue") ?? {};
|
|
600
600
|
}
|
|
601
|
+
function getAuthorizationFilter(context) {
|
|
602
|
+
return context.get("authorizationFilter") ?? {};
|
|
603
|
+
}
|
|
601
604
|
async function parseJson(context, schema) {
|
|
602
605
|
let body;
|
|
603
606
|
try {
|
|
@@ -755,10 +758,10 @@ function pathValues(path) {
|
|
|
755
758
|
values.cron_id = cronId;
|
|
756
759
|
return values;
|
|
757
760
|
}
|
|
758
|
-
async function
|
|
761
|
+
async function runAuthorizationHandler(context, resource, action, value) {
|
|
759
762
|
const handler = authorizationHandler?.(resource, action);
|
|
760
763
|
if (!handler)
|
|
761
|
-
return value;
|
|
764
|
+
return { value, filter: {} };
|
|
762
765
|
const user = context.get("user");
|
|
763
766
|
const result = await handler({ user, resource, action, permissions: user.permissions }, value);
|
|
764
767
|
if (result === false)
|
|
@@ -766,12 +769,17 @@ async function authorizeResource(context, resource, action, value) {
|
|
|
766
769
|
if (result !== undefined && result !== true && (typeof result !== "object" || Array.isArray(result) || result === null)) {
|
|
767
770
|
throw new Error("Authorization handlers must return an object, true, false, or undefined");
|
|
768
771
|
}
|
|
769
|
-
|
|
772
|
+
const filter = result && typeof result === "object" ? result : {};
|
|
773
|
+
return { value: { ...value, ...filter }, filter };
|
|
774
|
+
}
|
|
775
|
+
async function authorizeResource(context, resource, action, value) {
|
|
776
|
+
return (await runAuthorizationHandler(context, resource, action, value)).value;
|
|
770
777
|
}
|
|
771
778
|
async function authorize(context) {
|
|
772
779
|
const event = authorizationEvent(context.req.method, context.req.path);
|
|
773
780
|
if (!event) {
|
|
774
781
|
context.set("authorizationValue", {});
|
|
782
|
+
context.set("authorizationFilter", {});
|
|
775
783
|
return;
|
|
776
784
|
}
|
|
777
785
|
let body = {};
|
|
@@ -783,12 +791,15 @@ async function authorize(context) {
|
|
|
783
791
|
const query = Object.fromEntries(new URL(context.req.url).searchParams);
|
|
784
792
|
const value = { ...query, ...body, ...pathValues(context.req.path) };
|
|
785
793
|
const [resource, action] = event;
|
|
786
|
-
|
|
794
|
+
const authorized = await runAuthorizationHandler(context, resource, action, value);
|
|
795
|
+
context.set("authorizationValue", authorized.value);
|
|
796
|
+
context.set("authorizationFilter", authorized.filter);
|
|
787
797
|
}
|
|
788
798
|
var authMiddleware = async (context, next) => {
|
|
789
799
|
if (!authenticate) {
|
|
790
800
|
context.set("user", anonymousUser);
|
|
791
801
|
context.set("authorizationValue", {});
|
|
802
|
+
context.set("authorizationFilter", {});
|
|
792
803
|
await next();
|
|
793
804
|
return;
|
|
794
805
|
}
|
|
@@ -3232,7 +3243,7 @@ var openapi_default = {
|
|
|
3232
3243
|
info: {
|
|
3233
3244
|
title: "Aegra",
|
|
3234
3245
|
description: "\u751F\u4EA7\u53EF\u7528\u7684 Agent Protocol \u670D\u52A1\u7AEF",
|
|
3235
|
-
version: "0.
|
|
3246
|
+
version: "0.12.0"
|
|
3236
3247
|
},
|
|
3237
3248
|
paths: {
|
|
3238
3249
|
"/info": {
|
|
@@ -9523,8 +9534,72 @@ healthRoutes.get("/live", (context) => context.json({ status: "alive" }));
|
|
|
9523
9534
|
init_database();
|
|
9524
9535
|
init_settings();
|
|
9525
9536
|
import { Hono as Hono8 } from "hono";
|
|
9526
|
-
import { and as
|
|
9537
|
+
import { and as and10, asc as asc6, desc as desc6, eq as eq9, inArray as inArray6, sql as sql9 } from "drizzle-orm";
|
|
9527
9538
|
import { z as z11 } from "zod";
|
|
9539
|
+
|
|
9540
|
+
// src/core/auth-filters.ts
|
|
9541
|
+
import { and as and8, or as or4, sql as sql7 } from "drizzle-orm";
|
|
9542
|
+
var maxFilterDepth = 2;
|
|
9543
|
+
function malformed(reason) {
|
|
9544
|
+
return new ApiError(500, `Auth handler filter ${reason}. Check the filter returned by your auth handler.`);
|
|
9545
|
+
}
|
|
9546
|
+
function isPlainObject2(value) {
|
|
9547
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9548
|
+
}
|
|
9549
|
+
function unwrapMetadataEnvelope(filters) {
|
|
9550
|
+
const envelope = filters.metadata;
|
|
9551
|
+
if (!isPlainObject2(envelope))
|
|
9552
|
+
return filters;
|
|
9553
|
+
const { metadata: _envelope, ...rest } = filters;
|
|
9554
|
+
return { ...envelope, ...rest };
|
|
9555
|
+
}
|
|
9556
|
+
function combine(operator, clauses) {
|
|
9557
|
+
return operator === "and" ? and8(...clauses) : or4(...clauses);
|
|
9558
|
+
}
|
|
9559
|
+
function compileField(column, key, value) {
|
|
9560
|
+
if (!isPlainObject2(value)) {
|
|
9561
|
+
return sql7`${column} @> ${JSON.stringify({ [key]: value ?? null })}::jsonb`;
|
|
9562
|
+
}
|
|
9563
|
+
const entries = Object.entries(value);
|
|
9564
|
+
if (entries.length !== 1) {
|
|
9565
|
+
throw malformed("value must be a dict with exactly one operator key ($eq or $contains)");
|
|
9566
|
+
}
|
|
9567
|
+
const [operator, operand] = entries[0];
|
|
9568
|
+
if (operator === "$eq") {
|
|
9569
|
+
return sql7`${column} @> ${JSON.stringify({ [key]: operand ?? null })}::jsonb`;
|
|
9570
|
+
}
|
|
9571
|
+
if (operator === "$contains") {
|
|
9572
|
+
const items = Array.isArray(operand) ? operand : [operand ?? null];
|
|
9573
|
+
return sql7`(${column} -> ${key}::text) @> ${JSON.stringify(items)}::jsonb`;
|
|
9574
|
+
}
|
|
9575
|
+
throw malformed(`operator '${operator}' is not supported; use $eq or $contains`);
|
|
9576
|
+
}
|
|
9577
|
+
function compileBooleanOperator(column, operator, branches, depth) {
|
|
9578
|
+
if (depth >= maxFilterDepth) {
|
|
9579
|
+
throw malformed(`nests deeper than ${maxFilterDepth} levels`);
|
|
9580
|
+
}
|
|
9581
|
+
if (!Array.isArray(branches) || branches.length < 2) {
|
|
9582
|
+
throw malformed(`'${operator}' must be a list of at least 2 filter objects`);
|
|
9583
|
+
}
|
|
9584
|
+
for (const branch of branches) {
|
|
9585
|
+
if (!isPlainObject2(branch) || !Object.keys(branch).length) {
|
|
9586
|
+
throw malformed(`'${operator}' contains an empty or non-dict branch`);
|
|
9587
|
+
}
|
|
9588
|
+
}
|
|
9589
|
+
const compiled = branches.map((branch) => combine("and", compile(column, branch, depth + 1)));
|
|
9590
|
+
return combine(operator === "$or" ? "or" : "and", compiled);
|
|
9591
|
+
}
|
|
9592
|
+
function compile(column, filters, depth) {
|
|
9593
|
+
return Object.entries(filters).map(([key, value]) => key === "$or" || key === "$and" ? compileBooleanOperator(column, key, value, depth) : compileField(column, key, value));
|
|
9594
|
+
}
|
|
9595
|
+
function buildMetadataFilter(column, filters) {
|
|
9596
|
+
if (!filters || !Object.keys(filters).length)
|
|
9597
|
+
return;
|
|
9598
|
+
const clauses = compile(column, unwrapMetadataEnvelope(filters), 0);
|
|
9599
|
+
return clauses.length ? combine("and", clauses) : undefined;
|
|
9600
|
+
}
|
|
9601
|
+
|
|
9602
|
+
// src/routes/threads.ts
|
|
9528
9603
|
init_schema();
|
|
9529
9604
|
|
|
9530
9605
|
// src/services/thread-ttl.ts
|
|
@@ -9532,7 +9607,7 @@ init_project();
|
|
|
9532
9607
|
init_settings();
|
|
9533
9608
|
init_database();
|
|
9534
9609
|
import { z as z10 } from "zod";
|
|
9535
|
-
import { and as
|
|
9610
|
+
import { and as and9, asc as asc5, eq as eq8, inArray as inArray5, lte as lte2, notExists as notExists2, sql as sql8 } from "drizzle-orm";
|
|
9536
9611
|
init_schema();
|
|
9537
9612
|
var ttlSchema = z10.object({
|
|
9538
9613
|
strategy: z10.enum(["delete", "keep_latest"]).default("delete"),
|
|
@@ -9566,26 +9641,26 @@ async function resolveThreadTtl(request) {
|
|
|
9566
9641
|
ttlMinutes: requestedMinutes ?? configured?.default_ttl ?? 43200
|
|
9567
9642
|
};
|
|
9568
9643
|
}
|
|
9569
|
-
async function pruneExpiredThreads(userId) {
|
|
9644
|
+
async function pruneExpiredThreads(userId, metadataFilter) {
|
|
9570
9645
|
const config = await threadTtlConfig() ?? ttlSchema.parse({});
|
|
9571
9646
|
return db.transaction(async (transaction) => {
|
|
9572
|
-
const activeRun = transaction.select({ value:
|
|
9647
|
+
const activeRun = transaction.select({ value: sql8`1` }).from(runs).where(and9(eq8(runs.thread_id, threadTtl.thread_id), inArray5(runs.status, ["pending", "running"])));
|
|
9573
9648
|
const rows = await transaction.select({
|
|
9574
9649
|
thread_id: threadTtl.thread_id,
|
|
9575
9650
|
strategy: threadTtl.strategy,
|
|
9576
9651
|
ttl_minutes: threadTtl.ttl_minutes
|
|
9577
|
-
}).from(threadTtl).innerJoin(threads, eq8(threads.thread_id, threadTtl.thread_id)).where(
|
|
9652
|
+
}).from(threadTtl).innerJoin(threads, eq8(threads.thread_id, threadTtl.thread_id)).where(and9(lte2(threadTtl.expires_at, new Date), userId ? eq8(threads.user_id, userId) : undefined, buildMetadataFilter(threads.metadata_json, metadataFilter), notExists2(activeRun))).orderBy(asc5(threadTtl.expires_at)).limit(config.sweep_limit).for("update", { skipLocked: true });
|
|
9578
9653
|
let deleted = 0;
|
|
9579
9654
|
let pruned = 0;
|
|
9580
9655
|
for (const row of rows) {
|
|
9581
9656
|
if (row.strategy === "keep_latest") {
|
|
9582
|
-
await transaction.execute(
|
|
9657
|
+
await transaction.execute(sql8`DELETE FROM checkpoints c USING (
|
|
9583
9658
|
SELECT checkpoint_ns, max(checkpoint_id) latest_id FROM checkpoints WHERE thread_id=${row.thread_id} GROUP BY checkpoint_ns
|
|
9584
9659
|
) keep WHERE c.thread_id=${row.thread_id} AND c.checkpoint_ns=keep.checkpoint_ns AND c.checkpoint_id<>keep.latest_id`);
|
|
9585
|
-
await transaction.execute(
|
|
9660
|
+
await transaction.execute(sql8`DELETE FROM checkpoint_writes w WHERE w.thread_id=${row.thread_id} AND NOT EXISTS (
|
|
9586
9661
|
SELECT 1 FROM checkpoints c WHERE c.thread_id=w.thread_id AND c.checkpoint_ns=w.checkpoint_ns
|
|
9587
9662
|
AND c.checkpoint_id=w.checkpoint_id)`);
|
|
9588
|
-
await transaction.execute(
|
|
9663
|
+
await transaction.execute(sql8`DELETE FROM checkpoint_blobs b WHERE b.thread_id=${row.thread_id} AND NOT EXISTS (
|
|
9589
9664
|
SELECT 1 FROM checkpoints c, jsonb_each_text(c.checkpoint->'channel_versions') cv(channel,version)
|
|
9590
9665
|
WHERE c.thread_id=b.thread_id AND c.checkpoint_ns=b.checkpoint_ns AND cv.channel=b.channel AND cv.version=b.version)`);
|
|
9591
9666
|
await transaction.update(threadTtl).set({ expires_at: new Date(Date.now() + row.ttl_minutes * 60000) }).where(eq8(threadTtl.thread_id, row.thread_id));
|
|
@@ -9666,11 +9741,12 @@ function authorizationFilters3(context) {
|
|
|
9666
9741
|
return [
|
|
9667
9742
|
typeof value.thread_id === "string" ? eq9(threads.thread_id, value.thread_id) : undefined,
|
|
9668
9743
|
typeof value.status === "string" ? eq9(threads.status, value.status) : undefined,
|
|
9669
|
-
Object.keys(metadata).length ?
|
|
9744
|
+
Object.keys(metadata).length ? sql9`${threads.metadata_json} @> ${JSON.stringify(metadata)}::jsonb` : undefined,
|
|
9745
|
+
buildMetadataFilter(threads.metadata_json, getAuthorizationFilter(context))
|
|
9670
9746
|
].filter((filter) => filter !== undefined);
|
|
9671
9747
|
}
|
|
9672
9748
|
async function ownedThread2(threadId, context) {
|
|
9673
|
-
const rows = await db.select().from(threads).where(
|
|
9749
|
+
const rows = await db.select().from(threads).where(and10(eq9(threads.thread_id, threadId), eq9(threads.user_id, context.get("user").identity), ...authorizationFilters3(context))).limit(1);
|
|
9674
9750
|
if (!rows[0])
|
|
9675
9751
|
throw new ApiError(404, "Thread not found");
|
|
9676
9752
|
return thread(rows[0]);
|
|
@@ -9682,7 +9758,7 @@ async function graphForThread(threadId, context) {
|
|
|
9682
9758
|
const graphId = typeof owned.metadata.graph_id === "string" ? owned.metadata.graph_id : undefined;
|
|
9683
9759
|
if (graphId)
|
|
9684
9760
|
return getGraph(graphId, { user, accessContext: "threads.read", config: graphConfig(threadId) });
|
|
9685
|
-
const rows = await db.select({ graph_id: assistants.graph_id }).from(assistants).innerJoin(runs, eq9(runs.assistant_id, assistants.assistant_id)).where(
|
|
9761
|
+
const rows = await db.select({ graph_id: assistants.graph_id }).from(assistants).innerJoin(runs, eq9(runs.assistant_id, assistants.assistant_id)).where(and10(eq9(runs.thread_id, threadId), eq9(runs.user_id, userId))).orderBy(desc6(runs.created_at)).limit(1);
|
|
9686
9762
|
if (!rows[0])
|
|
9687
9763
|
return;
|
|
9688
9764
|
return getGraph(String(rows[0].graph_id), { user, accessContext: "threads.read", config: graphConfig(threadId) });
|
|
@@ -9749,7 +9825,7 @@ threadRoutes.post("/threads", async (context) => {
|
|
|
9749
9825
|
});
|
|
9750
9826
|
if (created[0])
|
|
9751
9827
|
return context.json(thread(created[0]));
|
|
9752
|
-
const existing = await db.select().from(threads).where(
|
|
9828
|
+
const existing = await db.select().from(threads).where(and10(eq9(threads.thread_id, id), eq9(threads.user_id, userId))).limit(1);
|
|
9753
9829
|
if (existing[0] && ifExists === "do_nothing")
|
|
9754
9830
|
return context.json(thread(existing[0]));
|
|
9755
9831
|
throw new ApiError(409, "Thread already exists");
|
|
@@ -9757,7 +9833,7 @@ threadRoutes.post("/threads", async (context) => {
|
|
|
9757
9833
|
threadRoutes.get("/threads", async (context) => {
|
|
9758
9834
|
const userId = context.get("user").identity;
|
|
9759
9835
|
const filters = authorizationFilters3(context);
|
|
9760
|
-
const rows = await db.select().from(threads).where(
|
|
9836
|
+
const rows = await db.select().from(threads).where(and10(eq9(threads.user_id, userId), ...filters)).orderBy(desc6(threads.created_at));
|
|
9761
9837
|
return context.json({ threads: rows.map((row) => thread(row)), total: rows.length });
|
|
9762
9838
|
});
|
|
9763
9839
|
threadRoutes.post("/threads/search", async (context) => {
|
|
@@ -9768,7 +9844,7 @@ threadRoutes.post("/threads/search", async (context) => {
|
|
|
9768
9844
|
throw new ApiError(422, "Invalid order_by");
|
|
9769
9845
|
const fieldName = body.sort_by ?? legacy?.[1]?.toLowerCase() ?? "created_at";
|
|
9770
9846
|
const field = threads[fieldName];
|
|
9771
|
-
const rows = await db.select().from(threads).where(
|
|
9847
|
+
const rows = await db.select().from(threads).where(and10(eq9(threads.user_id, userId), body.status ? eq9(threads.status, body.status) : undefined, sql9`${threads.metadata_json} @> ${JSON.stringify(body.metadata ?? {})}::jsonb`, buildMetadataFilter(threads.metadata_json, getAuthorizationFilter(context)))).orderBy((body.sort_order ?? legacy?.[2]?.toLowerCase()) === "asc" ? asc6(field) : desc6(field)).limit(clampLimit(body.limit, 20, settings.MAX_SEARCH_LIMIT)).offset(body.offset ?? 0);
|
|
9772
9848
|
return context.json(rows.map((row) => thread(row)));
|
|
9773
9849
|
});
|
|
9774
9850
|
threadRoutes.get("/threads/:threadId", async (context) => context.json(await ownedThread2(context.req.param("threadId"), context)));
|
|
@@ -9777,7 +9853,7 @@ threadRoutes.patch("/threads/:threadId", async (context) => {
|
|
|
9777
9853
|
const id = context.req.param("threadId");
|
|
9778
9854
|
const userId = context.get("user").identity;
|
|
9779
9855
|
const patch = { ...body.metadata ?? {}, ...authorizedMetadata(context) };
|
|
9780
|
-
const rows = await db.update(threads).set({ metadata_json:
|
|
9856
|
+
const rows = await db.update(threads).set({ metadata_json: sql9`${threads.metadata_json} || ${JSON.stringify(patch)}::jsonb`, updated_at: new Date }).where(and10(eq9(threads.thread_id, id), eq9(threads.user_id, userId), ...authorizationFilters3(context))).returning();
|
|
9781
9857
|
if (!rows[0])
|
|
9782
9858
|
throw new ApiError(404, "Thread not found");
|
|
9783
9859
|
return context.json(thread(rows[0]));
|
|
@@ -9785,16 +9861,16 @@ threadRoutes.patch("/threads/:threadId", async (context) => {
|
|
|
9785
9861
|
threadRoutes.delete("/threads/:threadId", async (context) => {
|
|
9786
9862
|
const threadId = context.req.param("threadId");
|
|
9787
9863
|
await ownedThread2(threadId, context);
|
|
9788
|
-
for (const row of await db.select({ run_id: runs.run_id }).from(runs).where(
|
|
9864
|
+
for (const row of await db.select({ run_id: runs.run_id }).from(runs).where(and10(eq9(runs.thread_id, threadId), inArray6(runs.status, ["pending", "running"])))) {
|
|
9789
9865
|
await cancelActiveRun(String(row.run_id));
|
|
9790
9866
|
}
|
|
9791
9867
|
await deleteThreadCheckpoints(threadId);
|
|
9792
|
-
const rows = await db.delete(threads).where(
|
|
9868
|
+
const rows = await db.delete(threads).where(and10(eq9(threads.thread_id, threadId), eq9(threads.user_id, context.get("user").identity), ...authorizationFilters3(context))).returning({ thread_id: threads.thread_id });
|
|
9793
9869
|
if (!rows[0])
|
|
9794
9870
|
throw new ApiError(404, "Thread not found");
|
|
9795
9871
|
return context.json({ status: "deleted" });
|
|
9796
9872
|
});
|
|
9797
|
-
threadRoutes.post("/threads/prune", async (context) => context.json(await pruneExpiredThreads(context.get("user").identity)));
|
|
9873
|
+
threadRoutes.post("/threads/prune", async (context) => context.json(await pruneExpiredThreads(context.get("user").identity, getAuthorizationFilter(context))));
|
|
9798
9874
|
threadRoutes.get("/threads/:threadId/state", async (context) => {
|
|
9799
9875
|
const id = context.req.param("threadId");
|
|
9800
9876
|
const graph = await graphForThread(id, context);
|
|
@@ -9985,7 +10061,7 @@ init_database();
|
|
|
9985
10061
|
init_settings();
|
|
9986
10062
|
init_database();
|
|
9987
10063
|
import { hostname } from "os";
|
|
9988
|
-
import { and as
|
|
10064
|
+
import { and as and11, asc as asc7, eq as eq10, like, lt as lt3, or as or5 } from "drizzle-orm";
|
|
9989
10065
|
init_schema();
|
|
9990
10066
|
var running = false;
|
|
9991
10067
|
var workerTasks = [];
|
|
@@ -10008,7 +10084,7 @@ async function workerLoop(index2) {
|
|
|
10008
10084
|
if (!runId)
|
|
10009
10085
|
continue;
|
|
10010
10086
|
try {
|
|
10011
|
-
const rows = await db.select().from(runs).where(
|
|
10087
|
+
const rows = await db.select().from(runs).where(and11(eq10(runs.run_id, runId), eq10(runs.status, "pending"))).limit(1);
|
|
10012
10088
|
if (!rows[0])
|
|
10013
10089
|
continue;
|
|
10014
10090
|
const record = runFromRow(rows[0]);
|
|
@@ -10032,7 +10108,7 @@ async function reapAbandonedRuns() {
|
|
|
10032
10108
|
const now = new Date;
|
|
10033
10109
|
const stale = new Date(now.getTime() - settings.STUCK_PENDING_THRESHOLD_SECONDS * 1000);
|
|
10034
10110
|
const recovered = await db.transaction(async (transaction) => {
|
|
10035
|
-
const recoverable = await transaction.select().from(runs).where(
|
|
10111
|
+
const recoverable = await transaction.select().from(runs).where(or5(and11(eq10(runs.status, "running"), lt3(runs.lease_expires_at, now)), and11(eq10(runs.status, "pending"), lt3(runs.updated_at, stale)))).for("update", { skipLocked: true });
|
|
10036
10112
|
const queued = [];
|
|
10037
10113
|
const exhausted = [];
|
|
10038
10114
|
for (const row of recoverable) {
|
|
@@ -10086,7 +10162,7 @@ async function stopWorkers() {
|
|
|
10086
10162
|
reaper = undefined;
|
|
10087
10163
|
const drained = Promise.allSettled(workerTasks);
|
|
10088
10164
|
await Promise.race([drained, Bun.sleep(settings.WORKER_DRAIN_TIMEOUT * 1000)]);
|
|
10089
|
-
const interrupted = await db.select({ run_id: runs.run_id }).from(runs).where(
|
|
10165
|
+
const interrupted = await db.select({ run_id: runs.run_id }).from(runs).where(and11(eq10(runs.status, "running"), like(runs.claimed_by, `${instanceId}-%`)));
|
|
10090
10166
|
for (const row of interrupted) {
|
|
10091
10167
|
await cancelActiveRun(String(row.run_id), "shutdown");
|
|
10092
10168
|
}
|
|
@@ -10238,4 +10314,4 @@ async function shutdown() {
|
|
|
10238
10314
|
process.on("SIGINT", () => void shutdown().then(() => process.exit(0)));
|
|
10239
10315
|
process.on("SIGTERM", () => void shutdown().then(() => process.exit(0)));
|
|
10240
10316
|
|
|
10241
|
-
//# debugId=
|
|
10317
|
+
//# debugId=01D88C5296A5310964756E2164756E21
|