Class: Kward::RPC::Server
- Inherits:
-
Object
- Object
- Kward::RPC::Server
- Defined in:
- lib/kward/rpc/server.rb
Overview
JSON-RPC backend for trusted local UI clients.
The server speaks LSP-style Content-Length framing over stdin/stdout,
exposes capabilities during initialize, redacts secrets in errors and
notifications, and coordinates auth, config, sessions, turns, tools,
memory, commands, and startup resources.
Server should stay focused on protocol concerns: framing, JSON-RPC error
codes, method dispatch, capability reporting, and redaction at the wire
boundary. Delegate stateful product behavior to manager objects such as
SessionManager, AuthManager, and ConfigManager. When adding an RPC
feature, update dispatch, capabilities, docs, and tests together so clients
can trust initialize as the source of supported behavior.
Constant Summary collapse
- PROTOCOL_VERSION =
1- JSONRPC_VERSION =
"2.0"- BUILTIN_SLASH_COMMAND_NAMES =
PromptCommands::BUILTIN_RESERVED_COMMAND_NAMES
- ERROR_CODES =
{ parse_error: -32_700, invalid_request: -32_600, method_not_found: -32_601, invalid_params: -32_602, internal_error: -32_603 }.freeze
- PROTOCOL_METHODS =
["initialize", "shutdown"].freeze
- WORKSPACE_METHODS =
["workspace/validate", "workspace/info"].freeze
- TOOL_METHODS =
["tools/list"].freeze
- MCP_METHODS =
["mcp/status"].freeze
- PROMPT_METHODS =
["prompts/list", "prompts/expand"].freeze
- SESSION_METHODS =
[ "sessions/create", "sessions/resume", "sessions/list", "sessions/rename", "sessions/clone", "sessions/compact", "sessions/forkMessages", "sessions/fork", "sessions/tree", "sessions/tree/setLabel", "sessions/tree/navigate", "sessions/export", "sessions/delete", "sessions/close", "sessions/transcript", "sessions/active" ].freeze
- TURN_METHODS =
["turns/start", "turns/cancel", "turns/status", "turns/events", "turns/list", "turns/listActive"].freeze
- PLUGIN_CHAT_METHODS =
["pluginChats/list", "pluginChats/open", "pluginChats/transcript", "pluginChats/subscribe", "pluginChats/unsubscribe", "pluginChats/turns/start", "pluginChats/turns/cancel", "pluginChats/turns/status", "pluginChats/turns/events", "pluginChats/turns/list", "pluginChats/turns/listActive"].freeze
- MODEL_METHODS =
["models/list", "models/current", "models/set", "reasoning/set", "models/refresh"].freeze
- RUNTIME_METHODS =
["runtime/state", "runtime/stats"].freeze
- RUNTIME_SETTING_METHODS =
["runtime/updateSetting", "runtime/reload"].freeze
- AUTH_METHODS =
[ "auth/status", "auth/providers", "auth/loginWithApiKey", "auth/logoutProvider", "auth/loginWithOAuth", "auth/startOpenAILogin", "auth/submitOpenAICode", "auth/loginStatus" ].freeze
- MEMORY_METHODS =
[ "memory/status", "memory/enable", "memory/disable", "memory/autoSummary/enable", "memory/autoSummary/disable", "memory/list", "memory/add", "memory/addCore", "memory/forget", "memory/promote", "memory/relax", "memory/inspect", "memory/why", "memory/summarize" ].freeze
- COMMAND_METHODS =
["commands/list", "commands/run"].freeze
- PLUGIN_ACTION_METHODS =
["pluginActions/list", "pluginActions/run"].freeze
- SKILL_CAPTURE_METHODS =
["skills/captureSessions", "skills/captureDraft", "skills/saveCapturedDraft"].freeze
- STARTUP_RESOURCE_METHODS =
["resources/startup"].freeze
- CONFIG_METHODS =
["config/read", "config/update"].freeze
- LOGGING_METHODS =
["logging/stats", "logging/tokenCsv"].freeze
- LIFECYCLE_HOOK_METHODS =
["hooks/logs"].freeze
- UI_METHODS =
["ui/answerQuestion", "ui/answerRequest"].freeze
- TOOL_APPROVAL_METHODS =
["tool/answerApproval"].freeze
- TRANSPORT_METHODS =
["transports/list", "transports/status"].freeze
- SESSION_EVENT_NOTIFICATION =
"session/event"- SESSION_UPDATED_NOTIFICATION =
"session/updated"- TURN_EVENT_NOTIFICATION =
"turn/event"- UI_QUESTION_NOTIFICATION =
"ui/question"- UI_REQUEST_NOTIFICATION =
"ui/request"- UI_PROGRESS_NOTIFICATION =
"ui/progress"- UI_NOTIFICATION =
"ui/notification"- UI_FOOTER_NOTIFICATION =
"ui/footer"- TOOL_APPROVAL_NOTIFICATION =
"tool/approvalRequested"- HOOK_EVENT_NOTIFICATION =
"hook/event"- METHOD_GROUPS =
{ protocol: PROTOCOL_METHODS, workspace: WORKSPACE_METHODS, tools: TOOL_METHODS, mcp: MCP_METHODS, prompts: PROMPT_METHODS, sessions: SESSION_METHODS, turns: TURN_METHODS, plugin_chats: PLUGIN_CHAT_METHODS, models: MODEL_METHODS, runtime: RUNTIME_METHODS, runtime_settings: RUNTIME_SETTING_METHODS, auth: AUTH_METHODS, memory: MEMORY_METHODS, commands: COMMAND_METHODS, plugin_actions: PLUGIN_ACTION_METHODS, skill_capture: SKILL_CAPTURE_METHODS, startup_resources: STARTUP_RESOURCE_METHODS, config: CONFIG_METHODS, logging: LOGGING_METHODS, lifecycle_hooks: LIFECYCLE_HOOK_METHODS, ui: UI_METHODS, tool_approval: TOOL_APPROVAL_METHODS }.freeze
- RPC_METHODS =
METHOD_GROUPS.values.flatten.freeze
Instance Attribute Summary collapse
- #plugin_chat_manager ⇒ Object readonly
- #session_manager ⇒ Object readonly
Instance Method Summary collapse
-
#error_payload(error) ⇒ Hash
Builds redacted diagnostics suitable for JSON-RPC error data.
-
#initialize(input: $stdin, output: $stdout, error_output: $stderr, client: Client.new) ⇒ Server
constructor
Creates the RPC server and its stateful managers.
-
#log_error(error) ⇒ void
Writes a redacted server diagnostic without exposing error payload data.
-
#notify(method, params = {}) ⇒ Object
Sends a redacted JSON-RPC notification to the client.
-
#run ⇒ void
Reads framed JSON-RPC messages until shutdown or EOF.
- #shutdown ⇒ Object
Constructor Details
#initialize(input: $stdin, output: $stdout, error_output: $stderr, client: Client.new) ⇒ Server
Creates the RPC server and its stateful managers.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/kward/rpc/server.rb', line 129 def initialize(input: $stdin, output: $stdout, error_output: $stderr, client: Client.new) @transport = Transport.new(input: input, output: output) @error_output = error_output @client = client @config_manager = ConfigManager.new @session_manager = SessionManager.new(server: self, client: client, config_manager: @config_manager) @plugin_chat_manager = PluginChatManager.new( server: self, client: client, plugin_registry_provider: -> { @session_manager.plugin_registry } ) @transport_manager = Kward::Transport::Manager.new( registry: @session_manager.plugin_registry, gateway: lambda { |transport_id| Kward::Transport::Gateway.new(session_manager: @session_manager, transport_id: transport_id) }, plugin_chat_gateway: lambda { |transport_id| Kward::Transport::PluginChatGateway.new(runtime: @plugin_chat_manager.runtime, transport_id: transport_id) }, config_provider: ->(transport_id) { ConfigFiles.transport_config(transport_id) } ) @auth_manager = AuthManager.new(server: self, config_manager: @config_manager) @shutdown = false @shutdown_complete = false end |
Instance Attribute Details
#plugin_chat_manager ⇒ Object (readonly)
155 156 157 |
# File 'lib/kward/rpc/server.rb', line 155 def plugin_chat_manager @plugin_chat_manager end |
#session_manager ⇒ Object (readonly)
155 156 157 |
# File 'lib/kward/rpc/server.rb', line 155 def session_manager @session_manager end |
Instance Method Details
#error_payload(error) ⇒ Hash
Builds redacted diagnostics suitable for JSON-RPC error data.
200 201 202 203 204 205 206 |
# File 'lib/kward/rpc/server.rb', line 200 def error_payload(error) Redactor.redact({ code: error.class.name, message: error., backtrace: Array(error.backtrace).first(8) }) end |
#log_error(error) ⇒ void
This method returns an undefined value.
Writes a redacted server diagnostic without exposing error payload data.
212 213 214 |
# File 'lib/kward/rpc/server.rb', line 212 def log_error(error) @error_output.puts("Kward RPC error: #{Redactor.redact_string(error.)}") if @error_output end |
#notify(method, params = {}) ⇒ Object
Sends a redacted JSON-RPC notification to the client.
192 193 194 |
# File 'lib/kward/rpc/server.rb', line 192 def notify(method, params = {}) @transport.({ jsonrpc: JSONRPC_VERSION, method: method, params: Redactor.redact(params) }) end |
#run ⇒ void
This method returns an undefined value.
Reads framed JSON-RPC messages until shutdown or EOF.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/kward/rpc/server.rb', line 160 def run until @shutdown begin = @transport. break unless () rescue JSON::ParserError => e write_error(nil, ERROR_CODES[:parse_error], "Parse error", e) rescue StandardError => e write_error(nil, ERROR_CODES[:invalid_request], e., e) end end ensure shutdown end |
#shutdown ⇒ Object
177 178 179 180 181 182 183 184 185 186 |
# File 'lib/kward/rpc/server.rb', line 177 def shutdown return if @shutdown_complete @shutdown = true @transport_manager.shutdown @plugin_chat_manager.shutdown @session_manager.shutdown_sessions @session_manager.shutdown_plugins @shutdown_complete = true end |