kward 0.82.0 → 0.84.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/CHANGELOG.md +96 -15
- data/CONTRIBUTING.md +74 -0
- data/Gemfile.lock +8 -2
- data/README.md +21 -1
- data/Rakefile +46 -2
- data/SECURITY.md +31 -0
- data/doc/agent-tools.md +1 -0
- data/doc/api.md +4 -0
- data/doc/composer.md +2 -2
- data/doc/configuration.md +82 -20
- data/doc/editor.md +47 -22
- data/doc/files.md +12 -7
- data/doc/getting-started.md +3 -0
- data/doc/pan.md +19 -15
- data/doc/permissions.md +1 -0
- data/doc/platform-support.md +48 -0
- data/doc/releasing.md +12 -4
- data/doc/rpc.md +2 -2
- data/doc/sandboxing.md +5 -1
- data/doc/security.md +4 -3
- data/doc/shell.md +101 -60
- data/doc/tabs.md +3 -0
- data/doc/troubleshooting.md +12 -2
- data/doc/usage.md +7 -6
- data/kward.gemspec +5 -4
- data/lib/kward/agent.rb +7 -3
- data/lib/kward/ansi.rb +110 -10
- data/lib/kward/auth/anthropic_oauth.rb +7 -7
- data/lib/kward/cli/auth_commands.rb +34 -13
- data/lib/kward/cli/commands.rb +83 -62
- data/lib/kward/cli/doctor.rb +39 -17
- data/lib/kward/cli/hook_commands.rb +22 -12
- data/lib/kward/cli/interactive_turn.rb +144 -21
- data/lib/kward/cli/project_skills_commands.rb +8 -4
- data/lib/kward/cli/prompt_interface.rb +27 -0
- data/lib/kward/cli/rendering.rb +15 -9
- data/lib/kward/cli/runtime_helpers.rb +260 -55
- data/lib/kward/cli/slash_commands.rb +21 -12
- data/lib/kward/cli/tabs.rb +91 -13
- data/lib/kward/cli/tool_summaries.rb +14 -0
- data/lib/kward/cli.rb +55 -7
- data/lib/kward/cli_transcript_formatter.rb +11 -4
- data/lib/kward/compaction/token_estimator.rb +12 -6
- data/lib/kward/config_files.rb +94 -63
- data/lib/kward/detached_run.rb +44 -0
- data/lib/kward/editor_prompt.rb +46 -0
- data/lib/kward/editor_prompt_session.rb +28 -0
- data/lib/kward/interactive_pty_runner.rb +102 -28
- data/lib/kward/{ekwsh.rb → kwsh.rb} +103 -24
- data/lib/kward/kwshrc.rb +233 -0
- data/lib/kward/markdown_code_block.rb +136 -0
- data/lib/kward/model/client.rb +35 -39
- data/lib/kward/model/model_info.rb +3 -2
- data/lib/kward/model/payloads.rb +0 -2
- data/lib/kward/model/provider_catalog.rb +5 -0
- data/lib/kward/model/stream_parser.rb +20 -4
- data/lib/kward/pan/index.html.erb +3 -3
- data/lib/kward/pan/server.rb +23 -3
- data/lib/kward/persistent_shell_session.rb +843 -0
- data/lib/kward/project_files.rb +19 -6
- data/lib/kward/prompt_interface/composer_renderer.rb +45 -41
- data/lib/kward/prompt_interface/composer_state.rb +33 -24
- data/lib/kward/prompt_interface/editor/auto_indent.rb +27 -22
- data/lib/kward/prompt_interface/editor/controller.rb +99 -33
- data/lib/kward/prompt_interface/editor/endwise.rb +13 -4
- data/lib/kward/prompt_interface/editor/modes/modern.rb +4 -0
- data/lib/kward/prompt_interface/editor/modes/vibe.rb +298 -47
- data/lib/kward/prompt_interface/editor/renderer.rb +109 -6
- data/lib/kward/prompt_interface/editor/runner.rb +362 -0
- data/lib/kward/prompt_interface/editor/runner_state.rb +78 -0
- data/lib/kward/prompt_interface/editor/state.rb +21 -10
- data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +68 -6
- data/lib/kward/prompt_interface/editor/vibe_state.rb +3 -3
- data/lib/kward/prompt_interface/editor/word_completion.rb +124 -0
- data/lib/kward/prompt_interface/file_overlay.rb +92 -22
- data/lib/kward/prompt_interface/key_handler.rb +75 -0
- data/lib/kward/prompt_interface/overlay_renderer.rb +7 -5
- data/lib/kward/prompt_interface/project_browser.rb +443 -17
- data/lib/kward/prompt_interface/runtime_state.rb +55 -2
- data/lib/kward/prompt_interface/screen.rb +2 -2
- data/lib/kward/prompt_interface/selection_prompt.rb +3 -1
- data/lib/kward/prompt_interface/slash_overlay.rb +19 -4
- data/lib/kward/prompt_interface/transcript_renderer.rb +12 -7
- data/lib/kward/prompt_interface.rb +169 -18
- data/lib/kward/prompts/commands.rb +2 -1
- data/lib/kward/prompts.rb +1 -1
- data/lib/kward/pty_output_sink.rb +47 -0
- data/lib/kward/rpc/auth_manager.rb +1 -1
- data/lib/kward/rpc/server.rb +2 -1
- data/lib/kward/rpc/transcript_normalizer.rb +7 -3
- data/lib/kward/scratchpad_languages.rb +74 -0
- data/lib/kward/scratchpad_runner.rb +155 -29
- data/lib/kward/shell_prompt.rb +52 -0
- data/lib/kward/shell_prompt_session.rb +58 -0
- data/lib/kward/terminal_keys.rb +13 -0
- data/lib/kward/terminal_text.rb +121 -0
- data/lib/kward/text_matcher.rb +18 -0
- data/lib/kward/tools/open_editor.rb +41 -0
- data/lib/kward/tools/prepare_shell_command.rb +28 -0
- data/lib/kward/tools/registry.rb +75 -8
- data/lib/kward/tools/replace_editor_buffer.rb +30 -0
- data/lib/kward/tools/run_shell_command.rb +24 -6
- data/lib/kward/tools/tool_call.rb +2 -1
- data/lib/kward/version.rb +1 -1
- data/templates/default/fulldoc/html/css/kward.css +0 -125
- data/templates/default/fulldoc/html/images/kward_workflow.svg +52 -0
- data/templates/default/fulldoc/html/setup.rb +1 -1
- data/templates/default/kward_navigation.rb +1 -0
- data/templates/default/layout/html/footer.erb +10 -0
- data/templates/default/layout/html/headers.erb +23 -0
- data/templates/default/layout/html/layout.erb +6 -18
- data/templates/default/layout/html/setup.rb +41 -2
- metadata +44 -8
- data/templates/default/fulldoc/html/images/kward_screen_1.png +0 -0
data/doc/releasing.md
CHANGED
|
@@ -60,13 +60,21 @@ If preparation fails before the commit, the command restores the version, lockfi
|
|
|
60
60
|
A pushed `v*` tag starts `.github/workflows/release.yml`. The workflow:
|
|
61
61
|
|
|
62
62
|
1. Checks that the tag, gem version, and changelog heading agree.
|
|
63
|
-
2.
|
|
63
|
+
2. Installs and enables Bubblewrap, then runs the full test suite and generated-documentation checks against Ruby 3.4 using the same Linux sandbox setup as normal CI.
|
|
64
64
|
3. Builds the gem and verifies its packaged files.
|
|
65
65
|
4. Publishes through RubyGems trusted publishing.
|
|
66
|
-
5.
|
|
67
|
-
6. Creates `Kward VERSION` as a GitHub Release using that version's changelog section and attaches the verified
|
|
66
|
+
5. Downloads the canonical published gem from RubyGems.org, waiting for propagation when necessary, and verifies its checksum against the RubyGems API.
|
|
67
|
+
6. Creates `Kward VERSION` as a GitHub Release using that version's changelog section and attaches the verified RubyGems artifact.
|
|
68
68
|
|
|
69
|
-
The publishing job uses the protected `release` environment. If RubyGems.org already has the version after a partially completed workflow, a rerun
|
|
69
|
+
The publishing job uses the protected `release` environment. If RubyGems.org already has the version after a partially completed workflow, a rerun downloads and verifies the canonical published gem before continuing. This also accommodates trusted-publishing attestations that can change the published gem bytes. For an existing GitHub Release, the workflow downloads and compares the gem, uploads it when missing, and publishes an unfinished draft. This makes normal workflow reruns safe without silently replacing mismatched artifacts.
|
|
70
|
+
|
|
71
|
+
If the workflow itself needs a fix after a tag has already been pushed, commit and push the fix to `main`, then recover the existing tag with the updated workflow:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
gh workflow run Release --ref main -f tag=v0.82.0
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Manual recovery still checks out and verifies the tagged source before publishing. The `release` environment permits automatic version-tag runs and manual recovery runs from `main` only.
|
|
70
78
|
|
|
71
79
|
Follow the run from the repository's **Actions → Release** page. Installation can be checked after publication with:
|
|
72
80
|
|
data/doc/rpc.md
CHANGED
|
@@ -80,11 +80,11 @@ Read `capabilities` at runtime instead of assuming every feature is available. I
|
|
|
80
80
|
- `mcp`: local stdio MCP server support through the shared `mcpServers` config. RPC exposes MCP tools to turns and advertises discovery with `methods: ["tools/list", "mcp/status"]`, `toolMetadata: true`, and `serverStatus: true`. It does not support MCP resources, prompts, sampling, or Streamable HTTP.
|
|
81
81
|
- `startupResources`: supported startup resource listing for context, skills, prompts, and plugins.
|
|
82
82
|
- `extensionUi`: question bridge support via `ui/question` and `ui/answerQuestion`, plus plugin footer updates via `ui/footer`; other UI primitives are explicitly unsupported.
|
|
83
|
-
- `composer`: composer-only UI features. Interactive session diff totals are explicitly unsupported over RPC (`composer.sessionDiff.supported: false`) because RPC clients already receive per-tool diff results and no live composer status payload is exposed. Clipboard copy is also unsupported over RPC (`composer.copy.supported: false`) because UI clients own clipboard access.
|
|
83
|
+
- `composer`: composer-only UI features. Interactive session diff totals are explicitly unsupported over RPC (`composer.sessionDiff.supported: false`) because RPC clients already receive per-tool diff results and no live composer status payload is exposed. Clipboard copy is also unsupported over RPC (`composer.copy.supported: false`) because UI clients own clipboard access. Vibe editor prompts are unsupported over RPC (`composer.editorPrompt.supported: false`) because RPC has no live integrated editor buffer.
|
|
84
84
|
- `security`: trusted-local behavior and optional per-turn tool approval. By default, RPC turns have no workspace mutation guard or tool approval, so shell commands and file changes can run. Clients can inspect file-tool guardrails through `capabilities.events.tools.workspaceGuardrails` and `runtime/state.workspaceGuardrailsEnabled`. `security.sandbox` reports the command sandbox mode, enforcement backend, and filesystem and network capabilities; session pinning and one-time elevation are unsupported. See [Command sandboxing](sandboxing.md) for the boundary and its limits.
|
|
85
85
|
- `export`: supported transcript export formats. Currently `markdown` and `html`; default is `markdown`.
|
|
86
86
|
- `starterPack`: explicitly unsupported (`supported: false`, reason `cliOnlyInstallCommand`). Use `kward init` from the shell.
|
|
87
|
-
- `shell`: explicitly unsupported (`supported: false`, reason `interactiveTuiOnly`) because `/shell`, `!command`, `/capture`, and PTY handoff require the local TUI. Model-requested `run_shell_command` tools remain bounded, captured, and noninteractive over RPC.
|
|
87
|
+
- `shell`: explicitly unsupported (`supported: false`, reason `interactiveTuiOnly`) because `/shell`, its transient `?` shell assistant, `!command`, `/capture`, and PTY handoff require the local TUI. Model-requested `run_shell_command` tools remain bounded, captured, and noninteractive over RPC.
|
|
88
88
|
- `logging`: local redacted telemetry, its directory and enabled categories, `logging/stats` and `logging/tokenCsv`, bucketed `usageCsv` support, JSONL storage, and 10 MB rotation with manual retention. Logs contain redacted metadata only. Configuration uses the `logging` key and `KWARD_LOGGING` environment prefix.
|
|
89
89
|
|
|
90
90
|
### `shutdown`
|
data/doc/sandboxing.md
CHANGED
|
@@ -106,12 +106,16 @@ this interface.
|
|
|
106
106
|
## Boundaries and limits
|
|
107
107
|
|
|
108
108
|
The current implementation protects **model-requested command workers only**.
|
|
109
|
+
The transient `?` shell assistant is intentionally not one of those workers: its
|
|
110
|
+
`run_shell_command` calls use the active user-owned `/shell` process so shell
|
|
111
|
+
state can persist.
|
|
112
|
+
|
|
109
113
|
It does not sandbox:
|
|
110
114
|
|
|
111
115
|
- the Kward Ruby host process;
|
|
112
116
|
- model-provider, search-provider, or RPC traffic;
|
|
113
117
|
- trusted Ruby plugins;
|
|
114
|
-
- MCP servers, lifecycle hooks, `/shell`, `!command`, `/capture`, or `/pty`.
|
|
118
|
+
- MCP servers, lifecycle hooks, `/shell`, `?` shell-agent commands, `!command`, `/capture`, or `/pty`.
|
|
115
119
|
|
|
116
120
|
Sandboxed command workers receive a minimal environment: Kward preserves only
|
|
117
121
|
basic terminal, locale, and path variables, then supplies a private `HOME` and
|
data/doc/security.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Kward can read code, edit files, run commands, call model and search providers, and load local extensions. That makes it useful, but it also means you should treat it like a developer tool running with your account—not like a sandbox.
|
|
4
4
|
|
|
5
|
-
This guide explains the trust boundaries and gives you a safe way to start work in an unfamiliar repository.
|
|
5
|
+
This guide explains the trust boundaries and gives you a safe way to start work in an unfamiliar repository. Report suspected vulnerabilities privately through the [security policy](https://github.com/kaiwood/kward/blob/main/SECURITY.md).
|
|
6
6
|
|
|
7
7
|
## The short version
|
|
8
8
|
|
|
@@ -56,8 +56,9 @@ Kward's built-in file tools normally resolve paths inside the active workspace.
|
|
|
56
56
|
|
|
57
57
|
These protections reduce accidental edits. They do not contain the whole process:
|
|
58
58
|
|
|
59
|
-
- With `sandbox.mode: off` (the default), `run_shell_command`, `!command`, `/capture`, `/shell`,
|
|
60
|
-
-
|
|
59
|
+
- With `sandbox.mode: off` (the default), `run_shell_command`, `!command`, `/capture`, `/shell`, `/pty`, and editor buffer runners run with your user permissions.
|
|
60
|
+
- Editor buffer runners are user-directed and execute the current in-memory buffer, including normal files and scratchpads, through the configured `editor.runners` binary without a shell. They are not covered by the command sandbox.
|
|
61
|
+
- A non-off [command sandbox](sandboxing.md) restricts only model-requested `run_shell_command` workers and their descendants. It does not cover `!command`, `/capture`, `/shell`, or `/pty`, including commands that the transient `?` shell assistant runs through the user's persistent `/shell` process.
|
|
61
62
|
- External `/shell` commands, `!command`, and `/pty` receive an interactive PTY. Kward forwards a conservative set of line-oriented controls into the inline region, then grants full-terminal passthrough when a child emits screen-oriented or unknown controls. Full passthrough bypasses transcript control-sequence sanitization, so run only commands you trust with terminal access. `capture <command>` and `/capture <command>` sanitize their captured output.
|
|
62
63
|
- Plugins, command hooks, and MCP servers are local processes with the same general operating-system access.
|
|
63
64
|
- Read-before-edit applies to Kward's file tools, not to arbitrary shell commands or extension code.
|
data/doc/shell.md
CHANGED
|
@@ -4,6 +4,7 @@ Kward lets you run your own shell commands without leaving the interactive TUI.
|
|
|
4
4
|
|
|
5
5
|
- **For one quick command, use `!command`.** It runs from the active workspace and returns you to the normal composer when it finishes.
|
|
6
6
|
- **For a longer stretch of shell work, use `/shell`.** It keeps its directory, environment, aliases, and history between commands.
|
|
7
|
+
- **To ask Kward for help from inside `/shell`, prefix the request with `?`.** It can inspect the latest shell output, run an explicitly requested state change, or prepare a command in the shell prompt for your confirmation.
|
|
7
8
|
- **For bounded output in the transcript view, use `/capture <command>`.** Inside `/shell`, use `capture <command>` for the same kind of readable output while keeping the shell's current state.
|
|
8
9
|
|
|
9
10
|
Ordinary `!command` input and external commands inside `/shell` receive an interactive PTY. Pagers, Vim, SSH, REPLs, password prompts, and other interactive tools therefore work without a `pty` prefix.
|
|
@@ -20,15 +21,14 @@ Prefix a command with `!` in the normal composer:
|
|
|
20
21
|
|
|
21
22
|
The command runs from the active workspace root and begins in an inline PTY region above a frozen composer. Line-oriented output, single-line carriage-return progress, and synchronized-output update brackets scroll the transcript area naturally while keyboard input belongs to the child process. If the child emits alternate-screen, clear-screen, absolute cursor, or unknown terminal controls, Kward conservatively hides the composer and switches permanently to full-terminal passthrough for the rest of that command. Pagers and full-screen applications therefore retain the complete terminal without relying on a command-name allowlist.
|
|
22
23
|
|
|
23
|
-
When an inline command exits without reading input, safe output is mirrored into the transient transcript view so a repaint cannot hide it. Carriage-return and horizontal-cursor progress redraws are reduced to their final visible lines, while an unterminated synchronized-output update is closed before Kward redraws. If the child reads input, Kward retains only output captured before the first forwarded input byte; this prevents echoed passwords, OTPs, or other input from entering tab state.
|
|
24
|
+
When an inline command exits without reading input, safe output is mirrored into the transient transcript view so a repaint cannot hide it. Carriage-return and horizontal-cursor progress redraws are reduced to their final visible lines, while an unterminated synchronized-output update is closed before Kward redraws. If the child reads input, Kward retains only output captured before the first forwarded input byte; this prevents echoed passwords, OTPs, or other input from entering tab state. Output from one-off commands is never added to the AI conversation or sent to the model.
|
|
24
25
|
|
|
25
|
-
Shell output can leave transient text in the transcript area. **After the command finishes, press Ctrl+L to redraw the durable conversation and clear that transient `!command` output.** While an interactive command
|
|
26
|
+
Shell output can leave transient text in the transcript area. **After the command finishes, press Ctrl+L to redraw the durable conversation and clear that transient `!command` output.** While an interactive command owns the terminal, the composer remains frozen and ordinary keyboard input belongs to the child process. Kward's tab shortcuts are intercepted separately; switching tabs detaches the command and lets it continue in the originating tab's bounded background state.
|
|
26
27
|
|
|
27
|
-
Configured `
|
|
28
|
+
Configured `kwshrc` aliases also work after `!`:
|
|
28
29
|
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
glog: "git log --decorate --stat --graph"
|
|
30
|
+
```sh
|
|
31
|
+
alias glog='git log --decorate --stat --graph'
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
```text
|
|
@@ -37,9 +37,8 @@ aliases:
|
|
|
37
37
|
|
|
38
38
|
An alias that resolves to `kward edit <filename>` opens Kward's integrated editor in the current session instead of starting a nested Kward process:
|
|
39
39
|
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
vibe: "kward edit"
|
|
40
|
+
```sh
|
|
41
|
+
alias vibe='kward edit'
|
|
43
42
|
```
|
|
44
43
|
|
|
45
44
|
```text
|
|
@@ -90,6 +89,31 @@ Leave shell mode with `exit`, `logout`, or Ctrl+D on an empty prompt.
|
|
|
90
89
|
|
|
91
90
|
`cd` changes only the embedded shell's directory. It does not change Kward's workspace root or the directory used by the model's other tools.
|
|
92
91
|
|
|
92
|
+
## Ask the shell agent
|
|
93
|
+
|
|
94
|
+
While `/shell` is active, start a submitted line with `?` to ask the transient shell assistant:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
? why did the last command fail?
|
|
98
|
+
? show me which process is listening on port 3000
|
|
99
|
+
? prepare a command to find Ruby files changed today
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The assistant receives the current shell directory, the last command, its exit status, and bounded output from that command. Output is sent to the model only because you explicitly asked with `?`; it is sanitized and bounded before being included, and shell-agent turns are not added to the normal session history.
|
|
103
|
+
|
|
104
|
+
If you explicitly ask the assistant to change shell state, it can use the active shell session:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
? cd into test
|
|
108
|
+
? set RAILS_ENV to test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
For a suggestion or prepared command, the assistant uses `prepare_shell_command`. The command is placed in the shell composer but is not run until you press `Enter`. Running a command directly and preparing one are deliberately separate actions.
|
|
112
|
+
|
|
113
|
+
If you explicitly ask it to open an existing workspace file, the assistant uses `open_editor` to open Kward's integrated editor. Opening the editor does not modify or save the file.
|
|
114
|
+
|
|
115
|
+
The shell assistant cannot safely run commands that require terminal input. Ask it to prepare those commands instead. The local `/shell` session keeps one interactive shell process alive, so directory changes, variables, functions, aliases, and other shell state persist between commands. The one-off `!command` and `/capture` workflows remain separate. SSH remains available through the normal interactive PTY handoff, but shell-agent prompting resumes after that SSH session exits.
|
|
116
|
+
|
|
93
117
|
## Interactive and captured commands
|
|
94
118
|
|
|
95
119
|
External commands inside `/shell` are interactive by default:
|
|
@@ -101,19 +125,19 @@ ruby
|
|
|
101
125
|
ssh example.com
|
|
102
126
|
```
|
|
103
127
|
|
|
104
|
-
Kward gives each command the terminal, forwards keyboard input, and restores the shell prompt when the command exits. It prints the submitted command but no PTY start message or exit-status summary. The line-oriented Git commands `git fetch`, `git ls-remote`, `git push`, `git remote`, and `git status` keep the shell prompt visible as a frozen display. Safe, line-oriented output from commands that did not read keyboard input is kept in the transient transcript view; full-screen and genuinely interactive output stays terminal-owned.
|
|
128
|
+
Kward gives each command the terminal, forwards keyboard input, and restores the shell prompt when the command exits. Interactive commands inherit your normal pager configuration, so commands such as `git log` can open `less` in full-screen mode. Kward suppresses Git paging only for noninteractive shell-agent and `capture` executions. It prints the submitted command but no PTY start message or exit-status summary. The line-oriented Git commands `git fetch`, `git ls-remote`, `git push`, `git remote`, and `git status` keep the shell prompt visible as a frozen display. Safe, line-oriented output from commands that did not read keyboard input is kept in the transient transcript view; full-screen and genuinely interactive output stays terminal-owned.
|
|
105
129
|
|
|
106
130
|
Use `capture` inside `/shell` when you want ordinary, readable output in Kward's transcript area instead of direct terminal control:
|
|
107
131
|
|
|
108
132
|
```sh
|
|
109
133
|
capture git status --short
|
|
110
|
-
capture bundle exec ruby -Itest test/
|
|
134
|
+
capture bundle exec ruby -Itest test/test_kwsh.rb
|
|
111
135
|
```
|
|
112
136
|
|
|
113
|
-
An `
|
|
137
|
+
An `kwsh` `capture` command:
|
|
114
138
|
|
|
115
139
|
- does not receive keyboard input,
|
|
116
|
-
- uses
|
|
140
|
+
- uses kwsh's built-in timeout and output-size limits,
|
|
117
141
|
- preserves safe color and styling,
|
|
118
142
|
- strips controls that could corrupt Kward's TUI,
|
|
119
143
|
- can be cancelled with Ctrl+C.
|
|
@@ -139,9 +163,9 @@ Each Kward tab owns its `/shell` state. Switching away and back restores that ta
|
|
|
139
163
|
- runtime aliases,
|
|
140
164
|
- shell prompt and transcript view.
|
|
141
165
|
|
|
142
|
-
Shell commands use a separate, workspace-scoped history rather than the normal chat-prompt history.
|
|
166
|
+
Shell commands use a separate, workspace-scoped history rather than the normal chat-prompt history. The shell-history limit is a built-in kwsh default.
|
|
143
167
|
|
|
144
|
-
Kward's tab shortcuts work at the shell prompt and while a
|
|
168
|
+
Kward's tab shortcuts work at the shell prompt and while a shell command is running. Switching tabs detaches the running command instead of interrupting it; bounded output and completion state remain owned by the originating tab and are restored when you return. While detached, the command no longer receives terminal input. Explicit cancellation or shutdown still terminates detached work. Bounded output from shell-agent `?` turns is also retained in the tab's transient runtime view, so it is restored when you switch away and back without being added to session history. Ctrl+L clears this transient shell and shell-agent output.
|
|
145
169
|
|
|
146
170
|
## Completion
|
|
147
171
|
|
|
@@ -179,13 +203,14 @@ When several candidates match, repeated Tab presses cycle through them and wrap
|
|
|
179
203
|
|
|
180
204
|
## Built-ins
|
|
181
205
|
|
|
182
|
-
|
|
206
|
+
The persistent `/shell` process handles these commands in-session so their state can persist:
|
|
183
207
|
|
|
184
208
|
| Built-in | What it does |
|
|
185
209
|
| --- | --- |
|
|
186
210
|
| `cd [dir]` | Change the shell directory. Supports `cd`, `cd -`, and relative paths. |
|
|
187
211
|
| `pwd` | Print the shell directory. |
|
|
188
212
|
| `export KEY[=value]` | Set an environment variable. `export` and `export -p` list variables. |
|
|
213
|
+
| `source <file>` / `. <file>` | Parse and apply aliases and exports from an rc file immediately. |
|
|
189
214
|
| `unset KEY` | Remove an environment variable. |
|
|
190
215
|
| `alias [name]` | List, inspect, or create aliases. |
|
|
191
216
|
| `unalias name` / `unalias -a` | Remove aliases. |
|
|
@@ -196,81 +221,97 @@ When several candidates match, repeated Tab presses cycle through them and wrap
|
|
|
196
221
|
|
|
197
222
|
Built-ins take precedence over aliases and executables.
|
|
198
223
|
|
|
199
|
-
## Configure
|
|
224
|
+
## Configure kwsh
|
|
200
225
|
|
|
201
|
-
Global shell configuration lives
|
|
226
|
+
Global shell configuration lives in these optional rc files, loaded in order:
|
|
202
227
|
|
|
203
228
|
```text
|
|
204
|
-
~/.kward/
|
|
229
|
+
~/.kward/kwshrc
|
|
230
|
+
~/.kwshrc
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
When `KWARD_CONFIG_PATH` selects another main config file, Kward reads the first file beside that config file instead. The later file overrides earlier aliases and exported variables with the same names. The rc format currently supports declarative `alias`, `export`, and `source` directives:
|
|
234
|
+
|
|
235
|
+
```sh
|
|
236
|
+
alias ll='ls -la'
|
|
237
|
+
alias gs="git status --short"
|
|
238
|
+
export BUNDLE_WITHOUT=production
|
|
239
|
+
export PATH="$HOME/bin:$PATH"
|
|
240
|
+
source ~/.kward/kwsh-aliases
|
|
205
241
|
```
|
|
206
242
|
|
|
207
|
-
|
|
243
|
+
`source` reads another rc file without executing it; relative paths in rc-file directives are resolved from the file containing the directive. When entered as a `/shell` builtin, the path is resolved from the current shell directory and its aliases and exports are applied immediately, without restarting Kward. Unsupported shell scripting is ignored for now.
|
|
208
244
|
|
|
209
|
-
|
|
245
|
+
The transient shell assistant normally follows the active conversation's model and reasoning effort. Configure it in the main JSON file:
|
|
210
246
|
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"shell": {
|
|
250
|
+
"agent": {
|
|
251
|
+
"provider": "openrouter",
|
|
252
|
+
"model": "openai/gpt-5.6-sol",
|
|
253
|
+
"reasoning_effort": "none"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The optional `provider` uses the lowercase configuration IDs listed in [Model providers](providers.md). When omitted, the shell assistant follows the active conversation. If a provider is explicitly configured without a model or reasoning effort, Kward uses that provider's defaults instead of inheriting the active conversation's values.
|
|
216
260
|
|
|
217
|
-
|
|
218
|
-
FORCE_COLOR: "1"
|
|
219
|
-
BUNDLE_WITHOUT: "production"
|
|
220
|
-
RAILS_ENV: "test"
|
|
261
|
+
Override those settings with environment variables:
|
|
221
262
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
glog: "git log --decorate --stat --graph"
|
|
227
|
-
be: "bundle exec"
|
|
228
|
-
t: "bundle exec ruby -Itest"
|
|
263
|
+
```sh
|
|
264
|
+
export KWSH_PROVIDER="openrouter"
|
|
265
|
+
export KWSH_MODE="openai/gpt-5.6-sol"
|
|
266
|
+
export KWSH_REASONING="none"
|
|
229
267
|
```
|
|
230
268
|
|
|
231
|
-
|
|
269
|
+
Environment variables take precedence over the JSON settings, and empty values are ignored.
|
|
270
|
+
|
|
271
|
+
### Runtime defaults
|
|
272
|
+
|
|
273
|
+
These runtime settings are built into kwsh and are not configurable through rc files:
|
|
232
274
|
|
|
233
275
|
| Setting | Default | What it does |
|
|
234
276
|
| --- | --- | --- |
|
|
235
|
-
| `shell` | `/bin/sh` |
|
|
236
|
-
| `timeout_seconds` | `300` | Maximum runtime for one captured command. |
|
|
237
|
-
| `max_output_bytes` | `1048576` | Maximum output retained for one captured command. |
|
|
277
|
+
| `shell` | `/bin/sh` | Absolute executable path for the persistent `/shell` process and interactive shell commands. |
|
|
278
|
+
| `timeout_seconds` | `300` | Maximum runtime for one captured or shell-agent command. |
|
|
279
|
+
| `max_output_bytes` | `1048576` | Maximum output retained for one captured or shell-agent command. |
|
|
238
280
|
| `history_limit` | `1000` | Maximum shell-history entries per workspace. |
|
|
239
281
|
|
|
240
|
-
Invalid or relative `shell` paths fall back to `/bin/sh`. These timeout and output limits apply
|
|
282
|
+
Invalid or relative `shell` paths fall back to `/bin/sh`. These timeout and output limits apply to `capture` inside `/shell` and shell-agent commands, not user-owned interactive commands or the separate `/capture` slash command.
|
|
241
283
|
|
|
242
284
|
### Environment
|
|
243
285
|
|
|
244
|
-
|
|
286
|
+
`export` values from rc files are applied when `/shell` starts and are also available to leading-`!` commands. Keys must be valid environment-variable names; invalid keys are ignored. Values support shell quoting and simple `$VAR`/`${VAR}` expansion.
|
|
245
287
|
|
|
246
288
|
Kward also supplies conservative terminal defaults:
|
|
247
289
|
|
|
248
290
|
```sh
|
|
249
|
-
CLICOLOR=1
|
|
250
|
-
COLORTERM=truecolor
|
|
251
|
-
TERM=xterm-256color # only when TERM is missing or dumb
|
|
291
|
+
export CLICOLOR=1
|
|
292
|
+
export COLORTERM=truecolor
|
|
293
|
+
export TERM=xterm-256color # only when TERM is missing or dumb
|
|
252
294
|
```
|
|
253
295
|
|
|
254
296
|
It does not force color. Set `FORCE_COLOR`, `CLICOLOR_FORCE`, or a command-specific option such as `--color=always` when needed.
|
|
255
297
|
|
|
256
|
-
When rbenv is available, Kward adds its shims and bin directories to `PATH` and supplies `RBENV_ROOT` if it was missing
|
|
298
|
+
When rbenv is available, Kward adds its shims and bin directories to `PATH` and supplies `RBENV_ROOT` if it was missing before starting `/shell`. The configured interactive shell may also load its normal startup files.
|
|
257
299
|
|
|
258
300
|
### Aliases
|
|
259
301
|
|
|
260
302
|
Aliases replace the first command word once and append any remaining arguments:
|
|
261
303
|
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
t: "bundle exec ruby -Itest"
|
|
304
|
+
```sh
|
|
305
|
+
alias ll='ls -la'
|
|
306
|
+
alias t='bundle exec ruby -Itest'
|
|
266
307
|
```
|
|
267
308
|
|
|
268
309
|
```sh
|
|
269
310
|
ll lib
|
|
270
311
|
# runs: ls -la lib
|
|
271
312
|
|
|
272
|
-
t test/
|
|
273
|
-
# runs: bundle exec ruby -Itest test/
|
|
313
|
+
t test/test_kwsh.rb
|
|
314
|
+
# runs: bundle exec ruby -Itest test/test_kwsh.rb
|
|
274
315
|
```
|
|
275
316
|
|
|
276
317
|
Configured aliases work inside `/shell` and after `!`. Aliases created with the `alias` built-in belong only to the current `/shell` session and are not shared with one-shot `!command` input.
|
|
@@ -281,17 +322,17 @@ Aliases are intentionally simple: they do not expand recursively and are not she
|
|
|
281
322
|
|
|
282
323
|
## Terminal output and safety
|
|
283
324
|
|
|
284
|
-
Interactive commands write directly to your terminal so full-screen tools can work. When a command does not read keyboard input and emits only line-oriented text plus safe color sequences, Kward mirrors that output into the transient transcript view after the command exits. Other interactive output is not sanitized and may contain terminal control sequences, so run only commands you trust with terminal access.
|
|
325
|
+
Interactive commands write directly to your terminal so full-screen tools can work. When a command does not read keyboard input and emits only line-oriented text plus safe color sequences, Kward mirrors that output into the transient transcript view after the command exits. Other interactive output is not sanitized and may contain terminal control sequences, so run only commands you trust with terminal access. Safe bounded output is included in a shell-agent request only when you explicitly use `?`; it is never sent to the model for ordinary shell commands.
|
|
285
326
|
|
|
286
327
|
Commands run with `capture` inside `/shell` preserve safe ANSI color and style sequences while removing cursor movement, clear-screen controls, title changes, alternate-screen controls, and similar sequences that could damage the TUI transcript.
|
|
287
328
|
|
|
288
329
|
## Limitations
|
|
289
330
|
|
|
290
|
-
|
|
331
|
+
The local `/shell` session is persistent, but it is not a complete terminal emulator or a remote-shell protocol:
|
|
291
332
|
|
|
292
|
-
-
|
|
293
|
-
-
|
|
294
|
-
-
|
|
295
|
-
- there is no login-shell readline integration,
|
|
333
|
+
- the one-off `!command` and `/capture` workflows do not share `/shell` state,
|
|
334
|
+
- shell state is held by the live process and is not serialized across Kward restarts,
|
|
335
|
+
- a stopped or unresponsive command can still require Ctrl+C or shell-session cleanup,
|
|
296
336
|
- full-screen terminal state is not retained after an interactive command exits,
|
|
297
|
-
-
|
|
337
|
+
- while an interactive SSH session owns the terminal, Kward cannot safely intercept `?` or provide remote cwd/completion context; shell-agent prompting resumes after SSH exits,
|
|
338
|
+
- safe line-oriented output may remain in the transient TUI transcript; only bounded safe output from an explicit `?` request enters the transient shell-agent context and none of it is added to the normal session history.
|
data/doc/tabs.md
CHANGED
|
@@ -39,6 +39,8 @@ A normal session tab can be activated in a linked Git worktree after you have re
|
|
|
39
39
|
|
|
40
40
|
```text
|
|
41
41
|
/tab worktree
|
|
42
|
+
# or
|
|
43
|
+
/worktree
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
When enabled, Kward keeps the same tab and transcript but rebuilds its agent against a new worktree. The tab label includes the worktree branch. The worktree is created from `HEAD`, so Kward warns when the original workspace is dirty and leaves those existing changes in the original checkout; it does not copy them automatically. `/tab worktree activate` is an explicit alias for the same action.
|
|
@@ -98,6 +100,7 @@ Tabs keep the conversations separate, so context from one tab does not automatic
|
|
|
98
100
|
| `/tab worktree merge` | Merge the current worktree branch into the branch checked out in its original workspace |
|
|
99
101
|
| `/tab worktree merge abort` | Abort a conflicted worktree merge in the original workspace |
|
|
100
102
|
| `/tab worktree remove` | Remove a clean linked worktree and keep its branch |
|
|
103
|
+
| `/worktree …` | Alias for `/tab worktree …` on the active tab |
|
|
101
104
|
| `/tab move left` | Move the current tab one slot left |
|
|
102
105
|
| `/tab move right` | Move the current tab one slot right |
|
|
103
106
|
| `/tab move <number>` | Move the current tab to a numbered position |
|
data/doc/troubleshooting.md
CHANGED
|
@@ -10,14 +10,24 @@ This page covers common issues and how to diagnose them. When something is not w
|
|
|
10
10
|
kward doctor
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
It checks that your config file is readable and valid JSON, that the config and session directories are writable, that the workspace exists, which provider and model are active, and which credentials are configured.
|
|
13
|
+
It checks that your config file is readable and valid JSON, that the config and session directories are writable, that the workspace exists, which provider and model are active, and which credentials are configured. Core check failures produce a nonzero exit status, so the command can also guard setup scripts. Optional features such as Pan are reported separately and do not make an otherwise healthy setup fail.
|
|
14
14
|
|
|
15
|
-
`kward auth status` gives a focused view of credentials only, also without printing secrets:
|
|
15
|
+
`kward auth status` gives a focused view of configured credentials only, also without printing secrets:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
kward auth status
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
Use `kward auth status --all` when you also want to see every unconfigured provider.
|
|
22
|
+
|
|
23
|
+
Kward keeps normal command failures concise. To include a Ruby backtrace while diagnosing an unexpected failure, rerun the command with debug errors enabled:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
KWARD_DEBUG=1 kward "Repeat the failing task"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Backtraces can include local paths and implementation details. Review them before sharing them publicly.
|
|
30
|
+
|
|
21
31
|
## Authentication errors and token expiration
|
|
22
32
|
|
|
23
33
|
OAuth tokens expire. Kward refreshes access tokens automatically when a refresh token is available, but if the refresh token is missing or expired, requests fail with a provider-specific error:
|
data/doc/usage.md
CHANGED
|
@@ -66,7 +66,7 @@ Inside interactive mode, ask Kward to run a command:
|
|
|
66
66
|
Run the focused test for the CLI status command.
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
Or run an interactive PTY command yourself from the composer by prefixing it with `!`. Aliases configured in `
|
|
69
|
+
Or run an interactive PTY command yourself from the composer by prefixing it with `!`. Aliases configured in `kwshrc` are expanded here too:
|
|
70
70
|
|
|
71
71
|
```text
|
|
72
72
|
!git status --short
|
|
@@ -78,7 +78,7 @@ For several commands, enter the embedded Kward shell:
|
|
|
78
78
|
/shell
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
`/shell` opens `
|
|
81
|
+
`/shell` opens `kwsh`, a Kward-native command mode with one persistent local shell process. It preserves state such as the current directory, environment variables, functions, and aliases between commands. Prefix a line with `?` inside `/shell` to ask a transient shell assistant about the latest output, execute an explicit state change, or prepare a command without running it. External commands receive an interactive PTY by default, so `git log`, `less`, Vim, SSH, and REPLs work without a prefix. Use `capture <command>` inside `/shell` or `/capture <command>` from the normal composer for bounded, transcript-friendly output. See [Embedded shell](shell.md) for built-ins, completion, configuration, ANSI handling, PTY passthrough, and limitations.
|
|
82
82
|
|
|
83
83
|
## Shell commands
|
|
84
84
|
|
|
@@ -123,7 +123,7 @@ Slash commands run local actions in the current session. Most do not send a prom
|
|
|
123
123
|
| `/git` | review uncommitted changes, stage files, and commit. |
|
|
124
124
|
| `/diff` | open the file changes recorded in the current session. |
|
|
125
125
|
| `/files` | browse project files in a nested tree and open them in the editor. |
|
|
126
|
-
| `/shell` | run stateful workspace commands with interactive PTY support
|
|
126
|
+
| `/shell` | run stateful workspace commands with interactive PTY support and ask the shell agent with `?`. |
|
|
127
127
|
| `/capture <command>` | run a bounded one-shot command and retain its output in the transcript. |
|
|
128
128
|
| `/pty <command>` | explicitly hand the terminal to an interactive command; retained for compatibility with existing workflows. |
|
|
129
129
|
| `/settings` | configure models, accounts, memory, interface, tools, context, personalization, and logging. |
|
|
@@ -143,6 +143,7 @@ Slash commands run local actions in the current session. Most do not send a prom
|
|
|
143
143
|
| `/tab worktree merge` | merge a clean worktree branch into the branch checked out in its original workspace. |
|
|
144
144
|
| `/tab worktree merge abort` | abort a conflicted worktree merge in the original workspace. |
|
|
145
145
|
| `/tab worktree remove` | remove a clean linked worktree while keeping its branch. |
|
|
146
|
+
| `/worktree …` | alias for `/tab worktree …` on the active tab. |
|
|
146
147
|
| `/session` | open the saved sessions picker or continue a previous session by path. |
|
|
147
148
|
| `/resume` | alias for `/session`. |
|
|
148
149
|
| `/session name <name>` | name or clear the current session. |
|
|
@@ -159,7 +160,7 @@ Slash commands run local actions in the current session. Most do not send a prom
|
|
|
159
160
|
| `/skill <name>` | activate a configured skill explicitly for the current session. |
|
|
160
161
|
| `/stats [range]` | summarize enabled local telemetry. |
|
|
161
162
|
| `/hooks ...` | inspect, diagnose, trust, or untrust lifecycle hooks. |
|
|
162
|
-
| `/scratchpad [
|
|
163
|
+
| `/scratchpad [language|help]` | open an unsaved, syntax-highlighted editor buffer; `/scratchpad` alone opens plain text. |
|
|
163
164
|
| `/redraw` | fix terminal drawing after resize or glitches. |
|
|
164
165
|
| `/reload` | reload installed plugins. |
|
|
165
166
|
| `/exit` | leave Kward. |
|
|
@@ -262,13 +263,13 @@ This screenshot shows the broken layout. Find the likely CSS issue.
|
|
|
262
263
|
|
|
263
264
|
## Pan mode
|
|
264
265
|
|
|
265
|
-
Pan mode starts a mobile-friendly
|
|
266
|
+
Pan mode starts a mobile-friendly local web UI:
|
|
266
267
|
|
|
267
268
|
```bash
|
|
268
269
|
kward --working-directory ~/code/project pan
|
|
269
270
|
```
|
|
270
271
|
|
|
271
|
-
|
|
272
|
+
Pan binds to loopback by default. Exposing it to a trusted LAN requires an explicit host setting and prints a warning because Pan uses plain HTTP. It exposes file, shell, web, and configured extension tools through a browser UI and requires a configured username plus a config or environment password. Pan saves conversations to the normal workspace session store; its session drawer can create, resume, rename, and delete sessions. Session changes are disabled while turns are active or queued. See [Pan mode](pan.md) for setup, browser workflows, security, and limitations.
|
|
272
273
|
|
|
273
274
|
## RPC backend
|
|
274
275
|
|
data/kward.gemspec
CHANGED
|
@@ -6,16 +6,16 @@ Gem::Specification.new do |spec|
|
|
|
6
6
|
spec.authors = ["Kai Wood"]
|
|
7
7
|
spec.email = ["kai.wood@icloud.com"]
|
|
8
8
|
|
|
9
|
-
spec.summary = "An
|
|
10
|
-
spec.description = "Kward is
|
|
11
|
-
spec.homepage = "https://github.
|
|
9
|
+
spec.summary = "An extensible Ruby coding agent for your terminal."
|
|
10
|
+
spec.description = "Kward is an extensible Ruby coding agent with workspace tools, resumable sessions, multiple model providers, a local browser UI, and JSON-RPC integrations."
|
|
11
|
+
spec.homepage = "https://kaiwood.github.io/kward/"
|
|
12
12
|
spec.license = "MIT"
|
|
13
13
|
spec.required_ruby_version = ">= 3.4"
|
|
14
14
|
|
|
15
15
|
spec.metadata["rubygems_mfa_required"] = "true"
|
|
16
16
|
spec.metadata["source_code_uri"] = "https://github.com/kaiwood/kward"
|
|
17
17
|
spec.metadata["changelog_uri"] = "https://github.com/kaiwood/kward/blob/main/CHANGELOG.md"
|
|
18
|
-
spec.metadata["documentation_uri"] = "https://github.
|
|
18
|
+
spec.metadata["documentation_uri"] = "https://kaiwood.github.io/kward/"
|
|
19
19
|
spec.metadata["bug_tracker_uri"] = "https://github.com/kaiwood/kward/issues"
|
|
20
20
|
|
|
21
21
|
spec.files = Dir.chdir(__dir__) do
|
|
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_dependency "tty-prompt"
|
|
35
35
|
spec.add_dependency "tty-reader"
|
|
36
36
|
spec.add_dependency "tty-screen"
|
|
37
|
+
spec.add_dependency "unicode-display_width"
|
|
37
38
|
end
|
data/lib/kward/agent.rb
CHANGED
|
@@ -28,10 +28,11 @@ module Kward
|
|
|
28
28
|
# lowest layer that owns the behavior, and use `Agent` only for cross-step turn
|
|
29
29
|
# coordination.
|
|
30
30
|
class Agent
|
|
31
|
-
def initialize(client:, tool_registry: ToolRegistry.new, conversation: Conversation.new, telemetry_logger: nil, warning_sink: nil, hook_manager: nil, hook_context: nil)
|
|
31
|
+
def initialize(client:, tool_registry: ToolRegistry.new, conversation: Conversation.new, telemetry_logger: nil, warning_sink: nil, hook_manager: nil, hook_context: nil, strict_provider: false)
|
|
32
32
|
@client = client
|
|
33
33
|
@tool_registry = tool_registry
|
|
34
34
|
@conversation = conversation
|
|
35
|
+
@strict_provider = strict_provider == true
|
|
35
36
|
@warning_sink = warning_sink
|
|
36
37
|
@telemetry_logger = telemetry_logger || TelemetryLogger.new(warning_sink: warning_sink)
|
|
37
38
|
@hook_manager = hook_manager
|
|
@@ -84,6 +85,7 @@ module Kward
|
|
|
84
85
|
end
|
|
85
86
|
loop do
|
|
86
87
|
cancellation&.raise_if_cancelled!
|
|
88
|
+
auto_compact_if_needed
|
|
87
89
|
begin
|
|
88
90
|
message = chat(on_reasoning_delta: on_reasoning_delta, on_retry: on_retry, cancellation: cancellation, steering: steering, options: options, tool_registry: tool_registry) do |event|
|
|
89
91
|
yield event if block_given?
|
|
@@ -240,7 +242,8 @@ module Kward
|
|
|
240
242
|
tools: registry.schemas,
|
|
241
243
|
provider: options[:provider] || @conversation.provider,
|
|
242
244
|
model: options[:model] || @conversation.model,
|
|
243
|
-
reasoning: options[:reasoning] || @conversation.reasoning_effort
|
|
245
|
+
reasoning: options[:reasoning] || @conversation.reasoning_effort,
|
|
246
|
+
provider_required: @strict_provider
|
|
244
247
|
}
|
|
245
248
|
before = run_hook("model_request_before", payload: request)
|
|
246
249
|
request = DeepCopy.merge(request, before.payload) if before.decision.modify?
|
|
@@ -260,7 +263,8 @@ module Kward
|
|
|
260
263
|
steering: steering,
|
|
261
264
|
provider: request[:provider] || request["provider"],
|
|
262
265
|
model: request[:model] || request["model"],
|
|
263
|
-
reasoning: request[:reasoning] || request["reasoning"]
|
|
266
|
+
reasoning: request[:reasoning] || request["reasoning"],
|
|
267
|
+
provider_required: request[:provider_required] || request["provider_required"]
|
|
264
268
|
}
|
|
265
269
|
)
|
|
266
270
|
run_hook("model_response_after_parse", payload: { message: response })
|