Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
VENV := .venv/bin

# ruff: prefer the project venv, fall back to `uvx ruff` when no venv is present
RUFF := $(shell [ -x .venv/bin/ruff ] && echo .venv/bin/ruff || echo "uvx ruff")

.PHONY: test lint fmt typecheck check hooks

test:
$(VENV)/pytest tests/ -v

lint:
$(VENV)/ruff check src/ tests/
$(RUFF) check src/ tests/

fmt:
$(VENV)/ruff format src/ tests/
$(RUFF) format src/ tests/

typecheck:
$(VENV)/pyright src/
Expand Down
31 changes: 31 additions & 0 deletions src/codeatrium/cli/prime_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,37 @@

# Retrieve past conversations from work on a specific branch
loci context --branch "feature/foo" --json
```

### IDE selection as a deictic anchor

When the IDE injects an active editor selection (shown as `⧉ Selected N lines from <file>`), treat that selection as the referent of "this / これ / この〜" in the user's prompt. The selection resolves *which* symbol the memory lookup is about — it is NOT by itself a request to recall.

Recall from a selection ONLY when BOTH hold:

1. a selection is active, AND
2. either (a) the user asks about the past — recall / why / history / decisions ("この実装の時の会話を思い出して", "これ前にどう決めた?"), or (b) your own next action on the selected code (edit / refactor / debug) needs prior decisions or constraints.

Do NOT recall when the selection is present only because the user is about to edit it and asks nothing past-oriented.

Map the selection to a query:

- Selection IS a named function/class → look it up directly:

```bash
loci context --symbol "<name>" --json
```

- Selection is a fragment INSIDE one function/class — the `def`/`class` line is usually not in the selection, so resolve the enclosing symbol first (LSP `workspaceSymbol`/`hover`, or read `<file>` around the selection), then:

```bash
loci context --symbol "<enclosing-symbol>" --json
```

- Selection spans multiple symbols or belongs to none (module-level code, config, comments), OR the lookups above return no results → fall back to semantic search over your question:

```bash
loci search "<the user's question>" --json
```\
"""

Expand Down
34 changes: 34 additions & 0 deletions tests/test_prime_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,40 @@ def test_prime_text_context_section_explains_bidirectional_recall():
)


# ---- IDE selection trigger contract ----


def test_prime_text_has_ide_selection_section():
"""PRIME_TEXT must explain IDE selection as a deictic anchor for context recall"""
assert "IDE selection as a deictic anchor" in PRIME_TEXT


def test_prime_text_ide_selection_requires_conjunction():
"""A selection alone must NOT trigger recall — requires selection AND a recall need"""
text_lower = PRIME_TEXT.lower()
assert "only when both" in text_lower
# both branches of the recall need must be present
assert "asks about the past" in text_lower
assert "your own next action" in text_lower


def test_prime_text_ide_selection_guards_against_over_fire():
"""PRIME_TEXT must tell the agent NOT to recall on edit-only selections"""
assert "Do NOT recall" in PRIME_TEXT


def test_prime_text_ide_selection_resolves_enclosing_symbol_for_fragments():
"""A fragment selection must resolve its enclosing symbol before context lookup"""
assert "enclosing symbol" in PRIME_TEXT


def test_prime_text_ide_selection_has_search_fallback():
"""When no single symbol applies or context is empty, fall back to loci search"""
text_lower = PRIME_TEXT.lower()
assert "spans multiple symbols" in text_lower
assert "return no results" in text_lower


# ---- inject_claude_md idempotency ----


Expand Down