AMPR-161 #482: declarative PhaseSpark surface + spark composition scaffolding#485
Merged
wow-miley merged 2 commits intoMay 17, 2026
Conversation
…n scaffolding Lands the AMPR-161 spike (declarative PhaseSpark authoring) plus the foundational refactor toward a unified spark-driven agent architecture. Declarative PhaseSpark (AMPR-161 core): - `DeclarativePhaseSparkSource` + `DeclarativePhaseSpark` types, parser, and 3 bundled `.spark.md` fixtures under `composeResources/files/sparks/` - `PhaseSparkLibrary` interface + `DefaultPhaseSparkLibrary` with deterministic phase/tag/keyword selection; KMP-platform fallbacks for resource loading - `AmpereSpikeFlags.declarativeSparksEnabled` gates the new path (default off) - `AgentLLMService.activePromptProvider` evaluated at call time prepends the agent's composed system prompt to outbound LLM payloads - `PhaseSparkManager` refactored from single-spark boolean to multi-spark list; cleans up in reverse order - Integration test asserts spark bodies reach the LLM payload verbatim and emit the expected SparkAppliedEvent/SparkRemovedEvent pairs Spark composition scaffolding (unification follow-up): - `Spark` interface enriched with optional pure-data fields: `agentRole`, `phaseContributions: Map<CognitivePhase, String>`, `requestedToolIds`. All default empty — no behavioral lambdas; sparks stay shareable as `.spark.md` - `SparkStack.buildSystemPrompt(currentPhase)` now concatenates EVERY spark's contribution plus its per-phase section. `effectiveAgentRole()` concatenates fragments across the stack; `effectiveRequestedTools()` unions. - `SparkParser` extracts `## When Perceiving/Planning/Executing/Learning` sections into `phaseContributions` - `DeclarativePhaseSpark` carries `eligiblePhases` + `phaseContributions` (one spark per source, multi-phase-capable) - `AutonomousAgent.currentCognitivePhase` tracked by `PhaseSparkManager` so `currentSystemPrompt` includes the right per-phase guidance per LLM call - `Tool.parameterStrategy: ParameterStrategy?` — tools own their own param-fill strategies; `ToolExecutionEngine` prefers tool-owned over the externally-registered map - `RoleSpark.Code/Research/Operations/Planning` enriched with `agentRole` + `requestedToolIds` for composition participation - State rename: `ProductAgentState` → `ProductState`, `ProjectAgentState` → `ProjectState` Out of scope (filed as follow-up tickets in `.context/`): - Deleting `CodeAgent`/`ProductAgent`/`ProjectAgent`/`QualityAgent` and migrating their hand-rolled step-routing into proper tools - Runtime Agent + dual-tool pattern for framework/agent separation - LLM-fusion composition of multiple sparks - User-authored sparks, hot-reload, SQLDelight persistence - Converting bundled `RoleSpark` to `.spark.md` (deferred until Kaml-in-commonMain) All existing tests pass with `declarativeSparksEnabled = false`. New tests: SparkParserTest, PhaseSparkLibraryTest, AgentLLMServiceActivePromptProviderTest, SparkBasedAgentActivePromptProviderTest, DeclarativeSparkIntegrationTest, and extended PhaseSparkManagerTest cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Concept staleness check — clean. No tracked-source changes need a concept update. |
…epts - 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands the AMPR-161 spike (declarative PhaseSpark authoring) plus foundational scaffolding for the broader unification of all agents under a single spark-driven architecture.
The PR has two layered bodies of work — both safe with the spike flag off (
AmpereSpikeFlags.declarativeSparksEnabled = false):Part 1 — Declarative PhaseSpark (AMPR-161 core)
Markdown-authored sparks reach the LLM payload through
PhaseSparkManagerandAgentLLMService.activePromptProvider:DeclarativePhaseSparkSource/DeclarativePhaseSparktypes +parseSparkparser with typedSparkParseResult { Ok | Failed }andSparkParseErrorsealed errorscooking-domain.spark.md,recipe-arc-task.spark.md,minimal-edge.spark.mdundercomposeResources/files/sparks/PhaseSparkLibrary+DefaultPhaseSparkLibrarywith deterministic phase / tag / keyword selection; KMP-platform fallbacks (JVM/Android classpath, no-op on iOS/JS/wasm)AmpereSpikeFlags.declarativeSparksEnabled: Boolean = falsegates the entire pathAgentLLMService.activePromptProvider: (() -> String?)? = nullevaluated at call time, prepended tosystemMessagewith blank-line separatorPhaseSparkManagerrefactored fromhasActivePhase: BooleantoappliedSparks: MutableList<PhaseSpark>; cleans up in reverse orderSparkAppliedEvent.sparkName == "PhaseSpark:cooking-domain"is emittedPart 2 — Spark composition scaffolding (unification follow-up)
Following design discussion in chat,
Sparkbecomes pure data andSparkStackactually composes (rather than the previous mutually-exclusive "last wins"):Sparkinterface enriched with optional pure-data fields — no behavioral lambdas, so sparks stay shareable as.spark.md:agentRole: String?— fragment of the role label (concatenated across the stack)phaseContributions: Map<CognitivePhase, String>— per-PROPEL-phase markdown sectionsrequestedToolIds: Set<ToolId>— additive tool requests (vs. the existing narrowingallowedTools)SparkStackcomposition:buildSystemPrompt(currentPhase)concatenates every spark'spromptContribution+ relevantphaseContributions[currentPhase]— brute-force composition; 10 sparks all show upeffectiveAgentRole()concatenates with" + "(e.g.,Cooking Domain + Project Manager)effectiveRequestedTools()unionsAutonomousAgent.currentCognitivePhaseis set byPhaseSparkManageron entry / cleared on cleanup;currentSystemPromptincludes the right per-phase guidance for each LLM call## When Perceiving/Planning/Executing/Learningsections → populatesphaseContributions;DeclarativePhaseSparkbecomes one-spark-per-source witheligiblePhases: Set<CognitivePhase>(no more per-phase expansion)ParameterStrategy:Tool.parameterStrategy: ParameterStrategy? = null.ToolExecutionEngineconsults the tool's own strategy first, falls back to externally-registered map for back-compatRoleSpark.{Code,Research,Operations,Planning}enriched withagentRole+requestedToolIdsso they participate in unified compositionProductAgentState→ProductState,ProjectAgentState→ProjectState(consistency withCodeState,QualityState)Deliberately not in this PR (filed as follow-up tickets)
CodeAgent/ProductAgent/ProjectAgent/QualityAgentand route every consumer throughSparkBasedAgent<S>factories — requires migrating ~2,500 LOC of hand-rolled step routing into proper tools (brief in.context/ticket-brief-delete-typed-agents-spark-migration.md).context/ticket-brief-runtime-agent-dual-tool.md)RoleSparkto.spark.md(deferred until Kaml-in-commonMain)Test plan
./gradlew :ampere-core:jvmTest(already passing on this branch)./gradlew :ampere-core:compileCommonMainKotlinMetadata(already passing — per release pre-flight memory)./gradlew ktlintFormat(clean)scripts/demo-declarative-sparks.shto see the spark stack assembly end-to-end (writes report toampere-core/build/declarative-sparks-demo.txt)🤖 Generated with Claude Code