* feat: introduce hindsight-api-slim and hindsight-all-slim packages Closes #552 - Move all source code from hindsight-api/ to new hindsight-api-slim/ - hindsight-api-slim has heavy ML deps (torch, sentence-transformers, transformers, einops, flashrank, mlx, mlx-lm, safetensors) and pg0-embedded as optional extras: [local-ml], [embedded-db], [all] - hindsight-api becomes a zero-code meta-package depending on hindsight-api-slim[all] for full backward compatibility - Add hindsight-all-slim meta-package: hindsight-api-slim + client + embed - hindsight-all updated to depend on hindsight-api-slim[all] - pg0.py: lazy-import pg0 with clear ImportError pointing to [embedded-db] - Dockerfile: replace sed hack with proper uv sync --extra flags - Update release.yml, test.yml, lint.sh, release.sh, CLAUDE.md and all path references throughout the repo * refactor: rename hindsight/ directory to hindsight-all/ * docs: document hindsight-api-slim and hindsight-all-slim package variants Add package variants table and extras explanation to installation.md * docs: remove emojis from installation.md, use professional tone * docs: link Docker slim variant to pip package variants section * docs: consolidate Docker image variants into single table * ci: fix working-directory paths after package restructure - Replace all hindsight-api → hindsight-api-slim in test.yml - Replace hindsight → hindsight-all in test.yml - Add --extra embedded-db to test-embed API install step * ci: add local-ml and embedded-db extras to API sync steps These extras were previously implicit in the old hindsight-api package (which bundled everything). Now that hindsight-api-slim uses optional extras, we must explicitly request local-ml and embedded-db in CI. * ci: add API install step with embedded-db to test-embed smoke test The smoke test starts hindsight-api as a daemon, which requires pg0-embedded. Add a dedicated install step for hindsight-api-slim with embedded-db extra so the daemon can start successfully. * ci: remove --no-install-project when using optional extras When --no-install-project is combined with --extra, the optional deps are not installed because extras require the project to be active. Remove --no-install-project from steps that need local-ml or embedded-db. * ci: fix ordering of uv sync steps to preserve optional extras When uv sync runs for a different workspace member, it removes optional extras installed for other members. Fix by always running extra-requiring API sync last, after other workspace member syncs. Also remove --no-install-project from embedded-db sync in test-embed, as --no-install-project prevents optional extras from being active. * ci: add local-ml extra to test-embed API install for smoke test The smoke test starts the full API server which needs sentence-transformers for local embeddings (default provider). Add local-ml extra to the install. * ci: simplify extras with --all-extras and add slim pip smoke test - Replace explicit --extra local-ml --extra embedded-db with --all-extras for cleaner, more maintainable sync steps - Add test-pip-slim job: tests hindsight-api-slim[embedded-db] without local ML models, using Cohere for embeddings/reranking (mirrors Docker slim smoke test approach) * ci: simplify slim smoke test to health check only (mirrors Docker test)
83 lines
5 KiB
Python
83 lines
5 KiB
Python
"""Prompts for the consolidation engine."""
|
|
|
|
# Default mission when no bank-specific mission is set
|
|
_DEFAULT_MISSION = "Track every detail: names, numbers, dates, places, and relationships. Prefer specifics over abstractions, never generalise."
|
|
|
|
# Processing rules — always present regardless of mission
|
|
_PROCESSING_RULES = """Processing rules (always apply):
|
|
- REDUNDANT: same info worded differently → UPDATE the existing observation.
|
|
- CONTRADICTION/UPDATE: capture both states with temporal markers ("used to X, now Y").
|
|
- RESOLVE REFERENCES: when a new fact provides a concrete value resolving a vague placeholder in an existing observation (e.g. "home country", "hometown", "birthplace", "native language", "her ex", "that city"), UPDATE the observation to embed the resolved value explicitly. Example: new fact says "grandma in Sweden" + existing observation says "moved from her home country" → update to "home country is Sweden".
|
|
- NEVER merge observations about different people or unrelated topics."""
|
|
|
|
# Data section — format placeholders {facts_text} and {observations_text} are substituted at call time
|
|
_BATCH_DATA_SECTION = """
|
|
NEW FACTS:
|
|
{facts_text}
|
|
|
|
EXISTING OBSERVATIONS (JSON array, pooled from recalls across all facts above):
|
|
{observations_text}
|
|
|
|
Each observation includes:
|
|
- id: unique identifier for updating
|
|
- text: the observation content
|
|
- proof_count: number of supporting memories
|
|
- occurred_start/occurred_end: temporal range of source facts
|
|
- source_memories: array of supporting facts with their text and dates
|
|
|
|
Compare the facts against existing observations:
|
|
- Same topic as an existing observation → UPDATE it (observation_id + source_fact_ids)
|
|
- New topic with durable knowledge → CREATE a new observation (source_fact_ids)
|
|
- Cross-reference facts within the batch: a later fact may resolve a vague reference in an earlier one
|
|
- Purely ephemeral facts → omit them unless the MISSION above explicitly targets such data (e.g. timestamped events, session state, screen content)"""
|
|
|
|
# Output format — JSON braces escaped as {{ }} so .format() leaves them literal
|
|
_BATCH_OUTPUT_FORMAT = """
|
|
Output a JSON object with three arrays.
|
|
|
|
## EXAMPLE
|
|
|
|
Input facts:
|
|
[a1b2c3d4-e5f6-7890-abcd-ef1234567890] Alice mentioned she works long hours, often past midnight | Involving: Alice (occurred_start=2024-01-15, mentioned_at=2024-01-15)
|
|
[b2c3d4e5-f6a7-8901-bcde-f12345678901] Alice said she's exhausted from the project deadlines | Involving: Alice (occurred_start=2024-01-20, mentioned_at=2024-01-20)
|
|
|
|
Good observation text — clean prose, no metadata, each fact tracked distinctly:
|
|
"Alice works long hours, often past midnight."
|
|
"Alice feels exhausted from project deadlines."
|
|
|
|
Bad observation text — NEVER do this (verbatim copy of fact text with metadata):
|
|
"Alice mentioned she works long hours, often past midnight | Involving: Alice (occurred_start=2024-01-15, mentioned_at=2024-01-15)"
|
|
|
|
Observation text rules:
|
|
- Write clean prose — NEVER copy raw fact lines or their metadata (temporal fields, "Involving:", "When:" labels, UUIDs).
|
|
- Parenthesized metadata like (occurred_start=...) and pipe-separated labels like "| Involving: ..." are fact formatting — strip them entirely from observation text.
|
|
- How many observations to create and how much to aggregate is driven by the MISSION above.
|
|
|
|
{{"creates": [{{"text": "Alice works long hours, often past midnight.", "source_fact_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]}}, {{"text": "Alice feels exhausted from project deadlines.", "source_fact_ids": ["b2c3d4e5-f6a7-8901-bcde-f12345678901"]}}],
|
|
"updates": [{{"text": "Alice works at Acme Corp as a senior engineer", "observation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "source_fact_ids": ["d4e5f6a7-b8c9-0123-defa-234567890123"]}}],
|
|
"deletes": [{{"observation_id": "e5f6a7b8-c9d0-1234-efab-345678901234"}}]}}
|
|
|
|
Rules:
|
|
- "source_fact_ids": copy the EXACT UUID strings shown in brackets [uuid] from NEW FACTS — never use integers or positions.
|
|
- "observation_id": copy the EXACT "id" UUID string from EXISTING OBSERVATIONS.
|
|
- One create/update may reference multiple facts when they jointly support the observation.
|
|
- "deletes": only when an observation is directly superseded or contradicted by new facts.
|
|
- Do NOT include "tags" — handled automatically.
|
|
- Return {{"creates": [], "updates": [], "deletes": []}} if nothing durable is found."""
|
|
|
|
|
|
def build_batch_consolidation_prompt(observations_mission: str | None = None) -> str:
|
|
"""
|
|
Build the consolidation prompt for batch mode (multiple facts per LLM call).
|
|
|
|
The mission defines *what* to track (customisable per bank).
|
|
Processing rules and output format are always present regardless of mission.
|
|
"""
|
|
mission = observations_mission or _DEFAULT_MISSION
|
|
|
|
return (
|
|
"You are a memory consolidation system. Synthesize facts into observations "
|
|
"and merge with existing observations when appropriate.\n\n"
|
|
f"## MISSION\n{mission}\n\n"
|
|
f"{_PROCESSING_RULES}" + _BATCH_DATA_SECTION + _BATCH_OUTPUT_FORMAT
|
|
)
|