@dsh-enhanced/assistant-evaluation 0.1.66 → 0.1.67
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/README.md +15 -0
- package/lib/attention-owner-questions.d.ts +21 -2
- package/lib/attention-owner-questions.d.ts.map +1 -1
- package/lib/attention-owner-questions.js +57 -20
- package/lib/attention-owner-questions.js.map +1 -1
- package/lib/attention-tuning.d.ts +66 -5
- package/lib/attention-tuning.d.ts.map +1 -1
- package/lib/attention-tuning.js +165 -13
- package/lib/attention-tuning.js.map +1 -1
- package/lib/benchmark/cli.d.ts.map +1 -1
- package/lib/benchmark/cli.js +3 -5
- package/lib/benchmark/cli.js.map +1 -1
- package/lib/benchmark/native-skills.d.ts.map +1 -1
- package/lib/benchmark/native-skills.js +1 -3
- package/lib/benchmark/native-skills.js.map +1 -1
- package/lib/benchmark/strategy-capabilities.d.ts.map +1 -1
- package/lib/benchmark/strategy-capabilities.js +0 -5
- package/lib/benchmark/strategy-capabilities.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/service.d.ts +55 -4
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +140 -5
- package/lib/service.js.map +1 -1
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +3 -1
- package/lib/store.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +14 -23
- package/lib/benchmark/super-relay.d.ts +0 -26
- package/lib/benchmark/super-relay.d.ts.map +0 -1
- package/lib/benchmark/super-relay.js +0 -173
- package/lib/benchmark/super-relay.js.map +0 -1
package/lib/service.js
CHANGED
|
@@ -4,7 +4,7 @@ import { acceptanceDigest, goalDefinitionSituation, validateTaskAcceptanceContra
|
|
|
4
4
|
import { EvaluationStore, EvaluationStoreError, canonicalEvaluationScope, evaluationLearningProjectionDigest, } from './store.js';
|
|
5
5
|
import { registerEvaluationTools } from './tools.js';
|
|
6
6
|
import { normalizeAttentionCohort, } from './attention-tuning.js';
|
|
7
|
-
import { ATTENTION_OWNER_QUESTION_SOURCE_ID, attentionOwnerQuestionIdempotencyKey, attentionOwnerQuestionText, } from './attention-owner-questions.js';
|
|
7
|
+
import { ATTENTION_OWNER_QUESTION_SOURCE_ID, attentionOwnerQuestionIdempotencyKey, attentionOwnerQuestionText, parseAttentionOwnerQuestionChoice, ATTENTION_OWNER_QUESTION_REPLY_PROTOCOL, } from './attention-owner-questions.js';
|
|
8
8
|
import { validateWorkItemOwnerFeedbackProof } from './work-item-owner-proof.js';
|
|
9
9
|
import { computeIntakeAttentionAgreement, INTAKE_ATTENTION_AGREEMENT_SCAN_LIMIT, isIntakeProvenanceSource } from './intake-attention-agreement.js';
|
|
10
10
|
import { executionStatuses, objectiveStatuses, outcomeSourceKinds, TRUSTED_EVALUATION_PRODUCER_PROTOCOL, } from './types.js';
|
|
@@ -15,6 +15,10 @@ function isOwnerQuestionDeliveryPort(value) {
|
|
|
15
15
|
&& typeof port.validateOwnerRoute === 'function' && typeof port.resolveOwnerRoute === 'function'
|
|
16
16
|
&& typeof port.inspectOwnerNotification === 'function' && typeof port.registerOwnerNotificationWithdrawal === 'function';
|
|
17
17
|
}
|
|
18
|
+
function isOwnerQuestionReplyPort(value) {
|
|
19
|
+
const port = value;
|
|
20
|
+
return typeof port === 'object' && port !== null && typeof port.registerOwnerNotificationReply === 'function';
|
|
21
|
+
}
|
|
18
22
|
export const ASSISTANT_EVALUATION_SKILL = `# Personal assistant self-evaluation
|
|
19
23
|
|
|
20
24
|
Use this workflow only to assess whether an already-finished task met its objective. A self-assessment is diagnostic evidence, never ground truth and never permission to change production behavior.
|
|
@@ -250,6 +254,8 @@ export class AssistantEvaluationService extends Service {
|
|
|
250
254
|
lastNotificationSyncAt = Number.NEGATIVE_INFINITY;
|
|
251
255
|
ownerQuestionWithdrawal;
|
|
252
256
|
activeOwnerQuestionWithdrawals = new WeakSet();
|
|
257
|
+
ownerQuestionReply;
|
|
258
|
+
activeOwnerQuestionReplies = new WeakSet();
|
|
253
259
|
attentionCohorts;
|
|
254
260
|
active = true;
|
|
255
261
|
constructor(ctx, input, options = {}) {
|
|
@@ -401,6 +407,8 @@ export class AssistantEvaluationService extends Service {
|
|
|
401
407
|
if (this.config.attentionOwnerQuestionDeliveryEnabled) {
|
|
402
408
|
this.bindOwnerQuestionWithdrawal(currentDelivery);
|
|
403
409
|
ctx.inject(['assistantDelivery'], deliveryCtx => this.bindOwnerQuestionWithdrawal(deliveryCtx.get('assistantDelivery')));
|
|
410
|
+
this.bindOwnerQuestionReply(currentDelivery);
|
|
411
|
+
ctx.inject(['assistantDelivery'], deliveryCtx => this.bindOwnerQuestionReply(deliveryCtx.get('assistantDelivery')));
|
|
404
412
|
}
|
|
405
413
|
const currentVerifier = ctx.get('assistantVerifier');
|
|
406
414
|
if (isTrustedVerifierEvaluationProducer(currentVerifier))
|
|
@@ -449,6 +457,7 @@ export class AssistantEvaluationService extends Service {
|
|
|
449
457
|
this.projectionTimer = undefined;
|
|
450
458
|
this.notificationFacts = undefined;
|
|
451
459
|
this.ownerQuestionWithdrawal?.dispose();
|
|
460
|
+
this.ownerQuestionReply?.dispose();
|
|
452
461
|
disposeCurrentProjector?.();
|
|
453
462
|
this.automationBinding?.dispose();
|
|
454
463
|
this.deliveryBinding?.dispose();
|
|
@@ -942,7 +951,14 @@ export class AssistantEvaluationService extends Service {
|
|
|
942
951
|
});
|
|
943
952
|
}
|
|
944
953
|
#looseningOptions() {
|
|
945
|
-
|
|
954
|
+
if (!this.config.attentionLooseningEnabled)
|
|
955
|
+
return undefined;
|
|
956
|
+
return Object.freeze({
|
|
957
|
+
replayWindowMs: this.config.attentionLooseningReplayWindowMs,
|
|
958
|
+
...(this.config.attentionOwnerQuestionDeliveryEnabled
|
|
959
|
+
? { ownerQuestionReplyLoop: Object.freeze({ noticeTtlMs: this.config.attentionOwnerQuestionNoticeTtlMs }) }
|
|
960
|
+
: {}),
|
|
961
|
+
});
|
|
946
962
|
}
|
|
947
963
|
#attentionCohort(input) {
|
|
948
964
|
let cohort;
|
|
@@ -1095,6 +1111,95 @@ export class AssistantEvaluationService extends Service {
|
|
|
1095
1111
|
this.ownerQuestionWithdrawal = binding;
|
|
1096
1112
|
return binding.dispose;
|
|
1097
1113
|
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Register (once per Delivery instance) the slice-5 reply consumer. A
|
|
1116
|
+
* Delivery without the reply port is treated as absent: slice-4 notice
|
|
1117
|
+
* delivery keeps working, only replies are not read. A registration error
|
|
1118
|
+
* only disables replies; it never blocks notice delivery.
|
|
1119
|
+
*/
|
|
1120
|
+
bindOwnerQuestionReply(source) {
|
|
1121
|
+
if (!this.active || !isOwnerQuestionReplyPort(source))
|
|
1122
|
+
return undefined;
|
|
1123
|
+
if (this.ownerQuestionReply?.source === source)
|
|
1124
|
+
return undefined;
|
|
1125
|
+
const registration = Object.freeze({
|
|
1126
|
+
protocol: ATTENTION_OWNER_QUESTION_REPLY_PROTOCOL,
|
|
1127
|
+
authority: 'assistantEvaluation',
|
|
1128
|
+
sourceId: ATTENTION_OWNER_QUESTION_SOURCE_ID,
|
|
1129
|
+
idempotencyKeyPrefix: attentionOwnerQuestionIdempotencyKey(''),
|
|
1130
|
+
consume: (input) => this.#consumeOwnerQuestionReply(input),
|
|
1131
|
+
});
|
|
1132
|
+
this.activeOwnerQuestionReplies.add(registration);
|
|
1133
|
+
let unregister;
|
|
1134
|
+
try {
|
|
1135
|
+
unregister = source.registerOwnerNotificationReply(registration)?.unregister;
|
|
1136
|
+
}
|
|
1137
|
+
catch (error) {
|
|
1138
|
+
this.activeOwnerQuestionReplies.delete(registration);
|
|
1139
|
+
this.ctx.logger.warn(`assistant-evaluation: owner-question reply registration failed; replies are not read: ${String(error)}`);
|
|
1140
|
+
return undefined;
|
|
1141
|
+
}
|
|
1142
|
+
if (typeof unregister !== 'function') {
|
|
1143
|
+
this.activeOwnerQuestionReplies.delete(registration);
|
|
1144
|
+
this.ctx.logger.warn('assistant-evaluation: owner-question reply registration returned no unregister; replies are not read');
|
|
1145
|
+
return undefined;
|
|
1146
|
+
}
|
|
1147
|
+
const release = unregister;
|
|
1148
|
+
this.ownerQuestionReply?.dispose();
|
|
1149
|
+
let live = true;
|
|
1150
|
+
const binding = Object.freeze({ source, registration, dispose: () => {
|
|
1151
|
+
if (!live)
|
|
1152
|
+
return;
|
|
1153
|
+
live = false;
|
|
1154
|
+
this.activeOwnerQuestionReplies.delete(registration);
|
|
1155
|
+
try {
|
|
1156
|
+
release();
|
|
1157
|
+
}
|
|
1158
|
+
catch { /* Delivery already gone */ }
|
|
1159
|
+
if (this.ownerQuestionReply === binding)
|
|
1160
|
+
this.ownerQuestionReply = undefined;
|
|
1161
|
+
} });
|
|
1162
|
+
this.ownerQuestionReply = binding;
|
|
1163
|
+
return binding.dispose;
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Synchronous Delivery callback for one authenticated reply to an exact
|
|
1167
|
+
* owner-question notice. Only exact whole-phrase choices are accepted; a
|
|
1168
|
+
* recognized choice is consumed even when its question is no longer open,
|
|
1169
|
+
* so a stale "authorize-once" never reaches the Agent. Storage errors are
|
|
1170
|
+
* `transient` and leave Delivery's Inbox pending for a bounded retry.
|
|
1171
|
+
*/
|
|
1172
|
+
#consumeOwnerQuestionReply(input) {
|
|
1173
|
+
if (!this.active || !this.config.attentionOwnerQuestionDeliveryEnabled)
|
|
1174
|
+
return 'ignored';
|
|
1175
|
+
if (typeof input?.idempotencyKey !== 'string' || typeof input.text !== 'string')
|
|
1176
|
+
return 'ignored';
|
|
1177
|
+
const prefix = attentionOwnerQuestionIdempotencyKey('');
|
|
1178
|
+
if (!input.idempotencyKey.startsWith(prefix))
|
|
1179
|
+
return 'ignored';
|
|
1180
|
+
const questionId = input.idempotencyKey.slice(prefix.length);
|
|
1181
|
+
const choice = parseAttentionOwnerQuestionChoice(input.text);
|
|
1182
|
+
if (choice === undefined || questionId.length === 0)
|
|
1183
|
+
return 'ignored';
|
|
1184
|
+
try {
|
|
1185
|
+
for (const cohort of this.attentionCohorts) {
|
|
1186
|
+
for (const scope of this.store.attention.scopes(cohort)) {
|
|
1187
|
+
const latest = this.store.attention.latestOwnerQuestion(scope, cohort);
|
|
1188
|
+
if (latest === undefined || latest === 'unverifiable' || latest.questionId !== questionId)
|
|
1189
|
+
continue;
|
|
1190
|
+
this.applyAttentionOwnerQuestionReply({ scope, cohort, questionId, choice });
|
|
1191
|
+
return 'applied';
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
// The notice was genuinely issued under this source and key, but the
|
|
1195
|
+
// local ledger no longer holds that exact question: consume the
|
|
1196
|
+
// recognized choice instead of sending it to the Agent.
|
|
1197
|
+
return 'applied';
|
|
1198
|
+
}
|
|
1199
|
+
catch {
|
|
1200
|
+
return 'transient';
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1098
1203
|
/**
|
|
1099
1204
|
* Send-time answer for one owner-question notice. It stays sendable only
|
|
1100
1205
|
* while its question is still the cohort's latest, open, unanswered, inside
|
|
@@ -1171,6 +1276,9 @@ export class AssistantEvaluationService extends Service {
|
|
|
1171
1276
|
continue;
|
|
1172
1277
|
}
|
|
1173
1278
|
this.bindOwnerQuestionWithdrawal(delivery);
|
|
1279
|
+
// A replaced Delivery instance needs the reply consumer bound as well;
|
|
1280
|
+
// the tick is the existing retry point, so no extra loop is added.
|
|
1281
|
+
this.bindOwnerQuestionReply(delivery);
|
|
1174
1282
|
// Only queue (or adopt) while this service's own withdrawal check is
|
|
1175
1283
|
// bound to this exact Delivery instance; otherwise a closed question
|
|
1176
1284
|
// could be sent unchecked.
|
|
@@ -1232,7 +1340,7 @@ export class AssistantEvaluationService extends Service {
|
|
|
1232
1340
|
scope: { principalId: owner.principalId, ...principal, workspace: scope.workspace, preset: scope.preset },
|
|
1233
1341
|
sessionId,
|
|
1234
1342
|
idempotencyKey,
|
|
1235
|
-
text: attentionOwnerQuestionText(question, scope),
|
|
1343
|
+
text: attentionOwnerQuestionText(question, scope, { repliesRead: true }),
|
|
1236
1344
|
expiresAt,
|
|
1237
1345
|
attention: { purpose: 'result' },
|
|
1238
1346
|
withdrawable: true,
|
|
@@ -1255,8 +1363,10 @@ export class AssistantEvaluationService extends Service {
|
|
|
1255
1363
|
}
|
|
1256
1364
|
/**
|
|
1257
1365
|
* Host-internal record-only owner reply to the cohort's latest question.
|
|
1258
|
-
* It never records a grant or changes a tuning version
|
|
1259
|
-
*
|
|
1366
|
+
* It never records a grant or changes a tuning version, and it is not the
|
|
1367
|
+
* slice-5 apply path; an owner who authorizes uses
|
|
1368
|
+
* `applyAttentionOwnerQuestionReply` (the only path the Delivery reply
|
|
1369
|
+
* consumer calls) or records a host grant through `grantAttentionLoosening`.
|
|
1260
1370
|
*/
|
|
1261
1371
|
recordAttentionOwnerQuestionReply(input) {
|
|
1262
1372
|
this.assertActive();
|
|
@@ -1272,6 +1382,23 @@ export class AssistantEvaluationService extends Service {
|
|
|
1272
1382
|
|| this.now() >= latest.question.createdAt + this.config.attentionOwnerQuestionNoticeTtlMs;
|
|
1273
1383
|
return this.store.attentionQuestions.recordReply(input.scope, cohort, latest.questionId, input.choice, latest.open, expired);
|
|
1274
1384
|
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Slice 5 evidence-backed apply path for one exact owner reply; the
|
|
1387
|
+
* Delivery consumer and Host callers use this instead of the record-only
|
|
1388
|
+
* seam. `authorize-once` records the reply and creates one bounded one-time
|
|
1389
|
+
* grant for exactly the questioned proposal (parent/candidate bounds, the
|
|
1390
|
+
* proposal's step size, one adoption); the next tuning tick still re-runs
|
|
1391
|
+
* the independent holdout replay before adopting. `decline` closes the
|
|
1392
|
+
* proposal. A proposal that already had an immutable decision returns
|
|
1393
|
+
* `proposal-terminal` and nothing adopts.
|
|
1394
|
+
*/
|
|
1395
|
+
applyAttentionOwnerQuestionReply(input) {
|
|
1396
|
+
this.assertActive();
|
|
1397
|
+
const cohort = this.#attentionCohort(input.cohort);
|
|
1398
|
+
if (!this.config.attentionOwnerQuestionDeliveryEnabled)
|
|
1399
|
+
return Object.freeze({ status: 'rejected', reason: 'delivery-disabled' });
|
|
1400
|
+
return this.store.attention.applyOwnerQuestionReply(input.scope, cohort, input.questionId, input.choice, { noticeTtlMs: this.config.attentionOwnerQuestionNoticeTtlMs });
|
|
1401
|
+
}
|
|
1275
1402
|
/** Per-question delivery decisions and recorded replies for one cohort. */
|
|
1276
1403
|
attentionOwnerQuestionStatus(input) {
|
|
1277
1404
|
this.assertActive();
|
|
@@ -1303,6 +1430,14 @@ export class AssistantEvaluationService extends Service {
|
|
|
1303
1430
|
return this.active && typeof registration === 'object' && registration !== null
|
|
1304
1431
|
&& this.activeOwnerQuestionWithdrawals.has(registration);
|
|
1305
1432
|
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Delivery's slot-anchored proof that the slice-5 reply consumer under the
|
|
1435
|
+
* `assistantEvaluation` authority is this live service's own registration.
|
|
1436
|
+
*/
|
|
1437
|
+
ownsOwnerNotificationReply(registration) {
|
|
1438
|
+
return this.active && typeof registration === 'object' && registration !== null
|
|
1439
|
+
&& this.activeOwnerQuestionReplies.has(registration);
|
|
1440
|
+
}
|
|
1306
1441
|
/** Delivery uses the same ownership boundary as Automations. */
|
|
1307
1442
|
ownsTrustedDeliveryEvaluationRegistration(registration) {
|
|
1308
1443
|
return this.active && typeof registration === 'object' && registration !== null
|