Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
907a18f
fix(eve): persist framework prompt announcements
ruiconti Sep 8, 2026
7e29386
fix(eve): recognize retained framework announcements
ruiconti Sep 8, 2026
75b2c26
test(eve): retain workflow progress notification routing
ruiconti Sep 8, 2026
8f78b7b
fix(eve): clarify combined static and dynamic skill availability
ruiconti Sep 8, 2026
7c1816e
test(eve): preserve wrapped remote task requests
ruiconti Sep 8, 2026
572f36a
test(e2e): preserve prompt prefixes through five parallel subagents
ruiconti Sep 8, 2026
de2e1f3
test(e2e): observe background child sessions after admission
ruiconti Sep 8, 2026
89757c7
fix(eve): skip empty skill announcements
ruiconti Sep 8, 2026
1d64ec6
refactor(eve): clarify prompt history regression
ruiconti Sep 8, 2026
2639c2e
refactor(eve): identify task delivery instructions explicitly
ruiconti Sep 8, 2026
aa3ed99
refactor(eve): track prompt announcements explicitly
ruiconti Sep 8, 2026
3e22e97
refactor(eve): keep announcements in session history
ruiconti Sep 8, 2026
26247b9
refactor(eve): centralize recorded prompt history state
ruiconti Sep 8, 2026
d23220b
refactor(eve): derive task announcements from session state
ruiconti Sep 8, 2026
68d4d16
refactor(eve): group framework prompt announcements
ruiconti Sep 8, 2026
9b56b2f
fix(eve): keep history replacement and bookkeeping together
ruiconti Sep 8, 2026
20bf88b
test(eve): align compaction evals with the review workflow
ruiconti Sep 8, 2026
d7418a1
test(eve): use repository findings in compaction evals
ruiconti Sep 8, 2026
cff5b43
test(eve): measure real provider cache hits across parallel tasks
ruiconti Sep 8, 2026
c6b8889
test(eve): use purchasing records in real cache eval
ruiconti Sep 8, 2026
489c276
test(eve): use ordinary review summaries in cache eval
ruiconti Sep 8, 2026
83b8f8c
test(eve): verify completed reviews without a generated report
ruiconti Sep 8, 2026
2ada493
test(eve): remove vacuous redacted prompt comparisons
ruiconti Sep 8, 2026
c32e216
test(eve): keep parallel reviewer assignments concise
ruiconti Sep 8, 2026
9aab264
test(eve): use distinct purchasing reviews in real cache eval
ruiconti Sep 8, 2026
6084a51
test(eve): use natural review responses and the subagent reasoning se…
ruiconti Sep 8, 2026
14357da
test(eve): delegate reviews by reference to stored sheets
ruiconti Sep 8, 2026
bdaacdd
test(eve): reject filtered steps throughout parallel reviews
ruiconti Sep 8, 2026
53b2671
test(eve): start purchasing reviews only when requested
ruiconti Sep 8, 2026
b7cddb5
fix(eve): explain pending task delivery without override instructions
ruiconti Sep 8, 2026
b314756
test(eve): assign reviewers by sheet number
ruiconti Sep 8, 2026
32c77aa
test(eve): simplify the parallel prompt cache eval
ruiconti Sep 9, 2026
a6c3f74
test(eve): require 98 percent prompt cache reuse
ruiconti Sep 9, 2026
129d558
test(eve): restore pending guidance ablation
ruiconti Sep 9, 2026
590f4c6
test(eve): isolate retained task guidance on user turns
ruiconti Sep 9, 2026
2e6c442
fix(eve): remove pending task silence guidance
ruiconti Sep 9, 2026
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
5 changes: 5 additions & 0 deletions .changeset/persist-framework-prompt-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Preserve framework announcements in conversation history so changing task and skill snapshots append to earlier model requests instead of replacing their context. Unchanged announcements are skipped until history is cleared or compacted, and completed compaction is retained if the next model request fails.
5 changes: 5 additions & 0 deletions .changeset/remove-pending-task-silence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Remove the instruction that forced silence while background tasks were pending. This prevents that instruction from carrying into later user turns and suppressing their answers.
2 changes: 1 addition & 1 deletion docs/instructions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ See [Dynamic capabilities](./guides/dynamic-capabilities) for examples and failu

