feat(soul): add sessions layer, MCP connectors, conversation continuity fix
- sessions.el: new sessions module with session management and approval gate
- routes.el: wire /api/sessions routes (list, get, create, approve, tool_result)
- chat.el: thread-aware activation — short messages anchor to last reply
before engram compilation so follow-ups stay on-topic
- chat.el: agentic path tracks per-session history (session_hist_{id})
instead of shared conv_history, seeding each turn with prior context
- chat.el: add call_neuron_mcp, dispatch_tool, is_builtin_tool, next_bridge_id
agentic_loop, bridge_save, agentic_resume, handle_tool_result
- dist/soul: rebuild with all of the above
This commit is contained in:
@@ -4,6 +4,7 @@ import "chat.el"
|
||||
import "studio.el"
|
||||
import "elp-input.el"
|
||||
import "neuron-api.el"
|
||||
import "sessions.el"
|
||||
import "soul.elh"
|
||||
|
||||
fn strip_query(path: String) -> String {
|
||||
@@ -376,10 +377,27 @@ fn handle_request(method: String, path: String, body: String) -> String {
|
||||
if str_starts_with(clean, "/api/connectors") {
|
||||
return handle_connectors(method, clean, body)
|
||||
}
|
||||
// GET /api/sessions — list all sessions
|
||||
if str_eq(clean, "/api/sessions") {
|
||||
return session_list()
|
||||
}
|
||||
// GET /api/sessions/:id — get session metadata + history
|
||||
if str_starts_with(clean, "/api/sessions/") {
|
||||
let gs_after: String = str_slice(clean, 14, str_len(clean))
|
||||
let gs_slash: Int = str_index_of(gs_after, "/")
|
||||
let gs_id: String = if gs_slash < 0 { gs_after } else { str_slice(gs_after, 0, gs_slash) }
|
||||
if !str_eq(gs_id, "") {
|
||||
return session_get(gs_id)
|
||||
}
|
||||
}
|
||||
return err_404(clean)
|
||||
}
|
||||
|
||||
if str_eq(method, "POST") {
|
||||
// POST /api/sessions — create new session
|
||||
if str_eq(clean, "/api/sessions") {
|
||||
return session_create(body)
|
||||
}
|
||||
// MCP tool-bridge resume: POST /api/sessions/{id}/tool_result
|
||||
// The client executed a tool the soul could not run in-process (an MCP
|
||||
// connector/plugin) and posts the result back here so the agentic loop
|
||||
@@ -390,6 +408,16 @@ fn handle_request(method: String, path: String, body: String) -> String {
|
||||
let session_id: String = if slash < 0 { after } else { str_slice(after, 0, slash) }
|
||||
return handle_tool_result(session_id, body)
|
||||
}
|
||||
// POST /api/sessions/:id/approve — user approval for a pending agentic tool call
|
||||
if str_starts_with(clean, "/api/sessions/") {
|
||||
let sess_after: String = str_slice(clean, 14, str_len(clean))
|
||||
let sess_slash: Int = str_index_of(sess_after, "/")
|
||||
let sess_id: String = if sess_slash < 0 { sess_after } else { str_slice(sess_after, 0, sess_slash) }
|
||||
let sess_sub: String = if sess_slash < 0 { "" } else { str_slice(sess_after, sess_slash + 1, str_len(sess_after)) }
|
||||
if !str_eq(sess_id, "") && str_eq(sess_sub, "approve") {
|
||||
return handle_session_approve(sess_id, body)
|
||||
}
|
||||
}
|
||||
if str_eq(clean, "/imprint/contextual") {
|
||||
return route_imprint_contextual(body)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user