You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AMPR-161 #482: fix CI by moving library test to jvmTest; refresh concepts
- Move PhaseSparkLibraryTest from commonTest to jvmTest. The test calls
DefaultPhaseSparkLibrary.load() which relies on the JVM classpath
fallback for resource access. Android unit tests (testDebugUnitTest)
don't have the bundled .spark.md files on their unit-test classpath,
causing all six library assertions to fail in CI. This matches the
existing pattern in ProviderPricingCatalogTest (also jvmTest only).
At runtime on Android, Res.readBytes works through Compose Resources,
so the implementation itself remains commonMain — only the test moves.
- Update docs/concepts/spark-system.md to reflect the new Spark fields
(phaseContributions, agentRole, requestedToolIds), composition rules
(additive, not exclusive), declarative .spark.md support, and the new
source files. Bump last_verified.
Concept-Verified: CognitiveRelay
Concept-Verified: PluginPermissions
Concept-Verified: PropelLoop
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
modelPreference) followed by a markdown body. The body may contain
49
+
`## When Perceiving / Planning / Executing / Learning` sections, which the
50
+
parser extracts into `phaseContributions`; text outside those headers
51
+
becomes the base `promptContribution`.
52
+
53
+
`DefaultPhaseSparkLibrary` loads the bundled fixtures at construction time;
54
+
`PhaseSparkLibrary.selectFor(SparkSelectionContext)` filters by phase
55
+
eligibility, tag intersection, and keyword match against `whenToUse`.
56
+
`PhaseSparkManager` consults the library when
57
+
`AmpereSpikeFlags.declarativeSparksEnabled` is on, applying both the
58
+
built-in `PhaseSpark.forPhase(phase)` and any selected declarative sparks.
31
59
32
60
## Why it exists
33
61
@@ -54,15 +82,20 @@ exceed parent permissions, so adding a Spark is monotone safe.
54
82
## Where it lives
55
83
56
84
-`agents/domain/cognition/Spark.kt` — the interface; not sealed (subpackages need to extend).
57
-
-`agents/domain/cognition/SparkStack.kt` — composition; intersection for tools, intersection-then-union semantics for file access.
85
+
-`agents/domain/cognition/SparkStack.kt` — composition; `buildSystemPrompt(phase)` concatenates every spark's contribution plus its per-phase section; `effectiveAgentRole()` concatenates role fragments; `effectiveRequestedTools()` unions; `effectiveAllowedTools()` intersects; intersection-then-union semantics for file access.
@@ -72,15 +105,19 @@ exceed parent permissions, so adding a Spark is monotone safe.
72
105
-**Apply/remove are paired and observed.** Every `SparkAppliedEvent` has a matching `SparkRemovedEvent` (or end-of-run cleanup). `ArcTraceProjection` uses these events to reconstruct phase context.
73
106
-**Tool-set composition is intersection.** When two Sparks both specify `allowedTools`, the effective set is `A ∩ B`, not `A ∪ B`. A change that switches to union is a permission expansion and violates the narrowing invariant.
74
107
-**PhaseSparks add context only.** They do not narrow tools (`allowedTools = null`) or file access (`fileAccessScope = null`). Their job is prompt augmentation, not capability gating.
75
-
-**Spark `name` follows `Type:Subtype`.**`Role:Code`, `Phase:Perceive`, `Project:ampere`. The trace projection extracts subtype from this prefix; ad-hoc names break trace bucketing.
108
+
-**Spark `name` follows `Type:Subtype`.**`Role:Code`, `Phase:Perceive`, `Project:ampere`, `PhaseSpark:cooking-domain`. The trace projection extracts subtype from this prefix; ad-hoc names break trace bucketing. Declarative sparks use `PhaseSpark:<id>` so trace bucketing that keys on `Phase:` still treats built-in phases distinctly.
109
+
-**Sparks are pure data.** No Kotlin lambdas on the `Spark` interface — behavioral guidance is expressed as markdown in `promptContribution` / `phaseContributions`, interpreted by the LLM. This is what makes a `.spark.md` file a complete, shareable unit of customization.
110
+
-**Composition is additive, not exclusive.** When `N` sparks are on the stack, `buildSystemPrompt` includes contributions from all `N` — not "the topmost wins". `effectiveAgentRole` concatenates fragments with `" + "` (e.g. `Code Writer + Cooking Domain`). `effectiveRequestedTools` unions.
76
111
77
112
## Common operations
78
113
79
-
-**Add a new Spark type** — implement `Spark` (or extend an existing sealed family like `PhaseSpark`), define `name`, `promptContribution`, optionally `allowedTools` / `fileAccessScope`, mark it `@Serializable` with a stable `@SerialName`.
114
+
-**Add a new Spark type** — implement `Spark` (or extend an existing sealed family like `PhaseSpark`), define `name`, `promptContribution`, optionally `allowedTools` / `fileAccessScope` / `phaseContributions` / `agentRole` / `requestedToolIds`, mark it `@Serializable` with a stable `@SerialName`.
115
+
-**Author a declarative spark** — write a `.spark.md` file under `composeResources/files/sparks/` with frontmatter (id, name, whenToUse required) and a markdown body, optionally with `## When <Phase>` sections for phase-specific guidance. Add the path to `DefaultPhaseSparkLibrary.DEFAULT_SPARKS`.
80
116
-**Apply a Spark transiently** — `SparkStack.push(spark)` and ensure a matching `pop` in `finally`. `PhaseSparkManager` handles this for phase boundaries.
81
-
-**Compose a per-agent stack** — `RoleSpark` + `ProjectSpark` at agent construction, then `PhaseSpark` pushed/popped per phase, then `TaskSpark` pushed/popped per task.
117
+
-**Compose a per-agent stack** — `RoleSpark` + `ProjectSpark` at agent construction, then `PhaseSpark` pushed/popped per phase (potentially multiple when declarative library is active), then `TaskSpark` pushed/popped per task.
82
118
-**Inspect the active stack** — subscribe to `SparkAppliedEvent` / `SparkRemovedEvent` on the bus, or read `SparkStack.current`.
83
119
-**Enable phase sparks** — set `AgentConfiguration.cognitiveConfig.phaseSparks.enabled = true` (optionally per-phase) or `AMPERE_PHASE_SPARKS=true` globally.
120
+
-**Enable declarative phase sparks** — set `AmpereSpikeFlags.declarativeSparksEnabled = true` and inject a `PhaseSparkLibrary` into the agent (via `SparkBasedAgent.setPhaseSparkLibrary` or `PhaseSparkManager.createWithLibrary`). Default is off; flip in `try { ... } finally { ... = false }` blocks in tests.
0 commit comments