Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions e2e-tests/helpers/utils/normalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,17 @@ export function normalizeMcpCallIds(dump: any): void {
*/
export function normalizeGitContextHashes(dump: any): void {
const scrub = (value: string): string =>
value.replace(/<dyad-git-context\b[^>]*>/g, (tag) =>
tag.replace(
/\b(commit|source_commit)="[0-9a-f]{40,64}"/gi,
'$1="[[GIT_COMMIT]]"',
),
);
value
.replace(
/(<system-reminder>Previous assistant message created (?:commit: |no commit\. Repository commit before that message: ))[0-9a-f]{40,64}(\.<\/system-reminder>)/gi,
"$1[[GIT_COMMIT]]$2",
)
.replace(/<dyad-git-context\b[^>]*>/g, (tag) =>
tag.replace(
/\b(commit|source_commit)="[0-9a-f]{40,64}"/gi,
'$1="[[GIT_COMMIT]]"',
),
);

const visit = (value: unknown, set: (next: unknown) => void): void => {
if (typeof value === "string") {
Expand Down

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion rules/local-agent-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ Agent tool definitions live in `src/pro/main/ipc/handlers/local_agent/tools/`. E
- When extending `handleLocalAgentStream` retry behavior, do not only match transport errors like `"terminated"`. Providers can emit structured stream errors such as `{ type: "error", error: { type: "server_error", ... } }`, and those transient 5xx / rate-limit failures need explicit retry classification too.
- Anthropic rejects any assistant `tool_use` unless the immediately following message contains every matching `tool_result`. When changing local-agent history assembly, retry replay, message injection, or `aiMessagesJson` persistence, run the transcript through the shared tool-call sanitizer at the provider/persistence boundary rather than relying only on the injection site to preserve ordering.
- In `prepareStep`-style paths, normalize the step message array even when `prepareStepMessages` returns `undefined`; split parallel tool results can still need merging on no-injection/no-compaction steps. Prefer the shared `sanitizeStepMessages` helper over ad hoc reference comparisons.
- Persisted assistant Git hashes (`sourceCommitHash` / `commitHash`) are database metadata, not part of `content` or `aiMessagesJson`. When local-agent replay needs that provenance, append an in-memory annotation only after `parseAiMessagesJson` has reconstructed the complete database message. Prefer the final `commitHash`; use `sourceCommitHash` only when no final commit exists, and never rewrite the stored transcript or insert the annotation inside a tool-call/tool-result pair.
- Persisted assistant Git hashes (`sourceCommitHash` / `commitHash`) are database metadata, not part of `content` or `aiMessagesJson`. When local-agent replay needs that provenance, append an in-memory `<system-reminder>` to the next user message only after `parseAiMessagesJson` has reconstructed the complete database messages. Prefer the final `commitHash`; use `sourceCommitHash` only when no final commit exists, and never rewrite the stored transcript or insert the reminder inside a tool-call/tool-result pair. Keep every mode-specific prompt constructor, including curated Build, aligned with this user-message format instead of teaching the retired assistant tag.
- Context compaction removes the assistant row immediately before the triggering user from model-visible history. When forwarding assistant-turn Git provenance to that user, seed it from the excluded preceding assistant; synthetic compaction-summary rows must neither replace nor clear that pending provenance.
- Keep clean no-op turns unversioned: retain their `sourceCommitHash` for provenance but leave `commitHash` null. Do not attach the current `HEAD` merely because it exists; that attributes another turn's checkpoint and exposes unrelated files in version UI and snapshots.

## Metadata-only stop tools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`context compaction (integration) > compaction can run mid-turn > compaction-mid-turn-transcript 1`] = `
"===
role: user
message: [{"type":"text","text":"tc=local-agent/compaction-mid-turn"}]
message: [{"type":"text","text":"tc=local-agent/compaction-mid-turn\\n\\n<system-reminder>Previous assistant message created no commit. Repository commit before that message: [[GIT_COMMIT]].</system-reminder>"}]

===
role: assistant
Expand All @@ -15,11 +15,11 @@ message: [{"type":"tool_result","tool_use_id":"[[TOOL_CALL_0]]","content":"File

===
role: assistant
message: [{"type":"text","text":"END OF COMPACTED TURN."},{"type":"text","text":"<dyad-git-context source_commit=\\"[[GIT_COMMIT]]\\" no_commit=\\"true\\"></dyad-git-context>"}]
message: [{"type":"text","text":"END OF COMPACTED TURN."}]

===
role: user
message: [{"type":"text","text":"[dump] hi"}]"
message: [{"type":"text","text":"[dump] hi\\n\\n<system-reminder>Previous assistant message created no commit. Repository commit before that message: [[GIT_COMMIT]].</system-reminder>"}]"
`;

exports[`context compaction (integration) > compaction triggers and shows summary > compaction-post-summary-transcript 1`] = `
Expand All @@ -29,13 +29,13 @@ message: [{"type":"text","text":"<dyad-compaction title=\\"Conversation compacte

===
role: user
message: [{"type":"text","text":"tc=local-agent/simple-response"}]
message: [{"type":"text","text":"tc=local-agent/simple-response\\n\\n<system-reminder>Previous assistant message created commit: [[GIT_COMMIT]].</system-reminder>"}]

===
role: assistant
message: [{"type":"text","text":"Hello! I understand your request. This is a simple response from the Basic Agent mode."},{"type":"text","text":"<dyad-git-context source_commit=\\"[[GIT_COMMIT]]\\" no_commit=\\"true\\"></dyad-git-context>"}]
message: [{"type":"text","text":"Hello! I understand your request. This is a simple response from the Basic Agent mode."}]

===
role: user
message: [{"type":"text","text":"[dump] hi"}]"
message: [{"type":"text","text":"[dump] hi\\n\\n<system-reminder>Previous assistant message created no commit. Repository commit before that message: [[GIT_COMMIT]].</system-reminder>"}]"
`;
Loading
Loading