Skip to content
Draft
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
20 changes: 20 additions & 0 deletions docs/INTERNAL-SUGGESTION-JOBS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Suggestion job provenance

The default suggestion judge launches `amplifier run --output-format json` with
these values in a private copy of its child environment:

- `AMPLIFIER_SESSION_VISIBILITY=internal`
- `AMPLIFIER_SESSION_PURPOSE=memory.suggestion`
- `AMPLIFIER_SESSION_ORIGIN=agent`

Only this implementation job gets the declaration. The caller's environment,
provider routing, credentials, CLI arguments, timer scheduling, and retry
behavior are unchanged. No raw environment values are logged.

The compatible CLI persists visibility and purpose as creation metadata. Unified
can then keep this history available for diagnostics while excluding it from
ordinary chat lists and default searches. A generic agent origin does not make
other standalone CLI conversations internal. End-to-end presentation requires
both the CLI persistence support and the Unified consumer support; an older CLI
ignores the visibility declaration. Historical unmarked sessions are not
rewritten or classified by prompt wording.
12 changes: 11 additions & 1 deletion src/amplifier_memory/suggest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1060,12 +1060,22 @@ def default_model_call(prompt: str, *, timeout: float = 300.0, call: Judge | Non
"`run_suggest` (and point AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH at a fixture)"
)
argv = build_argv(prompt, call)
# Only this background judge is internal. Preserve routing/credentials in
# the child environment without relabelling the caller or other CLI jobs.
child_env = dict(os.environ)
child_env.update(
AMPLIFIER_SESSION_VISIBILITY="internal",
AMPLIFIER_SESSION_PURPOSE="memory.suggestion",
AMPLIFIER_SESSION_ORIGIN="agent",
)
# The command as run, minus the request itself: a failure names the flags that
# produced it (a provider id that does not exist on this device is the likely one),
# never the whole transcript.
shown = " ".join(argv[:-1])
try:
proc = subprocess.run(argv, capture_output=True, text=True, check=False, timeout=timeout)
proc = subprocess.run(
argv, capture_output=True, text=True, check=False, timeout=timeout, env=child_env
)
except (OSError, ValueError, subprocess.TimeoutExpired) as exc:
raise RuntimeError(f"{shown} failed: {type(exc).__name__}: {exc}") from exc
if proc.returncode != 0:
Expand Down
31 changes: 31 additions & 0 deletions tests/test_suggest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1287,3 +1287,34 @@ def test_a_run_over_a_worker_only_night_still_reports(tmp_path: Path, store: Pat
assert report.status == "ok", "a night with no human sessions is not a degraded night"
assert "sessions=0 origin_excluded=3" in report.log_line
assert call.prompts == [], "no session read means no model call"


@pytest.mark.parametrize("returncode", [0, 1])
def test_only_suggestion_child_is_marked_internal(monkeypatch, returncode):
"""Explicit provenance reaches CLI without mutating this process or retrying."""
import os

seen = []
monkeypatch.setenv("AMPLIFIER_SESSION_VISIBILITY", "chat")
monkeypatch.setenv("AMPLIFIER_SESSION_PURPOSE", "caller.task")
monkeypatch.setenv("AMPLIFIER_SESSION_ORIGIN", "human")
monkeypatch.setenv("SYNTHETIC_ROUTING_SETTING", "keep")
monkeypatch.delenv("PYTEST_CURRENT_TEST", raising=False)
before = dict(os.environ)

def fake_run(argv, **kwargs):
seen.append((argv, kwargs))
return subprocess.CompletedProcess(argv, returncode, '{"response":"[]"}', "synthetic failure")

monkeypatch.setattr(suggest.subprocess, "run", fake_run)
if returncode:
with pytest.raises(RuntimeError, match="exited 1"):
suggest.default_model_call("synthetic")
else:
assert suggest.default_model_call("synthetic") == "[]"
assert len(seen) == 1
argv, kwargs = seen[0]
assert argv == ["amplifier", "run", "--output-format", "json", "synthetic"]
assert kwargs["env"] == {**before, "AMPLIFIER_SESSION_VISIBILITY": "internal",
"AMPLIFIER_SESSION_PURPOSE": "memory.suggestion", "AMPLIFIER_SESSION_ORIGIN": "agent"}
assert dict(os.environ) == before