Skip to content

feat: add lsp_format_document tool - #1194

Merged
will-lamerton merged 5 commits into
Nano-Collective:mainfrom
Dhirenderchoudhary:feat/lsp-format-document-1171
Sep 15, 2026
Merged

will-lamerton merged 5 commits into
Nano-Collective:mainfrom
Dhirenderchoudhary:feat/lsp-format-document-1171

Conversation

@Dhirenderchoudhary

Copy link
Copy Markdown
Contributor

Description

Adds an agent-callable lsp_format_document tool that uses the existing LSPManager.formatDocument() API to format a file via the connected language server, apply the returned edits, and write the result to disk. This replaces the need to guess a formatter CLI through execute_bash.

Also wires approval, plan-mode exclusion, ACP tool kind, compact result display, and a short docs note.

Closes #1171

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Changeset

  • Added a changeset (pnpm changeset) describing this change for the changelog

Docs-only or internal chores need no changeset (or run pnpm changeset --empty to note that intentionally).

Testing

Automated Tests

  • New features include passing tests in .spec.ts/tsx files
  • All existing tests pass (pnpm test:all completes successfully)
  • Tests cover both success and error scenarios

Manual Testing

  • Tested with Ollama
  • Tested with OpenRouter
  • Tested with OpenAI-compatible API
  • Tested MCP integration (if applicable)

Checklist

  • If this was for an open issue, I was assigned to it
  • Code follows project style guidelines
  • Self-review completed
  • Documentation updated (if needed)
  • No breaking changes (or clearly documented)
  • Appropriate logging added using structured logging (see CONTRIBUTING.md)

Expose the existing LSP formatDocument API as an agent-callable tool so
formatting can use the connected language server instead of guessing a CLI.
@github-actions github-actions Bot added area:tools Tool implementations and tool-calling area:docs Documentation labels Sep 4, 2026

@will-lamerton will-lamerton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work - the integration is more thorough than most tool-addition PRs. Plan-mode exclusion is wired in code and not just docs, checkpointing works for free via isReadOnly, and the approval matrix is covered across all four modes. A few things to fix before merge.

1. Hardcoded 2-space formatting will mangle tab-indented projects. formatFileWithLsp calls manager.formatDocument(absPath) with no options, so LSPClient.formatDocument falls back to tabSize: 2, insertSpaces: true (source/lsp/lsp-client.ts:270). Servers that honour FormattingOptions (typescript-language-server does) will convert tabs to spaces. This repo is Biome-formatted with tabs, so running the tool on nanocoder's own source reformats it against project style - which contradicts the tool description's promise of "project-style formatting". Please read .editorconfig / the project formatter config, or at minimum expose tabSize / insertSpaces in the input schema.

2. "No formatting changes needed" is returned when the server cannot format at all. LSPClient.formatDocument returns [] when documentFormattingProvider is absent (source/lsp/lsp-client.ts:263), and formatFileWithLsp maps empty edits to No formatting changes needed for X. The agent then concludes the file is clean when nothing was attempted. Please distinguish "server has no formatting support" from a genuine no-op.

3. positionToOffset does not clamp character to the end of its line. It clamps only to text.length, so an end position whose character overshoots the line length swallows every following line. On "ab\ncd\n", an end of {line: 0, character: 50} resolves to offset 6 (end of file) rather than 2 (end of line 0). Some servers emit large sentinel characters for "to end of line". Worth a test case too. Separately, the doc comment calls the result a "UTF-16-agnostic byte offset" - it is a UTF-16 code-unit offset, which is correct for LSP's default encoding, but the comment states the opposite of what the code does.

4. Missing changeset. New user-facing tool, so it needs one (pnpm changeset). Note the package name must be @nanocollective/nanocoder.

5. --plain --output-format json will not report formatted files. source/plain/shell.ts:317 lists ['write_file', 'string_replace', 'diff_edit'] as the mutating tools that populate filesChanged. lsp_format_document mutates a file and takes a path arg but is missing, so its edits silently drop out of the report.

Minor, non-blocking: FILE_ARG_TOOLS in source/acp/acp-timeline.ts:8 does not include the tool, so ACP checkpoints fall back to an 'opaque' git-status scan instead of a targeted path.

Honour .editorconfig (and optional tabSize/insertSpaces), distinguish
unsupported formatting from no-op edits, clamp LSP positions to line end,
report the tool in plain JSON filesChanged, and add a changeset.
Bring in schema/sandbox CI prerequisites from main, and replace RegExp-based
editorconfig globs with a star matcher so Semgrep stays clean.
@will-lamerton

Copy link
Copy Markdown
Member

Great work @Dhirenderchoudhary :)

@will-lamerton
will-lamerton merged commit 3f8589a into Nano-Collective:main Sep 15, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:docs Documentation area:tools Tool implementations and tool-calling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] expose lsp_format_document as an agent-callable tool

2 participants