Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4798cb9
feat: count shell fetches and read Codex's web_search action for docs…
mattrossman Jul 27, 2026
c3d64d8
fix: leave a Codex search action's content unknown rather than false
mattrossman Jul 27, 2026
e74878a
fix: count only shell fetches returned to the model
mattrossman Jul 28, 2026
20f65c1
Merge remote-tracking branch 'origin/main' into mattrossman/ai-958-in…
mattrossman Jul 28, 2026
64f8849
chore: refresh eval results
github-actions[bot] Jul 28, 2026
4502e71
chore: refresh eval results
github-actions[bot] Jul 28, 2026
4ccc766
fix: mark ambiguous shell fetches as unknown
mattrossman Jul 28, 2026
ba0dfb2
chore: refresh eval results
github-actions[bot] Jul 28, 2026
d36a5cf
chore: refresh eval results
github-actions[bot] Jul 28, 2026
f67aa40
chore: refresh eval results
github-actions[bot] Jul 28, 2026
cfafaaa
chore: refresh eval results
github-actions[bot] Jul 28, 2026
9a2f178
chore: refresh eval results
github-actions[bot] Jul 28, 2026
766c1a9
fix: preserve mixed shell result size
mattrossman Jul 29, 2026
e89a06e
Merge remote-tracking branch 'origin/main' into mattrossman/ai-958-in…
mattrossman Jul 31, 2026
313bd1e
fix: mark unflagged curl shell fetches as unknown content
mattrossman Jul 31, 2026
5de73b9
fix: use one consistent apex-host check for supabase docs reads
mattrossman Jul 31, 2026
9e36add
fix: rehydrate truncated docs results after scoring, not before
mattrossman Jul 31, 2026
4da4d91
fix: make shell fetch stdout-redirect check fd-aware
mattrossman Jul 31, 2026
e9d7220
fix: only count curl/wget as a shell fetch when it's the actual command
mattrossman Jul 31, 2026
e51c7b6
chore: format
mattrossman Jul 31, 2026
612cb7d
fix: split shell segments on newlines to find curl/wget across lines
mattrossman Aug 3, 2026
4a2c4f2
revert: restore eval-results.json to main, keep only the code fix
mattrossman Aug 3, 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
14 changes: 7 additions & 7 deletions apps/framework/harness/run-eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,6 @@ async function runOne(
mcpServers: session.mcpServers,
timeoutSec: TIMEOUT_SEC,
});
// Must run before session disposes below, see rehydrateTruncatedDocsResults.
await rehydrateTruncatedDocsResults(session.sandbox, run.toolCalls);

lastToolCalls = run.toolCalls;
lastTranscript = run.transcript;
lastAgentReport = run.agentReport;
Expand Down Expand Up @@ -485,6 +482,9 @@ async function runOne(
},
});

// Runs after scoring so the scorer sees what the agent actually saw, not rehydrated content.
await rehydrateTruncatedDocsResults(session.sandbox, run.toolCalls);

if (STOP_ON_PASS && last.passed) {
return {
...last,
Expand Down Expand Up @@ -536,10 +536,6 @@ async function runOne(
sandbox: cliSandbox?.sandbox,
timeoutSec: TIMEOUT_SEC,
});
// Must run before cliSandbox disposes below, see rehydrateTruncatedDocsResults.
if (cliSandbox)
await rehydrateTruncatedDocsResults(cliSandbox.sandbox, run.toolCalls);

lastToolCalls = run.toolCalls;
lastTranscript = run.transcript;
lastAgentReport = run.agentReport;
Expand All @@ -551,6 +547,10 @@ async function runOne(
agentReport: run.agentReport,
});

// Runs after scoring so the scorer sees what the agent actually saw, not rehydrated content.
if (cliSandbox)
await rehydrateTruncatedDocsResults(cliSandbox.sandbox, run.toolCalls);

