Skip to content

fix: bound workflow keyword matching - #79

Merged
QuintinShaw merged 2 commits into
QuintinShaw:mainfrom
SSS135:split/pr74-keyword-trigger
Jul 17, 2026
Merged

fix: bound workflow keyword matching#79
QuintinShaw merged 2 commits into
QuintinShaw:mainfrom
SSS135:split/pr74-keyword-trigger

Conversation

@SSS135

@SSS135 SSS135 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Unicode-aware identifier boundaries for workflow keyword matching while preserving the existing default-on auto-trigger behavior.

  • matches the built-in and custom trigger words at identifier boundaries
  • handles Unicode identifiers consistently
  • treats POSIX and Windows path components as bounded contexts
  • keeps interactive keyword triggering enabled by default

Windows test portability

Full Windows validation identified three test-harness portability issues on current main: home-directory isolation across HOME and USERPROFILE, platform-aware expected paths with node:path.join, and file-URL conversion for absolute dynamic-import paths. The corrections are confined to test setup and path handling and preserve the existing assertions.

Validation

  • npm test: 899/899 passed
  • focused workflow-editor suite: 138/138 passed
  • Biome: passed
  • TypeScript build: passed
  • git diff --check: passed
  • independent shortcut, quality, and spec reviews completed with no scoped implementation findings

Split from and supersedes the keyword-matching portion of #74.

@SSS135 SSS135 changed the title Draft: bound workflow keyword matching without changing defaults fix: bound workflow keyword matching Jul 16, 2026
@SSS135
SSS135 force-pushed the split/pr74-keyword-trigger branch from 9c8171a to b3d280c Compare July 16, 2026 11:59
@SSS135
SSS135 marked this pull request as ready for review July 16, 2026 15:42
@QuintinShaw

Copy link
Copy Markdown
Owner

Thanks @SSS135 — clean first split, and I appreciate you rebasing onto 2.14.0 already. Reviewed closely: the Unicode identifier-boundary regex is correct and ReDoS-safe (fixed-length lookarounds + a literal match, no nested quantifiers), default-on keyword triggering is genuinely preserved (only a new test locks it in — the ?? true default logic is untouched), and the Windows test-portability fixes are test-only. Tightening the default workflow word to identifier boundaries (so workflowRunner / my-workflow-helper no longer trigger) is a nice correctness bump on top. 899 tests green.

Merging. Looking forward to the rest as you mark them ready — workflow_control (#83) looks like the next clean standalone one; the two big resume PRs (#80/#81) will want a rebase since #78/#84 just landed in that area.

@QuintinShaw
QuintinShaw merged commit f169c1e into QuintinShaw:main Jul 17, 2026
1 check passed
QuintinShaw added a commit that referenced this pull request Jul 18, 2026
…, #89) (#93)

* feat(workflow): authorize keyword triggering instead of forcing it

Reframes keyword/effort triggering from 'force a workflow' to 'arm the tool and
let the model decide', addressing #88 (over-triggering), #89 (triggered runs
going idle instead of staying interactive), and cutting the always-on prompt
(part of #65).

- buildForcedWorkflowPrompt -> buildArmedWorkflowPrompt: the trigger now injects
  an authorize directive ('typing the word is explicit opt-in; if it's a request
  call workflow, if it's a question just answer -- the opt-in does not force a
  workflow') instead of 'You MUST / the ONLY acceptable action / Do NOT answer'.
  A lexical false-positive is no longer amplified into a forced wrong action.
- #89 falls out of de-forcing: the idle was a downstream effect of the model
  being told to emit nothing but one bare background workflow call (which ends
  the turn). Handled in a normal turn, Pi stays interactive and the model can
  fold results inline. No change to the tool's background machinery.
- Always-on prompt shrunk ~91% (6500 -> ~600 bytes): the ~20 'For workflow,'
  how-to lines moved off the always-on promptGuidelines into
  workflowHowToGuidelines(), injected into the message only on an armed turn; the
  always-on guideline is now a single gate line. Cuts self-priming and the
  always-on token cost, and stops churning the prompt-prefix cache.
- byEffort path de-forced too, with an explicit conversational-turn escape.
- Kept: keywordTriggerEnabled default ON (under authorize semantics the worst
  case is just an armed-turn directive), the #79 boundary regex, rainbow
  highlight, Backspace-to-disarm. README updated (force -> arm).

914 tests; always-on prompt budget ratcheted 6500 -> 650.

* refactor(workflow): root-and-branch authorize fix (P1-P5)

- Move the how-to mechanics from the per-armed-turn message into the
  workflow tool's static description, so the model has the manual on every
  arming path AND on off-keyword natural-language opt-ins, cacheably, not as
  per-turn priming (P2). Always-on promptGuidelines stays the single gate line.
- buildArmedWorkflowPrompt now leads with the decision boundary, states the
  truthful opt-in reason per path (keyword vs standing-effort), and carries the
  #89 background/deliver-back reassurance so an ending turn reads as expected,
  not a stall (P1, P3).
- /workflows run uses a distinct forcing directive (no question-escape) while
  avoiding the old MUST/ONLY language (P5).
- Gate line gains task-shape positives, balancing the strong negative (P4).
- Tests: trigger regression corpus (negatives/positives), gate-line R3, how-to
  now in tool description, armed-directive content, /workflows run forcing;
  honest prompt-budget ratchets (always-on ~766B, tool def grows to ~8.8KB as a
  MOVE, armed message drops ~6.8KB -> ~0.9KB; how-to trimming is #65, separate).

* docs: note the off-keyword natural-language path needs the workflow tool default-active

The how-to now lives in the tool description, so a bare natural-language opt-in
('fan this out') sees the mechanics only if the host keeps the workflow tool in
its default active set. The arming paths add it on arm; document the dependency.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants