wendkeep 0.71.1 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.en.md +6 -2
- package/README.md +6 -2
- package/docs/en/commands/observer.md +54 -35
- package/docs/pt-BR/commands/observer.md +56 -37
- package/hooks/observer-publish.mjs +1 -0
- package/package.json +2 -2
- package/packages/integrations/src/host-hooks.mjs +2 -0
- package/schema/observer/001-authority.sql +107 -0
- package/schema/observer/002-usage.sql +72 -0
- package/schema/observer/003-transcripts.sql +21 -0
- package/src/observer-memory-publish.mjs +2 -1
- package/src/observer-publish.mjs +15 -13
- package/src/observer-server.mjs +223 -40
- package/src/observer-sql-migrate.mjs +335 -0
- package/src/observer-sql-publish.mjs +398 -0
- package/src/observer-sql-store.mjs +542 -0
- package/src/observer-transcript-store.mjs +49 -0
- package/src/observer.mjs +23 -5
- package/web/observer/app.mjs +248 -1
- package/web/observer/index.html +1 -0
- package/web/observer/styles.css +34 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,34 @@ All notable changes to **wendkeep** are documented here. Format based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.72.0] — 2026-08-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Observer SQL authority.** O volume Docker agora usa `/data/observer.sqlite` como
|
|
12
|
+
autoridade única para documentos, sessões, agentes, uso, chamadas LLM e transcripts
|
|
13
|
+
comprimidos; as migrações SQL são versionadas e idempotentes.
|
|
14
|
+
- **Ingestão resiliente.** Hooks de sessão e subagentes enviam eventos idempotentes ao
|
|
15
|
+
Observer, preservam custos registrados e usam outbox local quando o container está
|
|
16
|
+
indisponível.
|
|
17
|
+
- **Dashboard de Consumo.** Cada projeto ganhou resumo de tokens/custos, filtros,
|
|
18
|
+
hierarquia agente/subagente/modelo, tendência diária, chamadas e leitura de transcript.
|
|
19
|
+
- **Migração sem perda.** Conteúdo legado do volume, `MEMORY_EVENTS.jsonl`, frontmatter de
|
|
20
|
+
custo e históricos sem transcript são importados sem apagar as fontes existentes;
|
|
21
|
+
históricos incompletos são marcados como `summary_only`; divergências entre frontmatter e
|
|
22
|
+
ledger ficam em linhas explícitas de reconciliação e `session_id` duplicado é desambiguado
|
|
23
|
+
por arquivo.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Markdown deixou de ser autoridade operacional no container. Ele permanece armazenado como
|
|
28
|
+
conteúdo documental no SQLite e só é materializado por exportação explícita.
|
|
29
|
+
- O transporte divide lotes por quantidade e tamanho, reconhece retries do hash legado e
|
|
30
|
+
preserva transcripts grandes dentro do limite HTTP do Observer.
|
|
31
|
+
- Lotes SQL agora usam gzip no transporte e são expandidos com limite controlado no Observer,
|
|
32
|
+
permitindo importar transcripts históricos que excedem 64 MB em JSON puro sem aumentar
|
|
33
|
+
indiscriminadamente o limite de requisição.
|
|
34
|
+
|
|
7
35
|
## [0.71.1] — 2026-08-17
|
|
8
36
|
|
|
9
37
|
### Added
|
package/README.en.md
CHANGED
|
@@ -88,7 +88,11 @@ Decisions, dead ends, the reason you chose X over Y — gone next session. The p
|
|
|
88
88
|
| **Cost** — what it all cost | Per‑model, cache‑aware token pricing per session — plus `cost --trend` with a run‑rate projection across the whole vault; research previews without a final rate remain unestimated. |
|
|
89
89
|
| **Multi‑agent** — one vault, both agents | `init` wires the session hooks into `.claude/settings.json` *and* `.codex/hooks.json`, and every note is tagged with the agent that wrote it: Claude Code is detected from its environment, anything else is recorded as Codex. One shared graph, whichever agent you are in. |
|
|
90
90
|
| **Local‑first** — no cloud, no account | Everything is plain Markdown on your disk. An optional MCP server (`@bitbonsai/mcpvault`) lets the agent read/write the vault. |
|
|
91
|
-
| **Local Observer** — many projects, one view | `wendkeep observer` keeps
|
|
91
|
+
| **Local Observer** — many projects, one view | `wendkeep observer` keeps documents, sessions, agents, tokens, costs, calls, and transcripts in the Docker volume SQLite database; every project gets a **Consumption** tab in the read-only dashboard at `http://127.0.0.1:8787/`, loopback has no token, and unavailable hooks use a gzip outbox without blocking the session, including large transcripts. |
|
|
92
|
+
|
|
93
|
+
During historical migration, the Observer preserves differences between frontmatter totals and the
|
|
94
|
+
ledger as explicit reconciliation rows, and disambiguates duplicate `session_id` values per file
|
|
95
|
+
without inventing calls.
|
|
92
96
|
|
|
93
97
|
## Requirements
|
|
94
98
|
|
|
@@ -111,7 +115,7 @@ npx wendkeep init
|
|
|
111
115
|
|
|
112
116
|
1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
|
|
113
117
|
2. Write a provider-neutral **`.wendkeep.json`** binding at the project root and a matching `.brain/PROJECT.json` marker in the vault, then merge the session hooks into **`.claude/settings.json`**. The binding is provider-neutral by design: any agent resolves the same vault from its session `cwd`, with no machine-global environment variable. Older registrations already in `.claude/settings.json` are adopted automatically.
|
|
114
|
-
3. Wire the Codex hooks in **`.codex/hooks.json`** —
|
|
118
|
+
3. Wire the Codex hooks in **`.codex/hooks.json`** — eleven compatible entries: `brain-inject` + `session-start` + `observer-publish` on `SessionStart`, `session-ensure` + `change-context` on `UserPromptSubmit`, `session-stop` + `observer-publish` + `change-nag` on `Stop`, `subagent-stop` + `observer-publish` on `SubagentStop`, and `change-guard` on `PreToolUse` for `Bash`, `exec_command`, `apply_patch`, and mutable MCP tools, always in the `npx wendkeep hook <name>` form. `observer-publish` keeps the sanitized index projection and also sends the local SQL authority with documents, consumption, and transcripts; it does not replace the local lifecycle. The guard accepts object, raw-string, and argv Codex payloads; before a mutation it compares the session with the project, Git root, remote, branch, and worktree, denying missing or divergent targets. The other four stay out because Codex offers no equivalent payload, tool, or event: `change-warn` (no reliable `tool_input.file_path`), `plan-capture` (no `ExitPlanMode`), `decision-capture` (`AskUserQuestion` is Claude-only), and `task-log` (`TaskCompleted` is not in Codex's event enum). Codex scope blocks use `permissionDecision: "deny"`; `ask` is never emitted in `PreToolUse`. The merge remains non-destructive, preserves third-party hooks, and migrates legacy `timeout` to `timeoutSec`. **Codex enumerates every hook as untrusted and runs none until you approve the “Hooks need review” prompt at startup — `init` cannot pre-approve them**.
|
|
115
119
|
4. Add the **`wendkeep-vault`** MCP server to `.mcp.json` so the agent can read/write the vault. Skip with `--no-mcp` — e.g. when the agent already has a vault MCP. (`--no-mcp` skips *only wendkeep's own* MCP; companion MCPs still follow `--companions`.)
|
|
116
120
|
5. Offer to pin **companion** plugins/MCP (multi-choice; **none** pre-checked — wendkeep is a neutral harness and presumes no third-party plugin). Each is wired the most agent-agnostic way it supports:
|
|
117
121
|
- **`context-mode`** — context optimizer + FTS5 memory, wired as a Claude Code plugin. It ships its own MCP server, so wendkeep deliberately adds no `.mcp.json` entry (registering both cold-started two servers at once). On non-Claude agents, add the MCP by hand: `npx -y context-mode`.
|
package/README.md
CHANGED
|
@@ -88,7 +88,11 @@ Decisions, dead ends, the reason you chose X over Y — gone next session. The p
|
|
|
88
88
|
| **Cost** — what it all cost | Per‑model, cache‑aware token pricing per session — plus `cost --trend` with a run‑rate projection across the whole vault; research previews without a final rate remain unestimated. |
|
|
89
89
|
| **Multi‑agent** — one vault, both agents | `init` wires the session hooks into `.claude/settings.json` *and* `.codex/hooks.json`, and every note is tagged with the agent that wrote it: Claude Code is detected from its environment, anything else is recorded as Codex. One shared graph, whichever agent you are in. |
|
|
90
90
|
| **Local‑first** — no cloud, no account | Everything is plain Markdown on your disk. An optional MCP server (`@bitbonsai/mcpvault`) lets the agent read/write the vault. |
|
|
91
|
-
| **Local Observer** — many projects, one view | `wendkeep observer` keeps
|
|
91
|
+
| **Local Observer** — many projects, one view | `wendkeep observer` keeps documents, sessions, agents, tokens, costs, calls, and transcripts in the Docker volume SQLite database; every project gets a **Consumption** tab in the read-only dashboard at `http://127.0.0.1:8787/`, loopback has no token, and unavailable hooks use a gzip outbox without blocking the session, including large transcripts. |
|
|
92
|
+
|
|
93
|
+
During historical migration, the Observer preserves differences between frontmatter totals and the
|
|
94
|
+
ledger as explicit reconciliation rows, and disambiguates duplicate `session_id` values per file
|
|
95
|
+
without inventing calls.
|
|
92
96
|
|
|
93
97
|
## Requirements
|
|
94
98
|
|
|
@@ -111,7 +115,7 @@ npx wendkeep init
|
|
|
111
115
|
|
|
112
116
|
1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
|
|
113
117
|
2. Write a provider-neutral **`.wendkeep.json`** binding at the project root and a matching `.brain/PROJECT.json` marker in the vault, then merge the session hooks into **`.claude/settings.json`**. The binding is provider-neutral by design: any agent resolves the same vault from its session `cwd`, with no machine-global environment variable. Older registrations already in `.claude/settings.json` are adopted automatically.
|
|
114
|
-
3. Wire the Codex hooks in **`.codex/hooks.json`** —
|
|
118
|
+
3. Wire the Codex hooks in **`.codex/hooks.json`** — eleven compatible entries: `brain-inject` + `session-start` + `observer-publish` on `SessionStart`, `session-ensure` + `change-context` on `UserPromptSubmit`, `session-stop` + `observer-publish` + `change-nag` on `Stop`, `subagent-stop` + `observer-publish` on `SubagentStop`, and `change-guard` on `PreToolUse` for `Bash`, `exec_command`, `apply_patch`, and mutable MCP tools, always in the `npx wendkeep hook <name>` form. `observer-publish` keeps the sanitized index projection and also sends the local SQL authority with documents, consumption, and transcripts; it does not replace the local lifecycle. The guard accepts object, raw-string, and argv Codex payloads; before a mutation it compares the session with the project, Git root, remote, branch, and worktree, denying missing or divergent targets. The other four stay out because Codex offers no equivalent payload, tool, or event: `change-warn` (no reliable `tool_input.file_path`), `plan-capture` (no `ExitPlanMode`), `decision-capture` (`AskUserQuestion` is Claude-only), and `task-log` (`TaskCompleted` is not in Codex's event enum). Codex scope blocks use `permissionDecision: "deny"`; `ask` is never emitted in `PreToolUse`. The merge remains non-destructive, preserves third-party hooks, and migrates legacy `timeout` to `timeoutSec`. **Codex enumerates every hook as untrusted and runs none until you approve the “Hooks need review” prompt at startup — `init` cannot pre-approve them**.
|
|
115
119
|
4. Add the **`wendkeep-vault`** MCP server to `.mcp.json` so the agent can read/write the vault. Skip with `--no-mcp` — e.g. when the agent already has a vault MCP. (`--no-mcp` skips *only wendkeep's own* MCP; companion MCPs still follow `--companions`.)
|
|
116
120
|
5. Offer to pin **companion** plugins/MCP (multi-choice; **none** pre-checked — wendkeep is a neutral harness and presumes no third-party plugin). Each is wired the most agent-agnostic way it supports:
|
|
117
121
|
- **`context-mode`** — context optimizer + FTS5 memory, wired as a Claude Code plugin. It ships its own MCP server, so wendkeep deliberately adds no `.mcp.json` entry (registering both cold-started two servers at once). On non-Claude agents, add the MCP by hand: `npx -y context-mode`.
|
|
@@ -4,20 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
## Purpose
|
|
6
6
|
|
|
7
|
-
The Observer consolidates observability for multiple WendKeep projects in a local service
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
The Observer consolidates observability for multiple WendKeep projects in a local service. The
|
|
8
|
+
Docker volume keeps `/data/observer.sqlite` as the single authority for documents, sessions,
|
|
9
|
+
agents, usage, calls, and complete transcripts. The content can be browsed and searched in the
|
|
10
|
+
container without depending on Obsidian for queries.
|
|
10
11
|
|
|
11
12
|
## When to use
|
|
12
13
|
|
|
13
|
-
Use it to query changes, sessions, decisions, bugs, learnings, specs, brain documents,
|
|
14
|
-
across projects through one local memory. During the
|
|
15
|
-
|
|
14
|
+
Use it to query changes, sessions, decisions, bugs, learnings, specs, brain documents, per-agent
|
|
15
|
+
and per-model consumption, and health across projects through one local memory. During the
|
|
16
|
+
transition, the vault and legacy Markdown files remain a recovery copy; the Observer is
|
|
17
|
+
authoritative for queries made through its container.
|
|
16
18
|
|
|
17
19
|
## When not to use
|
|
18
20
|
|
|
19
|
-
Do not use the Observer to edit, complete, or archive changes, curate memory,
|
|
20
|
-
or expose the service to the network. Edits still go through local
|
|
21
|
+
Do not use the Observer to edit, complete, or archive changes, curate memory, automatically export
|
|
22
|
+
the authority back to Markdown, or expose the service to the network. Edits still go through local
|
|
23
|
+
WendKeep hooks.
|
|
21
24
|
|
|
22
25
|
## Prerequisites
|
|
23
26
|
|
|
@@ -67,10 +70,11 @@ dashboard is served by the same process and opens directly, without a form or to
|
|
|
67
70
|
bound to the computer loopback; do not expose this address on a network interface.
|
|
68
71
|
|
|
69
72
|
The dashboard shows the multi-project list, version, health, latest session, active change, change
|
|
70
|
-
count, and last capture time. Opening a project exposes Overview, Sessions, Memory,
|
|
71
|
-
Sync screens.
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
count, and last capture time. Opening a project exposes Overview, Consumption, Sessions, Memory,
|
|
74
|
+
Changes, and Sync screens. Consumption shows total cost, token categories, primary agents,
|
|
75
|
+
subagents, providers, models, daily trend, historical coverage, and calls with prompt, response,
|
|
76
|
+
and complete transcript. Loading, empty, unavailable-server, conflict, no-pricing, and stale-data
|
|
77
|
+
states are visible, with manual refresh and an automatic 15-second refresh.
|
|
74
78
|
|
|
75
79
|
If the browser shows the shell but the list fails, check the service health at
|
|
76
80
|
`http://127.0.0.1:8787/healthz` and confirm that the container is running.
|
|
@@ -78,25 +82,31 @@ If the browser shows the shell but the list fails, check the service health at
|
|
|
78
82
|
## Expected result
|
|
79
83
|
|
|
80
84
|
`register` stores `project_id`, name, version, and registration time. `publish` reads the local
|
|
81
|
-
vault, produces the snapshot, and
|
|
82
|
-
sessions, decisions, bugs, learnings, specs, changes, CORE, DIGEST, SHARED_MEMORY,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
vault, produces the snapshot, and sends idempotent events to SQLite containing the complete content
|
|
86
|
+
of sessions, decisions, bugs, learnings, specs, changes, CORE, DIGEST, SHARED_MEMORY, brain state,
|
|
87
|
+
agent sessions, cost rollups, calls, and transcripts. The container stores everything in
|
|
88
|
+
`/data/observer.sqlite`; it does not mount `C:\GitHub` or any `.WendKeep-vault`. Markdown is only
|
|
89
|
+
the text held in SQL and is recreated as files only by an explicit read-only export.
|
|
90
|
+
`memory import` performs the initial load and returns file/hash parity. During migration, the
|
|
91
|
+
cost/token total recorded in frontmatter is preserved through an explicit reconciliation row when
|
|
92
|
+
the detailed ledger does not add up; that row does not invent calls. Historical sessions sharing
|
|
93
|
+
one `session_id` receive a canonical per-file identity so one rollup cannot overwrite the other.
|
|
94
|
+
|
|
95
|
+
`init` projects `observer-publish` into `SessionStart`, `Stop`, and `SubagentStop` after the primary
|
|
96
|
+
hooks. When the server is unavailable, it writes snapshots to `.brain/observer-outbox/` and SQL
|
|
97
|
+
events to `.brain/observer-sql-outbox/` without blocking the session; a later run retries the
|
|
98
|
+
batches. SQL batches use gzip so complete transcripts larger than 64 MB as plain JSON remain within
|
|
99
|
+
the transport limit; the Observer decompresses and validates the body before ingesting it. The
|
|
100
|
+
outbox is temporary transport, not authority.
|
|
91
101
|
|
|
92
102
|
## Common errors and diagnosis
|
|
93
103
|
|
|
94
104
|
- `project_not_registered`: run `observer register` before publishing.
|
|
95
105
|
- `host loopback`: replace `0.0.0.0` or a LAN address with `127.0.0.1`.
|
|
96
|
-
- Pending outbox: the service was unavailable; preserve `.brain/observer-outbox/` and
|
|
97
|
-
publisher. Do not delete events manually.
|
|
98
|
-
- If memory is incomplete, check the Sync screen, preserve the outbox, and run
|
|
99
|
-
`observer memory import` to rebuild the
|
|
106
|
+
- Pending outbox: the service was unavailable; preserve `.brain/observer-outbox/` and
|
|
107
|
+
`.brain/observer-sql-outbox/`, then rerun the publisher. Do not delete events manually.
|
|
108
|
+
- If memory or usage is incomplete, check the Sync screen, preserve the outbox, and run
|
|
109
|
+
`observer memory import` to rebuild the load from the vault.
|
|
100
110
|
|
|
101
111
|
## Next steps
|
|
102
112
|
|
|
@@ -106,25 +116,34 @@ projection.
|
|
|
106
116
|
|
|
107
117
|
## Data authority
|
|
108
118
|
|
|
109
|
-
The container is canonical for Observer queries and stores the complete published
|
|
110
|
-
vault
|
|
111
|
-
|
|
119
|
+
The container SQLite database is canonical for Observer queries and stores the complete published
|
|
120
|
+
content. The vault and any legacy `/data/memory` remain preserved during migration as a transition
|
|
121
|
+
and recovery copy; hooks do not update container Markdown after cutover. Observer screens do not
|
|
122
|
+
complete, archive, repair, or promote state.
|
|
112
123
|
|
|
113
124
|
## Minimal API
|
|
114
125
|
|
|
115
|
-
- `GET /healthz` — availability
|
|
116
|
-
- `GET /v1/projects` — projects with
|
|
126
|
+
- `GET /healthz` — availability, SQLite migration version, and legacy migration state.
|
|
127
|
+
- `GET /v1/projects` — projects registered in SQLite, with a snapshot when available.
|
|
117
128
|
- `GET /v1/projects/:project_id` — the latest project snapshot.
|
|
118
129
|
- `GET /v1/projects/:project_id/changes` — change summary from the snapshot.
|
|
119
130
|
- `PUT /v1/projects/:project_id` — explicit local registration.
|
|
120
131
|
- `POST /v1/projects/:project_id/snapshot` — idempotent local ingestion.
|
|
132
|
+
- `POST /v1/projects/:project_id/ingest` — idempotent batches of documents, sessions, agents,
|
|
133
|
+
rollups, calls, and transcripts.
|
|
121
134
|
- `GET /v1/projects/:project_id/memory/tree` — document tree and metadata.
|
|
122
135
|
- `GET /v1/projects/:project_id/memory/document?path=...` — complete Markdown content.
|
|
123
136
|
- `GET /v1/projects/:project_id/memory/search?q=...` — path and body search.
|
|
124
137
|
- `GET /v1/projects/:project_id/sync` — mode, counts, conflicts, and latest event.
|
|
125
|
-
- `PUT /v1/projects/:project_id/sync` —
|
|
138
|
+
- `PUT /v1/projects/:project_id/sync` — compatibility configuration; SQL remains authoritative.
|
|
126
139
|
- `GET /v1/projects/:project_id/memory/export` — read-only export with complete content.
|
|
127
140
|
- `POST /v1/projects/:project_id/memory/events` — idempotent batch ingestion.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
- `GET /v1/projects/:project_id/usage/summary` — filterable totals by period, change, session,
|
|
142
|
+
agent, provider, model, and role.
|
|
143
|
+
- `GET /v1/projects/:project_id/usage/breakdown` — agent, subagent, and model hierarchy.
|
|
144
|
+
- `GET /v1/projects/:project_id/usage/calls` — individual calls with prompt and response.
|
|
145
|
+
- `GET /v1/projects/:project_id/transcripts/:transcript_id` — compressed transcript validated by hash.
|
|
146
|
+
|
|
147
|
+
The `/v1` routes reject transported or expanded bodies above their limits and validate project,
|
|
148
|
+
path, revision, hash, idempotency, and isolation before writing to SQLite. Use `memory/export` for
|
|
149
|
+
a Markdown copy; it does not alter SQL authority.
|
|
@@ -4,21 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
## Objetivo
|
|
6
6
|
|
|
7
|
-
O Observer consolida a observabilidade de vários projetos WendKeep em um serviço local
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
O Observer consolida a observabilidade de vários projetos WendKeep em um serviço local. O volume
|
|
8
|
+
Docker mantém o SQLite `/data/observer.sqlite` como autoridade única para documentos, sessões,
|
|
9
|
+
agentes, uso, chamadas e transcripts completos. O conteúdo fica disponível para navegação e busca
|
|
10
|
+
no próprio container, sem depender do Obsidian para consulta.
|
|
10
11
|
|
|
11
12
|
## Quando usar
|
|
12
13
|
|
|
13
|
-
Use para consultar changes, sessões, decisões, bugs, aprendizados, specs, documentos do brain
|
|
14
|
-
saúde de vários projetos em uma única memória local. Durante a
|
|
15
|
-
|
|
16
|
-
container.
|
|
14
|
+
Use para consultar changes, sessões, decisões, bugs, aprendizados, specs, documentos do brain,
|
|
15
|
+
consumo por agente/modelo e saúde de vários projetos em uma única memória local. Durante a
|
|
16
|
+
transição, o vault e os arquivos Markdown legados continuam preservados como cópia de origem para
|
|
17
|
+
recuperação; o Observer é a autoridade de consulta do seu container.
|
|
17
18
|
|
|
18
19
|
## Quando não usar
|
|
19
20
|
|
|
20
|
-
Não use o Observer para editar, concluir ou arquivar changes, curar memória,
|
|
21
|
-
ou expor o serviço na rede. As edições continuam passando
|
|
21
|
+
Não use o Observer para editar, concluir ou arquivar changes, curar memória, exportar a autoridade
|
|
22
|
+
de volta para Markdown automaticamente ou expor o serviço na rede. As edições continuam passando
|
|
23
|
+
pelos hooks e pelo WendKeep local.
|
|
22
24
|
|
|
23
25
|
## Pré-requisitos
|
|
24
26
|
|
|
@@ -68,11 +70,12 @@ O painel é servido pelo mesmo processo e abre diretamente, sem formulário ou t
|
|
|
68
70
|
presa ao loopback do computador; não coloque o endereço em uma interface de rede.
|
|
69
71
|
|
|
70
72
|
O painel mostra a lista multi-projeto, versão, saúde, sessão mais recente, change ativa, contagem
|
|
71
|
-
de changes e data da última captura. Ao abrir um projeto, o workspace oferece
|
|
72
|
-
Sessões, Memória, Changes e Sincronização.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
de changes e data da última captura. Ao abrir um projeto, o workspace oferece Overview, Consumo,
|
|
74
|
+
Sessões, Memória, Changes e Sincronização. A aba Consumo mostra custo total, tokens por categoria,
|
|
75
|
+
agentes principais, subagentes, provedores, modelos, tendência diária, cobertura histórica e
|
|
76
|
+
chamadas com prompt, resposta e transcript completo. Os estados de carregamento, vazio, servidor
|
|
77
|
+
indisponível, conflito, modelo sem tarifa e dados desatualizados ficam visíveis, e a atualização
|
|
78
|
+
pode ser manual ou automática a cada 15 segundos.
|
|
76
79
|
|
|
77
80
|
Se o navegador mostrar a tela mas a lista falhar, confirme a saúde em
|
|
78
81
|
`http://127.0.0.1:8787/healthz` e verifique se o container está em execução.
|
|
@@ -80,25 +83,32 @@ Se o navegador mostrar a tela mas a lista falhar, confirme a saúde em
|
|
|
80
83
|
## Resultado esperado
|
|
81
84
|
|
|
82
85
|
`register` grava `project_id`, nome, versão e data de registro. `publish` lê o vault local,
|
|
83
|
-
produz o snapshot e
|
|
84
|
-
decisões, bugs, aprendizados, specs, changes, CORE, DIGEST, SHARED_MEMORY
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
produz o snapshot e envia eventos idempotentes para o SQLite com o conteúdo integral das sessões,
|
|
87
|
+
decisões, bugs, aprendizados, specs, changes, CORE, DIGEST, SHARED_MEMORY, estado do brain,
|
|
88
|
+
sessões de agentes, rollups de custo, chamadas e transcripts. O container grava tudo em
|
|
89
|
+
`/data/observer.sqlite`; não monta `C:\GitHub` nem qualquer `.WendKeep-vault`. Markdown é aceito
|
|
90
|
+
somente como conteúdo de uma coluna SQL e volta a existir como arquivo apenas pela exportação
|
|
91
|
+
read-only sob demanda. `memory import` faz a carga inicial e retorna a paridade por arquivo e hash.
|
|
92
|
+
Na migração, o total de custo/token registrado no frontmatter é preservado por uma linha de
|
|
93
|
+
reconciliação quando o ledger detalhado não fecha com ele; essa linha não inventa chamadas.
|
|
94
|
+
Sessões históricas com o mesmo `session_id` recebem uma identidade canônica por arquivo para
|
|
95
|
+
evitar que um rollup sobrescreva o outro.
|
|
96
|
+
|
|
97
|
+
O `init` projeta `observer-publish` para `SessionStart`, `Stop` e `SubagentStop` depois dos hooks
|
|
98
|
+
principais. Sem servidor disponível, ele grava snapshots em `.brain/observer-outbox/` e eventos
|
|
99
|
+
SQL em `.brain/observer-sql-outbox/`, sem bloquear a sessão; uma execução posterior tenta
|
|
100
|
+
reenviar os lotes. Os lotes SQL são enviados com gzip para que transcripts completos maiores que
|
|
101
|
+
64 MB em JSON puro continuem dentro do limite do transporte; o Observer descomprime e valida o
|
|
102
|
+
corpo antes de ingerir. O outbox é transporte temporário, não autoridade.
|
|
93
103
|
|
|
94
104
|
## Erros comuns e diagnóstico
|
|
95
105
|
|
|
96
106
|
- `project_not_registered`: rode `observer register` antes de publicar.
|
|
97
107
|
- `host loopback`: troque `0.0.0.0` ou endereço LAN por `127.0.0.1`.
|
|
98
|
-
- Outbox pendente: o serviço estava indisponível; preserve `.brain/observer-outbox/` e
|
|
99
|
-
publisher. Não apague eventos manualmente.
|
|
100
|
-
- Se a memória
|
|
101
|
-
`observer memory import` para reconstruir a
|
|
108
|
+
- Outbox pendente: o serviço estava indisponível; preserve `.brain/observer-outbox/` e
|
|
109
|
+
`.brain/observer-sql-outbox/` e repita o publisher. Não apague eventos manualmente.
|
|
110
|
+
- Se a memória ou o consumo ficarem incompletos, verifique a tela Sincronização, preserve o
|
|
111
|
+
outbox e rode `observer memory import` para reconstruir a carga a partir do vault.
|
|
102
112
|
|
|
103
113
|
## Próximos passos
|
|
104
114
|
|
|
@@ -107,25 +117,34 @@ removido com `docker compose down -v` durante a operação normal, pois isso apa
|
|
|
107
117
|
|
|
108
118
|
## Autoridade dos dados
|
|
109
119
|
|
|
110
|
-
O container é a memória canônica para consultas do Observer e guarda o conteúdo integral
|
|
111
|
-
publicado. O vault
|
|
112
|
-
fonte de recuperação;
|
|
120
|
+
O SQLite do container é a memória canônica para consultas do Observer e guarda o conteúdo integral
|
|
121
|
+
publicado. O vault e qualquer `/data/memory` legado continuam preservados durante a migração como
|
|
122
|
+
cópia de transição e fonte de recuperação; os hooks não atualizam Markdown no container depois do
|
|
123
|
+
corte. As telas do Observer não concluem, arquivam, reparam ou promovem estado.
|
|
113
124
|
|
|
114
125
|
## API mínima
|
|
115
126
|
|
|
116
|
-
- `GET /healthz` — disponibilidade
|
|
117
|
-
- `GET /v1/projects` — projetos com snapshot
|
|
127
|
+
- `GET /healthz` — disponibilidade, versão das migrações SQLite e estado da migração legada.
|
|
128
|
+
- `GET /v1/projects` — projetos registrados no SQLite, com snapshot quando houver.
|
|
118
129
|
- `GET /v1/projects/:project_id` — último snapshot do projeto.
|
|
119
130
|
- `GET /v1/projects/:project_id/changes` — resumo das changes do snapshot.
|
|
120
131
|
- `PUT /v1/projects/:project_id` — registro explícito local.
|
|
121
132
|
- `POST /v1/projects/:project_id/snapshot` — ingestão local idempotente.
|
|
133
|
+
- `POST /v1/projects/:project_id/ingest` — lote idempotente de documentos, sessões, agentes, rollups,
|
|
134
|
+
chamadas e transcripts.
|
|
122
135
|
- `GET /v1/projects/:project_id/memory/tree` — árvore e metadados dos documentos.
|
|
123
136
|
- `GET /v1/projects/:project_id/memory/document?path=...` — conteúdo Markdown integral.
|
|
124
137
|
- `GET /v1/projects/:project_id/memory/search?q=...` — busca no caminho e no corpo.
|
|
125
138
|
- `GET /v1/projects/:project_id/sync` — modo, contagem, conflitos e último evento.
|
|
126
|
-
- `PUT /v1/projects/:project_id/sync` —
|
|
139
|
+
- `PUT /v1/projects/:project_id/sync` — compatibilidade de configuração; a autoridade continua SQL.
|
|
127
140
|
- `GET /v1/projects/:project_id/memory/export` — exportação read-only com conteúdo completo.
|
|
128
141
|
- `POST /v1/projects/:project_id/memory/events` — ingestão idempotente em lote.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
- `GET /v1/projects/:project_id/usage/summary` — totais filtráveis por período, change, sessão,
|
|
143
|
+
agente, provedor, modelo e papel.
|
|
144
|
+
- `GET /v1/projects/:project_id/usage/breakdown` — hierarquia de agentes, subagentes e modelos.
|
|
145
|
+
- `GET /v1/projects/:project_id/usage/calls` — chamadas individuais com prompt e resposta.
|
|
146
|
+
- `GET /v1/projects/:project_id/transcripts/:transcript_id` — transcript comprimido, validado por hash.
|
|
147
|
+
|
|
148
|
+
As rotas `/v1` rejeitam corpo transportado ou expandido acima do limite e validam projeto, caminho,
|
|
149
|
+
revisão, hash, idempotência e isolamento antes de gravar o conteúdo no SQLite. Para preservar uma
|
|
150
|
+
cópia Markdown, use a rota `memory/export`; ela não altera a autoridade SQL.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wendkeep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"description": "Vault-first persistent memory for AI coding agents, with an optional profile-aware governance runtime: OFF, FLOW, GUIDE, GOVERN, or ASSURE. Local-first and agent-agnostic (Claude Code, Codex, Cursor…).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"node": ">=18"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
|
-
"check": "node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/project-vault.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
|
|
44
|
+
"check": "node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/project-vault.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-sql-store.mjs && node --check src/observer-sql-migrate.mjs && node --check src/observer-sql-publish.mjs && node --check src/observer-transcript-store.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
|
|
45
45
|
"test": "node --test --test-concurrency=2",
|
|
46
46
|
"release": "node scripts/release.mjs",
|
|
47
47
|
"release:dry": "node scripts/release.mjs --dry-run",
|
|
@@ -24,6 +24,8 @@ export const SESSION_HOOKS = [
|
|
|
24
24
|
{ event: 'PostToolUse', matcher: 'AskUserQuestion', name: 'decision-capture', timeout: 15, statusMessage: 'wendkeep: recording decision' },
|
|
25
25
|
// Refresh subagent/workflow telemetry as each subagent finishes (resilient to a missed Stop).
|
|
26
26
|
{ event: 'SubagentStop', matcher: null, name: 'subagent-stop', timeout: 20, codex: true, statusMessage: 'wendkeep: subagent telemetry' },
|
|
27
|
+
// Publish the SQL observer projection after the subagent telemetry is settled.
|
|
28
|
+
{ event: 'SubagentStop', matcher: null, name: 'observer-publish', timeout: 5, order: 20, codex: true, statusMessage: 'wendkeep: publishing local observer usage' },
|
|
27
29
|
// Log plan/task progress into the active session note when a task is marked complete.
|
|
28
30
|
// codex: TaskCompleted is not in Codex's hook event enum.
|
|
29
31
|
{ event: 'TaskCompleted', matcher: null, name: 'task-log', timeout: 10, statusMessage: 'wendkeep: plan progress' },
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
PRAGMA foreign_keys = ON;
|
|
2
|
+
|
|
3
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
4
|
+
version INTEGER PRIMARY KEY,
|
|
5
|
+
name TEXT NOT NULL,
|
|
6
|
+
applied_at TEXT NOT NULL
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
10
|
+
project_id TEXT PRIMARY KEY,
|
|
11
|
+
project_name TEXT NOT NULL,
|
|
12
|
+
wendkeep_version TEXT NOT NULL DEFAULT '',
|
|
13
|
+
registered_at TEXT NOT NULL,
|
|
14
|
+
updated_at TEXT NOT NULL
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TABLE IF NOT EXISTS ingest_events (
|
|
18
|
+
event_id TEXT PRIMARY KEY,
|
|
19
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
20
|
+
kind TEXT NOT NULL,
|
|
21
|
+
payload_hash TEXT NOT NULL,
|
|
22
|
+
payload_json TEXT NOT NULL,
|
|
23
|
+
occurred_at TEXT NOT NULL,
|
|
24
|
+
ingested_at TEXT NOT NULL,
|
|
25
|
+
status TEXT NOT NULL DEFAULT 'accepted'
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_ingest_events_project_time
|
|
29
|
+
ON ingest_events(project_id, occurred_at);
|
|
30
|
+
|
|
31
|
+
CREATE TABLE IF NOT EXISTS memory_events (
|
|
32
|
+
event_id TEXT PRIMARY KEY REFERENCES ingest_events(event_id) ON DELETE CASCADE,
|
|
33
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
34
|
+
entity_type TEXT NOT NULL,
|
|
35
|
+
logical_path TEXT NOT NULL,
|
|
36
|
+
operation TEXT NOT NULL,
|
|
37
|
+
revision INTEGER NOT NULL DEFAULT 1,
|
|
38
|
+
content_hash TEXT NOT NULL DEFAULT '',
|
|
39
|
+
source_session_id TEXT NOT NULL DEFAULT '',
|
|
40
|
+
source_turn_id TEXT NOT NULL DEFAULT '',
|
|
41
|
+
occurred_at TEXT NOT NULL,
|
|
42
|
+
payload_json TEXT NOT NULL,
|
|
43
|
+
UNIQUE(project_id, logical_path, revision)
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_memory_events_project_path
|
|
47
|
+
ON memory_events(project_id, logical_path, revision);
|
|
48
|
+
|
|
49
|
+
CREATE TABLE IF NOT EXISTS documents (
|
|
50
|
+
document_id TEXT PRIMARY KEY,
|
|
51
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
52
|
+
logical_path TEXT NOT NULL,
|
|
53
|
+
entity_type TEXT NOT NULL,
|
|
54
|
+
title TEXT NOT NULL DEFAULT '',
|
|
55
|
+
content TEXT NOT NULL DEFAULT '',
|
|
56
|
+
metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
57
|
+
content_hash TEXT NOT NULL DEFAULT '',
|
|
58
|
+
revision INTEGER NOT NULL DEFAULT 1,
|
|
59
|
+
source_session_id TEXT NOT NULL DEFAULT '',
|
|
60
|
+
source_turn_id TEXT NOT NULL DEFAULT '',
|
|
61
|
+
captured_at TEXT NOT NULL,
|
|
62
|
+
deleted_at TEXT,
|
|
63
|
+
UNIQUE(project_id, logical_path)
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_documents_project_type
|
|
67
|
+
ON documents(project_id, entity_type, deleted_at);
|
|
68
|
+
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_documents_project_revision
|
|
70
|
+
ON documents(project_id, revision);
|
|
71
|
+
|
|
72
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
73
|
+
session_id TEXT PRIMARY KEY,
|
|
74
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
75
|
+
provider TEXT NOT NULL DEFAULT '',
|
|
76
|
+
status TEXT NOT NULL DEFAULT 'unknown',
|
|
77
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
78
|
+
change_slug TEXT NOT NULL DEFAULT '',
|
|
79
|
+
started_at TEXT,
|
|
80
|
+
ended_at TEXT,
|
|
81
|
+
updated_at TEXT NOT NULL,
|
|
82
|
+
metadata_json TEXT NOT NULL DEFAULT '{}'
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_project_time
|
|
86
|
+
ON sessions(project_id, started_at, ended_at);
|
|
87
|
+
|
|
88
|
+
CREATE TABLE IF NOT EXISTS agent_runs (
|
|
89
|
+
agent_id TEXT PRIMARY KEY,
|
|
90
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
91
|
+
session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE,
|
|
92
|
+
parent_agent_id TEXT,
|
|
93
|
+
role TEXT NOT NULL DEFAULT 'main',
|
|
94
|
+
agent_name TEXT NOT NULL DEFAULT '',
|
|
95
|
+
agent_type TEXT NOT NULL DEFAULT '',
|
|
96
|
+
workflow TEXT NOT NULL DEFAULT '',
|
|
97
|
+
status TEXT NOT NULL DEFAULT 'unknown',
|
|
98
|
+
model TEXT NOT NULL DEFAULT '',
|
|
99
|
+
effort TEXT NOT NULL DEFAULT '',
|
|
100
|
+
started_at TEXT,
|
|
101
|
+
ended_at TEXT,
|
|
102
|
+
metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
103
|
+
FOREIGN KEY(parent_agent_id) REFERENCES agent_runs(agent_id) ON DELETE SET NULL
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_agent_runs_project_session
|
|
107
|
+
ON agent_runs(project_id, session_id, role);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS usage_rollups (
|
|
2
|
+
rollup_key TEXT PRIMARY KEY,
|
|
3
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
4
|
+
session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE,
|
|
5
|
+
agent_id TEXT NOT NULL REFERENCES agent_runs(agent_id) ON DELETE CASCADE,
|
|
6
|
+
role TEXT NOT NULL DEFAULT 'main',
|
|
7
|
+
provider TEXT NOT NULL DEFAULT '',
|
|
8
|
+
model_provider TEXT NOT NULL DEFAULT '',
|
|
9
|
+
model TEXT NOT NULL DEFAULT '',
|
|
10
|
+
effort TEXT NOT NULL DEFAULT '',
|
|
11
|
+
calls INTEGER NOT NULL DEFAULT 0,
|
|
12
|
+
tokens_input INTEGER NOT NULL DEFAULT 0,
|
|
13
|
+
tokens_cache_write INTEGER NOT NULL DEFAULT 0,
|
|
14
|
+
tokens_cache_read INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
tokens_output INTEGER NOT NULL DEFAULT 0,
|
|
16
|
+
tokens_reasoning INTEGER NOT NULL DEFAULT 0,
|
|
17
|
+
tokens_total INTEGER NOT NULL DEFAULT 0,
|
|
18
|
+
cost_usd REAL NOT NULL DEFAULT 0,
|
|
19
|
+
cost_status TEXT NOT NULL DEFAULT 'unknown',
|
|
20
|
+
pricing_source TEXT NOT NULL DEFAULT '',
|
|
21
|
+
pricing_version TEXT NOT NULL DEFAULT '',
|
|
22
|
+
wasted_usd REAL NOT NULL DEFAULT 0,
|
|
23
|
+
revision INTEGER NOT NULL DEFAULT 1,
|
|
24
|
+
occurred_at TEXT NOT NULL,
|
|
25
|
+
source_event_id TEXT NOT NULL REFERENCES ingest_events(event_id) ON DELETE CASCADE,
|
|
26
|
+
metadata_json TEXT NOT NULL DEFAULT '{}'
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_usage_rollups_project_time
|
|
30
|
+
ON usage_rollups(project_id, occurred_at);
|
|
31
|
+
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_usage_rollups_project_agent
|
|
33
|
+
ON usage_rollups(project_id, agent_id, role);
|
|
34
|
+
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_usage_rollups_project_model
|
|
36
|
+
ON usage_rollups(project_id, model_provider, model);
|
|
37
|
+
|
|
38
|
+
CREATE TABLE IF NOT EXISTS llm_calls (
|
|
39
|
+
call_id TEXT PRIMARY KEY,
|
|
40
|
+
project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE,
|
|
41
|
+
session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE,
|
|
42
|
+
agent_id TEXT NOT NULL REFERENCES agent_runs(agent_id) ON DELETE CASCADE,
|
|
43
|
+
role TEXT NOT NULL DEFAULT 'main',
|
|
44
|
+
provider TEXT NOT NULL DEFAULT '',
|
|
45
|
+
model_provider TEXT NOT NULL DEFAULT '',
|
|
46
|
+
model TEXT NOT NULL DEFAULT '',
|
|
47
|
+
effort TEXT NOT NULL DEFAULT '',
|
|
48
|
+
sequence INTEGER NOT NULL DEFAULT 0,
|
|
49
|
+
occurred_at TEXT NOT NULL,
|
|
50
|
+
tokens_input INTEGER NOT NULL DEFAULT 0,
|
|
51
|
+
tokens_cache_write INTEGER NOT NULL DEFAULT 0,
|
|
52
|
+
tokens_cache_read INTEGER NOT NULL DEFAULT 0,
|
|
53
|
+
tokens_output INTEGER NOT NULL DEFAULT 0,
|
|
54
|
+
tokens_reasoning INTEGER NOT NULL DEFAULT 0,
|
|
55
|
+
tokens_total INTEGER NOT NULL DEFAULT 0,
|
|
56
|
+
cost_usd REAL NOT NULL DEFAULT 0,
|
|
57
|
+
cost_status TEXT NOT NULL DEFAULT 'unknown',
|
|
58
|
+
transcript_id TEXT,
|
|
59
|
+
prompt_text TEXT NOT NULL DEFAULT '',
|
|
60
|
+
response_text TEXT NOT NULL DEFAULT '',
|
|
61
|
+
status TEXT NOT NULL DEFAULT 'complete',
|
|
62
|
+
metadata_json TEXT NOT NULL DEFAULT '{}'
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_llm_calls_project_time
|
|
66
|
+
ON llm_calls(project_id, occurred_at);
|
|
67
|
+
|
|
68
|
+
CREATE INDEX IF NOT EXISTS idx_llm_calls_project_agent
|
|
69
|
+
ON llm_calls(project_id, agent_id, sequence);
|
|
70
|
+
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_llm_calls_project_model
|
|
72
|
+
ON llm_calls(project_id, model_provider, model);
|