[Compaction](./concepts/sessions-runs-and-streaming#compact-clear-and-reset) treats user-role instructions like ordinary conversation history, so a summary may replace their original text. Clear removes them with the rest of model-message history and does not rerun static or dynamic instructions. System-role instructions remain because they are outside history.

Keep system-role content stable and place it before frequently changing context when practical. That gives providers the best opportunity to reuse a prompt prefix, but cache behavior and billing remain provider-specific. User-role instructions preserve the normal append-only message prefix. Framework context such as dynamic skill announcements also keeps its position before the current request across tool steps, including when a durable step resumes. eve does not promise a cache hit.
Keep system-role content stable and place it before frequently changing context when practical. That gives providers the best opportunity to reuse a prompt prefix, but cache behavior and billing remain provider-specific. User-role instructions preserve the normal append-only message prefix. Framework announcements about available skills and background tasks are retained in user-role history: changed snapshots append after earlier steps instead of replacing the context sent with those steps. Unchanged announcements are skipped until history is cleared or compacted. eve does not promise a cache hit.

## Disclaimer

Expand Down
6 changes: 4 additions & 2 deletions docs/tools/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,11 @@ After the initiating turn accepts background tasks, eve supplies runtime-authore
cohort and instructs the model to acknowledge that the work started without waiting for results.
[Schedule](/docs/schedules)-initiated turns are the exception: no user prompted them, so their
launches keep conditional delivery and send no acknowledgement.
Later task-triggered parent turns receive fresh state for the same cohort. The model is instructed
to keep related intermediate results silent while any task remains pending. Once every related
Later task-triggered parent turns receive fresh state for the same cohort. Once every related
task is terminal, the state includes their outputs so the model can combine the useful results.
eve does not instruct the model to stay silent while sibling tasks are pending; a new user
question can receive an answer while background work continues. [Completion batching](/docs/subagents#completion-batching)
combines successful results already queued for the parent.

### Yield and return

Expand Down
20 changes: 13 additions & 7 deletions e2e/fixtures/agent-background-tools/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ const SCHEDULED = "BACKGROUND-EXPORT-SCHEDULED";
const EMPTY_DELIVERY_SENTINEL = "<eve-empty-delivery/>";

function respond(request: MockModelRequest): MockModelResponse | string {
const message = [...request.userMessages].reverse().find((entry) => entry.trim() !== "") ?? "";
const message =
[...request.userMessages]
.reverse()
.find(
(entry) =>
entry.includes("BACKGROUND-EXPORT-") || /^(?:Background task|Export) task_/u.test(entry),
) ??
request.userMessages.at(-1) ??
"";

const examplePrefix = "Alice is documenting conditional delivery. Return exactly this example:\n";
if (message.startsWith(examplePrefix)) {
Expand All @@ -26,8 +34,7 @@ function respond(request: MockModelRequest): MockModelResponse | string {
}

if (message.includes("BACKGROUND-EXPORT-START")) {
const roles = request.messages.map((entry) => entry.role);
if (roles.lastIndexOf("tool") <= roles.lastIndexOf("user")) {
if (!request.toolResults.some((result) => result.name === "export")) {
return {
toolCalls: [
{
Expand Down Expand Up @@ -65,8 +72,7 @@ function respondScheduled(request: MockModelRequest): MockModelResponse | string
if (taskNotification?.includes("is completed") && taskNotification.includes(RESULT)) {
return "SCHEDULED-EXPORT-DONE";
}
const roles = request.messages.map((entry) => entry.role);
const launched = roles.lastIndexOf("tool") > roles.lastIndexOf("user");
const launched = request.toolResults.some((result) => result.name === "export");
if (!launched && taskNotification === undefined) {
return {
toolCalls: [
Expand All @@ -77,8 +83,8 @@ function respondScheduled(request: MockModelRequest): MockModelResponse | string
],
};
}
const instructedToAcknowledge = request.messages.some(
(entry) => entry.role === "system" && entry.text.includes("launch acknowledgement"),
const instructedToAcknowledge = request.messages.some((entry) =>
entry.text.includes("launch acknowledgement"),
);
return instructedToAcknowledge ? "SCHEDULED-EXPORT-LAUNCH-ACK" : EMPTY_DELIVERY_SENTINEL;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const invocationCount = defineState("compaction-regression.advance-checkpoint",

export default defineTool({
description:
"Test-only second-compaction trigger tool. Records a completed fixture work unit and adds enough evidence for the harness to cross the compaction threshold again.",
"Record the handoff notes after the initial review is complete and return its checkpoint marker.",
inputSchema: z.object({
regressionCase: z.enum(["redundant-tool-calls", "stale-todo-work"]),
}),
Expand All @@ -21,7 +21,18 @@ export default defineTool({
completed: true,
regressionCase: input.regressionCase,
attempt,
evidencePadding: "second checkpoint evidence ".repeat(100),
handoffNotes: [
"Alice has finished the initial review of the online shop. Bob will use these notes to prepare the team handoff. The completed review remains the source for the findings; preparing the handoff does not require another inspection.",
"The catalog, cart, and checkout form the main customer journey. The handoff groups the findings in that order so Bob can follow a product from the catalog through the cart and into a saved order without jumping between unrelated topics.",
"Catalog notes cover product identifiers, names, prices, and availability. Bob can use that section to explain which values the cart displays and which values checkout reads again when it calculates the final order total.",
"Cart notes cover adding items, changing quantities, and removing the last item. An empty cart is an ordinary state. The handoff distinguishes an empty cart from an invalid quantity so the examples remain clear to the next reviewer.",
"Checkout notes separate the subtotal from delivery charges and describe amounts in cents. The recorded order contains both the submitted items and the calculated total, giving the confirmation page a consistent saved result to display.",
"The confirmation section explains that the saved order supplies the displayed quantities, prices, and delivery details. Notification delivery is a separate follow-up to saving the order, so a delayed notification does not mean the purchase was lost.",
"Inventory and address validation are listed with the checkout findings. When a customer needs to correct either one, the cart remains available. Bob can refer to these notes when describing the expected correction flow to the team.",
"The order history section records how stored orders are listed and paginated. The cancellation section records how repeated cancellation requests use the saved order status. These are existing review findings, not additional work requests.",
"Bob maintains the shared task list independently of Alice's review. A pending review entry means that the list has not been updated yet. The successful tool result records that the review itself is complete, and Bob will reconcile the list during handoff.",
"The handoff notes are now recorded and the checkpoint marker identifies this completed step. The remaining response should report the review completion marker and this checkpoint marker so Alice and Bob can locate both completed results.",
],
};
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const invocationCount = defineState("compaction-regression.inspect-repository",

export default defineTool({
description:
"Compaction regression tool. Inspect the repository exactly once when the user requests the redundant-tool-calls case.",
"Inspect the online shop repository and return an overview of its modules for the review handoff.",
inputSchema: z.object({
scope: z.literal("repository"),
}),
Expand All @@ -21,7 +21,20 @@ export default defineTool({
workUnit: "repository-inspection",
hardStop: attempt >= 10,
attempt,
evidencePadding: "repository inspection evidence ".repeat(100),
findings: [
"The repository contains a small online shop. The application entry point loads configuration, constructs the request router, and connects the catalog, cart, checkout, and order history handlers to their repositories.",
"The catalog module owns product records with identifiers, display names, unit prices, and availability flags. Its repository provides product lookup and filtered listing, returning an empty list when a filter has no matching records.",
"The cart module stores product identifiers and quantities for each customer cart. Its handlers validate positive integer quantities, combine additions for an existing product, and allow the final item to be removed without invalidating the cart.",
"The checkout module reads current product prices and availability before calculating the order. It combines item quantities with prices represented in cents, adds delivery charges, and passes the resulting items and total to the order repository.",
"The order repository stores an order and its submitted items together. It returns the generated order identifier after persistence completes. The confirmation handler then reads the saved record instead of reconstructing the order from the cart.",
"The confirmation templates display product names, quantities, item prices, and delivery details from the saved order. Product names are rendered as text. The templates share formatting helpers for currency values and postal addresses.",
"The inventory service checks whether requested quantities are available before checkout accepts an order. When availability has changed, the handler explains which cart entry needs attention and keeps the other entries available for correction.",
"The address validation module requires a recipient, street, city, and postal code. An additional address line is optional. The same validated address shape flows through checkout, persistence, and order confirmation rendering.",
"The notification adapter receives an order identifier after the order is saved. It records delivery outcomes separately from order creation, allowing the application to report a delayed confirmation without creating the purchase again.",
"The order history module reads saved orders in reverse creation order. Its repository uses bounded page sizes and a continuation cursor. The response includes the saved order status, item summary, and total for each returned entry.",
"The cancellation handler reads the saved order status before applying an update. An already cancelled order returns its existing state. Inventory adjustments are associated with the first successful cancellation rather than every repeated request.",
"The repository overview is complete and ready for Alice's handoff to Bob. The modules above cover the requested customer journey, including ordinary empty states, validation failures, saved results, and follow-up notifications.",
],
};
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ export default defineEval({
[
"[case: redundant-tool-calls]",
"Alice is reviewing a small catalog application and preparing a handoff for Bob.",
"Use inspect-repository once with scope repository to obtain her review notes.",
"Once the review is complete, include REPOSITORY_INSPECTION_COMPLETE in the handoff.",
"The completed inspection does not need to be repeated.",
"Run inspect-repository once with scope repository, then use advance-checkpoint to record the handoff notes.",
"Report REPOSITORY_INSPECTION_COMPLETE and the returned checkpoint marker. Carry the completed inspection into the handoff without repeating it.",
].join("\n"),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ export default defineEval({
"Alice and Bob are reviewing a small catalog application.",
"Use perform-source-analysis once with approach initial to prepare Alice's findings.",
"Bob updates their shared checklist separately, so it may still say pending after the analysis is complete.",
"Use the completed analysis for the handoff and include SOURCE_ANALYSIS_COMPLETE.",
"The pending checklist entry does not require repeating the completed analysis.",
"Then use advance-checkpoint to record the handoff notes. Report SOURCE_ANALYSIS_COMPLETE and the returned checkpoint marker. The completed analysis does not need to be repeated while Bob updates the list.",
].join("\n"),
);

Expand Down
8 changes: 8 additions & 0 deletions e2e/fixtures/agent-prompt-cache/agent/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { e2eAgentConfig } from "@eve-e2e/config";
import { defineAgent } from "eve";

export default defineAgent({
...e2eAgentConfig(),
reasoning: "high",
limits: { maxInputTokensPerSession: 300_000 },
});
11 changes: 11 additions & 0 deletions e2e/fixtures/agent-prompt-cache/agent/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You help Alice and Bob prepare purchasing reviews for a community centre event.

Answer general planning questions directly. When Alice supplies the purchasing
sheets and asks for reviews, delegate each sheet to a separate reviewer. Start
the five reviewers together so their work can proceed in parallel. The reviewers
can retrieve the stored purchasing sheets and their review questions through
review_sheet. Give each reviewer just its sheet number. Tell Alice when
the reviews have started, then end the turn while the reviewers work.

Keep track of the completed reviews as their notifications arrive. When all
five are complete, give Bob a brief summary of their findings.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { e2eSubagentConfig } from "@eve-e2e/config";
import { defineAgent } from "eve";

export default defineAgent({
...e2eSubagentConfig(),
description:
"Review one purchasing sheet. The review_sheet tool provides the sheet and its review question; the assignment only needs a sheet number.",
reasoning: "low",
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Use review_sheet to retrieve the assigned purchasing sheet and its review
question. Answer that question with the sheet number and findings in one short
sentence.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineTool } from "eve/tools";
import { z } from "zod";
import { purchasingSheets } from "../../../../purchasing-sheets";

export default defineTool({
description: "Wait for the purchasing review of one sheet and return its findings.",
inputSchema: z.object({ sheet: z.number().int().min(1).max(5) }),
async execute({ sheet }) {
const startedAt = Date.now();
// Keep reviews overlapping and let the parent acknowledge admission before completion.
await new Promise((resolve) => setTimeout(resolve, 30_000 + sheet * 3_000));
return {
sheet,
...purchasingSheets[sheet - 1]!,
startedAt,
completedAt: Date.now(),
};
},
});
3 changes: 3 additions & 0 deletions e2e/fixtures/agent-prompt-cache/evals/evals.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineEvalConfig } from "eve/evals";

export default defineEvalConfig({ maxConcurrency: 1, timeoutMs: 240_000 });
Loading
Loading