Skip to content
This repository was archived by the owner on Aug 8, 2026. It is now read-only.

feat: add agent navigation tools, context reminders, and edit safety checks - #2

Merged
cheetahbyte merged 40 commits into
mainfrom
improvements/pi-a-b-opportunities
Aug 5, 2026
Merged

feat: add agent navigation tools, context reminders, and edit safety checks#2
cheetahbyte merged 40 commits into
mainfrom
improvements/pi-a-b-opportunities

Conversation

@cheetahbyte

@cheetahbyte cheetahbyte commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Pull Request Summary

This PR delivers a batch of agent capability improvements and safety guardrails for the coding agent, centered around three themes: better code navigation/search tools, smarter context management after compaction, and safer file edits.

New agent tools

symbol tool — Lets the agent find a symbol's declaration by exact name (functions, classes, methods, types, structs, etc.) across source files, returning the actual declaration body rather than just matching text lines. It respects .gitignore, supports JS/TS, Python, Go, Rust, Java, and C#, and includes safety caps on matches, body sizes, and files scanned.

outline tool — Provides a compact structural overview of a single file (top-level declarations as signatures only, without bodies). This is a cheaper alternative to reading a whole file to understand its shape, supporting the same set of languages, and is intended to be used before read/grep to narrow in on relevant parts of large files.

recall tool — Searches the full session history (including entries removed from the live context by compaction) for case-insensitive substring matches. This helps the agent recover exact error messages, code snippets, or earlier details that were summarized away during compaction.

All three tools are registered across tool factories, read-only tool lists, the SDK exports, and the TUI.

Context management after compaction

A constraints reminder mechanism was added: every 15 turns after a compaction, an ephemeral reminder message containing the latest compaction summary's "Constraints & Preferences" bullets is appended near the end of the outgoing context. This counters the "lost in the middle" problem where the summary drifts away from reliable retrieval zones during long sessions. The reminder is built fresh at context-assembly time and is never persisted, so it cannot accumulate clutter or go stale. It stays silent when there's no prior compaction or no meaningful constraints section.

Edit tool safety guardrail

The edit tool now performs a lightweight, dependency-free post-edit syntax check: JSON files are validated with JSON.parse, and common C-like/JS/TS languages are scanned for unbalanced braces/parens/brackets and unterminated literals (comment/string-aware, conservative to avoid false positives). If an issue is detected, the tool surfaces an advisory warning in its result and the TUI display, without ever failing or reverting the edit.

