code-yeongyu / code-yeongyu/senpi
Extension-triggered turns bypass before_agent_start, so proactive compaction never runs in goal/wake-driven sessions
- Dominant language
- TypeScript
- Stars
- 429
- Forks
- 98
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 526
Description
## Summary
Turns started by extensions through `pi.sendMessage(..., { triggerTurn: true })` never emit `before_agent_start`, so the compaction extension's proactive machinery in `packages/coding-agent/src/core/extensions/builtin/compaction/index.ts` (`threshold_trigger`, speculative warm-up, `hard_limit_trigger` valve, token-budget reminder) does not run for them. Only the core `_enforceCompactionBeforeProvider(..., "pre_prompt")` gate (`window - reserveTokens`) and idle compaction remain.
## Where
`packages/coding-agent/src/core/agent-session.ts` `sendCustomMessage()` (the `options?.triggerTurn` branch on an idle session):
```ts
await this._enforceCompactionBeforeProvider(this._findLastAssistantMessage(), false, "pre_prompt");
await this._enforceFinalProviderAdmission([appMessage]);
...
await this._promptAgent(appMessage, deferredTurnClaim);
```
The user-prompt path in `prompt()` calls `this._extensionRunner.emitBeforeAgentStart(...)` between those steps; this path does not.
## Evidence
Session `01a06520` (2026-09-03, omo-senpi ulw run on anthropic/claude-fable-5-1, 1M window): 5 user prompts vs 35 `goal-continuation` + 40 `omo-senpi:wake` extension-triggered turns. The context grew 108K -> 996K over 8 h. `~/.omo/agent/logs/compaction.log` has no `threshold_trigger` / `speculative_started` / `hard_limit_trigger` attributable to that session even after the estimate passed both the 80% adaptive threshold (~09:00Z) and the hard-limit line (`window - 40,000`, from 10:42Z). In that session auto-compaction was also disabled in settings, which explains the core gate staying silent, but the extension's hard-limit valve does not check `settings.enabled` and still never fired: the only prompt-shaped entry points in that window were goal continuations, and they bypass `before_agent_start`.
Consequence for goal-driven / wake-driven sessions (the norm under ulw-loop): compaction is emergency-only (core pre_prompt gate at ~98% of the window) instead of proactive at 80%, and speculative warm summaries are never produced.
## Suggested direction
Either emit `before_agent_start` (or a dedicated `before_turn_start`) for extension-triggered turns so the compaction extension sees them, or move the proactive checks to a hook that every turn passes through (e.g. the `context` event already runs per request but is read-only for compaction). Related: with `compaction.enabled: false` nothing warns the user as the window fills; the footer percentage is the only signal. #1328 stops the doomed `max_tokens=1` requests at the wall but does not restore proactive compaction for these turns.
Contributor guide
Research direction
Compare the triggerTurn branch in packages/coding-agent/src/core/agent-session.ts sendCustomMessage() with prompt(), focusing on where before_agent_start is emitted. Read the compaction hooks in packages/coding-agent/src/core/extensions/builtin/compaction/index.ts and verify that extension-triggered turns run the proactive checks, including threshold, speculative warm-up, hard-limit, and token-budget behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- ai-infra-agents, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100