@indexnetwork/protocol 6.9.0-rc.396.1 → 6.10.0-rc.397.1
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/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/negotiation/negotiation.consultation-policy.d.ts +40 -0
- package/dist/negotiation/negotiation.consultation-policy.d.ts.map +1 -0
- package/dist/negotiation/negotiation.consultation-policy.js +69 -0
- package/dist/negotiation/negotiation.consultation-policy.js.map +1 -0
- package/dist/negotiation/negotiation.graph.d.ts +33 -6
- package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
- package/dist/negotiation/negotiation.graph.js +76 -10
- package/dist/negotiation/negotiation.graph.js.map +1 -1
- package/dist/negotiation/negotiation.state.d.ts +3 -0
- package/dist/negotiation/negotiation.state.d.ts.map +1 -1
- package/dist/negotiation/negotiation.state.js +5 -0
- package/dist/negotiation/negotiation.state.js.map +1 -1
- package/dist/questioner/questioner.types.d.ts +3 -0
- package/dist/questioner/questioner.types.d.ts.map +1 -1
- package/dist/questioner/questioner.types.js +5 -0
- package/dist/questioner/questioner.types.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import { requestContext } from "../shared/observability/request-context.js";
|
|
|
4
4
|
import { NegotiationGraphState } from "./negotiation.state.js";
|
|
5
5
|
import { IndexNegotiator } from "./negotiation.agent.js";
|
|
6
6
|
import { ASK_USER_LOCK_SLACK_MS, allowedActionsFor, askUserAnswerWindowMs, configuredAskUserEnabled, configuredProtocolVersion, fallbackActionFor, isRejectLikeAction, isTerminalAction, readProtocolVersion, rejectActionFor } from "./negotiation.protocol.js";
|
|
7
|
+
import { assessConsultationEligibility, consultationPromptFor, negotiationConsultationPolicyMode } from "./negotiation.consultation-policy.js";
|
|
7
8
|
import { NegotiationScreener, configuredScreenMode } from "./negotiation.screen.js";
|
|
8
9
|
import { assessDeadlock, configuredDeadlockShiftEnabled, configuredDeadlockThreshold } from "./negotiation.deadlock.js";
|
|
9
10
|
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
@@ -329,6 +330,11 @@ export class NegotiationGraphFactory {
|
|
|
329
330
|
...(exactContinuation?.execution.consultation
|
|
330
331
|
? { privateConsultation: exactContinuation.execution.consultation }
|
|
331
332
|
: {}),
|
|
333
|
+
...(exactContinuation && (() => {
|
|
334
|
+
const turnContext = priorTask?.metadata?.turnContext;
|
|
335
|
+
const reason = turnContext?.consultationPolicyReason;
|
|
336
|
+
return typeof reason === 'string' ? { consultationPolicyReason: reason } : {};
|
|
337
|
+
})()),
|
|
332
338
|
...(seedMessages.length > 0 && { messages: seedMessages }),
|
|
333
339
|
};
|
|
334
340
|
}
|
|
@@ -468,13 +474,12 @@ export class NegotiationGraphFactory {
|
|
|
468
474
|
const seat = ownUser.id === (state.initiatorUserId ?? state.sourceUser.id)
|
|
469
475
|
? 'initiator'
|
|
470
476
|
: 'counterparty';
|
|
471
|
-
// ask_user availability (P3.2): flag on, full pause loop wired
|
|
477
|
+
// Legacy ask_user availability (P3.2): flag on, full pause loop wired
|
|
472
478
|
// (questioner + answer-window timer + an opportunity to resume
|
|
473
479
|
// against), v2 non-final non-opening turn, and this side's one client
|
|
474
|
-
// consultation not yet spent (rationing).
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
// continuation.
|
|
480
|
+
// consultation not yet spent (rationing). Shadow is observational and
|
|
481
|
+
// must preserve this legacy path byte-for-byte except for telemetry.
|
|
482
|
+
const policyMode = negotiationConsultationPolicyMode();
|
|
478
483
|
const askUserAvailable = version === 'v2'
|
|
479
484
|
&& !isFinalTurn
|
|
480
485
|
&& configuredAskUserEnabled()
|
|
@@ -607,11 +612,55 @@ export class NegotiationGraphFactory {
|
|
|
607
612
|
turn.action = openingAction;
|
|
608
613
|
}
|
|
609
614
|
}
|
|
610
|
-
//
|
|
611
|
-
//
|
|
612
|
-
//
|
|
613
|
-
//
|
|
614
|
-
|
|
615
|
+
// IND-508 deterministic admission is evaluated only after the opening
|
|
616
|
+
// guard but before any turn is persisted. It consumes action/role enums
|
|
617
|
+
// only; free-form reasoning, messages, profiles, and evaluator inputs
|
|
618
|
+
// are intentionally unavailable to the policy.
|
|
619
|
+
let consultationPolicyReason;
|
|
620
|
+
const policyEligibility = policyMode === 'off' ? { eligible: false } : assessConsultationEligibility({
|
|
621
|
+
protocolVersion: version,
|
|
622
|
+
seat,
|
|
623
|
+
isOpeningTurn: state.turnCount === 0 && !state.isContinuation,
|
|
624
|
+
isFinalTurn,
|
|
625
|
+
screenedOut: isScreenBlocked(state),
|
|
626
|
+
action: turn.action,
|
|
627
|
+
ownSuggestedRole: turn.assessment?.suggestedRoles?.ownUser,
|
|
628
|
+
priorActions: history.map((prior) => prior.action),
|
|
629
|
+
previouslyConsulted: hasPriorAskUser(state.messages, ownUser.id),
|
|
630
|
+
hasExactResumeCoordinate: Boolean(configuredAskUserEnabled()
|
|
631
|
+
&& questionerEnqueue
|
|
632
|
+
&& timeoutQueue?.enqueueAskUserExpiry
|
|
633
|
+
&& state.taskId
|
|
634
|
+
&& state.opportunityId
|
|
635
|
+
&& ownIntentId
|
|
636
|
+
&& state.indexContext.networkId),
|
|
637
|
+
lifecycleValid: Boolean(state.taskId && state.opportunityId && ownIntentId && state.indexContext.networkId),
|
|
638
|
+
});
|
|
639
|
+
const emitConsultationTelemetry = (stage, reason) => {
|
|
640
|
+
turnLog.info('negotiation_consultation_policy', { stage, mode: policyMode, reason });
|
|
641
|
+
emitWide({ type: 'negotiation_consultation_policy', stage, mode: policyMode, reason });
|
|
642
|
+
};
|
|
643
|
+
if (policyEligibility.eligible && policyEligibility.reason) {
|
|
644
|
+
emitConsultationTelemetry('eligible', policyEligibility.reason);
|
|
645
|
+
if (policyMode === 'on') {
|
|
646
|
+
consultationPolicyReason = policyEligibility.reason;
|
|
647
|
+
turn = {
|
|
648
|
+
...turn,
|
|
649
|
+
action: 'ask_user',
|
|
650
|
+
message: null,
|
|
651
|
+
assessment: {
|
|
652
|
+
reasoning: 'Client consultation required.',
|
|
653
|
+
suggestedRoles: turn.assessment.suggestedRoles,
|
|
654
|
+
},
|
|
655
|
+
askUser: consultationPromptFor(consultationPolicyReason),
|
|
656
|
+
};
|
|
657
|
+
emitConsultationTelemetry('asked', consultationPolicyReason);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
// Safety net: off/shadow retain legacy behavior. In on, a spontaneous
|
|
661
|
+
// ask_user is admissible only when the deterministic policy just
|
|
662
|
+
// authorized it, so no unbounded pause can enter shared history.
|
|
663
|
+
if (turn.action === 'ask_user' && (!askUserAvailable || (policyMode === 'on' && !consultationPolicyReason))) {
|
|
615
664
|
turnLog.warn('ask_user emitted while unavailable, coercing to conservative fallback', {
|
|
616
665
|
seat, isFinalTurn, taskId: state.taskId,
|
|
617
666
|
});
|
|
@@ -710,6 +759,7 @@ export class NegotiationGraphFactory {
|
|
|
710
759
|
indexContext: state.indexContext,
|
|
711
760
|
seedAssessment: state.seedAssessment,
|
|
712
761
|
...(isSource && state.discoveryQuery && { discoveryQuery: state.discoveryQuery }),
|
|
762
|
+
...(consultationPolicyReason && { consultationPolicyReason }),
|
|
713
763
|
},
|
|
714
764
|
...(state.continuationExecution ? { continuationExecution: state.continuationExecution } : {}),
|
|
715
765
|
});
|
|
@@ -754,6 +804,7 @@ export class NegotiationGraphFactory {
|
|
|
754
804
|
disclosureSubject: safeAskUser.disclosureSubject,
|
|
755
805
|
...(safeAskUser.draftQuestion && { draftQuestion: safeAskUser.draftQuestion }),
|
|
756
806
|
indexContext: NEGOTIATION_QUESTION_GENERIC_NETWORK,
|
|
807
|
+
...(consultationPolicyReason && { consultationPolicyReason }),
|
|
757
808
|
...(userContext && { userContext }),
|
|
758
809
|
},
|
|
759
810
|
}).catch((error) => {
|
|
@@ -1018,6 +1069,21 @@ export class NegotiationGraphFactory {
|
|
|
1018
1069
|
}),
|
|
1019
1070
|
});
|
|
1020
1071
|
}
|
|
1072
|
+
if (state.consultationPolicyReason) {
|
|
1073
|
+
// Stable, content-free terminal funnel telemetry. This executes only
|
|
1074
|
+
// after a fenced continuation has reached its terminal outcome.
|
|
1075
|
+
finalizeLog.info('negotiation_consultation_policy', {
|
|
1076
|
+
stage: 'terminal_outcome',
|
|
1077
|
+
reason: state.consultationPolicyReason,
|
|
1078
|
+
outcome: hasOpportunity ? 'accepted' : (screenedOut || isRejectLikeAction(lastTurn?.action)) ? 'rejected' : 'stalled',
|
|
1079
|
+
});
|
|
1080
|
+
emitWide({
|
|
1081
|
+
type: 'negotiation_consultation_policy',
|
|
1082
|
+
stage: 'terminal_outcome',
|
|
1083
|
+
reason: state.consultationPolicyReason,
|
|
1084
|
+
outcome: hasOpportunity ? 'accepted' : (screenedOut || isRejectLikeAction(lastTurn?.action)) ? 'rejected' : 'stalled',
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1021
1087
|
// Enqueue post-negotiation reflection (P5.2 memory write path) — fire
|
|
1022
1088
|
// and forget: a reflection failure must never affect the outcome. Only
|
|
1023
1089
|
// sessions that actually exchanged turns teach anything; init/turn
|