feat(memory): récolte automatique contrôlée de la mémoire (Lot E1)
Câble la récolte automatique de mémoire de bout en bout, sous contrôle explicite, du domaine jusqu'à l'UI : - domain : modèle `memory_harvest` (candidats de récolte, décision) + exports `lib.rs`. - application : use case `memory/harvest` branché dans `memory/mod`, `lib.rs`, le cycle de vie d'agent (`agent/lifecycle`) et l'orchestrateur (`orchestrator/service`). - app-tauri : wiring runtime dans `state`. - frontend : DTO `domain/index` + hook `useMemory`. Couverture : domain `memory_harvest` (14), application `memory_harvest` (5) et `orchestrator_service` (récolte, 4), plus patch test-only du mock gateway `workState` (`mock.test.ts`) et UI `memory.test`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -2624,6 +2624,7 @@ pub(crate) fn compose_convention_file(
|
||||
);
|
||||
}
|
||||
out.push_str(skill_awareness(mcp_enabled));
|
||||
out.push_str(memory_awareness());
|
||||
out.push_str("---\n\n");
|
||||
|
||||
if !project_context.trim().is_empty() {
|
||||
@ -2697,6 +2698,18 @@ fn skill_awareness(mcp_enabled: bool) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
/// The auto-memory harvest directive (Lot E1) injected in the `# Orchestration
|
||||
/// IdeA` block, right after [`skill_awareness`]. Independent of MCP: the agent emits
|
||||
/// the directive in its final reply text either way (IdeA harvests it from the
|
||||
/// recorded `Response`, not via a tool call), so a single wording serves both modes.
|
||||
fn memory_awareness() -> &'static str {
|
||||
"**Mémoire IdeA** : si une décision, convention, préférence utilisateur ou fait projet \
|
||||
durable mérite d'être capitalisé, ajoute à ta réponse finale un bloc fenced `idea-memory` \
|
||||
avec `slug`, `title`, `type`, `description`, puis `---` et le corps Markdown. N'en écris pas \
|
||||
pour les tâches temporaires, logs, tickets, résultats transitoires ou données sensibles ; \
|
||||
réutilise le même `slug` pour remplacer une note existante.\n\n"
|
||||
}
|
||||
|
||||
/// Renders a [`MemoryType`] as its stable lowercase label for the convention-file
|
||||
/// memory section (`user`/`feedback`/`project`/`reference`).
|
||||
#[must_use]
|
||||
@ -2885,6 +2898,35 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compose_convention_file_carries_memory_harvest_directive_both_modes() {
|
||||
// The auto-memory harvest directive (Lot E1) is present in both MCP and
|
||||
// file-protocol modes, positioned right after the Skills awareness and
|
||||
// before the orchestration block's closing separator / project context.
|
||||
for mcp_enabled in [true, false] {
|
||||
let doc =
|
||||
compose_convention_file("/root", "ctx", "# Persona", &[], &[], None, mcp_enabled);
|
||||
assert!(
|
||||
doc.contains("**Mémoire IdeA**"),
|
||||
"memory harvest directive present (mcp_enabled={mcp_enabled})"
|
||||
);
|
||||
assert!(
|
||||
doc.contains("bloc fenced `idea-memory`")
|
||||
&& doc.contains("réutilise le même `slug`"),
|
||||
"directive carries the idea-memory wording (mcp_enabled={mcp_enabled})"
|
||||
);
|
||||
// Position: after Skills awareness, before the project-context section.
|
||||
let skills_at = doc.find("**Skills IdeA**").unwrap();
|
||||
let memory_at = doc.find("**Mémoire IdeA**").unwrap();
|
||||
let context_at = doc.find("# Contexte projet").unwrap();
|
||||
assert!(
|
||||
skills_at < memory_at && memory_at < context_at,
|
||||
"order: skills awareness -> memory directive -> project context \
|
||||
(mcp_enabled={mcp_enabled})"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compose_convention_file_skill_awareness_uses_mcp_or_file_creation_path() {
|
||||
let mcp_doc = compose_convention_file("/root", "", "# Persona", &[], &[], None, true);
|
||||
|
||||
Reference in New Issue
Block a user