Skip to content

Commit e55ca65

Browse files
committed
Simplify handoff tool by removing inline ledger embedding
1 parent 0ba6de5 commit e55ca65

1 file changed

Lines changed: 24 additions & 68 deletions

File tree

handoff/tool.ts

Lines changed: 24 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,80 +4,37 @@
44
* Tools can trigger compaction directly, so handoff is implemented as a
55
* deliberate compaction that replaces noisy context with a clean restart brief.
66
*
7-
* The brief should complete the picture: preserve the important knowledge that
8-
* is still only present in the current context, while referenced ledger entry
9-
* bodies seed the post-handoff context immediately.
7+
* The brief should complete the picture: preserve the important situational
8+
* context that is still only present in the current turn, while notebook pages
9+
* remain durable grounding fetched on demand in the next context.
1010
*/
1111

1212
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
1313
import { Type } from "typebox";
1414
import type { AgenticodingState } from "../state.js";
1515
import { STATUS_KEY_HANDOFF } from "../tui.js";
1616

17-
const MAX_INLINE_ENTRIES = 3;
18-
const MAX_INLINE_CHARS = 4000;
19-
20-
/**
21-
* Extract names of existing ledger entries referenced in the task text.
22-
* Returns up to MAX_INLINE_ENTRIES entries with their full bodies,
23-
* capped at MAX_INLINE_CHARS total.
24-
*/
25-
function extractReferencedLedgerEntries(
26-
task: string,
27-
state: AgenticodingState,
28-
): { name: string; body: string }[] {
29-
const entryNames = Array.from(state.ledger.keys()).sort();
30-
const matched: { name: string; body: string }[] = [];
31-
const seen = new Set<string>();
32-
let totalChars = 0;
33-
34-
for (const name of entryNames) {
35-
if (task.includes(name) && !seen.has(name)) {
36-
const body = state.ledger.get(name);
37-
if (body) {
38-
const chars = body.length;
39-
if (totalChars + chars <= MAX_INLINE_CHARS && matched.length < MAX_INLINE_ENTRIES) {
40-
matched.push({ name, body });
41-
seen.add(name);
42-
totalChars += chars;
43-
}
44-
}
45-
}
46-
}
47-
48-
return matched;
49-
}
50-
5117
/**
5218
* Build the enriched task that becomes the compaction summary.
5319
*
54-
* Shape: handoff primer + inlined ledger bodies + original task.
20+
* Shape: handoff primer + original task.
5521
*/
56-
function buildEnrichedTask(
57-
task: string,
58-
state: AgenticodingState,
59-
): string {
60-
const refs = extractReferencedLedgerEntries(task, state);
61-
22+
function buildEnrichedTask(task: string): string {
6223
const parts: string[] = [
6324
"## Handoff — Continue Previous Work",
6425
"",
65-
"You are continuing a previous agent's work in a clean context. Available knowledge:",
66-
"- Use `ledger_get` to retrieve detailed entries by name on demand",
26+
"You are continuing a previous agent's work in a clean context. Use the available knowledge correctly:",
27+
"- Notebook pages hold durable grounding knowledge; fetch them with `notebook_read`",
28+
"- This handoff brief holds the distilled next task and immediate situational context",
29+
"- Use `notebook_index` to scan available pages when needed",
6730
"- Use `spawn` to delegate isolated subtasks to child agents",
68-
"- Build on ledger knowledge and the handoff brief rather than reconstructing old context",
69-
"- Treat the handoff brief as the missing picture that survived the cut",
31+
"- Build on notebook grounding and this brief rather than reconstructing old context",
32+
"",
33+
"## Task",
34+
"",
35+
task,
7036
];
7137

72-
if (refs.length > 0) {
73-
parts.push("", "### Inlined Ledger Context");
74-
for (const { name, body } of refs) {
75-
parts.push("", `Ledger: \`${name}\``, body, "---");
76-
}
77-
}
78-
79-
parts.push("", "## Task", "", task);
80-
8138
return parts.join("\n");
8239
}
8340

@@ -89,8 +46,8 @@ export function registerHandoffTool(
8946
name: "handoff",
9047
label: "Handoff",
9148
description:
92-
"Replace the active context with a compact handoff task at the end of " +
93-
"the current turn while keeping full history in the session file.\n\n" +
49+
"Replace the active context with a compact task brief at the end of " +
50+
"the current turn while keeping full history in the session file. Handoff clears the active notebook topic so the next clean context can assign a fresh one.\n\n" +
9451
"WHEN TO USE:\n" +
9552
" 1. Context past ~30% and the current job is no longer cleanly " +
9653
"represented near the front of attention.\n" +
@@ -100,14 +57,13 @@ export function registerHandoffTool(
10057
"Rule: one context, one job. When the job changes, call handoff.\n\n" +
10158
"AFTER HANDOFF the LLM sees:\n" +
10259
" • System prompt + context primer\n" +
103-
" • The handoff task — as a compaction summary at the top of context\n" +
104-
" • All ledger entries — accessible via ledger_get / ledger_list",
60+
" • The handoff task — the distilled next work at the top of context\n" +
61+
" • All notebook pagesdurable grounding accessible via notebook_read / notebook_index",
10562

10663
promptSnippet: "Pivot to a new job via deliberate handoff compaction",
10764
promptGuidelines: [
108-
"Call handoff when the job changes, or when context is past ~30% and noisy. " +
109-
"Capture reusable state in the ledger if needed, then draft a concise but " +
110-
"sufficiently detailed brief that completes the picture for the next clean context.",
65+
"Before handoff, promote any missing durable grounding knowledge to the notebook. " +
66+
"Then draft a concise but sufficiently detailed brief with the distilled next task and immediate starting state for the next clean context. The active notebook topic will reset after handoff, so the next context should assign a fresh topic from the brief or user direction.",
11167
],
11268

11369
executionMode: "sequential",
@@ -116,14 +72,14 @@ export function registerHandoffTool(
11672
task: Type.String({
11773
description:
11874
"What to do next. A concise but sufficiently detailed handoff brief. " +
119-
"This becomes the FIRST thing the LLM sees after handoff. Complete the " +
120-
"picture by preserving the important knowledge still missing from the ledger, " +
121-
"then make the next work unambiguous using any structure you want.",
75+
"This becomes the FIRST thing the LLM sees after handoff. Capture the distilled next task, " +
76+
"immediate starting state, blockers, failed paths worth avoiding, and relevant notebook page names. " +
77+
"The notebook is the long-term grounding store; this brief should carry only the remaining situational context.",
12278
}),
12379
}),
12480

12581
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
126-
const enrichedTask = buildEnrichedTask(params.task, state);
82+
const enrichedTask = buildEnrichedTask(params.task);
12783
state.pendingHandoff = { task: enrichedTask, source: "tool" };
12884
if (state.pendingRequestedHandoff) {
12985
state.pendingRequestedHandoff.toolCalled = true;

0 commit comments

Comments
 (0)