Developer experience

  • Vitest config now resolves @cheetahbyte/* workspace packages directly to source, so npm test no longer requires a full build.
  • Added comprehensive test coverage for all new tools, the constraints reminder, and the edit syntax guardrail, plus an update to an existing regression test reflecting the new built-in tool set.
  • docs-references added to .gitignore.

vegarsti and others added 27 commits August 4, 2026 12:36
Add a lightweight, dependency-free post-edit syntax sanity check to the
edit tool: JSON.parse for .json files, and a comment/string-aware
brace/paren/bracket balance + unterminated-literal scan for common
C-like/JS/TS languages. Advisory only - never blocks or rejects the
edit. Surfaces as EditToolDetails.syntaxWarning, appended to the tool's
text output, and shown in the TUI result render.
Adds a "recall" tool that searches the full session history (including
entries evicted from the live context by compaction) for a
case-insensitive substring match, so the model can recover exact error
messages, code snippets, or earlier details that were summarized away.
Registered as opt-in (like grep/find/ls), not part of default active
tools.
…in vitest config

The @cheetahbyte/* workspace aliases were missing from vitest.config.ts
(only the legacy @earendil-works/@mariozechner scopes were aliased), so
coding-agent tests failed to resolve @cheetahbyte/pi-ai, pi-agent-core,
pi-tui, pi-client, and pi-protocol in a worktree without a prior `npm
run build`. Mirrors the existing alias pattern already used here and in
packages/client and packages/server.
Adds a "symbol" tool that searches for exact-name declarations (function,
class, method, type, struct, etc.) across source files and returns the
actual declaration with its extracted body, instead of raw grep-style
text matches. Covers JS/TS, Python, Go, Rust, Java, and C# via a
per-extension regex ruleset, with string/comment-aware brace matching
for body extraction and an indentation-based fallback for Python.
Respects .gitignore. Registered as read-only and opt-in (not in
defaultActiveToolNames), matching grep/find/ls precedent.
Adds a new `outline` built-in tool that returns a compact, signature-only
preview of a single file's top-level declarations (classes, functions,
interfaces, types, structs, etc.), with methods nested one level under
their class/impl/trait, using per-extension regex heuristics.

Covers JS/TS, Python, Go, Rust, and Java/C#. Unsupported extensions get
a plain "use read instead" message rather than an error. Output is capped
at 500 declarations / 50KB with an actionable truncation notice, reusing
the existing truncate.ts conventions.

Registered like grep/find/ls: opt-in via --tools, included in
createReadOnlyTool(Definitions)/createAllTool(Definitions), and exported
from the package's public API. Not added to defaultActiveToolNames.
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
# Conflicts:
#	packages/coding-agent/src/core/sdk.ts
#	packages/coding-agent/src/core/tools/index.ts
#	packages/coding-agent/src/index.ts
# Conflicts:
#	packages/coding-agent/src/core/sdk.ts
#	packages/coding-agent/src/core/tools/index.ts
Full-document review by a fresh-context subagent found 2 blockers, 15
minors, and 12 nits; a second subagent verified every fix. All applied:

- autoCompact ran before_compaction only when no step was unfinished,
  making the hook unreachable on the live overflow path where the
  abandoned assistant step still occupies LaneState; now keyed on
  "not resuming a compaction step".
- Hook-supplied overflow compactions wrote no step_attempt, so the
  once-per-input guard never counted them and hook-driven compact-and-
  retry was unbounded; for reason overflow the hook path now writes the
  compaction step_attempt first.
- Empty compaction preparation is a real code branch, terminal for
  overflow. before_resume is invoked in the resume() dispatch. Pending
  deferred re-park verifies handle equality. resume() re-tags operation
  results as ResumeResult. MessageEntry declares terminate; options gain
  toolExecution; before_navigation loses its orphaned result fields;
  AbortRequestedRecord loses its unreachable reason field.
- Reduction bullets restated (newest-attempt closure, newest-own entry);
  Tier B records lane moves and covers the overflow and cancellation
  traces; hook-measured usage is written as hook ledger records at all
  three append sites; assorted stale wording from before the deferred-
  closure, ledger, and B2 changes brought current.
Section 18 no longer references observability.md, which described the
superseded ALS/global-context mechanism and is being removed. Absorbed
the two load-bearing points: the multi-runtime rationale for rejecting
ambient context (explicit arguments are the only portable abstraction),
and the adapter framing - the application supplies ExecutionContext to
bridge spans into OTel/Sentry/logs/metrics, pi ships no exporter and no
vendor dependency, adapters allocate their own span/trace ids, and may
use AsyncLocalStorage internally. Dropped the reading-list entry.
* feat: align sqlite storage with session lanes

* fix: delete lane from entry, action

* fix: errors and types

* fix: tests

* fix: usage records instead of session materialized

* chore: 1 mig

* fix

* refactor(agent): move harness experimental changes to split branch

* refactor and cleanup

* fix: use assertJsonSerializable for session metadata

* fix(sqlite): reject corrupt lane leafs on open

* fix: rebuild cache

* refactor: branch cache

* feat: session stats

* fix: enforce leases

* feat(agent): enforce fenced SQLite writer leases

* fix(agent): keep SQLite transactions synchronous

* fix(agent): align SQLite storage with conformance suite

---------

Co-authored-by: Christian Klotz <hello@christianklotz.co.uk>
@kody-ai

This comment has been minimized.

Comment thread packages/coding-agent/src/core/tools/outline.ts Outdated
Comment thread packages/coding-agent/src/core/tools/symbol.ts
Comment thread packages/coding-agent/src/core/tools/symbol.ts
Comment thread packages/coding-agent/src/core/tools/symbol.ts Outdated
Comment on lines +194 to +205
if (c === "'") {
state = "single";
continue;
}
if (c === '"') {
state = "double";
continue;
}
if (c === "`") {
state = "template";
continue;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

checkBraceBalance treats every ' as a single-quote opener, so Rust lifetimes (fn foo<'a>(x: &'a str) -> &'a str {) leave the scanner in "single" state at EOF and swallow the function-body {, emitting false unterminated single-quoted string at end of file warnings on every edit; C# interpolated strings ($"{a}" + "}") similarly produce false unbalanced '}' errors, telling the model a well-formed edit is broken. Skip ' followed by an identifier or static for Rust, and treat $" as an interpolated string that tracks {} braces for C#-like languages.

Prompt for LLM

File packages/coding-agent/src/core/tools/syntax-check.ts:

Line 194 to 205:

`checkBraceBalance` treats every `'` as a single-quote opener, so Rust lifetimes (`fn foo<'a>(x: &'a str) -> &'a str {`) leave the scanner in `"single"` state at EOF and swallow the function-body `{`, emitting false `unterminated single-quoted string at end of file` warnings on every edit; C# interpolated strings (`$"{a}" + "}"`) similarly produce false `unbalanced '}'` errors, telling the model a well-formed edit is broken. Skip `'` followed by an identifier or `static` for Rust, and treat `$"` as an interpolated string that tracks `{}` braces for C#-like languages.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment on lines +194 to +197
if (c === "'") {
state = "single";
continue;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

checkBraceBalance lacks language awareness and treats every ' as a single-quote opener, so Rust lifetimes (fn foo<'a>(x: &'a str)) force the scanner into "single" and swallow the following >, (, :, & until the next ', producing false unbalanced ')' with no matching '(' warnings on every edit to lifetime-bearing .rs files. Enter single-quote state only for plausible char literals—e.g., ' immediately followed by content and a closing ' within a few chars—and skip ' when immediately followed by an identifier character in Rust.

if (c === "'" && (isJsLike || isCharLiteralStart(content, i))) {
	state = "single";
	continue;
}
Prompt for LLM

File packages/coding-agent/src/core/tools/syntax-check.ts:

Line 194 to 197:

`checkBraceBalance` lacks language awareness and treats every `'` as a single-quote opener, so Rust lifetimes (`fn foo<'a>(x: &'a str)`) force the scanner into `"single"` and swallow the following `>`, `(`, `:`, `&` until the next `'`, producing false `unbalanced ')' with no matching '('` warnings on every edit to lifetime-bearing `.rs` files. Enter single-quote state only for plausible char literals—e.g., `'` immediately followed by content and a closing `'` within a few chars—and skip `'` when immediately followed by an identifier character in Rust.

Suggested Code:

if (c === "'" && (isJsLike || isCharLiteralStart(content, i))) {
	state = "single";
	continue;
}

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@kody-ai

This comment has been minimized.

Comment thread packages/coding-agent/src/core/tools/symbol.ts
Comment thread packages/coding-agent/src/core/tools/tree-sitter-navigation.ts Outdated
@kody-ai

This comment has been minimized.

Comment thread packages/agent/src/harness/compaction/compaction.ts
@kody-ai

kody-ai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Kody Review Complete

Great news! 🎉
No issues were found that match your current review configurations.

Keep up the excellent work! 🚀

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Business Logic

Access your configuration settings here.

@cheetahbyte cheetahbyte changed the title Improvements/pi a b opportunities feat: add agent navigation tools, context reminders, and edit safety checks Aug 5, 2026
@cheetahbyte
cheetahbyte merged commit 50a1a1d into main Aug 5, 2026
2 checks passed
@cheetahbyte
cheetahbyte deleted the improvements/pi-a-b-opportunities branch August 5, 2026 05:27
cheetahbyte added a commit that referenced this pull request Aug 5, 2026
feat: add agent navigation tools, context reminders, and edit safety checks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants