kward 0.71.0 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +30 -0
- data/CHANGELOG.md +93 -0
- data/Gemfile.lock +2 -2
- data/README.md +4 -0
- data/doc/agent-tools.md +15 -6
- data/doc/authentication.md +22 -1
- data/doc/code-search.md +42 -2
- data/doc/configuration.md +106 -3
- data/doc/context-budgeting.md +136 -0
- data/doc/context-tools.md +16 -3
- data/doc/editor.md +415 -0
- data/doc/extensibility.md +16 -7
- data/doc/files.md +100 -0
- data/doc/getting-started.md +25 -18
- data/doc/git.md +123 -0
- data/doc/memory.md +24 -4
- data/doc/personas.md +34 -5
- data/doc/plugins.md +72 -1
- data/doc/releasing.md +37 -9
- data/doc/rpc.md +75 -5
- data/doc/session-management.md +35 -1
- data/doc/shell.md +332 -0
- data/doc/tabs.md +122 -0
- data/doc/troubleshooting.md +77 -1
- data/doc/usage.md +79 -7
- data/doc/web-search.md +12 -4
- data/doc/workspace-tools.md +51 -12
- data/examples/plugins/space_invaders.rb +377 -0
- data/lib/kward/agent.rb +1 -1
- data/lib/kward/ansi.rb +62 -23
- data/lib/kward/cli/commands.rb +33 -2
- data/lib/kward/cli/git.rb +150 -0
- data/lib/kward/cli/interactive_turn.rb +73 -9
- data/lib/kward/cli/plugins.rb +54 -4
- data/lib/kward/cli/prompt_interface.rb +32 -1
- data/lib/kward/cli/rendering.rb +4 -1
- data/lib/kward/cli/runtime_helpers.rb +268 -4
- data/lib/kward/cli/sessions.rb +2 -2
- data/lib/kward/cli/settings.rb +217 -9
- data/lib/kward/cli/slash_commands.rb +628 -2
- data/lib/kward/cli/tabs.rb +725 -0
- data/lib/kward/cli/tool_summaries.rb +6 -0
- data/lib/kward/cli.rb +150 -26
- data/lib/kward/clipboard.rb +2 -3
- data/lib/kward/compactor.rb +7 -19
- data/lib/kward/config_files.rb +145 -1
- data/lib/kward/context_budget_meter.rb +44 -0
- data/lib/kward/conversation.rb +12 -4
- data/lib/kward/editor_mode.rb +25 -0
- data/lib/kward/ekwsh.rb +559 -0
- data/lib/kward/image_attachments.rb +3 -1
- data/lib/kward/interactive_pty_runner.rb +151 -0
- data/lib/kward/local_command_runner.rb +155 -0
- data/lib/kward/local_pty_command_runner.rb +171 -0
- data/lib/kward/model/context_usage.rb +2 -2
- data/lib/kward/model/payloads.rb +2 -5
- data/lib/kward/plugin_registry.rb +61 -0
- data/lib/kward/project_files.rb +52 -0
- data/lib/kward/prompt_history.rb +84 -0
- data/lib/kward/prompt_interface/composer_controller.rb +69 -1
- data/lib/kward/prompt_interface/composer_renderer.rb +109 -13
- data/lib/kward/prompt_interface/composer_state.rb +96 -27
- data/lib/kward/prompt_interface/editor/auto_close_pairs.rb +123 -0
- data/lib/kward/prompt_interface/editor/auto_indent.rb +510 -0
- data/lib/kward/prompt_interface/editor/buffer.rb +109 -0
- data/lib/kward/prompt_interface/editor/controller.rb +1218 -0
- data/lib/kward/prompt_interface/editor/endwise.rb +321 -0
- data/lib/kward/prompt_interface/editor/file_marker.rb +40 -0
- data/lib/kward/prompt_interface/editor/indent_navigation.rb +61 -0
- data/lib/kward/prompt_interface/editor/kill_ring.rb +78 -0
- data/lib/kward/prompt_interface/editor/modes/emacs.rb +259 -0
- data/lib/kward/prompt_interface/editor/modes/modern.rb +354 -0
- data/lib/kward/prompt_interface/editor/modes/vibe.rb +1812 -0
- data/lib/kward/prompt_interface/editor/modes/vibe_insert_readline.rb +166 -0
- data/lib/kward/prompt_interface/editor/renderer.rb +244 -0
- data/lib/kward/prompt_interface/editor/search.rb +76 -0
- data/lib/kward/prompt_interface/editor/selections.rb +120 -0
- data/lib/kward/prompt_interface/editor/state.rb +1271 -0
- data/lib/kward/prompt_interface/editor/status_text.rb +23 -0
- data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +422 -0
- data/lib/kward/prompt_interface/editor/undo_history.rb +46 -0
- data/lib/kward/prompt_interface/editor/vibe_state.rb +44 -0
- data/lib/kward/prompt_interface/file_overlay.rb +211 -0
- data/lib/kward/prompt_interface/git_prompt.rb +288 -0
- data/lib/kward/prompt_interface/interactive/controller.rb +186 -0
- data/lib/kward/prompt_interface/interactive/renderer.rb +71 -0
- data/lib/kward/prompt_interface/interactive/state.rb +62 -0
- data/lib/kward/prompt_interface/key_handler.rb +451 -57
- data/lib/kward/prompt_interface/overlay_renderer.rb +21 -2
- data/lib/kward/prompt_interface/project_browser.rb +524 -0
- data/lib/kward/prompt_interface/question_prompt.rb +99 -56
- data/lib/kward/prompt_interface/runtime_state.rb +43 -0
- data/lib/kward/prompt_interface/screen.rb +19 -3
- data/lib/kward/prompt_interface/selection_prompt.rb +10 -19
- data/lib/kward/prompt_interface/slash_overlay.rb +2 -0
- data/lib/kward/prompt_interface/stream_state.rb +7 -0
- data/lib/kward/prompt_interface/transcript_buffer.rb +6 -0
- data/lib/kward/prompt_interface.rb +366 -222
- data/lib/kward/prompts/commands.rb +9 -0
- data/lib/kward/prompts.rb +2 -0
- data/lib/kward/rpc/memory_methods.rb +83 -0
- data/lib/kward/rpc/server.rb +169 -83
- data/lib/kward/rpc/session_manager.rb +45 -121
- data/lib/kward/rpc/session_tree_rows.rb +9 -115
- data/lib/kward/rpc/tool_event_normalizer.rb +1 -1
- data/lib/kward/rpc/tool_metadata.rb +11 -0
- data/lib/kward/rpc/transcript_normalizer.rb +4 -39
- data/lib/kward/scratchpad_runner.rb +56 -0
- data/lib/kward/session_diff.rb +20 -3
- data/lib/kward/session_naming.rb +11 -0
- data/lib/kward/session_store.rb +44 -0
- data/lib/kward/session_tree_nodes.rb +136 -0
- data/lib/kward/session_tree_renderer.rb +9 -131
- data/lib/kward/tab_store.rb +47 -0
- data/lib/kward/terminal_keys.rb +84 -0
- data/lib/kward/terminal_sequences.rb +42 -0
- data/lib/kward/text_boundary.rb +25 -0
- data/lib/kward/tools/context_budget_stats.rb +54 -0
- data/lib/kward/tools/context_for_task.rb +204 -0
- data/lib/kward/tools/read_file.rb +8 -4
- data/lib/kward/tools/registry.rb +62 -16
- data/lib/kward/tools/tool_call.rb +10 -0
- data/lib/kward/version.rb +1 -1
- data/lib/kward/workers/git_guard.rb +93 -0
- data/lib/kward/workers/job.rb +99 -0
- data/lib/kward/workers/live_view.rb +49 -0
- data/lib/kward/workers/manager.rb +288 -0
- data/lib/kward/workers/queue_runner.rb +166 -0
- data/lib/kward/workers/queue_store.rb +112 -0
- data/lib/kward/workers/store.rb +72 -0
- data/lib/kward/workers/tool_policy.rb +23 -0
- data/lib/kward/workers/worker.rb +82 -0
- data/lib/kward/workers/write_lock.rb +38 -0
- data/lib/kward/workers.rb +10 -0
- data/lib/kward/workspace.rb +125 -87
- data/templates/default/fulldoc/html/css/kward.css +140 -36
- data/templates/default/fulldoc/html/images/kward_screen_1.png +0 -0
- data/templates/default/fulldoc/html/setup.rb +1 -0
- data/templates/default/kward_navigation.rb +12 -1
- data/templates/default/layout/html/layout.erb +23 -34
- data/templates/default/layout/html/setup.rb +6 -0
- metadata +67 -1
|
@@ -25,6 +25,15 @@ module Kward
|
|
|
25
25
|
{ name: "model", description: "Select the default model.", argument_hint: "" },
|
|
26
26
|
{ name: "reasoning", description: "Select reasoning effort.", argument_hint: "" },
|
|
27
27
|
{ name: "reload", description: "Reload installed plugins.", argument_hint: "" },
|
|
28
|
+
{ name: "workers", description: "Open the worker pipeline.", argument_hint: "[new|do <task>]" },
|
|
29
|
+
{ name: "queue", description: "Manage the tab-backed worker queue.", argument_hint: "[add|list|open|run|suspend|resume]" },
|
|
30
|
+
{ name: "git", description: "Review uncommitted changes and commit them.", argument_hint: "" },
|
|
31
|
+
{ name: "diff", description: "Open the file changes recorded in this session.", argument_hint: "" },
|
|
32
|
+
{ name: "files", description: "Browse project files.", argument_hint: "" },
|
|
33
|
+
{ name: "shell", description: "Open the embedded Kward shell.", argument_hint: "" },
|
|
34
|
+
{ name: "scratchpad", description: "Open an unsaved editor buffer.", argument_hint: "[text|markdown|ruby]" },
|
|
35
|
+
{ name: "pty", description: "Run a command in an interactive PTY passthrough session.", argument_hint: "<command>" },
|
|
36
|
+
{ name: "tab", description: "Manage tabs.", argument_hint: "[1-n|move|close|new|name]" },
|
|
28
37
|
{ name: "status", description: "Show the current status message.", argument_hint: "" },
|
|
29
38
|
{ name: "stats", description: "Show telemetry logging stats.", argument_hint: "[range]" },
|
|
30
39
|
{ name: "memory", description: "Inspect and manage Kward memory.", argument_hint: "[enable|disable|auto-summary|core|add|list|forget|promote|relax|inspect|why|summarize]" }
|
data/lib/kward/prompts.rb
CHANGED
|
@@ -35,6 +35,8 @@ module Kward
|
|
|
35
35
|
You are Kward, a concise practical CLI coding agent. Use tools to understand and modify software projects. Inspect files before changing them, make the smallest correct change, preserve existing style, and summarize what changed. Be honest about limitations.
|
|
36
36
|
|
|
37
37
|
For web research, use web_search to discover sources, fetch_content for important human-readable pages, and fetch_raw for machine-readable resources such as JSON, YAML, XML, RSS, OpenAPI specs, and plain text. Prefer official or primary sources and cite or mention the URLs you relied on.
|
|
38
|
+
|
|
39
|
+
Manage code context deliberately. Prefer context_for_task, summarize_file_structure, and read_file mode="outline"/"preview" before broad reads. Escalate to read_file mode="range" for exact lines, and use mode="full" only when focused context is insufficient. Use context_budget_stats when asked about context savings.
|
|
38
40
|
PROMPT
|
|
39
41
|
end
|
|
40
42
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require_relative "../memory/manager"
|
|
2
|
+
|
|
3
|
+
# Namespace for the Kward CLI agent runtime.
|
|
4
|
+
module Kward
|
|
5
|
+
# JSON-RPC backend namespace used by UI clients.
|
|
6
|
+
module RPC
|
|
7
|
+
# Memory-related RPC method implementations mixed into SessionManager.
|
|
8
|
+
module MemoryMethods
|
|
9
|
+
def memory_manager
|
|
10
|
+
Memory::Manager.for_config_dir(@config_dir)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def memory_status
|
|
14
|
+
manager = memory_manager
|
|
15
|
+
{ enabled: manager.enabled?, autoSummary: manager.auto_summary_enabled?, paths: manager.paths }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def memory_enable
|
|
19
|
+
memory_manager.enable
|
|
20
|
+
{ enabled: true }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def memory_disable
|
|
24
|
+
memory_manager.disable
|
|
25
|
+
{ enabled: false }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def memory_auto_summary_enable
|
|
29
|
+
memory_manager.auto_summary_enable
|
|
30
|
+
{ autoSummary: true }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def memory_auto_summary_disable
|
|
34
|
+
memory_manager.auto_summary_disable
|
|
35
|
+
{ autoSummary: false }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def memory_list(include_inactive: false, workspace_root: Dir.pwd)
|
|
39
|
+
memory_manager.hierarchy(include_inactive: include_inactive, workspace_root: workspace_root)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def memory_add(text:, scope: nil, tags: [])
|
|
43
|
+
{ memory: memory_manager.add_soft(text, scope: scope || "global", tags: tags) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def memory_add_core(text:, scope: nil, tags: [])
|
|
47
|
+
{ memory: memory_manager.add_core(text, scope: scope || "global", tags: tags) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def memory_forget(id:)
|
|
51
|
+
{ forgotten: memory_manager.forget_memory(id) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def memory_promote(id:)
|
|
55
|
+
{ memory: memory_manager.promote_memory(id) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def memory_relax(id:, workspace_root: Dir.pwd)
|
|
59
|
+
{ memory: memory_manager.relax_core(id, workspace_root: workspace_root) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def memory_inspect
|
|
63
|
+
memory_manager.inspect_memory
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def memory_why(session_id: nil)
|
|
67
|
+
if session_id
|
|
68
|
+
rpc_session = fetch_session(session_id)
|
|
69
|
+
return rpc_session.conversation.last_memory_retrieval || memory_manager.explain_retrieval
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
memory_manager.explain_retrieval
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def memory_summarize(session_id:)
|
|
76
|
+
rpc_session = fetch_session(session_id)
|
|
77
|
+
records = memory_manager.summarize_conversation(rpc_session.conversation, client: @client)
|
|
78
|
+
persist_memory_state(rpc_session)
|
|
79
|
+
{ memories: records }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
data/lib/kward/rpc/server.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative "../memory/manager"
|
|
|
5
5
|
require_relative "../plugin_registry"
|
|
6
6
|
require_relative "../prompts/commands"
|
|
7
7
|
require_relative "../tools/registry"
|
|
8
|
+
require_relative "../workers"
|
|
8
9
|
require_relative "../workspace"
|
|
9
10
|
require_relative "../telemetry/logger"
|
|
10
11
|
require_relative "../telemetry/stats"
|
|
@@ -43,13 +44,20 @@ module Kward
|
|
|
43
44
|
invalid_params: -32_602,
|
|
44
45
|
internal_error: -32_603
|
|
45
46
|
}.freeze
|
|
47
|
+
PROTOCOL_METHODS = ["initialize", "shutdown"].freeze
|
|
48
|
+
WORKSPACE_METHODS = ["workspace/validate", "workspace/info"].freeze
|
|
49
|
+
TOOL_METHODS = ["tools/list"].freeze
|
|
50
|
+
PROMPT_METHODS = ["prompts/list", "prompts/expand"].freeze
|
|
46
51
|
SESSION_METHODS = [
|
|
47
52
|
"sessions/create", "sessions/resume", "sessions/list", "sessions/rename",
|
|
48
53
|
"sessions/clone", "sessions/compact", "sessions/forkMessages", "sessions/fork",
|
|
49
54
|
"sessions/tree", "sessions/tree/setLabel", "sessions/tree/navigate",
|
|
50
55
|
"sessions/export", "sessions/delete", "sessions/close", "sessions/transcript"
|
|
51
56
|
].freeze
|
|
57
|
+
TURN_METHODS = ["turns/start", "turns/cancel", "turns/status", "turns/events"].freeze
|
|
52
58
|
MODEL_METHODS = ["models/list", "models/current", "models/set", "reasoning/set"].freeze
|
|
59
|
+
RUNTIME_METHODS = ["runtime/state", "runtime/stats"].freeze
|
|
60
|
+
RUNTIME_SETTING_METHODS = ["runtime/updateSetting", "runtime/reload"].freeze
|
|
53
61
|
AUTH_METHODS = [
|
|
54
62
|
"auth/status", "auth/providers", "auth/loginWithApiKey", "auth/logoutProvider",
|
|
55
63
|
"auth/loginWithOAuth", "auth/startOpenAILogin", "auth/submitOpenAICode", "auth/loginStatus"
|
|
@@ -60,14 +68,48 @@ module Kward
|
|
|
60
68
|
"memory/forget", "memory/promote", "memory/relax", "memory/inspect",
|
|
61
69
|
"memory/why", "memory/summarize"
|
|
62
70
|
].freeze
|
|
71
|
+
WORKER_METHODS = ["workers/list", "workers/show"].freeze
|
|
72
|
+
COMMAND_METHODS = ["commands/list", "commands/run"].freeze
|
|
73
|
+
STARTUP_RESOURCE_METHODS = ["resources/startup"].freeze
|
|
74
|
+
CONFIG_METHODS = ["config/read", "config/update"].freeze
|
|
75
|
+
LOGGING_METHODS = ["logging/stats", "logging/tokenCsv"].freeze
|
|
76
|
+
UI_METHODS = ["ui/answerQuestion"].freeze
|
|
77
|
+
SESSION_EVENT_NOTIFICATION = "session/event"
|
|
78
|
+
SESSION_UPDATED_NOTIFICATION = "session/updated"
|
|
79
|
+
TURN_EVENT_NOTIFICATION = "turn/event"
|
|
80
|
+
UI_QUESTION_NOTIFICATION = "ui/question"
|
|
81
|
+
UI_FOOTER_NOTIFICATION = "ui/footer"
|
|
82
|
+
METHOD_GROUPS = {
|
|
83
|
+
protocol: PROTOCOL_METHODS,
|
|
84
|
+
workspace: WORKSPACE_METHODS,
|
|
85
|
+
tools: TOOL_METHODS,
|
|
86
|
+
prompts: PROMPT_METHODS,
|
|
87
|
+
sessions: SESSION_METHODS,
|
|
88
|
+
turns: TURN_METHODS,
|
|
89
|
+
models: MODEL_METHODS,
|
|
90
|
+
runtime: RUNTIME_METHODS,
|
|
91
|
+
runtime_settings: RUNTIME_SETTING_METHODS,
|
|
92
|
+
auth: AUTH_METHODS,
|
|
93
|
+
memory: MEMORY_METHODS,
|
|
94
|
+
workers: WORKER_METHODS,
|
|
95
|
+
commands: COMMAND_METHODS,
|
|
96
|
+
startup_resources: STARTUP_RESOURCE_METHODS,
|
|
97
|
+
config: CONFIG_METHODS,
|
|
98
|
+
logging: LOGGING_METHODS,
|
|
99
|
+
ui: UI_METHODS
|
|
100
|
+
}.freeze
|
|
101
|
+
RPC_METHODS = METHOD_GROUPS.values.flatten.freeze
|
|
63
102
|
|
|
64
103
|
# Creates the RPC server and its stateful managers.
|
|
65
|
-
def initialize(input: $stdin, output: $stdout, error_output: $stderr, client: Client.new)
|
|
104
|
+
def initialize(input: $stdin, output: $stdout, error_output: $stderr, client: Client.new, experimental_workers: false)
|
|
66
105
|
@transport = Transport.new(input: input, output: output)
|
|
67
106
|
@error_output = error_output
|
|
107
|
+
@client = client
|
|
68
108
|
@config_manager = ConfigManager.new
|
|
69
109
|
@session_manager = SessionManager.new(server: self, client: client, config_manager: @config_manager)
|
|
70
110
|
@auth_manager = AuthManager.new(server: self, config_manager: @config_manager)
|
|
111
|
+
@worker_store = Workers::Store.new
|
|
112
|
+
@experimental_workers = experimental_workers
|
|
71
113
|
@shutdown = false
|
|
72
114
|
end
|
|
73
115
|
|
|
@@ -88,7 +130,7 @@ module Kward
|
|
|
88
130
|
end
|
|
89
131
|
end
|
|
90
132
|
ensure
|
|
91
|
-
@session_manager.
|
|
133
|
+
@session_manager.shutdown_sessions
|
|
92
134
|
end
|
|
93
135
|
|
|
94
136
|
# Sends a redacted JSON-RPC notification to the client.
|
|
@@ -149,139 +191,145 @@ module Kward
|
|
|
149
191
|
def dispatch(method, params)
|
|
150
192
|
params = stringify_keys(params || {})
|
|
151
193
|
case method
|
|
152
|
-
when
|
|
194
|
+
when PROTOCOL_METHODS[0]
|
|
153
195
|
initialize_result
|
|
154
|
-
when
|
|
196
|
+
when PROTOCOL_METHODS[1]
|
|
155
197
|
@shutdown = true
|
|
156
198
|
{ ok: true }
|
|
157
|
-
when
|
|
199
|
+
when WORKSPACE_METHODS[0]
|
|
158
200
|
{ root: @session_manager.validate_workspace_root(params["workspaceRoot"] || Dir.pwd) }
|
|
159
|
-
when
|
|
201
|
+
when WORKSPACE_METHODS[1]
|
|
160
202
|
workspace_info(params["workspaceRoot"] || Dir.pwd)
|
|
161
|
-
when
|
|
203
|
+
when TOOL_METHODS[0]
|
|
162
204
|
{ tools: ToolRegistry.new(workspace: configured_workspace).schemas }
|
|
163
|
-
when
|
|
205
|
+
when PROMPT_METHODS[0]
|
|
164
206
|
prompts_list
|
|
165
|
-
when
|
|
207
|
+
when PROMPT_METHODS[1]
|
|
166
208
|
prompts_expand(params)
|
|
167
|
-
when
|
|
209
|
+
when MODEL_METHODS[0]
|
|
168
210
|
models_list
|
|
169
|
-
when
|
|
211
|
+
when MODEL_METHODS[1]
|
|
170
212
|
models_current
|
|
171
|
-
when
|
|
213
|
+
when MODEL_METHODS[2]
|
|
172
214
|
models_set(params)
|
|
173
|
-
when
|
|
215
|
+
when MODEL_METHODS[3]
|
|
174
216
|
reasoning_set(params)
|
|
175
|
-
when
|
|
217
|
+
when RUNTIME_METHODS[0]
|
|
176
218
|
@session_manager.runtime_state(session_id: params.fetch("sessionId"))
|
|
177
|
-
when
|
|
219
|
+
when RUNTIME_METHODS[1]
|
|
178
220
|
@session_manager.runtime_stats(session_id: params.fetch("sessionId"))
|
|
179
|
-
when
|
|
221
|
+
when RUNTIME_SETTING_METHODS[0]
|
|
180
222
|
runtime_update_setting(params)
|
|
181
|
-
when
|
|
223
|
+
when RUNTIME_SETTING_METHODS[1]
|
|
182
224
|
runtime_reload(params)
|
|
183
|
-
when
|
|
225
|
+
when COMMAND_METHODS[0]
|
|
184
226
|
commands_list(params)
|
|
185
|
-
when
|
|
227
|
+
when COMMAND_METHODS[1]
|
|
186
228
|
commands_run(params)
|
|
187
|
-
when
|
|
229
|
+
when STARTUP_RESOURCE_METHODS[0]
|
|
188
230
|
startup_resources(params)
|
|
189
|
-
when
|
|
231
|
+
when CONFIG_METHODS[0]
|
|
190
232
|
{ path: @config_manager.config_path, config: @config_manager.read(redacted: params.fetch("redacted", true)) }
|
|
191
|
-
when
|
|
233
|
+
when CONFIG_METHODS[1]
|
|
192
234
|
config_update(params)
|
|
193
|
-
when
|
|
235
|
+
when LOGGING_METHODS[0]
|
|
194
236
|
logging_stats(params)
|
|
195
|
-
when
|
|
237
|
+
when LOGGING_METHODS[1]
|
|
196
238
|
logging_token_csv(params)
|
|
197
|
-
when
|
|
239
|
+
when MEMORY_METHODS[0]
|
|
198
240
|
@session_manager.memory_status
|
|
199
|
-
when
|
|
241
|
+
when MEMORY_METHODS[1]
|
|
200
242
|
@session_manager.memory_enable
|
|
201
|
-
when
|
|
243
|
+
when MEMORY_METHODS[2]
|
|
202
244
|
@session_manager.memory_disable
|
|
203
|
-
when
|
|
245
|
+
when MEMORY_METHODS[3]
|
|
204
246
|
@session_manager.memory_auto_summary_enable
|
|
205
|
-
when
|
|
247
|
+
when MEMORY_METHODS[4]
|
|
206
248
|
@session_manager.memory_auto_summary_disable
|
|
207
|
-
when
|
|
249
|
+
when MEMORY_METHODS[5]
|
|
208
250
|
@session_manager.memory_list(include_inactive: params["includeInactive"] || false, workspace_root: params["workspaceRoot"] || Dir.pwd)
|
|
209
|
-
when
|
|
251
|
+
when MEMORY_METHODS[6]
|
|
210
252
|
@session_manager.memory_add(text: params.fetch("text"), scope: params["scope"], tags: params["tags"] || [])
|
|
211
|
-
when
|
|
253
|
+
when MEMORY_METHODS[7]
|
|
212
254
|
@session_manager.memory_add_core(text: params.fetch("text"), scope: params["scope"], tags: params["tags"] || [])
|
|
213
|
-
when
|
|
255
|
+
when MEMORY_METHODS[8]
|
|
214
256
|
@session_manager.memory_forget(id: params.fetch("id"))
|
|
215
|
-
when
|
|
257
|
+
when MEMORY_METHODS[9]
|
|
216
258
|
@session_manager.memory_promote(id: params.fetch("id"))
|
|
217
|
-
when
|
|
259
|
+
when MEMORY_METHODS[10]
|
|
218
260
|
@session_manager.memory_relax(id: params.fetch("id"), workspace_root: params["workspaceRoot"] || Dir.pwd)
|
|
219
|
-
when
|
|
261
|
+
when MEMORY_METHODS[11]
|
|
220
262
|
@session_manager.memory_inspect
|
|
221
|
-
when
|
|
263
|
+
when MEMORY_METHODS[12]
|
|
222
264
|
@session_manager.memory_why(session_id: params["sessionId"])
|
|
223
|
-
when
|
|
265
|
+
when MEMORY_METHODS[13]
|
|
224
266
|
@session_manager.memory_summarize(session_id: params.fetch("sessionId"))
|
|
225
|
-
when
|
|
267
|
+
when WORKER_METHODS[0]
|
|
268
|
+
require_experimental_workers!
|
|
269
|
+
workers_list(params)
|
|
270
|
+
when WORKER_METHODS[1]
|
|
271
|
+
require_experimental_workers!
|
|
272
|
+
workers_show(params)
|
|
273
|
+
when AUTH_METHODS[0]
|
|
226
274
|
@auth_manager.status
|
|
227
|
-
when
|
|
275
|
+
when AUTH_METHODS[1]
|
|
228
276
|
@auth_manager.providers
|
|
229
|
-
when
|
|
277
|
+
when AUTH_METHODS[2]
|
|
230
278
|
auth_login_with_api_key(params)
|
|
231
|
-
when
|
|
279
|
+
when AUTH_METHODS[3]
|
|
232
280
|
auth_logout_provider(params)
|
|
233
|
-
when
|
|
281
|
+
when AUTH_METHODS[4]
|
|
234
282
|
@auth_manager.login_with_oauth(provider_id: params.fetch("providerId"), timeout_seconds: params["timeoutSeconds"] || 120)
|
|
235
|
-
when
|
|
283
|
+
when AUTH_METHODS[5]
|
|
236
284
|
@auth_manager.start_openai_login(timeout_seconds: params["timeoutSeconds"] || 120)
|
|
237
|
-
when
|
|
285
|
+
when AUTH_METHODS[6]
|
|
238
286
|
@auth_manager.submit_openai_code(login_id: params.fetch("loginId"), code: params.fetch("code"))
|
|
239
|
-
when
|
|
287
|
+
when AUTH_METHODS[7]
|
|
240
288
|
@auth_manager.login_status(login_id: params.fetch("loginId"))
|
|
241
|
-
when
|
|
289
|
+
when SESSION_METHODS[0]
|
|
242
290
|
@session_manager.create_session(workspace_root: params["workspaceRoot"] || Dir.pwd, name: params["name"], resume_last: params["resumeLast"] != false)
|
|
243
|
-
when
|
|
291
|
+
when SESSION_METHODS[1]
|
|
244
292
|
@session_manager.resume_session(path: params.fetch("path"), workspace_root: params["workspaceRoot"])
|
|
245
|
-
when
|
|
293
|
+
when SESSION_METHODS[2]
|
|
246
294
|
{ sessions: @session_manager.list_sessions(workspace_root: params["workspaceRoot"] || Dir.pwd, limit: params["limit"], current_session_path: params["currentSessionPath"]) }
|
|
247
|
-
when
|
|
295
|
+
when SESSION_METHODS[3]
|
|
248
296
|
@session_manager.rename_session(session_id: params.fetch("sessionId"), name: params["name"])
|
|
249
|
-
when
|
|
297
|
+
when SESSION_METHODS[4]
|
|
250
298
|
@session_manager.clone_session(session_id: params.fetch("sessionId"))
|
|
251
|
-
when
|
|
299
|
+
when SESSION_METHODS[5]
|
|
252
300
|
@session_manager.compact_session(session_id: params.fetch("sessionId"), custom_instructions: params["customInstructions"] || "")
|
|
253
|
-
when
|
|
301
|
+
when SESSION_METHODS[6]
|
|
254
302
|
@session_manager.fork_messages(session_id: params.fetch("sessionId"))
|
|
255
|
-
when
|
|
303
|
+
when SESSION_METHODS[7]
|
|
256
304
|
@session_manager.fork_session(session_id: params.fetch("sessionId"), entry_id: params.fetch("entryId"))
|
|
257
|
-
when
|
|
305
|
+
when SESSION_METHODS[8]
|
|
258
306
|
@session_manager.session_tree(session_id: params.fetch("sessionId"))
|
|
259
|
-
when
|
|
307
|
+
when SESSION_METHODS[9]
|
|
260
308
|
@session_manager.set_tree_label(session_id: params.fetch("sessionId"), entry_id: params.fetch("entryId"), label: params["label"])
|
|
261
|
-
when
|
|
309
|
+
when SESSION_METHODS[10]
|
|
262
310
|
@session_manager.navigate_tree(session_id: params.fetch("sessionId"), entry_id: params.fetch("entryId"), summarize: params["summarize"], custom_instructions: params["customInstructions"])
|
|
263
|
-
when
|
|
311
|
+
when SESSION_METHODS[11]
|
|
264
312
|
@session_manager.export_session(session_id: params.fetch("sessionId"), path: params["path"], format: params["format"])
|
|
265
|
-
when
|
|
313
|
+
when SESSION_METHODS[12]
|
|
266
314
|
@session_manager.delete_session(session_id: params.fetch("sessionId"))
|
|
267
|
-
when
|
|
315
|
+
when SESSION_METHODS[13]
|
|
268
316
|
@session_manager.close_session(session_id: params.fetch("sessionId"))
|
|
269
|
-
when
|
|
317
|
+
when SESSION_METHODS[14]
|
|
270
318
|
@session_manager.transcript(session_id: params.fetch("sessionId"))
|
|
271
|
-
when
|
|
319
|
+
when TURN_METHODS[0]
|
|
272
320
|
@session_manager.start_turn(
|
|
273
321
|
session_id: params.fetch("sessionId"),
|
|
274
322
|
input: params.fetch("input"),
|
|
275
323
|
streaming_behavior: params["streamingBehavior"],
|
|
276
324
|
attachments: params["attachments"] || []
|
|
277
325
|
)
|
|
278
|
-
when
|
|
326
|
+
when TURN_METHODS[1]
|
|
279
327
|
@session_manager.cancel_turn(turn_id: params.fetch("turnId"))
|
|
280
|
-
when
|
|
328
|
+
when TURN_METHODS[2]
|
|
281
329
|
@session_manager.turn_status(turn_id: params.fetch("turnId"))
|
|
282
|
-
when
|
|
330
|
+
when TURN_METHODS[3]
|
|
283
331
|
@session_manager.turn_events(turn_id: params.fetch("turnId"), after_sequence: params["afterSequence"] || 0)
|
|
284
|
-
when
|
|
332
|
+
when UI_METHODS[0]
|
|
285
333
|
@session_manager.answer_question(session_id: params.fetch("sessionId"), question_request_id: params.fetch("questionRequestId"), answers: params.fetch("answers"))
|
|
286
334
|
else
|
|
287
335
|
raise NoMethodError, method
|
|
@@ -313,13 +361,13 @@ module Kward
|
|
|
313
361
|
mode: "explicit",
|
|
314
362
|
persistence: "jsonl",
|
|
315
363
|
methods: SESSION_METHODS,
|
|
316
|
-
startupResume: { supported: true, method:
|
|
364
|
+
startupResume: { supported: true, method: SESSION_METHODS[0], parameter: "resumeLast", default: session_auto_resume_enabled?, immediateTranscript: true, sessionActivePersonaLabel: true },
|
|
317
365
|
list: { supported: true, source: "rpc", ancestry: true, treeFields: true },
|
|
318
|
-
fork: { supported: true, methods:
|
|
319
|
-
compact: { supported: true, method:
|
|
366
|
+
fork: { supported: true, methods: SESSION_METHODS.values_at(6, 7), entryIdFormat: "entry-id", selectedMessage: "excludedFromForkComposerTextReturned" },
|
|
367
|
+
compact: { supported: true, method: SESSION_METHODS[5], notification: SESSION_EVENT_NOTIFICATION, events: ["compactionStart", "compactionEnd"] },
|
|
320
368
|
import: { supported: false },
|
|
321
|
-
tree: { supported: true, method:
|
|
322
|
-
updates: { supported: false, notification:
|
|
369
|
+
tree: { supported: true, method: SESSION_METHODS[8], labels: true, labelTimestamps: true, navigate: true, summarize: true, shape: "tauren-tree-items-v1" },
|
|
370
|
+
updates: { supported: false, notification: SESSION_UPDATED_NOTIFICATION }
|
|
323
371
|
},
|
|
324
372
|
turns: {
|
|
325
373
|
mode: "async",
|
|
@@ -338,19 +386,19 @@ module Kward
|
|
|
338
386
|
eventReplay: { behavior: "recent-in-memory", persisted: false, limit: SessionManager::RECENT_EVENT_LIMIT }
|
|
339
387
|
},
|
|
340
388
|
events: {
|
|
341
|
-
notification:
|
|
389
|
+
notification: TURN_EVENT_NOTIFICATION,
|
|
342
390
|
assistantText: "assistantDelta",
|
|
343
391
|
reasoning: { start: false, delta: true, end: false },
|
|
344
392
|
modelRetry: { supported: true, event: "modelRetry" },
|
|
345
393
|
steering: { supported: @session_manager.in_flight_steer_supported?, event: "turnSteered", mode: @session_manager.in_flight_steer_supported? ? "native" : "unsupported" },
|
|
346
|
-
tools: { call: true, update: false, result: true, normalizedMetadata: true, diffs: true, changedFiles:
|
|
394
|
+
tools: { call: true, update: false, result: true, normalizedMetadata: true, diffs: true, changedFiles: true, workspaceGuardrails: workspace_guardrails_enabled?, focusedContext: true, contextBudgetStats: true },
|
|
347
395
|
errors: true,
|
|
348
396
|
sessionUpdates: false
|
|
349
397
|
},
|
|
350
398
|
attachments: {
|
|
351
399
|
input: {
|
|
352
400
|
supported: true,
|
|
353
|
-
method:
|
|
401
|
+
method: TURN_METHODS[0],
|
|
354
402
|
encoding: "base64",
|
|
355
403
|
mimeTypes: SessionManager::RPC_IMAGE_MIME_TYPES,
|
|
356
404
|
maxBytes: SessionManager::RPC_ATTACHMENT_MAX_BYTES
|
|
@@ -365,13 +413,13 @@ module Kward
|
|
|
365
413
|
},
|
|
366
414
|
runtime: {
|
|
367
415
|
supported: true,
|
|
368
|
-
methods:
|
|
416
|
+
methods: RUNTIME_METHODS,
|
|
369
417
|
state: { supported: true },
|
|
370
418
|
stats: { messageCounts: true, tokens: false, cost: false, contextUsage: true, contextUsageEstimated: true }
|
|
371
419
|
},
|
|
372
420
|
runtimeSettings: {
|
|
373
421
|
supported: true,
|
|
374
|
-
methods:
|
|
422
|
+
methods: RUNTIME_SETTING_METHODS,
|
|
375
423
|
settings: ["defaultModel", "defaultThinkingLevel"]
|
|
376
424
|
},
|
|
377
425
|
auth: {
|
|
@@ -384,17 +432,20 @@ module Kward
|
|
|
384
432
|
logout: true
|
|
385
433
|
},
|
|
386
434
|
memory: { supported: true, optIn: true, defaultEnabled: false, autoSummaryDefaultEnabled: false, promptInjection: "interactive", storage: { core: "json", soft: "jsonl", events: "jsonl" }, methods: MEMORY_METHODS },
|
|
387
|
-
|
|
388
|
-
|
|
435
|
+
workers: workers_capability,
|
|
436
|
+
commands: { supported: true, methods: COMMAND_METHODS, method: COMMAND_METHODS[0], runMethod: COMMAND_METHODS[1], sources: ["builtin", "prompt", "skill", "plugin"], executableSources: ["builtin", "plugin"] },
|
|
437
|
+
startupResources: { supported: true, method: STARTUP_RESOURCE_METHODS.first },
|
|
389
438
|
starterPack: { supported: false, reason: "cliOnlyInstallCommand" },
|
|
439
|
+
shell: { supported: false, reason: "interactiveTuiOnly" },
|
|
440
|
+
scratchpad: { supported: false, reason: "interactiveTuiOnly" },
|
|
390
441
|
extensionUi: {
|
|
391
|
-
question: { supported: true, notification:
|
|
442
|
+
question: { supported: true, notification: UI_QUESTION_NOTIFICATION, method: UI_METHODS.first, maxQuestions: 4, multiSelect: false, preview: false },
|
|
392
443
|
select: false,
|
|
393
444
|
confirm: false,
|
|
394
445
|
input: false,
|
|
395
446
|
editor: false,
|
|
396
447
|
widgets: false,
|
|
397
|
-
footer: { supported: true, notification:
|
|
448
|
+
footer: { supported: true, notification: UI_FOOTER_NOTIFICATION },
|
|
398
449
|
custom: false,
|
|
399
450
|
terminalInput: false
|
|
400
451
|
},
|
|
@@ -412,9 +463,9 @@ module Kward
|
|
|
412
463
|
logging: {
|
|
413
464
|
supported: true,
|
|
414
465
|
defaultEnabled: false,
|
|
415
|
-
methods:
|
|
416
|
-
stats: { supported: true, method:
|
|
417
|
-
usageCsv: { supported: true, method:
|
|
466
|
+
methods: LOGGING_METHODS,
|
|
467
|
+
stats: { supported: true, method: LOGGING_METHODS[0], defaultRange: TelemetryStats::DEFAULT_RANGE, units: %w[minutes hours days weeks months years] },
|
|
468
|
+
usageCsv: { supported: true, method: LOGGING_METHODS[1], defaultRange: TelemetryStats::DEFAULT_RANGE, buckets: %w[second minute hour day week month year] },
|
|
418
469
|
config: "logging",
|
|
419
470
|
envPrefix: "KWARD_LOGGING",
|
|
420
471
|
directory: File.join(ConfigFiles.config_dir, "logs"),
|
|
@@ -426,6 +477,18 @@ module Kward
|
|
|
426
477
|
}
|
|
427
478
|
end
|
|
428
479
|
|
|
480
|
+
def workers_capability
|
|
481
|
+
return { supported: false, reason: "experimentalWorkersFlagRequired", flag: "--experimental-workers" } unless @experimental_workers
|
|
482
|
+
|
|
483
|
+
{ supported: true, methods: WORKER_METHODS, roles: ["implementation", "request"], statuses: Workers::Worker::STATUSES, transcriptStorage: "sessions", metadataStorage: "json" }
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def require_experimental_workers!
|
|
487
|
+
return if @experimental_workers
|
|
488
|
+
|
|
489
|
+
raise NoMethodError, "workers require --experimental-workers"
|
|
490
|
+
end
|
|
491
|
+
|
|
429
492
|
def workspace_info(root)
|
|
430
493
|
root = @session_manager.validate_workspace_root(root)
|
|
431
494
|
{ root: root, basename: File.basename(root), writable: File.writable?(root) }
|
|
@@ -571,6 +634,20 @@ module Kward
|
|
|
571
634
|
{ sections: sections }
|
|
572
635
|
end
|
|
573
636
|
|
|
637
|
+
def workers_list(params)
|
|
638
|
+
include_archived = params["includeArchived"] == true
|
|
639
|
+
workers = @worker_store.list(include_archived: include_archived)
|
|
640
|
+
{ workers: workers }
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
def workers_show(params)
|
|
644
|
+
id = params.fetch("id").to_s.delete_prefix("#")
|
|
645
|
+
worker = @worker_store.find(id)
|
|
646
|
+
return { worker: worker } if worker
|
|
647
|
+
|
|
648
|
+
raise ArgumentError, "Unknown worker: #{id}"
|
|
649
|
+
end
|
|
650
|
+
|
|
574
651
|
def auth_login_with_api_key(params)
|
|
575
652
|
result = @auth_manager.login_with_api_key(provider_id: params.fetch("providerId"), api_key: params.fetch("apiKey"))
|
|
576
653
|
@session_manager.refresh_client_config
|
|
@@ -602,6 +679,15 @@ module Kward
|
|
|
602
679
|
end
|
|
603
680
|
|
|
604
681
|
def provider_model_from(value)
|
|
682
|
+
if value.is_a?(Hash)
|
|
683
|
+
provider = value["provider"] || value[:provider] || @session_manager.current_model[:provider]
|
|
684
|
+
model = value["model"] || value[:model] || value["id"] || value[:id]
|
|
685
|
+
model = model.to_s.strip
|
|
686
|
+
raise ArgumentError, "Model must be a non-empty string" if model.empty?
|
|
687
|
+
|
|
688
|
+
return [provider, model]
|
|
689
|
+
end
|
|
690
|
+
|
|
605
691
|
text = value.to_s.strip
|
|
606
692
|
raise ArgumentError, "Model must be a non-empty string" if text.empty?
|
|
607
693
|
|