Class: Kward::PanServer
- Inherits:
-
Object
- Object
- Kward::PanServer
- Defined in:
- lib/kward/pan/server.rb
Overview
Minimal local HTTP server for the experimental Pan web UI.
Constant Summary collapse
- DEFAULT_HOST =
"0.0.0.0"- DEFAULT_PORT =
8765- MAX_REQUEST_BODY_BYTES =
64 * 1024
Instance Attribute Summary collapse
-
#host ⇒ Object
readonly
Returns the value of attribute host.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
-
#workspace ⇒ Object
readonly
Returns the value of attribute workspace.
Instance Method Summary collapse
- #enqueue_prompt(prompt) ⇒ Object
-
#initialize(client:, working_directory:, config: ConfigFiles.read_config, config_dir: ConfigFiles.config_dir, output: $stderr) ⇒ PanServer
constructor
A new instance of PanServer.
- #run ⇒ Object
- #stop ⇒ Object
- #transcript_items ⇒ Object
Constructor Details
#initialize(client:, working_directory:, config: ConfigFiles.read_config, config_dir: ConfigFiles.config_dir, output: $stderr) ⇒ PanServer
Returns a new instance of PanServer.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/kward/pan/server.rb', line 28 def initialize(client:, working_directory:, config: ConfigFiles.read_config, config_dir: ConfigFiles.config_dir, output: $stderr) @client = client @output = output @workspace = Workspace.new(root: working_directory) @config = pan_config(config) @host = @config.fetch("host", DEFAULT_HOST).to_s @port = positive_port(@config.fetch("port", DEFAULT_PORT)) @username = @config["username"].to_s @password = @config["password"].to_s raise "Pan mode requires pan_mode.username and pan_mode.password in #{ConfigFiles.config_path}" if @username.empty? || @password.empty? @session_store = SessionStore.new(config_dir: config_dir, cwd: @workspace.root.to_s) @session = @session_store.create @conversation = Conversation.new( workspace_root: @workspace.root.to_s, model: (@client.current_model if @client.respond_to?(:current_model)), reasoning_effort: (@client.current_reasoning_effort if @client.respond_to?(:current_reasoning_effort)) ) @session.attach(@conversation) hook_context = lifecycle_hook_context hook_manager = lifecycle_hook_manager @agent = Agent.new( client: @client, tool_registry: ToolRegistry.new(workspace: @workspace, ask_user_question_enabled: false, hook_manager: hook_manager, hook_context: hook_context), conversation: @conversation, hook_manager: hook_manager, hook_context: hook_context ) @prompt_queue = Queue.new @subscribers = [] @subscribers_mutex = Mutex.new @worker_started = false @active = false @state_mutex = Mutex.new end |
Instance Attribute Details
#host ⇒ Object (readonly)
Returns the value of attribute host.
64 65 66 |
# File 'lib/kward/pan/server.rb', line 64 def host @host end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
64 65 66 |
# File 'lib/kward/pan/server.rb', line 64 def port @port end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
64 65 66 |
# File 'lib/kward/pan/server.rb', line 64 def session @session end |
#workspace ⇒ Object (readonly)
Returns the value of attribute workspace.
64 65 66 |
# File 'lib/kward/pan/server.rb', line 64 def workspace @workspace end |
Instance Method Details
#enqueue_prompt(prompt) ⇒ Object
90 91 92 93 94 95 96 97 98 |
# File 'lib/kward/pan/server.rb', line 90 def enqueue_prompt(prompt) text = prompt.to_s return { ok: false, error: "Prompt is required" } if text.strip.empty? queued_at = Time.now.utc.iso8601(3) @prompt_queue << { prompt: text, queued_at: queued_at } broadcast("queue", queue_payload) { ok: true, queued: @prompt_queue.size, active: active? } end |
#run ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/kward/pan/server.rb', line 66 def run start_worker @server = TCPServer.new(@host, @port) actual_port = @server.addr[1] @output.puts "Kward pan mode listening on http://#{display_host}:#{actual_port}" @output.puts "Workspace: #{@workspace.root}" @output.puts "Session: #{@session.path}" loop do socket = @server.accept Thread.new(socket) { |client_socket| handle_client(client_socket) } end rescue Interrupt @output.puts "\nPan mode stopped." ensure stop end |
#stop ⇒ Object
84 85 86 87 88 |
# File 'lib/kward/pan/server.rb', line 84 def stop @server&.close unless @server&.closed? rescue IOError nil end |
#transcript_items ⇒ Object
100 101 102 |
# File 'lib/kward/pan/server.rb', line 100 def transcript_items RPC::TranscriptNormalizer.new(@conversation.).normalize.flat_map { || pan_transcript_items() } end |