@sema-agent/core 1.438.0 → 1.440.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/subagent.js +17 -5
- package/dist/core/context-edit.js +17 -11
- package/package.json +1 -1
package/dist/agents/subagent.js
CHANGED
|
@@ -15,6 +15,7 @@ import { delimitUntrusted, inlineUntrusted } from "../core/untrusted-text.js";
|
|
|
15
15
|
import { boundedRedactedSummary } from "../core/untrusted-egress.js";
|
|
16
16
|
import { uuidv7 } from "../internal/harness.js";
|
|
17
17
|
import { addWorktree } from "../core/git-worktree-env.js";
|
|
18
|
+
import { shellQuote } from "../tools/fs/search.js";
|
|
18
19
|
import { BG_AGENT_REAP_STOP_ERROR, DURABLE_AGENT_HANDLE_RE, DURABLE_AGENT_HEARTBEAT_MS, normalizeAgentName } from "../core/task-registry.js";
|
|
19
20
|
import { canAccessAgentRecord } from "../core/background-agent-store.js";
|
|
20
21
|
import { extractErrorCode } from "../brain/errors.js";
|
|
@@ -154,18 +155,29 @@ export function createSubagentWorktreeHelper(baseEnv, repoRoot) {
|
|
|
154
155
|
destroy: { value: undefined, writable: true, configurable: true },
|
|
155
156
|
}),
|
|
156
157
|
});
|
|
157
|
-
|
|
158
|
+
const baseSha = await baseEnv
|
|
159
|
+
.exec("git rev-parse HEAD", { cwd: worktreeDir })
|
|
160
|
+
.then((r) => (r.ok && r.value.exitCode === 0 ? r.value.stdout.trim() : undefined))
|
|
161
|
+
.catch(() => undefined);
|
|
162
|
+
handles.set(worktreeDir, { destroy: () => env.destroy(), baseSha });
|
|
158
163
|
return { worktreeDir };
|
|
159
164
|
},
|
|
160
165
|
async finish(worktreeDir) {
|
|
161
|
-
const
|
|
166
|
+
const handle = handles.get(worktreeDir);
|
|
162
167
|
handles.delete(worktreeDir);
|
|
168
|
+
let changed = true;
|
|
163
169
|
const status = await baseEnv.exec("git status --porcelain", { cwd: worktreeDir });
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
if (status.ok && status.value.exitCode === 0 && handle?.baseSha !== undefined) {
|
|
171
|
+
const dirtyFiles = status.value.stdout.split("\n").filter((l) => l.trim() !== "").length;
|
|
172
|
+
const ahead = await baseEnv.exec(`git rev-list --count ${shellQuote(`${handle.baseSha}..HEAD`)}`, { cwd: worktreeDir });
|
|
173
|
+
const commits = ahead.ok && ahead.value.exitCode === 0 ? parseInt(ahead.value.stdout.trim(), 10) || 0 : -1;
|
|
174
|
+
if (commits >= 0)
|
|
175
|
+
changed = dirtyFiles > 0 || commits > 0;
|
|
176
|
+
}
|
|
177
|
+
if (changed)
|
|
166
178
|
return "kept";
|
|
167
179
|
try {
|
|
168
|
-
await destroy
|
|
180
|
+
await handle?.destroy();
|
|
169
181
|
}
|
|
170
182
|
catch {
|
|
171
183
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { DEFAULT_CHARS_PER_TOKEN, estimateContextTokens, estimateTokens } from "../internal/harness.js";
|
|
2
2
|
import { isToolResult } from "./message-utils.js";
|
|
3
3
|
const CLEARED_MARKER = "[tool result cleared to save context]";
|
|
4
|
-
const
|
|
4
|
+
const refNote = (ref) => `full text persisted; call ReadToolResult with ref "${ref}" to read it back`;
|
|
5
|
+
const mediaNote = (n) => `${n} attachment${n === 1 ? "" : "s"} no longer visible after this clear`;
|
|
6
|
+
const clearedMarker = (notes) => {
|
|
7
|
+
const present = notes.filter((n) => n !== undefined);
|
|
8
|
+
return present.length > 0 ? `[tool result cleared to save context — ${present.join("; ")}]` : CLEARED_MARKER;
|
|
9
|
+
};
|
|
5
10
|
export const EDIT_FRACTION = 0.7;
|
|
6
11
|
export const CONTEXT_OUTPUT_RESERVE_TOKENS = 20000;
|
|
7
12
|
export const COMPACTION_TRIGGER_BUFFER_TOKENS = 13000;
|
|
@@ -69,24 +74,25 @@ export function clearStaleToolResults(messages, opts) {
|
|
|
69
74
|
break;
|
|
70
75
|
}
|
|
71
76
|
const before = estimateTokens(out[idx], cpt);
|
|
72
|
-
|
|
77
|
+
const msg = out[idx];
|
|
78
|
+
const rawContent = Array.isArray(msg.content) ? msg.content : [];
|
|
79
|
+
let ref;
|
|
73
80
|
if (opts.offload) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.map((c) => c.text)
|
|
79
|
-
.join("\n")
|
|
80
|
-
: "";
|
|
81
|
+
const fullText = rawContent
|
|
82
|
+
.filter((c) => c?.type === "text" && typeof c.text === "string")
|
|
83
|
+
.map((c) => c.text)
|
|
84
|
+
.join("\n");
|
|
81
85
|
if (msg.toolCallId && fullText.trim().length > 0) {
|
|
82
86
|
try {
|
|
83
|
-
|
|
87
|
+
ref = refNote(opts.offload.persist(msg.toolCallId, fullText));
|
|
84
88
|
}
|
|
85
89
|
catch {
|
|
86
|
-
|
|
90
|
+
ref = undefined;
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
}
|
|
94
|
+
const mediaCount = rawContent.filter((c) => c?.type !== "text").length;
|
|
95
|
+
const marker = clearedMarker([ref, mediaCount > 0 ? mediaNote(mediaCount) : undefined]);
|
|
90
96
|
const cleared = {
|
|
91
97
|
...out[idx],
|
|
92
98
|
content: [{ type: "text", text: marker }],
|