Skip to content

Commit beccb8e

Browse files
committed
Add call sites
1 parent cf0b652 commit beccb8e

4 files changed

Lines changed: 166 additions & 0 deletions

File tree

‎skills/codealive-context-engine/SKILL.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,34 @@ artifact that fits in context. The outgoing calls you need are either in the
308308
source you just read or in the preview's 3-cap — reach for `relationships.py`
309309
only when you specifically need incoming calls, inheritance, or references.
310310

311+
**Call sites — read the call, not the whole caller.** Call relationships
312+
(`outgoing_calls` / `incoming_calls`) also show *where* each call is written:
313+
314+
```
315+
• my-org/backend::src/db.py::query
316+
📍 src/db.py:42
317+
↪ called at src/svc.py:17
318+
↪ called at src/svc.py:88 (~60% confident)
319+
↪ … 3 more call site(s) not shown
320+
```
321+
322+
There is no flag for this — positions come back whenever they are known, so
323+
don't go looking for one. Read those exact lines with `Read`/`sed` instead of
324+
fetching the whole calling artifact.
325+
326+
Three things to keep straight:
327+
- **No `called at` line** means the position is **not indexed yet** — the
328+
repository was indexed before call sites existed, or that one edge could not
329+
be located. It **never** means the call does not happen. The relationship
330+
being listed at all is what says the call exists.
331+
- **A confidence** (`~60% confident`) appears only when the position is
332+
approximate; treat it as a hint and confirm by reading. **No confidence
333+
means the position is exact.**
334+
- **`… N more`** means the list was capped, not that the rest do not exist.
335+
336+
For `incoming_calls` the file shown is the **caller's** file, which is a
337+
different file from the artifact you asked about.
338+
311339
**Noise caveat:** outgoing calls occasionally include compiler-generated
312340
helpers (`MoveNext`, `GetEnumerator`, closure invocations) for methods using
313341
`foreach`/LINQ. These are analyzer artifacts — ignore outgoing hits that

