Class: Kward::PanServer
- Inherits:
-
Object
- Object
- Kward::PanServer
- Defined in:
- lib/kward/pan/server.rb
Overview
Local HTTP server for the mobile-friendly Pan web UI.
Constant Summary collapse
- DEFAULT_HOST =
"127.0.0.1"- DEFAULT_PORT =
8765- MAX_REQUEST_BODY_BYTES =
64 * 1024
- ROUTING_PROBE_ADDRESS =
"8.8.8.8"- ROUTING_PROBE_PORT =
80
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, udp_socket_class: UDPSocket) ⇒ 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, udp_socket_class: UDPSocket) ⇒ PanServer
Returns a new instance of PanServer.
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 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/kward/pan/server.rb', line 35 def initialize(client:, working_directory:, config: ConfigFiles.read_config, config_dir: ConfigFiles.config_dir, output: $stderr, udp_socket_class: UDPSocket) @client = client @output = output @udp_socket_class = udp_socket_class @workspace = WorkspaceFactory.build( root: working_directory, guardrails: ConfigFiles.workspace_guardrails_enabled?(config), config: config ) @full_config = config @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 environment_password = ENV["KWARD_PAN_PASSWORD"].to_s @password = environment_password.empty? ? @config["password"].to_s : environment_password if @username.empty? || @password.empty? raise "Pan mode requires pan_mode.username and either pan_mode.password or KWARD_PAN_PASSWORD" end @session_store = SessionStore.new(config_dir: config_dir, cwd: @workspace.root.to_s) @session = @session_store.create( provider: (@client.current_provider if @client.respond_to?(:current_provider)), model: (@client.current_model if @client.respond_to?(:current_model)), reasoning_effort: (@client.current_reasoning_effort if @client.respond_to?(:current_reasoning_effort)) ) @conversation = new_conversation @session.attach(@conversation) @agent = build_agent @prompt_queue = Queue.new @subscribers = [] @subscribers_mutex = Mutex.new @worker_started = false @active = false @pending_turns = 0 @state_mutex = Mutex.new @session_mutex = Mutex.new end |
Instance Attribute Details
#host ⇒ Object (readonly)
Returns the value of attribute host.
74 75 76 |
# File 'lib/kward/pan/server.rb', line 74 def host @host end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
74 75 76 |
# File 'lib/kward/pan/server.rb', line 74 def port @port end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
74 75 76 |
# File 'lib/kward/pan/server.rb', line 74 def session @session end |
#workspace ⇒ Object (readonly)
Returns the value of attribute workspace.
74 75 76 |
# File 'lib/kward/pan/server.rb', line 74 def workspace @workspace end |
Instance Method Details
#enqueue_prompt(prompt) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/kward/pan/server.rb', line 103 def enqueue_prompt(prompt) text = prompt.to_s return { ok: false, error: "Prompt is required" } if text.strip.empty? @session_mutex.synchronize do queued_at = Time.now.utc.iso8601(3) @state_mutex.synchronize { @pending_turns += 1 } @prompt_queue << { prompt: text, queued_at: queued_at } end broadcast("queue", queue_payload) { ok: true, queued: @prompt_queue.size, active: active? } end |
#run ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/kward/pan/server.rb', line 76 def run warn_if_exposed 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
95 96 97 98 99 100 101 |
# File 'lib/kward/pan/server.rb', line 95 def stop @server&.close unless @server&.closed? rescue IOError nil ensure @plugin_registry&.shutdown! end |
#transcript_items ⇒ Object
116 117 118 119 120 121 122 123 |
# File 'lib/kward/pan/server.rb', line 116 def transcript_items RPC::TranscriptNormalizer.new(@conversation.).normalize.flat_map do || items = pan_transcript_items() text = turn_summary_text([:turnSummary]) items << { role: "turn-stats", label: "Turn summary", text: text } unless text.empty? items end end |