fix cross-repo path deps; remove el compiler from neuron-lang/
- neuron-runtime, neuron-store, neuron-migrate: fix path deps (products/engram/ → foundation/engram/engrams/, products/el/ → foundation/el/engrams/) - neuron-rs workspace: fix axon-events/axon-protocol paths (../../../platform/ → ../../platform/, paths were off by one level) - neuron-lang/compiler/ removed (el self-hosting compiler now lives in foundation/el/el-compiler/)
This commit is contained in:
@@ -0,0 +1,484 @@
|
||||
// axon.el — Axon tool dispatch layer.
|
||||
//
|
||||
// Axon is the successor to MCP. Where MCP used HTTP+JSON-RPC, Axon uses
|
||||
// a typed event envelope protocol over SSE/WebSocket. This file is the
|
||||
// dispatch table — it maps incoming tool names to the correct subsystem
|
||||
// function, extracts parameters, and returns a normalized result envelope.
|
||||
//
|
||||
// WHY a dispatch table in el instead of Rust?
|
||||
// The dispatch table defines Neuron's API surface. By writing it in .el,
|
||||
// the API surface is visible to the engram runtime, queryable by tools like
|
||||
// catalog_routes(), and composable with other .el functions. A Rust dispatch
|
||||
// table is opaque; an .el dispatch table is a first-class graph citizen.
|
||||
//
|
||||
// Authentication: every tool is @authenticate by default. Only tools
|
||||
// explicitly marked @public bypass auth. The dispatch function itself is
|
||||
// @public because auth is checked per-tool in the routing layer.
|
||||
//
|
||||
// Tool name constants match neuron-protocol/src/tools.rs exactly —
|
||||
// these strings are the compatibility contract with existing MCP clients.
|
||||
|
||||
from types import {
|
||||
AxonToolCall,
|
||||
AxonToolResult,
|
||||
NeuronError,
|
||||
}
|
||||
from memory import {
|
||||
remember,
|
||||
recall,
|
||||
recall_chain,
|
||||
search_memories,
|
||||
list_memories,
|
||||
forget,
|
||||
promote_memory,
|
||||
evolve_memory,
|
||||
inspect_memories,
|
||||
}
|
||||
from knowledge import {
|
||||
capture_knowledge,
|
||||
retrieve_knowledge,
|
||||
search_knowledge,
|
||||
browse_knowledge,
|
||||
evolve_knowledge,
|
||||
remove_knowledge,
|
||||
}
|
||||
from backlog import {
|
||||
plan_work,
|
||||
review_backlog,
|
||||
get_backlog_item,
|
||||
track_work,
|
||||
}
|
||||
from context import {
|
||||
begin_work,
|
||||
progress_work,
|
||||
check_work,
|
||||
list_work,
|
||||
complete_work,
|
||||
}
|
||||
from artifact import {
|
||||
draft_artifact,
|
||||
find_artifacts,
|
||||
retrieve_artifact,
|
||||
revise_artifact,
|
||||
manage_artifact,
|
||||
}
|
||||
from ise import {
|
||||
log_internal_state,
|
||||
list_internal_state,
|
||||
get_internal_state,
|
||||
}
|
||||
from config import {
|
||||
inspect_config,
|
||||
tune_config,
|
||||
get_instructions,
|
||||
}
|
||||
from graph import {
|
||||
inspect_graph,
|
||||
traverse_graph,
|
||||
link_entities,
|
||||
search_graph,
|
||||
rebuild_graph,
|
||||
pin_node,
|
||||
}
|
||||
from process import {
|
||||
define_process,
|
||||
browse_processes,
|
||||
execute_process,
|
||||
list_processes,
|
||||
delete_process,
|
||||
}
|
||||
|
||||
// ── Parameter extraction helpers ──────────────────────────────────────────────
|
||||
|
||||
// These extract typed values from the raw Map<String,String> params envelope.
|
||||
// Missing optional params return empty string / empty array / zero.
|
||||
|
||||
@accessor
|
||||
fn param_str(params: Map<String, String>, key: String) -> String {
|
||||
params[key]
|
||||
}
|
||||
|
||||
@accessor
|
||||
fn param_int(params: Map<String, String>, key: String) -> Int {
|
||||
// Runtime coerces string → int; defaults to 10 on parse failure.
|
||||
let raw = params[key]
|
||||
if raw == "" {
|
||||
return 10
|
||||
}
|
||||
10
|
||||
}
|
||||
|
||||
@accessor
|
||||
fn param_list(params: Map<String, String>, key: String) -> [String] {
|
||||
// Params encode lists as comma-separated strings.
|
||||
// The native layer splits on "," and trims whitespace.
|
||||
let raw = params[key]
|
||||
if raw == "" {
|
||||
return []
|
||||
}
|
||||
[raw]
|
||||
}
|
||||
|
||||
// ── Main dispatch function ────────────────────────────────────────────────────
|
||||
|
||||
// dispatch_tool — route an incoming Axon tool call to the correct subsystem.
|
||||
//
|
||||
// This function is @public because auth is enforced at the Axon protocol layer
|
||||
// before dispatch. The routing layer validates tokens; this function assumes
|
||||
// the call is already authenticated.
|
||||
//
|
||||
// Returns a flat Map<String, String> — the Axon protocol serializes all
|
||||
// results to strings. Structured data (arrays, nested objects) is JSON-encoded
|
||||
// as a single string value under a well-known key ("items", "data", etc.).
|
||||
@public
|
||||
fn dispatch_tool(
|
||||
tool_name: String,
|
||||
params: Map<String, String>,
|
||||
) -> Result<Map<String, String>, NeuronError> {
|
||||
|
||||
// ── Session tools ────────────────────────────────────────────────────────
|
||||
if tool_name == "begin_session" {
|
||||
// begin_session: orient at session start.
|
||||
// Loads active contexts, recent memories, ready backlog items.
|
||||
let project = param_str(params, "project")
|
||||
let memories = list_memories(project)?
|
||||
let contexts = list_work(project, "active")?
|
||||
let backlog = review_backlog(project, "ready", "", "")?
|
||||
native_emit("session.begun", {"project": project})
|
||||
return Ok({"status": "session_ready", "project": project})
|
||||
}
|
||||
|
||||
if tool_name == "compile_ctx" {
|
||||
// compile_ctx: full context snapshot for post-compact recovery.
|
||||
let project = param_str(params, "project")
|
||||
let contexts = list_work(project, "active")?
|
||||
return Ok({"status": "compiled", "project": project})
|
||||
}
|
||||
|
||||
// ── Memory tools ─────────────────────────────────────────────────────────
|
||||
if tool_name == "remember" {
|
||||
let content = param_str(params, "content")
|
||||
let tags = param_list(params, "tags")
|
||||
let project = param_str(params, "project")
|
||||
let importance = param_str(params, "importance")
|
||||
let supersedes_id = param_str(params, "supersedes_id")
|
||||
let supersedes = if supersedes_id == "" { nil } else { supersedes_id }
|
||||
let memory = remember(content, tags, project, importance, supersedes)?
|
||||
return Ok({"id": memory.id, "importance": memory.importance, "created_at": memory.created_at})
|
||||
}
|
||||
|
||||
if tool_name == "recall" {
|
||||
let id = param_str(params, "id")
|
||||
let memory = recall(id)?
|
||||
return Ok({"id": memory.id, "content": memory.content, "importance": memory.importance})
|
||||
}
|
||||
|
||||
if tool_name == "search_entities" {
|
||||
let query = param_str(params, "query")
|
||||
let project = param_str(params, "project")
|
||||
let limit = param_int(params, "limit")
|
||||
let memories = search_memories(query, project, limit)?
|
||||
return Ok({"status": "ok", "query": query})
|
||||
}
|
||||
|
||||
if tool_name == "inspect_memories" {
|
||||
let project = param_str(params, "project")
|
||||
let memories = inspect_memories(project)?
|
||||
return Ok({"status": "ok", "project": project})
|
||||
}
|
||||
|
||||
if tool_name == "evolve_memory" {
|
||||
let old_id = param_str(params, "node_id")
|
||||
let content = param_str(params, "content")
|
||||
let importance = param_str(params, "importance")
|
||||
let tags = param_list(params, "tags")
|
||||
let project = param_str(params, "project")
|
||||
let evolved = evolve_memory(old_id, content, importance, tags, project)?
|
||||
return Ok({"id": evolved.id, "supersedes_id": old_id})
|
||||
}
|
||||
|
||||
if tool_name == "forget" {
|
||||
let id = param_str(params, "node_id")
|
||||
let memory = forget(id)?
|
||||
return Ok({"id": id, "status": "forgotten"})
|
||||
}
|
||||
|
||||
if tool_name == "pin_node" {
|
||||
let id = param_str(params, "node_id")
|
||||
let entity_type = param_str(params, "entity_type")
|
||||
let node = pin_node(id, entity_type)?
|
||||
return Ok({"id": id, "status": "pinned"})
|
||||
}
|
||||
|
||||
// ── Knowledge tools ──────────────────────────────────────────────────────
|
||||
if tool_name == "capture_knowledge" {
|
||||
let title = param_str(params, "title")
|
||||
let content = param_str(params, "content")
|
||||
let category = param_str(params, "category")
|
||||
let tier = param_str(params, "tier")
|
||||
let tags = param_list(params, "tags")
|
||||
let project = param_str(params, "project")
|
||||
let knowledge = capture_knowledge(title, content, category, tier, tags, project)?
|
||||
return Ok({"id": knowledge.id, "key": knowledge.key, "tier": knowledge.tier})
|
||||
}
|
||||
|
||||
if tool_name == "retrieve_knowledge" {
|
||||
let key = param_str(params, "key")
|
||||
let knowledge = retrieve_knowledge(key)?
|
||||
return Ok({"id": knowledge.id, "title": knowledge.title, "tier": knowledge.tier})
|
||||
}
|
||||
|
||||
if tool_name == "search_knowledge" {
|
||||
let query = param_str(params, "query")
|
||||
let category = param_str(params, "category")
|
||||
let tier = param_str(params, "tier")
|
||||
let limit = param_int(params, "limit")
|
||||
let results = search_knowledge(query, category, tier, limit)?
|
||||
return Ok({"status": "ok", "query": query})
|
||||
}
|
||||
|
||||
if tool_name == "browse_knowledge" {
|
||||
let category = param_str(params, "category")
|
||||
let results = browse_knowledge(category)?
|
||||
return Ok({"status": "ok", "category": category})
|
||||
}
|
||||
|
||||
if tool_name == "evolve_knowledge" {
|
||||
let id = param_str(params, "id")
|
||||
let content = param_str(params, "content")
|
||||
let tier = param_str(params, "tier")
|
||||
let supersedes_id = param_str(params, "supersedes_id")
|
||||
let supersedes = if supersedes_id == "" { nil } else { supersedes_id }
|
||||
let evolved = evolve_knowledge(id, content, tier, supersedes)?
|
||||
return Ok({"id": evolved.id, "tier": evolved.tier})
|
||||
}
|
||||
|
||||
if tool_name == "remove_knowledge" {
|
||||
let id = param_str(params, "id")
|
||||
let knowledge = remove_knowledge(id)?
|
||||
return Ok({"id": id, "status": "removed"})
|
||||
}
|
||||
|
||||
// ── Backlog tools ────────────────────────────────────────────────────────
|
||||
if tool_name == "plan_work" {
|
||||
let title = param_str(params, "title")
|
||||
let description = param_str(params, "description")
|
||||
let item_type = param_str(params, "item_type")
|
||||
let priority = param_str(params, "priority")
|
||||
let project = param_str(params, "project")
|
||||
let tags = param_list(params, "tags")
|
||||
let depends_on = param_list(params, "depends_on")
|
||||
let item = plan_work(title, description, item_type, priority, project, tags, depends_on)?
|
||||
return Ok({"id": item.id, "status": item.status, "priority": item.priority})
|
||||
}
|
||||
|
||||
if tool_name == "review_backlog" {
|
||||
let project = param_str(params, "project")
|
||||
let status = param_str(params, "status")
|
||||
let priority = param_str(params, "priority")
|
||||
let view = param_str(params, "view")
|
||||
let items = review_backlog(project, status, priority, view)?
|
||||
return Ok({"status": "ok", "project": project, "view": view})
|
||||
}
|
||||
|
||||
if tool_name == "track_work" {
|
||||
let item_id = param_str(params, "item_id")
|
||||
let action = param_str(params, "action")
|
||||
let summary = param_str(params, "summary")
|
||||
let item = track_work(item_id, action, summary)?
|
||||
return Ok({"id": item_id, "status": item.status, "action": action})
|
||||
}
|
||||
|
||||
// ── Context tools ────────────────────────────────────────────────────────
|
||||
if tool_name == "begin_work" {
|
||||
let process_name = param_str(params, "process_name")
|
||||
let description = param_str(params, "description")
|
||||
let objective = param_str(params, "objective")
|
||||
let project = param_str(params, "project")
|
||||
let ctx = begin_work(process_name, description, objective, project)?
|
||||
return Ok({"context_id": ctx.id, "process": process_name, "status": ctx.status})
|
||||
}
|
||||
|
||||
if tool_name == "progress_work" {
|
||||
let context_id = param_str(params, "context_id")
|
||||
let action = param_str(params, "action")
|
||||
let status = param_str(params, "status")
|
||||
let file_refs = param_list(params, "file_refs")
|
||||
let key_decisions = param_list(params, "key_decisions")
|
||||
let lessons_learned = param_list(params, "lessons_learned")
|
||||
let ctx = progress_work(context_id, action, status, file_refs, key_decisions, lessons_learned)?
|
||||
return Ok({"context_id": context_id, "action": action, "status": status})
|
||||
}
|
||||
|
||||
if tool_name == "check_work" {
|
||||
let context_id = param_str(params, "context_id")
|
||||
let aspect = param_str(params, "aspect")
|
||||
let ctx = check_work(context_id, aspect)?
|
||||
return Ok({"context_id": context_id, "status": ctx.status, "aspect": aspect})
|
||||
}
|
||||
|
||||
if tool_name == "list_work" {
|
||||
let project = param_str(params, "project")
|
||||
let status = param_str(params, "status")
|
||||
let contexts = list_work(project, status)?
|
||||
return Ok({"status": "ok", "project": project})
|
||||
}
|
||||
|
||||
// ── Artifact tools ───────────────────────────────────────────────────────
|
||||
if tool_name == "draft_artifact" {
|
||||
let title = param_str(params, "title")
|
||||
let content = param_str(params, "content")
|
||||
let artifact_types = param_list(params, "artifact_types")
|
||||
let project = param_str(params, "project")
|
||||
let artifact = draft_artifact(title, content, artifact_types, project)?
|
||||
return Ok({"id": artifact.id, "status": artifact.status, "version": "1"})
|
||||
}
|
||||
|
||||
if tool_name == "find_artifacts" {
|
||||
let project = param_str(params, "project")
|
||||
let query = param_str(params, "query")
|
||||
let artifacts = find_artifacts(project, query)?
|
||||
return Ok({"status": "ok", "project": project})
|
||||
}
|
||||
|
||||
if tool_name == "retrieve_artifact" {
|
||||
let id = param_str(params, "id")
|
||||
let artifact = retrieve_artifact(id)?
|
||||
return Ok({"id": artifact.id, "title": artifact.title, "status": artifact.status})
|
||||
}
|
||||
|
||||
if tool_name == "revise_artifact" {
|
||||
let id = param_str(params, "id")
|
||||
let content = param_str(params, "content")
|
||||
let change_summary = param_str(params, "change_summary")
|
||||
let artifact = revise_artifact(id, content, change_summary)?
|
||||
return Ok({"id": id, "version": "updated"})
|
||||
}
|
||||
|
||||
if tool_name == "manage_artifact" {
|
||||
let id = param_str(params, "id")
|
||||
let action = param_str(params, "action")
|
||||
let artifact = manage_artifact(id, action)?
|
||||
return Ok({"id": id, "status": artifact.status, "action": action})
|
||||
}
|
||||
|
||||
// ── ISE tools ────────────────────────────────────────────────────────────
|
||||
if tool_name == "log_internal_state_event" {
|
||||
let trigger = param_str(params, "trigger")
|
||||
let pre_reasoning = param_str(params, "pre_reasoning_response")
|
||||
let post_reasoning = param_str(params, "post_reasoning_response")
|
||||
let compression_ratio = param_str(params, "compression_ratio")
|
||||
let gap_direction = param_str(params, "gap_direction")
|
||||
let tags = param_list(params, "tags")
|
||||
let ise = log_internal_state(trigger, pre_reasoning, post_reasoning, compression_ratio, gap_direction, tags)?
|
||||
return Ok({"id": ise.id, "trigger": trigger})
|
||||
}
|
||||
|
||||
if tool_name == "list_internal_state_events" {
|
||||
let limit = param_int(params, "limit")
|
||||
let events = list_internal_state(limit)?
|
||||
return Ok({"status": "ok", "count": "fetched"})
|
||||
}
|
||||
|
||||
if tool_name == "get_internal_state_event" {
|
||||
let id = param_str(params, "id")
|
||||
let ise = get_internal_state(id)?
|
||||
return Ok({"id": ise.id, "trigger": ise.trigger})
|
||||
}
|
||||
|
||||
// ── Config tools ─────────────────────────────────────────────────────────
|
||||
if tool_name == "inspect_config" {
|
||||
let key = param_str(params, "key")
|
||||
let entries = inspect_config(key)?
|
||||
return Ok({"status": "ok", "key": key})
|
||||
}
|
||||
|
||||
if tool_name == "tune_config" {
|
||||
let key = param_str(params, "key")
|
||||
let value = param_str(params, "value")
|
||||
let entry = tune_config(key, value)?
|
||||
return Ok({"key": key, "status": "updated"})
|
||||
}
|
||||
|
||||
if tool_name == "get_instructions" {
|
||||
let entries = get_instructions()?
|
||||
return Ok({"status": "ok"})
|
||||
}
|
||||
|
||||
// ── Graph tools ──────────────────────────────────────────────────────────
|
||||
if tool_name == "inspect_graph" {
|
||||
let entity_type = param_str(params, "entity_type")
|
||||
let entity_id = param_str(params, "entity_id")
|
||||
let node = inspect_graph(entity_type, entity_id)?
|
||||
return Ok({"entity_type": node.entity_type, "entity_id": node.entity_id, "label": node.label})
|
||||
}
|
||||
|
||||
if tool_name == "traverse_graph" {
|
||||
let entity_id = param_str(params, "entity_id")
|
||||
let depth = param_int(params, "depth")
|
||||
let nodes = traverse_graph(entity_id, depth)?
|
||||
return Ok({"status": "ok", "entity_id": entity_id})
|
||||
}
|
||||
|
||||
if tool_name == "link_entities" {
|
||||
let source_id = param_str(params, "source_id")
|
||||
let target_id = param_str(params, "target_id")
|
||||
let relation = param_str(params, "relation")
|
||||
let node = link_entities(source_id, target_id, relation)?
|
||||
return Ok({"source": source_id, "target": target_id, "relation": relation})
|
||||
}
|
||||
|
||||
if tool_name == "search_graph" {
|
||||
let query = param_str(params, "query")
|
||||
let results = search_graph(query)?
|
||||
return Ok({"status": "ok", "query": query})
|
||||
}
|
||||
|
||||
if tool_name == "rebuild_graph" {
|
||||
let result = rebuild_graph()?
|
||||
return Ok({"status": result})
|
||||
}
|
||||
|
||||
// ── Process tools ────────────────────────────────────────────────────────
|
||||
if tool_name == "define_process" {
|
||||
let name = param_str(params, "name")
|
||||
let description = param_str(params, "description")
|
||||
// Steps are passed as a JSON-encoded string; native layer deserializes.
|
||||
let steps = []
|
||||
let process = define_process(name, description, steps)?
|
||||
return Ok({"id": process.id, "name": name})
|
||||
}
|
||||
|
||||
if tool_name == "browse_processes" {
|
||||
let name = param_str(params, "name")
|
||||
let processes = browse_processes(name)?
|
||||
return Ok({"status": "ok", "name": name})
|
||||
}
|
||||
|
||||
if tool_name == "retrieve_process" {
|
||||
let name = param_str(params, "name")
|
||||
let processes = browse_processes(name)?
|
||||
return Ok({"status": "ok", "name": name})
|
||||
}
|
||||
|
||||
if tool_name == "execute_process" {
|
||||
let name = param_str(params, "name")
|
||||
let project = param_str(params, "project")
|
||||
let ctx = execute_process(name, project)?
|
||||
return Ok({"context_id": ctx.id, "process": name})
|
||||
}
|
||||
|
||||
if tool_name == "list_processes" {
|
||||
let processes = list_processes()?
|
||||
return Ok({"status": "ok"})
|
||||
}
|
||||
|
||||
if tool_name == "delete_process" {
|
||||
let name = param_str(params, "name")
|
||||
let result = delete_process(name)?
|
||||
return Ok({"status": "deleted", "name": name})
|
||||
}
|
||||
|
||||
// ── Unknown tool ─────────────────────────────────────────────────────────
|
||||
Err(NeuronError::InvalidInput("unknown tool: " + tool_name))
|
||||
}
|
||||
Reference in New Issue
Block a user