@granular-software/sdk 0.4.41 → 0.4.42
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 +137 -3
- package/dist/agent-evals.d.ts +137 -3
- package/dist/agent-evals.js +1075 -26
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +1075 -28
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.d.mts +60 -1
- package/dist/agent-harness.d.ts +60 -1
- package/dist/agent-harness.js +475 -0
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +467 -1
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +282 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +475 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +467 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/agent-evals.js
CHANGED
|
@@ -16086,7 +16086,275 @@ var Granular = class _Granular {
|
|
|
16086
16086
|
}
|
|
16087
16087
|
};
|
|
16088
16088
|
|
|
16089
|
+
// src/agent-harness-templates/action-presentation/0.1.0/manifest.json
|
|
16090
|
+
var manifest_default = {
|
|
16091
|
+
id: "action-presentation",
|
|
16092
|
+
version: "0.1.0",
|
|
16093
|
+
status: "candidate",
|
|
16094
|
+
owner: "granular",
|
|
16095
|
+
createdAt: "2026-05-25T00:00:00.000Z",
|
|
16096
|
+
changelog: "Candidate harness template focused on action-request detection and mutation result presentation. It exists to harden cases where the model answers with a terse completion such as Done instead of using tools and reporting the target/action/result.",
|
|
16097
|
+
promptBuilder: "buildGranularAgentSystemPrompt:action-presentation",
|
|
16098
|
+
continuationBuilder: "buildContinuationInstruction:action-presentation",
|
|
16099
|
+
modelOutputInstruction: "agent-evals:modelOutputInstruction",
|
|
16100
|
+
codeReviewPolicy: "reviewGeneratedJobCode",
|
|
16101
|
+
defaultModel: "gpt-5.4",
|
|
16102
|
+
modelMatrix: ["gpt-5.4"],
|
|
16103
|
+
temperature: 0,
|
|
16104
|
+
compatibility: {
|
|
16105
|
+
minSdkVersion: "0.4.40",
|
|
16106
|
+
capabilities: [
|
|
16107
|
+
"executeCode",
|
|
16108
|
+
"readEntities",
|
|
16109
|
+
"workflowHelpers",
|
|
16110
|
+
"savedData",
|
|
16111
|
+
"showRecords"
|
|
16112
|
+
]
|
|
16113
|
+
},
|
|
16114
|
+
evalGates: {
|
|
16115
|
+
requiredSuites: [
|
|
16116
|
+
"agent-harness-hardening",
|
|
16117
|
+
"agent-harness-runtime-e2e",
|
|
16118
|
+
"agent-production-readiness-e2e"
|
|
16119
|
+
],
|
|
16120
|
+
criticalBuckets: [
|
|
16121
|
+
"relationship-traversal",
|
|
16122
|
+
"cross-turn-reference",
|
|
16123
|
+
"ambiguous-target-choice",
|
|
16124
|
+
"confirmation-gated-mutation",
|
|
16125
|
+
"denied-action-refusal",
|
|
16126
|
+
"mutation-presentation"
|
|
16127
|
+
],
|
|
16128
|
+
maxRegressionPct: 0,
|
|
16129
|
+
minPassK: {
|
|
16130
|
+
"critical-mutation": 0.9,
|
|
16131
|
+
"permission-boundary": 1
|
|
16132
|
+
}
|
|
16133
|
+
}
|
|
16134
|
+
};
|
|
16135
|
+
|
|
16136
|
+
// src/agent-harness-templates/experimental-compact/0.1.0/manifest.json
|
|
16137
|
+
var manifest_default2 = {
|
|
16138
|
+
id: "experimental-compact",
|
|
16139
|
+
version: "0.1.0",
|
|
16140
|
+
status: "candidate",
|
|
16141
|
+
owner: "granular",
|
|
16142
|
+
createdAt: "2026-05-24T00:00:00.000Z",
|
|
16143
|
+
changelog: "Candidate harness template used for champion/challenger testing. It adds a compact decision discipline section on top of the stable renderer.",
|
|
16144
|
+
promptBuilder: "buildGranularAgentSystemPrompt:experimental-compact",
|
|
16145
|
+
continuationBuilder: "buildContinuationInstruction:experimental-compact",
|
|
16146
|
+
modelOutputInstruction: "agent-evals:modelOutputInstruction",
|
|
16147
|
+
codeReviewPolicy: "reviewGeneratedJobCode",
|
|
16148
|
+
defaultModel: "gpt-5.4",
|
|
16149
|
+
modelMatrix: ["gpt-5.4"],
|
|
16150
|
+
temperature: 0,
|
|
16151
|
+
compatibility: {
|
|
16152
|
+
minSdkVersion: "0.4.40",
|
|
16153
|
+
capabilities: [
|
|
16154
|
+
"executeCode",
|
|
16155
|
+
"readEntities",
|
|
16156
|
+
"workflowHelpers",
|
|
16157
|
+
"savedData",
|
|
16158
|
+
"showRecords"
|
|
16159
|
+
]
|
|
16160
|
+
},
|
|
16161
|
+
evalGates: {
|
|
16162
|
+
requiredSuites: [
|
|
16163
|
+
"agent-harness-hardening",
|
|
16164
|
+
"agent-harness-runtime-e2e",
|
|
16165
|
+
"agent-production-readiness-e2e"
|
|
16166
|
+
],
|
|
16167
|
+
criticalBuckets: [
|
|
16168
|
+
"relationship-traversal",
|
|
16169
|
+
"cross-turn-reference",
|
|
16170
|
+
"ambiguous-target-choice",
|
|
16171
|
+
"confirmation-gated-mutation",
|
|
16172
|
+
"denied-action-refusal",
|
|
16173
|
+
"mutation-presentation"
|
|
16174
|
+
],
|
|
16175
|
+
maxRegressionPct: 0,
|
|
16176
|
+
minPassK: {
|
|
16177
|
+
"critical-mutation": 0.9,
|
|
16178
|
+
"permission-boundary": 1
|
|
16179
|
+
}
|
|
16180
|
+
}
|
|
16181
|
+
};
|
|
16182
|
+
|
|
16183
|
+
// src/agent-harness-templates/stable/1.0.0/manifest.json
|
|
16184
|
+
var manifest_default3 = {
|
|
16185
|
+
id: "stable",
|
|
16186
|
+
version: "1.0.0",
|
|
16187
|
+
status: "stable",
|
|
16188
|
+
owner: "granular",
|
|
16189
|
+
createdAt: "2026-05-24T00:00:00.000Z",
|
|
16190
|
+
changelog: "Baseline template wrapping the existing Granular agent harness prompt, continuation instruction, output contract, and generated-job review policy.",
|
|
16191
|
+
promptBuilder: "buildGranularAgentSystemPrompt",
|
|
16192
|
+
continuationBuilder: "buildContinuationInstruction",
|
|
16193
|
+
modelOutputInstruction: "agent-evals:modelOutputInstruction",
|
|
16194
|
+
codeReviewPolicy: "reviewGeneratedJobCode",
|
|
16195
|
+
defaultModel: "gpt-5.4",
|
|
16196
|
+
modelMatrix: ["gpt-5.4"],
|
|
16197
|
+
temperature: 0,
|
|
16198
|
+
compatibility: {
|
|
16199
|
+
minSdkVersion: "0.4.40",
|
|
16200
|
+
capabilities: [
|
|
16201
|
+
"executeCode",
|
|
16202
|
+
"readEntities",
|
|
16203
|
+
"workflowHelpers",
|
|
16204
|
+
"savedData",
|
|
16205
|
+
"showRecords"
|
|
16206
|
+
]
|
|
16207
|
+
},
|
|
16208
|
+
evalGates: {
|
|
16209
|
+
requiredSuites: [
|
|
16210
|
+
"agent-harness-hardening",
|
|
16211
|
+
"agent-harness-runtime-e2e",
|
|
16212
|
+
"agent-production-readiness-e2e"
|
|
16213
|
+
],
|
|
16214
|
+
criticalBuckets: [
|
|
16215
|
+
"relationship-traversal",
|
|
16216
|
+
"cross-turn-reference",
|
|
16217
|
+
"ambiguous-target-choice",
|
|
16218
|
+
"confirmation-gated-mutation",
|
|
16219
|
+
"denied-action-refusal",
|
|
16220
|
+
"mutation-presentation"
|
|
16221
|
+
],
|
|
16222
|
+
maxRegressionPct: 0,
|
|
16223
|
+
minPassK: {
|
|
16224
|
+
"critical-mutation": 0.9,
|
|
16225
|
+
"permission-boundary": 1
|
|
16226
|
+
}
|
|
16227
|
+
}
|
|
16228
|
+
};
|
|
16229
|
+
|
|
16089
16230
|
// src/agent-harness.ts
|
|
16231
|
+
var HARNESS_TEMPLATE_STATUSES = [
|
|
16232
|
+
"draft",
|
|
16233
|
+
"candidate",
|
|
16234
|
+
"release-candidate",
|
|
16235
|
+
"stable",
|
|
16236
|
+
"deprecated"
|
|
16237
|
+
];
|
|
16238
|
+
function requireRecord(value, context) {
|
|
16239
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
16240
|
+
throw new Error(`${context} must be an object.`);
|
|
16241
|
+
}
|
|
16242
|
+
return value;
|
|
16243
|
+
}
|
|
16244
|
+
function requiredString(record, key, context) {
|
|
16245
|
+
const value = record[key];
|
|
16246
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
16247
|
+
throw new Error(`${context}.${key} must be a non-empty string.`);
|
|
16248
|
+
}
|
|
16249
|
+
return value;
|
|
16250
|
+
}
|
|
16251
|
+
function requiredNumber(record, key, context) {
|
|
16252
|
+
const value = record[key];
|
|
16253
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
16254
|
+
throw new Error(`${context}.${key} must be a finite number.`);
|
|
16255
|
+
}
|
|
16256
|
+
return value;
|
|
16257
|
+
}
|
|
16258
|
+
function requiredStringArray(record, key, context) {
|
|
16259
|
+
const value = record[key];
|
|
16260
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
|
|
16261
|
+
throw new Error(`${context}.${key} must be an array of non-empty strings.`);
|
|
16262
|
+
}
|
|
16263
|
+
return [...value];
|
|
16264
|
+
}
|
|
16265
|
+
function requiredNumberRecord(record, key, context) {
|
|
16266
|
+
const value = requireRecord(record[key], `${context}.${key}`);
|
|
16267
|
+
const output = {};
|
|
16268
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
16269
|
+
if (typeof entryValue !== "number" || !Number.isFinite(entryValue) || entryValue < 0 || entryValue > 1) {
|
|
16270
|
+
throw new Error(
|
|
16271
|
+
`${context}.${key}.${entryKey} must be a number between 0 and 1.`
|
|
16272
|
+
);
|
|
16273
|
+
}
|
|
16274
|
+
output[entryKey] = entryValue;
|
|
16275
|
+
}
|
|
16276
|
+
return output;
|
|
16277
|
+
}
|
|
16278
|
+
function validateHarnessTemplateManifest(value, context = "HarnessTemplateManifest") {
|
|
16279
|
+
const record = requireRecord(value, context);
|
|
16280
|
+
const status = requiredString(record, "status", context);
|
|
16281
|
+
if (!HARNESS_TEMPLATE_STATUSES.includes(status)) {
|
|
16282
|
+
throw new Error(
|
|
16283
|
+
`${context}.status must be one of ${HARNESS_TEMPLATE_STATUSES.join(", ")}.`
|
|
16284
|
+
);
|
|
16285
|
+
}
|
|
16286
|
+
const createdAt = requiredString(record, "createdAt", context);
|
|
16287
|
+
if (Number.isNaN(Date.parse(createdAt))) {
|
|
16288
|
+
throw new Error(`${context}.createdAt must be an ISO timestamp.`);
|
|
16289
|
+
}
|
|
16290
|
+
const compatibility = requireRecord(
|
|
16291
|
+
record.compatibility,
|
|
16292
|
+
`${context}.compatibility`
|
|
16293
|
+
);
|
|
16294
|
+
const evalGates = requireRecord(record.evalGates, `${context}.evalGates`);
|
|
16295
|
+
const maxRegressionPct = requiredNumber(
|
|
16296
|
+
evalGates,
|
|
16297
|
+
"maxRegressionPct",
|
|
16298
|
+
`${context}.evalGates`
|
|
16299
|
+
);
|
|
16300
|
+
if (maxRegressionPct < 0 || maxRegressionPct > 1) {
|
|
16301
|
+
throw new Error(
|
|
16302
|
+
`${context}.evalGates.maxRegressionPct must be between 0 and 1.`
|
|
16303
|
+
);
|
|
16304
|
+
}
|
|
16305
|
+
return {
|
|
16306
|
+
id: requiredString(record, "id", context),
|
|
16307
|
+
version: requiredString(record, "version", context),
|
|
16308
|
+
status,
|
|
16309
|
+
owner: requiredString(record, "owner", context),
|
|
16310
|
+
createdAt,
|
|
16311
|
+
changelog: requiredString(record, "changelog", context),
|
|
16312
|
+
promptBuilder: requiredString(record, "promptBuilder", context),
|
|
16313
|
+
continuationBuilder: requiredString(record, "continuationBuilder", context),
|
|
16314
|
+
modelOutputInstruction: requiredString(
|
|
16315
|
+
record,
|
|
16316
|
+
"modelOutputInstruction",
|
|
16317
|
+
context
|
|
16318
|
+
),
|
|
16319
|
+
codeReviewPolicy: requiredString(record, "codeReviewPolicy", context),
|
|
16320
|
+
defaultModel: requiredString(record, "defaultModel", context),
|
|
16321
|
+
modelMatrix: requiredStringArray(record, "modelMatrix", context),
|
|
16322
|
+
temperature: requiredNumber(record, "temperature", context),
|
|
16323
|
+
compatibility: {
|
|
16324
|
+
minSdkVersion: requiredString(
|
|
16325
|
+
compatibility,
|
|
16326
|
+
"minSdkVersion",
|
|
16327
|
+
`${context}.compatibility`
|
|
16328
|
+
),
|
|
16329
|
+
capabilities: requiredStringArray(
|
|
16330
|
+
compatibility,
|
|
16331
|
+
"capabilities",
|
|
16332
|
+
`${context}.compatibility`
|
|
16333
|
+
)
|
|
16334
|
+
},
|
|
16335
|
+
evalGates: {
|
|
16336
|
+
requiredSuites: requiredStringArray(
|
|
16337
|
+
evalGates,
|
|
16338
|
+
"requiredSuites",
|
|
16339
|
+
`${context}.evalGates`
|
|
16340
|
+
),
|
|
16341
|
+
criticalBuckets: requiredStringArray(
|
|
16342
|
+
evalGates,
|
|
16343
|
+
"criticalBuckets",
|
|
16344
|
+
`${context}.evalGates`
|
|
16345
|
+
),
|
|
16346
|
+
maxRegressionPct,
|
|
16347
|
+
minPassK: requiredNumberRecord(
|
|
16348
|
+
evalGates,
|
|
16349
|
+
"minPassK",
|
|
16350
|
+
`${context}.evalGates`
|
|
16351
|
+
)
|
|
16352
|
+
}
|
|
16353
|
+
};
|
|
16354
|
+
}
|
|
16355
|
+
function defineHarnessTemplateManifest(value, context) {
|
|
16356
|
+
return validateHarnessTemplateManifest(value, context);
|
|
16357
|
+
}
|
|
16090
16358
|
function asRecord4(value) {
|
|
16091
16359
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
16092
16360
|
return value;
|
|
@@ -16110,6 +16378,16 @@ function uniqueStrings(values, maxCount) {
|
|
|
16110
16378
|
}
|
|
16111
16379
|
return output;
|
|
16112
16380
|
}
|
|
16381
|
+
function stableStringify(value) {
|
|
16382
|
+
if (value === null || typeof value !== "object") {
|
|
16383
|
+
return JSON.stringify(value);
|
|
16384
|
+
}
|
|
16385
|
+
if (Array.isArray(value)) {
|
|
16386
|
+
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
16387
|
+
}
|
|
16388
|
+
const record = value;
|
|
16389
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
|
|
16390
|
+
}
|
|
16113
16391
|
function renderConstBlock(name, value) {
|
|
16114
16392
|
return `const ${name} = ${JSON.stringify(value, null, 2)} as const;`;
|
|
16115
16393
|
}
|
|
@@ -18049,6 +18327,156 @@ ${knownFactsBlock}
|
|
|
18049
18327
|
[Request]
|
|
18050
18328
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
18051
18329
|
}
|
|
18330
|
+
var STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST = defineHarnessTemplateManifest(
|
|
18331
|
+
manifest_default3,
|
|
18332
|
+
"stable@1.0.0 manifest"
|
|
18333
|
+
);
|
|
18334
|
+
function hashHarnessTemplateValue(value) {
|
|
18335
|
+
return hashString(stableStringify(value)) || "00000000";
|
|
18336
|
+
}
|
|
18337
|
+
function renderStableHarnessPrompt(input) {
|
|
18338
|
+
const prompt = buildGranularAgentSystemPrompt(input);
|
|
18339
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18340
|
+
STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18341
|
+
);
|
|
18342
|
+
return {
|
|
18343
|
+
templateId: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18344
|
+
templateVersion: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18345
|
+
templateHash,
|
|
18346
|
+
promptInstanceHash: hashHarnessTemplateValue({
|
|
18347
|
+
templateHash,
|
|
18348
|
+
input,
|
|
18349
|
+
prompt
|
|
18350
|
+
}),
|
|
18351
|
+
prompt
|
|
18352
|
+
};
|
|
18353
|
+
}
|
|
18354
|
+
function renderStableHarnessContinuation(resultPreview) {
|
|
18355
|
+
const instruction = buildContinuationInstruction(resultPreview);
|
|
18356
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18357
|
+
STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18358
|
+
);
|
|
18359
|
+
return {
|
|
18360
|
+
templateId: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18361
|
+
templateVersion: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18362
|
+
templateHash,
|
|
18363
|
+
instruction
|
|
18364
|
+
};
|
|
18365
|
+
}
|
|
18366
|
+
var STABLE_AGENT_HARNESS_TEMPLATE = {
|
|
18367
|
+
manifest: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST,
|
|
18368
|
+
renderPrompt: renderStableHarnessPrompt,
|
|
18369
|
+
renderContinuation: renderStableHarnessContinuation
|
|
18370
|
+
};
|
|
18371
|
+
var EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST = defineHarnessTemplateManifest(
|
|
18372
|
+
manifest_default2,
|
|
18373
|
+
"experimental-compact@0.1.0 manifest"
|
|
18374
|
+
);
|
|
18375
|
+
function renderExperimentalCompactHarnessPrompt(input) {
|
|
18376
|
+
const prompt = `${buildGranularAgentSystemPrompt(input)}
|
|
18377
|
+
|
|
18378
|
+
[Candidate Harness Delta: Compact Decision Discipline]
|
|
18379
|
+
- Prefer the smallest action that satisfies the current request.
|
|
18380
|
+
- When several records could match, ask one structured choice question before mutating.
|
|
18381
|
+
- Before any irreversible or outbound mutation, obtain explicit confirmation unless the policy surface already requires it.
|
|
18382
|
+
- Do not compensate for missing tools with raw network calls, synthetic records, or hidden side channels.
|
|
18383
|
+
- Keep the final user-facing reply focused on what was done, what was not done, and any remaining blocker.`;
|
|
18384
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18385
|
+
EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18386
|
+
);
|
|
18387
|
+
return {
|
|
18388
|
+
templateId: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18389
|
+
templateVersion: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18390
|
+
templateHash,
|
|
18391
|
+
promptInstanceHash: hashHarnessTemplateValue({
|
|
18392
|
+
templateHash,
|
|
18393
|
+
input,
|
|
18394
|
+
prompt
|
|
18395
|
+
}),
|
|
18396
|
+
prompt
|
|
18397
|
+
};
|
|
18398
|
+
}
|
|
18399
|
+
function renderExperimentalCompactHarnessContinuation(resultPreview) {
|
|
18400
|
+
const instruction = `${buildContinuationInstruction(resultPreview)}
|
|
18401
|
+
|
|
18402
|
+
Keep the continuation compact: either finish, ask the one blocking question, or run the next smallest safe action.`;
|
|
18403
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18404
|
+
EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18405
|
+
);
|
|
18406
|
+
return {
|
|
18407
|
+
templateId: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18408
|
+
templateVersion: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18409
|
+
templateHash,
|
|
18410
|
+
instruction
|
|
18411
|
+
};
|
|
18412
|
+
}
|
|
18413
|
+
var EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE = {
|
|
18414
|
+
manifest: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST,
|
|
18415
|
+
renderPrompt: renderExperimentalCompactHarnessPrompt,
|
|
18416
|
+
renderContinuation: renderExperimentalCompactHarnessContinuation
|
|
18417
|
+
};
|
|
18418
|
+
var ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST = defineHarnessTemplateManifest(
|
|
18419
|
+
manifest_default,
|
|
18420
|
+
"action-presentation@0.1.0 manifest"
|
|
18421
|
+
);
|
|
18422
|
+
function renderActionPresentationHarnessPrompt(input) {
|
|
18423
|
+
const prompt = `${buildGranularAgentSystemPrompt(input)}
|
|
18424
|
+
|
|
18425
|
+
[Candidate Harness Delta: Action Request And Result Presentation]
|
|
18426
|
+
- Treat requests like "handle it", "take care of it", "send it", "update it", "fix it", "process it", or "do it" as action requests when the message names a business object, target, workflow, or mutation verb.
|
|
18427
|
+
- For action requests involving session data, generated files, records, effects, or workflows, do not use text-only completion. Generate and run code, ask the blocking human question, or clearly refuse if policy/tooling prevents the action.
|
|
18428
|
+
- Never answer only "Done", "OK", "Handled", or similar terse completion text for a mutation request. The final user-facing reply must name the action attempted, the grounded target or blocker, and the actual result.
|
|
18429
|
+
- After a mutation/effect call, base the reply on the returned action result and include a visible target label or identifier when one exists.
|
|
18430
|
+
- If no target can be grounded, say what was searched and what exact identifier or choice is needed; do not pretend the action completed.`;
|
|
18431
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18432
|
+
ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18433
|
+
);
|
|
18434
|
+
return {
|
|
18435
|
+
templateId: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18436
|
+
templateVersion: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18437
|
+
templateHash,
|
|
18438
|
+
promptInstanceHash: hashHarnessTemplateValue({
|
|
18439
|
+
templateHash,
|
|
18440
|
+
input,
|
|
18441
|
+
prompt
|
|
18442
|
+
}),
|
|
18443
|
+
prompt
|
|
18444
|
+
};
|
|
18445
|
+
}
|
|
18446
|
+
function renderActionPresentationHarnessContinuation(resultPreview) {
|
|
18447
|
+
const instruction = `${buildContinuationInstruction(resultPreview)}
|
|
18448
|
+
|
|
18449
|
+
Before finishing, check whether the latest user request asked for an action. If it did, do not finish with a bare completion token; either continue with the needed tool/code step, ask the blocking question, refuse with the policy reason, or report the grounded action result with the target label.`;
|
|
18450
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18451
|
+
ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18452
|
+
);
|
|
18453
|
+
return {
|
|
18454
|
+
templateId: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18455
|
+
templateVersion: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18456
|
+
templateHash,
|
|
18457
|
+
instruction
|
|
18458
|
+
};
|
|
18459
|
+
}
|
|
18460
|
+
var ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE = {
|
|
18461
|
+
manifest: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST,
|
|
18462
|
+
renderPrompt: renderActionPresentationHarnessPrompt,
|
|
18463
|
+
renderContinuation: renderActionPresentationHarnessContinuation
|
|
18464
|
+
};
|
|
18465
|
+
var AGENT_HARNESS_TEMPLATES = {
|
|
18466
|
+
[STABLE_AGENT_HARNESS_TEMPLATE.manifest.id]: STABLE_AGENT_HARNESS_TEMPLATE,
|
|
18467
|
+
[EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE.manifest.id]: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE,
|
|
18468
|
+
[ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE.manifest.id]: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE
|
|
18469
|
+
};
|
|
18470
|
+
function resolveHarnessTemplate(templateId = "stable", options) {
|
|
18471
|
+
const resolved = AGENT_HARNESS_TEMPLATES[templateId];
|
|
18472
|
+
if (resolved) return resolved;
|
|
18473
|
+
{
|
|
18474
|
+
const known = Object.keys(AGENT_HARNESS_TEMPLATES).join(", ");
|
|
18475
|
+
throw new Error(
|
|
18476
|
+
`Unknown harness template "${templateId}". Known templates: ${known}`
|
|
18477
|
+
);
|
|
18478
|
+
}
|
|
18479
|
+
}
|
|
18052
18480
|
|
|
18053
18481
|
// src/openai-usage.ts
|
|
18054
18482
|
var OPENAI_PRICING_SOURCE_URL = "https://developers.openai.com/api/docs/models/gpt-5.4/";
|
|
@@ -18170,6 +18598,98 @@ function matchesPattern(text, matcher) {
|
|
|
18170
18598
|
if (typeof matcher === "string") return text.includes(matcher);
|
|
18171
18599
|
return matcher.test(text);
|
|
18172
18600
|
}
|
|
18601
|
+
function matcherFromConfig(value) {
|
|
18602
|
+
const match = value.match(/^\/([\s\S]*)\/([dgimsuvy]*)$/);
|
|
18603
|
+
if (!match) return value;
|
|
18604
|
+
return new RegExp(match[1] || "", match[2] || "");
|
|
18605
|
+
}
|
|
18606
|
+
function matchersFromConfig(values) {
|
|
18607
|
+
if (!values?.length) return void 0;
|
|
18608
|
+
return values.map((value) => matcherFromConfig(value));
|
|
18609
|
+
}
|
|
18610
|
+
function expectationsFromConfig(input) {
|
|
18611
|
+
if (!input) return void 0;
|
|
18612
|
+
return {
|
|
18613
|
+
replyIncludes: matchersFromConfig(input.replyIncludes),
|
|
18614
|
+
replyExcludes: matchersFromConfig(input.replyExcludes),
|
|
18615
|
+
actionIncludes: matchersFromConfig(input.actionIncludes),
|
|
18616
|
+
actionExcludes: matchersFromConfig(input.actionExcludes),
|
|
18617
|
+
codeIncludes: matchersFromConfig(input.codeIncludes),
|
|
18618
|
+
codeExcludes: matchersFromConfig(input.codeExcludes),
|
|
18619
|
+
behaviorBuckets: input.behaviorBuckets,
|
|
18620
|
+
actions: input.actions ? {
|
|
18621
|
+
required: matchersFromConfig(input.actions.required),
|
|
18622
|
+
forbidden: matchersFromConfig(input.actions.forbidden)
|
|
18623
|
+
} : void 0,
|
|
18624
|
+
prompts: input.prompts ? {
|
|
18625
|
+
...input.prompts,
|
|
18626
|
+
requiredConfirmationBefore: matchersFromConfig(
|
|
18627
|
+
input.prompts.requiredConfirmationBefore
|
|
18628
|
+
)
|
|
18629
|
+
} : void 0,
|
|
18630
|
+
presentation: input.presentation ? {
|
|
18631
|
+
mustMention: matchersFromConfig(input.presentation.mustMention),
|
|
18632
|
+
mustNotMention: matchersFromConfig(input.presentation.mustNotMention),
|
|
18633
|
+
mustDisplayOrSave: matchersFromConfig(
|
|
18634
|
+
input.presentation.mustDisplayOrSave
|
|
18635
|
+
)
|
|
18636
|
+
} : void 0
|
|
18637
|
+
};
|
|
18638
|
+
}
|
|
18639
|
+
function promptResponderFromConfig(rules) {
|
|
18640
|
+
if (!rules?.length) return void 0;
|
|
18641
|
+
return createHumanResponder(
|
|
18642
|
+
rules.map((rule) => ({
|
|
18643
|
+
type: rule.type,
|
|
18644
|
+
when: Array.isArray(rule.when) ? rule.when.map((matcher) => matcherFromConfig(matcher)) : rule.when ? matcherFromConfig(rule.when) : void 0,
|
|
18645
|
+
answer: rule.answer
|
|
18646
|
+
}))
|
|
18647
|
+
);
|
|
18648
|
+
}
|
|
18649
|
+
function inspectionFromConfig(inspection) {
|
|
18650
|
+
if (!inspection) return void 0;
|
|
18651
|
+
return {
|
|
18652
|
+
code: inspection.code,
|
|
18653
|
+
includes: matchersFromConfig(inspection.includes),
|
|
18654
|
+
excludes: matchersFromConfig(inspection.excludes)
|
|
18655
|
+
};
|
|
18656
|
+
}
|
|
18657
|
+
function inspectionsFromConfig(inspections) {
|
|
18658
|
+
if (!inspections) return void 0;
|
|
18659
|
+
if (Array.isArray(inspections)) {
|
|
18660
|
+
return inspections.map((inspection) => inspectionFromConfig(inspection)).filter(
|
|
18661
|
+
(inspection) => Boolean(inspection)
|
|
18662
|
+
);
|
|
18663
|
+
}
|
|
18664
|
+
return inspectionFromConfig(inspections);
|
|
18665
|
+
}
|
|
18666
|
+
function scenariosFromAgentEvalFile(file) {
|
|
18667
|
+
return file.scenarios.map((scenario) => ({
|
|
18668
|
+
id: scenario.id,
|
|
18669
|
+
description: scenario.description,
|
|
18670
|
+
request: scenario.request,
|
|
18671
|
+
behaviorBuckets: scenario.behaviorBuckets,
|
|
18672
|
+
human: promptResponderFromConfig(scenario.human),
|
|
18673
|
+
prepareRecords: scenario.prepareRecords,
|
|
18674
|
+
expect: expectationsFromConfig(scenario.expect),
|
|
18675
|
+
verify: inspectionFromConfig(scenario.verify),
|
|
18676
|
+
inspect: inspectionsFromConfig(scenario.inspect),
|
|
18677
|
+
steps: scenario.steps?.map((step) => ({
|
|
18678
|
+
id: step.id,
|
|
18679
|
+
request: step.request,
|
|
18680
|
+
behaviorBuckets: step.behaviorBuckets || scenario.behaviorBuckets,
|
|
18681
|
+
human: promptResponderFromConfig(step.human || scenario.human),
|
|
18682
|
+
expect: expectationsFromConfig(step.expect || scenario.expect),
|
|
18683
|
+
inspect: inspectionsFromConfig(step.inspect)
|
|
18684
|
+
}))
|
|
18685
|
+
}));
|
|
18686
|
+
}
|
|
18687
|
+
async function loadAgentEvalScenarioFile(filePath) {
|
|
18688
|
+
const raw = JSON.parse(
|
|
18689
|
+
await promises.readFile(filePath, "utf8")
|
|
18690
|
+
);
|
|
18691
|
+
return scenariosFromAgentEvalFile(raw);
|
|
18692
|
+
}
|
|
18173
18693
|
function assertMatches(label, text, includes = [], excludes = []) {
|
|
18174
18694
|
for (const matcher of includes) {
|
|
18175
18695
|
if (!matchesPattern(text, matcher)) {
|
|
@@ -18202,6 +18722,23 @@ function asArray3(value) {
|
|
|
18202
18722
|
if (!value) return [];
|
|
18203
18723
|
return Array.isArray(value) ? value : [value];
|
|
18204
18724
|
}
|
|
18725
|
+
function progressEvent(input) {
|
|
18726
|
+
return {
|
|
18727
|
+
...input,
|
|
18728
|
+
id: input.id || [
|
|
18729
|
+
input.scenarioId || "suite",
|
|
18730
|
+
input.stepId || input.phase,
|
|
18731
|
+
input.iteration ? `iteration-${input.iteration}` : "",
|
|
18732
|
+
input.jobId || "",
|
|
18733
|
+
input.title,
|
|
18734
|
+
Date.now()
|
|
18735
|
+
].filter(Boolean).join(":"),
|
|
18736
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
18737
|
+
};
|
|
18738
|
+
}
|
|
18739
|
+
async function emitProgress(handler, event) {
|
|
18740
|
+
await handler?.(progressEvent(event));
|
|
18741
|
+
}
|
|
18205
18742
|
var GPT_54_TOKEN_PRICING_USD_PER_MILLION = {
|
|
18206
18743
|
input: 2.5,
|
|
18207
18744
|
cachedInput: 0.25,
|
|
@@ -18444,7 +18981,7 @@ function filterPromptsByBoundary(liveDoc, prompts, boundaryTimestamp) {
|
|
|
18444
18981
|
});
|
|
18445
18982
|
}
|
|
18446
18983
|
function createScriptedPromptResponder(rules, fallback) {
|
|
18447
|
-
|
|
18984
|
+
const responder = async ({ prompt, history }) => {
|
|
18448
18985
|
const promptText = `${prompt.title || ""}
|
|
18449
18986
|
${prompt.message || ""}`;
|
|
18450
18987
|
for (const rule of rules) {
|
|
@@ -18461,6 +18998,11 @@ ${prompt.message || ""}`;
|
|
|
18461
18998
|
`No scripted prompt responder matched prompt ${prompt.id}: ${promptText}`
|
|
18462
18999
|
);
|
|
18463
19000
|
};
|
|
19001
|
+
Object.defineProperty(responder, "__granularScriptedPromptRules", {
|
|
19002
|
+
enumerable: false,
|
|
19003
|
+
value: rules
|
|
19004
|
+
});
|
|
19005
|
+
return responder;
|
|
18464
19006
|
}
|
|
18465
19007
|
function extractJsonObject(text) {
|
|
18466
19008
|
const start = text.indexOf("{");
|
|
@@ -18747,6 +19289,22 @@ ${checkpoint.latestJobResult}` : null
|
|
|
18747
19289
|
];
|
|
18748
19290
|
return lines.filter(Boolean).join("\n\n");
|
|
18749
19291
|
}
|
|
19292
|
+
function readableAgentMessage(message) {
|
|
19293
|
+
const record = asRecord6(message);
|
|
19294
|
+
if (!record) return JSON.stringify(message);
|
|
19295
|
+
if (typeof record.reply === "string" && record.reply.trim()) {
|
|
19296
|
+
return record.reply;
|
|
19297
|
+
}
|
|
19298
|
+
const show = asRecord6(record.show);
|
|
19299
|
+
const variableNames = asArray3(show?.variableNames).map((value) => String(value)).filter(Boolean);
|
|
19300
|
+
if (variableNames.length) {
|
|
19301
|
+
return `Displayed ${variableNames.join(", ")}`;
|
|
19302
|
+
}
|
|
19303
|
+
if (typeof record.kind === "string") {
|
|
19304
|
+
return `Agent ${record.kind} message`;
|
|
19305
|
+
}
|
|
19306
|
+
return JSON.stringify(message);
|
|
19307
|
+
}
|
|
18750
19308
|
async function waitForJobOutcome(input) {
|
|
18751
19309
|
const stdout = [];
|
|
18752
19310
|
const stderr = [];
|
|
@@ -18754,6 +19312,11 @@ async function waitForJobOutcome(input) {
|
|
|
18754
19312
|
let lastPromptCount = 0;
|
|
18755
19313
|
let lastMessageCount = 0;
|
|
18756
19314
|
let lastJobSummary = null;
|
|
19315
|
+
let lastActionSummaryKey = "";
|
|
19316
|
+
let lastActionSummaryLength = 0;
|
|
19317
|
+
let lastAgentMessageKey = "";
|
|
19318
|
+
let lastAgentMessageCount = 0;
|
|
19319
|
+
let lastJobStatus = "";
|
|
18757
19320
|
input.job.on("stdout", (line) => stdout.push(String(line)));
|
|
18758
19321
|
input.job.on("stderr", (line) => stderr.push(String(line)));
|
|
18759
19322
|
const startedAt = Date.now();
|
|
@@ -18769,7 +19332,71 @@ async function waitForJobOutcome(input) {
|
|
|
18769
19332
|
const messages = asArray3(asRecord6(liveDoc.conversation)?.messages);
|
|
18770
19333
|
lastMessageCount = messages.length;
|
|
18771
19334
|
lastJobSummary = asRecord6(asRecord6(liveDoc.jobs)?.byId)?.[input.job.id] || null;
|
|
19335
|
+
const jobRecord = asRecord6(lastJobSummary);
|
|
19336
|
+
const jobStatus = typeof jobRecord?.status === "string" ? jobRecord.status : "";
|
|
19337
|
+
if (jobStatus && jobStatus !== lastJobStatus) {
|
|
19338
|
+
lastJobStatus = jobStatus;
|
|
19339
|
+
input.onProgress?.({
|
|
19340
|
+
id: `${input.job.id}:status:${jobStatus}:${Date.now()}`,
|
|
19341
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19342
|
+
phase: "job",
|
|
19343
|
+
status: "running",
|
|
19344
|
+
jobId: input.job.id,
|
|
19345
|
+
title: `Job ${jobStatus}`,
|
|
19346
|
+
message: `Granular job ${input.job.id}`,
|
|
19347
|
+
data: jobRecord,
|
|
19348
|
+
...input.progressContext
|
|
19349
|
+
});
|
|
19350
|
+
}
|
|
19351
|
+
const actionSummary = getActionSummary(liveDoc, input.job.id);
|
|
19352
|
+
const actionSummaryKey = JSON.stringify(actionSummary);
|
|
19353
|
+
if (actionSummary.length && actionSummaryKey !== lastActionSummaryKey) {
|
|
19354
|
+
const newActions = actionSummary.slice(lastActionSummaryLength);
|
|
19355
|
+
lastActionSummaryLength = actionSummary.length;
|
|
19356
|
+
lastActionSummaryKey = actionSummaryKey;
|
|
19357
|
+
input.onProgress?.({
|
|
19358
|
+
id: `${input.job.id}:actions:${Date.now()}`,
|
|
19359
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19360
|
+
phase: "job",
|
|
19361
|
+
status: "running",
|
|
19362
|
+
jobId: input.job.id,
|
|
19363
|
+
title: newActions.length === 1 ? "Action observed" : "Actions observed",
|
|
19364
|
+
message: (newActions.length ? newActions : actionSummary).join("\n"),
|
|
19365
|
+
data: { actionSummary, newActions },
|
|
19366
|
+
...input.progressContext
|
|
19367
|
+
});
|
|
19368
|
+
}
|
|
19369
|
+
const agentMessages = getJobAgentMessages(liveDoc, input.job.id);
|
|
19370
|
+
const agentMessageKey = JSON.stringify(agentMessages);
|
|
19371
|
+
if (agentMessages.length && agentMessageKey !== lastAgentMessageKey) {
|
|
19372
|
+
const newMessages = agentMessages.slice(lastAgentMessageCount);
|
|
19373
|
+
lastAgentMessageCount = agentMessages.length;
|
|
19374
|
+
lastAgentMessageKey = agentMessageKey;
|
|
19375
|
+
const latestMessage = newMessages.at(-1) || agentMessages.at(-1);
|
|
19376
|
+
input.onProgress?.({
|
|
19377
|
+
id: `${input.job.id}:messages:${Date.now()}`,
|
|
19378
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19379
|
+
phase: "job",
|
|
19380
|
+
status: "running",
|
|
19381
|
+
jobId: input.job.id,
|
|
19382
|
+
title: "Agent message",
|
|
19383
|
+
message: readableAgentMessage(latestMessage),
|
|
19384
|
+
data: { agentMessages, newMessages },
|
|
19385
|
+
...input.progressContext
|
|
19386
|
+
});
|
|
19387
|
+
}
|
|
18772
19388
|
if (prompts.length > 0) {
|
|
19389
|
+
input.onProgress?.({
|
|
19390
|
+
id: `${input.job.id}:prompt:${prompts[0]?.id || Date.now()}`,
|
|
19391
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19392
|
+
phase: "prompt",
|
|
19393
|
+
status: "running",
|
|
19394
|
+
jobId: input.job.id,
|
|
19395
|
+
title: "Waiting for prompt answer",
|
|
19396
|
+
message: prompts[0]?.message || prompts[0]?.title,
|
|
19397
|
+
data: { prompts },
|
|
19398
|
+
...input.progressContext
|
|
19399
|
+
});
|
|
18773
19400
|
return { kind: "prompt", prompts, liveDoc, stdout, stderr };
|
|
18774
19401
|
}
|
|
18775
19402
|
try {
|
|
@@ -18778,6 +19405,17 @@ async function waitForJobOutcome(input) {
|
|
|
18778
19405
|
input.pollIntervalMs,
|
|
18779
19406
|
`job ${input.job.id} tick`
|
|
18780
19407
|
);
|
|
19408
|
+
input.onProgress?.({
|
|
19409
|
+
id: `${input.job.id}:completed:${Date.now()}`,
|
|
19410
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19411
|
+
phase: "job",
|
|
19412
|
+
status: "passed",
|
|
19413
|
+
jobId: input.job.id,
|
|
19414
|
+
title: "Job completed",
|
|
19415
|
+
message: JSON.stringify(result)?.slice(0, 800),
|
|
19416
|
+
data: { result, stdout, stderr },
|
|
19417
|
+
...input.progressContext
|
|
19418
|
+
});
|
|
18781
19419
|
return { kind: "completed", result, liveDoc, stdout, stderr };
|
|
18782
19420
|
} catch (error) {
|
|
18783
19421
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -19009,6 +19647,10 @@ function buildSessionLogReport(input) {
|
|
|
19009
19647
|
`- Environment id: \`${conversation.environment.environmentId}\``,
|
|
19010
19648
|
`- Sandbox id: \`${conversation.environment.sandboxId}\``,
|
|
19011
19649
|
`- Status: ${result?.status || (error ? "failed" : "unknown")}`,
|
|
19650
|
+
...systemPrompts[0]?.iteration.templateId ? [
|
|
19651
|
+
`- Harness template: \`${systemPrompts[0].iteration.templateId}@${systemPrompts[0].iteration.templateVersion || "unknown"}\``,
|
|
19652
|
+
`- Template hash: \`${systemPrompts[0].iteration.templateHash || "unknown"}\``
|
|
19653
|
+
] : [],
|
|
19012
19654
|
...result?.error || error ? [`- Error: ${result?.error || error}`] : [],
|
|
19013
19655
|
"",
|
|
19014
19656
|
"## Conversation"
|
|
@@ -19116,6 +19758,12 @@ function buildSessionLogReport(input) {
|
|
|
19116
19758
|
lines.push(
|
|
19117
19759
|
`### Turn ${turn.turnNumber}, Generation ${iteration.iteration}`,
|
|
19118
19760
|
"",
|
|
19761
|
+
...iteration.templateId ? [
|
|
19762
|
+
`- Template: \`${iteration.templateId}@${iteration.templateVersion || "unknown"}\``,
|
|
19763
|
+
`- Template hash: \`${iteration.templateHash || "unknown"}\``,
|
|
19764
|
+
`- Prompt hash: \`${iteration.promptInstanceHash || "unknown"}\``,
|
|
19765
|
+
""
|
|
19766
|
+
] : [],
|
|
19119
19767
|
fenced(iteration.systemPrompt, "text"),
|
|
19120
19768
|
""
|
|
19121
19769
|
);
|
|
@@ -19157,9 +19805,167 @@ function isTransientEvalError(error) {
|
|
|
19157
19805
|
const message = error instanceof Error ? error.message : String(error);
|
|
19158
19806
|
return /socket connection was closed unexpectedly/i.test(message) || /timed out after/i.test(message) || /ECONNRESET/i.test(message) || /network/i.test(message) || /429/.test(message);
|
|
19159
19807
|
}
|
|
19808
|
+
function assertionPassed(id, run) {
|
|
19809
|
+
try {
|
|
19810
|
+
run(id);
|
|
19811
|
+
return { id, label: id, status: "passed" };
|
|
19812
|
+
} catch (error) {
|
|
19813
|
+
return {
|
|
19814
|
+
id,
|
|
19815
|
+
label: id,
|
|
19816
|
+
status: "failed",
|
|
19817
|
+
message: error instanceof Error ? error.message : String(error)
|
|
19818
|
+
};
|
|
19819
|
+
}
|
|
19820
|
+
}
|
|
19821
|
+
function hasMatchers(matchers) {
|
|
19822
|
+
return Boolean(matchers?.length);
|
|
19823
|
+
}
|
|
19824
|
+
function evaluateExpectationAssertions(input) {
|
|
19825
|
+
const expect = input.expect;
|
|
19826
|
+
if (!expect) return [];
|
|
19827
|
+
const prefix = `${input.scenarioId} step ${input.stepIndex + 1}`;
|
|
19828
|
+
const assertions = [];
|
|
19829
|
+
const actionText = input.completed.actionSummary.join("\n");
|
|
19830
|
+
const codeText = input.completed.finalCode || "";
|
|
19831
|
+
const displaySurface = [
|
|
19832
|
+
input.completed.responseText,
|
|
19833
|
+
actionText,
|
|
19834
|
+
codeText,
|
|
19835
|
+
JSON.stringify(input.completed.result)
|
|
19836
|
+
].join("\n");
|
|
19837
|
+
const promptSurface = input.completed.promptInteractions.map(
|
|
19838
|
+
(interaction) => [interaction.type, interaction.title, interaction.message].join(" ")
|
|
19839
|
+
).join("\n");
|
|
19840
|
+
if (hasMatchers(expect.replyIncludes) || hasMatchers(expect.replyExcludes)) {
|
|
19841
|
+
assertions.push(
|
|
19842
|
+
assertionPassed(
|
|
19843
|
+
"reply",
|
|
19844
|
+
() => assertMatches(
|
|
19845
|
+
`Reply for ${prefix}`,
|
|
19846
|
+
input.completed.responseText,
|
|
19847
|
+
expect.replyIncludes,
|
|
19848
|
+
expect.replyExcludes
|
|
19849
|
+
)
|
|
19850
|
+
)
|
|
19851
|
+
);
|
|
19852
|
+
}
|
|
19853
|
+
if (hasMatchers(expect.actionIncludes) || hasMatchers(expect.actionExcludes)) {
|
|
19854
|
+
assertions.push(
|
|
19855
|
+
assertionPassed(
|
|
19856
|
+
"actions",
|
|
19857
|
+
() => assertMatches(
|
|
19858
|
+
`Action summary for ${prefix}`,
|
|
19859
|
+
actionText,
|
|
19860
|
+
expect.actionIncludes,
|
|
19861
|
+
expect.actionExcludes
|
|
19862
|
+
)
|
|
19863
|
+
)
|
|
19864
|
+
);
|
|
19865
|
+
}
|
|
19866
|
+
if (hasMatchers(expect.codeIncludes) || hasMatchers(expect.codeExcludes)) {
|
|
19867
|
+
assertions.push(
|
|
19868
|
+
assertionPassed(
|
|
19869
|
+
"code",
|
|
19870
|
+
() => assertMatches(
|
|
19871
|
+
`Generated code for ${prefix}`,
|
|
19872
|
+
codeText,
|
|
19873
|
+
expect.codeIncludes,
|
|
19874
|
+
expect.codeExcludes
|
|
19875
|
+
)
|
|
19876
|
+
)
|
|
19877
|
+
);
|
|
19878
|
+
}
|
|
19879
|
+
if (hasMatchers(expect.actions?.required) || hasMatchers(expect.actions?.forbidden)) {
|
|
19880
|
+
assertions.push(
|
|
19881
|
+
assertionPassed(
|
|
19882
|
+
"required-actions",
|
|
19883
|
+
() => assertMatches(
|
|
19884
|
+
`Required actions for ${prefix}`,
|
|
19885
|
+
actionText,
|
|
19886
|
+
expect.actions?.required,
|
|
19887
|
+
expect.actions?.forbidden
|
|
19888
|
+
)
|
|
19889
|
+
)
|
|
19890
|
+
);
|
|
19891
|
+
}
|
|
19892
|
+
if (hasMatchers(expect.presentation?.mustMention) || hasMatchers(expect.presentation?.mustNotMention)) {
|
|
19893
|
+
assertions.push(
|
|
19894
|
+
assertionPassed(
|
|
19895
|
+
"presentation",
|
|
19896
|
+
() => assertMatches(
|
|
19897
|
+
`Presentation for ${prefix}`,
|
|
19898
|
+
input.completed.responseText,
|
|
19899
|
+
expect.presentation?.mustMention,
|
|
19900
|
+
expect.presentation?.mustNotMention
|
|
19901
|
+
)
|
|
19902
|
+
)
|
|
19903
|
+
);
|
|
19904
|
+
}
|
|
19905
|
+
if (hasMatchers(expect.presentation?.mustDisplayOrSave)) {
|
|
19906
|
+
assertions.push(
|
|
19907
|
+
assertionPassed(
|
|
19908
|
+
"display",
|
|
19909
|
+
() => assertMatches(
|
|
19910
|
+
`Displayed or saved records for ${prefix}`,
|
|
19911
|
+
displaySurface,
|
|
19912
|
+
expect.presentation?.mustDisplayOrSave
|
|
19913
|
+
)
|
|
19914
|
+
)
|
|
19915
|
+
);
|
|
19916
|
+
}
|
|
19917
|
+
if (expect.prompts?.requiredChoiceWhenAmbiguous) {
|
|
19918
|
+
assertions.push(
|
|
19919
|
+
assertionPassed("choice", () => {
|
|
19920
|
+
if (!input.completed.promptInteractions.some(
|
|
19921
|
+
(interaction) => interaction.type === "choice"
|
|
19922
|
+
)) {
|
|
19923
|
+
throw new Error(`Expected ${prefix} to use a choice prompt.`);
|
|
19924
|
+
}
|
|
19925
|
+
})
|
|
19926
|
+
);
|
|
19927
|
+
}
|
|
19928
|
+
for (const forbiddenType of expect.prompts?.forbiddenPromptTypes || []) {
|
|
19929
|
+
assertions.push(
|
|
19930
|
+
assertionPassed(`forbidden-prompt:${forbiddenType}`, () => {
|
|
19931
|
+
if (input.completed.promptInteractions.some(
|
|
19932
|
+
(interaction) => interaction.type === forbiddenType
|
|
19933
|
+
)) {
|
|
19934
|
+
throw new Error(
|
|
19935
|
+
`Prompt interactions for ${prefix} used forbidden prompt type ${forbiddenType}.`
|
|
19936
|
+
);
|
|
19937
|
+
}
|
|
19938
|
+
})
|
|
19939
|
+
);
|
|
19940
|
+
}
|
|
19941
|
+
if (expect.prompts?.requiredConfirmationBefore?.length) {
|
|
19942
|
+
assertions.push(
|
|
19943
|
+
assertionPassed(
|
|
19944
|
+
"confirmation",
|
|
19945
|
+
() => assertMatches(
|
|
19946
|
+
`Confirmation prompts for ${prefix}`,
|
|
19947
|
+
[actionText, promptSurface].join("\n"),
|
|
19948
|
+
expect.prompts?.requiredConfirmationBefore
|
|
19949
|
+
)
|
|
19950
|
+
)
|
|
19951
|
+
);
|
|
19952
|
+
}
|
|
19953
|
+
return assertions;
|
|
19954
|
+
}
|
|
19160
19955
|
async function runAgentEvalSuite(options) {
|
|
19161
19956
|
const results = [];
|
|
19162
19957
|
for (const scenario of options.scenarios) {
|
|
19958
|
+
await options.harness.emitProgress?.({
|
|
19959
|
+
phase: "scenario",
|
|
19960
|
+
status: "running",
|
|
19961
|
+
scenarioId: scenario.id,
|
|
19962
|
+
title: "Scenario started",
|
|
19963
|
+
message: scenario.description || scenario.request || scenario.id,
|
|
19964
|
+
data: {
|
|
19965
|
+
scenarioId: scenario.id,
|
|
19966
|
+
behaviorBuckets: scenario.behaviorBuckets
|
|
19967
|
+
}
|
|
19968
|
+
});
|
|
19163
19969
|
let attempt = 0;
|
|
19164
19970
|
let finalResult = null;
|
|
19165
19971
|
while (attempt < 2 && !finalResult) {
|
|
@@ -19230,27 +20036,38 @@ async function runAgentEvalSuite(options) {
|
|
|
19230
20036
|
},
|
|
19231
20037
|
assertMatches
|
|
19232
20038
|
};
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
step.
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
)
|
|
20039
|
+
const assertions = evaluateExpectationAssertions({
|
|
20040
|
+
scenarioId: scenario.id,
|
|
20041
|
+
stepIndex: index,
|
|
20042
|
+
expect: step.expect,
|
|
20043
|
+
completed
|
|
20044
|
+
});
|
|
20045
|
+
for (const assertion of assertions) {
|
|
20046
|
+
await options.harness.emitProgress?.({
|
|
20047
|
+
phase: "assertion",
|
|
20048
|
+
status: assertion.status,
|
|
20049
|
+
scenarioId: scenario.id,
|
|
20050
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20051
|
+
title: assertion.label,
|
|
20052
|
+
message: assertion.message,
|
|
20053
|
+
data: assertion
|
|
20054
|
+
});
|
|
20055
|
+
}
|
|
20056
|
+
const failedAssertion = assertions.find(
|
|
20057
|
+
(assertion) => assertion.status === "failed"
|
|
20058
|
+
);
|
|
20059
|
+
if (failedAssertion) {
|
|
20060
|
+
throw new Error(failedAssertion.message || failedAssertion.label);
|
|
19252
20061
|
}
|
|
19253
20062
|
for (const inspection of stepInspections) {
|
|
20063
|
+
await options.harness.emitProgress?.({
|
|
20064
|
+
phase: "inspection",
|
|
20065
|
+
status: "running",
|
|
20066
|
+
scenarioId: scenario.id,
|
|
20067
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20068
|
+
title: "Running step inspection",
|
|
20069
|
+
message: inspection.code.slice(0, 500)
|
|
20070
|
+
});
|
|
19254
20071
|
const inspectionResult = await context.inspect(inspection.code);
|
|
19255
20072
|
const inspectionText = JSON.stringify(inspectionResult, null, 2);
|
|
19256
20073
|
assertMatches(
|
|
@@ -19266,9 +20083,32 @@ async function runAgentEvalSuite(options) {
|
|
|
19266
20083
|
});
|
|
19267
20084
|
}
|
|
19268
20085
|
inspectionResults.push(inspectionResult);
|
|
20086
|
+
await options.harness.emitProgress?.({
|
|
20087
|
+
phase: "inspection",
|
|
20088
|
+
status: "passed",
|
|
20089
|
+
scenarioId: scenario.id,
|
|
20090
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20091
|
+
title: "Step inspection passed",
|
|
20092
|
+
message: inspectionText.slice(0, 800),
|
|
20093
|
+
data: inspectionResult
|
|
20094
|
+
});
|
|
19269
20095
|
}
|
|
19270
20096
|
for (const check of stepChecks) {
|
|
20097
|
+
await options.harness.emitProgress?.({
|
|
20098
|
+
phase: "check",
|
|
20099
|
+
status: "running",
|
|
20100
|
+
scenarioId: scenario.id,
|
|
20101
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20102
|
+
title: "Running custom check"
|
|
20103
|
+
});
|
|
19271
20104
|
await check(context);
|
|
20105
|
+
await options.harness.emitProgress?.({
|
|
20106
|
+
phase: "check",
|
|
20107
|
+
status: "passed",
|
|
20108
|
+
scenarioId: scenario.id,
|
|
20109
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20110
|
+
title: "Custom check passed"
|
|
20111
|
+
});
|
|
19272
20112
|
}
|
|
19273
20113
|
stepResults.push({
|
|
19274
20114
|
id: step.id || `step-${index + 1}`,
|
|
@@ -19279,6 +20119,7 @@ async function runAgentEvalSuite(options) {
|
|
|
19279
20119
|
actionSummary: completed.actionSummary,
|
|
19280
20120
|
promptInteractions: completed.promptInteractions,
|
|
19281
20121
|
inspectionResults,
|
|
20122
|
+
assertions,
|
|
19282
20123
|
turnDir: completed.turnDir
|
|
19283
20124
|
});
|
|
19284
20125
|
}
|
|
@@ -19297,6 +20138,7 @@ async function runAgentEvalSuite(options) {
|
|
|
19297
20138
|
actionSummary: lastStep.actionSummary,
|
|
19298
20139
|
promptInteractions: lastStep.promptInteractions,
|
|
19299
20140
|
verification: lastStep.inspectionResults.length <= 1 ? lastStep.inspectionResults[0] ?? null : lastStep.inspectionResults,
|
|
20141
|
+
assertions: stepResults.flatMap((step) => step.assertions || []),
|
|
19300
20142
|
tokenUsage: aggregateConversationTokenUsage(conversation),
|
|
19301
20143
|
steps: stepResults,
|
|
19302
20144
|
turnDir: conversation.artifactDir
|
|
@@ -19318,6 +20160,14 @@ async function runAgentEvalSuite(options) {
|
|
|
19318
20160
|
conversation,
|
|
19319
20161
|
result
|
|
19320
20162
|
});
|
|
20163
|
+
await options.harness.emitProgress?.({
|
|
20164
|
+
phase: "scenario",
|
|
20165
|
+
status: "passed",
|
|
20166
|
+
scenarioId: scenario.id,
|
|
20167
|
+
title: "Scenario passed",
|
|
20168
|
+
message: `${result.assertions?.filter((assertion) => assertion.status === "passed").length || 0}/${result.assertions?.length || 0} assertions`,
|
|
20169
|
+
data: result
|
|
20170
|
+
});
|
|
19321
20171
|
finalResult = result;
|
|
19322
20172
|
} catch (error) {
|
|
19323
20173
|
const failureMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -19358,6 +20208,14 @@ async function runAgentEvalSuite(options) {
|
|
|
19358
20208
|
result: failed,
|
|
19359
20209
|
error: failureMessage
|
|
19360
20210
|
});
|
|
20211
|
+
await options.harness.emitProgress?.({
|
|
20212
|
+
phase: "scenario",
|
|
20213
|
+
status: "failed",
|
|
20214
|
+
scenarioId: scenario.id,
|
|
20215
|
+
title: "Scenario failed",
|
|
20216
|
+
message: failureMessage,
|
|
20217
|
+
data: failed
|
|
20218
|
+
});
|
|
19361
20219
|
finalResult = failed;
|
|
19362
20220
|
} finally {
|
|
19363
20221
|
await options.harness.closeConversation(conversation);
|
|
@@ -19406,6 +20264,11 @@ function createAgentEvalHarness(options) {
|
|
|
19406
20264
|
const chatTimeoutMs = options.chatTimeoutMs ?? 12e4;
|
|
19407
20265
|
const jobTimeoutMs = options.jobTimeoutMs ?? 9e4;
|
|
19408
20266
|
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
20267
|
+
const resolvedTemplate = resolveHarnessTemplate(
|
|
20268
|
+
options.harnessTemplateId || process.env.GRANULAR_AGENT_HARNESS_TEMPLATE || "stable");
|
|
20269
|
+
const promptRenderer = options.promptRenderer || resolvedTemplate.renderPrompt;
|
|
20270
|
+
const continuationRenderer = options.continuationRenderer || resolvedTemplate.renderContinuation;
|
|
20271
|
+
const onProgress = options.onProgress;
|
|
19409
20272
|
async function openConversation(label) {
|
|
19410
20273
|
await ensureDir(artifactDir);
|
|
19411
20274
|
const clientId = `${slugify(label)}-${Date.now()}`;
|
|
@@ -19474,6 +20337,13 @@ function createAgentEvalHarness(options) {
|
|
|
19474
20337
|
};
|
|
19475
20338
|
}
|
|
19476
20339
|
async function runInspection(conversation, inspection, completed, turnDir) {
|
|
20340
|
+
await emitProgress(onProgress, {
|
|
20341
|
+
phase: "inspection",
|
|
20342
|
+
status: "running",
|
|
20343
|
+
scenarioId: conversation.label,
|
|
20344
|
+
title: "Running inspection",
|
|
20345
|
+
message: inspection.code.slice(0, 500)
|
|
20346
|
+
});
|
|
19477
20347
|
let result = null;
|
|
19478
20348
|
let lastError = null;
|
|
19479
20349
|
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
@@ -19501,6 +20371,14 @@ function createAgentEvalHarness(options) {
|
|
|
19501
20371
|
});
|
|
19502
20372
|
}
|
|
19503
20373
|
await writeJson(path__default.default.join(turnDir, "verification.json"), result);
|
|
20374
|
+
await emitProgress(onProgress, {
|
|
20375
|
+
phase: "inspection",
|
|
20376
|
+
status: "passed",
|
|
20377
|
+
scenarioId: conversation.label,
|
|
20378
|
+
title: "Inspection passed",
|
|
20379
|
+
message: JSON.stringify(result)?.slice(0, 800),
|
|
20380
|
+
data: result
|
|
20381
|
+
});
|
|
19504
20382
|
return result;
|
|
19505
20383
|
}
|
|
19506
20384
|
async function resumePendingTurn(pending, responder) {
|
|
@@ -19510,6 +20388,16 @@ function createAgentEvalHarness(options) {
|
|
|
19510
20388
|
prompt,
|
|
19511
20389
|
history: pending.promptInteractions
|
|
19512
20390
|
});
|
|
20391
|
+
await emitProgress(onProgress, {
|
|
20392
|
+
phase: "interaction",
|
|
20393
|
+
status: "running",
|
|
20394
|
+
scenarioId: pending.conversation.label,
|
|
20395
|
+
stepId: path__default.default.basename(pending.turnDir),
|
|
20396
|
+
jobId: pending.job.id,
|
|
20397
|
+
title: "Prompt answered",
|
|
20398
|
+
message: `${prompt.type}: ${prompt.message || prompt.title} -> ${JSON.stringify(answer)}`,
|
|
20399
|
+
data: { prompt, answer }
|
|
20400
|
+
});
|
|
19513
20401
|
const session = pending.conversation.environment;
|
|
19514
20402
|
await session.answerPrompt(prompt.id, answer);
|
|
19515
20403
|
pending.promptInteractions.push({
|
|
@@ -19529,7 +20417,12 @@ function createAgentEvalHarness(options) {
|
|
|
19529
20417
|
job: pending.job,
|
|
19530
20418
|
boundaryTimestamp: pending.boundaryTimestamp,
|
|
19531
20419
|
timeoutMs: jobTimeoutMs,
|
|
19532
|
-
pollIntervalMs
|
|
20420
|
+
pollIntervalMs,
|
|
20421
|
+
onProgress: (event) => void onProgress?.(event),
|
|
20422
|
+
progressContext: {
|
|
20423
|
+
scenarioId: pending.conversation.label,
|
|
20424
|
+
stepId: path__default.default.basename(pending.turnDir)
|
|
20425
|
+
}
|
|
19533
20426
|
});
|
|
19534
20427
|
if (resumed.kind === "prompt") {
|
|
19535
20428
|
return {
|
|
@@ -19610,12 +20503,44 @@ function createAgentEvalHarness(options) {
|
|
|
19610
20503
|
};
|
|
19611
20504
|
conversation.logTurns.push(turnLog);
|
|
19612
20505
|
if (input.prepareRecords?.length) {
|
|
20506
|
+
await emitProgress(onProgress, {
|
|
20507
|
+
phase: "setup",
|
|
20508
|
+
status: "running",
|
|
20509
|
+
scenarioId: conversation.label,
|
|
20510
|
+
stepId: turnId,
|
|
20511
|
+
title: "Recording setup records",
|
|
20512
|
+
message: `${input.prepareRecords.length} records`,
|
|
20513
|
+
data: input.prepareRecords
|
|
20514
|
+
});
|
|
19613
20515
|
await conversation.environment.recordObjects(input.prepareRecords);
|
|
20516
|
+
await emitProgress(onProgress, {
|
|
20517
|
+
phase: "setup",
|
|
20518
|
+
status: "passed",
|
|
20519
|
+
scenarioId: conversation.label,
|
|
20520
|
+
stepId: turnId,
|
|
20521
|
+
title: "Setup records recorded",
|
|
20522
|
+
message: `${input.prepareRecords.length} records`
|
|
20523
|
+
});
|
|
19614
20524
|
}
|
|
19615
20525
|
if (input.prepareTools?.length) {
|
|
20526
|
+
await emitProgress(onProgress, {
|
|
20527
|
+
phase: "setup",
|
|
20528
|
+
status: "running",
|
|
20529
|
+
scenarioId: conversation.label,
|
|
20530
|
+
stepId: turnId,
|
|
20531
|
+
title: "Registering effect handlers",
|
|
20532
|
+
message: `${input.prepareTools.length} handlers`
|
|
20533
|
+
});
|
|
19616
20534
|
await options.granular.ontology(conversation.environment.sandboxId).effects.registerMany(input.prepareTools);
|
|
19617
20535
|
}
|
|
19618
20536
|
if (input.prepare) {
|
|
20537
|
+
await emitProgress(onProgress, {
|
|
20538
|
+
phase: "setup",
|
|
20539
|
+
status: "running",
|
|
20540
|
+
scenarioId: conversation.label,
|
|
20541
|
+
stepId: turnId,
|
|
20542
|
+
title: "Running custom setup"
|
|
20543
|
+
});
|
|
19619
20544
|
await input.prepare({
|
|
19620
20545
|
conversation,
|
|
19621
20546
|
environment: conversation.environment,
|
|
@@ -19624,6 +20549,14 @@ function createAgentEvalHarness(options) {
|
|
|
19624
20549
|
}
|
|
19625
20550
|
const boundaryTimestamp = Date.now();
|
|
19626
20551
|
conversation.history.push({ role: "user", content: input.request });
|
|
20552
|
+
await emitProgress(onProgress, {
|
|
20553
|
+
phase: "step",
|
|
20554
|
+
status: "running",
|
|
20555
|
+
scenarioId: conversation.label,
|
|
20556
|
+
stepId: turnId,
|
|
20557
|
+
title: "User request",
|
|
20558
|
+
message: input.request
|
|
20559
|
+
});
|
|
19627
20560
|
await writeJson(path__default.default.join(turnDir, "request.json"), {
|
|
19628
20561
|
request: input.request,
|
|
19629
20562
|
boundaryTimestamp
|
|
@@ -19665,7 +20598,7 @@ function createAgentEvalHarness(options) {
|
|
|
19665
20598
|
inputSchema: tool.inputSchema,
|
|
19666
20599
|
outputSchema: tool.outputSchema
|
|
19667
20600
|
}));
|
|
19668
|
-
const
|
|
20601
|
+
const renderedPrompt = promptRenderer({
|
|
19669
20602
|
domainDocumentation: await conversation.environment.getDomainDocumentation(),
|
|
19670
20603
|
sessionContext: {
|
|
19671
20604
|
sandboxId: conversation.environment.sandboxId,
|
|
@@ -19686,9 +20619,39 @@ function createAgentEvalHarness(options) {
|
|
|
19686
20619
|
tools,
|
|
19687
20620
|
checkpoint: latestCheckpoint
|
|
19688
20621
|
});
|
|
19689
|
-
const
|
|
20622
|
+
const systemPrompt = renderedPrompt.prompt;
|
|
20623
|
+
await emitProgress(onProgress, {
|
|
20624
|
+
phase: "prompt",
|
|
20625
|
+
status: "passed",
|
|
20626
|
+
scenarioId: conversation.label,
|
|
20627
|
+
stepId: turnId,
|
|
20628
|
+
iteration: iteration + 1,
|
|
20629
|
+
templateId: renderedPrompt.templateId,
|
|
20630
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20631
|
+
title: "Rendered harness prompt",
|
|
20632
|
+
message: `${systemPrompt.split("\n").length} lines`,
|
|
20633
|
+
data: {
|
|
20634
|
+
templateId: renderedPrompt.templateId,
|
|
20635
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20636
|
+
templateHash: renderedPrompt.templateHash,
|
|
20637
|
+
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
20638
|
+
prompt: systemPrompt
|
|
20639
|
+
}
|
|
20640
|
+
});
|
|
20641
|
+
const request = iteration === 0 ? input.request : continuationRenderer(
|
|
19690
20642
|
buildContinuationPreview(latestCheckpoint, noProgressCount)
|
|
19691
|
-
);
|
|
20643
|
+
).instruction;
|
|
20644
|
+
await emitProgress(onProgress, {
|
|
20645
|
+
phase: "generation",
|
|
20646
|
+
status: "running",
|
|
20647
|
+
scenarioId: conversation.label,
|
|
20648
|
+
stepId: turnId,
|
|
20649
|
+
iteration: iteration + 1,
|
|
20650
|
+
templateId: renderedPrompt.templateId,
|
|
20651
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20652
|
+
title: iteration === 0 ? "Generating agent response" : "Generating continuation",
|
|
20653
|
+
message: request
|
|
20654
|
+
});
|
|
19692
20655
|
const generation = await withTimeout2(
|
|
19693
20656
|
generateTurnWithRepair(options.generator, {
|
|
19694
20657
|
systemPrompt,
|
|
@@ -19707,10 +20670,31 @@ function createAgentEvalHarness(options) {
|
|
|
19707
20670
|
chatTimeoutMs,
|
|
19708
20671
|
`chat generation for ${conversation.label} iteration ${iteration + 1}`
|
|
19709
20672
|
);
|
|
20673
|
+
await emitProgress(onProgress, {
|
|
20674
|
+
phase: "generation",
|
|
20675
|
+
status: "passed",
|
|
20676
|
+
scenarioId: conversation.label,
|
|
20677
|
+
stepId: turnId,
|
|
20678
|
+
iteration: iteration + 1,
|
|
20679
|
+
templateId: renderedPrompt.templateId,
|
|
20680
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20681
|
+
title: generation.code ? "Generated job code" : "Generated text reply",
|
|
20682
|
+
message: generation.code || generation.reply || "",
|
|
20683
|
+
data: {
|
|
20684
|
+
reply: generation.reply,
|
|
20685
|
+
code: generation.code,
|
|
20686
|
+
attempts: generation.generationAttempts,
|
|
20687
|
+
usage: tokenUsageForGenerationOutput(generation)
|
|
20688
|
+
}
|
|
20689
|
+
});
|
|
19710
20690
|
const iterationLog = {
|
|
19711
20691
|
iteration: iteration + 1,
|
|
19712
20692
|
request,
|
|
19713
20693
|
systemPrompt,
|
|
20694
|
+
templateId: renderedPrompt.templateId,
|
|
20695
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20696
|
+
templateHash: renderedPrompt.templateHash,
|
|
20697
|
+
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
19714
20698
|
generationReply: generation.reply,
|
|
19715
20699
|
generatedCode: generation.code,
|
|
19716
20700
|
rawGeneration: generation.raw,
|
|
@@ -19757,6 +20741,15 @@ function createAgentEvalHarness(options) {
|
|
|
19757
20741
|
result: completed.result
|
|
19758
20742
|
};
|
|
19759
20743
|
await writeJson(path__default.default.join(turnDir, "result.json"), completed);
|
|
20744
|
+
await emitProgress(onProgress, {
|
|
20745
|
+
phase: "step",
|
|
20746
|
+
status: "passed",
|
|
20747
|
+
scenarioId: conversation.label,
|
|
20748
|
+
stepId: turnId,
|
|
20749
|
+
title: "Step completed with text reply",
|
|
20750
|
+
message: responseText2,
|
|
20751
|
+
data: completed
|
|
20752
|
+
});
|
|
19760
20753
|
return completed;
|
|
19761
20754
|
}
|
|
19762
20755
|
const session = conversation.environment;
|
|
@@ -19777,12 +20770,33 @@ function createAgentEvalHarness(options) {
|
|
|
19777
20770
|
)
|
|
19778
20771
|
}
|
|
19779
20772
|
});
|
|
20773
|
+
await emitProgress(onProgress, {
|
|
20774
|
+
phase: "job",
|
|
20775
|
+
status: "running",
|
|
20776
|
+
scenarioId: conversation.label,
|
|
20777
|
+
stepId: turnId,
|
|
20778
|
+
iteration: iteration + 1,
|
|
20779
|
+
jobId: job.id,
|
|
20780
|
+
templateId: renderedPrompt.templateId,
|
|
20781
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20782
|
+
title: "Submitted Granular job",
|
|
20783
|
+
message: job.id,
|
|
20784
|
+
data: { code: generation.code }
|
|
20785
|
+
});
|
|
19780
20786
|
const outcome = await waitForJobOutcome({
|
|
19781
20787
|
environment: conversation.environment,
|
|
19782
20788
|
job,
|
|
19783
20789
|
boundaryTimestamp,
|
|
19784
20790
|
timeoutMs: jobTimeoutMs,
|
|
19785
|
-
pollIntervalMs
|
|
20791
|
+
pollIntervalMs,
|
|
20792
|
+
onProgress: (event) => void onProgress?.(event),
|
|
20793
|
+
progressContext: {
|
|
20794
|
+
scenarioId: conversation.label,
|
|
20795
|
+
stepId: turnId,
|
|
20796
|
+
iteration: iteration + 1,
|
|
20797
|
+
templateId: renderedPrompt.templateId,
|
|
20798
|
+
templateVersion: renderedPrompt.templateVersion
|
|
20799
|
+
}
|
|
19786
20800
|
});
|
|
19787
20801
|
if (outcome.kind === "prompt") {
|
|
19788
20802
|
if (!autoAnswerPrompts) {
|
|
@@ -19892,6 +20906,23 @@ function createAgentEvalHarness(options) {
|
|
|
19892
20906
|
controllerReason: continuation.reason,
|
|
19893
20907
|
noProgressCount: continuation.nextNoProgressCount
|
|
19894
20908
|
};
|
|
20909
|
+
await emitProgress(onProgress, {
|
|
20910
|
+
phase: "continuation",
|
|
20911
|
+
status: continuation.shouldContinue ? "running" : "passed",
|
|
20912
|
+
scenarioId: conversation.label,
|
|
20913
|
+
stepId: turnId,
|
|
20914
|
+
iteration: iteration + 1,
|
|
20915
|
+
jobId: job.id,
|
|
20916
|
+
templateId: renderedPrompt.templateId,
|
|
20917
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20918
|
+
title: continuation.shouldContinue ? "Harness requested another loop" : "Harness accepted completion",
|
|
20919
|
+
message: `${continuation.reason}; ${continuation.outcome}`,
|
|
20920
|
+
data: {
|
|
20921
|
+
continuation,
|
|
20922
|
+
checkpoint: latestCheckpoint,
|
|
20923
|
+
verifierSnapshot
|
|
20924
|
+
}
|
|
20925
|
+
});
|
|
19895
20926
|
previousSnapshot = verifierSnapshot;
|
|
19896
20927
|
noProgressCount = continuation.nextNoProgressCount;
|
|
19897
20928
|
conversation.history.push({
|
|
@@ -19945,6 +20976,17 @@ function createAgentEvalHarness(options) {
|
|
|
19945
20976
|
result: outcome.result
|
|
19946
20977
|
};
|
|
19947
20978
|
await writeJson(path__default.default.join(turnDir, "result.json"), completed);
|
|
20979
|
+
await emitProgress(onProgress, {
|
|
20980
|
+
phase: "step",
|
|
20981
|
+
status: "passed",
|
|
20982
|
+
scenarioId: conversation.label,
|
|
20983
|
+
stepId: turnId,
|
|
20984
|
+
iteration: iteration + 1,
|
|
20985
|
+
jobId: job.id,
|
|
20986
|
+
title: "Step completed",
|
|
20987
|
+
message: responseText,
|
|
20988
|
+
data: completed
|
|
20989
|
+
});
|
|
19948
20990
|
return completed;
|
|
19949
20991
|
}
|
|
19950
20992
|
iteration += 1;
|
|
@@ -19956,6 +20998,7 @@ function createAgentEvalHarness(options) {
|
|
|
19956
20998
|
return {
|
|
19957
20999
|
artifactDir,
|
|
19958
21000
|
granular: options.granular,
|
|
21001
|
+
emitProgress: (event) => emitProgress(onProgress, event),
|
|
19959
21002
|
openConversation,
|
|
19960
21003
|
closeConversation,
|
|
19961
21004
|
runTurn,
|
|
@@ -20021,7 +21064,11 @@ function createAgentTester(options) {
|
|
|
20021
21064
|
controllerBudgets: options.controllerBudgets,
|
|
20022
21065
|
chatTimeoutMs: options.chatTimeoutMs,
|
|
20023
21066
|
jobTimeoutMs: options.jobTimeoutMs,
|
|
20024
|
-
pollIntervalMs: options.pollIntervalMs
|
|
21067
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
21068
|
+
harnessTemplateId: options.harnessTemplateId,
|
|
21069
|
+
promptRenderer: options.promptRenderer,
|
|
21070
|
+
continuationRenderer: options.continuationRenderer,
|
|
21071
|
+
onProgress: options.onProgress
|
|
20025
21072
|
});
|
|
20026
21073
|
return {
|
|
20027
21074
|
...harness,
|
|
@@ -20056,7 +21103,9 @@ exports.createScriptedPromptResponder = createScriptedPromptResponder;
|
|
|
20056
21103
|
exports.createTestArtifactsDirectory = createTestArtifactsDirectory;
|
|
20057
21104
|
exports.createTimestampedArtifactDirectory = createTimestampedArtifactDirectory;
|
|
20058
21105
|
exports.generateTurnWithRepair = generateTurnWithRepair;
|
|
21106
|
+
exports.loadAgentEvalScenarioFile = loadAgentEvalScenarioFile;
|
|
20059
21107
|
exports.runAgentEvalSuite = runAgentEvalSuite;
|
|
20060
21108
|
exports.runAgentTests = runAgentTests;
|
|
21109
|
+
exports.scenariosFromAgentEvalFile = scenariosFromAgentEvalFile;
|
|
20061
21110
|
//# sourceMappingURL=agent-evals.js.map
|
|
20062
21111
|
//# sourceMappingURL=agent-evals.js.map
|