feat(memory): scope coding + tools record_lesson/get_context_pack + branchement git_sync
This commit is contained in:
+60
-1
@@ -8,7 +8,8 @@ from mcp.server.sse import SseServerTransport
|
||||
from mcp.types import Tool, TextContent
|
||||
from app.auth import get_current_agent
|
||||
from app.scopes import has_scope_access, ALL_SCOPES
|
||||
from app.models import get_rule, get_all_rules, get_all_ports, get_port, set_rule, get_agent_by_key, update_key_last_used
|
||||
from app.models import (get_rule, get_all_rules, get_all_ports, get_port, set_rule, get_agent_by_key, update_key_last_used, add_memory_entry, list_memory_entries)
|
||||
from app.git_sync import push_scope_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -89,6 +90,38 @@ async def handle_list_tools() -> list[Tool]:
|
||||
},
|
||||
"required": ["scope", "agent", "data"]
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
name="record_lesson",
|
||||
description=("Record a typed, durable memory entry (decision/constraint/best-practice/"
|
||||
"common-error/do-not-use) in the coding scope. Call after a meaningful "
|
||||
"decision, a repeated correction, or a rejected approach worth remembering."),
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scope": {"type": "string", "description": "Scope, actuellement: coding"},
|
||||
"project": {"type": "string", "description": "Nom du repo/projet, omettre si transverse"},
|
||||
"type": {"type": "string", "enum": ["decision", "constraint", "best-practice", "common-error", "do-not-use"]},
|
||||
"title": {"type": "string", "description": "Resume court, 1 ligne"},
|
||||
"body": {"type": "string", "description": "1-3 phrases"},
|
||||
"tags": {"type": "array", "items": {"type": "string"}}
|
||||
},
|
||||
"required": ["scope", "type", "title", "body"]
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
name="get_context_pack",
|
||||
description=("Load only the memory entries relevant to the current task (selective "
|
||||
"loading, not the whole scope) — call before substantial coding work."),
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scope": {"type": "string", "description": "Scope, actuellement: coding"},
|
||||
"project": {"type": "string", "description": "Filtrer par projet ; omettre pour les entrees transverses"},
|
||||
"type": {"type": "string", "enum": ["decision", "constraint", "best-practice", "common-error", "do-not-use"]}
|
||||
},
|
||||
"required": ["scope"]
|
||||
}
|
||||
)
|
||||
]
|
||||
|
||||
@@ -162,6 +195,32 @@ async def handle_call_tool(name: str, arguments: dict) -> list[TextContent]:
|
||||
await set_rule(scope, existing)
|
||||
return [TextContent(type="text", text=json.dumps({"status": "ok", "scope": scope, "updated_keys": list(data.keys())}))]
|
||||
|
||||
elif name == "record_lesson":
|
||||
scope = arguments.get("scope")
|
||||
if not has_scope_access(caller_agent, scope):
|
||||
return [TextContent(type="text", text=json.dumps({"error": f"Agent {caller_agent} forbidden on scope {scope}"}))]
|
||||
type_ = arguments.get("type")
|
||||
title = arguments.get("title")
|
||||
body = arguments.get("body")
|
||||
if not (type_ and title and body):
|
||||
return [TextContent(type="text", text=json.dumps({"error": "type, title et body sont requis"}))]
|
||||
entry = await add_memory_entry(
|
||||
scope=scope, type_=type_, title=title, body=body, created_by=caller_agent,
|
||||
project=arguments.get("project"), tags=arguments.get("tags")
|
||||
)
|
||||
git_result = await push_scope_markdown(scope)
|
||||
entry["_git"] = git_result
|
||||
return [TextContent(type="text", text=json.dumps(entry))]
|
||||
|
||||
elif name == "get_context_pack":
|
||||
scope = arguments.get("scope")
|
||||
if not has_scope_access(caller_agent, scope):
|
||||
return [TextContent(type="text", text=json.dumps({"error": f"Agent {caller_agent} forbidden on scope {scope}"}))]
|
||||
entries = await list_memory_entries(
|
||||
scope=scope, project=arguments.get("project"), type_=arguments.get("type"), status="active"
|
||||
)
|
||||
return [TextContent(type="text", text=json.dumps(entries))]
|
||||
|
||||
return [TextContent(type="text", text=json.dumps({"error": "Unknown tool"}))]
|
||||
|
||||
# FastMCP / SSE Integration
|
||||
|
||||
Reference in New Issue
Block a user