spec(prompt): add project map prompt injection change set
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
# Design: Project Map Prompt Injection
|
||||
|
||||
## Status
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Phase | **Design** |
|
||||
| Based on | [Spec](spec.md) |
|
||||
| Next | Tasks |
|
||||
|
||||
## Design summary
|
||||
|
||||
This change adds a runtime guidance layer on top of the paired map/index artifact system. The implementation should not redesign map generation or retrieval. Instead, it should add a well-scoped injection pipeline that:
|
||||
- emits honest startup hints before init,
|
||||
- preloads the root pair after init,
|
||||
- expands under a hybrid budget,
|
||||
- avoids redundant reinjection by scanning real outgoing context,
|
||||
- varies guidance strength through explicit modes,
|
||||
- proves correctness with integration-heavy validation.
|
||||
|
||||
## Affected areas
|
||||
|
||||
### Source files likely to change
|
||||
- `pi-extension.ts`
|
||||
- shared config handling (`src/config.ts` or equivalent)
|
||||
- runtime helpers for map/index discovery and injection selection
|
||||
- tests covering extension lifecycle and per-turn behavior
|
||||
- docs/runtime guidance surfaces if needed
|
||||
|
||||
### New modules likely to appear
|
||||
- `src/prompt-injection.ts` or equivalent runtime helper
|
||||
- optional helper for canonical marker construction / detection
|
||||
- optional helper for token-budget estimation across paired artifacts
|
||||
|
||||
## Architecture changes
|
||||
|
||||
### 1. Injection policy helper
|
||||
Centralize prompt-injection logic in one helper rather than scattering it across hooks.
|
||||
|
||||
Suggested responsibilities:
|
||||
- determine current mode (`off` / `advisory` / `strong` / `strict`),
|
||||
- detect whether artifacts exist,
|
||||
- build pre-init startup hint,
|
||||
- build post-init root-pair payload,
|
||||
- estimate expansion budget,
|
||||
- choose additional artifacts under the budget,
|
||||
- construct a canonical injected marker/block,
|
||||
- scan outgoing context or payload for that marker,
|
||||
- decide whether reinjection is required.
|
||||
|
||||
This helper is the main guard against drift between startup hints, context hooks, and strict-mode checks.
|
||||
|
||||
### 2. Injection surfaces
|
||||
Use different extension surfaces for different responsibilities.
|
||||
|
||||
#### Pre-init / startup hint
|
||||
Use `before_agent_start` for lightweight startup guidance before real artifacts exist.
|
||||
|
||||
Required behavior:
|
||||
- inject only a hint,
|
||||
- tell the agent to run `project_map_init`,
|
||||
- keep the hint visible and inspectable.
|
||||
|
||||
#### Post-init root-pair preload
|
||||
Use `before_agent_start` to guarantee the initial post-init root-pair preload for a prompt.
|
||||
|
||||
Required behavior:
|
||||
- inject root `.pi-map.index.md`,
|
||||
- inject root `.pi-map.md`,
|
||||
- optionally append brief protocol text only if needed by the selected mode.
|
||||
|
||||
#### Relevant-turn reinjection
|
||||
Use `context` for relevant-turn checks.
|
||||
|
||||
Required behavior:
|
||||
- inspect `event.messages`,
|
||||
- decide whether the canonical block is already present,
|
||||
- only add the root pair / budgeted expansion if absent,
|
||||
- avoid rescanning on every trivial turn in `strong` mode.
|
||||
|
||||
#### Payload fallback
|
||||
Use `before_provider_request` only as a fallback or debugging surface when message-layer detection is insufficient.
|
||||
|
||||
### 3. Canonical marker design
|
||||
Deduplication depends on stable canonical detection.
|
||||
|
||||
The implementation should stamp injected content with a canonical marker block.
|
||||
|
||||
Recommended v1 shape:
|
||||
- a deterministic wrapper such as `<!-- PI_MAP_ROOT_PAIR_START -->` / `<!-- PI_MAP_ROOT_PAIR_END -->`,
|
||||
- normalized artifact identity lines for root `.pi-map.index.md` and root `.pi-map.md`,
|
||||
- trust-boundary text within the same wrapped block when the active mode requires it.
|
||||
|
||||
Marker rules:
|
||||
- stable across turns,
|
||||
- independent of provider formatting quirks,
|
||||
- easy to scan in both `event.messages` and final provider payload,
|
||||
- robust enough that root-pair presence can be detected without brittle full-text matching.
|
||||
|
||||
### 4. Budgeting
|
||||
Budgeting should be deterministic and layered.
|
||||
|
||||
#### Context-window discovery and fallback
|
||||
- Prefer active-model context-window metadata exposed by Pi runtime/model selection.
|
||||
- If context-window metadata is unavailable, fall back to the configured absolute cap.
|
||||
- The fallback path should be explicit in logs/debug behavior so budget decisions remain auditable.
|
||||
|
||||
#### Required order
|
||||
1. compute effective budget from relative percentage + optional absolute cap,
|
||||
2. reserve the root pair first,
|
||||
3. expand outward using a deterministic traversal order,
|
||||
4. stop when the budget would be exceeded.
|
||||
|
||||
#### Traversal strategy
|
||||
The spec does not force exact traversal heuristics, but the design should prefer:
|
||||
- root pair first,
|
||||
- shallow structural coverage before deep leaves,
|
||||
- predictable order over opaque scoring.
|
||||
|
||||
This keeps automatic injection understandable and auditable.
|
||||
|
||||
### 5. Mode control surface
|
||||
Expose a config/runtime setting for the four modes.
|
||||
|
||||
Because the current project config is loaded from flat JSON in `.pi-project-map.json`, v1 should prefer a flat compatible shape rather than forcing an immediate nested/YAML migration.
|
||||
|
||||
Suggested v1 config shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"promptInjectionMode": "strong",
|
||||
"contextBudgetPercent": 15,
|
||||
"contextBudgetMaxTokens": 100000
|
||||
}
|
||||
```
|
||||
|
||||
Migration note:
|
||||
- keep existing flat JSON loading in `src/config.ts`,
|
||||
- treat these as new additive keys,
|
||||
- decide explicitly whether existing `contextBudget` is deprecated, ignored for injection, or retained only for older LLM-analysis paths.
|
||||
|
||||
Optional runtime UX may later mirror thinking-level controls, but v1 implementation can start with config-driven mode selection as long as the semantics are the same.
|
||||
|
||||
### 6. Mode semantics
|
||||
#### `off`
|
||||
- no automatic artifact injection,
|
||||
- no startup/init hint beyond existing tool/docs discovery.
|
||||
|
||||
#### `advisory`
|
||||
- startup/init hints enabled,
|
||||
- optional root-pair preload,
|
||||
- light reminders,
|
||||
- weaker reinjection behavior.
|
||||
|
||||
#### `strong`
|
||||
- root-pair preload required,
|
||||
- budgeted expansion required,
|
||||
- relevant-turn reinjection checks required,
|
||||
- reminders before edits and architecture-sensitive reasoning.
|
||||
|
||||
#### `strict`
|
||||
- everything in `strong`, plus:
|
||||
- when protocol path is missing during sensitive actions, require explicit bypass justification.
|
||||
|
||||
### 7. Relevant-turn detection
|
||||
`strong` mode should not rescan on every turn.
|
||||
|
||||
Relevant-turn triggers should be mapped to concrete runtime signals where possible:
|
||||
- agent start,
|
||||
- edit intent / edit tool preparation,
|
||||
- architecture-sensitive planning prompts,
|
||||
- compaction completion,
|
||||
- root-pair artifact change detection.
|
||||
|
||||
This will likely require some combination of:
|
||||
- hook-local heuristics,
|
||||
- observed tool calls,
|
||||
- file timestamp/hash checks for root artifacts,
|
||||
- compaction event handling.
|
||||
|
||||
### 8. Visibility model
|
||||
The design should preserve mixed visibility.
|
||||
|
||||
- startup hints: visible and inspectable,
|
||||
- raw injected artifact blocks: agent-visible by default,
|
||||
- the fact that automatic injection exists should remain discoverable.
|
||||
|
||||
The implementation may use hidden custom message types for artifact payloads, but should not make startup/init behavior opaque.
|
||||
|
||||
### 9. Validation strategy
|
||||
This change is validation-heavy.
|
||||
|
||||
Unit tests alone are not enough, because the main risk is runtime interaction between hooks, message mutation, compaction, and reinjection.
|
||||
|
||||
#### Integration focus areas
|
||||
- startup before init,
|
||||
- startup after init,
|
||||
- root-pair marker insertion,
|
||||
- reinjection suppression when marker already exists,
|
||||
- reinjection after compaction,
|
||||
- reinjection after artifact mutation,
|
||||
- mode differences,
|
||||
- strict-mode bypass path,
|
||||
- mixed visibility expectations,
|
||||
- synthetic event-sequence coverage for relevant-turn heuristics such as edit-intent, architecture-sensitive reasoning, compaction, and artifact invalidation.
|
||||
|
||||
### 10. Documentation impact
|
||||
Runtime guidance docs must align with the spec, but retrieval docs remain separate.
|
||||
|
||||
Docs should teach:
|
||||
- startup hint before init,
|
||||
- root-pair automatic preload after init,
|
||||
- trust boundary,
|
||||
- mode ladder,
|
||||
- relevant-turn reinjection behavior,
|
||||
- integration-test importance.
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Message-level scanning misses provider serialization quirks | Add payload fallback via `before_provider_request` |
|
||||
| Root-pair marker becomes brittle | Use deterministic boundaries and normalized artifact identity lines |
|
||||
| 15% + 100k is too aggressive in some fleets | Keep both knobs configurable and document the opinionated default |
|
||||
| Relevant-turn detection becomes fuzzy | Centralize detection heuristics and prove them with integration tests |
|
||||
| `strict` mode causes friction | Keep `strong` as default and isolate strict-only bypass behavior |
|
||||
|
||||
## Settled defaults
|
||||
|
||||
- Root pair is always guaranteed after init.
|
||||
- Reinjection avoidance is based on canonical outgoing-context scanning.
|
||||
- Retrieval remains out of scope.
|
||||
- Mixed visibility is the intended baseline.
|
||||
- Four modes exist, with `strong` as default.
|
||||
- Default budget is 15% of active context window, capped at 100k tokens.
|
||||
Reference in New Issue
Block a user