‎skills/codealive-context-engine/scripts/lib/api_client.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,12 @@ def get_artifact_relationships(
626626
``relationships`` groups. Each group has relationType, totalCount,
627627
returnedCount, truncated, and an ``items`` list of related artifacts
628628
(identifier, filePath, startLine, shortSummary).
629+
630+
Call items additionally carry ``callSites`` — where the call is
631+
written (filePath, 1-based line, and a ``confidence`` only when the
632+
position is approximate) — and ``callSiteCount``, the pre-cap total.
633+
Their ABSENCE means the position is not indexed yet, never that the
634+
call does not happen.
629635
"""
630636
profile_map = {
631637
"callsOnly": "calls_only",

‎skills/codealive-context-engine/scripts/relationships.py‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,45 @@ def format_relationships(data: dict, data_source: str = None) -> str:
137137
output.append(f" • {ident}")
138138
if loc:
139139
output.append(f" 📍 {loc}")
140+
for call_site_line in _format_call_sites(item):
141+
output.append(call_site_line)
140142
if short_summary:
141143
output.append(f" 📝 {short_summary}")
142144

143145
output.append("")
144146
return "\n".join(output)
145147

146148

149+
def _format_call_sites(item: dict) -> list:
150+
"""Render where a call is written, if we know.
151+
152+
Nothing is printed when the position is unknown — which means the repository has not been
153+
re-indexed since call sites were introduced, NOT that the call does not happen. Printing an
154+
empty "call sites" heading would suggest the latter.
155+
"""
156+
call_sites = item.get("callSites")
157+
if not call_sites:
158+
return []
159+
160+
lines = []
161+
for site in call_sites:
162+
file_path = (site or {}).get("filePath")
163+
line_number = (site or {}).get("line")
164+
if not file_path or not line_number:
165+
continue
166+
167+
# Confidence is shown only when the backend sent one; its absence means the position is exact.
168+
confidence = (site or {}).get("confidence")
169+
approximate = f" (~{confidence:.0%} confident)" if confidence is not None else ""
170+
lines.append(f" ↪ called at {file_path}:{line_number}{approximate}")
171+
172+
total = item.get("callSiteCount")
173+
if isinstance(total, int) and total > len(lines) > 0:
174+
lines.append(f" ↪ … {total - len(lines)} more call site(s) not shown")
175+
176+
return lines
177+
178+
147179
def main():
148180
"""CLI interface for fetching artifact relationships."""
149181
if len(sys.argv) < 2 or sys.argv[1] == "--help":
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
"""Call-site rendering in the relationships script.
2+
3+
The failure mode is silent in both directions: a renderer that drops positions produces output that
4+
looks perfectly normal, and one that prints a heading for an unknown position tells the agent the
5+
call happens nowhere. Both are asserted here.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
import importlib.util
11+
from pathlib import Path
12+
13+
14+
REPO_ROOT = Path(__file__).resolve().parents[1]
15+
SCRIPTS_ROOT = REPO_ROOT / "skills" / "codealive-context-engine" / "scripts"
16+
17+
18+
def _load_relationships():
19+
spec = importlib.util.spec_from_file_location(
20+
"codealive_relationships_call_sites", SCRIPTS_ROOT / "relationships.py"
21+
)
22+
module = importlib.util.module_from_spec(spec)
23+
assert spec.loader is not None
24+
spec.loader.exec_module(module)
25+
return module
26+
27+
28+
relationships = _load_relationships()
29+
30+
31+
def _item(**overrides):
32+
item = {
33+
"identifier": "my-org/backend::src/db.py::query",
34+
"filePath": "src/db.py",
35+
"startLine": 42,
36+
}
37+
item.update(overrides)
38+
return item
39+
40+
41+
def test_known_positions_are_rendered_as_call_sites() -> None:
42+
# Arrange
43+
item = _item(
44+
callSites=[{"filePath": "src/svc.py", "line": 17}],
45+
callSiteCount=1,
46+
)
47+
48+
# Act
49+
lines = relationships._format_call_sites(item)
50+
51+
# Assert
52+
assert lines == [" ↪ called at src/svc.py:17"]
53+
54+
55+
def test_confidence_is_shown_only_when_the_position_is_approximate() -> None:
56+
# Arrange
57+
item = _item(
58+
callSites=[
59+
{"filePath": "src/svc.py", "line": 17},
60+
{"filePath": "src/svc.py", "line": 88, "confidence": 0.6},
61+
],
62+
callSiteCount=2,
63+
)
64+
65+
# Act
66+
lines = relationships._format_call_sites(item)
67+
68+
# Assert
69+
assert lines[0] == " ↪ called at src/svc.py:17"
70+
assert lines[1] == " ↪ called at src/svc.py:88 (~60% confident)"
71+
72+
73+
def test_a_capped_list_says_how_many_were_withheld() -> None:
74+
# Arrange
75+
item = _item(
76+
callSites=[{"filePath": "src/svc.py", "line": 17}],
77+
callSiteCount=4,
78+
)
79+
80+
# Act
81+
lines = relationships._format_call_sites(item)
82+
83+
# Assert
84+
assert lines[-1] == " ↪ … 3 more call site(s) not shown"
85+
86+
87+
def test_an_unindexed_position_renders_nothing_at_all() -> None:
88+
# An empty heading here would read as "this call happens nowhere", which is the opposite of
89+
# what a missing position means.
90+
# Arrange
91+
without_key = _item()
92+
explicit_empty = _item(callSites=[], callSiteCount=0)
93+
94+
# Act
95+
from_missing = relationships._format_call_sites(without_key)
96+
from_empty = relationships._format_call_sites(explicit_empty)
97+
98+
# Assert
99+
assert from_missing == []
100+
assert from_empty == []

0 commit comments

Comments
 (0)