@adonis-agora/agent 0.1.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/LICENSE +21 -0
- package/dist/configure.d.ts +18 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +29 -0
- package/dist/configure.js.map +1 -0
- package/dist/providers/agent_provider.d.ts +25 -0
- package/dist/providers/agent_provider.d.ts.map +1 -0
- package/dist/providers/agent_provider.js +511 -0
- package/dist/providers/agent_provider.js.map +1 -0
- package/dist/src/actor-resolver.d.ts +41 -0
- package/dist/src/actor-resolver.d.ts.map +1 -0
- package/dist/src/agent-deps-factory.d.ts +59 -0
- package/dist/src/agent-deps-factory.d.ts.map +1 -0
- package/dist/src/agent-deps-factory.js +111 -0
- package/dist/src/agent-deps-factory.js.map +1 -0
- package/dist/src/agent-deps.d.ts +42 -0
- package/dist/src/agent-deps.d.ts.map +1 -0
- package/dist/src/agent-deps.js +5 -0
- package/dist/src/agent-deps.js.map +1 -0
- package/dist/src/agent-loop.d.ts +101 -0
- package/dist/src/agent-loop.d.ts.map +1 -0
- package/dist/src/agent-loop.js +396 -0
- package/dist/src/agent-loop.js.map +1 -0
- package/dist/src/agent-registry.d.ts +10 -0
- package/dist/src/agent-registry.d.ts.map +1 -0
- package/dist/src/agent-service.d.ts +50 -0
- package/dist/src/agent-service.d.ts.map +1 -0
- package/dist/src/agent-service.js +82 -0
- package/dist/src/agent-service.js.map +1 -0
- package/dist/src/ai-sdk/ai-sdk-model.d.ts +17 -0
- package/dist/src/ai-sdk/ai-sdk-model.d.ts.map +1 -0
- package/dist/src/ai-sdk/ai-sdk-model.js +263 -0
- package/dist/src/ai-sdk/ai-sdk-model.js.map +1 -0
- package/dist/src/ai-sdk/index.d.ts +2 -0
- package/dist/src/ai-sdk/index.d.ts.map +1 -0
- package/dist/src/ai-tool-ref.d.ts +79 -0
- package/dist/src/ai-tool-ref.d.ts.map +1 -0
- package/dist/src/ai-tool-ref.js +81 -0
- package/dist/src/ai-tool-ref.js.map +1 -0
- package/dist/src/authorizer.d.ts +18 -0
- package/dist/src/authorizer.d.ts.map +1 -0
- package/dist/src/authz/authz-tool-authorizer.d.ts +85 -0
- package/dist/src/authz/authz-tool-authorizer.d.ts.map +1 -0
- package/dist/src/authz/authz-tool-authorizer.js +63 -0
- package/dist/src/authz/authz-tool-authorizer.js.map +1 -0
- package/dist/src/authz/index.d.ts +3 -0
- package/dist/src/authz/index.d.ts.map +1 -0
- package/dist/src/authz/index.js +2 -0
- package/dist/src/authz/index.js.map +1 -0
- package/dist/src/data/data-tool.d.ts +64 -0
- package/dist/src/data/data-tool.d.ts.map +1 -0
- package/dist/src/data/data-tool.js +146 -0
- package/dist/src/data/data-tool.js.map +1 -0
- package/dist/src/data/index.d.ts +7 -0
- package/dist/src/data/index.d.ts.map +1 -0
- package/dist/src/data/index.js +7 -0
- package/dist/src/data/index.js.map +1 -0
- package/dist/src/data/limit.d.ts +12 -0
- package/dist/src/data/limit.d.ts.map +1 -0
- package/dist/src/data/limit.js +29 -0
- package/dist/src/data/limit.js.map +1 -0
- package/dist/src/data/parser.d.ts +27 -0
- package/dist/src/data/parser.d.ts.map +1 -0
- package/dist/src/data/parser.js +18 -0
- package/dist/src/data/parser.js.map +1 -0
- package/dist/src/data/sql-validator.d.ts +37 -0
- package/dist/src/data/sql-validator.d.ts.map +1 -0
- package/dist/src/data/sql-validator.js +92 -0
- package/dist/src/data/sql-validator.js.map +1 -0
- package/dist/src/data/table-access.d.ts +40 -0
- package/dist/src/data/table-access.d.ts.map +1 -0
- package/dist/src/data/table-access.js +41 -0
- package/dist/src/data/table-access.js.map +1 -0
- package/dist/src/data/tenant-scope.d.ts +39 -0
- package/dist/src/data/tenant-scope.d.ts.map +1 -0
- package/dist/src/data/tenant-scope.js +126 -0
- package/dist/src/data/tenant-scope.js.map +1 -0
- package/dist/src/define_config.d.ts +153 -0
- package/dist/src/define_config.d.ts.map +1 -0
- package/dist/src/define_config.js +7 -0
- package/dist/src/define_config.js.map +1 -0
- package/dist/src/diagnostics.d.ts +82 -0
- package/dist/src/diagnostics.d.ts.map +1 -0
- package/dist/src/diagnostics.js +50 -0
- package/dist/src/diagnostics.js.map +1 -0
- package/dist/src/durable/agent-run-context.d.ts +24 -0
- package/dist/src/durable/agent-run-context.d.ts.map +1 -0
- package/dist/src/durable/agent-run-context.js +17 -0
- package/dist/src/durable/agent-run-context.js.map +1 -0
- package/dist/src/durable/agent-run-workflow.d.ts +37 -0
- package/dist/src/durable/agent-run-workflow.d.ts.map +1 -0
- package/dist/src/durable/agent-run-workflow.js +128 -0
- package/dist/src/durable/agent-run-workflow.js.map +1 -0
- package/dist/src/durable/durable-agent-runner.d.ts +25 -0
- package/dist/src/durable/durable-agent-runner.d.ts.map +1 -0
- package/dist/src/durable/durable-agent-runner.js +59 -0
- package/dist/src/durable/durable-agent-runner.js.map +1 -0
- package/dist/src/durable/index.d.ts +17 -0
- package/dist/src/durable/index.d.ts.map +1 -0
- package/dist/src/durable/index.js +20 -0
- package/dist/src/durable/index.js.map +1 -0
- package/dist/src/index.d.ts +55 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +45 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/personas.d.ts +7 -0
- package/dist/src/personas.d.ts.map +1 -0
- package/dist/src/rag/chunk.d.ts +14 -0
- package/dist/src/rag/chunk.d.ts.map +1 -0
- package/dist/src/rag/chunk.js +42 -0
- package/dist/src/rag/chunk.js.map +1 -0
- package/dist/src/rag/embedding-retriever.d.ts +15 -0
- package/dist/src/rag/embedding-retriever.d.ts.map +1 -0
- package/dist/src/rag/embedding-retriever.js +24 -0
- package/dist/src/rag/embedding-retriever.js.map +1 -0
- package/dist/src/rag/filter.d.ts +6 -0
- package/dist/src/rag/filter.d.ts.map +1 -0
- package/dist/src/rag/filter.js +11 -0
- package/dist/src/rag/filter.js.map +1 -0
- package/dist/src/rag/index.d.ts +8 -0
- package/dist/src/rag/index.d.ts.map +1 -0
- package/dist/src/rag/index.js +8 -0
- package/dist/src/rag/index.js.map +1 -0
- package/dist/src/rag/ingest.d.ts +33 -0
- package/dist/src/rag/ingest.d.ts.map +1 -0
- package/dist/src/rag/ingest.js +37 -0
- package/dist/src/rag/ingest.js.map +1 -0
- package/dist/src/rag/memory-vector-store.d.ts +16 -0
- package/dist/src/rag/memory-vector-store.d.ts.map +1 -0
- package/dist/src/rag/memory-vector-store.js +70 -0
- package/dist/src/rag/memory-vector-store.js.map +1 -0
- package/dist/src/rag/pg-vector-store.d.ts +84 -0
- package/dist/src/rag/pg-vector-store.d.ts.map +1 -0
- package/dist/src/rag/pg-vector-store.js +220 -0
- package/dist/src/rag/pg-vector-store.js.map +1 -0
- package/dist/src/rag/vector-store.d.ts +47 -0
- package/dist/src/rag/vector-store.d.ts.map +1 -0
- package/dist/src/rag/vector-store.js +5 -0
- package/dist/src/rag/vector-store.js.map +1 -0
- package/dist/src/rag-media/diagnostics.d.ts +43 -0
- package/dist/src/rag-media/diagnostics.d.ts.map +1 -0
- package/dist/src/rag-media/diagnostics.js +36 -0
- package/dist/src/rag-media/diagnostics.js.map +1 -0
- package/dist/src/rag-media/index.d.ts +5 -0
- package/dist/src/rag-media/index.d.ts.map +1 -0
- package/dist/src/rag-media/index.js +5 -0
- package/dist/src/rag-media/index.js.map +1 -0
- package/dist/src/rag-media/media-events.d.ts +23 -0
- package/dist/src/rag-media/media-events.d.ts.map +1 -0
- package/dist/src/rag-media/media-events.js +28 -0
- package/dist/src/rag-media/media-events.js.map +1 -0
- package/dist/src/rag-media/media-rag-ingestion.d.ts +155 -0
- package/dist/src/rag-media/media-rag-ingestion.d.ts.map +1 -0
- package/dist/src/rag-media/media-rag-ingestion.js +204 -0
- package/dist/src/rag-media/media-rag-ingestion.js.map +1 -0
- package/dist/src/rag-media/text-extractor.d.ts +46 -0
- package/dist/src/rag-media/text-extractor.d.ts.map +1 -0
- package/dist/src/rag-media/text-extractor.js +92 -0
- package/dist/src/rag-media/text-extractor.js.map +1 -0
- package/dist/src/redis-stream-client.d.ts +29 -0
- package/dist/src/redis-stream-client.d.ts.map +1 -0
- package/dist/src/redis-stream-client.js +2 -0
- package/dist/src/redis-stream-client.js.map +1 -0
- package/dist/src/redis-token-stream-sink.d.ts +36 -0
- package/dist/src/redis-token-stream-sink.d.ts.map +1 -0
- package/dist/src/redis-token-stream-sink.js +94 -0
- package/dist/src/redis-token-stream-sink.js.map +1 -0
- package/dist/src/runners/inline-agent-runner.d.ts +26 -0
- package/dist/src/runners/inline-agent-runner.d.ts.map +1 -0
- package/dist/src/runners/inline-agent-runner.js +85 -0
- package/dist/src/runners/inline-agent-runner.js.map +1 -0
- package/dist/src/spi/actor-directory.d.ts +23 -0
- package/dist/src/spi/actor-directory.d.ts.map +1 -0
- package/dist/src/spi/actor-directory.js +2 -0
- package/dist/src/spi/actor-directory.js.map +1 -0
- package/dist/src/spi/actor-resolver.d.ts +18 -0
- package/dist/src/spi/actor-resolver.d.ts.map +1 -0
- package/dist/src/spi/agent-runner.d.ts +20 -0
- package/dist/src/spi/agent-runner.d.ts.map +1 -0
- package/dist/src/spi/agent-store.d.ts +104 -0
- package/dist/src/spi/agent-store.d.ts.map +1 -0
- package/dist/src/spi/agent-store.js +2 -0
- package/dist/src/spi/agent-store.js.map +1 -0
- package/dist/src/spi/attachment-staging.d.ts +27 -0
- package/dist/src/spi/attachment-staging.d.ts.map +1 -0
- package/dist/src/spi/attachment-staging.js +2 -0
- package/dist/src/spi/attachment-staging.js.map +1 -0
- package/dist/src/spi/embedding-provider.d.ts +12 -0
- package/dist/src/spi/embedding-provider.d.ts.map +1 -0
- package/dist/src/spi/embedding-provider.js +2 -0
- package/dist/src/spi/embedding-provider.js.map +1 -0
- package/dist/src/spi/governance-queries.d.ts +215 -0
- package/dist/src/spi/governance-queries.d.ts.map +1 -0
- package/dist/src/spi/governance-queries.js +15 -0
- package/dist/src/spi/governance-queries.js.map +1 -0
- package/dist/src/spi/model-provider.d.ts +41 -0
- package/dist/src/spi/model-provider.d.ts.map +1 -0
- package/dist/src/spi/pricing-store.d.ts +45 -0
- package/dist/src/spi/pricing-store.d.ts.map +1 -0
- package/dist/src/spi/pricing-store.js +24 -0
- package/dist/src/spi/pricing-store.js.map +1 -0
- package/dist/src/spi/quota-store.d.ts +7 -0
- package/dist/src/spi/quota-store.d.ts.map +1 -0
- package/dist/src/spi/reranker.d.ts +17 -0
- package/dist/src/spi/reranker.d.ts.map +1 -0
- package/dist/src/spi/reranker.js +2 -0
- package/dist/src/spi/reranker.js.map +1 -0
- package/dist/src/spi/retriever.d.ts +28 -0
- package/dist/src/spi/retriever.d.ts.map +1 -0
- package/dist/src/spi/retriever.js +11 -0
- package/dist/src/spi/retriever.js.map +1 -0
- package/dist/src/spi/roles-policy.d.ts +11 -0
- package/dist/src/spi/roles-policy.d.ts.map +1 -0
- package/dist/src/spi/tool.d.ts +21 -0
- package/dist/src/spi/tool.d.ts.map +1 -0
- package/dist/src/stores/factory.d.ts +363 -0
- package/dist/src/stores/factory.d.ts.map +1 -0
- package/dist/src/stores/factory.js +341 -0
- package/dist/src/stores/factory.js.map +1 -0
- package/dist/src/stores/ledger-quota.d.ts +23 -0
- package/dist/src/stores/ledger-quota.d.ts.map +1 -0
- package/dist/src/stores/ledger-quota.js +32 -0
- package/dist/src/stores/ledger-quota.js.map +1 -0
- package/dist/src/stores/lucid-governance-queries.d.ts +73 -0
- package/dist/src/stores/lucid-governance-queries.d.ts.map +1 -0
- package/dist/src/stores/lucid-governance-queries.js +510 -0
- package/dist/src/stores/lucid-governance-queries.js.map +1 -0
- package/dist/src/stores/lucid-pricing.d.ts +20 -0
- package/dist/src/stores/lucid-pricing.d.ts.map +1 -0
- package/dist/src/stores/lucid-pricing.js +67 -0
- package/dist/src/stores/lucid-pricing.js.map +1 -0
- package/dist/src/stores/lucid-schema.d.ts +37 -0
- package/dist/src/stores/lucid-schema.d.ts.map +1 -0
- package/dist/src/stores/lucid-schema.js +139 -0
- package/dist/src/stores/lucid-schema.js.map +1 -0
- package/dist/src/stores/lucid.d.ts +73 -0
- package/dist/src/stores/lucid.d.ts.map +1 -0
- package/dist/src/stores/lucid.js +400 -0
- package/dist/src/stores/lucid.js.map +1 -0
- package/dist/src/telescope/dashboard.d.ts +21 -0
- package/dist/src/telescope/dashboard.d.ts.map +1 -0
- package/dist/src/telescope/dashboard.js +140 -0
- package/dist/src/telescope/dashboard.js.map +1 -0
- package/dist/src/telescope/data-providers.d.ts +39 -0
- package/dist/src/telescope/data-providers.d.ts.map +1 -0
- package/dist/src/telescope/data-providers.js +345 -0
- package/dist/src/telescope/data-providers.js.map +1 -0
- package/dist/src/telescope/extension.d.ts +27 -0
- package/dist/src/telescope/extension.d.ts.map +1 -0
- package/dist/src/telescope/extension.js +45 -0
- package/dist/src/telescope/extension.js.map +1 -0
- package/dist/src/telescope/index.d.ts +5 -0
- package/dist/src/telescope/index.d.ts.map +1 -0
- package/dist/src/telescope/index.js +4 -0
- package/dist/src/telescope/index.js.map +1 -0
- package/dist/src/telescope/telescope-sdk.d.ts +126 -0
- package/dist/src/telescope/telescope-sdk.d.ts.map +1 -0
- package/dist/src/telescope/telescope-sdk.js +15 -0
- package/dist/src/telescope/telescope-sdk.js.map +1 -0
- package/dist/src/testing/fake-embedding-provider.d.ts +37 -0
- package/dist/src/testing/fake-embedding-provider.d.ts.map +1 -0
- package/dist/src/testing/fake-embedding-provider.js +67 -0
- package/dist/src/testing/fake-embedding-provider.js.map +1 -0
- package/dist/src/testing/fake-media.d.ts +44 -0
- package/dist/src/testing/fake-media.d.ts.map +1 -0
- package/dist/src/testing/fake-media.js +69 -0
- package/dist/src/testing/fake-media.js.map +1 -0
- package/dist/src/testing/fake-model-provider.d.ts +29 -0
- package/dist/src/testing/fake-model-provider.d.ts.map +1 -0
- package/dist/src/testing/in-memory-actor-directory.d.ts +14 -0
- package/dist/src/testing/in-memory-actor-directory.d.ts.map +1 -0
- package/dist/src/testing/in-memory-actor-directory.js +27 -0
- package/dist/src/testing/in-memory-actor-directory.js.map +1 -0
- package/dist/src/testing/in-memory-attachment-staging.d.ts +22 -0
- package/dist/src/testing/in-memory-attachment-staging.d.ts.map +1 -0
- package/dist/src/testing/in-memory-attachment-staging.js +28 -0
- package/dist/src/testing/in-memory-attachment-staging.js.map +1 -0
- package/dist/src/testing/in-memory-governance-queries.d.ts +34 -0
- package/dist/src/testing/in-memory-governance-queries.d.ts.map +1 -0
- package/dist/src/testing/in-memory-governance-queries.js +373 -0
- package/dist/src/testing/in-memory-governance-queries.js.map +1 -0
- package/dist/src/testing/in-memory-pricing.d.ts +13 -0
- package/dist/src/testing/in-memory-pricing.d.ts.map +1 -0
- package/dist/src/testing/in-memory-pricing.js +27 -0
- package/dist/src/testing/in-memory-pricing.js.map +1 -0
- package/dist/src/testing/in-memory-quota.d.ts +11 -0
- package/dist/src/testing/in-memory-quota.d.ts.map +1 -0
- package/dist/src/testing/in-memory-sink.d.ts +14 -0
- package/dist/src/testing/in-memory-sink.d.ts.map +1 -0
- package/dist/src/testing/in-memory-store.d.ts +119 -0
- package/dist/src/testing/in-memory-store.d.ts.map +1 -0
- package/dist/src/testing/in-memory-store.js +317 -0
- package/dist/src/testing/in-memory-store.js.map +1 -0
- package/dist/src/testing/index.d.ts +11 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +11 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/tool-discovery.d.ts +35 -0
- package/dist/src/tool-discovery.d.ts.map +1 -0
- package/dist/src/tool-registry.d.ts +45 -0
- package/dist/src/tool-registry.d.ts.map +1 -0
- package/dist/src/tool-retry.d.ts +56 -0
- package/dist/src/tool-retry.d.ts.map +1 -0
- package/dist/src/tool-retry.js +95 -0
- package/dist/src/tool-retry.js.map +1 -0
- package/dist/src/types.d.ts +222 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/stubs/config/agent.stub +55 -0
- package/dist/stubs/database/migrations/create_agent_rag_chunks.stub +41 -0
- package/dist/stubs/database/migrations/create_agent_run_tracking.stub +80 -0
- package/dist/stubs/database/migrations/create_agent_tables.stub +113 -0
- package/package.json +174 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { LucidDatabaseLike } from './lucid.js';
|
|
2
|
+
/**
|
|
3
|
+
* The six agent table names. They match the cross-adapter snake_case contract the reference Drizzle
|
|
4
|
+
* store uses, so a dashboard or migration can point at any adapter and see the same physical schema.
|
|
5
|
+
*/
|
|
6
|
+
export declare const AGENT_TABLES: {
|
|
7
|
+
readonly threads: "agent_thread";
|
|
8
|
+
readonly messages: "agent_message";
|
|
9
|
+
readonly toolCalls: "agent_tool_call";
|
|
10
|
+
readonly tokenUsage: "agent_token_usage";
|
|
11
|
+
readonly modelPricing: "agent_model_pricing";
|
|
12
|
+
readonly runs: "agent_run";
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* `CREATE TABLE IF NOT EXISTS` DDL for the six agent tables plus their indexes, one statement per
|
|
16
|
+
* array element so each can be issued through Lucid's `rawQuery`. Portable across SQLite / Postgres /
|
|
17
|
+
* MySQL: quoted identifiers, epoch-ms `BIGINT` timestamps, `INTEGER` booleans (0/1) and `TEXT` JSON
|
|
18
|
+
* columns — no dialect-only types. A real deployment should prefer the bundled migration stub so the
|
|
19
|
+
* schema is versioned; this helper lets a store stand itself up in tests and scripts.
|
|
20
|
+
*
|
|
21
|
+
* The tool-call PK is the model-supplied `toolCallId` (not a generated id), preserving the invariant
|
|
22
|
+
* that a persisted tool call is addressable by exactly the id the model emitted.
|
|
23
|
+
*
|
|
24
|
+
* The `agent_run` table records each run (turn) lifecycle; `agent_message` / `agent_tool_call` /
|
|
25
|
+
* `agent_token_usage` each carry a nullable `run_id` correlation column (logically referencing
|
|
26
|
+
* `agent_run.id`, deliberately WITHOUT a DB-level foreign key — like the reference — so the additive
|
|
27
|
+
* migration can `ALTER TABLE ADD COLUMN` portably and a row recorded before run tracking shipped can
|
|
28
|
+
* keep a `null` run_id).
|
|
29
|
+
*/
|
|
30
|
+
export declare function createTableStatements(): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Idempotently provision the six agent tables through Lucid's async raw runner (`CREATE TABLE IF
|
|
33
|
+
* NOT EXISTS`). Works on every Lucid dialect. For an AdonisJS app prefer the published migration
|
|
34
|
+
* (`node ace configure @adonis-agora/agent`); this helper is for standalone use, tests and quick-starts.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createAgentTables(db: LucidDatabaseLike): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=lucid-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lucid-schema.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;CAOf,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAmGhD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5E"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The six agent table names. They match the cross-adapter snake_case contract the reference Drizzle
|
|
3
|
+
* store uses, so a dashboard or migration can point at any adapter and see the same physical schema.
|
|
4
|
+
*/
|
|
5
|
+
export const AGENT_TABLES = {
|
|
6
|
+
threads: 'agent_thread',
|
|
7
|
+
messages: 'agent_message',
|
|
8
|
+
toolCalls: 'agent_tool_call',
|
|
9
|
+
tokenUsage: 'agent_token_usage',
|
|
10
|
+
modelPricing: 'agent_model_pricing',
|
|
11
|
+
runs: 'agent_run',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* `CREATE TABLE IF NOT EXISTS` DDL for the six agent tables plus their indexes, one statement per
|
|
15
|
+
* array element so each can be issued through Lucid's `rawQuery`. Portable across SQLite / Postgres /
|
|
16
|
+
* MySQL: quoted identifiers, epoch-ms `BIGINT` timestamps, `INTEGER` booleans (0/1) and `TEXT` JSON
|
|
17
|
+
* columns — no dialect-only types. A real deployment should prefer the bundled migration stub so the
|
|
18
|
+
* schema is versioned; this helper lets a store stand itself up in tests and scripts.
|
|
19
|
+
*
|
|
20
|
+
* The tool-call PK is the model-supplied `toolCallId` (not a generated id), preserving the invariant
|
|
21
|
+
* that a persisted tool call is addressable by exactly the id the model emitted.
|
|
22
|
+
*
|
|
23
|
+
* The `agent_run` table records each run (turn) lifecycle; `agent_message` / `agent_tool_call` /
|
|
24
|
+
* `agent_token_usage` each carry a nullable `run_id` correlation column (logically referencing
|
|
25
|
+
* `agent_run.id`, deliberately WITHOUT a DB-level foreign key — like the reference — so the additive
|
|
26
|
+
* migration can `ALTER TABLE ADD COLUMN` portably and a row recorded before run tracking shipped can
|
|
27
|
+
* keep a `null` run_id).
|
|
28
|
+
*/
|
|
29
|
+
export function createTableStatements() {
|
|
30
|
+
const t = AGENT_TABLES;
|
|
31
|
+
return [
|
|
32
|
+
`CREATE TABLE IF NOT EXISTS "${t.threads}" (
|
|
33
|
+
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
|
|
34
|
+
"actor_ref" VARCHAR(255) NOT NULL,
|
|
35
|
+
"tenant_ref" VARCHAR(255) NULL,
|
|
36
|
+
"title" TEXT NOT NULL,
|
|
37
|
+
"persona" VARCHAR(255) NOT NULL DEFAULT 'default',
|
|
38
|
+
"transient" INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
"pinned_at" BIGINT NULL,
|
|
40
|
+
"summary" TEXT NULL,
|
|
41
|
+
"summary_message_count" INTEGER NOT NULL DEFAULT 0,
|
|
42
|
+
"active_stream_id" VARCHAR(255) NULL,
|
|
43
|
+
"created_at" BIGINT NOT NULL,
|
|
44
|
+
"updated_at" BIGINT NOT NULL,
|
|
45
|
+
"deleted_at" BIGINT NULL
|
|
46
|
+
)`,
|
|
47
|
+
`CREATE INDEX IF NOT EXISTS "${t.threads}_actor_updated_idx" ON "${t.threads}" ("actor_ref", "updated_at")`,
|
|
48
|
+
`CREATE TABLE IF NOT EXISTS "${t.messages}" (
|
|
49
|
+
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
|
|
50
|
+
"thread_id" VARCHAR(255) NOT NULL REFERENCES "${t.threads}" ("id") ON DELETE CASCADE,
|
|
51
|
+
"role" VARCHAR(255) NOT NULL,
|
|
52
|
+
"content" TEXT NOT NULL,
|
|
53
|
+
"tool_calls" TEXT NULL,
|
|
54
|
+
"tool_results" TEXT NULL,
|
|
55
|
+
"attachments" TEXT NULL,
|
|
56
|
+
"follow_ups" TEXT NULL,
|
|
57
|
+
"usage" TEXT NULL,
|
|
58
|
+
"persona" VARCHAR(255) NULL,
|
|
59
|
+
"run_id" VARCHAR(255) NULL,
|
|
60
|
+
"created_at" BIGINT NOT NULL
|
|
61
|
+
)`,
|
|
62
|
+
`CREATE INDEX IF NOT EXISTS "${t.messages}_thread_created_idx" ON "${t.messages}" ("thread_id", "created_at")`,
|
|
63
|
+
`CREATE INDEX IF NOT EXISTS "${t.messages}_run_idx" ON "${t.messages}" ("run_id")`,
|
|
64
|
+
`CREATE TABLE IF NOT EXISTS "${t.toolCalls}" (
|
|
65
|
+
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
|
|
66
|
+
"message_id" VARCHAR(255) NOT NULL REFERENCES "${t.messages}" ("id") ON DELETE CASCADE,
|
|
67
|
+
"tool_name" VARCHAR(255) NOT NULL,
|
|
68
|
+
"tool_type" VARCHAR(255) NOT NULL,
|
|
69
|
+
"input" TEXT NULL,
|
|
70
|
+
"output" TEXT NULL,
|
|
71
|
+
"status" VARCHAR(255) NOT NULL,
|
|
72
|
+
"executed_by_ref" VARCHAR(255) NULL,
|
|
73
|
+
"execution_ms" INTEGER NULL,
|
|
74
|
+
"error" TEXT NULL,
|
|
75
|
+
"run_id" VARCHAR(255) NULL,
|
|
76
|
+
"created_at" BIGINT NOT NULL,
|
|
77
|
+
"executed_at" BIGINT NULL
|
|
78
|
+
)`,
|
|
79
|
+
`CREATE INDEX IF NOT EXISTS "${t.toolCalls}_run_idx" ON "${t.toolCalls}" ("run_id")`,
|
|
80
|
+
`CREATE INDEX IF NOT EXISTS "${t.toolCalls}_status_created_idx" ON "${t.toolCalls}" ("status", "created_at")`,
|
|
81
|
+
`CREATE TABLE IF NOT EXISTS "${t.tokenUsage}" (
|
|
82
|
+
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
|
|
83
|
+
"thread_id" VARCHAR(255) NOT NULL REFERENCES "${t.threads}" ("id") ON DELETE CASCADE,
|
|
84
|
+
"actor_ref" VARCHAR(255) NOT NULL,
|
|
85
|
+
"message_id" VARCHAR(255) NULL,
|
|
86
|
+
"model_id" VARCHAR(255) NOT NULL,
|
|
87
|
+
"purpose" VARCHAR(255) NOT NULL,
|
|
88
|
+
"input_tokens" INTEGER NOT NULL,
|
|
89
|
+
"output_tokens" INTEGER NOT NULL,
|
|
90
|
+
"cache_write_tokens" INTEGER NULL,
|
|
91
|
+
"cache_read_tokens" INTEGER NULL,
|
|
92
|
+
"cost_usd" DOUBLE PRECISION NULL,
|
|
93
|
+
"run_id" VARCHAR(255) NULL,
|
|
94
|
+
"created_at" BIGINT NOT NULL
|
|
95
|
+
)`,
|
|
96
|
+
`CREATE INDEX IF NOT EXISTS "${t.tokenUsage}_actor_created_idx" ON "${t.tokenUsage}" ("actor_ref", "created_at")`,
|
|
97
|
+
`CREATE INDEX IF NOT EXISTS "${t.tokenUsage}_run_idx" ON "${t.tokenUsage}" ("run_id")`,
|
|
98
|
+
`CREATE TABLE IF NOT EXISTS "${t.modelPricing}" (
|
|
99
|
+
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
|
|
100
|
+
"model_id" VARCHAR(255) NOT NULL,
|
|
101
|
+
"input_price_per_1m" DOUBLE PRECISION NOT NULL,
|
|
102
|
+
"output_price_per_1m" DOUBLE PRECISION NOT NULL,
|
|
103
|
+
"cache_write_price_per_1m" DOUBLE PRECISION NULL,
|
|
104
|
+
"cache_read_price_per_1m" DOUBLE PRECISION NULL,
|
|
105
|
+
"effective_from" BIGINT NOT NULL,
|
|
106
|
+
"is_current" INTEGER NOT NULL
|
|
107
|
+
)`,
|
|
108
|
+
`CREATE TABLE IF NOT EXISTS "${t.runs}" (
|
|
109
|
+
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
|
|
110
|
+
"thread_id" VARCHAR(255) NOT NULL REFERENCES "${t.threads}" ("id") ON DELETE CASCADE,
|
|
111
|
+
"agent_name" VARCHAR(255) NULL,
|
|
112
|
+
"actor_ref" VARCHAR(255) NOT NULL,
|
|
113
|
+
"tenant_ref" VARCHAR(255) NULL,
|
|
114
|
+
"status" VARCHAR(255) NOT NULL,
|
|
115
|
+
"started_at" BIGINT NOT NULL,
|
|
116
|
+
"finished_at" BIGINT NULL,
|
|
117
|
+
"step_count" INTEGER NOT NULL DEFAULT 0,
|
|
118
|
+
"input_tokens" INTEGER NOT NULL DEFAULT 0,
|
|
119
|
+
"output_tokens" INTEGER NOT NULL DEFAULT 0,
|
|
120
|
+
"cost_usd" DOUBLE PRECISION NULL,
|
|
121
|
+
"error" TEXT NULL,
|
|
122
|
+
"durable" INTEGER NOT NULL DEFAULT 0
|
|
123
|
+
)`,
|
|
124
|
+
`CREATE INDEX IF NOT EXISTS "${t.runs}_started_idx" ON "${t.runs}" ("started_at")`,
|
|
125
|
+
`CREATE INDEX IF NOT EXISTS "${t.runs}_actor_started_idx" ON "${t.runs}" ("actor_ref", "started_at")`,
|
|
126
|
+
`CREATE INDEX IF NOT EXISTS "${t.runs}_status_started_idx" ON "${t.runs}" ("status", "started_at")`,
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Idempotently provision the six agent tables through Lucid's async raw runner (`CREATE TABLE IF
|
|
131
|
+
* NOT EXISTS`). Works on every Lucid dialect. For an AdonisJS app prefer the published migration
|
|
132
|
+
* (`node ace configure @adonis-agora/agent`); this helper is for standalone use, tests and quick-starts.
|
|
133
|
+
*/
|
|
134
|
+
export async function createAgentTables(db) {
|
|
135
|
+
for (const stmt of createTableStatements()) {
|
|
136
|
+
await db.rawQuery(stmt);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=lucid-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lucid-schema.js","sourceRoot":"","sources":["../../../src/stores/lucid-schema.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,OAAO,EAAE,cAAc;IACvB,QAAQ,EAAE,eAAe;IACzB,SAAS,EAAE,iBAAiB;IAC5B,UAAU,EAAE,mBAAmB;IAC/B,YAAY,EAAE,qBAAqB;IACnC,IAAI,EAAE,WAAW;CACT,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,GAAG,YAAY,CAAC;IACvB,OAAO;QACL,+BAA+B,CAAC,CAAC,OAAO;;;;;;;;;;;;;;MActC;QACF,+BAA+B,CAAC,CAAC,OAAO,2BAA2B,CAAC,CAAC,OAAO,+BAA+B;QAC3G,+BAA+B,CAAC,CAAC,QAAQ;;sDAES,CAAC,CAAC,OAAO;;;;;;;;;;;MAWzD;QACF,+BAA+B,CAAC,CAAC,QAAQ,4BAA4B,CAAC,CAAC,QAAQ,+BAA+B;QAC9G,+BAA+B,CAAC,CAAC,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,cAAc;QAClF,+BAA+B,CAAC,CAAC,SAAS;;uDAES,CAAC,CAAC,QAAQ;;;;;;;;;;;;MAY3D;QACF,+BAA+B,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,SAAS,cAAc;QACpF,+BAA+B,CAAC,CAAC,SAAS,4BAA4B,CAAC,CAAC,SAAS,4BAA4B;QAC7G,+BAA+B,CAAC,CAAC,UAAU;;sDAEO,CAAC,CAAC,OAAO;;;;;;;;;;;;MAYzD;QACF,+BAA+B,CAAC,CAAC,UAAU,2BAA2B,CAAC,CAAC,UAAU,+BAA+B;QACjH,+BAA+B,CAAC,CAAC,UAAU,iBAAiB,CAAC,CAAC,UAAU,cAAc;QACtF,+BAA+B,CAAC,CAAC,YAAY;;;;;;;;;MAS3C;QACF,+BAA+B,CAAC,CAAC,IAAI;;sDAEa,CAAC,CAAC,OAAO;;;;;;;;;;;;;MAazD;QACF,+BAA+B,CAAC,CAAC,IAAI,qBAAqB,CAAC,CAAC,IAAI,kBAAkB;QAClF,+BAA+B,CAAC,CAAC,IAAI,2BAA2B,CAAC,CAAC,IAAI,+BAA+B;QACrG,+BAA+B,CAAC,CAAC,IAAI,4BAA4B,CAAC,CAAC,IAAI,4BAA4B;KACpG,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAqB;IAC3D,KAAK,MAAM,IAAI,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC3C,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AgentStore, AppendMessageInput, CreateThreadInput, RecordRunEndInput, RecordRunStartInput, RecordToolCallInput, RecordUsageInput, UpdateToolCallInput } from '../spi/agent-store.js';
|
|
2
|
+
import type { StoredMessage, ThreadDetail, ThreadSummary } from '../types.js';
|
|
3
|
+
/** The chainable query-builder surface the store leans on (Knex-shaped). */
|
|
4
|
+
export interface LucidQueryBuilderLike {
|
|
5
|
+
where(column: string, value: unknown): this;
|
|
6
|
+
where(column: string, operator: string, value: unknown): this;
|
|
7
|
+
whereNull(column: string): this;
|
|
8
|
+
orderBy(column: string, direction: 'asc' | 'desc'): this;
|
|
9
|
+
limit(value: number): this;
|
|
10
|
+
offset(value: number): this;
|
|
11
|
+
first(): Promise<Record<string, unknown> | null>;
|
|
12
|
+
select(...columns: string[]): Promise<Record<string, unknown>[]>;
|
|
13
|
+
update(row: Record<string, unknown>): Promise<unknown>;
|
|
14
|
+
delete(): Promise<unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface LucidInsertBuilderLike {
|
|
17
|
+
insert(row: Record<string, unknown>): Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
/** A query client — the base connection or a transaction client (both expose `from`/`table`). */
|
|
20
|
+
export interface LucidClientLike {
|
|
21
|
+
from(table: string): LucidQueryBuilderLike;
|
|
22
|
+
table(table: string): LucidInsertBuilderLike;
|
|
23
|
+
}
|
|
24
|
+
/** The `Database` facade slice: a client plus raw SQL (DDL) and transactions. */
|
|
25
|
+
export interface LucidDatabaseLike extends LucidClientLike {
|
|
26
|
+
rawQuery(sql: string, bindings?: unknown[]): Promise<unknown>;
|
|
27
|
+
transaction<T>(callback: (trx: LucidClientLike) => Promise<T>): Promise<T>;
|
|
28
|
+
}
|
|
29
|
+
export interface LucidAgentStoreOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Run {@link createAgentTables} on first use so the tables exist without a migration. Convenient
|
|
32
|
+
* for tests/scripts; production should run the published migration. Default `false`.
|
|
33
|
+
*/
|
|
34
|
+
autoCreateTables?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A production-grade, persistent {@link AgentStore} backed by AdonisJS **Lucid** (Knex) over the five
|
|
38
|
+
* agent tables (threads, messages, tool calls, token usage, model pricing). JSON payloads are stored
|
|
39
|
+
* as TEXT and timestamps as epoch-ms integers, so it is portable across SQLite / Postgres / MySQL and
|
|
40
|
+
* is the behavioral twin of the in-memory store.
|
|
41
|
+
*
|
|
42
|
+
* `forkThread` / `truncateFrom` run in a transaction (cheap safety); `truncateFrom` deletes the
|
|
43
|
+
* doomed messages' tool calls explicitly (not only via FK cascade) so it works on SQLite even without
|
|
44
|
+
* `PRAGMA foreign_keys=ON`. The tool-call PK is always the model-supplied `toolCallId`.
|
|
45
|
+
*
|
|
46
|
+
* Usually you don't construct this directly: `config/agent.ts` selects it via `stores.lucid({ ... })`
|
|
47
|
+
* and the provider builds it, lazily importing `@adonisjs/lucid` only when the `lucid` store is chosen.
|
|
48
|
+
*/
|
|
49
|
+
export declare class LucidAgentStore implements AgentStore {
|
|
50
|
+
private readonly db;
|
|
51
|
+
private readonly autoCreateTables;
|
|
52
|
+
private ready;
|
|
53
|
+
constructor(db: LucidDatabaseLike, options?: LucidAgentStoreOptions);
|
|
54
|
+
private init;
|
|
55
|
+
createThread(input: CreateThreadInput): Promise<ThreadSummary>;
|
|
56
|
+
getThread(threadId: string): Promise<ThreadDetail | null>;
|
|
57
|
+
listThreads(actorRef: string, limit?: number): Promise<ThreadSummary[]>;
|
|
58
|
+
softDeleteThread(threadId: string): Promise<void>;
|
|
59
|
+
forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary>;
|
|
60
|
+
setTitle(threadId: string, title: string): Promise<void>;
|
|
61
|
+
setActiveStream(threadId: string, runId: string | null): Promise<void>;
|
|
62
|
+
appendMessage(input: AppendMessageInput): Promise<StoredMessage>;
|
|
63
|
+
truncateFrom(threadId: string, messageId: string): Promise<void>;
|
|
64
|
+
recordToolCall(input: RecordToolCallInput): Promise<void>;
|
|
65
|
+
updateToolCall(input: UpdateToolCallInput): Promise<void>;
|
|
66
|
+
recordUsage(input: RecordUsageInput): Promise<void>;
|
|
67
|
+
recordRunStart(input: RecordRunStartInput): Promise<void>;
|
|
68
|
+
recordRunEnd(input: RecordRunEndInput): Promise<void>;
|
|
69
|
+
quotaToday(actorRef: string, day: string): Promise<{
|
|
70
|
+
usedTokens: number;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=lucid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lucid.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import { AGENT_TABLES, createAgentTables } from './lucid-schema.js';
|
|
2
|
+
function toInt(value) {
|
|
3
|
+
if (typeof value === 'number')
|
|
4
|
+
return value;
|
|
5
|
+
if (typeof value === 'bigint')
|
|
6
|
+
return Number(value);
|
|
7
|
+
if (typeof value === 'string')
|
|
8
|
+
return Number.parseInt(value, 10) || 0;
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
function msToIso(value) {
|
|
12
|
+
return new Date(toInt(value)).toISOString();
|
|
13
|
+
}
|
|
14
|
+
function safeJson(value) {
|
|
15
|
+
if (value === undefined || value === null)
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
return JSON.stringify(value);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function parseJson(text) {
|
|
25
|
+
if (typeof text !== 'string' || text.length === 0)
|
|
26
|
+
return undefined;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(text);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A production-grade, persistent {@link AgentStore} backed by AdonisJS **Lucid** (Knex) over the five
|
|
36
|
+
* agent tables (threads, messages, tool calls, token usage, model pricing). JSON payloads are stored
|
|
37
|
+
* as TEXT and timestamps as epoch-ms integers, so it is portable across SQLite / Postgres / MySQL and
|
|
38
|
+
* is the behavioral twin of the in-memory store.
|
|
39
|
+
*
|
|
40
|
+
* `forkThread` / `truncateFrom` run in a transaction (cheap safety); `truncateFrom` deletes the
|
|
41
|
+
* doomed messages' tool calls explicitly (not only via FK cascade) so it works on SQLite even without
|
|
42
|
+
* `PRAGMA foreign_keys=ON`. The tool-call PK is always the model-supplied `toolCallId`.
|
|
43
|
+
*
|
|
44
|
+
* Usually you don't construct this directly: `config/agent.ts` selects it via `stores.lucid({ ... })`
|
|
45
|
+
* and the provider builds it, lazily importing `@adonisjs/lucid` only when the `lucid` store is chosen.
|
|
46
|
+
*/
|
|
47
|
+
export class LucidAgentStore {
|
|
48
|
+
db;
|
|
49
|
+
autoCreateTables;
|
|
50
|
+
ready = null;
|
|
51
|
+
constructor(db, options = {}) {
|
|
52
|
+
this.db = db;
|
|
53
|
+
this.autoCreateTables = options.autoCreateTables ?? false;
|
|
54
|
+
}
|
|
55
|
+
init() {
|
|
56
|
+
if (this.ready === null) {
|
|
57
|
+
this.ready = this.autoCreateTables ? createAgentTables(this.db) : Promise.resolve();
|
|
58
|
+
}
|
|
59
|
+
return this.ready;
|
|
60
|
+
}
|
|
61
|
+
async createThread(input) {
|
|
62
|
+
await this.init();
|
|
63
|
+
const id = crypto.randomUUID();
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
await this.db.table(AGENT_TABLES.threads).insert({
|
|
66
|
+
id,
|
|
67
|
+
actor_ref: input.actor.id,
|
|
68
|
+
tenant_ref: input.actor.tenantRef ?? null,
|
|
69
|
+
title: input.title ?? 'New chat',
|
|
70
|
+
persona: input.persona,
|
|
71
|
+
transient: input.transient ? 1 : 0,
|
|
72
|
+
pinned_at: null,
|
|
73
|
+
summary: null,
|
|
74
|
+
summary_message_count: 0,
|
|
75
|
+
active_stream_id: null,
|
|
76
|
+
created_at: now,
|
|
77
|
+
updated_at: now,
|
|
78
|
+
deleted_at: null,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
id,
|
|
82
|
+
title: input.title ?? 'New chat',
|
|
83
|
+
persona: input.persona,
|
|
84
|
+
transient: input.transient ?? false,
|
|
85
|
+
createdAt: new Date(now).toISOString(),
|
|
86
|
+
updatedAt: new Date(now).toISOString(),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async getThread(threadId) {
|
|
90
|
+
await this.init();
|
|
91
|
+
const row = await this.db
|
|
92
|
+
.from(AGENT_TABLES.threads)
|
|
93
|
+
.where('id', threadId)
|
|
94
|
+
.whereNull('deleted_at')
|
|
95
|
+
.first();
|
|
96
|
+
if (row === null || row === undefined)
|
|
97
|
+
return null;
|
|
98
|
+
const messageRows = await this.db
|
|
99
|
+
.from(AGENT_TABLES.messages)
|
|
100
|
+
.where('thread_id', threadId)
|
|
101
|
+
.orderBy('created_at', 'asc')
|
|
102
|
+
.select('*');
|
|
103
|
+
const messages = messageRows.map(rowToMessage);
|
|
104
|
+
const last = messages[messages.length - 1];
|
|
105
|
+
const activeStreamId = row.active_stream_id;
|
|
106
|
+
return {
|
|
107
|
+
...threadRowToSummary(row, last?.content),
|
|
108
|
+
messages,
|
|
109
|
+
...(typeof activeStreamId === 'string' ? { activeStreamId } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async listThreads(actorRef, limit = 50) {
|
|
113
|
+
await this.init();
|
|
114
|
+
const rows = await this.db
|
|
115
|
+
.from(AGENT_TABLES.threads)
|
|
116
|
+
.where('actor_ref', actorRef)
|
|
117
|
+
.where('transient', 0)
|
|
118
|
+
.whereNull('deleted_at')
|
|
119
|
+
.orderBy('updated_at', 'desc')
|
|
120
|
+
.limit(limit)
|
|
121
|
+
.select('*');
|
|
122
|
+
return rows.map((row) => threadRowToSummary(row));
|
|
123
|
+
}
|
|
124
|
+
async softDeleteThread(threadId) {
|
|
125
|
+
await this.init();
|
|
126
|
+
await this.db
|
|
127
|
+
.from(AGENT_TABLES.threads)
|
|
128
|
+
.where('id', threadId)
|
|
129
|
+
.update({ deleted_at: Date.now() });
|
|
130
|
+
}
|
|
131
|
+
async forkThread(threadId, fromMessageId) {
|
|
132
|
+
await this.init();
|
|
133
|
+
return this.db.transaction(async (trx) => {
|
|
134
|
+
const source = await trx.from(AGENT_TABLES.threads).where('id', threadId).first();
|
|
135
|
+
if (source === null || source === undefined) {
|
|
136
|
+
throw new Error(`thread ${threadId} not found`);
|
|
137
|
+
}
|
|
138
|
+
const messageRows = await trx
|
|
139
|
+
.from(AGENT_TABLES.messages)
|
|
140
|
+
.where('thread_id', threadId)
|
|
141
|
+
.orderBy('created_at', 'asc')
|
|
142
|
+
.select('*');
|
|
143
|
+
const cutoff = messageRows.findIndex((m) => String(m.id) === fromMessageId);
|
|
144
|
+
const kept = cutoff >= 0 ? messageRows.slice(0, cutoff + 1) : messageRows;
|
|
145
|
+
const id = crypto.randomUUID();
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
const title = String(source.title);
|
|
148
|
+
const persona = String(source.persona);
|
|
149
|
+
await trx.table(AGENT_TABLES.threads).insert({
|
|
150
|
+
id,
|
|
151
|
+
actor_ref: source.actor_ref,
|
|
152
|
+
tenant_ref: source.tenant_ref ?? null,
|
|
153
|
+
title,
|
|
154
|
+
persona,
|
|
155
|
+
transient: 0,
|
|
156
|
+
pinned_at: null,
|
|
157
|
+
summary: null,
|
|
158
|
+
summary_message_count: 0,
|
|
159
|
+
active_stream_id: null,
|
|
160
|
+
created_at: now,
|
|
161
|
+
updated_at: now,
|
|
162
|
+
deleted_at: null,
|
|
163
|
+
});
|
|
164
|
+
for (const m of kept) {
|
|
165
|
+
// New message id: the message PK is unique, so a fork copies content under fresh ids.
|
|
166
|
+
await trx.table(AGENT_TABLES.messages).insert({
|
|
167
|
+
id: crypto.randomUUID(),
|
|
168
|
+
thread_id: id,
|
|
169
|
+
role: m.role,
|
|
170
|
+
content: m.content,
|
|
171
|
+
tool_calls: m.tool_calls ?? null,
|
|
172
|
+
tool_results: m.tool_results ?? null,
|
|
173
|
+
attachments: m.attachments ?? null,
|
|
174
|
+
follow_ups: m.follow_ups ?? null,
|
|
175
|
+
usage: m.usage ?? null,
|
|
176
|
+
persona: m.persona ?? null,
|
|
177
|
+
created_at: toInt(m.created_at),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
id,
|
|
182
|
+
title,
|
|
183
|
+
persona,
|
|
184
|
+
transient: false,
|
|
185
|
+
createdAt: new Date(now).toISOString(),
|
|
186
|
+
updatedAt: new Date(now).toISOString(),
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
async setTitle(threadId, title) {
|
|
191
|
+
await this.init();
|
|
192
|
+
await this.db
|
|
193
|
+
.from(AGENT_TABLES.threads)
|
|
194
|
+
.where('id', threadId)
|
|
195
|
+
.update({ title, updated_at: Date.now() });
|
|
196
|
+
}
|
|
197
|
+
async setActiveStream(threadId, runId) {
|
|
198
|
+
await this.init();
|
|
199
|
+
await this.db
|
|
200
|
+
.from(AGENT_TABLES.threads)
|
|
201
|
+
.where('id', threadId)
|
|
202
|
+
.update({ active_stream_id: runId });
|
|
203
|
+
}
|
|
204
|
+
async appendMessage(input) {
|
|
205
|
+
await this.init();
|
|
206
|
+
const id = crypto.randomUUID();
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
await this.db.table(AGENT_TABLES.messages).insert({
|
|
209
|
+
id,
|
|
210
|
+
thread_id: input.threadId,
|
|
211
|
+
role: input.role,
|
|
212
|
+
content: input.content,
|
|
213
|
+
tool_calls: safeJson(input.toolCalls),
|
|
214
|
+
tool_results: safeJson(input.toolResults),
|
|
215
|
+
attachments: safeJson(input.attachments),
|
|
216
|
+
follow_ups: safeJson(input.followUps),
|
|
217
|
+
usage: safeJson(input.usage),
|
|
218
|
+
persona: input.persona ?? null,
|
|
219
|
+
run_id: input.runId ?? null,
|
|
220
|
+
created_at: now,
|
|
221
|
+
});
|
|
222
|
+
// Keep the thread's `updated_at` in step so list ordering reflects the latest activity.
|
|
223
|
+
await this.db
|
|
224
|
+
.from(AGENT_TABLES.threads)
|
|
225
|
+
.where('id', input.threadId)
|
|
226
|
+
.update({ updated_at: now });
|
|
227
|
+
return {
|
|
228
|
+
id,
|
|
229
|
+
role: input.role,
|
|
230
|
+
content: input.content,
|
|
231
|
+
createdAt: new Date(now).toISOString(),
|
|
232
|
+
...(input.toolCalls !== undefined ? { toolCalls: input.toolCalls } : {}),
|
|
233
|
+
...(input.toolResults !== undefined ? { toolResults: input.toolResults } : {}),
|
|
234
|
+
...(input.attachments !== undefined ? { attachments: input.attachments } : {}),
|
|
235
|
+
...(input.followUps !== undefined ? { followUps: input.followUps } : {}),
|
|
236
|
+
...(input.usage !== undefined ? { usage: input.usage } : {}),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async truncateFrom(threadId, messageId) {
|
|
240
|
+
await this.init();
|
|
241
|
+
await this.db.transaction(async (trx) => {
|
|
242
|
+
const rows = await trx
|
|
243
|
+
.from(AGENT_TABLES.messages)
|
|
244
|
+
.where('thread_id', threadId)
|
|
245
|
+
.orderBy('created_at', 'asc')
|
|
246
|
+
.select('id');
|
|
247
|
+
const cutoff = rows.findIndex((m) => String(m.id) === messageId);
|
|
248
|
+
if (cutoff < 0)
|
|
249
|
+
return;
|
|
250
|
+
const doomed = rows.slice(cutoff).map((m) => String(m.id));
|
|
251
|
+
for (const mid of doomed) {
|
|
252
|
+
// Delete tool calls explicitly (works on SQLite without FK cascade), then the message.
|
|
253
|
+
await trx.from(AGENT_TABLES.toolCalls).where('message_id', mid).delete();
|
|
254
|
+
await trx.from(AGENT_TABLES.messages).where('id', mid).delete();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
async recordToolCall(input) {
|
|
259
|
+
await this.init();
|
|
260
|
+
// PK = the model-supplied toolCallId (never a generated id).
|
|
261
|
+
await this.db.table(AGENT_TABLES.toolCalls).insert({
|
|
262
|
+
id: input.toolCallId,
|
|
263
|
+
message_id: input.messageId,
|
|
264
|
+
tool_name: input.toolName,
|
|
265
|
+
tool_type: input.toolType,
|
|
266
|
+
input: safeJson(input.input),
|
|
267
|
+
output: null,
|
|
268
|
+
status: input.status,
|
|
269
|
+
executed_by_ref: null,
|
|
270
|
+
execution_ms: null,
|
|
271
|
+
error: null,
|
|
272
|
+
run_id: input.runId ?? null,
|
|
273
|
+
created_at: Date.now(),
|
|
274
|
+
executed_at: null,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
async updateToolCall(input) {
|
|
278
|
+
await this.init();
|
|
279
|
+
const patch = { status: input.status };
|
|
280
|
+
if (input.output !== undefined)
|
|
281
|
+
patch.output = safeJson(input.output);
|
|
282
|
+
if (input.error !== undefined)
|
|
283
|
+
patch.error = input.error;
|
|
284
|
+
if (input.executionMs !== undefined)
|
|
285
|
+
patch.execution_ms = input.executionMs;
|
|
286
|
+
if (input.executedByRef !== undefined)
|
|
287
|
+
patch.executed_by_ref = input.executedByRef;
|
|
288
|
+
if (input.status === 'executed' || input.status === 'failed')
|
|
289
|
+
patch.executed_at = Date.now();
|
|
290
|
+
await this.db.from(AGENT_TABLES.toolCalls).where('id', input.toolCallId).update(patch);
|
|
291
|
+
}
|
|
292
|
+
async recordUsage(input) {
|
|
293
|
+
await this.init();
|
|
294
|
+
await this.db.table(AGENT_TABLES.tokenUsage).insert({
|
|
295
|
+
id: crypto.randomUUID(),
|
|
296
|
+
thread_id: input.threadId,
|
|
297
|
+
actor_ref: input.actorRef,
|
|
298
|
+
message_id: input.messageId ?? null,
|
|
299
|
+
model_id: input.modelId,
|
|
300
|
+
purpose: input.purpose,
|
|
301
|
+
input_tokens: input.usage.inputTokens,
|
|
302
|
+
output_tokens: input.usage.outputTokens,
|
|
303
|
+
cache_write_tokens: input.usage.cacheWriteTokens ?? null,
|
|
304
|
+
cache_read_tokens: input.usage.cacheReadTokens ?? null,
|
|
305
|
+
cost_usd: input.costUsd ?? null,
|
|
306
|
+
run_id: input.runId ?? null,
|
|
307
|
+
created_at: Date.now(),
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
async recordRunStart(input) {
|
|
311
|
+
await this.init();
|
|
312
|
+
await this.db.table(AGENT_TABLES.runs).insert({
|
|
313
|
+
id: input.runId,
|
|
314
|
+
thread_id: input.threadId,
|
|
315
|
+
agent_name: input.agentName ?? null,
|
|
316
|
+
actor_ref: input.actor.id,
|
|
317
|
+
tenant_ref: input.actor.tenantRef ?? null,
|
|
318
|
+
status: 'running',
|
|
319
|
+
started_at: Date.now(),
|
|
320
|
+
finished_at: null,
|
|
321
|
+
step_count: 0,
|
|
322
|
+
input_tokens: 0,
|
|
323
|
+
output_tokens: 0,
|
|
324
|
+
cost_usd: null,
|
|
325
|
+
error: null,
|
|
326
|
+
durable: input.durable ? 1 : 0,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
async recordRunEnd(input) {
|
|
330
|
+
await this.init();
|
|
331
|
+
const patch = {
|
|
332
|
+
status: input.status,
|
|
333
|
+
finished_at: input.finishedAt ?? Date.now(),
|
|
334
|
+
};
|
|
335
|
+
if (input.stepCount !== undefined)
|
|
336
|
+
patch.step_count = input.stepCount;
|
|
337
|
+
if (input.inputTokens !== undefined)
|
|
338
|
+
patch.input_tokens = input.inputTokens;
|
|
339
|
+
if (input.outputTokens !== undefined)
|
|
340
|
+
patch.output_tokens = input.outputTokens;
|
|
341
|
+
if (input.costUsd !== undefined)
|
|
342
|
+
patch.cost_usd = input.costUsd;
|
|
343
|
+
if (input.error !== undefined)
|
|
344
|
+
patch.error = input.error;
|
|
345
|
+
// First terminal wins: only settle a run still `running`, so a late `completed` from the loop can
|
|
346
|
+
// never overwrite a `failed`/`cancelled` the runner already recorded (idempotent under replay too).
|
|
347
|
+
await this.db
|
|
348
|
+
.from(AGENT_TABLES.runs)
|
|
349
|
+
.where('id', input.runId)
|
|
350
|
+
.where('status', 'running')
|
|
351
|
+
.update(patch);
|
|
352
|
+
}
|
|
353
|
+
async quotaToday(actorRef, day) {
|
|
354
|
+
await this.init();
|
|
355
|
+
// Inclusive UTC day window over epoch-ms `created_at`. Cache tokens are subsets of input/output
|
|
356
|
+
// and are NEVER re-added, so summing input+output is the whole-day token spend.
|
|
357
|
+
const start = Date.parse(`${day}T00:00:00.000Z`);
|
|
358
|
+
const end = Date.parse(`${day}T23:59:59.999Z`);
|
|
359
|
+
const rows = await this.db
|
|
360
|
+
.from(AGENT_TABLES.tokenUsage)
|
|
361
|
+
.where('actor_ref', actorRef)
|
|
362
|
+
.where('created_at', '>=', start)
|
|
363
|
+
.where('created_at', '<=', end)
|
|
364
|
+
.select('input_tokens', 'output_tokens');
|
|
365
|
+
const usedTokens = rows.reduce((sum, row) => sum + toInt(row.input_tokens) + toInt(row.output_tokens), 0);
|
|
366
|
+
return { usedTokens };
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function threadRowToSummary(row, lastPreview) {
|
|
370
|
+
const pinnedAt = row.pinned_at;
|
|
371
|
+
return {
|
|
372
|
+
id: String(row.id),
|
|
373
|
+
title: String(row.title),
|
|
374
|
+
persona: String(row.persona),
|
|
375
|
+
transient: toInt(row.transient) !== 0,
|
|
376
|
+
createdAt: msToIso(row.created_at),
|
|
377
|
+
updatedAt: msToIso(row.updated_at),
|
|
378
|
+
...(pinnedAt !== null && pinnedAt !== undefined ? { pinnedAt: msToIso(pinnedAt) } : {}),
|
|
379
|
+
...(lastPreview !== undefined ? { lastMessagePreview: lastPreview.slice(0, 120) } : {}),
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function rowToMessage(row) {
|
|
383
|
+
const toolCalls = parseJson(row.tool_calls);
|
|
384
|
+
const toolResults = parseJson(row.tool_results);
|
|
385
|
+
const attachments = parseJson(row.attachments);
|
|
386
|
+
const followUps = parseJson(row.follow_ups);
|
|
387
|
+
const usage = parseJson(row.usage);
|
|
388
|
+
return {
|
|
389
|
+
id: String(row.id),
|
|
390
|
+
role: String(row.role),
|
|
391
|
+
content: String(row.content),
|
|
392
|
+
createdAt: msToIso(row.created_at),
|
|
393
|
+
...(toolCalls !== undefined ? { toolCalls } : {}),
|
|
394
|
+
...(toolResults !== undefined ? { toolResults } : {}),
|
|
395
|
+
...(attachments !== undefined ? { attachments } : {}),
|
|
396
|
+
...(followUps !== undefined ? { followUps } : {}),
|
|
397
|
+
...(usage !== undefined ? { usage } : {}),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
//# sourceMappingURL=lucid.js.map
|