Skip to content

Commit 3cfb08b

Browse files
authored
feat!: use sqlite for all commands (#129)
Blocked by #128.
1 parent 5369ba5 commit 3cfb08b

12 files changed

Lines changed: 74 additions & 189 deletions

File tree

context_use/cli/app.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@
2222
" context-use quickstart "
2323
"Preview with last 30 days, real-time API\n"
2424
"\n"
25-
"Full pipeline (requires PostgreSQL):\n"
26-
" 1. context-use config set-store postgres "
27-
"Set up PostgreSQL (one-time)\n"
28-
" 2. context-use pipeline "
29-
"Ingest → memories (batch API)\n"
25+
"Full pipeline (batch API):\n"
26+
" context-use pipeline "
27+
"Ingest + memories in one go\n"
3028
"\n"
3129
"Or step by step:\n"
3230
" 1. context-use ingest "
@@ -42,7 +40,7 @@
4240
" context-use memories export "
4341
"Export to file\n"
4442
"\n"
45-
"Personal agent (requires PostgreSQL + adk extra):\n"
43+
"Personal agent (requires adk extra):\n"
4644
" 1. uv sync --extra adk "
4745
"Install the ADK extra\n"
4846
" 2. context-use config set-agent adk "
@@ -61,8 +59,8 @@
6159
"Show current settings\n"
6260
" context-use config set-key "
6361
"Change OpenAI API key\n"
64-
" context-use config set-store postgres "
65-
"Set up PostgreSQL\n"
62+
" context-use config set-store <backend> "
63+
"Switch store (sqlite)\n"
6664
" context-use config path "
6765
"Print config file location\n"
6866
)

context_use/cli/base.py

Lines changed: 14 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,7 @@ def providers() -> list[str]:
4646

4747

