kward 0.66.0 → 0.67.1
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/CHANGELOG.md +50 -3
- data/Gemfile.lock +2 -2
- data/README.md +5 -1
- data/doc/configuration.md +43 -1
- data/doc/memory.md +31 -9
- data/doc/rpc.md +41 -21
- data/doc/troubleshooting.md +55 -0
- data/doc/usage.md +41 -6
- data/lib/kward/cli.rb +1155 -195
- data/lib/kward/cli_transcript_formatter.rb +124 -0
- data/lib/kward/compaction/file_operation_tracker.rb +46 -0
- data/lib/kward/compactor.rb +3 -68
- data/lib/kward/config_files.rb +45 -69
- data/lib/kward/memory/manager.rb +66 -7
- data/lib/kward/model/client.rb +2 -195
- data/lib/kward/model/model_info.rb +9 -10
- data/lib/kward/model/payloads.rb +203 -0
- data/lib/kward/prompt_interface/banner.rb +77 -0
- data/lib/kward/prompt_interface.rb +220 -191
- data/lib/kward/prompts/commands.rb +3 -2
- data/lib/kward/rpc/runtime_payloads.rb +79 -0
- data/lib/kward/rpc/server.rb +33 -34
- data/lib/kward/rpc/session_manager.rb +518 -159
- data/lib/kward/rpc/tool_event_normalizer.rb +12 -9
- data/lib/kward/rpc/transcript_normalizer.rb +31 -53
- data/lib/kward/session_store.rb +269 -23
- data/lib/kward/session_trash.rb +96 -0
- data/lib/kward/session_tree_renderer.rb +264 -0
- data/lib/kward/tools/registry.rb +3 -1
- data/lib/kward/version.rb +1 -1
- data/lib/kward/workspace.rb +10 -5
- metadata +9 -1
|
@@ -9,6 +9,7 @@ module Kward
|
|
|
9
9
|
{ name: "resume", description: "Resume a saved session.", argument_hint: "[path]" },
|
|
10
10
|
{ name: "name", description: "Name or clear the current session.", argument_hint: "[name]" },
|
|
11
11
|
{ name: "clone", description: "Clone the current session.", argument_hint: "" },
|
|
12
|
+
{ name: "tree", description: "Navigate the current session tree.", argument_hint: "" },
|
|
12
13
|
{ name: "copy", description: "Copy clean session text to the clipboard.", argument_hint: "[last|transcript]" },
|
|
13
14
|
{ name: "export", description: "Export the current session as Markdown.", argument_hint: "[path]" },
|
|
14
15
|
{ name: "compact", description: "Compact the current conversation context.", argument_hint: "[instructions]" },
|
|
@@ -18,10 +19,10 @@ module Kward
|
|
|
18
19
|
{ name: "model", description: "Select the default model.", argument_hint: "" },
|
|
19
20
|
{ name: "openrouter/catalog", description: "List the full OpenRouter model catalog.", argument_hint: "" },
|
|
20
21
|
{ name: "reasoning", description: "Select reasoning effort.", argument_hint: "" },
|
|
22
|
+
{ name: "reload", description: "Reload installed plugins.", argument_hint: "" },
|
|
21
23
|
{ name: "status", description: "Show the current status message.", argument_hint: "" },
|
|
22
24
|
{ name: "stats", description: "Show telemetry logging stats.", argument_hint: "[range]" },
|
|
23
|
-
{ name: "
|
|
24
|
-
{ name: "memory", description: "Inspect and manage Kward memory.", argument_hint: "[enable|disable|auto-summary|core|add|list|forget|promote|inspect|why|summarize]" }
|
|
25
|
+
{ name: "memory", description: "Inspect and manage Kward memory.", argument_hint: "[enable|disable|auto-summary|core|add|list|forget|promote|relax|inspect|why|summarize]" }
|
|
25
26
|
].freeze
|
|
26
27
|
BUILTIN_RESERVED_COMMAND_NAMES = BUILTIN_COMMANDS.map { |command| command[:name] }.freeze
|
|
27
28
|
SLASH_COMMAND_PATTERN = %r{\A/(\S+)(?:\s+(.*))?\z}m
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Kward
|
|
2
|
+
module RPC
|
|
3
|
+
module RuntimePayloads
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
def state(session:, model:, streaming:, steering_supported:, auto_compaction_reserve_tokens:, active_persona_label:, message_count:, pending_count:, compaction_enabled:, workspace_guardrails_enabled:)
|
|
7
|
+
{
|
|
8
|
+
model: model,
|
|
9
|
+
thinkingLevel: model[:reasoningEffort],
|
|
10
|
+
isStreaming: streaming,
|
|
11
|
+
isCompacting: false,
|
|
12
|
+
steeringMode: steering_supported ? "in-flight" : "one-at-a-time",
|
|
13
|
+
followUpMode: "one-at-a-time",
|
|
14
|
+
sessionFile: session[:path],
|
|
15
|
+
rpcSessionId: session[:id],
|
|
16
|
+
persistentSessionId: session[:persistentId],
|
|
17
|
+
sessionName: session[:name],
|
|
18
|
+
autoCompactionEnabled: compaction_enabled,
|
|
19
|
+
autoCompactionReserveTokens: auto_compaction_reserve_tokens,
|
|
20
|
+
workspaceGuardrailsEnabled: workspace_guardrails_enabled,
|
|
21
|
+
autoRetryEnabled: false,
|
|
22
|
+
defaultProvider: model[:provider],
|
|
23
|
+
defaultModel: default_model_label(model),
|
|
24
|
+
defaultThinkingLevel: model[:reasoningEffort],
|
|
25
|
+
activePersonaLabel: active_persona_label,
|
|
26
|
+
hideThinkingBlock: false,
|
|
27
|
+
quietStartup: false,
|
|
28
|
+
transport: "kward-rpc",
|
|
29
|
+
imageAutoResize: false,
|
|
30
|
+
blockImages: false,
|
|
31
|
+
enabledModels: [],
|
|
32
|
+
enableSkillCommands: true,
|
|
33
|
+
messageCount: message_count,
|
|
34
|
+
pendingMessageCount: pending_count
|
|
35
|
+
}.compact
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def stats(session:, counts:, model:, auto_compaction_reserve_tokens:, context_usage:, compaction_enabled:)
|
|
39
|
+
{
|
|
40
|
+
sessionFile: session[:path],
|
|
41
|
+
rpcSessionId: session[:id],
|
|
42
|
+
persistentSessionId: session[:persistentId],
|
|
43
|
+
sessionName: session[:name],
|
|
44
|
+
userMessages: counts[:userMessages],
|
|
45
|
+
assistantMessages: counts[:assistantMessages],
|
|
46
|
+
toolCalls: counts[:toolCalls],
|
|
47
|
+
toolResults: counts[:toolResults],
|
|
48
|
+
totalMessages: counts[:totalMessages],
|
|
49
|
+
usingSubscription: model[:provider] == "Codex",
|
|
50
|
+
autoCompactionEnabled: compaction_enabled,
|
|
51
|
+
autoCompactionReserveTokens: auto_compaction_reserve_tokens,
|
|
52
|
+
contextUsage: context_usage
|
|
53
|
+
}.compact
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def session(rpc_session, modified_at:, active_persona_label: nil)
|
|
57
|
+
{
|
|
58
|
+
id: rpc_session.id,
|
|
59
|
+
persistentId: rpc_session.session.id,
|
|
60
|
+
path: rpc_session.session.path,
|
|
61
|
+
workspaceRoot: rpc_session.workspace_root,
|
|
62
|
+
cwd: rpc_session.session.cwd.to_s.empty? ? rpc_session.workspace_root : rpc_session.session.cwd,
|
|
63
|
+
name: rpc_session.session.name,
|
|
64
|
+
createdAt: rpc_session.session.created_at&.utc&.iso8601(3),
|
|
65
|
+
modifiedAt: modified_at&.utc&.iso8601(3),
|
|
66
|
+
parentId: rpc_session.session.parent_id,
|
|
67
|
+
parentPath: rpc_session.session.parent_path,
|
|
68
|
+
activePersonaLabel: active_persona_label
|
|
69
|
+
}.compact
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def default_model_label(model)
|
|
73
|
+
return nil if model[:provider].to_s.empty? || model[:id].to_s.empty?
|
|
74
|
+
|
|
75
|
+
"#{model[:provider]}/#{model[:id]}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
data/lib/kward/rpc/server.rb
CHANGED
|
@@ -132,7 +132,7 @@ module Kward
|
|
|
132
132
|
when "workspace/info"
|
|
133
133
|
workspace_info(params["workspaceRoot"] || Dir.pwd)
|
|
134
134
|
when "tools/list"
|
|
135
|
-
{ tools: ToolRegistry.new.schemas }
|
|
135
|
+
{ tools: ToolRegistry.new(workspace: configured_workspace).schemas }
|
|
136
136
|
when "prompts/list"
|
|
137
137
|
prompts_list
|
|
138
138
|
when "prompts/expand"
|
|
@@ -180,7 +180,7 @@ module Kward
|
|
|
180
180
|
when "memory/autoSummary/disable"
|
|
181
181
|
@session_manager.memory_auto_summary_disable
|
|
182
182
|
when "memory/list"
|
|
183
|
-
@session_manager.memory_list(include_inactive: params["includeInactive"] || false)
|
|
183
|
+
@session_manager.memory_list(include_inactive: params["includeInactive"] || false, workspace_root: params["workspaceRoot"] || Dir.pwd)
|
|
184
184
|
when "memory/add"
|
|
185
185
|
@session_manager.memory_add(text: params.fetch("text"), scope: params["scope"], tags: params["tags"] || [])
|
|
186
186
|
when "memory/addCore"
|
|
@@ -189,6 +189,8 @@ module Kward
|
|
|
189
189
|
@session_manager.memory_forget(id: params.fetch("id"))
|
|
190
190
|
when "memory/promote"
|
|
191
191
|
@session_manager.memory_promote(id: params.fetch("id"))
|
|
192
|
+
when "memory/relax"
|
|
193
|
+
@session_manager.memory_relax(id: params.fetch("id"), workspace_root: params["workspaceRoot"] || Dir.pwd)
|
|
192
194
|
when "memory/inspect"
|
|
193
195
|
@session_manager.memory_inspect
|
|
194
196
|
when "memory/why"
|
|
@@ -212,11 +214,11 @@ module Kward
|
|
|
212
214
|
when "auth/loginStatus"
|
|
213
215
|
@auth_manager.login_status(login_id: params.fetch("loginId"))
|
|
214
216
|
when "sessions/create"
|
|
215
|
-
@session_manager.create_session(workspace_root: params["workspaceRoot"] || Dir.pwd, name: params["name"])
|
|
217
|
+
@session_manager.create_session(workspace_root: params["workspaceRoot"] || Dir.pwd, name: params["name"], resume_last: params["resumeLast"] != false)
|
|
216
218
|
when "sessions/resume"
|
|
217
219
|
@session_manager.resume_session(path: params.fetch("path"), workspace_root: params["workspaceRoot"])
|
|
218
220
|
when "sessions/list"
|
|
219
|
-
{ sessions: @session_manager.list_sessions(workspace_root: params["workspaceRoot"] || Dir.pwd, limit: params["limit"]
|
|
221
|
+
{ sessions: @session_manager.list_sessions(workspace_root: params["workspaceRoot"] || Dir.pwd, limit: params["limit"], current_session_path: params["currentSessionPath"]) }
|
|
220
222
|
when "sessions/rename"
|
|
221
223
|
@session_manager.rename_session(session_id: params.fetch("sessionId"), name: params["name"])
|
|
222
224
|
when "sessions/clone"
|
|
@@ -227,6 +229,12 @@ module Kward
|
|
|
227
229
|
@session_manager.fork_messages(session_id: params.fetch("sessionId"))
|
|
228
230
|
when "sessions/fork"
|
|
229
231
|
@session_manager.fork_session(session_id: params.fetch("sessionId"), entry_id: params.fetch("entryId"))
|
|
232
|
+
when "sessions/tree"
|
|
233
|
+
@session_manager.session_tree(session_id: params.fetch("sessionId"))
|
|
234
|
+
when "sessions/tree/setLabel"
|
|
235
|
+
@session_manager.set_tree_label(session_id: params.fetch("sessionId"), entry_id: params.fetch("entryId"), label: params["label"])
|
|
236
|
+
when "sessions/tree/navigate"
|
|
237
|
+
@session_manager.navigate_tree(session_id: params.fetch("sessionId"), entry_id: params.fetch("entryId"), summarize: params["summarize"], custom_instructions: params["customInstructions"])
|
|
230
238
|
when "sessions/export"
|
|
231
239
|
@session_manager.export_session(session_id: params.fetch("sessionId"), path: params["path"], format: params["format"])
|
|
232
240
|
when "sessions/delete"
|
|
@@ -267,12 +275,6 @@ module Kward
|
|
|
267
275
|
def capabilities
|
|
268
276
|
{
|
|
269
277
|
framing: "content-length",
|
|
270
|
-
asyncTurns: true,
|
|
271
|
-
turnCancellation: "best-effort",
|
|
272
|
-
turnEventReplay: true,
|
|
273
|
-
uiQuestions: true,
|
|
274
|
-
authLogin: true,
|
|
275
|
-
configUpdate: true,
|
|
276
278
|
transcript: {
|
|
277
279
|
format: "tauren-transcript-v1",
|
|
278
280
|
messagesNormalized: true,
|
|
@@ -285,12 +287,13 @@ module Kward
|
|
|
285
287
|
sessions: {
|
|
286
288
|
mode: "explicit",
|
|
287
289
|
persistence: "jsonl",
|
|
288
|
-
methods: ["sessions/create", "sessions/resume", "sessions/list", "sessions/rename", "sessions/clone", "sessions/compact", "sessions/forkMessages", "sessions/fork", "sessions/export", "sessions/delete", "sessions/close", "sessions/transcript"],
|
|
290
|
+
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"],
|
|
291
|
+
startupResume: { supported: true, method: "sessions/create", parameter: "resumeLast", default: session_auto_resume_enabled?, immediateTranscript: true, sessionActivePersonaLabel: true },
|
|
289
292
|
list: { supported: true, source: "rpc", ancestry: true, treeFields: true },
|
|
290
|
-
fork: { supported: true, methods: ["sessions/forkMessages", "sessions/fork"], entryIdFormat: "
|
|
293
|
+
fork: { supported: true, methods: ["sessions/forkMessages", "sessions/fork"], entryIdFormat: "entry-id", selectedMessage: "excludedFromForkComposerTextReturned" },
|
|
291
294
|
compact: { supported: true, method: "sessions/compact", notification: "session/event", events: ["compactionStart", "compactionEnd"] },
|
|
292
295
|
import: { supported: false },
|
|
293
|
-
tree: { supported:
|
|
296
|
+
tree: { supported: true, method: "sessions/tree", labels: true, labelTimestamps: true, navigate: true, summarize: true, shape: "tauren-tree-items-v1" },
|
|
294
297
|
updates: { supported: false, notification: "session/updated" }
|
|
295
298
|
},
|
|
296
299
|
turns: {
|
|
@@ -315,7 +318,7 @@ module Kward
|
|
|
315
318
|
reasoning: { start: false, delta: true, end: false },
|
|
316
319
|
modelRetry: { supported: true, event: "modelRetry" },
|
|
317
320
|
steering: { supported: @session_manager.in_flight_steer_supported?, event: "turnSteered", mode: @session_manager.in_flight_steer_supported? ? "native" : "unsupported" },
|
|
318
|
-
tools: { call: true, update: false, result: true, normalizedMetadata: true, diffs: true, changedFiles: false },
|
|
321
|
+
tools: { call: true, update: false, result: true, normalizedMetadata: true, diffs: true, changedFiles: false, workspaceGuardrails: workspace_guardrails_enabled? },
|
|
319
322
|
errors: true,
|
|
320
323
|
sessionUpdates: false
|
|
321
324
|
},
|
|
@@ -354,7 +357,7 @@ module Kward
|
|
|
354
357
|
apiKeyProviders: ["openrouter"],
|
|
355
358
|
logout: true
|
|
356
359
|
},
|
|
357
|
-
memory: { supported: true, optIn: true, defaultEnabled: false, autoSummaryDefaultEnabled: false, promptInjection: "interactive", storage: { core: "json", soft: "jsonl", events: "jsonl" }, methods: ["memory/status", "memory/enable", "memory/disable", "memory/autoSummary/enable", "memory/autoSummary/disable", "memory/list", "memory/add", "memory/addCore", "memory/forget", "memory/promote", "memory/inspect", "memory/why", "memory/summarize"] },
|
|
360
|
+
memory: { supported: true, optIn: true, defaultEnabled: false, autoSummaryDefaultEnabled: false, promptInjection: "interactive", storage: { core: "json", soft: "jsonl", events: "jsonl" }, 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"] },
|
|
358
361
|
commands: { supported: true, methods: ["commands/list", "commands/run"], method: "commands/list", runMethod: "commands/run", sources: ["builtin", "prompt", "skill", "plugin"], executableSources: ["builtin", "plugin"] },
|
|
359
362
|
startupResources: { supported: true, method: "resources/startup" },
|
|
360
363
|
starterPack: { supported: false, reason: "cliOnlyInstallCommand" },
|
|
@@ -365,7 +368,7 @@ module Kward
|
|
|
365
368
|
input: false,
|
|
366
369
|
editor: false,
|
|
367
370
|
widgets: false,
|
|
368
|
-
footer:
|
|
371
|
+
footer: { supported: true, notification: "ui/footer" },
|
|
369
372
|
custom: false,
|
|
370
373
|
terminalInput: false
|
|
371
374
|
},
|
|
@@ -393,15 +396,7 @@ module Kward
|
|
|
393
396
|
categories: ["tokens", "performance", "tools", "errors"],
|
|
394
397
|
rotation: { maxBytes: TelemetryLogger::DEFAULT_MAX_BYTES, retention: "manual" },
|
|
395
398
|
content: "redacted-metadata-only"
|
|
396
|
-
}
|
|
397
|
-
session: { mode: "explicit", persistence: "jsonl" },
|
|
398
|
-
cancellation: { behavior: "best-effort", queuedTurns: "cancel-before-run", runningTurns: "stop-emitting-events-when-possible" },
|
|
399
|
-
eventReplay: { behavior: "recent-in-memory", persisted: false, limit: SessionManager::RECENT_EVENT_LIMIT },
|
|
400
|
-
uiQuestion: { supported: true, method: "ui/answerQuestion", notification: "ui/question", maxQuestions: 4, multiSelect: false },
|
|
401
|
-
prompts: { supported: true, methods: ["prompts/list", "prompts/expand"] },
|
|
402
|
-
skills: { supported: true, tool: "read_skill" },
|
|
403
|
-
tools: { supported: true, method: "tools/list", eventMetadata: true },
|
|
404
|
-
config: { supported: true, methods: ["config/read", "config/update"] }
|
|
399
|
+
}
|
|
405
400
|
}
|
|
406
401
|
end
|
|
407
402
|
|
|
@@ -467,6 +462,7 @@ module Kward
|
|
|
467
462
|
def runtime_reload(params)
|
|
468
463
|
@session_manager.runtime_state(session_id: params.fetch("sessionId"))
|
|
469
464
|
@session_manager.refresh_client_config
|
|
465
|
+
@session_manager.reload_plugins
|
|
470
466
|
{ ok: true, message: "Resources reloaded." }
|
|
471
467
|
end
|
|
472
468
|
|
|
@@ -503,15 +499,6 @@ module Kward
|
|
|
503
499
|
}
|
|
504
500
|
end
|
|
505
501
|
builtins = [
|
|
506
|
-
{
|
|
507
|
-
name: "crew",
|
|
508
|
-
description: "Reserved for future crew commands.",
|
|
509
|
-
argumentHint: "",
|
|
510
|
-
source: "builtin",
|
|
511
|
-
executable: false,
|
|
512
|
-
unsupported: true,
|
|
513
|
-
reason: "notImplemented"
|
|
514
|
-
},
|
|
515
502
|
{
|
|
516
503
|
name: "copy",
|
|
517
504
|
description: "CLI-only clipboard copy; RPC clients own their clipboard.",
|
|
@@ -608,6 +595,18 @@ module Kward
|
|
|
608
595
|
end
|
|
609
596
|
end
|
|
610
597
|
|
|
598
|
+
def configured_workspace(root = Dir.pwd)
|
|
599
|
+
Workspace.new(root: root, guardrails: workspace_guardrails_enabled?)
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def workspace_guardrails_enabled?
|
|
603
|
+
ConfigFiles.workspace_guardrails_enabled?(@config_manager.read(redacted: false))
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
def session_auto_resume_enabled?
|
|
607
|
+
ConfigFiles.session_auto_resume_enabled?(@config_manager.read(redacted: false))
|
|
608
|
+
end
|
|
609
|
+
|
|
611
610
|
def write_result(id, result)
|
|
612
611
|
@transport.write_message({ jsonrpc: JSONRPC_VERSION, id: id, result: Redactor.redact(result) })
|
|
613
612
|
end
|