You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: show model-written tool intent in the working indicator (#57)
## Related Issue
No linked issue — directly requested feature; problem explained below.
## Problem
While the agent works, the spinner shows a random rotating verb
("pythinking…", "marinating…") that carries no information about what
the agent is actually doing. Users watching a long turn cannot tell
whether the agent is reading, editing, or running tests without
expanding tool cards.
## What changed
Each tool call now carries a short, model-written intent that the
working indicator shows live.
- Tool schemas sent to providers gain an injected required first
property `i` ("concise intent"). Injection happens on request-only
schema clones — registered tools and their validation schemas are never
mutated. Tools with an exact schema contract (`StructuredOutput`), an
existing `i` property, or a non-object schema root are skipped.
- The runtime strips `i` after JSON parse and before validation, so
hooks, permission prompts, execution, and the persisted transcript all
see clean arguments. The sanitized intent (control characters stripped,
120-char cap) rides the `tool.call.started` event as a new optional
`intent` field.
- The TUI streams the intent into the spinner label from partial
tool-call arguments (the field is first in the schema, so it arrives at
the head of the stream on most wires), falls back to the
`tool.call.started` intent, and clears on every turn/step/result
boundary. Without an intent, the rotating labels behave exactly as
before.
- Gated by the `tool_intent` experimental flag, default on; disable with
`PYTHINKER_CODE_EXPERIMENTAL_TOOL_INTENT=0` or `[experimental]
tool_intent = false`.
## Checklist
- [x] I have read the
[CONTRIBUTING](https://github.com/Pythoughts-labs/pythinker-code/blob/main/CONTRIBUTING.md)
document.
- [x] I have linked a related issue, or explained the problem above.
- [x] I have added tests that prove my feature works.
- [x] Ran `gen-changesets` skill, or this PR needs no changeset.
- [x] Ran `gen-docs` skill, or this PR needs no doc update.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- The working indicator now shows live descriptions of ongoing tool
actions.
- Tool-call events can include optional intent descriptions.
- Intent display is enabled by default and can be disabled through
experimental configuration or an environment variable.
- Intent text is sanitized, normalized, and limited in length for clear,
safe display.
- **Documentation**
- Added configuration guidance for controlling tool-intent display.
- **Tests**
- Added coverage for intent display, lifecycle behavior, sanitization,
streaming, and tool-call handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Show what the agent is doing in the working indicator: eligible tool calls whose input schema accepts the injected field now carry a short model-written intent, streamed live into the spinner label (for example "check failing test…") instead of a rotating placeholder; disable with `PYTHINKER_CODE_EXPERIMENTAL_TOOL_INTENT=0`.
Copy file name to clipboardExpand all lines: docs/configuration/config-files.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -229,11 +229,12 @@ advisor = "reviewer-model"
229
229
230
230
## `experimental`
231
231
232
-
`experimental` stores persistent overrides for experimental-feature flags. Currently, `micro_compaction` is the only user-facing entry and defaults to `true`; set it to `false` only when you need to disable automatic trimming of older large tool results.
232
+
`experimental` stores persistent overrides for experimental-feature flags.
233
233
234
234
| Field | Type | Default | Description |
235
235
| --- | --- | --- | --- |
236
236
|`micro_compaction`|`boolean`|`true`| Trim older large tool results from context while preserving recent conversation |
237
+
|`tool_intent`|`boolean`|`true`| Ask the model to state a concise intent with eligible tool calls whose input schema accepts the injected field and show it live in the working indicator; set `false` to return to the rotating label |
Copy file name to clipboardExpand all lines: docs/configuration/env-vars.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -135,6 +135,7 @@ Switches that control the behavior of subsystems such as telemetry, background t
135
135
|`PYTHINKER_CODE_WORKFLOW_SIZE_GUIDELINE`| Override the advisory Dynamic Workflow size guideline injected into the tool guidance; takes higher priority than `config.toml`|`small`, `medium`, `large`, `unrestricted`|
136
136
|`PYTHINKER_CODE_EXPERIMENTAL_FLAG`| Enable all registered experimental features for this process; `micro_compaction` is already enabled by default |`1`, `true`, `yes`, `on`|
137
137
|`PYTHINKER_CODE_EXPERIMENTAL_MICRO_COMPACTION`| Override [`[experimental].micro_compaction`](./config-files.md#experimental) for this process | Truthy or falsy |
138
+
|`PYTHINKER_CODE_EXPERIMENTAL_TOOL_INTENT`| Override [`[experimental].tool_intent`](./config-files.md#experimental) for this process. When on (the default), eligible tool calls whose input schema accepts the injected field carry a short model-written intent that the working indicator shows live; set a falsy value to turn it off | Truthy or falsy |
138
139
|`PYTHINKER_SHELL_PATH`| Override the Git Bash path on Windows (used when auto-detection fails) | Absolute path |
139
140
|`PYTHINKER_MODEL_MAX_COMPLETION_TOKENS`| Hard cap on `max_completion_tokens` per LLM step; applies to the `pythinker` provider only | Positive integer; `0` or negative disables clamping |
140
141
|`PYTHINKER_MODEL_TEMPERATURE`| Sampling temperature for every request; applies to the `pythinker` provider only (global — independent of `PYTHINKER_MODEL_NAME`) | Number, e.g. `0.3`|
0 commit comments