4848
def require_api_key(cfg: Config) -> None:
49-
"""Exit with guidance if no API key is configured (no interactive prompt).
50-
51-
Used by all PostgreSQL commands where the key must be pre-configured.
52-
"""
49+
"""Exit with guidance if no API key is configured (no interactive prompt)."""
5350
if cfg.openai_api_key:
5451
return
5552
out.error(
@@ -59,20 +56,6 @@ def require_api_key(cfg: Config) -> None:
5956
sys.exit(1)
6057

6158

62-
def require_persistent(cfg: Config, command: str) -> None:
63-
"""Exit with guidance if the store backend is not PostgreSQL."""
64-
if cfg.store_provider == "postgres":
65-
return
66-
out.error(f"'{command}' requires PostgreSQL for persistent storage.")
67-
print()
68-
out.info("To try context-use without a database:")
69-
out.next_step("context-use quickstart")
70-
print()
71-
out.info("To set up PostgreSQL:")
72-
out.next_step("context-use config set-store postgres")
73-
sys.exit(1)
74-
75-
7659
def ensure_api_key(cfg: Config) -> None:
7760
"""Ensure an API key is present, prompting interactively if needed.
7861
@@ -330,40 +313,23 @@ async def run(
330313
"""Override with the command's actual logic."""
331314

332315

333-
class PersistentCommand(ContextCommand, ABC):
334-
"""Command that requires PostgreSQL.
316+
class ApiCommand(ContextCommand, ABC):
317+
"""Command that requires a configured OpenAI API key.
335318
336-
``_prepare`` enforces ``require_persistent`` before a context is built.
337-
Subclasses should set ``display_name`` to the full CLI path shown in the
338-
error message (e.g. ``"memories list"``).
319+
``_prepare`` enforces ``require_api_key`` before a context is built.
339320
"""
340321

341-
display_name: ClassVar[str] = ""
342-
343322
def _prepare(self, cfg: Config, args: argparse.Namespace) -> Config:
344-
require_persistent(cfg, self.display_name or self.name)
345-
return super()._prepare(cfg, args)
346-
347-
348-
class PersistentApiCommand(PersistentCommand, ABC):
349-
"""Command that requires PostgreSQL **and** a configured OpenAI API key.
350-
351-
``_prepare`` adds ``require_api_key`` on top of
352-
:class:`PersistentCommand`'s checks.
353-
"""
354-
355-
def _prepare(self, cfg: Config, args: argparse.Namespace) -> Config:
356-
cfg = super()._prepare(cfg, args)
357323
require_api_key(cfg)
358-
return cfg
324+
return super()._prepare(cfg, args)
359325

360326

361-
class AgentCommand(PersistentApiCommand, ABC):
362-
"""Command that requires PostgreSQL, an OpenAI API key, **and** a configured
327+
class AgentCommand(ApiCommand, ABC):
328+
"""Command that requires an OpenAI API key **and** a configured
363329
agent backend.
364330
365331
``_prepare`` adds ``require_agent_backend`` on top of
366-
:class:`PersistentApiCommand`'s checks.
332+
:class:`ApiCommand`'s checks.
367333
"""
368334

369335
def _prepare(self, cfg: Config, args: argparse.Namespace) -> Config:
@@ -373,15 +339,13 @@ def _prepare(self, cfg: Config, args: argparse.Namespace) -> Config:
373339

374340

375341
class EphemeralApiCommand(ContextCommand, ABC):
376-
"""Command that always runs with an SQLite store and an OpenAI API key.
342+
"""Command that runs with a temporary SQLite store and an OpenAI API key.
377343
378-
Intended for zero-config preview flows (e.g. ``quickstart``) where no
379-
database is needed or desired.
344+
Intended for zero-config preview flows (e.g. ``quickstart``) where the
345+
data does not need to persist beyond the session.
380346
381-
``_prepare`` unconditionally sets ``store_provider = "sqlite"`` and then
382-
calls ``ensure_api_key``, which prompts interactively when no key is
383-
configured (unlike :class:`PersistentApiCommand` which exits with an
384-
error).
347+
``_prepare`` points the database to a temporary file and then calls
348+
``ensure_api_key``, which prompts interactively when no key is configured.
385349
"""
386350

387351
llm_mode: ClassVar[str] = "sync"
@@ -404,7 +368,7 @@ class CommandGroup:
404368
405369
class MemoriesGroup(CommandGroup):
406370
name = "memories"
407-
help = "Manage memories (requires PostgreSQL)"
371+
help = "Manage memories"
408372
subcommands = [
409373
MemoriesGenerateCommand,
410374
MemoriesListCommand,

context_use/cli/commands/agent.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ async def run(
7272

7373
class AgentSynthesiseCommand(BaseAgentSkillCommand):
7474
name = "synthesise"
75-
display_name = "agent synthesise"
7675
help = "Synthesise pattern memories from event memories"
7776
skill_name = "synthesise"
7877
header_text = "Synthesising memories"
@@ -94,7 +93,6 @@ async def run(
9493

9594
class AgentUserProfileCommand(BaseAgentSkillCommand):
9695
name = "profile"
97-
display_name = "agent profile"
9896
help = "Compile a first-person user profile from memories (printed to stdout)"
9997
skill_name = "profile"
10098
header_text = "Generating user profile"
@@ -106,7 +104,6 @@ class AgentUserProfileCommand(BaseAgentSkillCommand):
106104

107105
class AgentAskCommand(AgentCommand):
108106
name = "ask"
109-
display_name = "agent ask"
110107
help = "Send a free-form query to the personal agent"
111108

112109
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -146,7 +143,7 @@ async def run(
146143

147144
class AgentGroup(CommandGroup):
148145
name = "agent"
149-
help = "Run the personal memory agent (requires PostgreSQL + adk extra)"
146+
help = "Run the personal memory agent (requires adk extra)"
150147
description = (
151148
"Run the personal memory agent with a built-in skill or a free-form query. "
152149
"Configure a backend first with: context-use config set-agent adk"

context_use/cli/commands/config.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ def badge(attr: str) -> str:
4848

4949
if cfg.store_provider == "postgres":
5050
store_val = f"postgres ({cfg.db_host}:{cfg.db_port}/{cfg.db_name})"
51+
elif cfg.store_provider == "sqlite":
52+
store_val = f"sqlite ({cfg.db_path})"
5153
else:
52-
store_val = "memory (in-memory, no persistence)"
54+
store_val = cfg.store_provider
5355
out.kv("Store", f"{store_val} {badge('store_provider')}")
5456

5557
if cfg.agent_backend:
@@ -70,8 +72,7 @@ def badge(attr: str) -> str:
7072
print()
7173
out.info("To change settings:")
7274
out.next_step("context-use config set-key", "change OpenAI API key")
73-
out.next_step("context-use config set-store postgres", "set up PostgreSQL")
74-
out.next_step("context-use config set-store memory", "switch to in-memory")
75+
out.next_step("context-use config set-store sqlite", "use SQLite (default)")
7576
out.next_step("context-use config set-agent adk", "configure agent backend")
7677
print()
7778

@@ -252,10 +253,10 @@ async def execute(self, args: argparse.Namespace) -> None:
252253
if backend == "adk":
253254
out.info("Requires the adk extra: uv sync --extra adk")
254255

255-
if not cfg.uses_postgres:
256-
out.warn("The agent requires PostgreSQL for persistent storage.")
256+
if cfg.store_provider not in ("sqlite", "postgres"):
257+
out.warn("The agent requires a persistent store (sqlite or postgres).")
257258
out.info("Set it up first with:")
258-
out.next_step("context-use config set-store postgres")
259+
out.next_step("context-use config set-store sqlite")
259260
print()
260261

261262
print()

context_use/cli/commands/ingest.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from context_use.cli import output as out
77
from context_use.cli.base import (
8-
PersistentCommand,
8+
ContextCommand,
99
add_archive_args,
1010
print_ingest_result,
1111
resolve_archive,
@@ -16,13 +16,12 @@
1616
from context_use import ContextUse
1717

1818

19-
class IngestCommand(PersistentCommand):
19+
class IngestCommand(ContextCommand):
2020
name = "ingest"
21-
help = "Step 1: Process a data export archive (requires PostgreSQL)"
21+
help = "Step 1: Process a data export archive"
2222
description = (
2323
"Process a data export archive. Run without arguments to "
24-
"interactively pick from archives in data/input/. "
25-
"Requires PostgreSQL."
24+
"interactively pick from archives in data/input/."
2625
)
2726

2827
def add_arguments(self, parser: argparse.ArgumentParser) -> None:

context_use/cli/commands/memories.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from context_use.models.memory import MemorySummary
1515

1616
from context_use.cli.base import (
17+
ApiCommand,
1718
CommandGroup,
18-
PersistentApiCommand,
19-
PersistentCommand,
19+
ContextCommand,
2020
run_batches,
2121
)
2222
from context_use.config import Config
@@ -57,9 +57,8 @@ def export_memories_json(memories: list[MemorySummary], path: Path) -> None:
5757
path.write_text(json.dumps(rows, indent=2, ensure_ascii=False), encoding="utf-8")
5858

5959

60-
class MemoriesGenerateCommand(PersistentApiCommand):
60+
class MemoriesGenerateCommand(ApiCommand):
6161
name = "generate"
62-
display_name = "memories generate"
6362
help = "Step 2: Generate memories from ingested archives (batch API)"
6463

6564
async def run(
@@ -101,9 +100,8 @@ async def run(
101100
print()
102101

103102

104-
class MemoriesListCommand(PersistentCommand):
103+
class MemoriesListCommand(ContextCommand):
105104
name = "list"
106-
display_name = "memories list"
107105
help = "List memories"
108106

109107
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -140,9 +138,8 @@ async def run(
140138
print()
141139

142140

143-
class MemoriesSearchCommand(PersistentApiCommand):
141+
class MemoriesSearchCommand(ApiCommand):
144142
name = "search"
145-
display_name = "memories search"
146143
help = "Semantic search over memories"
147144

148145
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -184,9 +181,8 @@ async def run(
184181
print()
185182

186183

187-
class MemoriesGetCommand(PersistentCommand):
184+
class MemoriesGetCommand(ContextCommand):
188185
name = "get"
189-
display_name = "memories get"
190186
help = "Show full details of a single memory"
191187

192188
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -215,9 +211,8 @@ async def run(
215211
print()
216212

217213

218-
class MemoriesUpdateCommand(PersistentApiCommand):
214+
class MemoriesUpdateCommand(ApiCommand):
219215
name = "update"
220-
display_name = "memories update"
221216
help = "Edit the content or date range of a memory"
222217

223218
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -255,9 +250,8 @@ async def run(
255250
out.success(f"Updated memory {m.id}")
256251

257252

258-
class MemoriesCreateCommand(PersistentApiCommand):
253+
class MemoriesCreateCommand(ApiCommand):
259254
name = "create"
260-
display_name = "memories create"
261255
help = "Write a new memory to the store"
262256

263257
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -291,9 +285,8 @@ async def run(
291285
out.success(f"Created memory {m.id}")
292286

293287

294-
class MemoriesArchiveCommand(PersistentCommand):
288+
class MemoriesArchiveCommand(ContextCommand):
295289
name = "archive"
296-
display_name = "memories archive"
297290
help = "Mark one or more memories as superseded"
298291

299292
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -325,9 +318,8 @@ async def run(
325318
out.warn(f"Not found: {', '.join(not_found)}")
326319

327320

328-
class MemoriesExportCommand(PersistentCommand):
321+
class MemoriesExportCommand(ContextCommand):
329322
name = "export"
330-
display_name = "memories export"
331323
help = "Export memories to a file"
332324

333325
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
@@ -373,7 +365,7 @@ async def run(
373365

374366
class MemoriesGroup(CommandGroup):
375367
name = "memories"
376-
help = "Manage memories (requires PostgreSQL)"
368+
help = "Manage memories"
377369
subcommands = [
378370
MemoriesGenerateCommand,
379371
MemoriesListCommand,

0 commit comments

Comments
 (0)