if (STOP_ON_PASS && last.passed) {
return {
...last,
Expand Down
40 changes: 25 additions & 15 deletions apps/web/src/components/results/eval-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ReactNode } from "react"
import {
CheckIcon,
ChevronRightIcon,
CircleHelpIcon,
FileTextIcon,
SearchIcon,
XIcon,
Expand All @@ -16,13 +17,15 @@ const DOCS_CALL_SOURCE_LABEL: Record<DocsCall["source"], string> = {
search_docs: "MCP",
web_fetch: "Web Fetch",
web_search: "Web Search",
shell_fetch: "Shell",
}

// Cool color for MCP (our own docs tool), warm for the agent going around it onto the open web.
const DOCS_CALL_SOURCE_CHIP_CLASS: Record<DocsCall["source"], string> = {
search_docs: "bg-indigo-500/10 text-indigo-700 dark:text-indigo-400",
web_fetch: "bg-amber-500/10 text-amber-700 dark:text-amber-400",
web_search: "bg-amber-500/10 text-amber-700 dark:text-amber-400",
shell_fetch: "bg-orange-500/10 text-orange-700 dark:text-orange-400",
}

const docsSourceChipClassName =
Expand All @@ -31,9 +34,10 @@ const docsSourceChipClassName =
const evalMetaGridClassName =
"grid grid-cols-[6.5rem_minmax(0,1fr)] items-start gap-x-4 gap-y-4 text-xs"

/** Search icon for a bare hit, file icon for a call that actually pulled in page text. */
/** Shows whether page content was read, not read, or cannot be determined. */
function docsCallIcon(call: DocsCall) {
return call.hasContent === false ? SearchIcon : FileTextIcon
if (call.hasContent === undefined) return CircleHelpIcon
return call.hasContent ? FileTextIcon : SearchIcon
}

/** Pulls the quoted search term out of search_docs's raw GraphQL query for display, else returns the query as-is. */
Expand Down Expand Up @@ -120,6 +124,7 @@ function ResultDocsCalls({ calls }: { calls: DocsCall[] }) {
<div className="flex flex-col gap-1.5 leading-relaxed text-foreground">
{calls.map((call, index) => {
const searchOnly = call.hasContent === false
const contentUnknown = call.hasContent === undefined
const Icon = docsCallIcon(call)
const queryLabel = docsCallQueryLabel(call)
const sizeLabel = docsCallSizeLabel(call)
Expand All @@ -132,24 +137,29 @@ function ResultDocsCalls({ calls }: { calls: DocsCall[] }) {
className="size-4 shrink-0 text-muted-foreground/50 transition-transform group-open:rotate-90"
aria-hidden
/>
<Icon
className={cn(
"size-4 shrink-0",
searchOnly
? "text-muted-foreground/60"
: "text-muted-foreground"
)}
aria-hidden
/>
<span
title={contentUnknown ? "Content unknown" : undefined}
className="shrink-0"
>
<Icon
className={cn(
"size-4",
searchOnly || contentUnknown
? "text-muted-foreground/60"
: "text-muted-foreground"
)}
aria-hidden
/>
</span>
<span
title={queryLabel}
className={cn(
"min-w-0 truncate",
searchOnly ? "text-muted-foreground" : "text-foreground"
)}
className="min-w-0 truncate text-foreground"
>
{queryLabel}
</span>
{contentUnknown ? (
<span className="sr-only">Content unknown</span>
) : null}
{sizeLabel ? (
<span className="shrink-0 font-mono text-xs tracking-wide text-muted-foreground">
{sizeLabel}
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/agents/codex/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,27 @@ describe('codexParser', () => {
expect(result?.tool?.originalName).toBe('search_docs');
});

it("keeps a web_search item's action, which says what the hosted tool did", () => {
const url = 'https://supabase.com/changelog.md';
const stream = JSON.stringify({
type: 'item.completed',
item: {
id: 'ws_0',
type: 'web_search',
query: url,
action: { type: 'open_page', url },
status: 'completed',
},
});

const adapted = adaptTranscript(codexParser.parseTranscript(stream).events);
expect(adapted.toolCalls[0].name).toBe('web_search');
expect(adapted.toolCalls[0].body).toEqual({
query: url,
action: { type: 'open_page', url },
});
});

it('emits an error event for a failed turn', () => {
const stream = [
JSON.stringify({ type: 'turn.started' }),
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/agents/codex/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,14 @@ function itemToEvents(item: Record<string, unknown>): TranscriptEvent[] {
);
}
case 'web_search': {
// `action` says what the hosted tool actually did (`search`,
// `open_page`, `find_in_page`). `query` is only its display rendering,
// which collapses a url open and a search for that url into the same
// string, so keep the action itself.
return toolCallPair(
id,
'web_search',
{ query: item.query },
{ query: item.query, action: item.action },
undefined,
statusSuccess(item.status)
);
Expand Down
Loading