Skip to content

Commit 63faa85

Browse files
authored
feat(soul): agent logic upgrade (#149)
* fix(update): improve native update flow (#64) * feat(soul): port blackbox agent-loop observability and session tools Add wire events for todo updates, tool skips, subagent fallback, agent-list deltas, and overflow recovery. Wire opt-in ToolUseSkipped telemetry, AgentList injection, budget nudge, microcompact pruning, ToolSearch discovery, session worktree enter/exit, and opt-in harvest-on-stop memory capture. Update changelog, architecture docs, and tests. * feat(toolset): surface cross-step dedup via ToolUseSkipped wire event Add opt-in emits_tool_use_skipped hook for cross-step duplicate visibility, pin exclusive default for unflagged plugin tools, and document the gate contract. * feat(todo): emit TodoListUpdated wire event on write/read * feat(agent): emit SubagentToolFallback wire event on unknown type * feat(soul): emit ContextOverflowRecovered wire event; assert one-shot reactive retry * feat(soul): add opt-in token-budget nudge (config-gated, one-shot per turn) * docs(agent): add brief hygiene note to Agent tool description * docs: changelog + architecture note for agent-loop best-practice port * test: refresh inline snapshots for agent-loop port * test: refresh default agent snapshot for hygiene note * test: align agent-loop port tests with wire and fail-fast semantics * test(e2e): refresh wire snapshots for TodoListUpdated events * chore(test): fix ruff/pyright and format snapshot refresh files * fix(soul): resolve merge duplicates from blackbox port integration Drop duplicate budget-nudge, ToolUseSkipped emit paths, and conflicting tests introduced when merging feat/blackbox-agent-loop-port into main. * fix(wire): remove duplicate ContextOverflowRecovered class definition * test: refresh snapshots for new worktree/tool_search tools and AgentListDelta wire events * test: fix ruff formatting and refresh wire snapshots for agent-logic-upgrade 4 files were unformatted (ruff would-reformat). 5 e2e snapshot tests were stale after new slash commands (/recap, /accept-edits, /goal, /learn, /best-practices) and skill entries were added to the wire initialize handshake. * fix: address PR #149 review comments from code-quality and security bots - ci-pythinker-host.yml: add workflow-level `permissions: contents: read` - llm.py: use urlparse hostname check instead of substring match for dashscope and workspace endpoint detection (prevents false positives from path segments) - dependencies.py: remove duplicate '=' from _VERSION_PREFIX_RE character class - test_memory_phase_bcd.py: consolidate to single import style for pythinkersoul module - test_toolset.py: replace standalone awaits with gather/assignment forms - test_toolset_concurrency.py: remove always-true redundant assertion - examples/feedback-worker/index.ts: replace .+? with [^<]*? to prevent ReDoS * fix(examples): linear parseMailbox to avoid polynomial ReDoS CodeQL flagged the angle-bracket regex in the feedback-worker example as a polynomial regular expression on uncontrolled header input. Replace it with an indexOf/slice parse that is linear in input length while preserving the "Name <addr>" parsing behavior.
1 parent 920d998 commit 63faa85

51 files changed

Lines changed: 2869 additions & 1243 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
description: Never add Co-authored-by or other AI/tool trailers to git commits or PRs
3+
alwaysApply: true
4+
---
5+
6+
# No co-author or AI trailers on commits
7+
8+
**Never** add `Co-authored-by`, `Signed-off-by` for an AI tool, or any Cursor/Claude/Copilot
9+
footer to commit messages or PR descriptions.
10+
11+
This matches `AGENTS.md`: commits use Conventional Commits subject (+ optional body) only.
12+
13+
## When creating commits
14+
15+
- Pass the message via HEREDoc or `-m` with **only** the intended subject/body.
16+
- Do **not** append `Co-authored-by: Cursor <cursoragent@cursor.com>` or similar.
17+
- If a hook or tool adds a co-author trailer, **amend it out** before pushing (only when amend rules allow).
18+
19+
## Examples
20+
21+
```text
22+
feat(soul): emit TodoListUpdated wire event
23+
```
24+
25+
Not:
26+
27+
```text
28+
feat(soul): emit TodoListUpdated wire event
29+
30+
Co-authored-by: Cursor <cursoragent@cursor.com>
31+
```

.github/workflows/ci-pythinker-host.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ on:
1717
- "uv.lock"
1818

1919

20+
permissions:
21+
contents: read
22+
2023
env:
2124
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
2225

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@ GitHub Releases page; `0.8.0` is the new starting line.
1515

1616
## Unreleased
1717

18+
- **Stop-time memory extraction can now be enabled explicitly.** Added an opt-in
19+
`memory.harvest_on_stop` setting that stages safe assistant decisions, blockers, evidence, and
20+
next steps into the existing scratchpad recall flow at turn end without writing directly to
21+
durable `MEMORY.md`.
22+
- **Agents can now discover visible tools and temporarily work from a session worktree.** Added
23+
`ToolSearch` plus root-session `EnterWorktree` and `ExitWorktree` tools so agents can find
24+
currently available capabilities by keyword and isolate a session's operational working directory
25+
in a git worktree without deleting user work on exit.
26+
- **Agent-loop observability now emits explicit Wire events for key runtime state.** Added
27+
`TodoListUpdated`, `SubagentToolFallback`, `AgentListDelta`, `ToolUseSkipped`, and
28+
`ContextOverflowRecovered` events, with todo updates, subagent launch fallbacks, same-step tool
29+
reuse/policy skips for tools that explicitly opt in, agent-list injections, and
30+
context-overflow recovery now surfaced best-effort over Wire without changing existing tool
31+
results.
32+
- **Spend ceilings now warn before they stop a session.** When `max_session_cost_usd` is configured,
33+
the loop appends a bounded system reminder after a turn crosses `budget_nudge_ratio` of the
34+
ceiling, nudging the agent to conserve budget without auto-continuing or hiding a later
35+
`budget_exhausted` stop.
36+
- **The Agent tool description now gives clearer prompt-briefing guidance.** Fresh subagents should
37+
receive the goal, scope, expected output contract, and verification criteria; the Haiku-style
38+
tool-use summary from the blackbox reference was deliberately not ported.
39+
1840
## 0.46.0 (2026-06-14)
1941

2042
- **Startup auto-update now picks up new releases within half an hour instead of up to a day.** The background update check was throttled to once every 24h, so a freshly published release could go unnoticed for a full day after the last check; the interval is now 30 minutes. The silent installer also no longer marks the throttle *before* the network call — a transient startup network error returns `FAILED` and is retried on the next launch instead of suppressing updates for the whole window.

docs/en/customization/architecture.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ The end-to-end flow when a session starts and processes a turn:
8787
The soul is the heart of the runtime. Beyond the loop itself it owns approvals, context and
8888
compaction, slash commands, dynamic prompt injection, and a checkpoint-rewind mechanism.
8989

90+
The agent loop emits per-turn and per-step wire events for orchestration observability. The
91+
canonical list lives in `src/pythinker_code/wire/types.py` (`Event` union): `StepBegin`,
92+
`StepRetry`, `StepInterrupted`, `ToolExecutionStarted`, `StatusUpdate`, plus
93+
`TodoListUpdated`, `SubagentToolFallback`, `AgentListDelta`, `ToolUseSkipped`, and
94+
`ContextOverflowRecovered`.
95+
9096
| Path | Purpose | Key entry points and interfaces |
9197
| --- | --- | --- |
9298
| `src/pythinker_code/soul/pythinkersoul.py` | Core loop: user input, slash commands, LLM calls, tool runs, compaction, telemetry spans. | `PythinkerSoul`, `PythinkerSoul.run`, `FLOW_COMMAND_PREFIX` |
@@ -168,6 +174,12 @@ model; `/usage` defaults to the active provider, with `/usage all` as the explic
168174
| `src/pythinker_code/ui/print/` | Non-interactive output (text / stream-json). | `Print` |
169175
| `src/pythinker_code/ui/acp/` | Deprecated single-session ACP shim (raises on use); the live server is `src/pythinker_code/acp/`. | `ACP` |
170176

177+
The agent loop emits per-turn and per-step events for UI, replay, and dashboard consumers. The
178+
canonical list lives in the `Event` union in `src/pythinker_code/wire/types.py`; commonly consumed
179+
events include `StepBegin`, `StepRetry`, `StepInterrupted`, `ToolExecutionStarted`, `StatusUpdate`,
180+
`TodoListUpdated`, `SubagentToolFallback`, `AgentListDelta`, `ToolUseSkipped`, and
181+
`ContextOverflowRecovered`.
182+
171183
The shell can run with a working directory inside its subtree, so `src/pythinker_code/ui/`
172184
is a candidate for a focused nested guide on prompt, visualization, and component layout.
173185

docs/en/release-notes/changelog.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,28 @@ GitHub Releases page; `0.8.0` is the new starting line.
1717

1818
## Unreleased
1919

20+
- **Stop-time memory extraction can now be enabled explicitly.** Added an opt-in
21+
`memory.harvest_on_stop` setting that stages safe assistant decisions, blockers, evidence, and
22+
next steps into the existing scratchpad recall flow at turn end without writing directly to
23+
durable `MEMORY.md`.
24+
- **Agents can now discover visible tools and temporarily work from a session worktree.** Added
25+
`ToolSearch` plus root-session `EnterWorktree` and `ExitWorktree` tools so agents can find
26+
currently available capabilities by keyword and isolate a session's operational working directory
27+
in a git worktree without deleting user work on exit.
28+
- **Agent-loop observability now emits explicit Wire events for key runtime state.** Added
29+
`TodoListUpdated`, `SubagentToolFallback`, `AgentListDelta`, `ToolUseSkipped`, and
30+
`ContextOverflowRecovered` events, with todo updates, subagent launch fallbacks, same-step tool
31+
reuse/policy skips for tools that explicitly opt in, agent-list injections, and
32+
context-overflow recovery now surfaced best-effort over Wire without changing existing tool
33+
results.
34+
- **Spend ceilings now warn before they stop a session.** When `max_session_cost_usd` is configured,
35+
the loop appends a bounded system reminder after a turn crosses `budget_nudge_ratio` of the
36+
ceiling, nudging the agent to conserve budget without auto-continuing or hiding a later
37+
`budget_exhausted` stop.
38+
- **The Agent tool description now gives clearer prompt-briefing guidance.** Fresh subagents should
39+
receive the goal, scope, expected output contract, and verification criteria; the Haiku-style
40+
tool-use summary from the blackbox reference was deliberately not ported.
41+
2042
## 0.46.0 (2026-06-14)
2143

2244
- **Startup auto-update now picks up new releases within half an hour instead of up to a day.** The background update check was throttled to once every 24h, so a freshly published release could go unnoticed for a full day after the last check; the interval is now 30 minutes. The silent installer also no longer marks the throttle *before* the network call — a transient startup network error returns `FAILED` and is retried on the next launch instead of suppressing updates for the whole window.

0 commit comments

Comments
 (0)