@granular-software/sdk 0.4.41 → 0.4.43
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 +1197 -79
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +1197 -81
- 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 +597 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +589 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/agent-evals.js
CHANGED
|
@@ -188,9 +188,9 @@ var require_node_gyp_build = __commonJS({
|
|
|
188
188
|
}
|
|
189
189
|
function parseTags(file) {
|
|
190
190
|
var arr = file.split(".");
|
|
191
|
-
var
|
|
191
|
+
var extension2 = arr.pop();
|
|
192
192
|
var tags = { file, specificity: 0 };
|
|
193
|
-
if (
|
|
193
|
+
if (extension2 !== "node") return;
|
|
194
194
|
for (var i = 0; i < arr.length; i++) {
|
|
195
195
|
var tag = arr[i];
|
|
196
196
|
if (tag === "node" || tag === "electron" || tag === "node-webkit") {
|
|
@@ -438,7 +438,7 @@ var require_permessage_deflate = __commonJS({
|
|
|
438
438
|
var kBuffers = Symbol("buffers");
|
|
439
439
|
var kError = Symbol("error");
|
|
440
440
|
var zlibLimiter;
|
|
441
|
-
var
|
|
441
|
+
var PerMessageDeflate2 = class {
|
|
442
442
|
/**
|
|
443
443
|
* Creates a PerMessageDeflate instance.
|
|
444
444
|
*
|
|
@@ -449,6 +449,9 @@ var require_permessage_deflate = __commonJS({
|
|
|
449
449
|
* acknowledge disabling of client context takeover
|
|
450
450
|
* @param {Number} [options.concurrencyLimit=10] The number of concurrent
|
|
451
451
|
* calls to zlib
|
|
452
|
+
* @param {Boolean} [options.isServer=false] Create the instance in either
|
|
453
|
+
* server or client mode
|
|
454
|
+
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
452
455
|
* @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
|
|
453
456
|
* use of a custom server window size
|
|
454
457
|
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
|
|
@@ -459,15 +462,12 @@ var require_permessage_deflate = __commonJS({
|
|
|
459
462
|
* deflate
|
|
460
463
|
* @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
|
|
461
464
|
* inflate
|
|
462
|
-
* @param {Boolean} [isServer=false] Create the instance in either server or
|
|
463
|
-
* client mode
|
|
464
|
-
* @param {Number} [maxPayload=0] The maximum allowed message length
|
|
465
465
|
*/
|
|
466
|
-
constructor(options
|
|
467
|
-
this._maxPayload = maxPayload | 0;
|
|
466
|
+
constructor(options) {
|
|
468
467
|
this._options = options || {};
|
|
469
468
|
this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024;
|
|
470
|
-
this.
|
|
469
|
+
this._maxPayload = this._options.maxPayload | 0;
|
|
470
|
+
this._isServer = !!this._options.isServer;
|
|
471
471
|
this._deflate = null;
|
|
472
472
|
this._inflate = null;
|
|
473
473
|
this.params = null;
|
|
@@ -776,7 +776,7 @@ var require_permessage_deflate = __commonJS({
|
|
|
776
776
|
});
|
|
777
777
|
}
|
|
778
778
|
};
|
|
779
|
-
module.exports =
|
|
779
|
+
module.exports = PerMessageDeflate2;
|
|
780
780
|
function deflateOnData(chunk) {
|
|
781
781
|
this[kBuffers].push(chunk);
|
|
782
782
|
this[kTotalLength] += chunk.length;
|
|
@@ -1056,7 +1056,7 @@ var require_validation = __commonJS({
|
|
|
1056
1056
|
var require_receiver = __commonJS({
|
|
1057
1057
|
"../../node_modules/ws/lib/receiver.js"(exports, module) {
|
|
1058
1058
|
var { Writable } = __require("stream");
|
|
1059
|
-
var
|
|
1059
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
1060
1060
|
var {
|
|
1061
1061
|
BINARY_TYPES,
|
|
1062
1062
|
EMPTY_BUFFER,
|
|
@@ -1086,6 +1086,10 @@ var require_receiver = __commonJS({
|
|
|
1086
1086
|
* extensions
|
|
1087
1087
|
* @param {Boolean} [options.isServer=false] Specifies whether to operate in
|
|
1088
1088
|
* client or server mode
|
|
1089
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
1090
|
+
* buffered data chunks
|
|
1091
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
1092
|
+
* fragments
|
|
1089
1093
|
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
1090
1094
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
1091
1095
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -1096,6 +1100,8 @@ var require_receiver = __commonJS({
|
|
|
1096
1100
|
this._binaryType = options.binaryType || BINARY_TYPES[0];
|
|
1097
1101
|
this._extensions = options.extensions || {};
|
|
1098
1102
|
this._isServer = !!options.isServer;
|
|
1103
|
+
this._maxBufferedChunks = options.maxBufferedChunks | 0;
|
|
1104
|
+
this._maxFragments = options.maxFragments | 0;
|
|
1099
1105
|
this._maxPayload = options.maxPayload | 0;
|
|
1100
1106
|
this._skipUTF8Validation = !!options.skipUTF8Validation;
|
|
1101
1107
|
this[kWebSocket] = void 0;
|
|
@@ -1125,6 +1131,18 @@ var require_receiver = __commonJS({
|
|
|
1125
1131
|
*/
|
|
1126
1132
|
_write(chunk, encoding, cb) {
|
|
1127
1133
|
if (this._opcode === 8 && this._state == GET_INFO) return cb();
|
|
1134
|
+
if (this._maxBufferedChunks > 0 && this._buffers.length >= this._maxBufferedChunks) {
|
|
1135
|
+
cb(
|
|
1136
|
+
this.createError(
|
|
1137
|
+
RangeError,
|
|
1138
|
+
"Too many buffered chunks",
|
|
1139
|
+
false,
|
|
1140
|
+
1008,
|
|
1141
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
1142
|
+
)
|
|
1143
|
+
);
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1128
1146
|
this._bufferedBytes += chunk.length;
|
|
1129
1147
|
this._buffers.push(chunk);
|
|
1130
1148
|
this.startLoop(cb);
|
|
@@ -1223,7 +1241,7 @@ var require_receiver = __commonJS({
|
|
|
1223
1241
|
return;
|
|
1224
1242
|
}
|
|
1225
1243
|
const compressed = (buf[0] & 64) === 64;
|
|
1226
|
-
if (compressed && !this._extensions[
|
|
1244
|
+
if (compressed && !this._extensions[PerMessageDeflate2.extensionName]) {
|
|
1227
1245
|
const error = this.createError(
|
|
1228
1246
|
RangeError,
|
|
1229
1247
|
"RSV1 must be clear",
|
|
@@ -1454,6 +1472,17 @@ var require_receiver = __commonJS({
|
|
|
1454
1472
|
return;
|
|
1455
1473
|
}
|
|
1456
1474
|
if (data.length) {
|
|
1475
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
1476
|
+
const error = this.createError(
|
|
1477
|
+
RangeError,
|
|
1478
|
+
"Too many message fragments",
|
|
1479
|
+
false,
|
|
1480
|
+
1008,
|
|
1481
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
1482
|
+
);
|
|
1483
|
+
cb(error);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1457
1486
|
this._messageLength = this._totalPayloadLength;
|
|
1458
1487
|
this._fragments.push(data);
|
|
1459
1488
|
}
|
|
@@ -1467,7 +1496,7 @@ var require_receiver = __commonJS({
|
|
|
1467
1496
|
* @private
|
|
1468
1497
|
*/
|
|
1469
1498
|
decompress(data, cb) {
|
|
1470
|
-
const perMessageDeflate = this._extensions[
|
|
1499
|
+
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
1471
1500
|
perMessageDeflate.decompress(data, this._fin, (err, buf) => {
|
|
1472
1501
|
if (err) return cb(err);
|
|
1473
1502
|
if (buf.length) {
|
|
@@ -1483,6 +1512,17 @@ var require_receiver = __commonJS({
|
|
|
1483
1512
|
cb(error);
|
|
1484
1513
|
return;
|
|
1485
1514
|
}
|
|
1515
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
1516
|
+
const error = this.createError(
|
|
1517
|
+
RangeError,
|
|
1518
|
+
"Too many message fragments",
|
|
1519
|
+
false,
|
|
1520
|
+
1008,
|
|
1521
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
1522
|
+
);
|
|
1523
|
+
cb(error);
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1486
1526
|
this._fragments.push(buf);
|
|
1487
1527
|
}
|
|
1488
1528
|
this.dataMessage(cb);
|
|
@@ -1648,7 +1688,10 @@ var require_sender = __commonJS({
|
|
|
1648
1688
|
"../../node_modules/ws/lib/sender.js"(exports, module) {
|
|
1649
1689
|
var { Duplex } = __require("stream");
|
|
1650
1690
|
var { randomFillSync } = __require("crypto");
|
|
1651
|
-
var
|
|
1691
|
+
var {
|
|
1692
|
+
types: { isUint8Array }
|
|
1693
|
+
} = __require("util");
|
|
1694
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
1652
1695
|
var { EMPTY_BUFFER, kWebSocket, NOOP } = require_constants();
|
|
1653
1696
|
var { isBlob, isValidStatusCode } = require_validation();
|
|
1654
1697
|
var { mask: applyMask, toBuffer } = require_buffer_util();
|
|
@@ -1801,8 +1844,10 @@ var require_sender = __commonJS({
|
|
|
1801
1844
|
buf.writeUInt16BE(code, 0);
|
|
1802
1845
|
if (typeof data === "string") {
|
|
1803
1846
|
buf.write(data, 2);
|
|
1804
|
-
} else {
|
|
1847
|
+
} else if (isUint8Array(data)) {
|
|
1805
1848
|
buf.set(data, 2);
|
|
1849
|
+
} else {
|
|
1850
|
+
throw new TypeError("Second argument must be a string or a Uint8Array");
|
|
1806
1851
|
}
|
|
1807
1852
|
}
|
|
1808
1853
|
const options = {
|
|
@@ -1932,7 +1977,7 @@ var require_sender = __commonJS({
|
|
|
1932
1977
|
* @public
|
|
1933
1978
|
*/
|
|
1934
1979
|
send(data, options, cb) {
|
|
1935
|
-
const perMessageDeflate = this._extensions[
|
|
1980
|
+
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
1936
1981
|
let opcode = options.binary ? 2 : 1;
|
|
1937
1982
|
let rsv1 = options.compress;
|
|
1938
1983
|
let byteLength;
|
|
@@ -2056,7 +2101,7 @@ var require_sender = __commonJS({
|
|
|
2056
2101
|
this.sendFrame(_Sender.frame(data, options), cb);
|
|
2057
2102
|
return;
|
|
2058
2103
|
}
|
|
2059
|
-
const perMessageDeflate = this._extensions[
|
|
2104
|
+
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
2060
2105
|
this._bufferedBytes += options[kByteLength];
|
|
2061
2106
|
this._state = DEFLATING;
|
|
2062
2107
|
perMessageDeflate.compress(data, options.fin, (_, buf) => {
|
|
@@ -2492,11 +2537,11 @@ var require_extension = __commonJS({
|
|
|
2492
2537
|
return offers;
|
|
2493
2538
|
}
|
|
2494
2539
|
function format(extensions) {
|
|
2495
|
-
return Object.keys(extensions).map((
|
|
2496
|
-
let configurations = extensions[
|
|
2540
|
+
return Object.keys(extensions).map((extension2) => {
|
|
2541
|
+
let configurations = extensions[extension2];
|
|
2497
2542
|
if (!Array.isArray(configurations)) configurations = [configurations];
|
|
2498
2543
|
return configurations.map((params) => {
|
|
2499
|
-
return [
|
|
2544
|
+
return [extension2].concat(
|
|
2500
2545
|
Object.keys(params).map((k) => {
|
|
2501
2546
|
let values = params[k];
|
|
2502
2547
|
if (!Array.isArray(values)) values = [values];
|
|
@@ -2521,7 +2566,7 @@ var require_websocket = __commonJS({
|
|
|
2521
2566
|
var { randomBytes, createHash } = __require("crypto");
|
|
2522
2567
|
var { Duplex, Readable } = __require("stream");
|
|
2523
2568
|
var { URL: URL2 } = __require("url");
|
|
2524
|
-
var
|
|
2569
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
2525
2570
|
var Receiver2 = require_receiver();
|
|
2526
2571
|
var Sender2 = require_sender();
|
|
2527
2572
|
var { isBlob } = require_validation();
|
|
@@ -2680,6 +2725,10 @@ var require_websocket = __commonJS({
|
|
|
2680
2725
|
* multiple times in the same tick
|
|
2681
2726
|
* @param {Function} [options.generateMask] The function used to generate the
|
|
2682
2727
|
* masking key
|
|
2728
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
2729
|
+
* buffered data chunks
|
|
2730
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
2731
|
+
* fragments
|
|
2683
2732
|
* @param {Number} [options.maxPayload=0] The maximum allowed message size
|
|
2684
2733
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
2685
2734
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -2691,6 +2740,8 @@ var require_websocket = __commonJS({
|
|
|
2691
2740
|
binaryType: this.binaryType,
|
|
2692
2741
|
extensions: this._extensions,
|
|
2693
2742
|
isServer: this._isServer,
|
|
2743
|
+
maxBufferedChunks: options.maxBufferedChunks,
|
|
2744
|
+
maxFragments: options.maxFragments,
|
|
2694
2745
|
maxPayload: options.maxPayload,
|
|
2695
2746
|
skipUTF8Validation: options.skipUTF8Validation
|
|
2696
2747
|
});
|
|
@@ -2729,8 +2780,8 @@ var require_websocket = __commonJS({
|
|
|
2729
2780
|
this.emit("close", this._closeCode, this._closeMessage);
|
|
2730
2781
|
return;
|
|
2731
2782
|
}
|
|
2732
|
-
if (this._extensions[
|
|
2733
|
-
this._extensions[
|
|
2783
|
+
if (this._extensions[PerMessageDeflate2.extensionName]) {
|
|
2784
|
+
this._extensions[PerMessageDeflate2.extensionName].cleanup();
|
|
2734
2785
|
}
|
|
2735
2786
|
this._receiver.removeAllListeners();
|
|
2736
2787
|
this._readyState = _WebSocket.CLOSED;
|
|
@@ -2892,7 +2943,7 @@ var require_websocket = __commonJS({
|
|
|
2892
2943
|
fin: true,
|
|
2893
2944
|
...options
|
|
2894
2945
|
};
|
|
2895
|
-
if (!this._extensions[
|
|
2946
|
+
if (!this._extensions[PerMessageDeflate2.extensionName]) {
|
|
2896
2947
|
opts.compress = false;
|
|
2897
2948
|
}
|
|
2898
2949
|
this._sender.send(data || EMPTY_BUFFER, opts, cb);
|
|
@@ -2990,6 +3041,8 @@ var require_websocket = __commonJS({
|
|
|
2990
3041
|
autoPong: true,
|
|
2991
3042
|
closeTimeout: CLOSE_TIMEOUT,
|
|
2992
3043
|
protocolVersion: protocolVersions[1],
|
|
3044
|
+
maxBufferedChunks: 1024 * 1024,
|
|
3045
|
+
maxFragments: 128 * 1024,
|
|
2993
3046
|
maxPayload: 100 * 1024 * 1024,
|
|
2994
3047
|
skipUTF8Validation: false,
|
|
2995
3048
|
perMessageDeflate: true,
|
|
@@ -3018,7 +3071,7 @@ var require_websocket = __commonJS({
|
|
|
3018
3071
|
} else {
|
|
3019
3072
|
try {
|
|
3020
3073
|
parsedUrl = new URL2(address);
|
|
3021
|
-
} catch
|
|
3074
|
+
} catch {
|
|
3022
3075
|
throw new SyntaxError(`Invalid URL: ${address}`);
|
|
3023
3076
|
}
|
|
3024
3077
|
}
|
|
@@ -3066,13 +3119,13 @@ var require_websocket = __commonJS({
|
|
|
3066
3119
|
opts.path = parsedUrl.pathname + parsedUrl.search;
|
|
3067
3120
|
opts.timeout = opts.handshakeTimeout;
|
|
3068
3121
|
if (opts.perMessageDeflate) {
|
|
3069
|
-
perMessageDeflate = new
|
|
3070
|
-
opts.perMessageDeflate
|
|
3071
|
-
false,
|
|
3072
|
-
opts.maxPayload
|
|
3073
|
-
);
|
|
3122
|
+
perMessageDeflate = new PerMessageDeflate2({
|
|
3123
|
+
...opts.perMessageDeflate,
|
|
3124
|
+
isServer: false,
|
|
3125
|
+
maxPayload: opts.maxPayload
|
|
3126
|
+
});
|
|
3074
3127
|
opts.headers["Sec-WebSocket-Extensions"] = format({
|
|
3075
|
-
[
|
|
3128
|
+
[PerMessageDeflate2.extensionName]: perMessageDeflate.offer()
|
|
3076
3129
|
});
|
|
3077
3130
|
}
|
|
3078
3131
|
if (protocols.length) {
|
|
@@ -3215,23 +3268,25 @@ var require_websocket = __commonJS({
|
|
|
3215
3268
|
return;
|
|
3216
3269
|
}
|
|
3217
3270
|
const extensionNames = Object.keys(extensions);
|
|
3218
|
-
if (extensionNames.length !== 1 || extensionNames[0] !==
|
|
3271
|
+
if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate2.extensionName) {
|
|
3219
3272
|
const message = "Server indicated an extension that was not requested";
|
|
3220
3273
|
abortHandshake(websocket, socket, message);
|
|
3221
3274
|
return;
|
|
3222
3275
|
}
|
|
3223
3276
|
try {
|
|
3224
|
-
perMessageDeflate.accept(extensions[
|
|
3277
|
+
perMessageDeflate.accept(extensions[PerMessageDeflate2.extensionName]);
|
|
3225
3278
|
} catch (err) {
|
|
3226
3279
|
const message = "Invalid Sec-WebSocket-Extensions header";
|
|
3227
3280
|
abortHandshake(websocket, socket, message);
|
|
3228
3281
|
return;
|
|
3229
3282
|
}
|
|
3230
|
-
websocket._extensions[
|
|
3283
|
+
websocket._extensions[PerMessageDeflate2.extensionName] = perMessageDeflate;
|
|
3231
3284
|
}
|
|
3232
3285
|
websocket.setSocket(socket, head, {
|
|
3233
3286
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
3234
3287
|
generateMask: opts.generateMask,
|
|
3288
|
+
maxBufferedChunks: opts.maxBufferedChunks,
|
|
3289
|
+
maxFragments: opts.maxFragments,
|
|
3235
3290
|
maxPayload: opts.maxPayload,
|
|
3236
3291
|
skipUTF8Validation: opts.skipUTF8Validation
|
|
3237
3292
|
});
|
|
@@ -3543,9 +3598,9 @@ var require_websocket_server = __commonJS({
|
|
|
3543
3598
|
var http = __require("http");
|
|
3544
3599
|
var { Duplex } = __require("stream");
|
|
3545
3600
|
var { createHash } = __require("crypto");
|
|
3546
|
-
var
|
|
3547
|
-
var
|
|
3548
|
-
var
|
|
3601
|
+
var extension2 = require_extension();
|
|
3602
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3603
|
+
var subprotocol2 = require_subprotocol();
|
|
3549
3604
|
var WebSocket2 = require_websocket();
|
|
3550
3605
|
var { CLOSE_TIMEOUT, GUID, kWebSocket } = require_constants();
|
|
3551
3606
|
var keyRegex = /^[+/0-9A-Za-z]{22}==$/;
|
|
@@ -3571,6 +3626,10 @@ var require_websocket_server = __commonJS({
|
|
|
3571
3626
|
* called
|
|
3572
3627
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
3573
3628
|
* @param {String} [options.host] The hostname where to bind the server
|
|
3629
|
+
* @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
|
|
3630
|
+
* buffered data chunks
|
|
3631
|
+
* @param {Number} [options.maxFragments=131072] The maximum number of message
|
|
3632
|
+
* fragments
|
|
3574
3633
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
3575
3634
|
* size
|
|
3576
3635
|
* @param {Boolean} [options.noServer=false] Enable no server mode
|
|
@@ -3592,6 +3651,8 @@ var require_websocket_server = __commonJS({
|
|
|
3592
3651
|
options = {
|
|
3593
3652
|
allowSynchronousEvents: true,
|
|
3594
3653
|
autoPong: true,
|
|
3654
|
+
maxBufferedChunks: 1024 * 1024,
|
|
3655
|
+
maxFragments: 128 * 1024,
|
|
3595
3656
|
maxPayload: 100 * 1024 * 1024,
|
|
3596
3657
|
skipUTF8Validation: false,
|
|
3597
3658
|
perMessageDeflate: false,
|
|
@@ -3768,7 +3829,7 @@ var require_websocket_server = __commonJS({
|
|
|
3768
3829
|
let protocols = /* @__PURE__ */ new Set();
|
|
3769
3830
|
if (secWebSocketProtocol !== void 0) {
|
|
3770
3831
|
try {
|
|
3771
|
-
protocols =
|
|
3832
|
+
protocols = subprotocol2.parse(secWebSocketProtocol);
|
|
3772
3833
|
} catch (err) {
|
|
3773
3834
|
const message = "Invalid Sec-WebSocket-Protocol header";
|
|
3774
3835
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
@@ -3778,16 +3839,16 @@ var require_websocket_server = __commonJS({
|
|
|
3778
3839
|
const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
|
|
3779
3840
|
const extensions = {};
|
|
3780
3841
|
if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) {
|
|
3781
|
-
const perMessageDeflate = new
|
|
3782
|
-
this.options.perMessageDeflate,
|
|
3783
|
-
true,
|
|
3784
|
-
this.options.maxPayload
|
|
3785
|
-
);
|
|
3842
|
+
const perMessageDeflate = new PerMessageDeflate2({
|
|
3843
|
+
...this.options.perMessageDeflate,
|
|
3844
|
+
isServer: true,
|
|
3845
|
+
maxPayload: this.options.maxPayload
|
|
3846
|
+
});
|
|
3786
3847
|
try {
|
|
3787
|
-
const offers =
|
|
3788
|
-
if (offers[
|
|
3789
|
-
perMessageDeflate.accept(offers[
|
|
3790
|
-
extensions[
|
|
3848
|
+
const offers = extension2.parse(secWebSocketExtensions);
|
|
3849
|
+
if (offers[PerMessageDeflate2.extensionName]) {
|
|
3850
|
+
perMessageDeflate.accept(offers[PerMessageDeflate2.extensionName]);
|
|
3851
|
+
extensions[PerMessageDeflate2.extensionName] = perMessageDeflate;
|
|
3791
3852
|
}
|
|
3792
3853
|
} catch (err) {
|
|
3793
3854
|
const message = "Invalid or unacceptable Sec-WebSocket-Extensions header";
|
|
@@ -3858,10 +3919,10 @@ var require_websocket_server = __commonJS({
|
|
|
3858
3919
|
ws._protocol = protocol;
|
|
3859
3920
|
}
|
|
3860
3921
|
}
|
|
3861
|
-
if (extensions[
|
|
3862
|
-
const params = extensions[
|
|
3863
|
-
const value =
|
|
3864
|
-
[
|
|
3922
|
+
if (extensions[PerMessageDeflate2.extensionName]) {
|
|
3923
|
+
const params = extensions[PerMessageDeflate2.extensionName].params;
|
|
3924
|
+
const value = extension2.format({
|
|
3925
|
+
[PerMessageDeflate2.extensionName]: [params]
|
|
3865
3926
|
});
|
|
3866
3927
|
headers.push(`Sec-WebSocket-Extensions: ${value}`);
|
|
3867
3928
|
ws._extensions = extensions;
|
|
@@ -3871,6 +3932,8 @@ var require_websocket_server = __commonJS({
|
|
|
3871
3932
|
socket.removeListener("error", socketOnError);
|
|
3872
3933
|
ws.setSocket(socket, head, {
|
|
3873
3934
|
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
3935
|
+
maxBufferedChunks: this.options.maxBufferedChunks,
|
|
3936
|
+
maxFragments: this.options.maxFragments,
|
|
3874
3937
|
maxPayload: this.options.maxPayload,
|
|
3875
3938
|
skipUTF8Validation: this.options.skipUTF8Validation
|
|
3876
3939
|
});
|
|
@@ -3931,19 +3994,25 @@ var require_websocket_server = __commonJS({
|
|
|
3931
3994
|
// ../../node_modules/ws/wrapper.mjs
|
|
3932
3995
|
var wrapper_exports = {};
|
|
3933
3996
|
__export(wrapper_exports, {
|
|
3997
|
+
PerMessageDeflate: () => import_permessage_deflate.default,
|
|
3934
3998
|
Receiver: () => import_receiver.default,
|
|
3935
3999
|
Sender: () => import_sender.default,
|
|
3936
4000
|
WebSocket: () => import_websocket.default,
|
|
3937
4001
|
WebSocketServer: () => import_websocket_server.default,
|
|
3938
4002
|
createWebSocketStream: () => import_stream.default,
|
|
3939
|
-
default: () => wrapper_default
|
|
4003
|
+
default: () => wrapper_default,
|
|
4004
|
+
extension: () => import_extension.default,
|
|
4005
|
+
subprotocol: () => import_subprotocol.default
|
|
3940
4006
|
});
|
|
3941
|
-
var import_stream, import_receiver, import_sender, import_websocket, import_websocket_server, wrapper_default;
|
|
4007
|
+
var import_stream, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
|
|
3942
4008
|
var init_wrapper = __esm({
|
|
3943
4009
|
"../../node_modules/ws/wrapper.mjs"() {
|
|
3944
4010
|
import_stream = __toESM(require_stream());
|
|
4011
|
+
import_extension = __toESM(require_extension());
|
|
4012
|
+
import_permessage_deflate = __toESM(require_permessage_deflate());
|
|
3945
4013
|
import_receiver = __toESM(require_receiver());
|
|
3946
4014
|
import_sender = __toESM(require_sender());
|
|
4015
|
+
import_subprotocol = __toESM(require_subprotocol());
|
|
3947
4016
|
import_websocket = __toESM(require_websocket());
|
|
3948
4017
|
import_websocket_server = __toESM(require_websocket_server());
|
|
3949
4018
|
wrapper_default = import_websocket.default;
|
|
@@ -16086,7 +16155,275 @@ var Granular = class _Granular {
|
|
|
16086
16155
|
}
|
|
16087
16156
|
};
|
|
16088
16157
|
|
|
16158
|
+
// src/agent-harness-templates/action-presentation/0.1.0/manifest.json
|
|
16159
|
+
var manifest_default = {
|
|
16160
|
+
id: "action-presentation",
|
|
16161
|
+
version: "0.1.0",
|
|
16162
|
+
status: "candidate",
|
|
16163
|
+
owner: "granular",
|
|
16164
|
+
createdAt: "2026-05-25T00:00:00.000Z",
|
|
16165
|
+
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.",
|
|
16166
|
+
promptBuilder: "buildGranularAgentSystemPrompt:action-presentation",
|
|
16167
|
+
continuationBuilder: "buildContinuationInstruction:action-presentation",
|
|
16168
|
+
modelOutputInstruction: "agent-evals:modelOutputInstruction",
|
|
16169
|
+
codeReviewPolicy: "reviewGeneratedJobCode",
|
|
16170
|
+
defaultModel: "gpt-5.4",
|
|
16171
|
+
modelMatrix: ["gpt-5.4"],
|
|
16172
|
+
temperature: 0,
|
|
16173
|
+
compatibility: {
|
|
16174
|
+
minSdkVersion: "0.4.40",
|
|
16175
|
+
capabilities: [
|
|
16176
|
+
"executeCode",
|
|
16177
|
+
"readEntities",
|
|
16178
|
+
"workflowHelpers",
|
|
16179
|
+
"savedData",
|
|
16180
|
+
"showRecords"
|
|
16181
|
+
]
|
|
16182
|
+
},
|
|
16183
|
+
evalGates: {
|
|
16184
|
+
requiredSuites: [
|
|
16185
|
+
"agent-harness-hardening",
|
|
16186
|
+
"agent-harness-runtime-e2e",
|
|
16187
|
+
"agent-production-readiness-e2e"
|
|
16188
|
+
],
|
|
16189
|
+
criticalBuckets: [
|
|
16190
|
+
"relationship-traversal",
|
|
16191
|
+
"cross-turn-reference",
|
|
16192
|
+
"ambiguous-target-choice",
|
|
16193
|
+
"confirmation-gated-mutation",
|
|
16194
|
+
"denied-action-refusal",
|
|
16195
|
+
"mutation-presentation"
|
|
16196
|
+
],
|
|
16197
|
+
maxRegressionPct: 0,
|
|
16198
|
+
minPassK: {
|
|
16199
|
+
"critical-mutation": 0.9,
|
|
16200
|
+
"permission-boundary": 1
|
|
16201
|
+
}
|
|
16202
|
+
}
|
|
16203
|
+
};
|
|
16204
|
+
|
|
16205
|
+
// src/agent-harness-templates/experimental-compact/0.1.0/manifest.json
|
|
16206
|
+
var manifest_default2 = {
|
|
16207
|
+
id: "experimental-compact",
|
|
16208
|
+
version: "0.1.0",
|
|
16209
|
+
status: "candidate",
|
|
16210
|
+
owner: "granular",
|
|
16211
|
+
createdAt: "2026-05-24T00:00:00.000Z",
|
|
16212
|
+
changelog: "Candidate harness template used for champion/challenger testing. It adds a compact decision discipline section on top of the stable renderer.",
|
|
16213
|
+
promptBuilder: "buildGranularAgentSystemPrompt:experimental-compact",
|
|
16214
|
+
continuationBuilder: "buildContinuationInstruction:experimental-compact",
|
|
16215
|
+
modelOutputInstruction: "agent-evals:modelOutputInstruction",
|
|
16216
|
+
codeReviewPolicy: "reviewGeneratedJobCode",
|
|
16217
|
+
defaultModel: "gpt-5.4",
|
|
16218
|
+
modelMatrix: ["gpt-5.4"],
|
|
16219
|
+
temperature: 0,
|
|
16220
|
+
compatibility: {
|
|
16221
|
+
minSdkVersion: "0.4.40",
|
|
16222
|
+
capabilities: [
|
|
16223
|
+
"executeCode",
|
|
16224
|
+
"readEntities",
|
|
16225
|
+
"workflowHelpers",
|
|
16226
|
+
"savedData",
|
|
16227
|
+
"showRecords"
|
|
16228
|
+
]
|
|
16229
|
+
},
|
|
16230
|
+
evalGates: {
|
|
16231
|
+
requiredSuites: [
|
|
16232
|
+
"agent-harness-hardening",
|
|
16233
|
+
"agent-harness-runtime-e2e",
|
|
16234
|
+
"agent-production-readiness-e2e"
|
|
16235
|
+
],
|
|
16236
|
+
criticalBuckets: [
|
|
16237
|
+
"relationship-traversal",
|
|
16238
|
+
"cross-turn-reference",
|
|
16239
|
+
"ambiguous-target-choice",
|
|
16240
|
+
"confirmation-gated-mutation",
|
|
16241
|
+
"denied-action-refusal",
|
|
16242
|
+
"mutation-presentation"
|
|
16243
|
+
],
|
|
16244
|
+
maxRegressionPct: 0,
|
|
16245
|
+
minPassK: {
|
|
16246
|
+
"critical-mutation": 0.9,
|
|
16247
|
+
"permission-boundary": 1
|
|
16248
|
+
}
|
|
16249
|
+
}
|
|
16250
|
+
};
|
|
16251
|
+
|
|
16252
|
+
// src/agent-harness-templates/stable/1.0.0/manifest.json
|
|
16253
|
+
var manifest_default3 = {
|
|
16254
|
+
id: "stable",
|
|
16255
|
+
version: "1.0.0",
|
|
16256
|
+
status: "stable",
|
|
16257
|
+
owner: "granular",
|
|
16258
|
+
createdAt: "2026-05-24T00:00:00.000Z",
|
|
16259
|
+
changelog: "Baseline template wrapping the existing Granular agent harness prompt, continuation instruction, output contract, and generated-job review policy.",
|
|
16260
|
+
promptBuilder: "buildGranularAgentSystemPrompt",
|
|
16261
|
+
continuationBuilder: "buildContinuationInstruction",
|
|
16262
|
+
modelOutputInstruction: "agent-evals:modelOutputInstruction",
|
|
16263
|
+
codeReviewPolicy: "reviewGeneratedJobCode",
|
|
16264
|
+
defaultModel: "gpt-5.4",
|
|
16265
|
+
modelMatrix: ["gpt-5.4"],
|
|
16266
|
+
temperature: 0,
|
|
16267
|
+
compatibility: {
|
|
16268
|
+
minSdkVersion: "0.4.40",
|
|
16269
|
+
capabilities: [
|
|
16270
|
+
"executeCode",
|
|
16271
|
+
"readEntities",
|
|
16272
|
+
"workflowHelpers",
|
|
16273
|
+
"savedData",
|
|
16274
|
+
"showRecords"
|
|
16275
|
+
]
|
|
16276
|
+
},
|
|
16277
|
+
evalGates: {
|
|
16278
|
+
requiredSuites: [
|
|
16279
|
+
"agent-harness-hardening",
|
|
16280
|
+
"agent-harness-runtime-e2e",
|
|
16281
|
+
"agent-production-readiness-e2e"
|
|
16282
|
+
],
|
|
16283
|
+
criticalBuckets: [
|
|
16284
|
+
"relationship-traversal",
|
|
16285
|
+
"cross-turn-reference",
|
|
16286
|
+
"ambiguous-target-choice",
|
|
16287
|
+
"confirmation-gated-mutation",
|
|
16288
|
+
"denied-action-refusal",
|
|
16289
|
+
"mutation-presentation"
|
|
16290
|
+
],
|
|
16291
|
+
maxRegressionPct: 0,
|
|
16292
|
+
minPassK: {
|
|
16293
|
+
"critical-mutation": 0.9,
|
|
16294
|
+
"permission-boundary": 1
|
|
16295
|
+
}
|
|
16296
|
+
}
|
|
16297
|
+
};
|
|
16298
|
+
|
|
16089
16299
|
// src/agent-harness.ts
|
|
16300
|
+
var HARNESS_TEMPLATE_STATUSES = [
|
|
16301
|
+
"draft",
|
|
16302
|
+
"candidate",
|
|
16303
|
+
"release-candidate",
|
|
16304
|
+
"stable",
|
|
16305
|
+
"deprecated"
|
|
16306
|
+
];
|
|
16307
|
+
function requireRecord(value, context) {
|
|
16308
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
16309
|
+
throw new Error(`${context} must be an object.`);
|
|
16310
|
+
}
|
|
16311
|
+
return value;
|
|
16312
|
+
}
|
|
16313
|
+
function requiredString(record, key, context) {
|
|
16314
|
+
const value = record[key];
|
|
16315
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
16316
|
+
throw new Error(`${context}.${key} must be a non-empty string.`);
|
|
16317
|
+
}
|
|
16318
|
+
return value;
|
|
16319
|
+
}
|
|
16320
|
+
function requiredNumber(record, key, context) {
|
|
16321
|
+
const value = record[key];
|
|
16322
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
16323
|
+
throw new Error(`${context}.${key} must be a finite number.`);
|
|
16324
|
+
}
|
|
16325
|
+
return value;
|
|
16326
|
+
}
|
|
16327
|
+
function requiredStringArray(record, key, context) {
|
|
16328
|
+
const value = record[key];
|
|
16329
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
|
|
16330
|
+
throw new Error(`${context}.${key} must be an array of non-empty strings.`);
|
|
16331
|
+
}
|
|
16332
|
+
return [...value];
|
|
16333
|
+
}
|
|
16334
|
+
function requiredNumberRecord(record, key, context) {
|
|
16335
|
+
const value = requireRecord(record[key], `${context}.${key}`);
|
|
16336
|
+
const output = {};
|
|
16337
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
16338
|
+
if (typeof entryValue !== "number" || !Number.isFinite(entryValue) || entryValue < 0 || entryValue > 1) {
|
|
16339
|
+
throw new Error(
|
|
16340
|
+
`${context}.${key}.${entryKey} must be a number between 0 and 1.`
|
|
16341
|
+
);
|
|
16342
|
+
}
|
|
16343
|
+
output[entryKey] = entryValue;
|
|
16344
|
+
}
|
|
16345
|
+
return output;
|
|
16346
|
+
}
|
|
16347
|
+
function validateHarnessTemplateManifest(value, context = "HarnessTemplateManifest") {
|
|
16348
|
+
const record = requireRecord(value, context);
|
|
16349
|
+
const status = requiredString(record, "status", context);
|
|
16350
|
+
if (!HARNESS_TEMPLATE_STATUSES.includes(status)) {
|
|
16351
|
+
throw new Error(
|
|
16352
|
+
`${context}.status must be one of ${HARNESS_TEMPLATE_STATUSES.join(", ")}.`
|
|
16353
|
+
);
|
|
16354
|
+
}
|
|
16355
|
+
const createdAt = requiredString(record, "createdAt", context);
|
|
16356
|
+
if (Number.isNaN(Date.parse(createdAt))) {
|
|
16357
|
+
throw new Error(`${context}.createdAt must be an ISO timestamp.`);
|
|
16358
|
+
}
|
|
16359
|
+
const compatibility = requireRecord(
|
|
16360
|
+
record.compatibility,
|
|
16361
|
+
`${context}.compatibility`
|
|
16362
|
+
);
|
|
16363
|
+
const evalGates = requireRecord(record.evalGates, `${context}.evalGates`);
|
|
16364
|
+
const maxRegressionPct = requiredNumber(
|
|
16365
|
+
evalGates,
|
|
16366
|
+
"maxRegressionPct",
|
|
16367
|
+
`${context}.evalGates`
|
|
16368
|
+
);
|
|
16369
|
+
if (maxRegressionPct < 0 || maxRegressionPct > 1) {
|
|
16370
|
+
throw new Error(
|
|
16371
|
+
`${context}.evalGates.maxRegressionPct must be between 0 and 1.`
|
|
16372
|
+
);
|
|
16373
|
+
}
|
|
16374
|
+
return {
|
|
16375
|
+
id: requiredString(record, "id", context),
|
|
16376
|
+
version: requiredString(record, "version", context),
|
|
16377
|
+
status,
|
|
16378
|
+
owner: requiredString(record, "owner", context),
|
|
16379
|
+
createdAt,
|
|
16380
|
+
changelog: requiredString(record, "changelog", context),
|
|
16381
|
+
promptBuilder: requiredString(record, "promptBuilder", context),
|
|
16382
|
+
continuationBuilder: requiredString(record, "continuationBuilder", context),
|
|
16383
|
+
modelOutputInstruction: requiredString(
|
|
16384
|
+
record,
|
|
16385
|
+
"modelOutputInstruction",
|
|
16386
|
+
context
|
|
16387
|
+
),
|
|
16388
|
+
codeReviewPolicy: requiredString(record, "codeReviewPolicy", context),
|
|
16389
|
+
defaultModel: requiredString(record, "defaultModel", context),
|
|
16390
|
+
modelMatrix: requiredStringArray(record, "modelMatrix", context),
|
|
16391
|
+
temperature: requiredNumber(record, "temperature", context),
|
|
16392
|
+
compatibility: {
|
|
16393
|
+
minSdkVersion: requiredString(
|
|
16394
|
+
compatibility,
|
|
16395
|
+
"minSdkVersion",
|
|
16396
|
+
`${context}.compatibility`
|
|
16397
|
+
),
|
|
16398
|
+
capabilities: requiredStringArray(
|
|
16399
|
+
compatibility,
|
|
16400
|
+
"capabilities",
|
|
16401
|
+
`${context}.compatibility`
|
|
16402
|
+
)
|
|
16403
|
+
},
|
|
16404
|
+
evalGates: {
|
|
16405
|
+
requiredSuites: requiredStringArray(
|
|
16406
|
+
evalGates,
|
|
16407
|
+
"requiredSuites",
|
|
16408
|
+
`${context}.evalGates`
|
|
16409
|
+
),
|
|
16410
|
+
criticalBuckets: requiredStringArray(
|
|
16411
|
+
evalGates,
|
|
16412
|
+
"criticalBuckets",
|
|
16413
|
+
`${context}.evalGates`
|
|
16414
|
+
),
|
|
16415
|
+
maxRegressionPct,
|
|
16416
|
+
minPassK: requiredNumberRecord(
|
|
16417
|
+
evalGates,
|
|
16418
|
+
"minPassK",
|
|
16419
|
+
`${context}.evalGates`
|
|
16420
|
+
)
|
|
16421
|
+
}
|
|
16422
|
+
};
|
|
16423
|
+
}
|
|
16424
|
+
function defineHarnessTemplateManifest(value, context) {
|
|
16425
|
+
return validateHarnessTemplateManifest(value, context);
|
|
16426
|
+
}
|
|
16090
16427
|
function asRecord4(value) {
|
|
16091
16428
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
16092
16429
|
return value;
|
|
@@ -16110,6 +16447,16 @@ function uniqueStrings(values, maxCount) {
|
|
|
16110
16447
|
}
|
|
16111
16448
|
return output;
|
|
16112
16449
|
}
|
|
16450
|
+
function stableStringify(value) {
|
|
16451
|
+
if (value === null || typeof value !== "object") {
|
|
16452
|
+
return JSON.stringify(value);
|
|
16453
|
+
}
|
|
16454
|
+
if (Array.isArray(value)) {
|
|
16455
|
+
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
16456
|
+
}
|
|
16457
|
+
const record = value;
|
|
16458
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
|
|
16459
|
+
}
|
|
16113
16460
|
function renderConstBlock(name, value) {
|
|
16114
16461
|
return `const ${name} = ${JSON.stringify(value, null, 2)} as const;`;
|
|
16115
16462
|
}
|
|
@@ -18049,6 +18396,156 @@ ${knownFactsBlock}
|
|
|
18049
18396
|
[Request]
|
|
18050
18397
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
18051
18398
|
}
|
|
18399
|
+
var STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST = defineHarnessTemplateManifest(
|
|
18400
|
+
manifest_default3,
|
|
18401
|
+
"stable@1.0.0 manifest"
|
|
18402
|
+
);
|
|
18403
|
+
function hashHarnessTemplateValue(value) {
|
|
18404
|
+
return hashString(stableStringify(value)) || "00000000";
|
|
18405
|
+
}
|
|
18406
|
+
function renderStableHarnessPrompt(input) {
|
|
18407
|
+
const prompt = buildGranularAgentSystemPrompt(input);
|
|
18408
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18409
|
+
STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18410
|
+
);
|
|
18411
|
+
return {
|
|
18412
|
+
templateId: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18413
|
+
templateVersion: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18414
|
+
templateHash,
|
|
18415
|
+
promptInstanceHash: hashHarnessTemplateValue({
|
|
18416
|
+
templateHash,
|
|
18417
|
+
input,
|
|
18418
|
+
prompt
|
|
18419
|
+
}),
|
|
18420
|
+
prompt
|
|
18421
|
+
};
|
|
18422
|
+
}
|
|
18423
|
+
function renderStableHarnessContinuation(resultPreview) {
|
|
18424
|
+
const instruction = buildContinuationInstruction(resultPreview);
|
|
18425
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18426
|
+
STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18427
|
+
);
|
|
18428
|
+
return {
|
|
18429
|
+
templateId: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18430
|
+
templateVersion: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18431
|
+
templateHash,
|
|
18432
|
+
instruction
|
|
18433
|
+
};
|
|
18434
|
+
}
|
|
18435
|
+
var STABLE_AGENT_HARNESS_TEMPLATE = {
|
|
18436
|
+
manifest: STABLE_AGENT_HARNESS_TEMPLATE_MANIFEST,
|
|
18437
|
+
renderPrompt: renderStableHarnessPrompt,
|
|
18438
|
+
renderContinuation: renderStableHarnessContinuation
|
|
18439
|
+
};
|
|
18440
|
+
var EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST = defineHarnessTemplateManifest(
|
|
18441
|
+
manifest_default2,
|
|
18442
|
+
"experimental-compact@0.1.0 manifest"
|
|
18443
|
+
);
|
|
18444
|
+
function renderExperimentalCompactHarnessPrompt(input) {
|
|
18445
|
+
const prompt = `${buildGranularAgentSystemPrompt(input)}
|
|
18446
|
+
|
|
18447
|
+
[Candidate Harness Delta: Compact Decision Discipline]
|
|
18448
|
+
- Prefer the smallest action that satisfies the current request.
|
|
18449
|
+
- When several records could match, ask one structured choice question before mutating.
|
|
18450
|
+
- Before any irreversible or outbound mutation, obtain explicit confirmation unless the policy surface already requires it.
|
|
18451
|
+
- Do not compensate for missing tools with raw network calls, synthetic records, or hidden side channels.
|
|
18452
|
+
- Keep the final user-facing reply focused on what was done, what was not done, and any remaining blocker.`;
|
|
18453
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18454
|
+
EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18455
|
+
);
|
|
18456
|
+
return {
|
|
18457
|
+
templateId: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18458
|
+
templateVersion: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18459
|
+
templateHash,
|
|
18460
|
+
promptInstanceHash: hashHarnessTemplateValue({
|
|
18461
|
+
templateHash,
|
|
18462
|
+
input,
|
|
18463
|
+
prompt
|
|
18464
|
+
}),
|
|
18465
|
+
prompt
|
|
18466
|
+
};
|
|
18467
|
+
}
|
|
18468
|
+
function renderExperimentalCompactHarnessContinuation(resultPreview) {
|
|
18469
|
+
const instruction = `${buildContinuationInstruction(resultPreview)}
|
|
18470
|
+
|
|
18471
|
+
Keep the continuation compact: either finish, ask the one blocking question, or run the next smallest safe action.`;
|
|
18472
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18473
|
+
EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18474
|
+
);
|
|
18475
|
+
return {
|
|
18476
|
+
templateId: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18477
|
+
templateVersion: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18478
|
+
templateHash,
|
|
18479
|
+
instruction
|
|
18480
|
+
};
|
|
18481
|
+
}
|
|
18482
|
+
var EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE = {
|
|
18483
|
+
manifest: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE_MANIFEST,
|
|
18484
|
+
renderPrompt: renderExperimentalCompactHarnessPrompt,
|
|
18485
|
+
renderContinuation: renderExperimentalCompactHarnessContinuation
|
|
18486
|
+
};
|
|
18487
|
+
var ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST = defineHarnessTemplateManifest(
|
|
18488
|
+
manifest_default,
|
|
18489
|
+
"action-presentation@0.1.0 manifest"
|
|
18490
|
+
);
|
|
18491
|
+
function renderActionPresentationHarnessPrompt(input) {
|
|
18492
|
+
const prompt = `${buildGranularAgentSystemPrompt(input)}
|
|
18493
|
+
|
|
18494
|
+
[Candidate Harness Delta: Action Request And Result Presentation]
|
|
18495
|
+
- 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.
|
|
18496
|
+
- 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.
|
|
18497
|
+
- 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.
|
|
18498
|
+
- After a mutation/effect call, base the reply on the returned action result and include a visible target label or identifier when one exists.
|
|
18499
|
+
- If no target can be grounded, say what was searched and what exact identifier or choice is needed; do not pretend the action completed.`;
|
|
18500
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18501
|
+
ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18502
|
+
);
|
|
18503
|
+
return {
|
|
18504
|
+
templateId: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18505
|
+
templateVersion: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18506
|
+
templateHash,
|
|
18507
|
+
promptInstanceHash: hashHarnessTemplateValue({
|
|
18508
|
+
templateHash,
|
|
18509
|
+
input,
|
|
18510
|
+
prompt
|
|
18511
|
+
}),
|
|
18512
|
+
prompt
|
|
18513
|
+
};
|
|
18514
|
+
}
|
|
18515
|
+
function renderActionPresentationHarnessContinuation(resultPreview) {
|
|
18516
|
+
const instruction = `${buildContinuationInstruction(resultPreview)}
|
|
18517
|
+
|
|
18518
|
+
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.`;
|
|
18519
|
+
const templateHash = hashHarnessTemplateValue(
|
|
18520
|
+
ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST
|
|
18521
|
+
);
|
|
18522
|
+
return {
|
|
18523
|
+
templateId: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.id,
|
|
18524
|
+
templateVersion: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST.version,
|
|
18525
|
+
templateHash,
|
|
18526
|
+
instruction
|
|
18527
|
+
};
|
|
18528
|
+
}
|
|
18529
|
+
var ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE = {
|
|
18530
|
+
manifest: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE_MANIFEST,
|
|
18531
|
+
renderPrompt: renderActionPresentationHarnessPrompt,
|
|
18532
|
+
renderContinuation: renderActionPresentationHarnessContinuation
|
|
18533
|
+
};
|
|
18534
|
+
var AGENT_HARNESS_TEMPLATES = {
|
|
18535
|
+
[STABLE_AGENT_HARNESS_TEMPLATE.manifest.id]: STABLE_AGENT_HARNESS_TEMPLATE,
|
|
18536
|
+
[EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE.manifest.id]: EXPERIMENTAL_COMPACT_AGENT_HARNESS_TEMPLATE,
|
|
18537
|
+
[ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE.manifest.id]: ACTION_PRESENTATION_AGENT_HARNESS_TEMPLATE
|
|
18538
|
+
};
|
|
18539
|
+
function resolveHarnessTemplate(templateId = "stable", options) {
|
|
18540
|
+
const resolved = AGENT_HARNESS_TEMPLATES[templateId];
|
|
18541
|
+
if (resolved) return resolved;
|
|
18542
|
+
{
|
|
18543
|
+
const known = Object.keys(AGENT_HARNESS_TEMPLATES).join(", ");
|
|
18544
|
+
throw new Error(
|
|
18545
|
+
`Unknown harness template "${templateId}". Known templates: ${known}`
|
|
18546
|
+
);
|
|
18547
|
+
}
|
|
18548
|
+
}
|
|
18052
18549
|
|
|
18053
18550
|
// src/openai-usage.ts
|
|
18054
18551
|
var OPENAI_PRICING_SOURCE_URL = "https://developers.openai.com/api/docs/models/gpt-5.4/";
|
|
@@ -18170,6 +18667,98 @@ function matchesPattern(text, matcher) {
|
|
|
18170
18667
|
if (typeof matcher === "string") return text.includes(matcher);
|
|
18171
18668
|
return matcher.test(text);
|
|
18172
18669
|
}
|
|
18670
|
+
function matcherFromConfig(value) {
|
|
18671
|
+
const match = value.match(/^\/([\s\S]*)\/([dgimsuvy]*)$/);
|
|
18672
|
+
if (!match) return value;
|
|
18673
|
+
return new RegExp(match[1] || "", match[2] || "");
|
|
18674
|
+
}
|
|
18675
|
+
function matchersFromConfig(values) {
|
|
18676
|
+
if (!values?.length) return void 0;
|
|
18677
|
+
return values.map((value) => matcherFromConfig(value));
|
|
18678
|
+
}
|
|
18679
|
+
function expectationsFromConfig(input) {
|
|
18680
|
+
if (!input) return void 0;
|
|
18681
|
+
return {
|
|
18682
|
+
replyIncludes: matchersFromConfig(input.replyIncludes),
|
|
18683
|
+
replyExcludes: matchersFromConfig(input.replyExcludes),
|
|
18684
|
+
actionIncludes: matchersFromConfig(input.actionIncludes),
|
|
18685
|
+
actionExcludes: matchersFromConfig(input.actionExcludes),
|
|
18686
|
+
codeIncludes: matchersFromConfig(input.codeIncludes),
|
|
18687
|
+
codeExcludes: matchersFromConfig(input.codeExcludes),
|
|
18688
|
+
behaviorBuckets: input.behaviorBuckets,
|
|
18689
|
+
actions: input.actions ? {
|
|
18690
|
+
required: matchersFromConfig(input.actions.required),
|
|
18691
|
+
forbidden: matchersFromConfig(input.actions.forbidden)
|
|
18692
|
+
} : void 0,
|
|
18693
|
+
prompts: input.prompts ? {
|
|
18694
|
+
...input.prompts,
|
|
18695
|
+
requiredConfirmationBefore: matchersFromConfig(
|
|
18696
|
+
input.prompts.requiredConfirmationBefore
|
|
18697
|
+
)
|
|
18698
|
+
} : void 0,
|
|
18699
|
+
presentation: input.presentation ? {
|
|
18700
|
+
mustMention: matchersFromConfig(input.presentation.mustMention),
|
|
18701
|
+
mustNotMention: matchersFromConfig(input.presentation.mustNotMention),
|
|
18702
|
+
mustDisplayOrSave: matchersFromConfig(
|
|
18703
|
+
input.presentation.mustDisplayOrSave
|
|
18704
|
+
)
|
|
18705
|
+
} : void 0
|
|
18706
|
+
};
|
|
18707
|
+
}
|
|
18708
|
+
function promptResponderFromConfig(rules) {
|
|
18709
|
+
if (!rules?.length) return void 0;
|
|
18710
|
+
return createHumanResponder(
|
|
18711
|
+
rules.map((rule) => ({
|
|
18712
|
+
type: rule.type,
|
|
18713
|
+
when: Array.isArray(rule.when) ? rule.when.map((matcher) => matcherFromConfig(matcher)) : rule.when ? matcherFromConfig(rule.when) : void 0,
|
|
18714
|
+
answer: rule.answer
|
|
18715
|
+
}))
|
|
18716
|
+
);
|
|
18717
|
+
}
|
|
18718
|
+
function inspectionFromConfig(inspection) {
|
|
18719
|
+
if (!inspection) return void 0;
|
|
18720
|
+
return {
|
|
18721
|
+
code: inspection.code,
|
|
18722
|
+
includes: matchersFromConfig(inspection.includes),
|
|
18723
|
+
excludes: matchersFromConfig(inspection.excludes)
|
|
18724
|
+
};
|
|
18725
|
+
}
|
|
18726
|
+
function inspectionsFromConfig(inspections) {
|
|
18727
|
+
if (!inspections) return void 0;
|
|
18728
|
+
if (Array.isArray(inspections)) {
|
|
18729
|
+
return inspections.map((inspection) => inspectionFromConfig(inspection)).filter(
|
|
18730
|
+
(inspection) => Boolean(inspection)
|
|
18731
|
+
);
|
|
18732
|
+
}
|
|
18733
|
+
return inspectionFromConfig(inspections);
|
|
18734
|
+
}
|
|
18735
|
+
function scenariosFromAgentEvalFile(file) {
|
|
18736
|
+
return file.scenarios.map((scenario) => ({
|
|
18737
|
+
id: scenario.id,
|
|
18738
|
+
description: scenario.description,
|
|
18739
|
+
request: scenario.request,
|
|
18740
|
+
behaviorBuckets: scenario.behaviorBuckets,
|
|
18741
|
+
human: promptResponderFromConfig(scenario.human),
|
|
18742
|
+
prepareRecords: scenario.prepareRecords,
|
|
18743
|
+
expect: expectationsFromConfig(scenario.expect),
|
|
18744
|
+
verify: inspectionFromConfig(scenario.verify),
|
|
18745
|
+
inspect: inspectionsFromConfig(scenario.inspect),
|
|
18746
|
+
steps: scenario.steps?.map((step) => ({
|
|
18747
|
+
id: step.id,
|
|
18748
|
+
request: step.request,
|
|
18749
|
+
behaviorBuckets: step.behaviorBuckets || scenario.behaviorBuckets,
|
|
18750
|
+
human: promptResponderFromConfig(step.human || scenario.human),
|
|
18751
|
+
expect: expectationsFromConfig(step.expect || scenario.expect),
|
|
18752
|
+
inspect: inspectionsFromConfig(step.inspect)
|
|
18753
|
+
}))
|
|
18754
|
+
}));
|
|
18755
|
+
}
|
|
18756
|
+
async function loadAgentEvalScenarioFile(filePath) {
|
|
18757
|
+
const raw = JSON.parse(
|
|
18758
|
+
await promises.readFile(filePath, "utf8")
|
|
18759
|
+
);
|
|
18760
|
+
return scenariosFromAgentEvalFile(raw);
|
|
18761
|
+
}
|
|
18173
18762
|
function assertMatches(label, text, includes = [], excludes = []) {
|
|
18174
18763
|
for (const matcher of includes) {
|
|
18175
18764
|
if (!matchesPattern(text, matcher)) {
|
|
@@ -18202,6 +18791,23 @@ function asArray3(value) {
|
|
|
18202
18791
|
if (!value) return [];
|
|
18203
18792
|
return Array.isArray(value) ? value : [value];
|
|
18204
18793
|
}
|
|
18794
|
+
function progressEvent(input) {
|
|
18795
|
+
return {
|
|
18796
|
+
...input,
|
|
18797
|
+
id: input.id || [
|
|
18798
|
+
input.scenarioId || "suite",
|
|
18799
|
+
input.stepId || input.phase,
|
|
18800
|
+
input.iteration ? `iteration-${input.iteration}` : "",
|
|
18801
|
+
input.jobId || "",
|
|
18802
|
+
input.title,
|
|
18803
|
+
Date.now()
|
|
18804
|
+
].filter(Boolean).join(":"),
|
|
18805
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
18806
|
+
};
|
|
18807
|
+
}
|
|
18808
|
+
async function emitProgress(handler, event) {
|
|
18809
|
+
await handler?.(progressEvent(event));
|
|
18810
|
+
}
|
|
18205
18811
|
var GPT_54_TOKEN_PRICING_USD_PER_MILLION = {
|
|
18206
18812
|
input: 2.5,
|
|
18207
18813
|
cachedInput: 0.25,
|
|
@@ -18444,7 +19050,7 @@ function filterPromptsByBoundary(liveDoc, prompts, boundaryTimestamp) {
|
|
|
18444
19050
|
});
|
|
18445
19051
|
}
|
|
18446
19052
|
function createScriptedPromptResponder(rules, fallback) {
|
|
18447
|
-
|
|
19053
|
+
const responder = async ({ prompt, history }) => {
|
|
18448
19054
|
const promptText = `${prompt.title || ""}
|
|
18449
19055
|
${prompt.message || ""}`;
|
|
18450
19056
|
for (const rule of rules) {
|
|
@@ -18461,6 +19067,11 @@ ${prompt.message || ""}`;
|
|
|
18461
19067
|
`No scripted prompt responder matched prompt ${prompt.id}: ${promptText}`
|
|
18462
19068
|
);
|
|
18463
19069
|
};
|
|
19070
|
+
Object.defineProperty(responder, "__granularScriptedPromptRules", {
|
|
19071
|
+
enumerable: false,
|
|
19072
|
+
value: rules
|
|
19073
|
+
});
|
|
19074
|
+
return responder;
|
|
18464
19075
|
}
|
|
18465
19076
|
function extractJsonObject(text) {
|
|
18466
19077
|
const start = text.indexOf("{");
|
|
@@ -18747,6 +19358,22 @@ ${checkpoint.latestJobResult}` : null
|
|
|
18747
19358
|
];
|
|
18748
19359
|
return lines.filter(Boolean).join("\n\n");
|
|
18749
19360
|
}
|
|
19361
|
+
function readableAgentMessage(message) {
|
|
19362
|
+
const record = asRecord6(message);
|
|
19363
|
+
if (!record) return JSON.stringify(message);
|
|
19364
|
+
if (typeof record.reply === "string" && record.reply.trim()) {
|
|
19365
|
+
return record.reply;
|
|
19366
|
+
}
|
|
19367
|
+
const show = asRecord6(record.show);
|
|
19368
|
+
const variableNames = asArray3(show?.variableNames).map((value) => String(value)).filter(Boolean);
|
|
19369
|
+
if (variableNames.length) {
|
|
19370
|
+
return `Displayed ${variableNames.join(", ")}`;
|
|
19371
|
+
}
|
|
19372
|
+
if (typeof record.kind === "string") {
|
|
19373
|
+
return `Agent ${record.kind} message`;
|
|
19374
|
+
}
|
|
19375
|
+
return JSON.stringify(message);
|
|
19376
|
+
}
|
|
18750
19377
|
async function waitForJobOutcome(input) {
|
|
18751
19378
|
const stdout = [];
|
|
18752
19379
|
const stderr = [];
|
|
@@ -18754,6 +19381,11 @@ async function waitForJobOutcome(input) {
|
|
|
18754
19381
|
let lastPromptCount = 0;
|
|
18755
19382
|
let lastMessageCount = 0;
|
|
18756
19383
|
let lastJobSummary = null;
|
|
19384
|
+
let lastActionSummaryKey = "";
|
|
19385
|
+
let lastActionSummaryLength = 0;
|
|
19386
|
+
let lastAgentMessageKey = "";
|
|
19387
|
+
let lastAgentMessageCount = 0;
|
|
19388
|
+
let lastJobStatus = "";
|
|
18757
19389
|
input.job.on("stdout", (line) => stdout.push(String(line)));
|
|
18758
19390
|
input.job.on("stderr", (line) => stderr.push(String(line)));
|
|
18759
19391
|
const startedAt = Date.now();
|
|
@@ -18769,7 +19401,71 @@ async function waitForJobOutcome(input) {
|
|
|
18769
19401
|
const messages = asArray3(asRecord6(liveDoc.conversation)?.messages);
|
|
18770
19402
|
lastMessageCount = messages.length;
|
|
18771
19403
|
lastJobSummary = asRecord6(asRecord6(liveDoc.jobs)?.byId)?.[input.job.id] || null;
|
|
19404
|
+
const jobRecord = asRecord6(lastJobSummary);
|
|
19405
|
+
const jobStatus = typeof jobRecord?.status === "string" ? jobRecord.status : "";
|
|
19406
|
+
if (jobStatus && jobStatus !== lastJobStatus) {
|
|
19407
|
+
lastJobStatus = jobStatus;
|
|
19408
|
+
input.onProgress?.({
|
|
19409
|
+
id: `${input.job.id}:status:${jobStatus}:${Date.now()}`,
|
|
19410
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19411
|
+
phase: "job",
|
|
19412
|
+
status: "running",
|
|
19413
|
+
jobId: input.job.id,
|
|
19414
|
+
title: `Job ${jobStatus}`,
|
|
19415
|
+
message: `Granular job ${input.job.id}`,
|
|
19416
|
+
data: jobRecord,
|
|
19417
|
+
...input.progressContext
|
|
19418
|
+
});
|
|
19419
|
+
}
|
|
19420
|
+
const actionSummary = getActionSummary(liveDoc, input.job.id);
|
|
19421
|
+
const actionSummaryKey = JSON.stringify(actionSummary);
|
|
19422
|
+
if (actionSummary.length && actionSummaryKey !== lastActionSummaryKey) {
|
|
19423
|
+
const newActions = actionSummary.slice(lastActionSummaryLength);
|
|
19424
|
+
lastActionSummaryLength = actionSummary.length;
|
|
19425
|
+
lastActionSummaryKey = actionSummaryKey;
|
|
19426
|
+
input.onProgress?.({
|
|
19427
|
+
id: `${input.job.id}:actions:${Date.now()}`,
|
|
19428
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19429
|
+
phase: "job",
|
|
19430
|
+
status: "running",
|
|
19431
|
+
jobId: input.job.id,
|
|
19432
|
+
title: newActions.length === 1 ? "Action observed" : "Actions observed",
|
|
19433
|
+
message: (newActions.length ? newActions : actionSummary).join("\n"),
|
|
19434
|
+
data: { actionSummary, newActions },
|
|
19435
|
+
...input.progressContext
|
|
19436
|
+
});
|
|
19437
|
+
}
|
|
19438
|
+
const agentMessages = getJobAgentMessages(liveDoc, input.job.id);
|
|
19439
|
+
const agentMessageKey = JSON.stringify(agentMessages);
|
|
19440
|
+
if (agentMessages.length && agentMessageKey !== lastAgentMessageKey) {
|
|
19441
|
+
const newMessages = agentMessages.slice(lastAgentMessageCount);
|
|
19442
|
+
lastAgentMessageCount = agentMessages.length;
|
|
19443
|
+
lastAgentMessageKey = agentMessageKey;
|
|
19444
|
+
const latestMessage = newMessages.at(-1) || agentMessages.at(-1);
|
|
19445
|
+
input.onProgress?.({
|
|
19446
|
+
id: `${input.job.id}:messages:${Date.now()}`,
|
|
19447
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19448
|
+
phase: "job",
|
|
19449
|
+
status: "running",
|
|
19450
|
+
jobId: input.job.id,
|
|
19451
|
+
title: "Agent message",
|
|
19452
|
+
message: readableAgentMessage(latestMessage),
|
|
19453
|
+
data: { agentMessages, newMessages },
|
|
19454
|
+
...input.progressContext
|
|
19455
|
+
});
|
|
19456
|
+
}
|
|
18772
19457
|
if (prompts.length > 0) {
|
|
19458
|
+
input.onProgress?.({
|
|
19459
|
+
id: `${input.job.id}:prompt:${prompts[0]?.id || Date.now()}`,
|
|
19460
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19461
|
+
phase: "prompt",
|
|
19462
|
+
status: "running",
|
|
19463
|
+
jobId: input.job.id,
|
|
19464
|
+
title: "Waiting for prompt answer",
|
|
19465
|
+
message: prompts[0]?.message || prompts[0]?.title,
|
|
19466
|
+
data: { prompts },
|
|
19467
|
+
...input.progressContext
|
|
19468
|
+
});
|
|
18773
19469
|
return { kind: "prompt", prompts, liveDoc, stdout, stderr };
|
|
18774
19470
|
}
|
|
18775
19471
|
try {
|
|
@@ -18778,6 +19474,17 @@ async function waitForJobOutcome(input) {
|
|
|
18778
19474
|
input.pollIntervalMs,
|
|
18779
19475
|
`job ${input.job.id} tick`
|
|
18780
19476
|
);
|
|
19477
|
+
input.onProgress?.({
|
|
19478
|
+
id: `${input.job.id}:completed:${Date.now()}`,
|
|
19479
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19480
|
+
phase: "job",
|
|
19481
|
+
status: "passed",
|
|
19482
|
+
jobId: input.job.id,
|
|
19483
|
+
title: "Job completed",
|
|
19484
|
+
message: JSON.stringify(result)?.slice(0, 800),
|
|
19485
|
+
data: { result, stdout, stderr },
|
|
19486
|
+
...input.progressContext
|
|
19487
|
+
});
|
|
18781
19488
|
return { kind: "completed", result, liveDoc, stdout, stderr };
|
|
18782
19489
|
} catch (error) {
|
|
18783
19490
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -19009,6 +19716,10 @@ function buildSessionLogReport(input) {
|
|
|
19009
19716
|
`- Environment id: \`${conversation.environment.environmentId}\``,
|
|
19010
19717
|
`- Sandbox id: \`${conversation.environment.sandboxId}\``,
|
|
19011
19718
|
`- Status: ${result?.status || (error ? "failed" : "unknown")}`,
|
|
19719
|
+
...systemPrompts[0]?.iteration.templateId ? [
|
|
19720
|
+
`- Harness template: \`${systemPrompts[0].iteration.templateId}@${systemPrompts[0].iteration.templateVersion || "unknown"}\``,
|
|
19721
|
+
`- Template hash: \`${systemPrompts[0].iteration.templateHash || "unknown"}\``
|
|
19722
|
+
] : [],
|
|
19012
19723
|
...result?.error || error ? [`- Error: ${result?.error || error}`] : [],
|
|
19013
19724
|
"",
|
|
19014
19725
|
"## Conversation"
|
|
@@ -19116,6 +19827,12 @@ function buildSessionLogReport(input) {
|
|
|
19116
19827
|
lines.push(
|
|
19117
19828
|
`### Turn ${turn.turnNumber}, Generation ${iteration.iteration}`,
|
|
19118
19829
|
"",
|
|
19830
|
+
...iteration.templateId ? [
|
|
19831
|
+
`- Template: \`${iteration.templateId}@${iteration.templateVersion || "unknown"}\``,
|
|
19832
|
+
`- Template hash: \`${iteration.templateHash || "unknown"}\``,
|
|
19833
|
+
`- Prompt hash: \`${iteration.promptInstanceHash || "unknown"}\``,
|
|
19834
|
+
""
|
|
19835
|
+
] : [],
|
|
19119
19836
|
fenced(iteration.systemPrompt, "text"),
|
|
19120
19837
|
""
|
|
19121
19838
|
);
|
|
@@ -19157,9 +19874,167 @@ function isTransientEvalError(error) {
|
|
|
19157
19874
|
const message = error instanceof Error ? error.message : String(error);
|
|
19158
19875
|
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
19876
|
}
|
|
19877
|
+
function assertionPassed(id, run) {
|
|
19878
|
+
try {
|
|
19879
|
+
run(id);
|
|
19880
|
+
return { id, label: id, status: "passed" };
|
|
19881
|
+
} catch (error) {
|
|
19882
|
+
return {
|
|
19883
|
+
id,
|
|
19884
|
+
label: id,
|
|
19885
|
+
status: "failed",
|
|
19886
|
+
message: error instanceof Error ? error.message : String(error)
|
|
19887
|
+
};
|
|
19888
|
+
}
|
|
19889
|
+
}
|
|
19890
|
+
function hasMatchers(matchers) {
|
|
19891
|
+
return Boolean(matchers?.length);
|
|
19892
|
+
}
|
|
19893
|
+
function evaluateExpectationAssertions(input) {
|
|
19894
|
+
const expect = input.expect;
|
|
19895
|
+
if (!expect) return [];
|
|
19896
|
+
const prefix = `${input.scenarioId} step ${input.stepIndex + 1}`;
|
|
19897
|
+
const assertions = [];
|
|
19898
|
+
const actionText = input.completed.actionSummary.join("\n");
|
|
19899
|
+
const codeText = input.completed.finalCode || "";
|
|
19900
|
+
const displaySurface = [
|
|
19901
|
+
input.completed.responseText,
|
|
19902
|
+
actionText,
|
|
19903
|
+
codeText,
|
|
19904
|
+
JSON.stringify(input.completed.result)
|
|
19905
|
+
].join("\n");
|
|
19906
|
+
const promptSurface = input.completed.promptInteractions.map(
|
|
19907
|
+
(interaction) => [interaction.type, interaction.title, interaction.message].join(" ")
|
|
19908
|
+
).join("\n");
|
|
19909
|
+
if (hasMatchers(expect.replyIncludes) || hasMatchers(expect.replyExcludes)) {
|
|
19910
|
+
assertions.push(
|
|
19911
|
+
assertionPassed(
|
|
19912
|
+
"reply",
|
|
19913
|
+
() => assertMatches(
|
|
19914
|
+
`Reply for ${prefix}`,
|
|
19915
|
+
input.completed.responseText,
|
|
19916
|
+
expect.replyIncludes,
|
|
19917
|
+
expect.replyExcludes
|
|
19918
|
+
)
|
|
19919
|
+
)
|
|
19920
|
+
);
|
|
19921
|
+
}
|
|
19922
|
+
if (hasMatchers(expect.actionIncludes) || hasMatchers(expect.actionExcludes)) {
|
|
19923
|
+
assertions.push(
|
|
19924
|
+
assertionPassed(
|
|
19925
|
+
"actions",
|
|
19926
|
+
() => assertMatches(
|
|
19927
|
+
`Action summary for ${prefix}`,
|
|
19928
|
+
actionText,
|
|
19929
|
+
expect.actionIncludes,
|
|
19930
|
+
expect.actionExcludes
|
|
19931
|
+
)
|
|
19932
|
+
)
|
|
19933
|
+
);
|
|
19934
|
+
}
|
|
19935
|
+
if (hasMatchers(expect.codeIncludes) || hasMatchers(expect.codeExcludes)) {
|
|
19936
|
+
assertions.push(
|
|
19937
|
+
assertionPassed(
|
|
19938
|
+
"code",
|
|
19939
|
+
() => assertMatches(
|
|
19940
|
+
`Generated code for ${prefix}`,
|
|
19941
|
+
codeText,
|
|
19942
|
+
expect.codeIncludes,
|
|
19943
|
+
expect.codeExcludes
|
|
19944
|
+
)
|
|
19945
|
+
)
|
|
19946
|
+
);
|
|
19947
|
+
}
|
|
19948
|
+
if (hasMatchers(expect.actions?.required) || hasMatchers(expect.actions?.forbidden)) {
|
|
19949
|
+
assertions.push(
|
|
19950
|
+
assertionPassed(
|
|
19951
|
+
"required-actions",
|
|
19952
|
+
() => assertMatches(
|
|
19953
|
+
`Required actions for ${prefix}`,
|
|
19954
|
+
actionText,
|
|
19955
|
+
expect.actions?.required,
|
|
19956
|
+
expect.actions?.forbidden
|
|
19957
|
+
)
|
|
19958
|
+
)
|
|
19959
|
+
);
|
|
19960
|
+
}
|
|
19961
|
+
if (hasMatchers(expect.presentation?.mustMention) || hasMatchers(expect.presentation?.mustNotMention)) {
|
|
19962
|
+
assertions.push(
|
|
19963
|
+
assertionPassed(
|
|
19964
|
+
"presentation",
|
|
19965
|
+
() => assertMatches(
|
|
19966
|
+
`Presentation for ${prefix}`,
|
|
19967
|
+
input.completed.responseText,
|
|
19968
|
+
expect.presentation?.mustMention,
|
|
19969
|
+
expect.presentation?.mustNotMention
|
|
19970
|
+
)
|
|
19971
|
+
)
|
|
19972
|
+
);
|
|
19973
|
+
}
|
|
19974
|
+
if (hasMatchers(expect.presentation?.mustDisplayOrSave)) {
|
|
19975
|
+
assertions.push(
|
|
19976
|
+
assertionPassed(
|
|
19977
|
+
"display",
|
|
19978
|
+
() => assertMatches(
|
|
19979
|
+
`Displayed or saved records for ${prefix}`,
|
|
19980
|
+
displaySurface,
|
|
19981
|
+
expect.presentation?.mustDisplayOrSave
|
|
19982
|
+
)
|
|
19983
|
+
)
|
|
19984
|
+
);
|
|
19985
|
+
}
|
|
19986
|
+
if (expect.prompts?.requiredChoiceWhenAmbiguous) {
|
|
19987
|
+
assertions.push(
|
|
19988
|
+
assertionPassed("choice", () => {
|
|
19989
|
+
if (!input.completed.promptInteractions.some(
|
|
19990
|
+
(interaction) => interaction.type === "choice"
|
|
19991
|
+
)) {
|
|
19992
|
+
throw new Error(`Expected ${prefix} to use a choice prompt.`);
|
|
19993
|
+
}
|
|
19994
|
+
})
|
|
19995
|
+
);
|
|
19996
|
+
}
|
|
19997
|
+
for (const forbiddenType of expect.prompts?.forbiddenPromptTypes || []) {
|
|
19998
|
+
assertions.push(
|
|
19999
|
+
assertionPassed(`forbidden-prompt:${forbiddenType}`, () => {
|
|
20000
|
+
if (input.completed.promptInteractions.some(
|
|
20001
|
+
(interaction) => interaction.type === forbiddenType
|
|
20002
|
+
)) {
|
|
20003
|
+
throw new Error(
|
|
20004
|
+
`Prompt interactions for ${prefix} used forbidden prompt type ${forbiddenType}.`
|
|
20005
|
+
);
|
|
20006
|
+
}
|
|
20007
|
+
})
|
|
20008
|
+
);
|
|
20009
|
+
}
|
|
20010
|
+
if (expect.prompts?.requiredConfirmationBefore?.length) {
|
|
20011
|
+
assertions.push(
|
|
20012
|
+
assertionPassed(
|
|
20013
|
+
"confirmation",
|
|
20014
|
+
() => assertMatches(
|
|
20015
|
+
`Confirmation prompts for ${prefix}`,
|
|
20016
|
+
[actionText, promptSurface].join("\n"),
|
|
20017
|
+
expect.prompts?.requiredConfirmationBefore
|
|
20018
|
+
)
|
|
20019
|
+
)
|
|
20020
|
+
);
|
|
20021
|
+
}
|
|
20022
|
+
return assertions;
|
|
20023
|
+
}
|
|
19160
20024
|
async function runAgentEvalSuite(options) {
|
|
19161
20025
|
const results = [];
|
|
19162
20026
|
for (const scenario of options.scenarios) {
|
|
20027
|
+
await options.harness.emitProgress?.({
|
|
20028
|
+
phase: "scenario",
|
|
20029
|
+
status: "running",
|
|
20030
|
+
scenarioId: scenario.id,
|
|
20031
|
+
title: "Scenario started",
|
|
20032
|
+
message: scenario.description || scenario.request || scenario.id,
|
|
20033
|
+
data: {
|
|
20034
|
+
scenarioId: scenario.id,
|
|
20035
|
+
behaviorBuckets: scenario.behaviorBuckets
|
|
20036
|
+
}
|
|
20037
|
+
});
|
|
19163
20038
|
let attempt = 0;
|
|
19164
20039
|
let finalResult = null;
|
|
19165
20040
|
while (attempt < 2 && !finalResult) {
|
|
@@ -19230,27 +20105,38 @@ async function runAgentEvalSuite(options) {
|
|
|
19230
20105
|
},
|
|
19231
20106
|
assertMatches
|
|
19232
20107
|
};
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
step.
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
)
|
|
20108
|
+
const assertions = evaluateExpectationAssertions({
|
|
20109
|
+
scenarioId: scenario.id,
|
|
20110
|
+
stepIndex: index,
|
|
20111
|
+
expect: step.expect,
|
|
20112
|
+
completed
|
|
20113
|
+
});
|
|
20114
|
+
for (const assertion of assertions) {
|
|
20115
|
+
await options.harness.emitProgress?.({
|
|
20116
|
+
phase: "assertion",
|
|
20117
|
+
status: assertion.status,
|
|
20118
|
+
scenarioId: scenario.id,
|
|
20119
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20120
|
+
title: assertion.label,
|
|
20121
|
+
message: assertion.message,
|
|
20122
|
+
data: assertion
|
|
20123
|
+
});
|
|
20124
|
+
}
|
|
20125
|
+
const failedAssertion = assertions.find(
|
|
20126
|
+
(assertion) => assertion.status === "failed"
|
|
20127
|
+
);
|
|
20128
|
+
if (failedAssertion) {
|
|
20129
|
+
throw new Error(failedAssertion.message || failedAssertion.label);
|
|
19252
20130
|
}
|
|
19253
20131
|
for (const inspection of stepInspections) {
|
|
20132
|
+
await options.harness.emitProgress?.({
|
|
20133
|
+
phase: "inspection",
|
|
20134
|
+
status: "running",
|
|
20135
|
+
scenarioId: scenario.id,
|
|
20136
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20137
|
+
title: "Running step inspection",
|
|
20138
|
+
message: inspection.code.slice(0, 500)
|
|
20139
|
+
});
|
|
19254
20140
|
const inspectionResult = await context.inspect(inspection.code);
|
|
19255
20141
|
const inspectionText = JSON.stringify(inspectionResult, null, 2);
|
|
19256
20142
|
assertMatches(
|
|
@@ -19266,9 +20152,32 @@ async function runAgentEvalSuite(options) {
|
|
|
19266
20152
|
});
|
|
19267
20153
|
}
|
|
19268
20154
|
inspectionResults.push(inspectionResult);
|
|
20155
|
+
await options.harness.emitProgress?.({
|
|
20156
|
+
phase: "inspection",
|
|
20157
|
+
status: "passed",
|
|
20158
|
+
scenarioId: scenario.id,
|
|
20159
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20160
|
+
title: "Step inspection passed",
|
|
20161
|
+
message: inspectionText.slice(0, 800),
|
|
20162
|
+
data: inspectionResult
|
|
20163
|
+
});
|
|
19269
20164
|
}
|
|
19270
20165
|
for (const check of stepChecks) {
|
|
20166
|
+
await options.harness.emitProgress?.({
|
|
20167
|
+
phase: "check",
|
|
20168
|
+
status: "running",
|
|
20169
|
+
scenarioId: scenario.id,
|
|
20170
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20171
|
+
title: "Running custom check"
|
|
20172
|
+
});
|
|
19271
20173
|
await check(context);
|
|
20174
|
+
await options.harness.emitProgress?.({
|
|
20175
|
+
phase: "check",
|
|
20176
|
+
status: "passed",
|
|
20177
|
+
scenarioId: scenario.id,
|
|
20178
|
+
stepId: step.id || `step-${index + 1}`,
|
|
20179
|
+
title: "Custom check passed"
|
|
20180
|
+
});
|
|
19272
20181
|
}
|
|
19273
20182
|
stepResults.push({
|
|
19274
20183
|
id: step.id || `step-${index + 1}`,
|
|
@@ -19279,6 +20188,7 @@ async function runAgentEvalSuite(options) {
|
|
|
19279
20188
|
actionSummary: completed.actionSummary,
|
|
19280
20189
|
promptInteractions: completed.promptInteractions,
|
|
19281
20190
|
inspectionResults,
|
|
20191
|
+
assertions,
|
|
19282
20192
|
turnDir: completed.turnDir
|
|
19283
20193
|
});
|
|
19284
20194
|
}
|
|
@@ -19297,6 +20207,7 @@ async function runAgentEvalSuite(options) {
|
|
|
19297
20207
|
actionSummary: lastStep.actionSummary,
|
|
19298
20208
|
promptInteractions: lastStep.promptInteractions,
|
|
19299
20209
|
verification: lastStep.inspectionResults.length <= 1 ? lastStep.inspectionResults[0] ?? null : lastStep.inspectionResults,
|
|
20210
|
+
assertions: stepResults.flatMap((step) => step.assertions || []),
|
|
19300
20211
|
tokenUsage: aggregateConversationTokenUsage(conversation),
|
|
19301
20212
|
steps: stepResults,
|
|
19302
20213
|
turnDir: conversation.artifactDir
|
|
@@ -19318,6 +20229,14 @@ async function runAgentEvalSuite(options) {
|
|
|
19318
20229
|
conversation,
|
|
19319
20230
|
result
|
|
19320
20231
|
});
|
|
20232
|
+
await options.harness.emitProgress?.({
|
|
20233
|
+
phase: "scenario",
|
|
20234
|
+
status: "passed",
|
|
20235
|
+
scenarioId: scenario.id,
|
|
20236
|
+
title: "Scenario passed",
|
|
20237
|
+
message: `${result.assertions?.filter((assertion) => assertion.status === "passed").length || 0}/${result.assertions?.length || 0} assertions`,
|
|
20238
|
+
data: result
|
|
20239
|
+
});
|
|
19321
20240
|
finalResult = result;
|
|
19322
20241
|
} catch (error) {
|
|
19323
20242
|
const failureMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -19358,6 +20277,14 @@ async function runAgentEvalSuite(options) {
|
|
|
19358
20277
|
result: failed,
|
|
19359
20278
|
error: failureMessage
|
|
19360
20279
|
});
|
|
20280
|
+
await options.harness.emitProgress?.({
|
|
20281
|
+
phase: "scenario",
|
|
20282
|
+
status: "failed",
|
|
20283
|
+
scenarioId: scenario.id,
|
|
20284
|
+
title: "Scenario failed",
|
|
20285
|
+
message: failureMessage,
|
|
20286
|
+
data: failed
|
|
20287
|
+
});
|
|
19361
20288
|
finalResult = failed;
|
|
19362
20289
|
} finally {
|
|
19363
20290
|
await options.harness.closeConversation(conversation);
|
|
@@ -19406,6 +20333,11 @@ function createAgentEvalHarness(options) {
|
|
|
19406
20333
|
const chatTimeoutMs = options.chatTimeoutMs ?? 12e4;
|
|
19407
20334
|
const jobTimeoutMs = options.jobTimeoutMs ?? 9e4;
|
|
19408
20335
|
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
20336
|
+
const resolvedTemplate = resolveHarnessTemplate(
|
|
20337
|
+
options.harnessTemplateId || process.env.GRANULAR_AGENT_HARNESS_TEMPLATE || "stable");
|
|
20338
|
+
const promptRenderer = options.promptRenderer || resolvedTemplate.renderPrompt;
|
|
20339
|
+
const continuationRenderer = options.continuationRenderer || resolvedTemplate.renderContinuation;
|
|
20340
|
+
const onProgress = options.onProgress;
|
|
19409
20341
|
async function openConversation(label) {
|
|
19410
20342
|
await ensureDir(artifactDir);
|
|
19411
20343
|
const clientId = `${slugify(label)}-${Date.now()}`;
|
|
@@ -19474,6 +20406,13 @@ function createAgentEvalHarness(options) {
|
|
|
19474
20406
|
};
|
|
19475
20407
|
}
|
|
19476
20408
|
async function runInspection(conversation, inspection, completed, turnDir) {
|
|
20409
|
+
await emitProgress(onProgress, {
|
|
20410
|
+
phase: "inspection",
|
|
20411
|
+
status: "running",
|
|
20412
|
+
scenarioId: conversation.label,
|
|
20413
|
+
title: "Running inspection",
|
|
20414
|
+
message: inspection.code.slice(0, 500)
|
|
20415
|
+
});
|
|
19477
20416
|
let result = null;
|
|
19478
20417
|
let lastError = null;
|
|
19479
20418
|
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
@@ -19501,6 +20440,14 @@ function createAgentEvalHarness(options) {
|
|
|
19501
20440
|
});
|
|
19502
20441
|
}
|
|
19503
20442
|
await writeJson(path__default.default.join(turnDir, "verification.json"), result);
|
|
20443
|
+
await emitProgress(onProgress, {
|
|
20444
|
+
phase: "inspection",
|
|
20445
|
+
status: "passed",
|
|
20446
|
+
scenarioId: conversation.label,
|
|
20447
|
+
title: "Inspection passed",
|
|
20448
|
+
message: JSON.stringify(result)?.slice(0, 800),
|
|
20449
|
+
data: result
|
|
20450
|
+
});
|
|
19504
20451
|
return result;
|
|
19505
20452
|
}
|
|
19506
20453
|
async function resumePendingTurn(pending, responder) {
|
|
@@ -19510,6 +20457,16 @@ function createAgentEvalHarness(options) {
|
|
|
19510
20457
|
prompt,
|
|
19511
20458
|
history: pending.promptInteractions
|
|
19512
20459
|
});
|
|
20460
|
+
await emitProgress(onProgress, {
|
|
20461
|
+
phase: "interaction",
|
|
20462
|
+
status: "running",
|
|
20463
|
+
scenarioId: pending.conversation.label,
|
|
20464
|
+
stepId: path__default.default.basename(pending.turnDir),
|
|
20465
|
+
jobId: pending.job.id,
|
|
20466
|
+
title: "Prompt answered",
|
|
20467
|
+
message: `${prompt.type}: ${prompt.message || prompt.title} -> ${JSON.stringify(answer)}`,
|
|
20468
|
+
data: { prompt, answer }
|
|
20469
|
+
});
|
|
19513
20470
|
const session = pending.conversation.environment;
|
|
19514
20471
|
await session.answerPrompt(prompt.id, answer);
|
|
19515
20472
|
pending.promptInteractions.push({
|
|
@@ -19529,7 +20486,12 @@ function createAgentEvalHarness(options) {
|
|
|
19529
20486
|
job: pending.job,
|
|
19530
20487
|
boundaryTimestamp: pending.boundaryTimestamp,
|
|
19531
20488
|
timeoutMs: jobTimeoutMs,
|
|
19532
|
-
pollIntervalMs
|
|
20489
|
+
pollIntervalMs,
|
|
20490
|
+
onProgress: (event) => void onProgress?.(event),
|
|
20491
|
+
progressContext: {
|
|
20492
|
+
scenarioId: pending.conversation.label,
|
|
20493
|
+
stepId: path__default.default.basename(pending.turnDir)
|
|
20494
|
+
}
|
|
19533
20495
|
});
|
|
19534
20496
|
if (resumed.kind === "prompt") {
|
|
19535
20497
|
return {
|
|
@@ -19610,12 +20572,44 @@ function createAgentEvalHarness(options) {
|
|
|
19610
20572
|
};
|
|
19611
20573
|
conversation.logTurns.push(turnLog);
|
|
19612
20574
|
if (input.prepareRecords?.length) {
|
|
20575
|
+
await emitProgress(onProgress, {
|
|
20576
|
+
phase: "setup",
|
|
20577
|
+
status: "running",
|
|
20578
|
+
scenarioId: conversation.label,
|
|
20579
|
+
stepId: turnId,
|
|
20580
|
+
title: "Recording setup records",
|
|
20581
|
+
message: `${input.prepareRecords.length} records`,
|
|
20582
|
+
data: input.prepareRecords
|
|
20583
|
+
});
|
|
19613
20584
|
await conversation.environment.recordObjects(input.prepareRecords);
|
|
20585
|
+
await emitProgress(onProgress, {
|
|
20586
|
+
phase: "setup",
|
|
20587
|
+
status: "passed",
|
|
20588
|
+
scenarioId: conversation.label,
|
|
20589
|
+
stepId: turnId,
|
|
20590
|
+
title: "Setup records recorded",
|
|
20591
|
+
message: `${input.prepareRecords.length} records`
|
|
20592
|
+
});
|
|
19614
20593
|
}
|
|
19615
20594
|
if (input.prepareTools?.length) {
|
|
20595
|
+
await emitProgress(onProgress, {
|
|
20596
|
+
phase: "setup",
|
|
20597
|
+
status: "running",
|
|
20598
|
+
scenarioId: conversation.label,
|
|
20599
|
+
stepId: turnId,
|
|
20600
|
+
title: "Registering effect handlers",
|
|
20601
|
+
message: `${input.prepareTools.length} handlers`
|
|
20602
|
+
});
|
|
19616
20603
|
await options.granular.ontology(conversation.environment.sandboxId).effects.registerMany(input.prepareTools);
|
|
19617
20604
|
}
|
|
19618
20605
|
if (input.prepare) {
|
|
20606
|
+
await emitProgress(onProgress, {
|
|
20607
|
+
phase: "setup",
|
|
20608
|
+
status: "running",
|
|
20609
|
+
scenarioId: conversation.label,
|
|
20610
|
+
stepId: turnId,
|
|
20611
|
+
title: "Running custom setup"
|
|
20612
|
+
});
|
|
19619
20613
|
await input.prepare({
|
|
19620
20614
|
conversation,
|
|
19621
20615
|
environment: conversation.environment,
|
|
@@ -19624,6 +20618,14 @@ function createAgentEvalHarness(options) {
|
|
|
19624
20618
|
}
|
|
19625
20619
|
const boundaryTimestamp = Date.now();
|
|
19626
20620
|
conversation.history.push({ role: "user", content: input.request });
|
|
20621
|
+
await emitProgress(onProgress, {
|
|
20622
|
+
phase: "step",
|
|
20623
|
+
status: "running",
|
|
20624
|
+
scenarioId: conversation.label,
|
|
20625
|
+
stepId: turnId,
|
|
20626
|
+
title: "User request",
|
|
20627
|
+
message: input.request
|
|
20628
|
+
});
|
|
19627
20629
|
await writeJson(path__default.default.join(turnDir, "request.json"), {
|
|
19628
20630
|
request: input.request,
|
|
19629
20631
|
boundaryTimestamp
|
|
@@ -19665,7 +20667,7 @@ function createAgentEvalHarness(options) {
|
|
|
19665
20667
|
inputSchema: tool.inputSchema,
|
|
19666
20668
|
outputSchema: tool.outputSchema
|
|
19667
20669
|
}));
|
|
19668
|
-
const
|
|
20670
|
+
const renderedPrompt = promptRenderer({
|
|
19669
20671
|
domainDocumentation: await conversation.environment.getDomainDocumentation(),
|
|
19670
20672
|
sessionContext: {
|
|
19671
20673
|
sandboxId: conversation.environment.sandboxId,
|
|
@@ -19686,9 +20688,39 @@ function createAgentEvalHarness(options) {
|
|
|
19686
20688
|
tools,
|
|
19687
20689
|
checkpoint: latestCheckpoint
|
|
19688
20690
|
});
|
|
19689
|
-
const
|
|
20691
|
+
const systemPrompt = renderedPrompt.prompt;
|
|
20692
|
+
await emitProgress(onProgress, {
|
|
20693
|
+
phase: "prompt",
|
|
20694
|
+
status: "passed",
|
|
20695
|
+
scenarioId: conversation.label,
|
|
20696
|
+
stepId: turnId,
|
|
20697
|
+
iteration: iteration + 1,
|
|
20698
|
+
templateId: renderedPrompt.templateId,
|
|
20699
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20700
|
+
title: "Rendered harness prompt",
|
|
20701
|
+
message: `${systemPrompt.split("\n").length} lines`,
|
|
20702
|
+
data: {
|
|
20703
|
+
templateId: renderedPrompt.templateId,
|
|
20704
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20705
|
+
templateHash: renderedPrompt.templateHash,
|
|
20706
|
+
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
20707
|
+
prompt: systemPrompt
|
|
20708
|
+
}
|
|
20709
|
+
});
|
|
20710
|
+
const request = iteration === 0 ? input.request : continuationRenderer(
|
|
19690
20711
|
buildContinuationPreview(latestCheckpoint, noProgressCount)
|
|
19691
|
-
);
|
|
20712
|
+
).instruction;
|
|
20713
|
+
await emitProgress(onProgress, {
|
|
20714
|
+
phase: "generation",
|
|
20715
|
+
status: "running",
|
|
20716
|
+
scenarioId: conversation.label,
|
|
20717
|
+
stepId: turnId,
|
|
20718
|
+
iteration: iteration + 1,
|
|
20719
|
+
templateId: renderedPrompt.templateId,
|
|
20720
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20721
|
+
title: iteration === 0 ? "Generating agent response" : "Generating continuation",
|
|
20722
|
+
message: request
|
|
20723
|
+
});
|
|
19692
20724
|
const generation = await withTimeout2(
|
|
19693
20725
|
generateTurnWithRepair(options.generator, {
|
|
19694
20726
|
systemPrompt,
|
|
@@ -19707,10 +20739,31 @@ function createAgentEvalHarness(options) {
|
|
|
19707
20739
|
chatTimeoutMs,
|
|
19708
20740
|
`chat generation for ${conversation.label} iteration ${iteration + 1}`
|
|
19709
20741
|
);
|
|
20742
|
+
await emitProgress(onProgress, {
|
|
20743
|
+
phase: "generation",
|
|
20744
|
+
status: "passed",
|
|
20745
|
+
scenarioId: conversation.label,
|
|
20746
|
+
stepId: turnId,
|
|
20747
|
+
iteration: iteration + 1,
|
|
20748
|
+
templateId: renderedPrompt.templateId,
|
|
20749
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20750
|
+
title: generation.code ? "Generated job code" : "Generated text reply",
|
|
20751
|
+
message: generation.code || generation.reply || "",
|
|
20752
|
+
data: {
|
|
20753
|
+
reply: generation.reply,
|
|
20754
|
+
code: generation.code,
|
|
20755
|
+
attempts: generation.generationAttempts,
|
|
20756
|
+
usage: tokenUsageForGenerationOutput(generation)
|
|
20757
|
+
}
|
|
20758
|
+
});
|
|
19710
20759
|
const iterationLog = {
|
|
19711
20760
|
iteration: iteration + 1,
|
|
19712
20761
|
request,
|
|
19713
20762
|
systemPrompt,
|
|
20763
|
+
templateId: renderedPrompt.templateId,
|
|
20764
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20765
|
+
templateHash: renderedPrompt.templateHash,
|
|
20766
|
+
promptInstanceHash: renderedPrompt.promptInstanceHash,
|
|
19714
20767
|
generationReply: generation.reply,
|
|
19715
20768
|
generatedCode: generation.code,
|
|
19716
20769
|
rawGeneration: generation.raw,
|
|
@@ -19757,6 +20810,15 @@ function createAgentEvalHarness(options) {
|
|
|
19757
20810
|
result: completed.result
|
|
19758
20811
|
};
|
|
19759
20812
|
await writeJson(path__default.default.join(turnDir, "result.json"), completed);
|
|
20813
|
+
await emitProgress(onProgress, {
|
|
20814
|
+
phase: "step",
|
|
20815
|
+
status: "passed",
|
|
20816
|
+
scenarioId: conversation.label,
|
|
20817
|
+
stepId: turnId,
|
|
20818
|
+
title: "Step completed with text reply",
|
|
20819
|
+
message: responseText2,
|
|
20820
|
+
data: completed
|
|
20821
|
+
});
|
|
19760
20822
|
return completed;
|
|
19761
20823
|
}
|
|
19762
20824
|
const session = conversation.environment;
|
|
@@ -19777,12 +20839,33 @@ function createAgentEvalHarness(options) {
|
|
|
19777
20839
|
)
|
|
19778
20840
|
}
|
|
19779
20841
|
});
|
|
20842
|
+
await emitProgress(onProgress, {
|
|
20843
|
+
phase: "job",
|
|
20844
|
+
status: "running",
|
|
20845
|
+
scenarioId: conversation.label,
|
|
20846
|
+
stepId: turnId,
|
|
20847
|
+
iteration: iteration + 1,
|
|
20848
|
+
jobId: job.id,
|
|
20849
|
+
templateId: renderedPrompt.templateId,
|
|
20850
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20851
|
+
title: "Submitted Granular job",
|
|
20852
|
+
message: job.id,
|
|
20853
|
+
data: { code: generation.code }
|
|
20854
|
+
});
|
|
19780
20855
|
const outcome = await waitForJobOutcome({
|
|
19781
20856
|
environment: conversation.environment,
|
|
19782
20857
|
job,
|
|
19783
20858
|
boundaryTimestamp,
|
|
19784
20859
|
timeoutMs: jobTimeoutMs,
|
|
19785
|
-
pollIntervalMs
|
|
20860
|
+
pollIntervalMs,
|
|
20861
|
+
onProgress: (event) => void onProgress?.(event),
|
|
20862
|
+
progressContext: {
|
|
20863
|
+
scenarioId: conversation.label,
|
|
20864
|
+
stepId: turnId,
|
|
20865
|
+
iteration: iteration + 1,
|
|
20866
|
+
templateId: renderedPrompt.templateId,
|
|
20867
|
+
templateVersion: renderedPrompt.templateVersion
|
|
20868
|
+
}
|
|
19786
20869
|
});
|
|
19787
20870
|
if (outcome.kind === "prompt") {
|
|
19788
20871
|
if (!autoAnswerPrompts) {
|
|
@@ -19892,6 +20975,23 @@ function createAgentEvalHarness(options) {
|
|
|
19892
20975
|
controllerReason: continuation.reason,
|
|
19893
20976
|
noProgressCount: continuation.nextNoProgressCount
|
|
19894
20977
|
};
|
|
20978
|
+
await emitProgress(onProgress, {
|
|
20979
|
+
phase: "continuation",
|
|
20980
|
+
status: continuation.shouldContinue ? "running" : "passed",
|
|
20981
|
+
scenarioId: conversation.label,
|
|
20982
|
+
stepId: turnId,
|
|
20983
|
+
iteration: iteration + 1,
|
|
20984
|
+
jobId: job.id,
|
|
20985
|
+
templateId: renderedPrompt.templateId,
|
|
20986
|
+
templateVersion: renderedPrompt.templateVersion,
|
|
20987
|
+
title: continuation.shouldContinue ? "Harness requested another loop" : "Harness accepted completion",
|
|
20988
|
+
message: `${continuation.reason}; ${continuation.outcome}`,
|
|
20989
|
+
data: {
|
|
20990
|
+
continuation,
|
|
20991
|
+
checkpoint: latestCheckpoint,
|
|
20992
|
+
verifierSnapshot
|
|
20993
|
+
}
|
|
20994
|
+
});
|
|
19895
20995
|
previousSnapshot = verifierSnapshot;
|
|
19896
20996
|
noProgressCount = continuation.nextNoProgressCount;
|
|
19897
20997
|
conversation.history.push({
|
|
@@ -19945,6 +21045,17 @@ function createAgentEvalHarness(options) {
|
|
|
19945
21045
|
result: outcome.result
|
|
19946
21046
|
};
|
|
19947
21047
|
await writeJson(path__default.default.join(turnDir, "result.json"), completed);
|
|
21048
|
+
await emitProgress(onProgress, {
|
|
21049
|
+
phase: "step",
|
|
21050
|
+
status: "passed",
|
|
21051
|
+
scenarioId: conversation.label,
|
|
21052
|
+
stepId: turnId,
|
|
21053
|
+
iteration: iteration + 1,
|
|
21054
|
+
jobId: job.id,
|
|
21055
|
+
title: "Step completed",
|
|
21056
|
+
message: responseText,
|
|
21057
|
+
data: completed
|
|
21058
|
+
});
|
|
19948
21059
|
return completed;
|
|
19949
21060
|
}
|
|
19950
21061
|
iteration += 1;
|
|
@@ -19956,6 +21067,7 @@ function createAgentEvalHarness(options) {
|
|
|
19956
21067
|
return {
|
|
19957
21068
|
artifactDir,
|
|
19958
21069
|
granular: options.granular,
|
|
21070
|
+
emitProgress: (event) => emitProgress(onProgress, event),
|
|
19959
21071
|
openConversation,
|
|
19960
21072
|
closeConversation,
|
|
19961
21073
|
runTurn,
|
|
@@ -20021,7 +21133,11 @@ function createAgentTester(options) {
|
|
|
20021
21133
|
controllerBudgets: options.controllerBudgets,
|
|
20022
21134
|
chatTimeoutMs: options.chatTimeoutMs,
|
|
20023
21135
|
jobTimeoutMs: options.jobTimeoutMs,
|
|
20024
|
-
pollIntervalMs: options.pollIntervalMs
|
|
21136
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
21137
|
+
harnessTemplateId: options.harnessTemplateId,
|
|
21138
|
+
promptRenderer: options.promptRenderer,
|
|
21139
|
+
continuationRenderer: options.continuationRenderer,
|
|
21140
|
+
onProgress: options.onProgress
|
|
20025
21141
|
});
|
|
20026
21142
|
return {
|
|
20027
21143
|
...harness,
|
|
@@ -20056,7 +21172,9 @@ exports.createScriptedPromptResponder = createScriptedPromptResponder;
|
|
|
20056
21172
|
exports.createTestArtifactsDirectory = createTestArtifactsDirectory;
|
|
20057
21173
|
exports.createTimestampedArtifactDirectory = createTimestampedArtifactDirectory;
|
|
20058
21174
|
exports.generateTurnWithRepair = generateTurnWithRepair;
|
|
21175
|
+
exports.loadAgentEvalScenarioFile = loadAgentEvalScenarioFile;
|
|
20059
21176
|
exports.runAgentEvalSuite = runAgentEvalSuite;
|
|
20060
21177
|
exports.runAgentTests = runAgentTests;
|
|
21178
|
+
exports.scenariosFromAgentEvalFile = scenariosFromAgentEvalFile;
|
|
20061
21179
|
//# sourceMappingURL=agent-evals.js.map
|
|
20062
21180
|
//# sourceMappingURL=agent-evals.js.map
|