Files
Maven/internal/ipc/wire.go
T
kami 2bf11f052d Merge branch 'fix/g07' into fix/integrated
# Conflicts:
#	internal/ipc/api.go
#	internal/ipc/client.go
#	internal/llm/client.go
2026-08-01 14:36:48 +04:00

173 lines
6.9 KiB
Go

package ipc
import (
"encoding/json"
"errors"
"fmt"
)
// Method — one RPC verb. The set is intentionally small: it mirrors exactly
// what a module legitimately needs from core state, and nothing more. Adding
// a method is a core-authority change (every method is a new thing a module
// can ask for); do it deliberately.
type Method string
const (
MethodWriteFact Method = "write_fact"
MethodLatestFact Method = "latest_fact"
MethodLatestFactBySource Method = "latest_fact_by_source"
MethodSince Method = "since"
MethodPresence Method = "presence"
MethodCreateReminder Method = "create_reminder"
MethodMarkReminder Method = "mark_reminder"
MethodListReminders Method = "list_reminders"
MethodRecordNudge Method = "record_nudge"
MethodResolveNudge Method = "resolve_nudge"
MethodRecentOutcomes Method = "recent_outcomes"
MethodRecentFacts Method = "recent_facts"
MethodRecentActiveFacts Method = "recent_active_facts_by_kind"
MethodCalendarEvents Method = "calendar_events"
MethodRecentNudges Method = "recent_nudges"
MethodRecentEcoTraces Method = "recent_ecosystem_traces"
MethodWriteNote Method = "write_note"
MethodQueryNotes Method = "query_notes"
MethodRecentNotes Method = "recent_notes"
MethodRecentNotesFromSource Method = "recent_notes_source"
MethodProposeTool Method = "propose_tool"
MethodEnableTool Method = "enable_tool"
MethodDisableTool Method = "disable_tool"
MethodAssertStepUp Method = "assert_stepup"
MethodStoreEncryptionKey Method = "store_encryption_key"
MethodUnlock Method = "unlock"
MethodLookupTool Method = "lookup_tool"
MethodListTools Method = "list_tools"
MethodDeleteTool Method = "delete_tool"
MethodListProposedRoutines Method = "list_proposed_routines"
MethodDismissProposedRoutine Method = "dismiss_proposed_routine"
MethodAcceptProposedRoutine Method = "accept_proposed_routine"
MethodRevertFact Method = "revert_fact"
MethodTickTrace Method = "tick_trace"
MethodMorningStatus Method = "morning_status"
MethodMCPServers Method = "mcp_servers"
MethodDayPlan Method = "day_plan"
MethodChat Method = "chat"
MethodCaptureTask Method = "capture_task"
MethodListTasks Method = "list_tasks"
MethodSetTaskStatus Method = "set_task_status"
MethodIngestMail Method = "ingest_mail"
MethodSwapModel Method = "swap_model"
MethodModelStatus Method = "model_status"
MethodDescribeImage Method = "describe_image"
MethodCaptureStart Method = "capture_start"
MethodCaptureAppend Method = "capture_append"
MethodCaptureStop Method = "capture_stop"
MethodCaptureStatus Method = "capture_status"
MethodEnrollSpeaker Method = "enroll_speaker"
MethodListSpeakers Method = "list_speakers"
MethodForgetSpeaker Method = "forget_speaker"
MethodRecentEvents Method = "recent_events"
// MethodPing — liveness, and the only method that answers in locked mode
// without a passkey assertion. It reaches no store, takes no arguments and
// returns whether the daemon is locked, so an operator tool can tell "she is
// up and waiting for a passkey" apart from "she is not there at all".
// Everything else about her state needs the store, and the store needs the
// key.
MethodPing Method = "ping"
)
// Request — one frame from module to core. Params is the JSON-encoded argument
// struct for Method (see api.go for the per-method shapes). The server
// unmarshals Params based on Method; an unknown Method ⇒ ErrUnknownMethod.
type Request struct {
Method Method `json:"m"`
Params json.RawMessage `json:"p,omitempty"`
}
// Response — one frame from core back to module. Exactly one of Result/Error
// is set. Result is the JSON-encoded return value of the method (might be a
// scalar, a struct, or null for void methods).
type Response struct {
Result json.RawMessage `json:"r,omitempty"`
Error *RpcError `json:"e,omitempty"`
}
// RpcError — a typed wire error. Code is one of the sentinel codes below;
// the client rehydrates it into the matching package sentinel so callers can
// use errors.Is like they would in-process (core's contract is the same on
// both sides of the wire — the boundary shouldn't change error semantics).
type RpcError struct {
Code string `json:"c"`
Message string `json:"m,omitempty"`
}
func (e *RpcError) Error() string {
if e.Message != "" {
return fmt.Sprintf("ipc: %s: %s", e.Code, e.Message)
}
return fmt.Sprintf("ipc: %s", e.Code)
}
// Sentinel codes. Stable over the wire — do not rename. Mirror the package
// sentinels in api.go 1:1. The string is the contract.
const (
codeNoFact = "no_fact"
codeConfidence = "confidence"
codeVoidsMissing = "voids_missing"
codeNudgeNotFound = "nudge_not_found"
codeNudgeOutcome = "nudge_outcome"
codeReminderMissing = "reminder_not_found"
codeReminderState = "reminder_state"
codeToolNotFound = "tool_not_found"
codeUnknownMethod = "unknown_method"
codeBadParams = "bad_params"
codeForbidden = "forbidden"
codeInternal = "internal"
)
// codeOf maps a server-side sentinel to its wire code. Anything not matched
// is codeInternal — we never leak internal Go error text to a module; it
// gets a generic "internal" and the daemon logs the real error server-side.
func codeOf(err error) string {
switch {
case err == nil:
return ""
case errors.Is(err, ErrNoFact):
return codeNoFact
case errors.Is(err, ErrConfidence):
return codeConfidence
case errors.Is(err, ErrVoidsMissing):
return codeVoidsMissing
case errors.Is(err, ErrNudgeNotFound):
return codeNudgeNotFound
case errors.Is(err, ErrNudgeOutcome):
return codeNudgeOutcome
case errors.Is(err, ErrReminderNotFound):
return codeReminderMissing
case errors.Is(err, ErrReminderState):
return codeReminderState
case errors.Is(err, ErrToolNotFound):
return codeToolNotFound
case errors.Is(err, ErrUnknownMethod):
return codeUnknownMethod
case errors.Is(err, ErrBadParams):
return codeBadParams
case errors.Is(err, ErrForbidden):
return codeForbidden
default:
return codeInternal
}
}
// rpcErr builds the wire error for a server-side error. message is omitted
// for sentinel codes (the Code carries the meaning; no need to echo text the
// caller can re-derive from errors.Is) and included for internal/bad-params
// where the text is the actual diagnostic.
func rpcErr(err error) *RpcError {
c := codeOf(err)
if c == codeInternal || c == codeBadParams {
return &RpcError{Code: c, Message: err.Error()}
}
return &RpcError{Code: c}
}