@asm-agent/postgres 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -0
- package/dist/database.d.ts +58 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +373 -0
- package/dist/database.js.map +1 -0
- package/dist/grounded-memory.d.ts +148 -0
- package/dist/grounded-memory.d.ts.map +1 -0
- package/dist/grounded-memory.js +386 -0
- package/dist/grounded-memory.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/repositories.d.ts +53 -0
- package/dist/repositories.d.ts.map +1 -0
- package/dist/repositories.js +2 -0
- package/dist/repositories.js.map +1 -0
- package/dist/types.d.ts +87 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/migrations/0001_foundation.sql +143 -0
- package/migrations/0002_grounded_memory.sql +160 -0
- package/migrations/0003_evidence_cleanup.sql +6 -0
- package/migrations/0004_governance.sql +61 -0
- package/migrations/0005_asm_models.sql +64 -0
- package/migrations/0006_knowledge_workflows.sql +82 -0
- package/migrations/0007_asm_cm_runtime.sql +28 -0
- package/migrations/0008_promotion_security.sql +8 -0
- package/package.json +46 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport type { PoolClient, QueryResult, QueryResultRow } from \"pg\";\nimport { Pool } from \"pg\";\nimport type { PostgresConfig } from \"./config.js\";\nimport type { DurableRepositories } from \"./repositories.js\";\nimport type {\n\tGoalRecord,\n\tIdempotencyStartResult,\n\tLeaseRecord,\n\tOutboxEvent,\n\tOwnerRecord,\n\tProjectRecord,\n\tScheduleRecord,\n\tSessionMessageInput,\n\tSessionMessageRecord,\n\tSessionRecord,\n\tSessionStatus,\n} from \"./types.js\";\n\nconst MIGRATION_LOCK_ID = 4_385_780_217;\n\ninterface MigrationFile {\n\tversion: number;\n\tname: string;\n\tchecksum: string;\n\tsql: string;\n}\n\ninterface MigrationRow extends QueryResultRow {\n\tversion: number;\n\tname: string;\n\tchecksum: string;\n}\n\ninterface SessionRow extends QueryResultRow {\n\tid: string;\n\tproject_id: string;\n\tparent_session_id: string | null;\n\tstatus: SessionStatus;\n\tcwd: string;\n\tname: string | null;\n\trlm_depth: number;\n\ttranscript_revision: string;\n\tcreated_at: Date;\n\tupdated_at: Date;\n}\n\ninterface LeaseRow extends QueryResultRow {\n\tresource_type: string;\n\tresource_id: string;\n\towner_id: string;\n\tfencing_token: string;\n\texpires_at: Date;\n}\n\ninterface OutboxRow extends QueryResultRow {\n\tid: string;\n\ttopic: string;\n\taggregate_type: string;\n\taggregate_id: string;\n\tpayload: unknown;\n\theaders: unknown;\n\tattempts: number;\n}\n\ninterface IdempotencyRow extends QueryResultRow {\n\trequest_hash: string;\n\tstatus: \"started\" | \"completed\" | \"failed\";\n\tresponse: unknown;\n}\n\ninterface MessageRow extends QueryResultRow {\n\tsequence: string;\n\tentry_id: string;\n\tparent_entry_id: string | null;\n\tentry_type: string;\n\tpayload: unknown;\n\tcreated_at: Date;\n}\n\ninterface GoalRow extends QueryResultRow {\n\tid: string;\n\tsession_id: string;\n\tstatus: GoalRecord[\"status\"];\n\tobjective: string;\n\ttoken_budget: string | null;\n\ttokens_used: string;\n\ttime_used_seconds: string;\n\tcontinuations_used: number;\n\tlast_reason: string | null;\n\tlast_error: string | null;\n}\n\ninterface ScheduleRow extends QueryResultRow {\n\tid: string;\n\tsession_id: string;\n\tstatus: ScheduleRecord[\"status\"];\n\tsource: string;\n\tschedule_kind: ScheduleRecord[\"scheduleKind\"];\n\texpression: string;\n\tinterval_ms: string | null;\n\tprompt: string;\n\tmetadata: unknown;\n\tnext_run_at: Date | null;\n\tlast_run_at: Date | null;\n\trun_count: string;\n}\n\nexport interface ReadinessReport {\n\tready: boolean;\n\tdatabase: \"ok\" | \"unavailable\";\n\tmigrations: \"current\" | \"pending\" | \"unknown\";\n\tpendingMigrations: string[];\n\terror?: string;\n}\n\nexport class PostgresStore implements DurableRepositories {\n\treadonly pool: Pool;\n\n\tconstructor(config: PostgresConfig) {\n\t\tthis.pool = new Pool({\n\t\t\tconnectionString: config.connectionString,\n\t\t\tmax: config.maxConnections,\n\t\t\tconnectionTimeoutMillis: config.connectionTimeoutMs,\n\t\t\tapplication_name: \"asm-agent\",\n\t\t});\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.pool.end();\n\t}\n\n\tasync migrate(): Promise<void> {\n\t\tconst migrations = await loadMigrations();\n\t\tconst client = await this.pool.connect();\n\t\ttry {\n\t\t\tawait client.query(\"SELECT pg_advisory_lock($1)\", [MIGRATION_LOCK_ID]);\n\t\t\tfor (const migration of migrations) {\n\t\t\t\tawait this.applyMigration(client, migration);\n\t\t\t}\n\t\t} finally {\n\t\t\tawait client.query(\"SELECT pg_advisory_unlock($1)\", [MIGRATION_LOCK_ID]).catch(() => undefined);\n\t\t\tclient.release();\n\t\t}\n\t}\n\n\tasync readiness(): Promise<ReadinessReport> {\n\t\ttry {\n\t\t\tawait this.pool.query(\"SELECT 1\");\n\t\t\tconst migrations = await loadMigrations();\n\t\t\tconst result = await this.pool.query<MigrationRow>(\n\t\t\t\t\"SELECT version, name, checksum FROM asm_agent.schema_migrations ORDER BY version\",\n\t\t\t);\n\t\t\tconst applied = new Map(result.rows.map((row) => [row.version, row]));\n\t\t\tconst pending = migrations\n\t\t\t\t.filter((migration) => applied.get(migration.version)?.checksum !== migration.checksum)\n\t\t\t\t.map((migration) => migration.name);\n\t\t\treturn {\n\t\t\t\tready: pending.length === 0,\n\t\t\t\tdatabase: \"ok\",\n\t\t\t\tmigrations: pending.length === 0 ? \"current\" : \"pending\",\n\t\t\t\tpendingMigrations: pending,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tready: false,\n\t\t\t\tdatabase: \"unavailable\",\n\t\t\t\tmigrations: \"unknown\",\n\t\t\t\tpendingMigrations: [],\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\tasync transaction<T>(operation: (client: PoolClient) => Promise<T>): Promise<T> {\n\t\tconst client = await this.pool.connect();\n\t\ttry {\n\t\t\tawait client.query(\"BEGIN\");\n\t\t\tconst result = await operation(client);\n\t\t\tawait client.query(\"COMMIT\");\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tawait client.query(\"ROLLBACK\").catch(() => undefined);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tclient.release();\n\t\t}\n\t}\n\n\tasync ensureOwner(record: OwnerRecord): Promise<void> {\n\t\tawait this.pool.query(\n\t\t\t`INSERT INTO asm_agent.owners (id, handle) VALUES ($1, $2)\n\t\t\t ON CONFLICT (id) DO UPDATE SET handle = EXCLUDED.handle, updated_at = clock_timestamp()`,\n\t\t\t[record.id, record.handle],\n\t\t);\n\t}\n\n\tasync ensureProject(record: ProjectRecord): Promise<void> {\n\t\tawait this.pool.query(\n\t\t\t`INSERT INTO asm_agent.projects (id, owner_id, key, root_path) VALUES ($1, $2, $3, $4)\n\t\t\t ON CONFLICT (id) DO UPDATE SET key = EXCLUDED.key, root_path = EXCLUDED.root_path,\n\t\t\t updated_at = clock_timestamp()`,\n\t\t\t[record.id, record.ownerId, record.key, record.rootPath],\n\t\t);\n\t}\n\n\tasync createSession(input: {\n\t\tid: string;\n\t\tprojectId: string;\n\t\tparentSessionId?: string;\n\t\tcwd: string;\n\t\tname?: string;\n\t\trlmDepth?: number;\n\t}): Promise<SessionRecord> {\n\t\tconst result = await this.pool.query<SessionRow>(\n\t\t\t`INSERT INTO asm_agent.sessions (id, project_id, parent_session_id, cwd, name, rlm_depth)\n\t\t\t VALUES ($1, $2, $3, $4, $5, $6)\n\t\t\t ON CONFLICT (id) DO UPDATE SET updated_at = clock_timestamp()\n\t\t\t RETURNING *`,\n\t\t\t[input.id, input.projectId, input.parentSessionId ?? null, input.cwd, input.name ?? null, input.rlmDepth ?? 0],\n\t\t);\n\t\treturn sessionFromRow(requiredRow(result, \"create session\"));\n\t}\n\n\tasync getSession(id: string): Promise<SessionRecord | undefined> {\n\t\tconst result = await this.pool.query<SessionRow>(\"SELECT * FROM asm_agent.sessions WHERE id = $1\", [id]);\n\t\treturn result.rows[0] ? sessionFromRow(result.rows[0]) : undefined;\n\t}\n\n\tasync updateSessionStatus(id: string, status: SessionStatus): Promise<boolean> {\n\t\tconst result = await this.pool.query(\n\t\t\t\"UPDATE asm_agent.sessions SET status = $2, updated_at = clock_timestamp() WHERE id = $1\",\n\t\t\t[id, status],\n\t\t);\n\t\treturn (result.rowCount ?? 0) === 1;\n\t}\n\n\tasync appendMessage(sessionId: string, message: SessionMessageInput): Promise<number> {\n\t\treturn this.transaction(async (client) => {\n\t\t\tconst revisionResult = await client.query<{ transcript_revision: string }>(\n\t\t\t\t`UPDATE asm_agent.sessions SET transcript_revision = transcript_revision + 1,\n\t\t\t\t updated_at = clock_timestamp() WHERE id = $1 RETURNING transcript_revision`,\n\t\t\t\t[sessionId],\n\t\t\t);\n\t\t\tconst sequence = Number(requiredRow(revisionResult, \"increment transcript revision\").transcript_revision);\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.agent_messages\n\t\t\t\t (session_id, sequence, entry_id, parent_entry_id, entry_type, payload, created_at)\n\t\t\t\t VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7)`,\n\t\t\t\t[\n\t\t\t\t\tsessionId,\n\t\t\t\t\tsequence,\n\t\t\t\t\tmessage.entryId,\n\t\t\t\t\tmessage.parentEntryId ?? null,\n\t\t\t\t\tmessage.entryType,\n\t\t\t\t\tJSON.stringify(message.payload),\n\t\t\t\t\tmessage.createdAt,\n\t\t\t\t],\n\t\t\t);\n\t\t\treturn sequence;\n\t\t});\n\t}\n\n\tasync listMessages(sessionId: string, afterSequence = 0): Promise<SessionMessageRecord[]> {\n\t\tconst result = await this.pool.query<MessageRow>(\n\t\t\t`SELECT sequence, entry_id, parent_entry_id, entry_type, payload, created_at\n\t\t\t FROM asm_agent.agent_messages WHERE session_id = $1 AND sequence > $2 ORDER BY sequence`,\n\t\t\t[sessionId, afterSequence],\n\t\t);\n\t\treturn result.rows.map((row) => ({\n\t\t\tsequence: Number(row.sequence),\n\t\t\tentryId: row.entry_id,\n\t\t\tparentEntryId: row.parent_entry_id ?? undefined,\n\t\t\tentryType: row.entry_type,\n\t\t\tpayload: row.payload,\n\t\t\tcreatedAt: row.created_at,\n\t\t}));\n\t}\n\n\tasync upsertGoal(goal: GoalRecord): Promise<void> {\n\t\tawait this.pool.query(\n\t\t\t`INSERT INTO asm_agent.goals\n\t\t\t (id, session_id, status, objective, token_budget, tokens_used, time_used_seconds,\n\t\t\t continuations_used, last_reason, last_error)\n\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)\n\t\t\t ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, objective = EXCLUDED.objective,\n\t\t\t token_budget = EXCLUDED.token_budget, tokens_used = EXCLUDED.tokens_used,\n\t\t\t time_used_seconds = EXCLUDED.time_used_seconds, continuations_used = EXCLUDED.continuations_used,\n\t\t\t last_reason = EXCLUDED.last_reason, last_error = EXCLUDED.last_error, updated_at = clock_timestamp()`,\n\t\t\t[\n\t\t\t\tgoal.id,\n\t\t\t\tgoal.sessionId,\n\t\t\t\tgoal.status,\n\t\t\t\tgoal.objective,\n\t\t\t\tgoal.tokenBudget ?? null,\n\t\t\t\tgoal.tokensUsed,\n\t\t\t\tgoal.timeUsedSeconds,\n\t\t\t\tgoal.continuationsUsed,\n\t\t\t\tgoal.lastReason ?? null,\n\t\t\t\tgoal.lastError ?? null,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync getCurrentGoal(sessionId: string): Promise<GoalRecord | undefined> {\n\t\tconst result = await this.pool.query<GoalRow>(\n\t\t\t`SELECT * FROM asm_agent.goals WHERE session_id = $1\n\t\t\t ORDER BY updated_at DESC, id DESC LIMIT 1`,\n\t\t\t[sessionId],\n\t\t);\n\t\tconst row = result.rows[0];\n\t\treturn row\n\t\t\t? {\n\t\t\t\t\tid: row.id,\n\t\t\t\t\tsessionId: row.session_id,\n\t\t\t\t\tstatus: row.status,\n\t\t\t\t\tobjective: row.objective,\n\t\t\t\t\ttokenBudget: row.token_budget === null ? undefined : Number(row.token_budget),\n\t\t\t\t\ttokensUsed: Number(row.tokens_used),\n\t\t\t\t\ttimeUsedSeconds: Number(row.time_used_seconds),\n\t\t\t\t\tcontinuationsUsed: row.continuations_used,\n\t\t\t\t\tlastReason: row.last_reason ?? undefined,\n\t\t\t\t\tlastError: row.last_error ?? undefined,\n\t\t\t\t}\n\t\t\t: undefined;\n\t}\n\n\tasync upsertSchedule(schedule: ScheduleRecord): Promise<void> {\n\t\tawait this.pool.query(\n\t\t\t`INSERT INTO asm_agent.schedules\n\t\t\t (id, session_id, status, source, schedule_kind, expression, interval_ms, prompt,\n\t\t\t metadata, next_run_at, last_run_at, run_count)\n\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10,$11,$12)\n\t\t\t ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, source = EXCLUDED.source,\n\t\t\t schedule_kind = EXCLUDED.schedule_kind, expression = EXCLUDED.expression,\n\t\t\t interval_ms = EXCLUDED.interval_ms, prompt = EXCLUDED.prompt, metadata = EXCLUDED.metadata,\n\t\t\t next_run_at = EXCLUDED.next_run_at, last_run_at = EXCLUDED.last_run_at,\n\t\t\t run_count = EXCLUDED.run_count, updated_at = clock_timestamp()`,\n\t\t\t[\n\t\t\t\tschedule.id,\n\t\t\t\tschedule.sessionId,\n\t\t\t\tschedule.status,\n\t\t\t\tschedule.source,\n\t\t\t\tschedule.scheduleKind,\n\t\t\t\tschedule.expression,\n\t\t\t\tschedule.intervalMs ?? null,\n\t\t\t\tschedule.prompt,\n\t\t\t\tJSON.stringify(schedule.metadata),\n\t\t\t\tschedule.nextRunAt ?? null,\n\t\t\t\tschedule.lastRunAt ?? null,\n\t\t\t\tschedule.runCount,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync listDueSchedules(now: Date, limit = 100): Promise<ScheduleRecord[]> {\n\t\tconst result = await this.pool.query<ScheduleRow>(\n\t\t\t`SELECT * FROM asm_agent.schedules WHERE status = 'active' AND next_run_at <= $1\n\t\t\t ORDER BY next_run_at, id LIMIT $2`,\n\t\t\t[now, limit],\n\t\t);\n\t\treturn result.rows.map(scheduleFromRow);\n\t}\n\n\tasync acquireLease(input: {\n\t\tresourceType: string;\n\t\tresourceId: string;\n\t\townerId: string;\n\t\tttlMs: number;\n\t}): Promise<LeaseRecord | undefined> {\n\t\tif (!Number.isInteger(input.ttlMs) || input.ttlMs <= 0) throw new Error(\"Lease ttlMs must be positive\");\n\t\tconst result = await this.pool.query<LeaseRow>(\n\t\t\t`INSERT INTO asm_agent.leases (resource_type, resource_id, owner_id, expires_at)\n\t\t\t VALUES ($1, $2, $3, clock_timestamp() + ($4 * interval '1 millisecond'))\n\t\t\t ON CONFLICT (resource_type, resource_id) DO UPDATE SET\n\t\t\t owner_id = EXCLUDED.owner_id,\n\t\t\t fencing_token = nextval('asm_agent.lease_fencing_token_seq'),\n\t\t\t acquired_at = clock_timestamp(), expires_at = EXCLUDED.expires_at\n\t\t\t WHERE asm_agent.leases.expires_at <= clock_timestamp()\n\t\t\t RETURNING *`,\n\t\t\t[input.resourceType, input.resourceId, input.ownerId, input.ttlMs],\n\t\t);\n\t\treturn result.rows[0] ? leaseFromRow(result.rows[0]) : undefined;\n\t}\n\n\tasync renewLease(lease: LeaseRecord, ttlMs: number): Promise<boolean> {\n\t\tconst result = await this.pool.query(\n\t\t\t`UPDATE asm_agent.leases SET expires_at = clock_timestamp() + ($5 * interval '1 millisecond')\n\t\t\t WHERE resource_type = $1 AND resource_id = $2 AND owner_id = $3 AND fencing_token = $4\n\t\t\t AND expires_at > clock_timestamp()`,\n\t\t\t[lease.resourceType, lease.resourceId, lease.ownerId, lease.fencingToken, ttlMs],\n\t\t);\n\t\treturn (result.rowCount ?? 0) === 1;\n\t}\n\n\tasync releaseLease(lease: LeaseRecord): Promise<boolean> {\n\t\tconst result = await this.pool.query(\n\t\t\t`DELETE FROM asm_agent.leases WHERE resource_type = $1 AND resource_id = $2\n\t\t\t AND owner_id = $3 AND fencing_token = $4`,\n\t\t\t[lease.resourceType, lease.resourceId, lease.ownerId, lease.fencingToken],\n\t\t);\n\t\treturn (result.rowCount ?? 0) === 1;\n\t}\n\n\tasync startIdempotent(input: {\n\t\tscope: string;\n\t\tkey: string;\n\t\trequestHash: string;\n\t\texpiresAt?: Date;\n\t}): Promise<IdempotencyStartResult> {\n\t\treturn this.transaction(async (client) => {\n\t\t\tconst inserted = await client.query(\n\t\t\t\t`INSERT INTO asm_agent.idempotency_records (scope, key, request_hash, status, expires_at)\n\t\t\t\t VALUES ($1, $2, $3, 'started', $4) ON CONFLICT DO NOTHING`,\n\t\t\t\t[input.scope, input.key, input.requestHash, input.expiresAt ?? null],\n\t\t\t);\n\t\t\tif ((inserted.rowCount ?? 0) === 1) return { status: \"started\" };\n\t\t\tconst existing = requiredRow(\n\t\t\t\tawait client.query<IdempotencyRow>(\n\t\t\t\t\t\"SELECT request_hash, status, response FROM asm_agent.idempotency_records WHERE scope = $1 AND key = $2 FOR UPDATE\",\n\t\t\t\t\t[input.scope, input.key],\n\t\t\t\t),\n\t\t\t\t\"load idempotency record\",\n\t\t\t);\n\t\t\tif (existing.request_hash !== input.requestHash)\n\t\t\t\tthrow new Error(\"Idempotency key reused with different request\");\n\t\t\treturn existing.status === \"completed\"\n\t\t\t\t? { status: \"replayed\", response: existing.response }\n\t\t\t\t: { status: \"in_progress\" };\n\t\t});\n\t}\n\n\tasync completeIdempotent(scope: string, key: string, response: unknown): Promise<void> {\n\t\tawait this.pool.query(\n\t\t\t`UPDATE asm_agent.idempotency_records SET status = 'completed', response = $3::jsonb,\n\t\t\t error = NULL, updated_at = clock_timestamp() WHERE scope = $1 AND key = $2`,\n\t\t\t[scope, key, JSON.stringify(response)],\n\t\t);\n\t}\n\n\tasync enqueueOutbox(input: Omit<OutboxEvent, \"id\" | \"attempts\">): Promise<string> {\n\t\tconst id = randomUUID();\n\t\tawait this.pool.query(\n\t\t\t`INSERT INTO asm_agent.outbox_events\n\t\t\t (id, topic, aggregate_type, aggregate_id, payload, headers)\n\t\t\t VALUES ($1, $2, $3, $4, $5::jsonb, $6::jsonb)`,\n\t\t\t[\n\t\t\t\tid,\n\t\t\t\tinput.topic,\n\t\t\t\tinput.aggregateType,\n\t\t\t\tinput.aggregateId,\n\t\t\t\tJSON.stringify(input.payload),\n\t\t\t\tJSON.stringify(input.headers),\n\t\t\t],\n\t\t);\n\t\treturn id;\n\t}\n\n\tasync claimOutbox(workerId: string, limit = 100, lockMs = 30_000): Promise<OutboxEvent[]> {\n\t\treturn this.transaction(async (client) => {\n\t\t\tconst result = await client.query<OutboxRow>(\n\t\t\t\t`WITH candidates AS (\n\t\t\t\t SELECT id FROM asm_agent.outbox_events\n\t\t\t\t WHERE published_at IS NULL AND available_at <= clock_timestamp()\n\t\t\t\t AND (locked_until IS NULL OR locked_until <= clock_timestamp())\n\t\t\t\t ORDER BY available_at, id FOR UPDATE SKIP LOCKED LIMIT $1\n\t\t\t\t)\n\t\t\t\tUPDATE asm_agent.outbox_events event SET locked_by = $2,\n\t\t\t\t locked_until = clock_timestamp() + ($3 * interval '1 millisecond'), attempts = attempts + 1\n\t\t\t\tFROM candidates WHERE event.id = candidates.id RETURNING event.*`,\n\t\t\t\t[limit, workerId, lockMs],\n\t\t\t);\n\t\t\treturn result.rows.map(outboxFromRow);\n\t\t});\n\t}\n\n\tasync markOutboxPublished(id: string, workerId: string): Promise<boolean> {\n\t\tconst result = await this.pool.query(\n\t\t\t`UPDATE asm_agent.outbox_events SET published_at = clock_timestamp(), locked_by = NULL,\n\t\t\t locked_until = NULL WHERE id = $1 AND locked_by = $2 AND published_at IS NULL`,\n\t\t\t[id, workerId],\n\t\t);\n\t\treturn (result.rowCount ?? 0) === 1;\n\t}\n\n\tprivate async applyMigration(client: PoolClient, migration: MigrationFile): Promise<void> {\n\t\tlet existing: MigrationRow | undefined;\n\t\ttry {\n\t\t\texisting = (\n\t\t\t\tawait client.query<MigrationRow>(\n\t\t\t\t\t\"SELECT version, name, checksum FROM asm_agent.schema_migrations WHERE version = $1\",\n\t\t\t\t\t[migration.version],\n\t\t\t\t)\n\t\t\t).rows[0];\n\t\t} catch (error) {\n\t\t\tif ((error as { code?: string }).code !== \"42P01\") throw error;\n\t\t}\n\t\tif (existing) {\n\t\t\tif (existing.checksum !== migration.checksum) {\n\t\t\t\tthrow new Error(`Migration checksum mismatch: ${migration.name}`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tawait client.query(\"BEGIN\");\n\t\ttry {\n\t\t\tawait client.query(migration.sql);\n\t\t\tawait client.query(\"INSERT INTO asm_agent.schema_migrations (version, name, checksum) VALUES ($1, $2, $3)\", [\n\t\t\t\tmigration.version,\n\t\t\t\tmigration.name,\n\t\t\t\tmigration.checksum,\n\t\t\t]);\n\t\t\tawait client.query(\"COMMIT\");\n\t\t} catch (error) {\n\t\t\tawait client.query(\"ROLLBACK\");\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nasync function loadMigrations(): Promise<MigrationFile[]> {\n\tconst directory = new URL(\"../migrations/\", import.meta.url);\n\tconst names = (await readdir(directory)).filter((name) => /^\\d+_[a-z0-9_-]+\\.sql$/.test(name)).sort();\n\treturn Promise.all(\n\t\tnames.map(async (name) => {\n\t\t\tconst sql = await readFile(new URL(name, directory), \"utf8\");\n\t\t\treturn {\n\t\t\t\tversion: Number(name.slice(0, name.indexOf(\"_\"))),\n\t\t\t\tname,\n\t\t\t\tchecksum: createHash(\"sha256\").update(sql).digest(\"hex\"),\n\t\t\t\tsql,\n\t\t\t};\n\t\t}),\n\t);\n}\n\nfunction requiredRow<T extends QueryResultRow>(result: QueryResult<T>, operation: string): T {\n\tconst row = result.rows[0];\n\tif (!row) throw new Error(`PostgreSQL did not return a row for ${operation}`);\n\treturn row;\n}\n\nfunction sessionFromRow(row: SessionRow): SessionRecord {\n\treturn {\n\t\tid: row.id,\n\t\tprojectId: row.project_id,\n\t\tparentSessionId: row.parent_session_id ?? undefined,\n\t\tstatus: row.status,\n\t\tcwd: row.cwd,\n\t\tname: row.name ?? undefined,\n\t\trlmDepth: row.rlm_depth,\n\t\ttranscriptRevision: Number(row.transcript_revision),\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t};\n}\n\nfunction leaseFromRow(row: LeaseRow): LeaseRecord {\n\treturn {\n\t\tresourceType: row.resource_type,\n\t\tresourceId: row.resource_id,\n\t\townerId: row.owner_id,\n\t\tfencingToken: Number(row.fencing_token),\n\t\texpiresAt: row.expires_at,\n\t};\n}\n\nfunction outboxFromRow(row: OutboxRow): OutboxEvent {\n\treturn {\n\t\tid: row.id,\n\t\ttopic: row.topic,\n\t\taggregateType: row.aggregate_type,\n\t\taggregateId: row.aggregate_id,\n\t\tpayload: row.payload,\n\t\theaders: row.headers,\n\t\tattempts: row.attempts,\n\t};\n}\n\nfunction scheduleFromRow(row: ScheduleRow): ScheduleRecord {\n\treturn {\n\t\tid: row.id,\n\t\tsessionId: row.session_id,\n\t\tstatus: row.status,\n\t\tsource: row.source,\n\t\tscheduleKind: row.schedule_kind,\n\t\texpression: row.expression,\n\t\tintervalMs: row.interval_ms === null ? undefined : Number(row.interval_ms),\n\t\tprompt: row.prompt,\n\t\tmetadata: row.metadata,\n\t\tnextRunAt: row.next_run_at ?? undefined,\n\t\tlastRunAt: row.last_run_at ?? undefined,\n\t\trunCount: Number(row.run_count),\n\t};\n}\n"]}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { PostgresStore } from "./database.js";
|
|
2
|
+
export type MemoryKind = "observation" | "fact" | "instruction";
|
|
3
|
+
export type ReaderType = "owner" | "project" | "session" | "agent";
|
|
4
|
+
export type FeedbackRating = "positive" | "negative" | "correction";
|
|
5
|
+
export interface ReaderScope {
|
|
6
|
+
type: ReaderType;
|
|
7
|
+
id: string;
|
|
8
|
+
}
|
|
9
|
+
export interface EvidenceSnapshotInput {
|
|
10
|
+
id: string;
|
|
11
|
+
ownerId: string;
|
|
12
|
+
projectId: string;
|
|
13
|
+
sourceType: "user" | "tool" | "document" | "system";
|
|
14
|
+
sourceUri?: string;
|
|
15
|
+
contentType: string;
|
|
16
|
+
content: string | Record<string, unknown>;
|
|
17
|
+
capturedAt: Date;
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface MemoryRecordView {
|
|
21
|
+
id: string;
|
|
22
|
+
ownerId: string;
|
|
23
|
+
projectId: string;
|
|
24
|
+
sessionId?: string;
|
|
25
|
+
kind: MemoryKind;
|
|
26
|
+
revision: number;
|
|
27
|
+
content: string;
|
|
28
|
+
evidenceIds: string[];
|
|
29
|
+
scopes: ReaderScope[];
|
|
30
|
+
expiresAt?: Date;
|
|
31
|
+
tombstonedAt?: Date;
|
|
32
|
+
metadata: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
export interface RetrievalCandidateView {
|
|
35
|
+
memoryId: string;
|
|
36
|
+
revision: number;
|
|
37
|
+
content: string;
|
|
38
|
+
score: number;
|
|
39
|
+
selected: boolean;
|
|
40
|
+
reasonCodes: string[];
|
|
41
|
+
}
|
|
42
|
+
export interface RetrievalResult {
|
|
43
|
+
decisionId: string;
|
|
44
|
+
algorithm: "lexical-v1" | "vector-l2-v1" | "phase76-address-head-v1";
|
|
45
|
+
candidates: RetrievalCandidateView[];
|
|
46
|
+
}
|
|
47
|
+
export interface AuthorizedMemoryCandidate {
|
|
48
|
+
memoryId: string;
|
|
49
|
+
revision: number;
|
|
50
|
+
content: string;
|
|
51
|
+
}
|
|
52
|
+
export interface LearnedRankingInput {
|
|
53
|
+
decisionId?: string;
|
|
54
|
+
ownerId: string;
|
|
55
|
+
projectId: string;
|
|
56
|
+
sessionId?: string;
|
|
57
|
+
reader: ReaderScope;
|
|
58
|
+
query: string;
|
|
59
|
+
latencyMs: number;
|
|
60
|
+
queryEmbedding: number[];
|
|
61
|
+
candidates: AuthorizedMemoryCandidate[];
|
|
62
|
+
ranked: Array<{
|
|
63
|
+
memoryId: string;
|
|
64
|
+
score: number;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
export declare class GroundedMemoryStore {
|
|
68
|
+
private readonly database;
|
|
69
|
+
constructor(database: PostgresStore);
|
|
70
|
+
createEvidence(input: EvidenceSnapshotInput): Promise<{
|
|
71
|
+
id: string;
|
|
72
|
+
digest: string;
|
|
73
|
+
}>;
|
|
74
|
+
addEvidenceClaim(input: {
|
|
75
|
+
id: string;
|
|
76
|
+
evidenceId: string;
|
|
77
|
+
claim: string;
|
|
78
|
+
locator?: Record<string, unknown>;
|
|
79
|
+
}): Promise<void>;
|
|
80
|
+
createMemory(input: {
|
|
81
|
+
id: string;
|
|
82
|
+
ownerId: string;
|
|
83
|
+
projectId: string;
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
kind: MemoryKind;
|
|
86
|
+
content: string;
|
|
87
|
+
evidenceIds: string[];
|
|
88
|
+
scopes?: ReaderScope[];
|
|
89
|
+
expiresAt?: Date;
|
|
90
|
+
metadata?: Record<string, unknown>;
|
|
91
|
+
embedding?: {
|
|
92
|
+
model: string;
|
|
93
|
+
values: number[];
|
|
94
|
+
};
|
|
95
|
+
}): Promise<MemoryRecordView>;
|
|
96
|
+
correctMemory(input: {
|
|
97
|
+
memoryId: string;
|
|
98
|
+
ownerId: string;
|
|
99
|
+
projectId: string;
|
|
100
|
+
content: string;
|
|
101
|
+
evidenceIds: string[];
|
|
102
|
+
reason: string;
|
|
103
|
+
metadata?: Record<string, unknown>;
|
|
104
|
+
embedding?: {
|
|
105
|
+
model: string;
|
|
106
|
+
values: number[];
|
|
107
|
+
};
|
|
108
|
+
}): Promise<MemoryRecordView>;
|
|
109
|
+
linkMemory(sourceMemoryId: string, targetMemoryId: string, relation: string): Promise<void>;
|
|
110
|
+
inspectMemory(memoryId: string, reader: ReaderScope, ownerId: string, projectId: string, includeRevoked?: boolean): Promise<MemoryRecordView>;
|
|
111
|
+
exportProject(ownerId: string, projectId: string, reader: ReaderScope): Promise<MemoryRecordView[]>;
|
|
112
|
+
revokeMemory(memoryId: string, ownerId: string, projectId: string, reason: string): Promise<boolean>;
|
|
113
|
+
revokeEvidence(evidenceId: string, ownerId: string, projectId: string, reason: string): Promise<number>;
|
|
114
|
+
requestErasure(memoryId: string, ownerId: string, projectId: string): Promise<string>;
|
|
115
|
+
processErasure(memoryId: string): Promise<boolean>;
|
|
116
|
+
listAuthorizedForLearnedRanking(input: {
|
|
117
|
+
ownerId: string;
|
|
118
|
+
projectId: string;
|
|
119
|
+
reader: ReaderScope;
|
|
120
|
+
limit: number;
|
|
121
|
+
}): Promise<AuthorizedMemoryCandidate[]>;
|
|
122
|
+
recordLearnedRanking(input: LearnedRankingInput): Promise<RetrievalResult>;
|
|
123
|
+
retrieveLexical(input: RetrievalInput): Promise<RetrievalResult>;
|
|
124
|
+
retrieveVector(input: RetrievalInput & {
|
|
125
|
+
embedding: number[];
|
|
126
|
+
}): Promise<RetrievalResult>;
|
|
127
|
+
addFeedback(input: {
|
|
128
|
+
id: string;
|
|
129
|
+
decisionId: string;
|
|
130
|
+
targetMemoryId?: string;
|
|
131
|
+
rating: FeedbackRating;
|
|
132
|
+
comment?: string;
|
|
133
|
+
}): Promise<void>;
|
|
134
|
+
private inflateMemory;
|
|
135
|
+
private loadMemory;
|
|
136
|
+
private recordDecision;
|
|
137
|
+
}
|
|
138
|
+
interface RetrievalInput {
|
|
139
|
+
decisionId?: string;
|
|
140
|
+
ownerId: string;
|
|
141
|
+
projectId: string;
|
|
142
|
+
sessionId?: string;
|
|
143
|
+
reader: ReaderScope;
|
|
144
|
+
query: string;
|
|
145
|
+
limit: number;
|
|
146
|
+
}
|
|
147
|
+
export {};
|
|
148
|
+
//# sourceMappingURL=grounded-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grounded-memory.d.ts","sourceRoot":"","sources":["../src/grounded-memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport type { PoolClient, QueryResultRow } from \"pg\";\nimport type { PostgresStore } from \"./database.js\";\n\nexport type MemoryKind = \"observation\" | \"fact\" | \"instruction\";\nexport type ReaderType = \"owner\" | \"project\" | \"session\" | \"agent\";\nexport type FeedbackRating = \"positive\" | \"negative\" | \"correction\";\n\nexport interface ReaderScope {\n\ttype: ReaderType;\n\tid: string;\n}\n\nexport interface EvidenceSnapshotInput {\n\tid: string;\n\townerId: string;\n\tprojectId: string;\n\tsourceType: \"user\" | \"tool\" | \"document\" | \"system\";\n\tsourceUri?: string;\n\tcontentType: string;\n\tcontent: string | Record<string, unknown>;\n\tcapturedAt: Date;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface MemoryRecordView {\n\tid: string;\n\townerId: string;\n\tprojectId: string;\n\tsessionId?: string;\n\tkind: MemoryKind;\n\trevision: number;\n\tcontent: string;\n\tevidenceIds: string[];\n\tscopes: ReaderScope[];\n\texpiresAt?: Date;\n\ttombstonedAt?: Date;\n\tmetadata: Record<string, unknown>;\n}\n\nexport interface RetrievalCandidateView {\n\tmemoryId: string;\n\trevision: number;\n\tcontent: string;\n\tscore: number;\n\tselected: boolean;\n\treasonCodes: string[];\n}\n\nexport interface RetrievalResult {\n\tdecisionId: string;\n\talgorithm: \"lexical-v1\" | \"vector-l2-v1\" | \"phase76-address-head-v1\";\n\tcandidates: RetrievalCandidateView[];\n}\n\nexport interface AuthorizedMemoryCandidate {\n\tmemoryId: string;\n\trevision: number;\n\tcontent: string;\n}\n\nexport interface LearnedRankingInput {\n\tdecisionId?: string;\n\townerId: string;\n\tprojectId: string;\n\tsessionId?: string;\n\treader: ReaderScope;\n\tquery: string;\n\tlatencyMs: number;\n\tqueryEmbedding: number[];\n\tcandidates: AuthorizedMemoryCandidate[];\n\tranked: Array<{ memoryId: string; score: number }>;\n}\n\ninterface MemoryRow extends QueryResultRow {\n\tid: string;\n\towner_id: string;\n\tproject_id: string;\n\tsession_id: string | null;\n\tkind: MemoryKind;\n\tcurrent_revision: number;\n\tcontent: string;\n\tmetadata: Record<string, unknown>;\n\texpires_at: Date | null;\n\ttombstoned_at: Date | null;\n}\n\ninterface ScopeRow extends QueryResultRow {\n\treader_type: ReaderType;\n\treader_id: string;\n}\n\ninterface EvidenceIdRow extends QueryResultRow {\n\tevidence_id: string;\n}\n\ninterface LexicalRow extends QueryResultRow {\n\tid: string;\n\trevision: number;\n\tcontent: string;\n\tscore: number;\n}\n\ninterface VectorRow extends QueryResultRow {\n\tid: string;\n\trevision: number;\n\tcontent: string;\n\tembedding: number[];\n}\n\nexport class GroundedMemoryStore {\n\tconstructor(private readonly database: PostgresStore) {}\n\n\tasync createEvidence(input: EvidenceSnapshotInput): Promise<{ id: string; digest: string }> {\n\t\tconst canonical = typeof input.content === \"string\" ? input.content : stableJson(input.content);\n\t\tconst digest = createHash(\"sha256\").update(canonical).digest(\"hex\");\n\t\tconst result = await this.database.pool.query<{ id: string }>(\n\t\t\t`INSERT INTO asm_agent.evidence_snapshots\n\t\t\t (id, owner_id, project_id, source_type, source_uri, content_type, content_text,\n\t\t\t content_json, digest, captured_at, metadata)\n\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb,$9,$10,$11::jsonb)\n\t\t\t ON CONFLICT (owner_id, project_id, digest) DO NOTHING RETURNING id`,\n\t\t\t[\n\t\t\t\tinput.id,\n\t\t\t\tinput.ownerId,\n\t\t\t\tinput.projectId,\n\t\t\t\tinput.sourceType,\n\t\t\t\tinput.sourceUri ?? null,\n\t\t\t\tinput.contentType,\n\t\t\t\ttypeof input.content === \"string\" ? input.content : null,\n\t\t\t\ttypeof input.content === \"string\" ? null : stableJson(input.content),\n\t\t\t\tdigest,\n\t\t\t\tinput.capturedAt,\n\t\t\t\tJSON.stringify(input.metadata ?? {}),\n\t\t\t],\n\t\t);\n\t\tif (result.rows[0]) return { id: result.rows[0].id, digest };\n\t\tconst existing = await this.database.pool.query<{ id: string }>(\n\t\t\t\"SELECT id FROM asm_agent.evidence_snapshots WHERE owner_id = $1 AND project_id = $2 AND digest = $3\",\n\t\t\t[input.ownerId, input.projectId, digest],\n\t\t);\n\t\tconst row = existing.rows[0];\n\t\tif (!row) throw new Error(\"Evidence conflict could not be resolved\");\n\t\treturn { id: row.id, digest };\n\t}\n\n\tasync addEvidenceClaim(input: {\n\t\tid: string;\n\t\tevidenceId: string;\n\t\tclaim: string;\n\t\tlocator?: Record<string, unknown>;\n\t}): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.evidence_claims (id, evidence_id, claim, locator)\n\t\t\t VALUES ($1,$2,$3,$4::jsonb)`,\n\t\t\t[input.id, input.evidenceId, requiredContent(input.claim), JSON.stringify(input.locator ?? {})],\n\t\t);\n\t}\n\n\tasync createMemory(input: {\n\t\tid: string;\n\t\townerId: string;\n\t\tprojectId: string;\n\t\tsessionId?: string;\n\t\tkind: MemoryKind;\n\t\tcontent: string;\n\t\tevidenceIds: string[];\n\t\tscopes?: ReaderScope[];\n\t\texpiresAt?: Date;\n\t\tmetadata?: Record<string, unknown>;\n\t\tembedding?: { model: string; values: number[] };\n\t}): Promise<MemoryRecordView> {\n\t\tconst content = requiredContent(input.content);\n\t\tawait this.database.transaction(async (client) => {\n\t\t\tawait assertEvidence(client, input.ownerId, input.projectId, input.evidenceIds);\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.memory_records\n\t\t\t\t (id, owner_id, project_id, session_id, kind, expires_at) VALUES ($1,$2,$3,$4,$5,$6)`,\n\t\t\t\t[input.id, input.ownerId, input.projectId, input.sessionId ?? null, input.kind, input.expiresAt ?? null],\n\t\t\t);\n\t\t\tawait client.query(\n\t\t\t\t\"INSERT INTO asm_agent.memory_revisions (memory_id, revision, content, metadata) VALUES ($1,1,$2,$3::jsonb)\",\n\t\t\t\t[input.id, content, JSON.stringify(input.metadata ?? {})],\n\t\t\t);\n\t\t\tawait insertEvidenceLinks(client, input.id, 1, input.evidenceIds);\n\t\t\tawait insertScopes(client, input.id, input.scopes ?? [{ type: \"owner\", id: input.ownerId }]);\n\t\t\tawait upsertProjections(client, input.id, 1, content, input.embedding);\n\t\t});\n\t\treturn this.loadMemory(input.id, input.ownerId, input.projectId);\n\t}\n\n\tasync correctMemory(input: {\n\t\tmemoryId: string;\n\t\townerId: string;\n\t\tprojectId: string;\n\t\tcontent: string;\n\t\tevidenceIds: string[];\n\t\treason: string;\n\t\tmetadata?: Record<string, unknown>;\n\t\tembedding?: { model: string; values: number[] };\n\t}): Promise<MemoryRecordView> {\n\t\tconst content = requiredContent(input.content);\n\t\tawait this.database.transaction(async (client) => {\n\t\t\tawait assertEvidence(client, input.ownerId, input.projectId, input.evidenceIds);\n\t\t\tconst locked = await client.query<{ current_revision: number }>(\n\t\t\t\t`SELECT current_revision FROM asm_agent.memory_records\n\t\t\t\t WHERE id = $1 AND owner_id = $2 AND project_id = $3 AND tombstoned_at IS NULL FOR UPDATE`,\n\t\t\t\t[input.memoryId, input.ownerId, input.projectId],\n\t\t\t);\n\t\t\tconst row = locked.rows[0];\n\t\t\tif (!row) throw new Error(\"Memory not found or revoked\");\n\t\t\tconst revision = row.current_revision + 1;\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.memory_revisions\n\t\t\t\t (memory_id, revision, content, metadata, correction_reason) VALUES ($1,$2,$3,$4::jsonb,$5)`,\n\t\t\t\t[input.memoryId, revision, content, JSON.stringify(input.metadata ?? {}), input.reason],\n\t\t\t);\n\t\t\tawait insertEvidenceLinks(client, input.memoryId, revision, input.evidenceIds);\n\t\t\tawait client.query(\n\t\t\t\t`UPDATE asm_agent.memory_records SET current_revision = $2, updated_at = clock_timestamp()\n\t\t\t\t WHERE id = $1`,\n\t\t\t\t[input.memoryId, revision],\n\t\t\t);\n\t\t\tawait upsertProjections(client, input.memoryId, revision, content, input.embedding);\n\t\t});\n\t\treturn this.loadMemory(input.memoryId, input.ownerId, input.projectId);\n\t}\n\n\tasync linkMemory(sourceMemoryId: string, targetMemoryId: string, relation: string): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.memory_links (source_memory_id, target_memory_id, relation)\n\t\t\t VALUES ($1,$2,$3) ON CONFLICT DO NOTHING`,\n\t\t\t[sourceMemoryId, targetMemoryId, requiredContent(relation)],\n\t\t);\n\t}\n\n\tasync inspectMemory(\n\t\tmemoryId: string,\n\t\treader: ReaderScope,\n\t\townerId: string,\n\t\tprojectId: string,\n\t\tincludeRevoked = false,\n\t): Promise<MemoryRecordView> {\n\t\tconst result = await this.database.pool.query<MemoryRow>(\n\t\t\t`${memorySelect()} WHERE record.id = $1 AND record.owner_id = $2 AND record.project_id = $3\n\t\t\t AND ($4::boolean OR (record.tombstoned_at IS NULL AND (record.expires_at IS NULL OR record.expires_at > clock_timestamp())))\n\t\t\t AND ${scopePredicate(5, 6)}`,\n\t\t\t[memoryId, ownerId, projectId, includeRevoked, reader.type, reader.id],\n\t\t);\n\t\tconst row = result.rows[0];\n\t\tif (!row) throw new Error(\"Memory not found or reader is not authorized\");\n\t\treturn this.inflateMemory(row);\n\t}\n\n\tasync exportProject(ownerId: string, projectId: string, reader: ReaderScope): Promise<MemoryRecordView[]> {\n\t\tconst result = await this.database.pool.query<MemoryRow>(\n\t\t\t`${memorySelect()} WHERE record.owner_id = $1 AND record.project_id = $2\n\t\t\t AND record.tombstoned_at IS NULL AND (record.expires_at IS NULL OR record.expires_at > clock_timestamp())\n\t\t\t AND ${scopePredicate(3, 4)} ORDER BY record.created_at, record.id`,\n\t\t\t[ownerId, projectId, reader.type, reader.id],\n\t\t);\n\t\treturn Promise.all(result.rows.map((row) => this.inflateMemory(row)));\n\t}\n\n\tasync revokeMemory(memoryId: string, ownerId: string, projectId: string, reason: string): Promise<boolean> {\n\t\treturn this.database.transaction(async (client) =>\n\t\t\trevokeMemories(client, [memoryId], ownerId, projectId, reason),\n\t\t);\n\t}\n\n\tasync revokeEvidence(evidenceId: string, ownerId: string, projectId: string, reason: string): Promise<number> {\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tconst evidence = await client.query(\n\t\t\t\t`UPDATE asm_agent.evidence_snapshots SET revoked_at = clock_timestamp()\n\t\t\t\t WHERE id = $1 AND owner_id = $2 AND project_id = $3 AND revoked_at IS NULL RETURNING id`,\n\t\t\t\t[evidenceId, ownerId, projectId],\n\t\t\t);\n\t\t\tif ((evidence.rowCount ?? 0) === 0) return 0;\n\t\t\tconst memories = await client.query<{ memory_id: string }>(\n\t\t\t\t`SELECT DISTINCT link.memory_id FROM asm_agent.memory_revision_evidence link\n\t\t\t\t JOIN asm_agent.memory_records record ON record.id = link.memory_id\n\t\t\t\t WHERE link.evidence_id = $1 AND record.tombstoned_at IS NULL`,\n\t\t\t\t[evidenceId],\n\t\t\t);\n\t\t\tlet revoked = 0;\n\t\t\tfor (const memory of memories.rows) {\n\t\t\t\tif (await revokeMemories(client, [memory.memory_id], ownerId, projectId, reason)) revoked++;\n\t\t\t}\n\t\t\treturn revoked;\n\t\t});\n\t}\n\n\tasync requestErasure(memoryId: string, ownerId: string, projectId: string): Promise<string> {\n\t\tconst jobId = randomUUID();\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tawait revokeMemories(client, [memoryId], ownerId, projectId, \"erasure_requested\");\n\t\t\tconst inserted = await client.query<{ id: string }>(\n\t\t\t\t`INSERT INTO asm_agent.memory_erasure_jobs (id, memory_id) VALUES ($1,$2)\n\t\t\t\t ON CONFLICT (memory_id) WHERE status IN ('pending','running') DO NOTHING RETURNING id`,\n\t\t\t\t[jobId, memoryId],\n\t\t\t);\n\t\t\tif (inserted.rows[0]) return inserted.rows[0].id;\n\t\t\tconst existing = await client.query<{ id: string }>(\n\t\t\t\t`SELECT id FROM asm_agent.memory_erasure_jobs WHERE memory_id = $1\n\t\t\t\t AND status IN ('pending','running') ORDER BY requested_at DESC LIMIT 1`,\n\t\t\t\t[memoryId],\n\t\t\t);\n\t\t\tconst row = existing.rows[0];\n\t\t\tif (!row) throw new Error(\"Could not create or resolve memory erasure job\");\n\t\t\treturn row.id;\n\t\t});\n\t}\n\n\tasync processErasure(memoryId: string): Promise<boolean> {\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tconst job = await client.query<{ id: string }>(\n\t\t\t\t`UPDATE asm_agent.memory_erasure_jobs SET status = 'running', attempts = attempts + 1\n\t\t\t\t WHERE memory_id = $1 AND status = 'pending' RETURNING id`,\n\t\t\t\t[memoryId],\n\t\t\t);\n\t\t\tconst row = job.rows[0];\n\t\t\tif (!row) return false;\n\t\t\tawait client.query(\"DELETE FROM asm_agent.memory_records WHERE id = $1 AND tombstoned_at IS NOT NULL\", [\n\t\t\t\tmemoryId,\n\t\t\t]);\n\t\t\tawait client.query(\n\t\t\t\t`UPDATE asm_agent.memory_erasure_jobs SET status = 'completed', completed_at = clock_timestamp()\n\t\t\t\t WHERE id = $1`,\n\t\t\t\t[row.id],\n\t\t\t);\n\t\t\treturn true;\n\t\t});\n\t}\n\n\tasync listAuthorizedForLearnedRanking(input: {\n\t\townerId: string;\n\t\tprojectId: string;\n\t\treader: ReaderScope;\n\t\tlimit: number;\n\t}): Promise<AuthorizedMemoryCandidate[]> {\n\t\tif (!Number.isInteger(input.limit) || input.limit < 1 || input.limit > 128) {\n\t\t\tthrow new Error(\"Learned-ranking candidate limit must be between 1 and 128\");\n\t\t}\n\t\tconst rows = await this.database.pool.query<{\n\t\t\tid: string;\n\t\t\trevision: number;\n\t\t\tcontent: string;\n\t\t}>(\n\t\t\t`SELECT record.id, record.current_revision AS revision, revision.content\n\t\t\t FROM asm_agent.memory_records record\n\t\t\t JOIN asm_agent.memory_revisions revision ON revision.memory_id = record.id\n\t\t\t AND revision.revision = record.current_revision\n\t\t\t WHERE record.owner_id = $1 AND record.project_id = $2 AND record.tombstoned_at IS NULL\n\t\t\t AND (record.expires_at IS NULL OR record.expires_at > clock_timestamp())\n\t\t\t AND ${scopePredicate(3, 4)}\n\t\t\t ORDER BY record.updated_at DESC, record.id LIMIT $5`,\n\t\t\t[input.ownerId, input.projectId, input.reader.type, input.reader.id, input.limit],\n\t\t);\n\t\treturn rows.rows.map((row) => ({ memoryId: row.id, revision: row.revision, content: row.content }));\n\t}\n\n\tasync recordLearnedRanking(input: LearnedRankingInput): Promise<RetrievalResult> {\n\t\tif (input.queryEmbedding.length === 0 || input.queryEmbedding.some((value) => !Number.isFinite(value))) {\n\t\t\tthrow new Error(\"Learned-ranking query embedding must contain finite values\");\n\t\t}\n\t\tconst byId = new Map(input.candidates.map((candidate) => [candidate.memoryId, candidate]));\n\t\tconst seen = new Set<string>();\n\t\tconst candidates = input.ranked.map((ranked) => {\n\t\t\tconst candidate = byId.get(ranked.memoryId);\n\t\t\tif (!candidate || seen.has(ranked.memoryId)) {\n\t\t\t\tthrow new Error(\"Learned ranking contains an unknown or duplicate memory\");\n\t\t\t}\n\t\t\tif (!Number.isFinite(ranked.score) || ranked.score < 0 || ranked.score > 1) {\n\t\t\t\tthrow new Error(\"Learned-ranking score must be between zero and one\");\n\t\t\t}\n\t\t\tseen.add(ranked.memoryId);\n\t\t\treturn {\n\t\t\t\tmemoryId: candidate.memoryId,\n\t\t\t\trevision: candidate.revision,\n\t\t\t\tcontent: candidate.content,\n\t\t\t\tscore: ranked.score,\n\t\t\t\tselected: true,\n\t\t\t\treasonCodes: [\"phase76_late_interaction\", \"checkpoint_bound\"],\n\t\t\t};\n\t\t});\n\t\treturn this.recordDecision(\n\t\t\t{ ...input, limit: Math.max(1, input.ranked.length) },\n\t\t\t\"phase76-address-head-v1\",\n\t\t\tcandidates,\n\t\t\tinput.latencyMs,\n\t\t\tinput.queryEmbedding,\n\t\t);\n\t}\n\n\tasync retrieveLexical(input: RetrievalInput): Promise<RetrievalResult> {\n\t\tconst started = performance.now();\n\t\tconst rows = await this.database.pool.query<LexicalRow>(\n\t\t\t`SELECT record.id, record.current_revision AS revision, revision.content,\n\t\t\t LEAST(1, ts_rank_cd(projection.document, websearch_to_tsquery('simple', $5)))::float8 AS score\n\t\t\t FROM asm_agent.memory_records record\n\t\t\t JOIN asm_agent.memory_revisions revision ON revision.memory_id = record.id\n\t\t\t AND revision.revision = record.current_revision\n\t\t\t JOIN asm_agent.memory_lexical_projections projection ON projection.memory_id = record.id\n\t\t\t WHERE record.owner_id = $1 AND record.project_id = $2 AND record.tombstoned_at IS NULL\n\t\t\t AND (record.expires_at IS NULL OR record.expires_at > clock_timestamp())\n\t\t\t AND ${scopePredicate(3, 4)} AND projection.document @@ websearch_to_tsquery('simple', $5)\n\t\t\t ORDER BY score DESC, record.id LIMIT $6`,\n\t\t\t[input.ownerId, input.projectId, input.reader.type, input.reader.id, input.query, input.limit],\n\t\t);\n\t\treturn this.recordDecision(input, \"lexical-v1\", rows.rows.map(toLexicalCandidate), performance.now() - started);\n\t}\n\n\tasync retrieveVector(input: RetrievalInput & { embedding: number[] }): Promise<RetrievalResult> {\n\t\tif (input.embedding.length === 0 || input.embedding.some((value) => !Number.isFinite(value))) {\n\t\t\tthrow new Error(\"Query embedding must contain finite values\");\n\t\t}\n\t\tconst started = performance.now();\n\t\tconst rows = await this.database.pool.query<VectorRow>(\n\t\t\t`SELECT record.id, record.current_revision AS revision, revision.content, projection.embedding\n\t\t\t FROM asm_agent.memory_records record\n\t\t\t JOIN asm_agent.memory_revisions revision ON revision.memory_id = record.id\n\t\t\t AND revision.revision = record.current_revision\n\t\t\t JOIN asm_agent.memory_vector_projections projection ON projection.memory_id = record.id\n\t\t\t WHERE record.owner_id = $1 AND record.project_id = $2 AND record.tombstoned_at IS NULL\n\t\t\t AND (record.expires_at IS NULL OR record.expires_at > clock_timestamp())\n\t\t\t AND projection.dimensions = $5 AND ${scopePredicate(3, 4)}`,\n\t\t\t[input.ownerId, input.projectId, input.reader.type, input.reader.id, input.embedding.length],\n\t\t);\n\t\tconst candidates = rows.rows\n\t\t\t.map((row) => ({\n\t\t\t\tmemoryId: row.id,\n\t\t\t\trevision: row.revision,\n\t\t\t\tcontent: row.content,\n\t\t\t\tscore: cosineSimilarity(input.embedding, row.embedding),\n\t\t\t\tselected: true,\n\t\t\t\treasonCodes: [\"vector_similarity\"],\n\t\t\t}))\n\t\t\t.sort((left, right) => right.score - left.score || left.memoryId.localeCompare(right.memoryId))\n\t\t\t.slice(0, input.limit);\n\t\treturn this.recordDecision(input, \"vector-l2-v1\", candidates, performance.now() - started, input.embedding);\n\t}\n\n\tasync addFeedback(input: {\n\t\tid: string;\n\t\tdecisionId: string;\n\t\ttargetMemoryId?: string;\n\t\trating: FeedbackRating;\n\t\tcomment?: string;\n\t}): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.retrieval_feedback\n\t\t\t (id, decision_id, target_memory_id, rating, comment) VALUES ($1,$2,$3,$4,$5)`,\n\t\t\t[input.id, input.decisionId, input.targetMemoryId ?? null, input.rating, input.comment ?? null],\n\t\t);\n\t}\n\n\tprivate async inflateMemory(row: MemoryRow): Promise<MemoryRecordView> {\n\t\tconst [evidence, scopes] = await Promise.all([\n\t\t\tthis.database.pool.query<EvidenceIdRow>(\n\t\t\t\t`SELECT evidence_id FROM asm_agent.memory_revision_evidence\n\t\t\t\t WHERE memory_id = $1 AND revision = $2 ORDER BY evidence_id`,\n\t\t\t\t[row.id, row.current_revision],\n\t\t\t),\n\t\t\tthis.database.pool.query<ScopeRow>(\n\t\t\t\t\"SELECT reader_type, reader_id FROM asm_agent.memory_reader_scopes WHERE memory_id = $1 ORDER BY reader_type, reader_id\",\n\t\t\t\t[row.id],\n\t\t\t),\n\t\t]);\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\townerId: row.owner_id,\n\t\t\tprojectId: row.project_id,\n\t\t\tsessionId: row.session_id ?? undefined,\n\t\t\tkind: row.kind,\n\t\t\trevision: row.current_revision,\n\t\t\tcontent: row.content,\n\t\t\tevidenceIds: evidence.rows.map((item) => item.evidence_id),\n\t\t\tscopes: scopes.rows.map((scope) => ({ type: scope.reader_type, id: scope.reader_id })),\n\t\t\texpiresAt: row.expires_at ?? undefined,\n\t\t\ttombstonedAt: row.tombstoned_at ?? undefined,\n\t\t\tmetadata: row.metadata,\n\t\t};\n\t}\n\n\tprivate async loadMemory(memoryId: string, ownerId: string, projectId: string): Promise<MemoryRecordView> {\n\t\tconst result = await this.database.pool.query<MemoryRow>(\n\t\t\t`${memorySelect()} WHERE record.id = $1 AND record.owner_id = $2 AND record.project_id = $3`,\n\t\t\t[memoryId, ownerId, projectId],\n\t\t);\n\t\tconst row = result.rows[0];\n\t\tif (!row) throw new Error(\"Memory not found\");\n\t\treturn this.inflateMemory(row);\n\t}\n\n\tprivate async recordDecision(\n\t\tinput: RetrievalInput,\n\t\talgorithm: RetrievalResult[\"algorithm\"],\n\t\tcandidates: RetrievalCandidateView[],\n\t\tlatencyMs: number,\n\t\tqueryEmbedding?: number[],\n\t): Promise<RetrievalResult> {\n\t\tconst decisionId = input.decisionId ?? randomUUID();\n\t\tawait this.database.transaction(async (client) => {\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.retrieval_decisions\n\t\t\t\t (id, owner_id, project_id, session_id, reader_type, reader_id, query, algorithm,\n\t\t\t\t algorithm_version, query_embedding, latency_ms, reason_codes)\n\t\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7,$8,'1',$9,$10,$11)`,\n\t\t\t\t[\n\t\t\t\t\tdecisionId,\n\t\t\t\t\tinput.ownerId,\n\t\t\t\t\tinput.projectId,\n\t\t\t\t\tinput.sessionId ?? null,\n\t\t\t\t\tinput.reader.type,\n\t\t\t\t\tinput.reader.id,\n\t\t\t\t\tinput.query,\n\t\t\t\t\talgorithm,\n\t\t\t\t\tqueryEmbedding ?? null,\n\t\t\t\t\tMath.max(0, Math.round(latencyMs)),\n\t\t\t\t\tcandidates.length > 0 ? [\"candidates_found\"] : [\"no_candidates\"],\n\t\t\t\t],\n\t\t\t);\n\t\t\tfor (const [index, candidate] of candidates.entries()) {\n\t\t\t\tawait client.query(\n\t\t\t\t\t`INSERT INTO asm_agent.retrieval_candidates\n\t\t\t\t\t (decision_id, memory_id, revision, rank, score, selected, reason_codes)\n\t\t\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7)`,\n\t\t\t\t\t[\n\t\t\t\t\t\tdecisionId,\n\t\t\t\t\t\tcandidate.memoryId,\n\t\t\t\t\t\tcandidate.revision,\n\t\t\t\t\t\tindex + 1,\n\t\t\t\t\t\tcandidate.score,\n\t\t\t\t\t\tcandidate.selected,\n\t\t\t\t\t\tcandidate.reasonCodes,\n\t\t\t\t\t],\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\treturn { decisionId, algorithm, candidates };\n\t}\n}\n\ninterface RetrievalInput {\n\tdecisionId?: string;\n\townerId: string;\n\tprojectId: string;\n\tsessionId?: string;\n\treader: ReaderScope;\n\tquery: string;\n\tlimit: number;\n}\n\nfunction memorySelect(): string {\n\treturn `SELECT record.id, record.owner_id, record.project_id, record.session_id, record.kind,\n\t record.current_revision, revision.content, revision.metadata, record.expires_at, record.tombstoned_at\n\t FROM asm_agent.memory_records record JOIN asm_agent.memory_revisions revision\n\t ON revision.memory_id = record.id AND revision.revision = record.current_revision`;\n}\n\nfunction scopePredicate(typeParameter: number, idParameter: number): string {\n\treturn `EXISTS (SELECT 1 FROM asm_agent.memory_reader_scopes scope\n\t WHERE scope.memory_id = record.id AND scope.reader_type = $${typeParameter} AND scope.reader_id = $${idParameter})`;\n}\n\nasync function assertEvidence(\n\tclient: PoolClient,\n\townerId: string,\n\tprojectId: string,\n\tevidenceIds: string[],\n): Promise<void> {\n\tif (evidenceIds.length === 0) throw new Error(\"Grounded memory requires at least one evidence snapshot\");\n\tconst result = await client.query<{ id: string }>(\n\t\t`SELECT id FROM asm_agent.evidence_snapshots WHERE id = ANY($1::uuid[])\n\t\t AND owner_id = $2 AND project_id = $3 AND revoked_at IS NULL`,\n\t\t[evidenceIds, ownerId, projectId],\n\t);\n\tif (result.rows.length !== new Set(evidenceIds).size)\n\t\tthrow new Error(\"Evidence missing, revoked, or outside project scope\");\n}\n\nasync function insertEvidenceLinks(\n\tclient: PoolClient,\n\tmemoryId: string,\n\trevision: number,\n\tevidenceIds: string[],\n): Promise<void> {\n\tfor (const evidenceId of new Set(evidenceIds)) {\n\t\tawait client.query(\n\t\t\t`INSERT INTO asm_agent.memory_revision_evidence (memory_id, revision, evidence_id) VALUES ($1,$2,$3)`,\n\t\t\t[memoryId, revision, evidenceId],\n\t\t);\n\t}\n}\n\nasync function insertScopes(client: PoolClient, memoryId: string, scopes: ReaderScope[]): Promise<void> {\n\tif (scopes.length === 0) throw new Error(\"Memory requires at least one reader scope\");\n\tfor (const scope of scopes) {\n\t\tawait client.query(\n\t\t\t\"INSERT INTO asm_agent.memory_reader_scopes (memory_id, reader_type, reader_id) VALUES ($1,$2,$3)\",\n\t\t\t[memoryId, scope.type, scope.id],\n\t\t);\n\t}\n}\n\nasync function upsertProjections(\n\tclient: PoolClient,\n\tmemoryId: string,\n\trevision: number,\n\tcontent: string,\n\tembedding?: { model: string; values: number[] },\n): Promise<void> {\n\tawait client.query(\n\t\t`INSERT INTO asm_agent.memory_lexical_projections (memory_id, revision, document)\n\t\t VALUES ($1,$2,to_tsvector('simple',$3)) ON CONFLICT (memory_id) DO UPDATE\n\t\t SET revision = EXCLUDED.revision, document = EXCLUDED.document, projected_at = clock_timestamp()`,\n\t\t[memoryId, revision, content],\n\t);\n\tif (!embedding) {\n\t\tawait client.query(\"DELETE FROM asm_agent.memory_vector_projections WHERE memory_id = $1\", [memoryId]);\n\t\treturn;\n\t}\n\tif (embedding.values.length === 0 || embedding.values.some((value) => !Number.isFinite(value))) {\n\t\tthrow new Error(\"Embedding must contain finite values\");\n\t}\n\tawait client.query(\n\t\t`INSERT INTO asm_agent.memory_vector_projections (memory_id, revision, model, dimensions, embedding)\n\t\t VALUES ($1,$2,$3,$4,$5) ON CONFLICT (memory_id) DO UPDATE SET revision = EXCLUDED.revision,\n\t\t model = EXCLUDED.model, dimensions = EXCLUDED.dimensions, embedding = EXCLUDED.embedding,\n\t\t projected_at = clock_timestamp()`,\n\t\t[memoryId, revision, embedding.model, embedding.values.length, embedding.values],\n\t);\n}\n\nasync function revokeMemories(\n\tclient: PoolClient,\n\tmemoryIds: string[],\n\townerId: string,\n\tprojectId: string,\n\treason: string,\n): Promise<boolean> {\n\tconst result = await client.query<{ id: string }>(\n\t\t`UPDATE asm_agent.memory_records SET tombstoned_at = clock_timestamp(), revocation_reason = $4,\n\t\t updated_at = clock_timestamp() WHERE id = ANY($1::uuid[]) AND owner_id = $2 AND project_id = $3\n\t\t AND tombstoned_at IS NULL RETURNING id`,\n\t\t[memoryIds, ownerId, projectId, reason],\n\t);\n\tif (result.rows.length === 0) return false;\n\tconst revokedIds = result.rows.map((row) => row.id);\n\tawait client.query(\"DELETE FROM asm_agent.memory_lexical_projections WHERE memory_id = ANY($1::uuid[])\", [\n\t\trevokedIds,\n\t]);\n\tawait client.query(\"DELETE FROM asm_agent.memory_vector_projections WHERE memory_id = ANY($1::uuid[])\", [\n\t\trevokedIds,\n\t]);\n\tawait client.query(\n\t\t`UPDATE asm_agent.retrieval_candidates SET eligible = false, selected = false,\n\t\t reason_codes = array_append(reason_codes, 'revoked') WHERE memory_id = ANY($1::uuid[]) AND eligible = true`,\n\t\t[revokedIds],\n\t);\n\treturn true;\n}\n\nfunction requiredContent(content: string): string {\n\tconst normalized = content.trim();\n\tif (!normalized) throw new Error(\"Memory content must not be empty\");\n\treturn normalized;\n}\n\nfunction stableJson(value: Record<string, unknown>): string {\n\treturn JSON.stringify(value, Object.keys(value).sort());\n}\n\nfunction cosineSimilarity(left: number[], right: number[]): number {\n\tlet dot = 0;\n\tlet leftMagnitude = 0;\n\tlet rightMagnitude = 0;\n\tfor (let index = 0; index < left.length; index++) {\n\t\tconst leftValue = left[index] ?? 0;\n\t\tconst rightValue = right[index] ?? 0;\n\t\tdot += leftValue * rightValue;\n\t\tleftMagnitude += leftValue * leftValue;\n\t\trightMagnitude += rightValue * rightValue;\n\t}\n\tif (leftMagnitude === 0 || rightMagnitude === 0) return 0;\n\treturn Math.max(0, Math.min(1, (dot / Math.sqrt(leftMagnitude * rightMagnitude) + 1) / 2));\n}\n\nfunction toLexicalCandidate(row: LexicalRow): RetrievalCandidateView {\n\treturn {\n\t\tmemoryId: row.id,\n\t\trevision: row.revision,\n\t\tcontent: row.content,\n\t\tscore: row.score,\n\t\tselected: true,\n\t\treasonCodes: [\"lexical_match\"],\n\t};\n}\n"]}
|