Skip to content

feat(macros): add read-only sequence tracker and /macros command (#1585) - #1619

Open
rishu685 wants to merge 1 commit into
Nano-Collective:mainfrom
rishu685:feat/workflow-macros
Open

rishu685 wants to merge 1 commit into
Nano-Collective:mainfrom
rishu685:feat/workflow-macros

Conversation

@rishu685

@rishu685 rishu685 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1585 (Part 1 of 2)

Summary

Per review feedback from @addyCooks, this PR implements PR 1: Runtime Read-Only Sequence Tracker & Listing.

Execution mechanisms (runner: macro custom tool), compiler logic, parameter binding across steps, and /macros compile are deferred to PR 2.


Key Changes in PR 1

  1. Read-Only Sequence Tracker (source/macros/sequence-tracker.ts):

    • Tracks repeated multi-step read-only tool sequences across the session.
    • Non-overlapping repeat counting: checks startIndex > lastEnd and tracks streaks so identical tool runs (e.g. four read_file calls in a row) only count once per run (occurrences = 1) and do not inflate candidate counts.
    • Retains exemplarRecords on WorkflowPattern with real argument values for PR 2's parameterization.
  2. Explicit Chain Break Semantics (breakChain()):

    • tracker.breakChain() resets contiguous tracking on non-read-only tool calls, failed executions (isToolResultError), and agent subagent batches (executeAgentBatch).
  3. Parallel Batch Tagging (parallelBatch: true):

    • Read-only tools executing concurrently in Promise.all batches are tagged with parallelBatch: true so PR 2's compiler knows they are concurrent siblings rather than sequential dependencies.
  4. Interactive /macros Command (source/commands/macros.tsx):

    • /macros: Displays candidate workflows (getCandidates(), occurrences $\ge 2$) with clean counts.
    • /macros clear & /clear: Resets active tracking history and discovered patterns.
  5. Coverage Scope:

    • Tracking is integrated into the interactive TUI turn loop (source/hooks/chat-handler/conversation/tool-executor.tsx). Non-interactive paths (ACP and --plain) call processToolUse directly and are excluded in v1.

Upcoming in PR 2

  • Custom tools parser update (runner: macro).
  • Compiler parameter binding and outputs chaining.
  • Gated execution with pre-tool-use confirmation.
  • /macros compile command.

Testing & Verification

  • Unit & integration tests in sequence-tracker.spec.ts, macros.spec.tsx, tool-executor.spec.ts, clear.spec.tsx.
  • All tests pass (47/47), types, linter, Knip, and production build clean.

Comment thread source/macros/macro-compiler.ts Fixed
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

nc-review: needs work — 2 blocking, 4 important

@rishu685 — there is a blocking item below.

The PR introduces a new source/macros/ subsystem (sequence tracker, runner, compiler, plus types) that is not wired into any existing module: nothing in source/ imports the new types or instantiates SequenceTracker, no tool/command surfaces the macros to the user, and exportMacroToMarkdown emits a markdown file that the project's CustomToolLoader will reject (missing required frontmatter and a JSON-only body that is not a shell script). The change is a substantial new abstraction with no integration and no behavioural impact — it cannot do what its description claims. This warrants a spec/issue discussion before implementation rather than a merge.

🔴 blocking · completeness · source/macros/macro-runner.ts

No module in source/ imports @/types/macros, executeMacro, SequenceTracker, or any of the new helpers (verified by searching source for @/macros and @/types/macros). The subsystem has zero integration: no ToolManager hook intercepts tool execution to feed recordExecution, no built-in command surfaces detected macros, and no startup path references the types. The PR's stated goal — 'compile repeated agent workflows into verified deterministic macros that execute locally in a single turn' — is not achievable from this diff alone, because nothing ever calls executeMacro and nothing ever creates a SequenceTracker. Either wire the subsystem into the existing tool-execution / conversation-loop / custom-tool-loader surface, or split this PR so the integrator commit lands alongside it.

🔴 blocking · correctness · source/macros/macro-compiler.ts

exportMacroToMarkdown claims to produce 'standard Nanocoder custom tool markdown format', but the output is not loadable by parseCustomToolFile (source/custom-tools/parser.ts). It emits only name, description, and parameters, while the parser requires approval (defaulted to 'always', which would force every compiled macro to prompt before running), read_only, timeout_ms, cwd, env, and shell. The body the compiler writes is # Macro Workflow Pipeline Steps\n\``json\n...\n```, which the parser would treat as a literal shell script and feed to shellQuote/renderBody— that is not how a macro step pipeline should execute. If a user follows the description and drops the file into.nanocoder/tools/, it either fails to parse or, worse, attempts to execute a literal python -c 'import json,...'`-shaped payload under the shell. The PR description's claim that this output is the standard tool markdown format is incorrect.

🟠 important · design · source/types/macros.ts

ToolExecutionRecord / WorkflowPattern / MacroDefinition / MacroExecutionResult are five new public types in source/types/ with no consumer in the codebase. Adding a new top-level directory (source/macros/) plus a new types module is a significant surface-area change; per CONTRIBUTING, 'substantial changes' are expected to be proposed in an issue before implementation. The diff also overlaps with ConversationStateManager.detectRepetition in source/app/utils/conversation-state.ts, which already tracks recent tool calls and flags repeating actions for the continuation prompt. Before merging, the maintainers will want to see (a) the issue/spec that this is concretely solving, (b) where these types hook into the tool-execution path, and (c) why SequenceTracker is a better home for repetition detection than ConversationStateManager already is.

🟠 important · tests · source/macros/sequence-tracker.spec.ts

The tests cover interpolateValue, executeMacro against a hand-rolled mock executor, createMacroFromSequence / exportMacroToMarkdown against fixed inputs, and SequenceTracker with two-record sequences. None of them exercise the claimed end-to-end behaviour — that tool calls dispatched through executeToolsDirectly would feed the tracker and produce a candidate pattern, or that an exported markdown file is accepted by the custom-tool loader. The spec file also uses only two-step sequences at the default minOccurrencesForCandidate: 2, which is exactly the minimum case; boundary conditions (max sequence length, partial failures mid-sequence, history eviction at maxHistory) are not covered. Because the macro pipeline has no integration, the existing tests only prove the unit-level functions compile and the interpolation/signature logic is locally correct — they do not prove the PR's stated claim.

🟠 important · warranted · source/macros/macro-compiler.ts

The diff references issue #1585 in the title only ('(#1585)') and uses the word 'Addresses' rather than 'Closes', but the context confirms the PR is not linked as a closing PR. CONTRIBUTING says substantial changes should be drafted and discussed in an issue before implementation. This PR adds five new files and four new exported types with no integration code, no spec, and a description that misrepresents what the compiler output is. A maintainer cannot tell from the diff alone what problem this solves end-to-end. The right next step is to file (or finish) the spec on issue #1585 describing how macros fit alongside the existing custom-tools/custom-commands/skills primitives, then split this PR into the building blocks once there is agreement on the design.

🟠 important · scope · source/macros/macro-runner.ts

The PR is framed as a single feature ('compile repeated agent workflows') but lands three independent subsystems — sliding-window pattern detection, a sequential tool orchestrator, and a tool-format exporter — without any of them being wired into the agent loop. Even if the project wants all three, they should land in separate, reviewable commits (or separate PRs) so each can be discussed on its own merits. As-is, a reviewer cannot accept the runner without accepting the tracker, or vice versa, which is exactly the coupling CONTRIBUTING's 'discuss substantial changes first' guidance is asking contributors to avoid.


🔴 blocking · 🟠 a reviewer would ask for a change · ⚪ optional

Automated code review — correctness, security, design, tests, plus duplicates and scope. A human still decides; this is not a substitute for review and is not exhaustive. The required status checks separately cover lint, formatting, types, unused dependencies, the test suite and the build. This bot never merges. Maintainers can rerun with /re-review.

@github-actions github-actions Bot added the agent:needs-work nc-review found blocking findings label Oct 7, 2026
@rishu685

rishu685 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

I have updated this PR to consolidate all components into a complete, unified implementation!

Summary of What is Included in this PR

  1. Deterministic Multi-Step Runner (source/macros/macro-runner.ts):

    • Executes multi-step composite workflows sequentially without intermediate LLM inference.
    • Supports parameter templating ({{param}}, {{input.arg}}, {{steps.outputKey}}).
    • Hardened against prototype pollution using own-property checking (Object.prototype.hasOwnProperty) and reduce property traversal (passes Semgrep rule prototype-pollution-loop).
    • Graceful failure trapping: halts execution cleanly and returns detailed failure diagnostics if any step encounters an error.
  2. Sliding-Window Sequence Tracker (source/macros/sequence-tracker.ts):

    • Tracks contiguous chains of successful tool execution traces.
    • Discovers recurring tool execution sequences ($k \in [2, 5]$) and computes pattern frequency, occurrence counts, and timestamps.
    • Exported global singleton getSequenceTracker() for tracking throughout the session.
  3. Macro Compiler & Exporter (source/macros/macro-compiler.ts):

    • Compiles execution history into parameterized MacroDefinition schemas.
    • Formats macro definitions into YAML frontmatter using standard JSON.stringify to escape backslashes (\) and double quotes ("), resolving the CodeQL/Semgrep security warnings.
  4. Interactive /macros Command & CLI View (source/commands/macros.tsx):

    • /macros: Displays discovered repeatable patterns from the active session with occurrences and success counts.
    • /macros compile <pattern_id> [name]: Compiles and exports a workflow to .nanocoder/tools/<name>.md.
    • /macros clear: Resets session pattern history.
    • Lazily registered in source/commands/lazy-registry.ts.
  5. Test & Quality Verification:

    • Unit Tests: 11/11 AVA unit tests passing across runner, tracker, compiler, and /macros command (pnpm run test:ava source/macros/*.spec.ts source/commands/macros.spec.tsx).
    • Static Analysis: tsc --noEmit, biome lint, and biome check passing with 0 errors.
    • Security Scanners: semgrep scan --config auto --error passing with 0 findings on 808 files.

@addyCooks addyCooks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @rishu685, the code is tidy and the checks pass,
but I can't review it for merge yet. I ran it:

  1. Nothing calls recordExecution or executeMacro outside the specs (sequence-tracker.ts L25, macro-runner.ts L62), so /macros is always empty in a real session and compile can't be reached.
  2. /macros compile builds a dummy sequence with empty args (macros.tsx L121-128), so a compiled macro would have no real parameters.
  3. The exported markdown (macro-compiler.ts L70-97) parses as a custom tool, but with approval: always and a body that is only a JSON dump handed to the shell. It doesn't run the macro steps.
  4. macros.tsx L140-141 silently overwrites an existing tool file with the same name.

Since #1585 is a proposal and no design is agreed yet,
Happy to review once it's settled.

@github-actions github-actions Bot added the area:tui Terminal UI label Oct 10, 2026
@rishu685 rishu685 changed the title feat(macros): compile repeated agent workflows into verified deterministic macros (#1585) feat(macros): add read-only sequence tracker and /macros command (#1585) Oct 10, 2026
@rishu685
rishu685 force-pushed the feat/workflow-macros branch 2 times, most recently from 0b8b169 to 852c278 Compare October 10, 2026 08:15
@rishu685
rishu685 requested a review from addyCooks October 10, 2026 08:20

@addyCooks addyCooks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @rishu685, #1619 now matches the PR 1 scope we agreed.
I checked the head commit: the specs pass (44/44), types, lint, knip and Semgrep are clean, breakChain() is wired for mutations, failures and agent batches, the pass count is gone, parallel batches are tagged, and the coverage note is in the description.

Before this can merge:

  1. Counts are inflated (sequence-tracker.ts L55-86): one run of four read_file calls reports read_file -> read_file — 3 times, because each suffix counts as a repeat. Please count non-overlapping repeats so a single run isn't reported as repeated.
  2. /macros lists non-repeated pairs: it uses getPatterns(1), while the empty-state text says "repeated". Please list getCandidates() (2 or more).
  3. PR body: "Resolves #1585" will close the issue when Part 1 merges. Please change it to "Part of #1585".
  4. acp-agent.ts: the encoding fixes are unrelated to this issue; please move them to a separate PR or drop them here.

Optional: output is stored per record but nothing reads it yet,
so it could wait for PR 2, and the tracker could reset on /clear.

@rishu685
rishu685 force-pushed the feat/workflow-macros branch from 852c278 to df95b90 Compare October 10, 2026 15:20
@rishu685

Copy link
Copy Markdown
Contributor Author

Hi @addyCooks!

Thank you for catching those items! I've addressed all points in the latest push:

  1. Non-overlapping repeat counting: Updated sequence-tracker.ts with end-index and streak tracking so overlapping suffixes and runs of identical tools (such as four consecutive read_file calls) are only counted once (occurrences = 1) and not reported as repeated candidate workflows.
  2. /macros candidate listing: Updated /macros to display tracker.getCandidates() ($\ge 2$ occurrences), matching the empty-state message.
  3. PR description: Changed from "Resolves [Feature] Architecture: Compile repeated agent workflows into verified deterministic macros #1585" to "Part of [Feature] Architecture: Compile repeated agent workflows into verified deterministic macros #1585".
  4. Dropped acp-agent.ts: Reverted source/acp/acp-agent.ts completely back to main to keep this PR strictly focused on macros.
  5. Optional refinements: Dropped the unused output field from ToolExecutionRecord, and wired getSequenceTracker().clear() into /clear in app-util.ts.

All 47 tests (ava), type checks, Biome, Knip, and production build pass cleanly. Ready for your review!

@rishu685
rishu685 requested a review from addyCooks October 10, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:needs-work nc-review found blocking findings area:tui Terminal UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants