@modelprofile.com/flexharness 10.11.0 → 10.13.0
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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.flexharness.d.ts +21 -2
- package/dist_ts/classes.flexharness.js +430 -63
- package/dist_ts/classes.toolcatalog.d.ts +80 -0
- package/dist_ts/classes.toolcatalog.js +1336 -0
- package/dist_ts/errors.d.ts +5 -0
- package/dist_ts/errors.js +10 -1
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/interfaces.d.ts +179 -2
- package/dist_ts/interfaces.js +29 -1
- package/dist_ts/plugins.d.ts +7 -3
- package/dist_ts/plugins.js +7 -3
- package/dist_ts/utils.harnessoptions.d.ts +2 -1
- package/dist_ts/utils.harnessoptions.js +19 -1
- package/dist_ts/utils.json.js +37 -2
- package/dist_ts/utils.schemadeclarations.d.ts +53 -0
- package/dist_ts/utils.schemadeclarations.js +315 -0
- package/dist_ts/utils.sessionmetrics.d.ts +17 -0
- package/dist_ts/utils.sessionmetrics.js +72 -0
- package/package.json +6 -5
- package/readme.md +58 -8
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexharness.ts +484 -58
- package/ts/classes.toolcatalog.ts +1431 -0
- package/ts/errors.ts +8 -0
- package/ts/index.ts +1 -0
- package/ts/interfaces.ts +198 -2
- package/ts/plugins.ts +10 -2
- package/ts/readme.md +58 -8
- package/ts/utils.harnessoptions.ts +22 -0
- package/ts/utils.json.ts +33 -1
- package/ts/utils.schemadeclarations.ts +322 -0
- package/ts/utils.sessionmetrics.ts +104 -0
- package/ts_chat_harness/readme.md +1 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders JSON Schema as TypeScript declarations for the tool catalog. The output depends only on
|
|
3
|
+
* the schema, so the same schema always renders to the same bytes.
|
|
4
|
+
*/
|
|
5
|
+
const identifierPattern = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
6
|
+
const maxRenderDepth = 32;
|
|
7
|
+
const maxInlineObjectCharacters = 100;
|
|
8
|
+
const maxSafeInteger = Number.MAX_SAFE_INTEGER;
|
|
9
|
+
export const isSchemaRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10
|
+
export const isIdentifier = (value) => identifierPattern.test(value);
|
|
11
|
+
const literal = (value) => {
|
|
12
|
+
if (typeof value === 'string')
|
|
13
|
+
return JSON.stringify(value);
|
|
14
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
15
|
+
return String(value);
|
|
16
|
+
if (typeof value === 'boolean' || value === null)
|
|
17
|
+
return String(value);
|
|
18
|
+
return 'unknown';
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Reports whether `character` occurs outside brackets, braces, parentheses, string literals and
|
|
22
|
+
* comments.
|
|
23
|
+
*/
|
|
24
|
+
const hasTopLevel = (text, character) => {
|
|
25
|
+
let depth = 0;
|
|
26
|
+
let quote;
|
|
27
|
+
for (let index = 0; index < text.length; index++) {
|
|
28
|
+
const current = text[index];
|
|
29
|
+
if (quote) {
|
|
30
|
+
if (current === '\\')
|
|
31
|
+
index++;
|
|
32
|
+
else if (current === quote)
|
|
33
|
+
quote = undefined;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (current === '/' && text[index + 1] === '*') {
|
|
37
|
+
const end = text.indexOf('*/', index + 2);
|
|
38
|
+
if (end === -1)
|
|
39
|
+
return false;
|
|
40
|
+
index = end + 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (current === '"' || current === "'")
|
|
44
|
+
quote = current;
|
|
45
|
+
else if (current === '{' || current === '[' || current === '(' || current === '<')
|
|
46
|
+
depth++;
|
|
47
|
+
else if (current === '}' || current === ']' || current === ')' || current === '>')
|
|
48
|
+
depth--;
|
|
49
|
+
else if (depth === 0 && current === character)
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
};
|
|
54
|
+
const union = (parts) => {
|
|
55
|
+
const unique = [...new Set(parts)];
|
|
56
|
+
if (unique.includes('unknown'))
|
|
57
|
+
return 'unknown';
|
|
58
|
+
const withoutNever = unique.length > 1 ? unique.filter((part) => part !== 'never') : unique;
|
|
59
|
+
return withoutNever.join(' | ');
|
|
60
|
+
};
|
|
61
|
+
const intersection = (parts) => {
|
|
62
|
+
const unique = [...new Set(parts)].filter((part) => part !== 'unknown');
|
|
63
|
+
if (unique.length === 0)
|
|
64
|
+
return 'unknown';
|
|
65
|
+
return unique.map((part) => hasTopLevel(part, '|') ? `(${part})` : part).join(' & ');
|
|
66
|
+
};
|
|
67
|
+
const arrayOf = (element) => hasTopLevel(element, '|') || hasTopLevel(element, '&') ? `(${element})[]` : `${element}[]`;
|
|
68
|
+
const propertyKey = (name) => isIdentifier(name) ? name : JSON.stringify(name);
|
|
69
|
+
/** A JSDoc block at `indent`; a short single line stays on one line. */
|
|
70
|
+
export const docBlock = (text, indent) => {
|
|
71
|
+
const lines = text.replace(/\*\//g, '*\\/').split('\n').map((line) => line.trimEnd());
|
|
72
|
+
if (lines.length === 1 && indent.length + lines[0].length <= 100)
|
|
73
|
+
return `${indent}/** ${lines[0]} */\n`;
|
|
74
|
+
return `${indent}/**\n${lines.map((line) => line ? `${indent} * ${line}` : `${indent} *`).join('\n')}\n${indent} */\n`;
|
|
75
|
+
};
|
|
76
|
+
export const countOf = (count, unit) => `${count} ${unit}${count === 1 ? '' : 's'}`;
|
|
77
|
+
/** Constraints a TypeScript type cannot state, in a short readable form. */
|
|
78
|
+
const constraintsOf = (schema) => {
|
|
79
|
+
const constraints = [];
|
|
80
|
+
const types = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
81
|
+
if (types.includes('integer'))
|
|
82
|
+
constraints.push('integer');
|
|
83
|
+
if (typeof schema.format === 'string')
|
|
84
|
+
constraints.push(`format ${schema.format}`);
|
|
85
|
+
const bound = (value) => typeof value === 'number' && Number.isFinite(value) && Math.abs(value) !== maxSafeInteger;
|
|
86
|
+
if (bound(schema.exclusiveMinimum))
|
|
87
|
+
constraints.push(`> ${schema.exclusiveMinimum}`);
|
|
88
|
+
else if (bound(schema.minimum))
|
|
89
|
+
constraints.push(`${schema.exclusiveMinimum === true ? '>' : '>='} ${schema.minimum}`);
|
|
90
|
+
if (bound(schema.exclusiveMaximum))
|
|
91
|
+
constraints.push(`< ${schema.exclusiveMaximum}`);
|
|
92
|
+
else if (bound(schema.maximum))
|
|
93
|
+
constraints.push(`${schema.exclusiveMaximum === true ? '<' : '<='} ${schema.maximum}`);
|
|
94
|
+
if (bound(schema.multipleOf))
|
|
95
|
+
constraints.push(`multiple of ${schema.multipleOf}`);
|
|
96
|
+
const range = (min, max, unit) => {
|
|
97
|
+
const hasMin = bound(min) && min > 0;
|
|
98
|
+
const hasMax = bound(max);
|
|
99
|
+
if (hasMin && hasMax)
|
|
100
|
+
constraints.push(min === max ? countOf(min, unit) : `${min}-${countOf(max, unit)}`);
|
|
101
|
+
else if (hasMin)
|
|
102
|
+
constraints.push(`at least ${countOf(min, unit)}`);
|
|
103
|
+
else if (hasMax)
|
|
104
|
+
constraints.push(`at most ${countOf(max, unit)}`);
|
|
105
|
+
};
|
|
106
|
+
range(schema.minLength, schema.maxLength, 'character');
|
|
107
|
+
range(schema.minItems, schema.maxItems, 'item');
|
|
108
|
+
if (schema.uniqueItems === true)
|
|
109
|
+
constraints.push('unique items');
|
|
110
|
+
if (typeof schema.pattern === 'string')
|
|
111
|
+
constraints.push(`pattern /${schema.pattern}/`);
|
|
112
|
+
if (schema.default !== undefined) {
|
|
113
|
+
const value = JSON.stringify(schema.default);
|
|
114
|
+
if (value !== undefined && value.length <= 60)
|
|
115
|
+
constraints.push(`default ${value}`);
|
|
116
|
+
}
|
|
117
|
+
if (schema.deprecated === true)
|
|
118
|
+
constraints.push('deprecated');
|
|
119
|
+
return constraints;
|
|
120
|
+
};
|
|
121
|
+
/** The documentation of a property: its description and the constraints its type cannot state. */
|
|
122
|
+
export const schemaDoc = (schema, description) => {
|
|
123
|
+
if (!isSchemaRecord(schema))
|
|
124
|
+
return description?.trim() || undefined;
|
|
125
|
+
const text = (description ?? (typeof schema.description === 'string' ? schema.description : '')).trim();
|
|
126
|
+
const constraints = constraintsOf(schema);
|
|
127
|
+
if (constraints.length === 0)
|
|
128
|
+
return text || undefined;
|
|
129
|
+
return text ? `${text} (${constraints.join(', ')})` : constraints.join(', ');
|
|
130
|
+
};
|
|
131
|
+
export class SchemaDeclarationWriter {
|
|
132
|
+
context;
|
|
133
|
+
used = new Set();
|
|
134
|
+
inlining = new Set();
|
|
135
|
+
constructor(context) {
|
|
136
|
+
this.context = context;
|
|
137
|
+
}
|
|
138
|
+
get usedTypes() {
|
|
139
|
+
return [...this.used].sort();
|
|
140
|
+
}
|
|
141
|
+
/** The TypeScript type of `schema`, with continuation lines indented relative to `indent`. */
|
|
142
|
+
type(schema, indent = '', depth = 0, omitMemberDocs = false) {
|
|
143
|
+
if (depth > maxRenderDepth)
|
|
144
|
+
return 'unknown';
|
|
145
|
+
if (schema === true)
|
|
146
|
+
return 'unknown';
|
|
147
|
+
if (schema === false)
|
|
148
|
+
return 'never';
|
|
149
|
+
if (!isSchemaRecord(schema))
|
|
150
|
+
return 'unknown';
|
|
151
|
+
const base = this.baseType(schema, indent, depth, omitMemberDocs);
|
|
152
|
+
return schema.nullable === true ? union([base, 'null']) : base;
|
|
153
|
+
}
|
|
154
|
+
/** The members of an object schema; undefined when the schema is not a plain object type. */
|
|
155
|
+
objectMembers(schema) {
|
|
156
|
+
if (!isSchemaRecord(schema) || !this.isPlainObject(schema))
|
|
157
|
+
return undefined;
|
|
158
|
+
const properties = isSchemaRecord(schema.properties) ? schema.properties : {};
|
|
159
|
+
return Object.entries(properties).map(([name, property]) => {
|
|
160
|
+
const doc = schemaDoc(property);
|
|
161
|
+
return { name, ...(doc === undefined ? {} : { doc }) };
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/** Whether an object schema requires none of its properties. */
|
|
165
|
+
hasNoRequiredProperties(schema) {
|
|
166
|
+
return isSchemaRecord(schema)
|
|
167
|
+
&& this.isPlainObject(schema)
|
|
168
|
+
&& !(Array.isArray(schema.required) && schema.required.length > 0);
|
|
169
|
+
}
|
|
170
|
+
/** `interface Name { … }` for a plain object schema, otherwise `type Name = …;`. */
|
|
171
|
+
namedDeclaration(name, schema, description) {
|
|
172
|
+
const doc = isSchemaRecord(schema)
|
|
173
|
+
? (description ?? (typeof schema.description === 'string' ? schema.description : undefined))?.trim()
|
|
174
|
+
: description?.trim();
|
|
175
|
+
const prefix = doc ? docBlock(doc, '') : '';
|
|
176
|
+
if (isSchemaRecord(schema) && this.isPlainObject(schema) && schema.nullable !== true) {
|
|
177
|
+
return `${prefix}interface ${name} ${this.objectType(schema, '', 0, false)}`;
|
|
178
|
+
}
|
|
179
|
+
return `${prefix}type ${name} = ${this.type(schema, '', 0)};`;
|
|
180
|
+
}
|
|
181
|
+
isPlainObject(schema) {
|
|
182
|
+
if (schema.$ref !== undefined || 'const' in schema || schema.enum !== undefined)
|
|
183
|
+
return false;
|
|
184
|
+
if (schema.anyOf !== undefined || schema.oneOf !== undefined || schema.allOf !== undefined)
|
|
185
|
+
return false;
|
|
186
|
+
if (schema.type === 'object')
|
|
187
|
+
return true;
|
|
188
|
+
return schema.type === undefined && isSchemaRecord(schema.properties);
|
|
189
|
+
}
|
|
190
|
+
baseType(schema, indent, depth, omitMemberDocs) {
|
|
191
|
+
if (typeof schema.$ref === 'string')
|
|
192
|
+
return this.reference(schema.$ref, indent, depth);
|
|
193
|
+
if ('const' in schema)
|
|
194
|
+
return literal(schema.const);
|
|
195
|
+
if (Array.isArray(schema.enum))
|
|
196
|
+
return schema.enum.length ? union(schema.enum.map(literal)) : 'never';
|
|
197
|
+
const alternatives = Array.isArray(schema.anyOf) ? schema.anyOf : Array.isArray(schema.oneOf) ? schema.oneOf : undefined;
|
|
198
|
+
if (alternatives?.length) {
|
|
199
|
+
return union(alternatives.map((alternative) => this.type(alternative, indent, depth + 1)));
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(schema.allOf) && schema.allOf.length) {
|
|
202
|
+
const own = { ...schema };
|
|
203
|
+
delete own.allOf;
|
|
204
|
+
const hasOwnShape = own.type !== undefined || own.properties !== undefined;
|
|
205
|
+
return intersection([
|
|
206
|
+
...schema.allOf.map((part) => this.type(part, indent, depth + 1)),
|
|
207
|
+
...(hasOwnShape ? [this.type(own, indent, depth + 1)] : []),
|
|
208
|
+
]);
|
|
209
|
+
}
|
|
210
|
+
const types = Array.isArray(schema.type)
|
|
211
|
+
? schema.type.filter((type) => typeof type === 'string')
|
|
212
|
+
: typeof schema.type === 'string'
|
|
213
|
+
? [schema.type]
|
|
214
|
+
: this.inferredTypes(schema);
|
|
215
|
+
if (types.length === 0)
|
|
216
|
+
return 'unknown';
|
|
217
|
+
return union(types.map((type) => {
|
|
218
|
+
switch (type) {
|
|
219
|
+
case 'string': return 'string';
|
|
220
|
+
case 'number':
|
|
221
|
+
case 'integer': return 'number';
|
|
222
|
+
case 'boolean': return 'boolean';
|
|
223
|
+
case 'null': return 'null';
|
|
224
|
+
case 'array': return this.arrayType(schema, indent, depth);
|
|
225
|
+
case 'object': return this.objectType(schema, indent, depth, omitMemberDocs);
|
|
226
|
+
default: return 'unknown';
|
|
227
|
+
}
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
inferredTypes(schema) {
|
|
231
|
+
if (schema.properties !== undefined
|
|
232
|
+
|| schema.additionalProperties !== undefined
|
|
233
|
+
|| schema.patternProperties !== undefined
|
|
234
|
+
|| schema.required !== undefined)
|
|
235
|
+
return ['object'];
|
|
236
|
+
if (schema.items !== undefined || schema.prefixItems !== undefined)
|
|
237
|
+
return ['array'];
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
reference(ref, indent, depth) {
|
|
241
|
+
const name = this.context.namedType(ref);
|
|
242
|
+
if (name) {
|
|
243
|
+
this.used.add(name);
|
|
244
|
+
return name;
|
|
245
|
+
}
|
|
246
|
+
const target = this.context.resolve(ref);
|
|
247
|
+
if (target === undefined || this.inlining.has(ref))
|
|
248
|
+
return 'unknown';
|
|
249
|
+
this.inlining.add(ref);
|
|
250
|
+
try {
|
|
251
|
+
return this.type(target, indent, depth + 1);
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
this.inlining.delete(ref);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
arrayType(schema, indent, depth) {
|
|
258
|
+
const tuple = Array.isArray(schema.prefixItems)
|
|
259
|
+
? schema.prefixItems
|
|
260
|
+
: Array.isArray(schema.items) ? schema.items : undefined;
|
|
261
|
+
if (tuple) {
|
|
262
|
+
const rest = Array.isArray(schema.prefixItems) ? schema.items : schema.additionalItems;
|
|
263
|
+
const members = tuple.map((item) => this.type(item, indent, depth + 1));
|
|
264
|
+
if (rest !== undefined && rest !== false) {
|
|
265
|
+
members.push(`...${arrayOf(this.type(rest, indent, depth + 1))}`);
|
|
266
|
+
}
|
|
267
|
+
return `[${members.join(', ')}]`;
|
|
268
|
+
}
|
|
269
|
+
if (schema.items === undefined)
|
|
270
|
+
return 'unknown[]';
|
|
271
|
+
return arrayOf(this.type(schema.items, indent, depth + 1));
|
|
272
|
+
}
|
|
273
|
+
objectType(schema, indent, depth, omitMemberDocs) {
|
|
274
|
+
const memberIndent = `${indent} `;
|
|
275
|
+
const properties = isSchemaRecord(schema.properties) ? schema.properties : {};
|
|
276
|
+
const required = new Set(Array.isArray(schema.required)
|
|
277
|
+
? schema.required.filter((name) => typeof name === 'string')
|
|
278
|
+
: []);
|
|
279
|
+
const members = [];
|
|
280
|
+
for (const [name, property] of Object.entries(properties)) {
|
|
281
|
+
const type = this.type(property, memberIndent, depth + 1);
|
|
282
|
+
const doc = omitMemberDocs ? undefined : schemaDoc(property);
|
|
283
|
+
members.push({
|
|
284
|
+
...(doc === undefined ? {} : { doc }),
|
|
285
|
+
text: `${propertyKey(name)}${required.has(name) ? '' : '?'}: ${type}`,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
const indexTypes = [];
|
|
289
|
+
if (isSchemaRecord(schema.patternProperties)) {
|
|
290
|
+
for (const property of Object.values(schema.patternProperties)) {
|
|
291
|
+
indexTypes.push(this.type(property, memberIndent, depth + 1));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (isSchemaRecord(schema.additionalProperties)) {
|
|
295
|
+
indexTypes.push(this.type(schema.additionalProperties, memberIndent, depth + 1));
|
|
296
|
+
}
|
|
297
|
+
else if (schema.additionalProperties === true && members.length > 0) {
|
|
298
|
+
indexTypes.push('unknown');
|
|
299
|
+
}
|
|
300
|
+
if (indexTypes.length)
|
|
301
|
+
members.push({ text: `[key: string]: ${union(indexTypes)}` });
|
|
302
|
+
if (members.length === 0)
|
|
303
|
+
return schema.additionalProperties === false ? '{}' : 'Record<string, unknown>';
|
|
304
|
+
if (members.every((member) => member.doc === undefined && !member.text.includes('\n'))) {
|
|
305
|
+
const inline = `{ ${members.map((member) => member.text).join('; ')} }`;
|
|
306
|
+
if (inline.length <= maxInlineObjectCharacters)
|
|
307
|
+
return inline;
|
|
308
|
+
}
|
|
309
|
+
const lines = members.map((member) => `${member.doc === undefined ? '' : docBlock(member.doc, memberIndent)}${memberIndent}${member.text};`);
|
|
310
|
+
return `{\n${lines.join('\n')}\n${indent}}`;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** Indents every non-empty line of `text`. */
|
|
314
|
+
export const indentLines = (text, indent) => text.split('\n').map((line) => line ? `${indent}${line}` : line).join('\n');
|
|
315
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuc2NoZW1hZGVjbGFyYXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdXRpbHMuc2NoZW1hZGVjbGFyYXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQWlCSCxNQUFNLGlCQUFpQixHQUFHLDRCQUE0QixDQUFDO0FBQ3ZELE1BQU0sY0FBYyxHQUFHLEVBQUUsQ0FBQztBQUMxQixNQUFNLHlCQUF5QixHQUFHLEdBQUcsQ0FBQztBQUN0QyxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7QUFFL0MsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBYyxFQUF1QyxFQUFFLENBQ3BGLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV2RSxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsQ0FBQyxLQUFhLEVBQVcsRUFBRSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV0RixNQUFNLE9BQU8sR0FBRyxDQUFDLEtBQWMsRUFBVSxFQUFFO0lBQ3pDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtRQUFFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM1RCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlFLElBQUksT0FBTyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJO1FBQUUsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkUsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyxDQUFDO0FBRUY7OztHQUdHO0FBQ0gsTUFBTSxXQUFXLEdBQUcsQ0FBQyxJQUFZLEVBQUUsU0FBaUIsRUFBVyxFQUFFO0lBQy9ELElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNkLElBQUksS0FBeUIsQ0FBQztJQUM5QixLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ2pELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QixJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsSUFBSSxPQUFPLEtBQUssSUFBSTtnQkFBRSxLQUFLLEVBQUUsQ0FBQztpQkFDekIsSUFBSSxPQUFPLEtBQUssS0FBSztnQkFBRSxLQUFLLEdBQUcsU0FBUyxDQUFDO1lBQzlDLFNBQVM7UUFDWCxDQUFDO1FBQ0QsSUFBSSxPQUFPLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDL0MsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQzFDLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQztnQkFBRSxPQUFPLEtBQUssQ0FBQztZQUM3QixLQUFLLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQztZQUNoQixTQUFTO1FBQ1gsQ0FBQztRQUNELElBQUksT0FBTyxLQUFLLEdBQUcsSUFBSSxPQUFPLEtBQUssR0FBRztZQUFFLEtBQUssR0FBRyxPQUFPLENBQUM7YUFDbkQsSUFBSSxPQUFPLEtBQUssR0FBRyxJQUFJLE9BQU8sS0FBSyxHQUFHLElBQUksT0FBTyxLQUFLLEdBQUcsSUFBSSxPQUFPLEtBQUssR0FBRztZQUFFLEtBQUssRUFBRSxDQUFDO2FBQ3RGLElBQUksT0FBTyxLQUFLLEdBQUcsSUFBSSxPQUFPLEtBQUssR0FBRyxJQUFJLE9BQU8sS0FBSyxHQUFHLElBQUksT0FBTyxLQUFLLEdBQUc7WUFBRSxLQUFLLEVBQUUsQ0FBQzthQUN0RixJQUFJLEtBQUssS0FBSyxDQUFDLElBQUksT0FBTyxLQUFLLFNBQVM7WUFBRSxPQUFPLElBQUksQ0FBQztJQUM3RCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDLENBQUM7QUFFRixNQUFNLEtBQUssR0FBRyxDQUFDLEtBQWUsRUFBVSxFQUFFO0lBQ3hDLE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ25DLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUNqRCxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDNUYsT0FBTyxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ2xDLENBQUMsQ0FBQztBQUVGLE1BQU0sWUFBWSxHQUFHLENBQUMsS0FBZSxFQUFVLEVBQUU7SUFDL0MsTUFBTSxNQUFNLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLEtBQUssU0FBUyxDQUFDLENBQUM7SUFDeEUsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUMxQyxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUN2RixDQUFDLENBQUM7QUFFRixNQUFNLE9BQU8sR0FBRyxDQUFDLE9BQWUsRUFBVSxFQUFFLENBQzFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLElBQUksV0FBVyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxPQUFPLElBQUksQ0FBQztBQUU3RixNQUFNLFdBQVcsR0FBRyxDQUFDLElBQVksRUFBVSxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7QUFFL0Ysd0VBQXdFO0FBQ3hFLE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxDQUFDLElBQVksRUFBRSxNQUFjLEVBQVUsRUFBRTtJQUMvRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN0RixJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxHQUFHO1FBQUUsT0FBTyxHQUFHLE1BQU0sT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztJQUN6RyxPQUFPLEdBQUcsTUFBTSxRQUFRLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLE1BQU0sSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssTUFBTSxPQUFPLENBQUM7QUFDekgsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLENBQUMsS0FBYSxFQUFFLElBQVksRUFBVSxFQUFFLENBQUMsR0FBRyxLQUFLLElBQUksSUFBSSxHQUFHLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7QUFFNUcsNEVBQTRFO0FBQzVFLE1BQU0sYUFBYSxHQUFHLENBQUMsTUFBa0MsRUFBWSxFQUFFO0lBQ3JFLE1BQU0sV0FBVyxHQUFhLEVBQUUsQ0FBQztJQUNqQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkUsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztRQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDM0QsSUFBSSxPQUFPLE1BQU0sQ0FBQyxNQUFNLEtBQUssUUFBUTtRQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsVUFBVSxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUNuRixNQUFNLEtBQUssR0FBRyxDQUFDLEtBQWMsRUFBbUIsRUFBRSxDQUNoRCxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLGNBQWMsQ0FBQztJQUM1RixJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7UUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssTUFBTSxDQUFDLGdCQUFnQixFQUFFLENBQUMsQ0FBQztTQUNoRixJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO1FBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZILElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztRQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO1NBQ2hGLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDdkgsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQztRQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUNuRixNQUFNLEtBQUssR0FBRyxDQUFDLEdBQVksRUFBRSxHQUFZLEVBQUUsSUFBWSxFQUFRLEVBQUU7UUFDL0QsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDckMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzFCLElBQUksTUFBTSxJQUFJLE1BQU07WUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2FBQ3JHLElBQUksTUFBTTtZQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxPQUFPLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQzthQUMvRCxJQUFJLE1BQU07WUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLFdBQVcsT0FBTyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDckUsQ0FBQyxDQUFDO0lBQ0YsS0FBSyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUN2RCxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hELElBQUksTUFBTSxDQUFDLFdBQVcsS0FBSyxJQUFJO1FBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUNsRSxJQUFJLE9BQU8sTUFBTSxDQUFDLE9BQU8sS0FBSyxRQUFRO1FBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLE1BQU0sQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ3hGLElBQUksTUFBTSxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUNqQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QyxJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxDQUFDLE1BQU0sSUFBSSxFQUFFO1lBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxXQUFXLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDdEYsQ0FBQztJQUNELElBQUksTUFBTSxDQUFDLFVBQVUsS0FBSyxJQUFJO1FBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMvRCxPQUFPLFdBQVcsQ0FBQztBQUNyQixDQUFDLENBQUM7QUFFRixrR0FBa0c7QUFDbEcsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBdUIsRUFBRSxXQUFvQixFQUFzQixFQUFFO0lBQzdGLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDO1FBQUUsT0FBTyxXQUFXLEVBQUUsSUFBSSxFQUFFLElBQUksU0FBUyxDQUFDO0lBQ3JFLE1BQU0sSUFBSSxHQUFHLENBQUMsV0FBVyxJQUFJLENBQUMsT0FBTyxNQUFNLENBQUMsV0FBVyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN4RyxNQUFNLFdBQVcsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDMUMsSUFBSSxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLElBQUksSUFBSSxTQUFTLENBQUM7SUFDdkQsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxLQUFLLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUMvRSxDQUFDLENBQUM7QUFFRixNQUFNLE9BQU8sdUJBQXVCO0lBSUw7SUFIWixJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUN6QixRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUU5QyxZQUE2QixPQUFrQztRQUFsQyxZQUFPLEdBQVAsT0FBTyxDQUEyQjtJQUFHLENBQUM7SUFFbkUsSUFBVyxTQUFTO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRUQsOEZBQThGO0lBQ3ZGLElBQUksQ0FBQyxNQUF1QixFQUFFLE1BQU0sR0FBRyxFQUFFLEVBQUUsS0FBSyxHQUFHLENBQUMsRUFBRSxjQUFjLEdBQUcsS0FBSztRQUNqRixJQUFJLEtBQUssR0FBRyxjQUFjO1lBQUUsT0FBTyxTQUFTLENBQUM7UUFDN0MsSUFBSSxNQUFNLEtBQUssSUFBSTtZQUFFLE9BQU8sU0FBUyxDQUFDO1FBQ3RDLElBQUksTUFBTSxLQUFLLEtBQUs7WUFBRSxPQUFPLE9BQU8sQ0FBQztRQUNyQyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQztZQUFFLE9BQU8sU0FBUyxDQUFDO1FBQzlDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDbEUsT0FBTyxNQUFNLENBQUMsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNqRSxDQUFDO0lBRUQsNkZBQTZGO0lBQ3RGLGFBQWEsQ0FDbEIsTUFBdUI7UUFFdkIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDO1lBQUUsT0FBTyxTQUFTLENBQUM7UUFDN0UsTUFBTSxVQUFVLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzlFLE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsRUFBRSxFQUFFO1lBQ3pELE1BQU0sR0FBRyxHQUFHLFNBQVMsQ0FBQyxRQUEyQixDQUFDLENBQUM7WUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLENBQUMsR0FBRyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUN6RCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxnRUFBZ0U7SUFDekQsdUJBQXVCLENBQUMsTUFBdUI7UUFDcEQsT0FBTyxjQUFjLENBQUMsTUFBTSxDQUFDO2VBQ3hCLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDO2VBQzFCLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBRUQsb0ZBQW9GO0lBQzdFLGdCQUFnQixDQUFDLElBQVksRUFBRSxNQUF1QixFQUFFLFdBQW9CO1FBQ2pGLE1BQU0sR0FBRyxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7WUFDaEMsQ0FBQyxDQUFDLENBQUMsV0FBVyxJQUFJLENBQUMsT0FBTyxNQUFNLENBQUMsV0FBVyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUU7WUFDcEcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUN4QixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM1QyxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDckYsT0FBTyxHQUFHLE1BQU0sYUFBYSxJQUFJLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQy9FLENBQUM7UUFDRCxPQUFPLEdBQUcsTUFBTSxRQUFRLElBQUksTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQztJQUNoRSxDQUFDO0lBRU8sYUFBYSxDQUFDLE1BQWtDO1FBQ3RELElBQUksTUFBTSxDQUFDLElBQUksS0FBSyxTQUFTLElBQUksT0FBTyxJQUFJLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxLQUFLLFNBQVM7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUM5RixJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3pHLElBQUksTUFBTSxDQUFDLElBQUksS0FBSyxRQUFRO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDMUMsT0FBTyxNQUFNLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxjQUFjLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7SUFFTyxRQUFRLENBQ2QsTUFBa0MsRUFDbEMsTUFBYyxFQUNkLEtBQWEsRUFDYixjQUF1QjtRQUV2QixJQUFJLE9BQU8sTUFBTSxDQUFDLElBQUksS0FBSyxRQUFRO1lBQUUsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3ZGLElBQUksT0FBTyxJQUFJLE1BQU07WUFBRSxPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDcEQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFBRSxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1FBQ3RHLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBQ3pILElBQUksWUFBWSxFQUFFLE1BQU0sRUFBRSxDQUFDO1lBQ3pCLE9BQU8sS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBOEIsRUFBRSxNQUFNLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoSCxDQUFDO1FBQ0QsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3ZELE1BQU0sR0FBRyxHQUFHLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUMxQixPQUFPLEdBQUcsQ0FBQyxLQUFLLENBQUM7WUFDakIsTUFBTSxXQUFXLEdBQUcsR0FBRyxDQUFDLElBQUksS0FBSyxTQUFTLElBQUksR0FBRyxDQUFDLFVBQVUsS0FBSyxTQUFTLENBQUM7WUFDM0UsT0FBTyxZQUFZLENBQUM7Z0JBQ2xCLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBdUIsRUFBRSxNQUFNLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUNwRixHQUFHLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2FBQzVELENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFDdEMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFrQixFQUFFLENBQUMsT0FBTyxJQUFJLEtBQUssUUFBUSxDQUFDO1lBQ3hFLENBQUMsQ0FBQyxPQUFPLE1BQU0sQ0FBQyxJQUFJLEtBQUssUUFBUTtnQkFDL0IsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFDZixDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNqQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sU0FBUyxDQUFDO1FBQ3pDLE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUM5QixRQUFRLElBQUksRUFBRSxDQUFDO2dCQUNiLEtBQUssUUFBUSxDQUFDLENBQUMsT0FBTyxRQUFRLENBQUM7Z0JBQy9CLEtBQUssUUFBUSxDQUFDO2dCQUNkLEtBQUssU0FBUyxDQUFDLENBQUMsT0FBTyxRQUFRLENBQUM7Z0JBQ2hDLEtBQUssU0FBUyxDQUFDLENBQUMsT0FBTyxTQUFTLENBQUM7Z0JBQ2pDLEtBQUssTUFBTSxDQUFDLENBQUMsT0FBTyxNQUFNLENBQUM7Z0JBQzNCLEtBQUssT0FBTyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQzNELEtBQUssUUFBUSxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBQyxDQUFDO2dCQUM3RSxPQUFPLENBQUMsQ0FBQyxPQUFPLFNBQVMsQ0FBQztZQUM1QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNOLENBQUM7SUFFTyxhQUFhLENBQUMsTUFBa0M7UUFDdEQsSUFDRSxNQUFNLENBQUMsVUFBVSxLQUFLLFNBQVM7ZUFDNUIsTUFBTSxDQUFDLG9CQUFvQixLQUFLLFNBQVM7ZUFDekMsTUFBTSxDQUFDLGlCQUFpQixLQUFLLFNBQVM7ZUFDdEMsTUFBTSxDQUFDLFFBQVEsS0FBSyxTQUFTO1lBQ2hDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNwQixJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxXQUFXLEtBQUssU0FBUztZQUFFLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNyRixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFTyxTQUFTLENBQUMsR0FBVyxFQUFFLE1BQWMsRUFBRSxLQUFhO1FBQzFELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLElBQUksSUFBSSxFQUFFLENBQUM7WUFDVCxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNwQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN6QyxJQUFJLE1BQU0sS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDO1lBQUUsT0FBTyxTQUFTLENBQUM7UUFDckUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDO1lBQ0gsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzlDLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzVCLENBQUM7SUFDSCxDQUFDO0lBRU8sU0FBUyxDQUFDLE1BQWtDLEVBQUUsTUFBYyxFQUFFLEtBQWE7UUFDakYsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1lBQzdDLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVztZQUNwQixDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUMzRCxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUM7WUFDdkYsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUF1QixFQUFFLE1BQU0sRUFBRSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMzRixJQUFJLElBQUksS0FBSyxTQUFTLElBQUksSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO2dCQUN6QyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBdUIsRUFBRSxNQUFNLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZGLENBQUM7WUFDRCxPQUFPLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO1FBQ25DLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUztZQUFFLE9BQU8sV0FBVyxDQUFDO1FBQ25ELE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQXdCLEVBQUUsTUFBTSxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hGLENBQUM7SUFFTyxVQUFVLENBQ2hCLE1BQWtDLEVBQ2xDLE1BQWMsRUFDZCxLQUFhLEVBQ2IsY0FBdUI7UUFFdkIsTUFBTSxZQUFZLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQztRQUNuQyxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDOUUsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO1lBQ3JELENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBa0IsRUFBRSxDQUFDLE9BQU8sSUFBSSxLQUFLLFFBQVEsQ0FBQztZQUM1RSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDUixNQUFNLE9BQU8sR0FBMEMsRUFBRSxDQUFDO1FBQzFELEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDMUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUEyQixFQUFFLFlBQVksRUFBRSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDN0UsTUFBTSxHQUFHLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxRQUEyQixDQUFDLENBQUM7WUFDaEYsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDWCxHQUFHLENBQUMsR0FBRyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO2dCQUNyQyxJQUFJLEVBQUUsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssSUFBSSxFQUFFO2FBQ3RFLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBYSxFQUFFLENBQUM7UUFDaEMsSUFBSSxjQUFjLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQztZQUM3QyxLQUFLLE1BQU0sUUFBUSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQztnQkFDL0QsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQTJCLEVBQUUsWUFBWSxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ25GLENBQUM7UUFDSCxDQUFDO1FBQ0QsSUFBSSxjQUFjLENBQUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLEVBQUUsQ0FBQztZQUNoRCxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLG9CQUFvQixFQUFFLFlBQVksRUFBRSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRixDQUFDO2FBQU0sSUFBSSxNQUFNLENBQUMsb0JBQW9CLEtBQUssSUFBSSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEUsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM3QixDQUFDO1FBQ0QsSUFBSSxVQUFVLENBQUMsTUFBTTtZQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEtBQUssQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNyRixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sTUFBTSxDQUFDLG9CQUFvQixLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyx5QkFBeUIsQ0FBQztRQUMxRyxJQUFJLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEtBQUssU0FBUyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3ZGLE1BQU0sTUFBTSxHQUFHLEtBQUssT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBQ3hFLElBQUksTUFBTSxDQUFDLE1BQU0sSUFBSSx5QkFBeUI7Z0JBQUUsT0FBTyxNQUFNLENBQUM7UUFDaEUsQ0FBQztRQUNELE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUNuQyxHQUFHLE1BQU0sQ0FBQyxHQUFHLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLFlBQVksQ0FBQyxHQUFHLFlBQVksR0FBRyxNQUFNLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztRQUN6RyxPQUFPLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxNQUFNLEdBQUcsQ0FBQztJQUM5QyxDQUFDO0NBQ0Y7QUFFRCw4Q0FBOEM7QUFDOUMsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBQUMsSUFBWSxFQUFFLE1BQWMsRUFBVSxFQUFFLENBQ2xFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxHQUFHLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMifQ==
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IFlexSessionMetrics, IFlexSessionMetricsState, TFlexModelCallUsage } from './interfaces.js';
|
|
2
|
+
/** Fixed-size accumulator. One owner per generation / actual compactor invocation. */
|
|
3
|
+
export interface ISessionMetricsOperation {
|
|
4
|
+
id: string;
|
|
5
|
+
source: 'generation' | 'compaction';
|
|
6
|
+
reportedTokens: number;
|
|
7
|
+
reportedTokensExact: boolean;
|
|
8
|
+
complete: boolean;
|
|
9
|
+
sawCall: boolean;
|
|
10
|
+
lastObservedInputTokens?: number;
|
|
11
|
+
lastObservedInputTokensAt?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const createSessionMetricsState: (complete: boolean) => IFlexSessionMetricsState;
|
|
14
|
+
export declare const createSessionMetricsOperation: (id: string, source: ISessionMetricsOperation["source"]) => ISessionMetricsOperation;
|
|
15
|
+
export declare function observeSessionMetricsCall(operation: ISessionMetricsOperation, call: TFlexModelCallUsage): void;
|
|
16
|
+
export declare function settleSessionMetricsOperation(metrics: IFlexSessionMetricsState, operation: ISessionMetricsOperation): void;
|
|
17
|
+
export declare function sessionMetricsView(metrics: IFlexSessionMetricsState): IFlexSessionMetrics;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export const createSessionMetricsState = (complete) => ({
|
|
2
|
+
reportedLifetimeUsedTokens: 0,
|
|
3
|
+
reportedLifetimeUsedTokensExact: true,
|
|
4
|
+
lifetimeUsageComplete: complete,
|
|
5
|
+
});
|
|
6
|
+
export const createSessionMetricsOperation = (id, source) => ({
|
|
7
|
+
id, source, reportedTokens: 0, reportedTokensExact: true, complete: true, sawCall: false,
|
|
8
|
+
});
|
|
9
|
+
const isTokenCount = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
10
|
+
/** Saturation is a safe lower bound, never a rounded purported exact total. */
|
|
11
|
+
const addTokens = (left, right) => right > Number.MAX_SAFE_INTEGER - left
|
|
12
|
+
? { tokens: Number.MAX_SAFE_INTEGER, exact: false }
|
|
13
|
+
: { tokens: left + right, exact: true };
|
|
14
|
+
export function observeSessionMetricsCall(operation, call) {
|
|
15
|
+
operation.sawCall = true;
|
|
16
|
+
if (call.status === 'unreported') {
|
|
17
|
+
operation.complete = false;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { usage } = call;
|
|
21
|
+
if (call.usageComplete === false)
|
|
22
|
+
operation.complete = false;
|
|
23
|
+
if (!Object.values(usage).every(isTokenCount)
|
|
24
|
+
|| !isTokenCount(usage.totalTokens)
|
|
25
|
+
|| usage.inputTokens > Number.MAX_SAFE_INTEGER - usage.outputTokens
|
|
26
|
+
|| usage.totalTokens !== usage.inputTokens + usage.outputTokens) {
|
|
27
|
+
operation.complete = false;
|
|
28
|
+
operation.reportedTokensExact = false;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const sum = addTokens(operation.reportedTokens, usage.totalTokens);
|
|
32
|
+
operation.reportedTokens = sum.tokens;
|
|
33
|
+
operation.reportedTokensExact &&= sum.exact;
|
|
34
|
+
if (operation.source === 'generation' && call.usageComplete !== false) {
|
|
35
|
+
operation.lastObservedInputTokens = usage.inputTokens;
|
|
36
|
+
operation.lastObservedInputTokensAt = new Date().toISOString();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function settleSessionMetricsOperation(metrics, operation) {
|
|
40
|
+
const key = operation.source === 'generation' ? 'pendingGenerationId' : 'pendingCompactionId';
|
|
41
|
+
if (metrics[key] !== operation.id)
|
|
42
|
+
throw new Error('Session metrics operation ownership changed.');
|
|
43
|
+
const sum = addTokens(metrics.reportedLifetimeUsedTokens, operation.reportedTokens);
|
|
44
|
+
metrics.reportedLifetimeUsedTokens = sum.tokens;
|
|
45
|
+
metrics.reportedLifetimeUsedTokensExact &&= sum.exact && operation.reportedTokensExact;
|
|
46
|
+
metrics.lifetimeUsageComplete &&= operation.complete
|
|
47
|
+
&& metrics.reportedLifetimeUsedTokensExact
|
|
48
|
+
// An arbitrary compactor may make uninstrumented calls. No report is not proof of zero spend.
|
|
49
|
+
&& (operation.source === 'generation' || operation.sawCall);
|
|
50
|
+
if (operation.lastObservedInputTokens !== undefined) {
|
|
51
|
+
metrics.lastObservedInputTokens = operation.lastObservedInputTokens;
|
|
52
|
+
metrics.lastObservedInputTokensAt = operation.lastObservedInputTokensAt;
|
|
53
|
+
}
|
|
54
|
+
delete metrics[key];
|
|
55
|
+
}
|
|
56
|
+
export function sessionMetricsView(metrics) {
|
|
57
|
+
const inFlight = metrics.pendingGenerationId !== undefined || metrics.pendingCompactionId !== undefined;
|
|
58
|
+
const lifetimeUsageComplete = metrics.lifetimeUsageComplete && !inFlight;
|
|
59
|
+
return {
|
|
60
|
+
reportedLifetimeUsedTokens: metrics.reportedLifetimeUsedTokens,
|
|
61
|
+
reportedLifetimeUsedTokensExact: metrics.reportedLifetimeUsedTokensExact,
|
|
62
|
+
lifetimeUsageComplete,
|
|
63
|
+
inFlight,
|
|
64
|
+
...(lifetimeUsageComplete ? { lifetimeUsedTokens: metrics.reportedLifetimeUsedTokens } : {}),
|
|
65
|
+
...(metrics.lastObservedInputTokens === undefined ? {} : {
|
|
66
|
+
lastObservedInputTokens: metrics.lastObservedInputTokens,
|
|
67
|
+
lastObservedInputTokensAt: metrics.lastObservedInputTokensAt,
|
|
68
|
+
lastObservedInputTokensFreshness: 'historical',
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuc2Vzc2lvbm1ldHJpY3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy91dGlscy5zZXNzaW9ubWV0cmljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkEsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxRQUFpQixFQUE0QixFQUFFLENBQUMsQ0FBQztJQUN6RiwwQkFBMEIsRUFBRSxDQUFDO0lBQzdCLCtCQUErQixFQUFFLElBQUk7SUFDckMscUJBQXFCLEVBQUUsUUFBUTtDQUNoQyxDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxDQUMzQyxFQUFVLEVBQ1YsTUFBMEMsRUFDaEIsRUFBRSxDQUFDLENBQUM7SUFDOUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsQ0FBQyxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLO0NBQ3pGLENBQUMsQ0FBQztBQUVILE1BQU0sWUFBWSxHQUFHLENBQUMsS0FBYyxFQUFtQixFQUFFLENBQ3ZELE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUM7QUFFekUsK0VBQStFO0FBQy9FLE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBWSxFQUFFLEtBQWEsRUFBc0MsRUFBRSxDQUNwRixLQUFLLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixHQUFHLElBQUk7SUFDcEMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFO0lBQ25ELENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEdBQUcsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQztBQUU1QyxNQUFNLFVBQVUseUJBQXlCLENBQ3ZDLFNBQW1DLEVBQ25DLElB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
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Task Venture Capital GmbH",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "@modelprofile.com/flexharness",
|
|
5
|
-
"version": "10.
|
|
5
|
+
"version": "10.13.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Managed agent sessions with tools, MCP, chat, OCR, documents and browser control through focused subpath imports.",
|
|
8
8
|
"main": "./dist_ts/index.js",
|
|
@@ -74,15 +74,16 @@
|
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@
|
|
78
|
-
"@modelprofile.com/flexharness-
|
|
77
|
+
"@cfworker/json-schema": "^4.1.1",
|
|
78
|
+
"@modelprofile.com/flexharness-agent": "10.13.0",
|
|
79
|
+
"@modelprofile.com/flexharness-models": "10.13.0",
|
|
79
80
|
"@push.rocks/smartrequest": "^5.5.1",
|
|
80
81
|
"ai": "^7.0.111",
|
|
81
82
|
"zod": "^4.6.5"
|
|
82
83
|
},
|
|
83
84
|
"peerDependencies": {
|
|
84
85
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
85
|
-
"@push.rocks/smartbrowser": "^5.0.0",
|
|
86
|
+
"@push.rocks/smartbrowser": "^5.0.0 || ^6.0.0",
|
|
86
87
|
"@push.rocks/smartpdf": "^6.0.0",
|
|
87
88
|
"sharp": "^0.35.3",
|
|
88
89
|
"puppeteer": "^24.42.0",
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
"lit": "^3.2.0",
|
|
93
94
|
"@types/react": "^19.0.0",
|
|
94
95
|
"@lossless.org/client": "^1.17.0",
|
|
95
|
-
"@design.estate/dees-catalog": "^17.0.0 || ^19.5.0 || ^20.0.0"
|
|
96
|
+
"@design.estate/dees-catalog": "^17.0.0 || ^19.5.0 || ^20.0.0 || ^21.0.0"
|
|
96
97
|
},
|
|
97
98
|
"peerDependenciesMeta": {
|
|
98
99
|
"@modelcontextprotocol/sdk": {
|
package/readme.md
CHANGED
|
@@ -62,7 +62,7 @@ or provider SDKs.
|
|
|
62
62
|
| `/chat` | Portable streaming `ChatSession`, history and usage | None |
|
|
63
63
|
| `/chat/cli` | Ink/React terminal chat | `ink ink-text-input react`; TypeScript: `@types/react` |
|
|
64
64
|
| `/chat/web` | Lit `flexchat-window`, `flexchat-message`, `flexchat-input` | `lit` |
|
|
65
|
-
| `/chat/harness` | `FlexHarnessTranscript` and intents for the `@design.estate/dees-catalog` harness components, browser-safe | `@design.estate/dees-catalog` `^17.0.0 \|\| ^19.5.0 \|\| ^20.0.0` (types only) |
|
|
65
|
+
| `/chat/harness` | `FlexHarnessTranscript` and intents for the `@design.estate/dees-catalog` harness components, browser-safe | `@design.estate/dees-catalog` `^17.0.0 \|\| ^19.5.0 \|\| ^20.0.0 \|\| ^21.0.0` (types only) |
|
|
66
66
|
| `/kvm` | Browser control, terminal framing and OCR observation | `puppeteer` |
|
|
67
67
|
| `/documents` | PDF and image documents, `extractTextFromPdf` | `@push.rocks/smartpdf`; for image documents `sharp` |
|
|
68
68
|
| `/mcp` | MCP clients and AI SDK tool conversion | `@modelcontextprotocol/sdk` |
|
|
@@ -92,6 +92,41 @@ a model backed by its own server transport, or supply `run` in
|
|
|
92
92
|
`IChatSessionOptions`. The web element accepts an `IChatSession` and maintains its
|
|
93
93
|
own subscription. Full Node `AgentSession` remains at the agent package root.
|
|
94
94
|
|
|
95
|
+
## Durable session token metrics
|
|
96
|
+
|
|
97
|
+
Read `await harness.getSessionMetrics(scopeId, sessionId)` for bounded, durable
|
|
98
|
+
accounting independent of transcript visibility. It reads fixed-size projection
|
|
99
|
+
state rather than summing assistant messages or scanning event/archive/child history.
|
|
100
|
+
A warm read joins outstanding projection writes and surfaces accounting failures.
|
|
101
|
+
|
|
102
|
+
| Field | Meaning |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `reportedLifetimeUsedTokens` | Sum of durably settled per-call reports. Incomplete accounting makes this a lower bound. |
|
|
105
|
+
| `reportedLifetimeUsedTokensExact` | Whether the sum of those reports is exact; invalid reports and safe-integer overflow make it inexact. |
|
|
106
|
+
| `lifetimeUsageComplete` | Every owned call is accounted for and no accounting operation remains in flight. |
|
|
107
|
+
| `lifetimeUsedTokens` | Present only when the lifetime total is complete. Zero is a valid total. |
|
|
108
|
+
| `inFlight` | A generation or actual compactor invocation has not settled its accounting yet. |
|
|
109
|
+
| `lastObservedInputTokens`, `lastObservedInputTokensAt` | Input count and observation time of the last settled generation call with complete input/output totals. |
|
|
110
|
+
| `lastObservedInputTokensFreshness` | Always `historical`. This is **not** current context size: output, steering, compaction and reversion can change context. |
|
|
111
|
+
|
|
112
|
+
Accounting covers this session's generation calls and reported compaction calls,
|
|
113
|
+
including failure, cancellation and retries. Child sessions own their own spend;
|
|
114
|
+
tool-owned model calls are not included. Do not sum cumulative assistant-message
|
|
115
|
+
usage to reconstruct lifetime spend. Missing/partial reports remain incomplete;
|
|
116
|
+
unsafe totals saturate at `Number.MAX_SAFE_INTEGER` without claiming exactness.
|
|
117
|
+
A compactor that reports no calls cannot prove zero spend.
|
|
118
|
+
|
|
119
|
+
New sessions start complete at zero. Existing/imported sessions with unknown prior
|
|
120
|
+
spend start incomplete. Write-ahead operation markers make interrupted recovery
|
|
121
|
+
conservative: unresolved operations are cleared without certifying their unknown
|
|
122
|
+
spend. Undo, redo, compaction and transcript archiving never subtract lifetime
|
|
123
|
+
spend. Importing visible history does not reconstruct historical billing.
|
|
124
|
+
|
|
125
|
+
Conversational runs that exhaust `maxSteps` with tool work or unseen input remaining
|
|
126
|
+
fail with `FlexHarnessStepLimitError` (`FLEX_STEP_LIMIT`), rather than being marked
|
|
127
|
+
completed with an empty answer. Standalone Agent callers retain tool-only results
|
|
128
|
+
and can inspect `terminationReason: 'model' | 'step-limit'`.
|
|
129
|
+
|
|
95
130
|
## Provider subpaths
|
|
96
131
|
|
|
97
132
|
Install `@modelprofile.com/flexharness-providers` once. Its root exports all provider
|
|
@@ -260,7 +295,7 @@ const harness = new FlexHarness<IProjectScope>({
|
|
|
260
295
|
maxSteps: 8,
|
|
261
296
|
},
|
|
262
297
|
],
|
|
263
|
-
maxSubagentDepth:
|
|
298
|
+
maxSubagentDepth: 6,
|
|
264
299
|
maxSubagentCallsPerRun: 32,
|
|
265
300
|
externalErrorProjector: (_error, context) => ({
|
|
266
301
|
name: 'ModelOperationError',
|
|
@@ -414,12 +449,10 @@ Normal Flex session cleanup always waits in-flight local project operations, the
|
|
|
414
449
|
|
|
415
450
|
## Subagents
|
|
416
451
|
|
|
417
|
-
`subagents` enables the harness-owned `delegate` and `
|
|
452
|
+
`subagents` enables the harness-owned `delegate`, `delegate_result`, and `delegate_send` tools when at least one definition exists and the session depth is below `maxSubagentDepth`. A tool provider cannot replace any enabled built-in; global and agent tool allowlists still intersect to control model-facing exposure. Delegation is asynchronous by default: `delegate` returns `{ taskId, status: 'running', runId }` after durable child admission, so the parent can continue independent work. `delegate_result({ taskId, waitMs? })` reads live status and, once settled, bounded final text and model identity; its optional wait is limited to 240 seconds and observes parent cancellation. Set `foreground: true` to await the final answer in `delegate` itself. Children remain owned by the parent turn: Stop cancels its exact child runs, and the parent joins them before releasing authority and finalizing. A child result enters the parent's next model context as untrusted task data. When the parent's model ends its turn while background children still run, the turn waits for the next child to settle and takes its result in with another step (while steps remain), so a delegated result is never lost because the parent finished first.
|
|
418
453
|
|
|
419
454
|
The model calls it with this exact input shape:
|
|
420
455
|
|
|
421
|
-
When upgrading from 9.x, callers that require the previous synchronous delegate result must pass `foreground: true`. Tool providers must also leave the newly reserved `delegate_result` name available when subagents are enabled.
|
|
422
|
-
|
|
423
456
|
```typescript
|
|
424
457
|
interface IDelegateInput {
|
|
425
458
|
description: string;
|
|
@@ -430,9 +463,24 @@ interface IDelegateInput {
|
|
|
430
463
|
}
|
|
431
464
|
```
|
|
432
465
|
|
|
466
|
+
When upgrading from 9.x, callers that require the previous synchronous delegate result must pass `foreground: true`. Tool providers must also leave the reserved `delegate_result` and `delegate_send` names available when subagents are enabled.
|
|
467
|
+
|
|
468
|
+
`delegate_send({ taskId, prompt })` sends follow-up instructions to a running direct child owned by this exact parent turn. Both fields are required and extra fields are rejected; `taskId` is non-empty and at most 512 UTF-8 bytes, and `prompt` is non-empty and at most 64 KiB. It returns `{ steerId, queueId, runId }` on admission, with a stable steer identity derived from the parent run and tool call. The child takes the input at its next inference boundary, without interrupting a running tool or permission wait. A child waiting to finish while its own descendants run can take the follow-up and continue inference; those descendants keep running. Use `delegate_result` to inspect progress and collect the final answer.
|
|
469
|
+
|
|
470
|
+
Controllers can use the same admission path explicitly:
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
await harness.sendSubagentInput(scopeId, parentSessionId, parentRunId, taskId, {
|
|
474
|
+
steerId: 'follow-up-1',
|
|
475
|
+
prompt: 'Prefer primary sources and include the publication date.',
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Sending requires the exact active parent run, its currently delegated direct child, matching captured configuration and parent/child generations, and live writable ancestors. It does not authorize a root to skip levels, or infer ownership from immutable creation-origin metadata: a resumed child belongs to the current delegate invocation. Foreign, unowned, stale, cancelled, settled, or ending runs reject; sending never starts an idle generation, restarts a child, or resumes one. General public `steerPrompt()` still forbids child sessions. Child sends share root steering's duplicate rejection, pending count/byte bounds, accepted/applied events, durable user-message application, and terminal unapplied-input accounting.
|
|
480
|
+
|
|
433
481
|
Before creating or resuming a child, FlexHarness requests permission on the parent run with `kind: 'subagent.start'`, the parent `toolCallId`, and separately bounded harness-owned agent/task metadata. Its metadata includes `childSessionId`, the exact ID reserved for this call: FlexHarness derives it deterministically when `taskId` is omitted and copies the supplied candidate when `taskId` is present. A resume also retains that candidate as `taskId`. This block is not truncated by `toolOutputLimits`. The reserved ID binds permission handling before child creation but does not prove that the child exists or is owned: applications must treat the later delegated admission context as authoritative. The controller answers through the normal permission APIs. This request has no `rememberKey`, so `always` is invalid; controllers use `once` or `reject`.
|
|
434
482
|
|
|
435
|
-
Each new invocation creates a durable child `IFlexSession` with immutable `parentSessionId`, origin `parentRunId`, origin `parentToolCallId`, `agent`, and `depth`. New public roots persist `depth: 0`; legacy schema-1 roots may omit it. These fields are harness-owned; public `createSession()`
|
|
483
|
+
Each new invocation creates a durable child `IFlexSession` with immutable `parentSessionId`, origin `parentRunId`, origin `parentToolCallId`, `agent`, and `depth`. New public roots persist `depth: 0`; legacy schema-1 roots may omit it. These fields are harness-owned; public `createSession()` accepts `sessionId`, `sessionGenerationId`, `configurationRef`, and `title`. A child inherits its parent's `configurationRef` and cannot resume under a different reference. Child sessions reject direct `prompt()`, `startPrompt()`, `enqueuePrompt()`, and `schedulePrompt()` calls and run only through the `delegate` tool. The model and tool resolver contexts receive optional immutable `parentSessionId` and `agent` values so integrations can apply agent-specific model and tool policy. Child prompts use the definition's `modelHint`, `system`, and `maxSteps`.
|
|
436
484
|
|
|
437
485
|
The parent tool part receives `childSessionId` as soon as the child is acquired, so a host can offer an authorized live transcript. A foreground call also adds the resolved child model to its part and returns bounded JSON:
|
|
438
486
|
|
|
@@ -485,7 +533,7 @@ Acquisition completes before generation-side branch reversion, context compactio
|
|
|
485
533
|
|
|
486
534
|
For a normally acquired lease, FlexHarness gives `close()` an awaited attempt after AgentSession generation and before canonical accepted, rejected, or interrupted finalization and the terminal `prompt.finished` event. If an abort detaches an acquisition that ignores its signal, the run may settle before acquisition returns; FlexHarness retains that owner and closes any late lease. `close()` must be idempotent and safe to retry after rejection. A close failure prevents successful child acceptance and remains owned by the exact child session generation for retry by later exact-session deletion, scope retirement, or disposal. Retirement and disposal truthfully wait for late acquisition and lease cleanup.
|
|
487
535
|
|
|
488
|
-
Limits are validated and frozen at construction: at most 32 unique definitions; names are non-empty and at most 128 UTF-8 bytes; descriptions 2048 bytes; optional model hints 512 bytes; optional system prompts 64 KiB; and optional `maxSteps` a positive safe integer. `maxSubagentDepth` defaults to
|
|
536
|
+
Limits are validated and frozen at construction: at most 32 unique definitions; names are non-empty and at most 128 UTF-8 bytes; descriptions 2048 bytes; optional model hints 512 bytes; optional system prompts 64 KiB; and optional `maxSteps` a positive safe integer. `maxSubagentDepth` defaults to 6 and must be a positive safe integer at most 8. The root is depth 0, so the default permits six child levels (depths 1 through 6); delegation tools are absent at the configured maximum. `maxSubagentCallsPerRun` defaults to 32 and must be a positive safe integer at most 128. A call slot is consumed synchronously at the start of every schema-valid delegate execution, before semantic bounds, subagent type/depth validation, permission, or child work. Inputs rejected by the tool schema never start delegate execution and do not consume a slot. After successful semantic validation, the child ID candidate is reserved for the rest of the parent run, including after permission rejection or later failure. Permission rejection creates no child session. Omitting `taskId` reserves a deterministic new child ID; supplying `taskId` reserves that unverified candidate and attempts resume after permission only if it identifies a resumable child. Delegate descriptions are non-empty and at most 256 UTF-8 bytes, prompts non-empty and at most 64 KiB, subagent types at most 128 bytes, and task IDs at most 512 bytes.
|
|
489
537
|
|
|
490
538
|
Scope snapshots remain schema 1 and legacy child tombstones without `subagent` provenance continue to load. New child tombstones write the atomic provenance block and reject partial, parent-generation-mismatched, depth-mismatched, or duplicate-origin records. FlexHarness versions before this provenance addition reject that new optional key under their strict reader, so downgrading or mixing old readers with newly written scope snapshots is unsupported.
|
|
491
539
|
|
|
@@ -645,7 +693,7 @@ console.log(result.unappliedSteerIds); // [] once the run took the steer in
|
|
|
645
693
|
|
|
646
694
|
The run takes a steer in at its next step boundary: after the tool results of its current model step are recorded and before its next model call. A running tool call or a pending permission is never interrupted; the steer waits for the boundary that follows it. A steer taken in is a user message of the run (`steerId` set) that the model sees in its next call and every later turn. If the run had already answered, the assistant message that answered is completed and the run answers on in a new assistant message after the steer; a steer taken in before the run answered anything is placed before its still empty assistant message. `IFlexPromptResult.userMessage` stays the prompt and `assistantMessage` is the run's last assistant message. Undo and redo treat the run's messages as one turn.
|
|
647
695
|
|
|
648
|
-
`steerPrompt()` resolves with `{ steerId, queueId, runId }` once the run accepted the steer and `prompt.steer.accepted` was emitted; `prompt.steer.applied` carries the `messageId` of the user message the steer became. Every accepted steer ends in exactly one of two ways: it is in the model context of later turns, or it is listed in `unappliedSteerIds`, in arrival order, on `IFlexPromptResult` and `run.finished`, and on the finished queue entry when that list is not empty. A steer is listed when the run did not take it in before it ended, because its last model step was already running or because it was stopped or failed, and also when the run itself does not stay in context. `keptInContext` on `run.finished` and on the finished queue entry says whether it does: it is `false` for a failed run and for a run stopped before any model output, and such a run lists every steer it accepted, including the ones it took in and reported with `prompt.steer.applied`. Send its prompt and its unapplied steers again to have them answered. The run stops taking steers atomically when its generation ends or `abort()`/`cancelPrompt()` stops it. A steer for a prompt without a running run, or whose run is ending, is refused with `FlexHarnessSteerRejectedError` reason `not-running`; the caller sends it as the next turn instead. Reusing a `steerId` within a run is refused with reason `duplicate`, an unknown `queueId` throws `FlexHarnessNotFoundError`, and
|
|
696
|
+
`steerPrompt()` resolves with `{ steerId, queueId, runId }` once the run accepted the steer and `prompt.steer.accepted` was emitted; `prompt.steer.applied` carries the `messageId` of the user message the steer became. Every accepted steer ends in exactly one of two ways: it is in the model context of later turns, or it is listed in `unappliedSteerIds`, in arrival order, on `IFlexPromptResult` and `run.finished`, and on the finished queue entry when that list is not empty. A steer is listed when the run did not take it in before it ended, because its last model step was already running or because it was stopped or failed, and also when the run itself does not stay in context. `keptInContext` on `run.finished` and on the finished queue entry says whether it does: it is `false` for a failed run and for a run stopped before any model output, and such a run lists every steer it accepted, including the ones it took in and reported with `prompt.steer.applied`. Send its prompt and its unapplied steers again to have them answered. The run stops taking steers atomically when its generation ends or `abort()`/`cancelPrompt()` stops it. A steer for a prompt without a running run, or whose run is ending, is refused with `FlexHarnessSteerRejectedError` reason `not-running`; the caller sends it as the next turn instead. Reusing a `steerId` within a run is refused with reason `duplicate`, an unknown `queueId` throws `FlexHarnessNotFoundError`, and child sessions reject this general API (their exact parent run uses `sendSubagentInput()` or `delegate_send` instead). A run holds at most `maxOutstandingPromptsPerSession` pending steers, and their bytes count against the session's outstanding prompt byte limit until the run takes them in or ends, so `startPrompt()` and `enqueuePrompt()` are refused with `FlexHarnessQueueFullError` while pending steers fill it. They are process-local like queue entries: a process restart ends the run and drops its pending steers, while steers it took in are durable parts of the turn.
|
|
649
697
|
|
|
650
698
|
## Slash Commands
|
|
651
699
|
|
|
@@ -1089,6 +1137,8 @@ Each domain serializes its own mutations. A successful run first persists a hidd
|
|
|
1089
1137
|
|
|
1090
1138
|
Projection stores accept schema version 1, 2, or 3 from `load()`, but every `save()` receives the current schema-3 shape. Schema 3 records explicit reversion protocol, transcript/workspace provenance, and V2 disposition. A terminal V2 segment must be conclusively `revertible`, `no-change`, or `nonrevertible`; a pending V2 capture remains owned by its capture WAL and is never treated as transcript history.
|
|
1091
1139
|
|
|
1140
|
+
Current schema-3 projections also persist optional `metrics` state. Older strict readers that do not recognize this key cannot reopen a projection after metrics have been written; downgrade or mixed-version access to that session is unsupported.
|
|
1141
|
+
|
|
1092
1142
|
A loaded schema-1 projection has no reversion state. Schema-2 `workspaceCaptured` segments migrate as protocol-1 workspace/revertible history without discarding references; transcript-only segments migrate as protocol-1 transcript provenance. Under `workspace-required`, that legacy transcript history is a barrier. The next projection mutation writes schema 3. Custom stores must preserve strict compare-and-swap revisions across schema-1 and schema-2 read-upgrade-write cycles, including uncertain-save reconciliation.
|
|
1093
1143
|
|
|
1094
1144
|
## Migrating From 2.x
|