@granular-software/sdk 0.4.46 → 0.4.47
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/agent-evals.d.mts +3 -0
- package/dist/agent-evals.d.ts +3 -0
- package/dist/agent-evals.js +692 -419
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +692 -419
- package/dist/agent-evals.mjs.map +1 -1
- package/package.json +1 -1
package/dist/agent-evals.mjs
CHANGED
|
@@ -19862,6 +19862,202 @@ async function writeJson(filePath, value) {
|
|
|
19862
19862
|
await writeFile(filePath, `${JSON.stringify(value, null, 2)}
|
|
19863
19863
|
`);
|
|
19864
19864
|
}
|
|
19865
|
+
function safePathSegment(value, fallback) {
|
|
19866
|
+
const normalized = (value || "").trim().toLowerCase();
|
|
19867
|
+
const sanitized = normalized.replace(/[^a-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 128);
|
|
19868
|
+
return sanitized || fallback;
|
|
19869
|
+
}
|
|
19870
|
+
function extractToolCalls(rawGeneration) {
|
|
19871
|
+
const raw = asRecord6(rawGeneration);
|
|
19872
|
+
if (!raw) return null;
|
|
19873
|
+
const choices = asArray3(raw.choices);
|
|
19874
|
+
const firstChoiceMessage = asRecord6(choices[0]);
|
|
19875
|
+
const message = asRecord6(firstChoiceMessage?.message);
|
|
19876
|
+
const toolCalls = asArray3(message?.tool_calls);
|
|
19877
|
+
if (toolCalls.length > 0) return toolCalls;
|
|
19878
|
+
return asArray3(raw.tool_calls).length > 0 ? asArray3(raw.tool_calls) : null;
|
|
19879
|
+
}
|
|
19880
|
+
function buildTurnMdxReport(input) {
|
|
19881
|
+
const {
|
|
19882
|
+
status,
|
|
19883
|
+
conversation,
|
|
19884
|
+
request,
|
|
19885
|
+
requestTimestamp,
|
|
19886
|
+
turnLog,
|
|
19887
|
+
responseText,
|
|
19888
|
+
terminalKind,
|
|
19889
|
+
actionSummary = [],
|
|
19890
|
+
promptInteractions = [],
|
|
19891
|
+
result,
|
|
19892
|
+
prompts = [],
|
|
19893
|
+
verification,
|
|
19894
|
+
error
|
|
19895
|
+
} = input;
|
|
19896
|
+
const iterationLines = [];
|
|
19897
|
+
for (const iteration of turnLog.iterations) {
|
|
19898
|
+
iterationLines.push(`### Iteration ${iteration.iteration}`);
|
|
19899
|
+
iterationLines.push(
|
|
19900
|
+
`- Request: ${iteration.request}`,
|
|
19901
|
+
`- Generation duration: ${iteration.generationDurationMs !== void 0 ? `${iteration.generationDurationMs}ms` : "unknown"}`
|
|
19902
|
+
);
|
|
19903
|
+
if (iteration.templateId) {
|
|
19904
|
+
iterationLines.push(
|
|
19905
|
+
`- Template: ${iteration.templateId}@${iteration.templateVersion || "unknown"}`
|
|
19906
|
+
);
|
|
19907
|
+
}
|
|
19908
|
+
if (iteration.templateHash) {
|
|
19909
|
+
iterationLines.push(`- Template hash: ${iteration.templateHash}`);
|
|
19910
|
+
}
|
|
19911
|
+
if (iteration.promptInstanceHash) {
|
|
19912
|
+
iterationLines.push(`- Prompt hash: ${iteration.promptInstanceHash}`);
|
|
19913
|
+
}
|
|
19914
|
+
iterationLines.push("", "#### Full prompt sent to LLM", "");
|
|
19915
|
+
iterationLines.push(fenced(iteration.systemPrompt, "text"));
|
|
19916
|
+
if (iteration.generationReply?.trim()) {
|
|
19917
|
+
iterationLines.push(
|
|
19918
|
+
"",
|
|
19919
|
+
"#### LLM reply text",
|
|
19920
|
+
iteration.generationReply.trim(),
|
|
19921
|
+
""
|
|
19922
|
+
);
|
|
19923
|
+
}
|
|
19924
|
+
if (iteration.generatedCode?.trim()) {
|
|
19925
|
+
iterationLines.push("#### Generated code", "", fenced(iteration.generatedCode.trim(), "ts"));
|
|
19926
|
+
}
|
|
19927
|
+
const toolCalls = extractToolCalls(iteration.rawGeneration);
|
|
19928
|
+
iterationLines.push("#### Tool calls / raw generation", "");
|
|
19929
|
+
if (toolCalls) {
|
|
19930
|
+
iterationLines.push(fenced(JSON.stringify(toolCalls, null, 2), "json"));
|
|
19931
|
+
} else if (iteration.rawGeneration) {
|
|
19932
|
+
iterationLines.push(fenced(JSON.stringify(iteration.rawGeneration, null, 2), "json"));
|
|
19933
|
+
} else {
|
|
19934
|
+
iterationLines.push("_No tool call information._");
|
|
19935
|
+
}
|
|
19936
|
+
if (iteration.tokenUsage) {
|
|
19937
|
+
iterationLines.push("", "#### Token usage", ...formatTokenUsage(iteration.tokenUsage));
|
|
19938
|
+
}
|
|
19939
|
+
if (iteration.responseText?.trim()) {
|
|
19940
|
+
iterationLines.push("", "#### Runtime/prompt outcome", iteration.responseText);
|
|
19941
|
+
}
|
|
19942
|
+
if (iteration.actionSummary?.length) {
|
|
19943
|
+
iterationLines.push("", "#### Action summary", "");
|
|
19944
|
+
iterationLines.push(...iteration.actionSummary.map((line) => `- ${line}`));
|
|
19945
|
+
}
|
|
19946
|
+
if (iteration.continuation) {
|
|
19947
|
+
iterationLines.push("", "#### Continuation", "", jsonBlock(iteration.continuation));
|
|
19948
|
+
}
|
|
19949
|
+
if (iteration.result !== void 0) {
|
|
19950
|
+
iterationLines.push("", "#### Result", "", jsonBlock(iteration.result));
|
|
19951
|
+
}
|
|
19952
|
+
if (iteration.error) {
|
|
19953
|
+
iterationLines.push("", `#### Error`, "", iteration.error);
|
|
19954
|
+
}
|
|
19955
|
+
iterationLines.push("", "---", "");
|
|
19956
|
+
}
|
|
19957
|
+
const promptEventLines = conversation.promptEvents.filter((event) => event.receivedAt >= requestTimestamp).map((event, index) => {
|
|
19958
|
+
const prompt = event.prompt;
|
|
19959
|
+
return `${index + 1}. ${prompt.type} ${prompt.title || ""} ${prompt.message ? `\u2014 ${prompt.message}` : ""}`;
|
|
19960
|
+
});
|
|
19961
|
+
const historyLines = conversation.history.map((entry, index) => {
|
|
19962
|
+
const label = `${index + 1}. ${entry.role}`;
|
|
19963
|
+
const detail = entry.content || (entry.code ? "(code)" : "");
|
|
19964
|
+
return `${label}: ${detail || "(no text)"}`;
|
|
19965
|
+
});
|
|
19966
|
+
const lines = [
|
|
19967
|
+
"# Local Agent Query Report",
|
|
19968
|
+
"",
|
|
19969
|
+
`- timestamp: ${new Date(requestTimestamp).toISOString()}`,
|
|
19970
|
+
`- turn: ${turnLog.turnNumber} (${turnLog.turnId})`,
|
|
19971
|
+
`- status: ${status}`,
|
|
19972
|
+
"",
|
|
19973
|
+
"## Table of contents",
|
|
19974
|
+
"- [Metadata](#metadata)",
|
|
19975
|
+
"- [User query and context](#user-query-and-context)",
|
|
19976
|
+
"- [Conversation history](#conversation-history)",
|
|
19977
|
+
"- [Harness loop iterations](#harness-loop-iterations)",
|
|
19978
|
+
"- [Result and interactions](#result-and-interactions)",
|
|
19979
|
+
"",
|
|
19980
|
+
"## Metadata",
|
|
19981
|
+
`- Ontology: ${conversation.environment.ontologyId}`,
|
|
19982
|
+
`- Subject: ${conversation.environment.subjectId}`,
|
|
19983
|
+
`- Session: ${conversation.environment.sessionId}`,
|
|
19984
|
+
`- Environment: ${conversation.environment.environmentId}`,
|
|
19985
|
+
`- Sandbox: ${conversation.environment.sandboxId}`,
|
|
19986
|
+
`- Permission profile: ${conversation.environment.permissionProfileId}`,
|
|
19987
|
+
`- Conversation artifacts: ${turnLog.turnDir}`,
|
|
19988
|
+
"",
|
|
19989
|
+
"## User query and context",
|
|
19990
|
+
"",
|
|
19991
|
+
"### Request",
|
|
19992
|
+
fenced(request, "text"),
|
|
19993
|
+
"",
|
|
19994
|
+
"### Open prompts at/after request time"
|
|
19995
|
+
];
|
|
19996
|
+
if (promptEventLines.length) {
|
|
19997
|
+
lines.push(...promptEventLines.map((line) => `- ${line}`));
|
|
19998
|
+
} else {
|
|
19999
|
+
lines.push("- _None");
|
|
20000
|
+
}
|
|
20001
|
+
lines.push(
|
|
20002
|
+
"",
|
|
20003
|
+
"## Conversation history",
|
|
20004
|
+
...historyLines.map((line) => `- ${line}`),
|
|
20005
|
+
"",
|
|
20006
|
+
"## Harness loop iterations",
|
|
20007
|
+
"",
|
|
20008
|
+
...iterationLines,
|
|
20009
|
+
"## Result and interactions",
|
|
20010
|
+
""
|
|
20011
|
+
);
|
|
20012
|
+
if (responseText) {
|
|
20013
|
+
lines.push("### Final response", responseText, "");
|
|
20014
|
+
}
|
|
20015
|
+
if (terminalKind) {
|
|
20016
|
+
lines.push(`### Terminal kind`, terminalKind, "");
|
|
20017
|
+
}
|
|
20018
|
+
lines.push("### Action summary");
|
|
20019
|
+
if (actionSummary.length) {
|
|
20020
|
+
lines.push(...actionSummary.map((line) => `- ${line}`));
|
|
20021
|
+
} else {
|
|
20022
|
+
lines.push("- None");
|
|
20023
|
+
}
|
|
20024
|
+
lines.push("", "### User interactions");
|
|
20025
|
+
if (promptInteractions.length) {
|
|
20026
|
+
for (const interaction of promptInteractions) {
|
|
20027
|
+
lines.push(
|
|
20028
|
+
`- ${interaction.type} ${interaction.message || interaction.title} -> ${JSON.stringify(interaction.answer)}`
|
|
20029
|
+
);
|
|
20030
|
+
}
|
|
20031
|
+
} else {
|
|
20032
|
+
lines.push("- None");
|
|
20033
|
+
}
|
|
20034
|
+
lines.push("", "### Pending prompts");
|
|
20035
|
+
if (prompts.length) {
|
|
20036
|
+
for (const prompt of prompts) {
|
|
20037
|
+
lines.push(`- ${prompt.type} ${prompt.title || ""} ${prompt.message || ""}`);
|
|
20038
|
+
}
|
|
20039
|
+
} else {
|
|
20040
|
+
lines.push("- None");
|
|
20041
|
+
}
|
|
20042
|
+
if (result !== void 0) {
|
|
20043
|
+
lines.push("", "### Result payload", "", jsonBlock(result));
|
|
20044
|
+
}
|
|
20045
|
+
if (verification !== void 0) {
|
|
20046
|
+
lines.push("", "### Verification", "", jsonBlock(verification));
|
|
20047
|
+
}
|
|
20048
|
+
if (error) {
|
|
20049
|
+
lines.push("", `### Error`, "", error);
|
|
20050
|
+
}
|
|
20051
|
+
if (turnLog.error) {
|
|
20052
|
+
lines.push("", "### Turn log error", "", turnLog.error);
|
|
20053
|
+
}
|
|
20054
|
+
lines.push("");
|
|
20055
|
+
if (iterationLines.length === 0) {
|
|
20056
|
+
lines.splice(lines.indexOf("## Harness loop iterations") + 1, 0, "- _No iterations recorded._");
|
|
20057
|
+
}
|
|
20058
|
+
return `${lines.join("\n")}
|
|
20059
|
+
`;
|
|
20060
|
+
}
|
|
19865
20061
|
function describeScenarioBehavior(result) {
|
|
19866
20062
|
if (result.scenario.description?.trim()) {
|
|
19867
20063
|
return result.scenario.description.trim();
|
|
@@ -20642,6 +20838,16 @@ function createAgentEvalHarness(options) {
|
|
|
20642
20838
|
const chatTimeoutMs = options.chatTimeoutMs ?? 12e4;
|
|
20643
20839
|
const jobTimeoutMs = options.jobTimeoutMs ?? 9e4;
|
|
20644
20840
|
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
20841
|
+
const isTruthyEnv = (value) => {
|
|
20842
|
+
return value?.trim().toLowerCase() === "1" || value?.trim().toLowerCase() === "true" || value?.trim().toLowerCase() === "yes" || value?.trim().toLowerCase() === "on";
|
|
20843
|
+
};
|
|
20844
|
+
const localTurnReportsEnabled = (() => {
|
|
20845
|
+
if (typeof options.local === "boolean") return options.local;
|
|
20846
|
+
return process.env.NODE_ENV === "development" || isTruthyEnv(process.env.GRANULAR_LOCAL) || isTruthyEnv(process.env.GRANULAR_USE_LOCAL_ENDPOINTS) || isTruthyEnv(process.env.GRANULAR_USE_LOCAL) || process.env.GRANULAR_ENDPOINT_MODE?.toLowerCase() === "local";
|
|
20847
|
+
})();
|
|
20848
|
+
const localTurnReportBaseDir = path.resolve(
|
|
20849
|
+
options.localTurnReportBaseDir || process.cwd()
|
|
20850
|
+
);
|
|
20645
20851
|
const resolvedTemplate = resolveHarnessTemplate(
|
|
20646
20852
|
options.harnessTemplateId || process.env.GRANULAR_AGENT_HARNESS_TEMPLATE || "stable");
|
|
20647
20853
|
const promptRenderer = options.promptRenderer || resolvedTemplate.renderPrompt;
|
|
@@ -20690,6 +20896,41 @@ function createAgentEvalHarness(options) {
|
|
|
20690
20896
|
} catch {
|
|
20691
20897
|
}
|
|
20692
20898
|
}
|
|
20899
|
+
async function writeLocalTurnReport(input) {
|
|
20900
|
+
if (!localTurnReportsEnabled) return;
|
|
20901
|
+
const { status, conversation, turnLog, request, requestTimestamp, error } = input;
|
|
20902
|
+
const requestId = safePathSegment(
|
|
20903
|
+
new Date(requestTimestamp).toISOString().replace(/[:.]/g, "-"),
|
|
20904
|
+
"turn"
|
|
20905
|
+
);
|
|
20906
|
+
const reportDir = path.join(
|
|
20907
|
+
localTurnReportBaseDir,
|
|
20908
|
+
safePathSegment(conversation.environment.ontologyId, "ontology"),
|
|
20909
|
+
safePathSegment(conversation.environment.subjectId, "subject"),
|
|
20910
|
+
safePathSegment(conversation.environment.sessionId, "session")
|
|
20911
|
+
);
|
|
20912
|
+
await ensureDir(reportDir);
|
|
20913
|
+
const completed = input.completed;
|
|
20914
|
+
const pending = input.pending;
|
|
20915
|
+
const report = buildTurnMdxReport({
|
|
20916
|
+
status,
|
|
20917
|
+
conversation,
|
|
20918
|
+
request,
|
|
20919
|
+
requestTimestamp,
|
|
20920
|
+
turnLog,
|
|
20921
|
+
responseText: completed?.responseText,
|
|
20922
|
+
terminalKind: completed?.terminalKind,
|
|
20923
|
+
actionSummary: completed?.actionSummary,
|
|
20924
|
+
promptInteractions: completed?.promptInteractions || pending?.promptInteractions,
|
|
20925
|
+
result: completed?.result,
|
|
20926
|
+
prompts: pending?.prompts,
|
|
20927
|
+
verification: completed?.verification,
|
|
20928
|
+
error
|
|
20929
|
+
});
|
|
20930
|
+
const reportPath = path.join(reportDir, `${requestId}.mdx`);
|
|
20931
|
+
await writeFile(reportPath, report);
|
|
20932
|
+
console.log(`[agent][local] saved query report: ${reportPath}`);
|
|
20933
|
+
}
|
|
20693
20934
|
async function runCheckJob(code, session) {
|
|
20694
20935
|
const job = await session.submitJob(code);
|
|
20695
20936
|
return withTimeout2(job.result, jobTimeoutMs, `check job ${job.id}`);
|
|
@@ -20949,99 +21190,96 @@ function createAgentEvalHarness(options) {
|
|
|
20949
21190
|
const baselineClosureId = getCurrentClosureId(
|
|
20950
21191
|
cloneJson(conversation.environment.document)
|
|
20951
21192
|
);
|
|
20952
|
-
|
|
20953
|
-
|
|
20954
|
-
|
|
20955
|
-
|
|
20956
|
-
|
|
20957
|
-
|
|
20958
|
-
boundaryTimestamp
|
|
20959
|
-
|
|
20960
|
-
|
|
20961
|
-
|
|
21193
|
+
const writeTurnReport = async (status) => {
|
|
21194
|
+
await writeLocalTurnReport({
|
|
21195
|
+
status: status.type,
|
|
21196
|
+
conversation,
|
|
21197
|
+
turnLog,
|
|
21198
|
+
request: input.request,
|
|
21199
|
+
requestTimestamp: boundaryTimestamp,
|
|
21200
|
+
completed: status.completed,
|
|
21201
|
+
pending: status.pending,
|
|
21202
|
+
error: status.error
|
|
20962
21203
|
});
|
|
20963
|
-
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
20967
|
-
|
|
20968
|
-
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
...workflowFocus.entryPaths,
|
|
20972
|
-
...referentFocus.entryPaths,
|
|
20973
|
-
...focusedHeapEntryPathsFromUiContext(promptHeap, input.uiContext)
|
|
20974
|
-
]
|
|
20975
|
-
};
|
|
20976
|
-
const tools = conversation.environment.getEffects().map((tool) => ({
|
|
20977
|
-
name: tool.name,
|
|
20978
|
-
description: tool.description,
|
|
20979
|
-
className: tool.className,
|
|
20980
|
-
static: tool.static,
|
|
20981
|
-
ready: tool.ready,
|
|
20982
|
-
inputSchema: tool.inputSchema,
|
|
20983
|
-
outputSchema: tool.outputSchema
|
|
20984
|
-
}));
|
|
20985
|
-
const renderedPrompt = promptRenderer({
|
|
20986
|
-
domainDocumentation: await conversation.environment.getDomainDocumentation(),
|
|
20987
|
-
sessionContext: {
|
|
20988
|
-
sandboxId: conversation.environment.sandboxId,
|
|
20989
|
-
environmentId: conversation.environment.environmentId,
|
|
20990
|
-
domainRevision: conversation.environment.domainRevision,
|
|
20991
|
-
uiContext: input.uiContext || null
|
|
20992
|
-
},
|
|
20993
|
-
heapSummary: projectHeapSummary(asRecord6(liveDoc?.heap), {
|
|
20994
|
-
focus: heapFocus
|
|
20995
|
-
}),
|
|
20996
|
-
fileSummary: projectSessionFileSummary(liveDoc),
|
|
20997
|
-
referentSummary: projectConversationReferentSummary(liveDoc),
|
|
20998
|
-
loopSummary: projectLoopSummary(liveDoc, pendingPrompts, {
|
|
21204
|
+
};
|
|
21205
|
+
try {
|
|
21206
|
+
while (iteration < maxIterations) {
|
|
21207
|
+
const liveDoc = cloneJson(conversation.environment.document);
|
|
21208
|
+
const promptHeap = normalizeHeapSnapshot2(asRecord6(liveDoc?.heap));
|
|
21209
|
+
const pendingPrompts = filterPromptsByBoundary(
|
|
21210
|
+
liveDoc,
|
|
21211
|
+
getOpenPromptsFromDoc(liveDoc),
|
|
20999
21212
|
boundaryTimestamp
|
|
21000
|
-
|
|
21001
|
-
|
|
21213
|
+
);
|
|
21214
|
+
const workflowFocus = projectWorkflowFocus(liveDoc, pendingPrompts, {
|
|
21002
21215
|
boundaryTimestamp
|
|
21003
|
-
})
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
|
|
21013
|
-
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
|
|
21017
|
-
|
|
21018
|
-
|
|
21216
|
+
});
|
|
21217
|
+
const referentFocus = projectConversationReferentFocus(liveDoc);
|
|
21218
|
+
const heapFocus = {
|
|
21219
|
+
variableNames: [
|
|
21220
|
+
...workflowFocus.variableNames,
|
|
21221
|
+
...referentFocus.variableNames
|
|
21222
|
+
],
|
|
21223
|
+
listNames: [...workflowFocus.listNames, ...referentFocus.listNames],
|
|
21224
|
+
entryPaths: [
|
|
21225
|
+
...workflowFocus.entryPaths,
|
|
21226
|
+
...referentFocus.entryPaths,
|
|
21227
|
+
...focusedHeapEntryPathsFromUiContext(promptHeap, input.uiContext)
|
|
21228
|
+
]
|
|
21229
|
+
};
|
|
21230
|
+
const tools = conversation.environment.getEffects().map((tool) => ({
|
|
21231
|
+
name: tool.name,
|
|
21232
|
+
description: tool.description,
|
|
21233
|
+
className: tool.className,
|
|
21234
|
+
static: tool.static,
|
|
21235
|
+
ready: tool.ready,
|
|
21236
|
+
inputSchema: tool.inputSchema,
|
|
21237
|
+
outputSchema: tool.outputSchema
|
|
21238
|
+
}));
|
|
21239
|
+
const renderedPrompt = promptRenderer({
|
|
21240
|
+
domainDocumentation: await conversation.environment.getDomainDocumentation(),
|
|
21241
|
+
sessionContext: {
|
|
21242
|
+
sandboxId: conversation.environment.sandboxId,
|
|
21243
|
+
environmentId: conversation.environment.environmentId,
|
|
21244
|
+
domainRevision: conversation.environment.domainRevision,
|
|
21245
|
+
uiContext: input.uiContext || null
|
|
21246
|
+
},
|
|
21247
|
+
heapSummary: projectHeapSummary(asRecord6(liveDoc?.heap), {
|
|
21248
|
+
focus: heapFocus
|
|
21249
|
+
}),
|
|
21250
|
+
fileSummary: projectSessionFileSummary(liveDoc),
|
|
21251
|
+
referentSummary: projectConversationReferentSummary(liveDoc),
|
|
21252
|
+
loopSummary: projectLoopSummary(liveDoc, pendingPrompts, {
|
|
21253
|
+
boundaryTimestamp
|
|
21254
|
+
}),
|
|
21255
|
+
workflowSummary: projectWorkflowSummary(liveDoc, pendingPrompts, {
|
|
21256
|
+
boundaryTimestamp
|
|
21257
|
+
}),
|
|
21258
|
+
tools,
|
|
21259
|
+
checkpoint: latestCheckpoint
|
|
21260
|
+
});
|
|
21261
|
+
const systemPrompt = renderedPrompt.prompt;
|
|
21262
|
+
await emitProgress(onProgress, {
|
|
21263
|
+
phase: "prompt",
|
|
21264
|
+
status: "passed",
|
|
21265
|
+
scenarioId: conversation.label,
|
|
21266
|
+
stepId: turnId,
|
|
21267
|
+
iteration: iteration + 1,
|
|
21019
21268
|
templateId: renderedPrompt.templateId,
|
|
21020
21269
|
templateVersion: renderedPrompt.templateVersion,
|
|
21021
|
-
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
|
|
21025
|
-
|
|
21026
|
-
|
|
21027
|
-
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
iteration: iteration + 1,
|
|
21035
|
-
templateId: renderedPrompt.templateId,
|
|
21036
|
-
templateVersion: renderedPrompt.templateVersion,
|
|
21037
|
-
title: iteration === 0 ? "Generating agent response" : "Generating continuation",
|
|
21038
|
-
message: request
|
|
21039
|
-
});
|
|
21040
|
-
const emittedGeneratedReasoningLines = /* @__PURE__ */ new Set();
|
|
21041
|
-
let generatedReasoningBuffer = "";
|
|
21042
|
-
const emitGeneratedReasoningLine = async (line) => {
|
|
21043
|
-
if (emittedGeneratedReasoningLines.has(line)) return;
|
|
21044
|
-
emittedGeneratedReasoningLines.add(line);
|
|
21270
|
+
title: "Rendered harness prompt",
|
|
21271
|
+
message: `${systemPrompt.split("\n").length} lines`,
|
|
21272
|
+
data: {
|
|
21273
|
+
templateId: renderedPrompt.templateId,
|
|
21274
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21275
|
+
templateHash: renderedPrompt.templateHash,
|
|
21276
|
+
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
21277
|
+
prompt: systemPrompt
|
|
21278
|
+
}
|
|
21279
|
+
});
|
|
21280
|
+
const request = iteration === 0 ? input.request : continuationRenderer(
|
|
21281
|
+
buildContinuationPreview(latestCheckpoint, noProgressCount)
|
|
21282
|
+
).instruction;
|
|
21045
21283
|
await emitProgress(onProgress, {
|
|
21046
21284
|
phase: "generation",
|
|
21047
21285
|
status: "running",
|
|
@@ -21050,190 +21288,231 @@ function createAgentEvalHarness(options) {
|
|
|
21050
21288
|
iteration: iteration + 1,
|
|
21051
21289
|
templateId: renderedPrompt.templateId,
|
|
21052
21290
|
templateVersion: renderedPrompt.templateVersion,
|
|
21053
|
-
title: "
|
|
21054
|
-
message:
|
|
21055
|
-
data: { source: "generated_code_comment" }
|
|
21291
|
+
title: iteration === 0 ? "Generating agent response" : "Generating continuation",
|
|
21292
|
+
message: request
|
|
21056
21293
|
});
|
|
21057
|
-
|
|
21058
|
-
|
|
21059
|
-
|
|
21060
|
-
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
title: "Generated text reply delta",
|
|
21075
|
-
message: delta,
|
|
21076
|
-
data: { delta }
|
|
21077
|
-
});
|
|
21078
|
-
},
|
|
21079
|
-
onCodeDelta: async (delta) => {
|
|
21080
|
-
const parsed = consumeGranularReasoningOnlyChunk(
|
|
21081
|
-
generatedReasoningBuffer,
|
|
21082
|
-
delta
|
|
21083
|
-
);
|
|
21084
|
-
generatedReasoningBuffer = parsed.buffer;
|
|
21085
|
-
for (const line of parsed.reasoningLines) {
|
|
21086
|
-
await emitGeneratedReasoningLine(line);
|
|
21087
|
-
}
|
|
21088
|
-
},
|
|
21089
|
-
usageContext: {
|
|
21090
|
-
sandboxId: conversation.environment.sandboxId,
|
|
21091
|
-
environmentId: conversation.environment.environmentId,
|
|
21092
|
-
sessionId: conversation.environment.sessionId,
|
|
21093
|
-
subjectId: conversation.environment.subjectId,
|
|
21094
|
-
permissionProfileId: conversation.environment.permissionProfileId
|
|
21095
|
-
}
|
|
21096
|
-
}),
|
|
21097
|
-
chatTimeoutMs,
|
|
21098
|
-
`chat generation for ${conversation.label} iteration ${iteration + 1}`
|
|
21099
|
-
);
|
|
21100
|
-
await emitProgress(onProgress, {
|
|
21101
|
-
phase: "generation",
|
|
21102
|
-
status: "passed",
|
|
21103
|
-
scenarioId: conversation.label,
|
|
21104
|
-
stepId: turnId,
|
|
21105
|
-
iteration: iteration + 1,
|
|
21106
|
-
templateId: renderedPrompt.templateId,
|
|
21107
|
-
templateVersion: renderedPrompt.templateVersion,
|
|
21108
|
-
title: generation.code ? "Generated job code" : "Generated text reply",
|
|
21109
|
-
message: generation.code || generation.reply || "",
|
|
21110
|
-
data: {
|
|
21111
|
-
reply: generation.reply,
|
|
21112
|
-
code: generation.code,
|
|
21113
|
-
attempts: generation.generationAttempts,
|
|
21114
|
-
usage: tokenUsageForGenerationOutput(generation)
|
|
21115
|
-
}
|
|
21116
|
-
});
|
|
21117
|
-
const generatedReasoningLines = generation.code ? consumeGranularReasoningOnlyChunk("", generation.code, {
|
|
21118
|
-
final: true
|
|
21119
|
-
}).reasoningLines : [];
|
|
21120
|
-
for (const line of generatedReasoningLines) {
|
|
21121
|
-
await emitGeneratedReasoningLine(line);
|
|
21122
|
-
}
|
|
21123
|
-
const iterationLog = {
|
|
21124
|
-
iteration: iteration + 1,
|
|
21125
|
-
request,
|
|
21126
|
-
systemPrompt,
|
|
21127
|
-
templateId: renderedPrompt.templateId,
|
|
21128
|
-
templateVersion: renderedPrompt.templateVersion,
|
|
21129
|
-
templateHash: renderedPrompt.templateHash,
|
|
21130
|
-
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
21131
|
-
generationReply: generation.reply,
|
|
21132
|
-
generatedCode: generation.code,
|
|
21133
|
-
rawGeneration: generation.raw,
|
|
21134
|
-
generationAttempts: generation.generationAttempts,
|
|
21135
|
-
tokenUsage: tokenUsageForGenerationOutput(generation)
|
|
21136
|
-
};
|
|
21137
|
-
turnLog.iterations.push(iterationLog);
|
|
21138
|
-
await writeJson(
|
|
21139
|
-
path.join(turnDir, `iteration-${iteration + 1}-generation.json`),
|
|
21140
|
-
generation
|
|
21141
|
-
);
|
|
21142
|
-
if (!generation.code) {
|
|
21143
|
-
const responseText2 = generation.reply?.trim() || "Done.";
|
|
21144
|
-
conversation.history.push({ role: "assistant", content: responseText2 });
|
|
21145
|
-
const completed = {
|
|
21146
|
-
conversation,
|
|
21147
|
-
request: input.request,
|
|
21148
|
-
turnDir,
|
|
21149
|
-
responseText: responseText2,
|
|
21150
|
-
terminalKind: "reply",
|
|
21151
|
-
actionSummary: [],
|
|
21152
|
-
promptInteractions: [],
|
|
21153
|
-
verification: null,
|
|
21154
|
-
result: generation.reply?.trim() || responseText2
|
|
21155
|
-
};
|
|
21156
|
-
if (input.verification) {
|
|
21157
|
-
completed.verification = await runInspection(
|
|
21158
|
-
conversation,
|
|
21159
|
-
input.verification,
|
|
21160
|
-
completed,
|
|
21161
|
-
turnDir
|
|
21162
|
-
);
|
|
21163
|
-
}
|
|
21164
|
-
iterationLog.responseText = responseText2;
|
|
21165
|
-
iterationLog.terminalKind = "reply";
|
|
21166
|
-
iterationLog.actionSummary = [];
|
|
21167
|
-
iterationLog.promptInteractions = [];
|
|
21168
|
-
iterationLog.result = completed.result;
|
|
21169
|
-
turnLog.completed = {
|
|
21170
|
-
responseText: responseText2,
|
|
21171
|
-
terminalKind: "reply",
|
|
21172
|
-
actionSummary: [],
|
|
21173
|
-
promptInteractions: [],
|
|
21174
|
-
result: completed.result
|
|
21294
|
+
const emittedGeneratedReasoningLines = /* @__PURE__ */ new Set();
|
|
21295
|
+
let generatedReasoningBuffer = "";
|
|
21296
|
+
const emitGeneratedReasoningLine = async (line) => {
|
|
21297
|
+
if (emittedGeneratedReasoningLines.has(line)) return;
|
|
21298
|
+
emittedGeneratedReasoningLines.add(line);
|
|
21299
|
+
await emitProgress(onProgress, {
|
|
21300
|
+
phase: "generation",
|
|
21301
|
+
status: "running",
|
|
21302
|
+
scenarioId: conversation.label,
|
|
21303
|
+
stepId: turnId,
|
|
21304
|
+
iteration: iteration + 1,
|
|
21305
|
+
templateId: renderedPrompt.templateId,
|
|
21306
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21307
|
+
title: "Generated reasoning comment",
|
|
21308
|
+
message: line,
|
|
21309
|
+
data: { source: "generated_code_comment" }
|
|
21310
|
+
});
|
|
21175
21311
|
};
|
|
21176
|
-
|
|
21312
|
+
const generationStartedAt = Date.now();
|
|
21313
|
+
const generation = await withTimeout2(
|
|
21314
|
+
generateTurnWithRepair(options.generator, {
|
|
21315
|
+
systemPrompt,
|
|
21316
|
+
history: buildHistory(conversation.history),
|
|
21317
|
+
request,
|
|
21318
|
+
attempt: 1,
|
|
21319
|
+
tools,
|
|
21320
|
+
onReplyDelta: async (delta) => {
|
|
21321
|
+
await emitProgress(onProgress, {
|
|
21322
|
+
phase: "generation",
|
|
21323
|
+
status: "running",
|
|
21324
|
+
scenarioId: conversation.label,
|
|
21325
|
+
stepId: turnId,
|
|
21326
|
+
iteration: iteration + 1,
|
|
21327
|
+
templateId: renderedPrompt.templateId,
|
|
21328
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21329
|
+
title: "Generated text reply delta",
|
|
21330
|
+
message: delta,
|
|
21331
|
+
data: { delta }
|
|
21332
|
+
});
|
|
21333
|
+
},
|
|
21334
|
+
onCodeDelta: async (delta) => {
|
|
21335
|
+
const parsed = consumeGranularReasoningOnlyChunk(
|
|
21336
|
+
generatedReasoningBuffer,
|
|
21337
|
+
delta
|
|
21338
|
+
);
|
|
21339
|
+
generatedReasoningBuffer = parsed.buffer;
|
|
21340
|
+
for (const line of parsed.reasoningLines) {
|
|
21341
|
+
await emitGeneratedReasoningLine(line);
|
|
21342
|
+
}
|
|
21343
|
+
},
|
|
21344
|
+
usageContext: {
|
|
21345
|
+
sandboxId: conversation.environment.sandboxId,
|
|
21346
|
+
environmentId: conversation.environment.environmentId,
|
|
21347
|
+
sessionId: conversation.environment.sessionId,
|
|
21348
|
+
subjectId: conversation.environment.subjectId,
|
|
21349
|
+
permissionProfileId: conversation.environment.permissionProfileId
|
|
21350
|
+
}
|
|
21351
|
+
}),
|
|
21352
|
+
chatTimeoutMs,
|
|
21353
|
+
`chat generation for ${conversation.label} iteration ${iteration + 1}`
|
|
21354
|
+
);
|
|
21355
|
+
const generationDurationMs = Date.now() - generationStartedAt;
|
|
21177
21356
|
await emitProgress(onProgress, {
|
|
21178
|
-
phase: "
|
|
21357
|
+
phase: "generation",
|
|
21179
21358
|
status: "passed",
|
|
21180
21359
|
scenarioId: conversation.label,
|
|
21181
21360
|
stepId: turnId,
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21361
|
+
iteration: iteration + 1,
|
|
21362
|
+
templateId: renderedPrompt.templateId,
|
|
21363
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21364
|
+
title: generation.code ? "Generated job code" : "Generated text reply",
|
|
21365
|
+
message: generation.code || generation.reply || "",
|
|
21366
|
+
data: {
|
|
21367
|
+
reply: generation.reply,
|
|
21368
|
+
code: generation.code,
|
|
21369
|
+
attempts: generation.generationAttempts,
|
|
21370
|
+
usage: tokenUsageForGenerationOutput(generation)
|
|
21371
|
+
}
|
|
21185
21372
|
});
|
|
21186
|
-
|
|
21187
|
-
|
|
21188
|
-
|
|
21189
|
-
|
|
21190
|
-
|
|
21191
|
-
|
|
21192
|
-
|
|
21193
|
-
systemPrompt,
|
|
21194
|
-
history: buildHistory(conversation.history),
|
|
21195
|
-
scenarioLabel: conversation.label,
|
|
21196
|
-
turnId,
|
|
21373
|
+
const generatedReasoningLines = generation.code ? consumeGranularReasoningOnlyChunk("", generation.code, {
|
|
21374
|
+
final: true
|
|
21375
|
+
}).reasoningLines : [];
|
|
21376
|
+
for (const line of generatedReasoningLines) {
|
|
21377
|
+
await emitGeneratedReasoningLine(line);
|
|
21378
|
+
}
|
|
21379
|
+
const iterationLog = {
|
|
21197
21380
|
iteration: iteration + 1,
|
|
21198
|
-
|
|
21381
|
+
request,
|
|
21382
|
+
generationDurationMs,
|
|
21383
|
+
systemPrompt,
|
|
21384
|
+
templateId: renderedPrompt.templateId,
|
|
21385
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21386
|
+
templateHash: renderedPrompt.templateHash,
|
|
21387
|
+
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
21199
21388
|
generationReply: generation.reply,
|
|
21389
|
+
generatedCode: generation.code,
|
|
21200
21390
|
rawGeneration: generation.raw,
|
|
21201
|
-
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21206
|
-
|
|
21207
|
-
|
|
21208
|
-
|
|
21209
|
-
|
|
21210
|
-
|
|
21211
|
-
|
|
21212
|
-
|
|
21213
|
-
|
|
21214
|
-
|
|
21215
|
-
|
|
21216
|
-
|
|
21217
|
-
|
|
21218
|
-
|
|
21219
|
-
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
|
|
21223
|
-
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
|
|
21391
|
+
generationAttempts: generation.generationAttempts,
|
|
21392
|
+
tokenUsage: tokenUsageForGenerationOutput(generation)
|
|
21393
|
+
};
|
|
21394
|
+
turnLog.iterations.push(iterationLog);
|
|
21395
|
+
await writeJson(
|
|
21396
|
+
path.join(turnDir, `iteration-${iteration + 1}-generation.json`),
|
|
21397
|
+
generation
|
|
21398
|
+
);
|
|
21399
|
+
if (!generation.code) {
|
|
21400
|
+
const responseText2 = generation.reply?.trim() || "Done.";
|
|
21401
|
+
conversation.history.push({ role: "assistant", content: responseText2 });
|
|
21402
|
+
const completed = {
|
|
21403
|
+
conversation,
|
|
21404
|
+
request: input.request,
|
|
21405
|
+
turnDir,
|
|
21406
|
+
responseText: responseText2,
|
|
21407
|
+
terminalKind: "reply",
|
|
21408
|
+
actionSummary: [],
|
|
21409
|
+
promptInteractions: [],
|
|
21410
|
+
verification: null,
|
|
21411
|
+
result: generation.reply?.trim() || responseText2
|
|
21412
|
+
};
|
|
21413
|
+
if (input.verification) {
|
|
21414
|
+
completed.verification = await runInspection(
|
|
21415
|
+
conversation,
|
|
21416
|
+
input.verification,
|
|
21417
|
+
completed,
|
|
21418
|
+
turnDir
|
|
21419
|
+
);
|
|
21420
|
+
}
|
|
21421
|
+
iterationLog.responseText = responseText2;
|
|
21422
|
+
iterationLog.terminalKind = "reply";
|
|
21423
|
+
iterationLog.actionSummary = [];
|
|
21424
|
+
iterationLog.promptInteractions = [];
|
|
21425
|
+
iterationLog.result = completed.result;
|
|
21426
|
+
turnLog.completed = {
|
|
21427
|
+
responseText: responseText2,
|
|
21428
|
+
terminalKind: "reply",
|
|
21429
|
+
actionSummary: [],
|
|
21430
|
+
promptInteractions: [],
|
|
21431
|
+
result: completed.result
|
|
21432
|
+
};
|
|
21433
|
+
await writeJson(path.join(turnDir, "result.json"), completed);
|
|
21434
|
+
await writeTurnReport({ type: "completed", completed });
|
|
21435
|
+
await emitProgress(onProgress, {
|
|
21436
|
+
phase: "step",
|
|
21437
|
+
status: "passed",
|
|
21438
|
+
scenarioId: conversation.label,
|
|
21439
|
+
stepId: turnId,
|
|
21440
|
+
title: "Step completed with text reply",
|
|
21441
|
+
message: responseText2,
|
|
21442
|
+
data: completed
|
|
21443
|
+
});
|
|
21444
|
+
return completed;
|
|
21445
|
+
}
|
|
21446
|
+
const session = conversation.environment;
|
|
21447
|
+
const job = await session.submitJob(generation.code, {
|
|
21448
|
+
agent: {
|
|
21449
|
+
userRequest: input.request,
|
|
21450
|
+
generationRequest: request,
|
|
21451
|
+
systemPrompt,
|
|
21452
|
+
history: buildHistory(conversation.history),
|
|
21453
|
+
scenarioLabel: conversation.label,
|
|
21454
|
+
turnId,
|
|
21455
|
+
iteration: iteration + 1,
|
|
21456
|
+
tools,
|
|
21457
|
+
generationReply: generation.reply,
|
|
21458
|
+
rawGeneration: generation.raw,
|
|
21459
|
+
repairIssues: generation.generationAttempts?.flatMap(
|
|
21460
|
+
(attempt) => attempt.repairIssues || []
|
|
21461
|
+
)
|
|
21462
|
+
}
|
|
21463
|
+
});
|
|
21464
|
+
await emitProgress(onProgress, {
|
|
21465
|
+
phase: "job",
|
|
21466
|
+
status: "running",
|
|
21227
21467
|
scenarioId: conversation.label,
|
|
21228
21468
|
stepId: turnId,
|
|
21229
21469
|
iteration: iteration + 1,
|
|
21470
|
+
jobId: job.id,
|
|
21230
21471
|
templateId: renderedPrompt.templateId,
|
|
21231
|
-
templateVersion: renderedPrompt.templateVersion
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21472
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21473
|
+
title: "Submitted Granular job",
|
|
21474
|
+
message: job.id,
|
|
21475
|
+
data: { code: generation.code }
|
|
21476
|
+
});
|
|
21477
|
+
const outcome = await waitForJobOutcome({
|
|
21478
|
+
environment: conversation.environment,
|
|
21479
|
+
job,
|
|
21480
|
+
boundaryTimestamp,
|
|
21481
|
+
timeoutMs: jobTimeoutMs,
|
|
21482
|
+
pollIntervalMs,
|
|
21483
|
+
onProgress: (event) => void onProgress?.(event),
|
|
21484
|
+
progressContext: {
|
|
21485
|
+
scenarioId: conversation.label,
|
|
21486
|
+
stepId: turnId,
|
|
21487
|
+
iteration: iteration + 1,
|
|
21488
|
+
templateId: renderedPrompt.templateId,
|
|
21489
|
+
templateVersion: renderedPrompt.templateVersion
|
|
21490
|
+
}
|
|
21491
|
+
});
|
|
21492
|
+
if (outcome.kind === "prompt") {
|
|
21493
|
+
if (!autoAnswerPrompts) {
|
|
21494
|
+
const pending2 = {
|
|
21495
|
+
conversation,
|
|
21496
|
+
request: input.request,
|
|
21497
|
+
turnDir,
|
|
21498
|
+
boundaryTimestamp,
|
|
21499
|
+
finalCode: generation.code,
|
|
21500
|
+
finalReply: generation.reply?.trim() || "",
|
|
21501
|
+
stdout: outcome.stdout,
|
|
21502
|
+
stderr: outcome.stderr,
|
|
21503
|
+
prompts: outcome.prompts,
|
|
21504
|
+
promptInteractions: [],
|
|
21505
|
+
job
|
|
21506
|
+
};
|
|
21507
|
+
await writeTurnReport({ type: "pending", pending: pending2 });
|
|
21508
|
+
return pending2;
|
|
21509
|
+
}
|
|
21510
|
+
if (!input.human) {
|
|
21511
|
+
throw new Error(
|
|
21512
|
+
"This turn reached a human prompt but no responder was provided"
|
|
21513
|
+
);
|
|
21514
|
+
}
|
|
21515
|
+
let pending = {
|
|
21237
21516
|
conversation,
|
|
21238
21517
|
request: input.request,
|
|
21239
21518
|
turnDir,
|
|
@@ -21246,187 +21525,180 @@ function createAgentEvalHarness(options) {
|
|
|
21246
21525
|
promptInteractions: [],
|
|
21247
21526
|
job
|
|
21248
21527
|
};
|
|
21528
|
+
while ("prompts" in pending) {
|
|
21529
|
+
const resumed = await resumePendingTurn(pending, input.human);
|
|
21530
|
+
if ("prompts" in resumed) {
|
|
21531
|
+
pending = resumed;
|
|
21532
|
+
continue;
|
|
21533
|
+
}
|
|
21534
|
+
if (input.verification) {
|
|
21535
|
+
resumed.verification = await runInspection(
|
|
21536
|
+
conversation,
|
|
21537
|
+
input.verification,
|
|
21538
|
+
resumed,
|
|
21539
|
+
turnDir
|
|
21540
|
+
);
|
|
21541
|
+
}
|
|
21542
|
+
turnLog.completed = {
|
|
21543
|
+
responseText: resumed.responseText,
|
|
21544
|
+
terminalKind: resumed.terminalKind,
|
|
21545
|
+
actionSummary: resumed.actionSummary,
|
|
21546
|
+
promptInteractions: resumed.promptInteractions,
|
|
21547
|
+
result: resumed.result
|
|
21548
|
+
};
|
|
21549
|
+
await writeTurnReport({ type: "completed", completed: resumed });
|
|
21550
|
+
return resumed;
|
|
21551
|
+
}
|
|
21249
21552
|
}
|
|
21250
|
-
if (
|
|
21553
|
+
if (outcome.kind !== "completed") {
|
|
21251
21554
|
throw new Error(
|
|
21252
|
-
"
|
|
21555
|
+
"Unexpected non-completed outcome after prompt handling"
|
|
21253
21556
|
);
|
|
21254
21557
|
}
|
|
21255
|
-
|
|
21256
|
-
|
|
21257
|
-
|
|
21258
|
-
|
|
21259
|
-
|
|
21260
|
-
|
|
21261
|
-
|
|
21558
|
+
await sleep2(350);
|
|
21559
|
+
const settledLiveDoc = cloneJson(
|
|
21560
|
+
conversation.environment.document
|
|
21561
|
+
);
|
|
21562
|
+
const sessionHeap = normalizeHeapSnapshot2(asRecord6(settledLiveDoc?.heap));
|
|
21563
|
+
const presentation = resolveJobPresentation({
|
|
21564
|
+
jobId: job.id,
|
|
21565
|
+
result: outcome.result,
|
|
21262
21566
|
stdout: outcome.stdout,
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21567
|
+
agentMessages: getJobAgentMessages(settledLiveDoc, job.id),
|
|
21568
|
+
sessionHeap
|
|
21569
|
+
});
|
|
21570
|
+
const responseText = presentation.responseText || generation.reply?.trim() || "Done.";
|
|
21571
|
+
const verifierSnapshot = createHarnessVerifierSnapshot({
|
|
21572
|
+
finalCode: generation.code,
|
|
21573
|
+
resultPreview: JSON.stringify(outcome.result, null, 2),
|
|
21574
|
+
liveDoc: settledLiveDoc,
|
|
21575
|
+
projectionOptions: { boundaryTimestamp }
|
|
21576
|
+
});
|
|
21577
|
+
const continuation = evaluateContinuation({
|
|
21578
|
+
iteration,
|
|
21579
|
+
budgets: controllerBudgets,
|
|
21580
|
+
baselineClosureId,
|
|
21581
|
+
currentClosureId: getCurrentClosureId(settledLiveDoc),
|
|
21582
|
+
liveDoc: settledLiveDoc,
|
|
21583
|
+
pendingPrompts: filterPromptsByBoundary(
|
|
21584
|
+
settledLiveDoc,
|
|
21585
|
+
getOpenPromptsFromDoc(settledLiveDoc),
|
|
21586
|
+
boundaryTimestamp
|
|
21587
|
+
),
|
|
21588
|
+
projectionOptions: { boundaryTimestamp },
|
|
21589
|
+
latestResponseText: responseText,
|
|
21590
|
+
previousSnapshot,
|
|
21591
|
+
currentSnapshot: verifierSnapshot,
|
|
21592
|
+
previousNoProgressCount: noProgressCount
|
|
21593
|
+
});
|
|
21594
|
+
latestCheckpoint = {
|
|
21595
|
+
iteration: iteration + 1,
|
|
21596
|
+
latestJobStatus: "succeeded",
|
|
21597
|
+
latestJobResult: JSON.stringify(outcome.result, null, 2),
|
|
21598
|
+
latestActionSummary: getActionSummary(settledLiveDoc, job.id),
|
|
21599
|
+
controllerOutcome: continuation.outcome,
|
|
21600
|
+
controllerReason: continuation.reason,
|
|
21601
|
+
noProgressCount: continuation.nextNoProgressCount
|
|
21267
21602
|
};
|
|
21268
|
-
|
|
21269
|
-
|
|
21270
|
-
|
|
21271
|
-
|
|
21272
|
-
|
|
21603
|
+
await emitProgress(onProgress, {
|
|
21604
|
+
phase: "continuation",
|
|
21605
|
+
status: continuation.shouldContinue ? "running" : "passed",
|
|
21606
|
+
scenarioId: conversation.label,
|
|
21607
|
+
stepId: turnId,
|
|
21608
|
+
iteration: iteration + 1,
|
|
21609
|
+
jobId: job.id,
|
|
21610
|
+
templateId: renderedPrompt.templateId,
|
|
21611
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
21612
|
+
title: continuation.shouldContinue ? "Harness requested another loop" : "Harness accepted completion",
|
|
21613
|
+
message: `${continuation.reason}; ${continuation.outcome}`,
|
|
21614
|
+
data: {
|
|
21615
|
+
continuation,
|
|
21616
|
+
checkpoint: latestCheckpoint,
|
|
21617
|
+
verifierSnapshot
|
|
21618
|
+
}
|
|
21619
|
+
});
|
|
21620
|
+
previousSnapshot = verifierSnapshot;
|
|
21621
|
+
noProgressCount = continuation.nextNoProgressCount;
|
|
21622
|
+
conversation.history.push({
|
|
21623
|
+
role: "assistant",
|
|
21624
|
+
content: responseText,
|
|
21625
|
+
code: generation.code,
|
|
21626
|
+
jobStatus: "succeeded",
|
|
21627
|
+
jobResultPreview: JSON.stringify(outcome.result, null, 2)
|
|
21628
|
+
});
|
|
21629
|
+
await writeJson(
|
|
21630
|
+
path.join(turnDir, `iteration-${iteration + 1}-result.json`),
|
|
21631
|
+
{
|
|
21632
|
+
responseText,
|
|
21633
|
+
continuation,
|
|
21634
|
+
actionSummary: latestCheckpoint.latestActionSummary,
|
|
21635
|
+
result: outcome.result
|
|
21273
21636
|
}
|
|
21637
|
+
);
|
|
21638
|
+
iterationLog.responseText = responseText;
|
|
21639
|
+
iterationLog.terminalKind = getCurrentClosureId(settledLiveDoc) ? "closure" : "reply";
|
|
21640
|
+
iterationLog.actionSummary = latestCheckpoint.latestActionSummary || [];
|
|
21641
|
+
iterationLog.promptInteractions = [];
|
|
21642
|
+
iterationLog.continuation = continuation;
|
|
21643
|
+
iterationLog.result = outcome.result;
|
|
21644
|
+
if (!continuation.shouldContinue) {
|
|
21645
|
+
const completed = {
|
|
21646
|
+
conversation,
|
|
21647
|
+
request: input.request,
|
|
21648
|
+
turnDir,
|
|
21649
|
+
responseText,
|
|
21650
|
+
terminalKind: getCurrentClosureId(settledLiveDoc) ? "closure" : "reply",
|
|
21651
|
+
finalCode: generation.code,
|
|
21652
|
+
actionSummary: latestCheckpoint.latestActionSummary || [],
|
|
21653
|
+
promptInteractions: [],
|
|
21654
|
+
verification: null,
|
|
21655
|
+
result: outcome.result
|
|
21656
|
+
};
|
|
21274
21657
|
if (input.verification) {
|
|
21275
|
-
|
|
21658
|
+
completed.verification = await runInspection(
|
|
21276
21659
|
conversation,
|
|
21277
21660
|
input.verification,
|
|
21278
|
-
|
|
21661
|
+
completed,
|
|
21279
21662
|
turnDir
|
|
21280
21663
|
);
|
|
21281
21664
|
}
|
|
21282
21665
|
turnLog.completed = {
|
|
21283
|
-
responseText
|
|
21284
|
-
terminalKind:
|
|
21285
|
-
actionSummary:
|
|
21286
|
-
promptInteractions:
|
|
21287
|
-
result:
|
|
21666
|
+
responseText,
|
|
21667
|
+
terminalKind: completed.terminalKind,
|
|
21668
|
+
actionSummary: completed.actionSummary,
|
|
21669
|
+
promptInteractions: [],
|
|
21670
|
+
result: outcome.result
|
|
21288
21671
|
};
|
|
21289
|
-
|
|
21672
|
+
await writeJson(path.join(turnDir, "result.json"), completed);
|
|
21673
|
+
await writeTurnReport({ type: "completed", completed });
|
|
21674
|
+
await emitProgress(onProgress, {
|
|
21675
|
+
phase: "step",
|
|
21676
|
+
status: "passed",
|
|
21677
|
+
scenarioId: conversation.label,
|
|
21678
|
+
stepId: turnId,
|
|
21679
|
+
iteration: iteration + 1,
|
|
21680
|
+
jobId: job.id,
|
|
21681
|
+
title: "Step completed",
|
|
21682
|
+
message: responseText,
|
|
21683
|
+
data: completed
|
|
21684
|
+
});
|
|
21685
|
+
return completed;
|
|
21290
21686
|
}
|
|
21687
|
+
iteration += 1;
|
|
21291
21688
|
}
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
"Unexpected non-completed outcome after prompt handling"
|
|
21295
|
-
);
|
|
21296
|
-
}
|
|
21297
|
-
await sleep2(350);
|
|
21298
|
-
const settledLiveDoc = cloneJson(
|
|
21299
|
-
conversation.environment.document
|
|
21300
|
-
);
|
|
21301
|
-
const sessionHeap = normalizeHeapSnapshot2(asRecord6(settledLiveDoc?.heap));
|
|
21302
|
-
const presentation = resolveJobPresentation({
|
|
21303
|
-
jobId: job.id,
|
|
21304
|
-
result: outcome.result,
|
|
21305
|
-
stdout: outcome.stdout,
|
|
21306
|
-
agentMessages: getJobAgentMessages(settledLiveDoc, job.id),
|
|
21307
|
-
sessionHeap
|
|
21308
|
-
});
|
|
21309
|
-
const responseText = presentation.responseText || generation.reply?.trim() || "Done.";
|
|
21310
|
-
const verifierSnapshot = createHarnessVerifierSnapshot({
|
|
21311
|
-
finalCode: generation.code,
|
|
21312
|
-
resultPreview: JSON.stringify(outcome.result, null, 2),
|
|
21313
|
-
liveDoc: settledLiveDoc,
|
|
21314
|
-
projectionOptions: { boundaryTimestamp }
|
|
21315
|
-
});
|
|
21316
|
-
const continuation = evaluateContinuation({
|
|
21317
|
-
iteration,
|
|
21318
|
-
budgets: controllerBudgets,
|
|
21319
|
-
baselineClosureId,
|
|
21320
|
-
currentClosureId: getCurrentClosureId(settledLiveDoc),
|
|
21321
|
-
liveDoc: settledLiveDoc,
|
|
21322
|
-
pendingPrompts: filterPromptsByBoundary(
|
|
21323
|
-
settledLiveDoc,
|
|
21324
|
-
getOpenPromptsFromDoc(settledLiveDoc),
|
|
21325
|
-
boundaryTimestamp
|
|
21326
|
-
),
|
|
21327
|
-
projectionOptions: { boundaryTimestamp },
|
|
21328
|
-
latestResponseText: responseText,
|
|
21329
|
-
previousSnapshot,
|
|
21330
|
-
currentSnapshot: verifierSnapshot,
|
|
21331
|
-
previousNoProgressCount: noProgressCount
|
|
21332
|
-
});
|
|
21333
|
-
latestCheckpoint = {
|
|
21334
|
-
iteration: iteration + 1,
|
|
21335
|
-
latestJobStatus: "succeeded",
|
|
21336
|
-
latestJobResult: JSON.stringify(outcome.result, null, 2),
|
|
21337
|
-
latestActionSummary: getActionSummary(settledLiveDoc, job.id),
|
|
21338
|
-
controllerOutcome: continuation.outcome,
|
|
21339
|
-
controllerReason: continuation.reason,
|
|
21340
|
-
noProgressCount: continuation.nextNoProgressCount
|
|
21341
|
-
};
|
|
21342
|
-
await emitProgress(onProgress, {
|
|
21343
|
-
phase: "continuation",
|
|
21344
|
-
status: continuation.shouldContinue ? "running" : "passed",
|
|
21345
|
-
scenarioId: conversation.label,
|
|
21346
|
-
stepId: turnId,
|
|
21347
|
-
iteration: iteration + 1,
|
|
21348
|
-
jobId: job.id,
|
|
21349
|
-
templateId: renderedPrompt.templateId,
|
|
21350
|
-
templateVersion: renderedPrompt.templateVersion,
|
|
21351
|
-
title: continuation.shouldContinue ? "Harness requested another loop" : "Harness accepted completion",
|
|
21352
|
-
message: `${continuation.reason}; ${continuation.outcome}`,
|
|
21353
|
-
data: {
|
|
21354
|
-
continuation,
|
|
21355
|
-
checkpoint: latestCheckpoint,
|
|
21356
|
-
verifierSnapshot
|
|
21357
|
-
}
|
|
21358
|
-
});
|
|
21359
|
-
previousSnapshot = verifierSnapshot;
|
|
21360
|
-
noProgressCount = continuation.nextNoProgressCount;
|
|
21361
|
-
conversation.history.push({
|
|
21362
|
-
role: "assistant",
|
|
21363
|
-
content: responseText,
|
|
21364
|
-
code: generation.code,
|
|
21365
|
-
jobStatus: "succeeded",
|
|
21366
|
-
jobResultPreview: JSON.stringify(outcome.result, null, 2)
|
|
21367
|
-
});
|
|
21368
|
-
await writeJson(
|
|
21369
|
-
path.join(turnDir, `iteration-${iteration + 1}-result.json`),
|
|
21370
|
-
{
|
|
21371
|
-
responseText,
|
|
21372
|
-
continuation,
|
|
21373
|
-
actionSummary: latestCheckpoint.latestActionSummary,
|
|
21374
|
-
result: outcome.result
|
|
21375
|
-
}
|
|
21689
|
+
throw new Error(
|
|
21690
|
+
`Turn exceeded iteration budget (${maxIterations}) for ${conversation.label}`
|
|
21376
21691
|
);
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
|
|
21381
|
-
|
|
21382
|
-
iterationLog.result = outcome.result;
|
|
21383
|
-
if (!continuation.shouldContinue) {
|
|
21384
|
-
const completed = {
|
|
21385
|
-
conversation,
|
|
21386
|
-
request: input.request,
|
|
21387
|
-
turnDir,
|
|
21388
|
-
responseText,
|
|
21389
|
-
terminalKind: getCurrentClosureId(settledLiveDoc) ? "closure" : "reply",
|
|
21390
|
-
finalCode: generation.code,
|
|
21391
|
-
actionSummary: latestCheckpoint.latestActionSummary || [],
|
|
21392
|
-
promptInteractions: [],
|
|
21393
|
-
verification: null,
|
|
21394
|
-
result: outcome.result
|
|
21395
|
-
};
|
|
21396
|
-
if (input.verification) {
|
|
21397
|
-
completed.verification = await runInspection(
|
|
21398
|
-
conversation,
|
|
21399
|
-
input.verification,
|
|
21400
|
-
completed,
|
|
21401
|
-
turnDir
|
|
21402
|
-
);
|
|
21403
|
-
}
|
|
21404
|
-
turnLog.completed = {
|
|
21405
|
-
responseText,
|
|
21406
|
-
terminalKind: completed.terminalKind,
|
|
21407
|
-
actionSummary: completed.actionSummary,
|
|
21408
|
-
promptInteractions: [],
|
|
21409
|
-
result: outcome.result
|
|
21410
|
-
};
|
|
21411
|
-
await writeJson(path.join(turnDir, "result.json"), completed);
|
|
21412
|
-
await emitProgress(onProgress, {
|
|
21413
|
-
phase: "step",
|
|
21414
|
-
status: "passed",
|
|
21415
|
-
scenarioId: conversation.label,
|
|
21416
|
-
stepId: turnId,
|
|
21417
|
-
iteration: iteration + 1,
|
|
21418
|
-
jobId: job.id,
|
|
21419
|
-
title: "Step completed",
|
|
21420
|
-
message: responseText,
|
|
21421
|
-
data: completed
|
|
21422
|
-
});
|
|
21423
|
-
return completed;
|
|
21692
|
+
} catch (error) {
|
|
21693
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21694
|
+
const latestIteration = latestIterationLog(turnLog);
|
|
21695
|
+
if (latestIteration) {
|
|
21696
|
+
latestIteration.error = message;
|
|
21424
21697
|
}
|
|
21425
|
-
|
|
21698
|
+
turnLog.error = message;
|
|
21699
|
+
await writeTurnReport({ type: "failed", error: message });
|
|
21700
|
+
throw error;
|
|
21426
21701
|
}
|
|
21427
|
-
throw new Error(
|
|
21428
|
-
`Turn exceeded iteration budget (${maxIterations}) for ${conversation.label}`
|
|
21429
|
-
);
|
|
21430
21702
|
}
|
|
21431
21703
|
return {
|
|
21432
21704
|
artifactDir,
|
|
@@ -21461,6 +21733,7 @@ function createAgentTester(options) {
|
|
|
21461
21733
|
const harness = createAgentEvalHarness({
|
|
21462
21734
|
granular,
|
|
21463
21735
|
environmentId: resolvedEnvironmentId || void 0,
|
|
21736
|
+
local: options.local,
|
|
21464
21737
|
openEnvironment: async ({ clientId }) => {
|
|
21465
21738
|
if (resolvedEnvironmentId) {
|
|
21466
21739
|
return granular.createSession({
|