@indexnetwork/protocol 21.1.0-rc.493.1 → 22.0.0-rc.494.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/CHANGELOG.md +26 -0
- package/dist/chat/chat-streaming.types.d.ts +2 -23
- package/dist/chat/chat-streaming.types.js +0 -3
- package/dist/chat/chat.agent.d.ts +0 -5
- package/dist/chat/chat.streamer.js +3 -6
- package/dist/chat/negotiator.persona.d.ts +1 -1
- package/dist/chat/negotiator.persona.js +0 -7
- package/dist/chat/negotiator.prompt.js +10 -12
- package/dist/chat/onboarding.persona.d.ts +1 -1
- package/dist/chat/onboarding.persona.js +0 -1
- package/dist/chat/onboarding.prompt.js +2 -2
- package/dist/chat/signal.persona.d.ts +1 -1
- package/dist/chat/signal.persona.js +1 -2
- package/dist/chat/signal.prompt.d.ts +6 -5
- package/dist/chat/signal.prompt.js +17 -37
- package/dist/index.d.ts +2 -6
- package/dist/index.js +1 -3
- package/dist/intents/graph/intent.graph.d.ts +1 -2
- package/dist/intents/graph/intent.graph.execute.js +0 -15
- package/dist/intents/graph/intent.graph.js +1 -2
- package/dist/intents/graph/intent.graph.shared.d.ts +0 -2
- package/dist/intents/intent.module.d.ts +0 -3
- package/dist/intents/intent.module.js +2 -2
- package/dist/mcp/mcp.authorization-policy.d.ts +2 -2
- package/dist/mcp/mcp.authorization-policy.js +0 -24
- package/dist/opportunities/opportunity.graph.d.ts +1 -1
- package/dist/opportunities/opportunity.tools.cards.d.ts +0 -13
- package/dist/opportunities/opportunity.tools.cards.js +0 -22
- package/dist/opportunities/opportunity.tools.js +4 -65
- package/dist/opportunities/opportunity.tools.port.d.ts +1 -1
- package/dist/questions/question.env.d.ts +5 -35
- package/dist/questions/question.env.js +5 -70
- package/dist/questions/question.input.d.ts +36 -145
- package/dist/questions/question.input.js +1 -56
- package/dist/questions/question.module.d.ts +10 -22
- package/dist/questions/question.module.js +9 -19
- package/dist/shared/agent/activity-projection.d.ts +2 -2
- package/dist/shared/agent/tool.factory.js +3 -15
- package/dist/shared/agent/tool.helpers.d.ts +0 -73
- package/dist/shared/agent/tool.registry.js +0 -2
- package/dist/shared/agent/tool.runtime.d.ts +1 -1
- package/dist/shared/agent/tool.runtime.js +3 -14
- package/dist/shared/observability/request-context.d.ts +0 -5
- package/package.json +1 -1
- package/dist/opportunities/opportunity.pending-questions.d.ts +0 -33
- package/dist/opportunities/opportunity.pending-questions.js +0 -42
- package/dist/questions/question.agent.d.ts +0 -28
- package/dist/questions/question.agent.js +0 -136
- package/dist/questions/question.ask.tool.d.ts +0 -12
- package/dist/questions/question.ask.tool.js +0 -297
- package/dist/questions/question.persistence.port.d.ts +0 -84
- package/dist/questions/question.persistence.port.js +0 -1
- package/dist/questions/question.presets.d.ts +0 -21
- package/dist/questions/question.presets.js +0 -388
- package/dist/questions/question.tools.d.ts +0 -15
- package/dist/questions/question.tools.js +0 -216
- package/dist/questions/question.tools.port.d.ts +0 -12
- package/dist/questions/question.tools.port.js +0 -1
- package/dist/shared/schemas/pending-question.schema.d.ts +0 -28
- package/dist/shared/schemas/pending-question.schema.js +0 -1
|
@@ -733,7 +733,7 @@ export declare class OpportunityGraphFactory {
|
|
|
733
733
|
seedAssessmentScore?: number | undefined;
|
|
734
734
|
}[]> | undefined;
|
|
735
735
|
discoverySummary?: import("../shared/schemas/discovery-question.schema.js").DiscoverySummary | import("@langchain/langgraph").OverwriteValue<import("../shared/schemas/discovery-question.schema.js").DiscoverySummary | null> | null | undefined;
|
|
736
|
-
}, "scope" | "__start__" | "
|
|
736
|
+
}, "scope" | "__start__" | "prep" | "discovery" | "evaluation" | "persist" | "negotiate" | "resolve" | "ranking", {
|
|
737
737
|
userId: import("@langchain/langgraph").BaseChannel<import("./opportunity.graph.shared.js").Id<"users">, import("./opportunity.graph.shared.js").Id<"users"> | import("@langchain/langgraph").OverwriteValue<import("./opportunity.graph.shared.js").Id<"users">>, unknown>;
|
|
738
738
|
searchQuery: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
|
|
739
739
|
networkId: import("@langchain/langgraph").BaseChannel<import("./opportunity.graph.shared.js").Id<"networks"> | undefined, import("./opportunity.graph.shared.js").Id<"networks"> | import("@langchain/langgraph").OverwriteValue<import("./opportunity.graph.shared.js").Id<"networks"> | undefined> | undefined, unknown>;
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
import { type OpportunityOwnerAction, type OpportunityOwnerApprovalVerdict } from "./opportunity.owner-approval.js";
|
|
9
9
|
export declare function stripLeadingNarratorName(remark: string, narratorName: string): string;
|
|
10
10
|
import type { Opportunity } from "../shared/interfaces/database.interface.js";
|
|
11
|
-
import type { PendingQuestionSummary } from "../shared/schemas/pending-question.schema.js";
|
|
12
11
|
export declare const logger: import("../shared/observability/log.js").LoggerWithSource;
|
|
13
12
|
/**
|
|
14
13
|
* Build the agent-facing profile link for a counterpart — always the Index web
|
|
@@ -72,18 +71,6 @@ export declare function attachOpportunityAppLink(card: Record<string, unknown> &
|
|
|
72
71
|
}, opts: {
|
|
73
72
|
frontendUrl: string | undefined;
|
|
74
73
|
}): void;
|
|
75
|
-
export interface PublicUptakeQuestion {
|
|
76
|
-
id: string;
|
|
77
|
-
title: string;
|
|
78
|
-
prompt: string;
|
|
79
|
-
options: Array<{
|
|
80
|
-
label: string;
|
|
81
|
-
description: string;
|
|
82
|
-
}>;
|
|
83
|
-
multiSelect: boolean;
|
|
84
|
-
}
|
|
85
|
-
export declare function publicUptakeQuestion(question: PendingQuestionSummary): PublicUptakeQuestion;
|
|
86
|
-
export declare function uptakeAdvisory(opportunityId: string, questions: PublicUptakeQuestion[]): string;
|
|
87
74
|
/**
|
|
88
75
|
* IND-593: stable fail-closed denial for the owner-approval boundary. The
|
|
89
76
|
* `missing` reason carries the fresh, server-derived interaction challenge the
|
|
@@ -111,28 +111,6 @@ export function attachOpportunityAppLink(card, opts) {
|
|
|
111
111
|
if (appUrl)
|
|
112
112
|
card.appUrl = appUrl;
|
|
113
113
|
}
|
|
114
|
-
export function publicUptakeQuestion(question) {
|
|
115
|
-
return {
|
|
116
|
-
id: question.id,
|
|
117
|
-
title: question.title,
|
|
118
|
-
prompt: question.prompt,
|
|
119
|
-
options: question.options,
|
|
120
|
-
multiSelect: question.multiSelect,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
export function uptakeAdvisory(opportunityId, questions) {
|
|
124
|
-
return JSON.stringify({
|
|
125
|
-
success: false,
|
|
126
|
-
error: "Resolve the pending uptake questions or explicitly continue anyway.",
|
|
127
|
-
advisory: {
|
|
128
|
-
code: "unresolved_uptake_questions",
|
|
129
|
-
advisoryOnly: true,
|
|
130
|
-
opportunityId,
|
|
131
|
-
questions,
|
|
132
|
-
acknowledgedUptakeQuestionIds: questions.map((question) => question.id),
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
114
|
/**
|
|
137
115
|
* IND-593: stable fail-closed denial for the owner-approval boundary. The
|
|
138
116
|
* `missing` reason carries the fresh, server-derived interaction challenge the
|
|
@@ -10,14 +10,13 @@ import { requestContext } from "../shared/observability/request-context.js";
|
|
|
10
10
|
import { success, error, UUID_REGEX } from "../shared/agent/tool.helpers.js";
|
|
11
11
|
import { focusedIntentId, focusedNetworkId } from "../shared/agent/tool.scope.js";
|
|
12
12
|
import { OpportunityPresenter, gatherPresenterContext } from "./opportunity.presentation.js";
|
|
13
|
-
import { isUptakeGuardEnabled } from "../questions/question.module.js";
|
|
14
13
|
import { admitOpportunityUpdate } from "./opportunity.update-admission.js";
|
|
15
14
|
import { opportunityOwnerActionForStatus } from "./opportunity.owner-approval.js";
|
|
16
15
|
import { ownerApprovalProvenanceFor } from "./opportunity.owner-provenance.js";
|
|
17
16
|
export { buildOpportunityPresentation } from "./opportunity.presentation.js";
|
|
18
17
|
import { sendOpportunity, updateOpportunityStatus } from "./opportunity.graph.modes.js";
|
|
19
18
|
import { createListOpportunitiesTool } from "./opportunity.tools.list.js";
|
|
20
|
-
import { confirmDeliveryError, logger, ownerApprovalDenial
|
|
19
|
+
import { confirmDeliveryError, logger, ownerApprovalDenial } from "./opportunity.tools.cards.js";
|
|
21
20
|
export { attachOpportunityAppLink, attachProfileLink, buildMinimalOpportunityCard, buildNegotiationUrl, buildOpportunityAppUrl, buildProfileUrl } from "./opportunity.tools.cards.js";
|
|
22
21
|
export function createOpportunityTools(defineTool, deps) {
|
|
23
22
|
const { database, userDb, systemDb, graphs, cache } = deps;
|
|
@@ -36,13 +35,12 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
36
35
|
"- `rejected`: Decline a received opportunity.\n" +
|
|
37
36
|
"- `expired`: Mark as expired (typically done by the system after timeout).\n\n" +
|
|
38
37
|
"**When to use:** After list_opportunities returns persisted opportunity cards. " +
|
|
39
|
-
"The user clicks 'Send' (pending), 'Accept', or 'Reject' on the card, and the agent calls this tool
|
|
40
|
-
"An accepted transition may first return a non-success uptake advisory with preparatory questions. Surface those questions, then retry with all returned question ids in acknowledgedUptakeQuestionIds; acknowledgement confirms presentation, not an answer.\n\n" +
|
|
38
|
+
"The user clicks 'Send' (pending), 'Accept', or 'Reject' on the card, and the agent calls this tool.\n\n" +
|
|
41
39
|
"**Owner approval (agents):** Agent-driven send/accept/reject transitions require an explicit owner-issued approval proof. " +
|
|
42
40
|
"Call without ownerApprovalProof first: the denial returns an approval challenge (interactionId, expiresAt) bound to the exact opportunity, action, owner, and agent. " +
|
|
43
41
|
"Relay that challenge to the owner for explicit approval, then retry once with the issued ownerApprovalProof. " +
|
|
44
|
-
"Proofs are single-use and expire;
|
|
45
|
-
"**Returns:** Confirmation with the new status and notification details (who was notified)
|
|
42
|
+
"Proofs are single-use and expire; negotiation approvals and advisory values are never substitutes.\n\n" +
|
|
43
|
+
"**Returns:** Confirmation with the new status and notification details (who was notified).",
|
|
46
44
|
querySchema: z.object({
|
|
47
45
|
opportunityId: z
|
|
48
46
|
.string()
|
|
@@ -58,10 +56,6 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
58
56
|
.describe("Opaque owner-issued approval proof for this exact transition (agents only). Obtained after the owner " +
|
|
59
57
|
"explicitly approves the interaction challenge returned by a proof-less call. The opportunity, action, " +
|
|
60
58
|
"owner, agent, and interaction binding is always derived server-side; only this token is presented."),
|
|
61
|
-
acknowledgedUptakeQuestionIds: z
|
|
62
|
-
.array(z.string().min(1))
|
|
63
|
-
.optional()
|
|
64
|
-
.describe("On an acknowledged retry after an uptake advisory, include every question id returned by that advisory."),
|
|
65
59
|
scopeType: z
|
|
66
60
|
.enum(['intent'])
|
|
67
61
|
.optional()
|
|
@@ -137,61 +131,6 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
137
131
|
if (verdict.kind === 'denied')
|
|
138
132
|
return ownerApprovalDenial(opportunityId, ownerAction, verdict);
|
|
139
133
|
}
|
|
140
|
-
// The caller actor's own network is the exact question lookup boundary,
|
|
141
|
-
// even for an otherwise unscoped request. A focused network may only be
|
|
142
|
-
// equal to this after the guard above.
|
|
143
|
-
// Unscoped callers query all of their exact opportunity questions; a
|
|
144
|
-
// network-scoped caller is clamped to the bound network. Selecting the
|
|
145
|
-
// first duplicate actor row would miss a valid question on another
|
|
146
|
-
// shared network.
|
|
147
|
-
const uptakeNetworkId = scopedNetworkId;
|
|
148
|
-
// Soft uptake interlock: only acceptance is advisory-gated. All existing
|
|
149
|
-
// actor/scope/privacy guards run first so the question lookup cannot be
|
|
150
|
-
// used to probe opportunities or networks the caller cannot access.
|
|
151
|
-
if (query.status === "accepted" && isUptakeGuardEnabled() && deps.findPendingQuestions) {
|
|
152
|
-
try {
|
|
153
|
-
const pending = await deps.findPendingQuestions(context.userId, {
|
|
154
|
-
sourceType: "opportunity",
|
|
155
|
-
sourceId: opportunityId,
|
|
156
|
-
modes: ["negotiation"],
|
|
157
|
-
purpose: "uptake",
|
|
158
|
-
...(uptakeNetworkId ? { networkId: uptakeNetworkId } : {}),
|
|
159
|
-
});
|
|
160
|
-
// Defense in depth if a host overlooks one or more filters. Actor
|
|
161
|
-
// internals are checked here and never serialized into the advisory.
|
|
162
|
-
const exactPending = pending.filter((question) => {
|
|
163
|
-
if (question.sourceType !== "opportunity" ||
|
|
164
|
-
question.sourceId !== opportunityId ||
|
|
165
|
-
question.mode !== "negotiation" ||
|
|
166
|
-
question.purpose !== "uptake") {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
if (!question.actors?.some((actor) => actor.userId === context.userId))
|
|
170
|
-
return false;
|
|
171
|
-
if (uptakeNetworkId && !question.actors.some((actor) => actor.userId === context.userId && actor.networkId === uptakeNetworkId)) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
return true;
|
|
175
|
-
});
|
|
176
|
-
const acknowledged = new Set(query.acknowledgedUptakeQuestionIds ?? []);
|
|
177
|
-
if (exactPending.some((question) => !acknowledged.has(question.id))) {
|
|
178
|
-
return uptakeAdvisory(opportunityId, exactPending.map(publicUptakeQuestion));
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch (err) {
|
|
182
|
-
logger.warn("update_opportunity: uptake question lookup failed open", {
|
|
183
|
-
opportunityId,
|
|
184
|
-
userId: context.userId,
|
|
185
|
-
error: err instanceof Error ? err.message : String(err),
|
|
186
|
-
});
|
|
187
|
-
deps.reportToolError?.(err, {
|
|
188
|
-
subsystem: "opportunity",
|
|
189
|
-
operation: "opportunity.uptake_lookup",
|
|
190
|
-
toolName: "update_opportunity",
|
|
191
|
-
userId: context.userId,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
134
|
const isSend = query.status === "pending";
|
|
196
135
|
const _updateGraphStart = Date.now();
|
|
197
136
|
const _updateTraceEmitter = requestContext.getStore()?.traceEmitter;
|
|
@@ -11,6 +11,6 @@ export interface OpportunityOwnerApprovalDeps {
|
|
|
11
11
|
opportunityOwnerApproval?: OpportunityOwnerApprovalAuthority;
|
|
12
12
|
}
|
|
13
13
|
/** Host capabilities consumed by opportunity discovery, delivery, and presentation tools. */
|
|
14
|
-
export type OpportunityToolDeps = Pick<ToolRegistryCompositionDeps, "database" | "userDb" | "systemDb" | "cache" | "chatSummary" | "opportunityPresentation" | "questionerEnqueue" | "
|
|
14
|
+
export type OpportunityToolDeps = Pick<ToolRegistryCompositionDeps, "database" | "userDb" | "systemDb" | "cache" | "chatSummary" | "opportunityPresentation" | "questionerEnqueue" | "negotiationSummary" | "negotiationDatabase" | "deliveryLedger" | "frontendUrl" | "stampNewbornOpportunities" | "reportToolError" | "opportunityOperations"> & OpportunityOwnerApprovalDeps & {
|
|
15
15
|
graphs: Pick<ToolRegistryCompositionDeps["graphs"], "index" | "networkMembership" | "opportunity">;
|
|
16
16
|
};
|
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* questions/question.env —
|
|
2
|
+
* questions/question.env — leftover question env constants.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* QUESTIONER_UPTAKE_ENABLED per-surface switch — advisory pre-accept uptake
|
|
9
|
-
* interlock. Requires the master switch.
|
|
10
|
-
* QUESTIONER_UPTAKE_AUTHORITY_THRESHOLD
|
|
11
|
-
* authority threshold (0-100, default 70).
|
|
12
|
-
* QUESTIONER_CHAT_WAIT_TIMEOUT_MS how long the blocking ask_user_question chat
|
|
13
|
-
* tool waits for an inline answer (default 4 min).
|
|
14
|
-
* QUESTIONER_INTENT_DAILY_CAP refinement questions one intent may generate
|
|
15
|
-
* per rolling 24h, recovery + pool combined
|
|
16
|
-
* (default 2; 0 disables refinement).
|
|
17
|
-
*
|
|
18
|
-
* All reads go through this module — do not read these variables via
|
|
19
|
-
* `process.env` elsewhere. Values are read on every call (no caching) so tests
|
|
20
|
-
* and long-lived processes observe changes.
|
|
4
|
+
* The QUESTIONER_* runtime flags are retired with the card generators
|
|
5
|
+
* (conversational-questions plan); park-path routing is always on. What
|
|
6
|
+
* remains are the historical budget constants still referenced by the
|
|
7
|
+
* questions-table adapter until its surface drops.
|
|
21
8
|
*/
|
|
22
|
-
export declare const CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT = 240000;
|
|
23
|
-
export declare const UPTAKE_AUTHORITY_THRESHOLD_DEFAULT = 70;
|
|
24
9
|
/**
|
|
25
10
|
* Refinement questions a single intent may generate per rolling window.
|
|
26
11
|
*
|
|
@@ -40,18 +25,3 @@ export declare const INTENT_QUESTION_DAILY_CAP_DEFAULT = 2;
|
|
|
40
25
|
* have granted the second burst a full fresh allowance.
|
|
41
26
|
*/
|
|
42
27
|
export declare const INTENT_QUESTION_DAILY_WINDOW_HOURS = 24;
|
|
43
|
-
/** Master switch: is any background question generation enabled? */
|
|
44
|
-
export declare function isQuestionerEnabled(): boolean;
|
|
45
|
-
/** Advisory uptake interlock. Flag-off by default and subordinate to the master switch. */
|
|
46
|
-
export declare function isUptakeGuardEnabled(): boolean;
|
|
47
|
-
/** Authority threshold below which hosts may generate uptake questions. */
|
|
48
|
-
export declare function uptakeAuthorityThreshold(): number;
|
|
49
|
-
/** Wait budget for the blocking ask_user_question chat tool. */
|
|
50
|
-
export declare function chatQuestionWaitTimeoutMs(): number;
|
|
51
|
-
/**
|
|
52
|
-
* Per-intent refinement budget over {@link INTENT_QUESTION_DAILY_WINDOW_HOURS}.
|
|
53
|
-
*
|
|
54
|
-
* Zero is a meaningful setting — it disables background refinement entirely
|
|
55
|
-
* without touching the master switch — so this does not reuse `positiveIntEnv`.
|
|
56
|
-
*/
|
|
57
|
-
export declare function intentQuestionDailyCap(): number;
|
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* questions/question.env —
|
|
2
|
+
* questions/question.env — leftover question env constants.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* QUESTIONER_UPTAKE_ENABLED per-surface switch — advisory pre-accept uptake
|
|
9
|
-
* interlock. Requires the master switch.
|
|
10
|
-
* QUESTIONER_UPTAKE_AUTHORITY_THRESHOLD
|
|
11
|
-
* authority threshold (0-100, default 70).
|
|
12
|
-
* QUESTIONER_CHAT_WAIT_TIMEOUT_MS how long the blocking ask_user_question chat
|
|
13
|
-
* tool waits for an inline answer (default 4 min).
|
|
14
|
-
* QUESTIONER_INTENT_DAILY_CAP refinement questions one intent may generate
|
|
15
|
-
* per rolling 24h, recovery + pool combined
|
|
16
|
-
* (default 2; 0 disables refinement).
|
|
17
|
-
*
|
|
18
|
-
* All reads go through this module — do not read these variables via
|
|
19
|
-
* `process.env` elsewhere. Values are read on every call (no caching) so tests
|
|
20
|
-
* and long-lived processes observe changes.
|
|
4
|
+
* The QUESTIONER_* runtime flags are retired with the card generators
|
|
5
|
+
* (conversational-questions plan); park-path routing is always on. What
|
|
6
|
+
* remains are the historical budget constants still referenced by the
|
|
7
|
+
* questions-table adapter until its surface drops.
|
|
21
8
|
*/
|
|
22
|
-
export const CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT = 240000;
|
|
23
|
-
export const UPTAKE_AUTHORITY_THRESHOLD_DEFAULT = 70;
|
|
24
9
|
/**
|
|
25
10
|
* Refinement questions a single intent may generate per rolling window.
|
|
26
11
|
*
|
|
@@ -40,53 +25,3 @@ export const INTENT_QUESTION_DAILY_CAP_DEFAULT = 2;
|
|
|
40
25
|
* have granted the second burst a full fresh allowance.
|
|
41
26
|
*/
|
|
42
27
|
export const INTENT_QUESTION_DAILY_WINDOW_HOURS = 24;
|
|
43
|
-
/**
|
|
44
|
-
* Parse a positive integer env var, clamped to the safe-integer range so a
|
|
45
|
-
* malformed env value cannot crash `AbortSignal.timeout` (which throws on
|
|
46
|
-
* values outside `[0, MAX_SAFE_INTEGER]`).
|
|
47
|
-
*/
|
|
48
|
-
function positiveIntEnv(name, fallback) {
|
|
49
|
-
const raw = process.env[name];
|
|
50
|
-
if (!raw)
|
|
51
|
-
return fallback;
|
|
52
|
-
const parsed = Number.parseInt(raw, 10);
|
|
53
|
-
if (!Number.isFinite(parsed) || parsed <= 0 || parsed > Number.MAX_SAFE_INTEGER)
|
|
54
|
-
return fallback;
|
|
55
|
-
return parsed;
|
|
56
|
-
}
|
|
57
|
-
/** Master switch: is any background question generation enabled? */
|
|
58
|
-
export function isQuestionerEnabled() {
|
|
59
|
-
return process.env.QUESTIONER_ENABLED === "true";
|
|
60
|
-
}
|
|
61
|
-
/** Advisory uptake interlock. Flag-off by default and subordinate to the master switch. */
|
|
62
|
-
export function isUptakeGuardEnabled() {
|
|
63
|
-
return isQuestionerEnabled() && process.env.QUESTIONER_UPTAKE_ENABLED === "true";
|
|
64
|
-
}
|
|
65
|
-
/** Authority threshold below which hosts may generate uptake questions. */
|
|
66
|
-
export function uptakeAuthorityThreshold() {
|
|
67
|
-
const raw = process.env.QUESTIONER_UPTAKE_AUTHORITY_THRESHOLD;
|
|
68
|
-
if (!raw?.trim())
|
|
69
|
-
return UPTAKE_AUTHORITY_THRESHOLD_DEFAULT;
|
|
70
|
-
if (!/^-?\d+$/.test(raw.trim()))
|
|
71
|
-
return UPTAKE_AUTHORITY_THRESHOLD_DEFAULT;
|
|
72
|
-
const parsed = Number.parseInt(raw, 10);
|
|
73
|
-
return Math.min(100, Math.max(0, parsed));
|
|
74
|
-
}
|
|
75
|
-
/** Wait budget for the blocking ask_user_question chat tool. */
|
|
76
|
-
export function chatQuestionWaitTimeoutMs() {
|
|
77
|
-
return positiveIntEnv("QUESTIONER_CHAT_WAIT_TIMEOUT_MS", CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Per-intent refinement budget over {@link INTENT_QUESTION_DAILY_WINDOW_HOURS}.
|
|
81
|
-
*
|
|
82
|
-
* Zero is a meaningful setting — it disables background refinement entirely
|
|
83
|
-
* without touching the master switch — so this does not reuse `positiveIntEnv`.
|
|
84
|
-
*/
|
|
85
|
-
export function intentQuestionDailyCap() {
|
|
86
|
-
const raw = process.env.QUESTIONER_INTENT_DAILY_CAP;
|
|
87
|
-
if (!raw?.trim())
|
|
88
|
-
return INTENT_QUESTION_DAILY_CAP_DEFAULT;
|
|
89
|
-
if (!/^\d+$/.test(raw.trim()))
|
|
90
|
-
return INTENT_QUESTION_DAILY_CAP_DEFAULT;
|
|
91
|
-
return Number.parseInt(raw, 10);
|
|
92
|
-
}
|
|
@@ -1,37 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* questions/question.input —
|
|
2
|
+
* questions/question.input — park-path question payloads.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Foreground and ambient adapter entry points inject a `QuestionerEnqueueFn`
|
|
14
|
-
* (defined here as a port alias) to schedule async generation without
|
|
15
|
-
* importing the queue implementation.
|
|
4
|
+
* The QuestionerAgent and its per-mode generation envelope are retired
|
|
5
|
+
* (conversational-questions plan, "Retirements"). What survives is the
|
|
6
|
+
* payload the negotiation graph hands the composition root when a
|
|
7
|
+
* negotiation parks needing its client's input: the two park families
|
|
8
|
+
* (`negotiation_inflight`/`inflight_consultation` mid-flight consults and
|
|
9
|
+
* `negotiation`/`stalled_followup` post-stall parks). The composition root
|
|
10
|
+
* routes them to the question-message regeneration queue keyed on the parked
|
|
11
|
+
* side's `(recipientUserId, recipientIntentId)`; the parked negotiation is
|
|
12
|
+
* the durable record and the DM message is its rendering.
|
|
16
13
|
*/
|
|
17
14
|
import type { ToolScopeType } from "../shared/agent/tool.scope.js";
|
|
18
|
-
import type { NegotiationQuestionCandidate
|
|
15
|
+
import type { NegotiationQuestionCandidate } from "./question.schema.js";
|
|
19
16
|
import type { NegotiationConsultationReason } from "../negotiations/negotiation.module.js";
|
|
20
|
-
/**
|
|
21
|
-
export interface IntentContext {
|
|
22
|
-
intentId: string;
|
|
23
|
-
payload: string;
|
|
24
|
-
summary?: string;
|
|
25
|
-
/** The user's global user_context paragraph (profile-replacing identity text). */
|
|
26
|
-
userContext?: string;
|
|
27
|
-
}
|
|
28
|
-
/** Recovery-only intent context after a successful discovery completion. */
|
|
29
|
-
export interface RecoveryIntentContext extends IntentContext {
|
|
30
|
-
purpose: "recovery";
|
|
31
|
-
/** Privacy-safe aggregate signal; raw negotiation evidence is never provided. */
|
|
32
|
-
rejectedNegotiationCount?: number;
|
|
33
|
-
}
|
|
34
|
-
/** Shared context fields for negotiation-mode questions. */
|
|
17
|
+
/** Shared context fields for negotiation park payloads. */
|
|
35
18
|
interface NegotiationContextBase {
|
|
36
19
|
negotiationId: string;
|
|
37
20
|
/** Privacy-reviewed generic description; never raw counterparty identity/profile. */
|
|
@@ -48,20 +31,10 @@ export interface PostStallNegotiationContext extends NegotiationContextBase {
|
|
|
48
31
|
/** The recipient's own exact opportunity-bound signal, never evaluator reasoning. */
|
|
49
32
|
recipientIntent: string;
|
|
50
33
|
}
|
|
51
|
-
/** Pre-accept uptake context targeting a counterparty's preparatory conditions. */
|
|
52
|
-
export interface UptakeNegotiationContext extends NegotiationContextBase {
|
|
53
|
-
purpose: "uptake";
|
|
54
|
-
/** Plain-language activity or commitment whose feasibility needs clarification. */
|
|
55
|
-
proposedActivity: string;
|
|
56
|
-
}
|
|
57
|
-
/** Negotiation context discriminated by internal question purpose. */
|
|
58
|
-
export type NegotiationContext = PostStallNegotiationContext | UptakeNegotiationContext;
|
|
59
34
|
/**
|
|
60
35
|
* Negotiation-inflight context — a negotiator mid-negotiation wants to ask its
|
|
61
|
-
* OWN client a question before continuing (the `ask_user` action, P3.2).
|
|
62
|
-
* negotiator supplies only a closed category
|
|
63
|
-
* server-owned fixed copy and never agent-authored instruction text.
|
|
64
|
-
* Distinct from {@link NegotiationContext}, which covers post-stall questions.
|
|
36
|
+
* OWN client a question before continuing (the `ask_user` action, P3.2).
|
|
37
|
+
* The negotiator supplies only a closed category.
|
|
65
38
|
*/
|
|
66
39
|
export interface NegotiationInflightContext {
|
|
67
40
|
negotiationId: string;
|
|
@@ -69,108 +42,47 @@ export interface NegotiationInflightContext {
|
|
|
69
42
|
counterpartyHint: string;
|
|
70
43
|
/** Community / index context the negotiation runs in. */
|
|
71
44
|
indexContext: string;
|
|
72
|
-
/** Closed server-owned category selecting
|
|
45
|
+
/** Closed server-owned category selecting the consultation reason. */
|
|
73
46
|
consultationPolicyReason: NegotiationConsultationReason;
|
|
74
47
|
/** The user's global user_context paragraph (profile-replacing identity text). */
|
|
75
48
|
userContext?: string;
|
|
76
49
|
}
|
|
77
50
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* grounded in the recent conversation and the user's identity context.
|
|
82
|
-
*/
|
|
83
|
-
export interface ChatContext {
|
|
84
|
-
/** What the orchestrator needs to learn and why (authored by the chat model). */
|
|
85
|
-
purpose: string;
|
|
86
|
-
/** Draft questions proposed by the orchestrator. The agent refines these. */
|
|
87
|
-
draftQuestions?: Array<{
|
|
88
|
-
prompt: string;
|
|
89
|
-
options?: string[];
|
|
90
|
-
multiSelect?: boolean;
|
|
91
|
-
}>;
|
|
92
|
-
/** Recent conversation excerpt for grounding (most recent messages last). */
|
|
93
|
-
conversationExcerpt?: string;
|
|
94
|
-
/** The user's global user_context paragraph (profile-replacing identity text). */
|
|
95
|
-
userContext?: string;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Pool-discovery context — mined discriminators from a discovery-run pool
|
|
99
|
-
* (IND-418). No generator LLM runs for this mode: the QuestionerQueue
|
|
100
|
-
* synthesizes the question deterministically from the top discriminator and
|
|
101
|
-
* stashes the rest as interview-mode alternates.
|
|
102
|
-
*/
|
|
103
|
-
export interface PoolDiscoveryContext {
|
|
104
|
-
intentId: string;
|
|
105
|
-
/** Truncated intent payload (+ summary) display snippet. */
|
|
106
|
-
intentText: string;
|
|
107
|
-
/** Stable hash of the full normalized payload + summary used for freshness. */
|
|
108
|
-
intentFingerprint?: string;
|
|
109
|
-
poolSize: number;
|
|
110
|
-
/** Exact bounded candidate opportunity IDs supplied to synthesis. */
|
|
111
|
-
opportunityIds: string[];
|
|
112
|
-
/** Discovery run that produced the pool. */
|
|
113
|
-
runId?: string;
|
|
114
|
-
/** Eligible discriminators, VoI-descending (asked + chain alternates). */
|
|
115
|
-
discriminators: QuestionPoolDiscriminator[];
|
|
116
|
-
/** ISO-8601 timestamp of the mining pass. */
|
|
117
|
-
minedAt: string;
|
|
118
|
-
}
|
|
119
|
-
/** Discriminated union: mode selects the context shape. */
|
|
120
|
-
export type QuestionerContext = IntentContext | RecoveryIntentContext | NegotiationContext | NegotiationInflightContext | ChatContext | PoolDiscoveryContext;
|
|
121
|
-
/**
|
|
122
|
-
* Payload shape accepted by the questionerEnqueue callback. Covers all
|
|
123
|
-
* question modes — the composition root bridges this to the concrete
|
|
124
|
-
* QuestionerQueue.
|
|
51
|
+
* Payload shape accepted by the questionerEnqueue callback: exactly the two
|
|
52
|
+
* park families. The composition root bridges this to the question-message
|
|
53
|
+
* regeneration queue.
|
|
125
54
|
*/
|
|
126
55
|
export type QuestionerEnqueuePayload = QuestionerInput;
|
|
127
56
|
/**
|
|
128
|
-
* Callback signature for
|
|
57
|
+
* Callback signature for the park-path enqueue.
|
|
129
58
|
*
|
|
130
|
-
* Ambient adapter port:
|
|
131
|
-
*
|
|
132
|
-
* queue implementation directly.
|
|
59
|
+
* Ambient adapter port: the negotiation graph and the external-consultation
|
|
60
|
+
* pause path inject this callback from the composition root; they never
|
|
61
|
+
* import the queue implementation directly.
|
|
133
62
|
*/
|
|
134
63
|
export type QuestionerEnqueueFn = (input: QuestionerEnqueuePayload) => Promise<void>;
|
|
135
|
-
/**
|
|
64
|
+
/** Shared envelope fields for both park families. */
|
|
136
65
|
interface QuestionerInputBase {
|
|
137
|
-
/**
|
|
138
|
-
mode: QuestionMode;
|
|
139
|
-
/** User the questions are generated for. */
|
|
66
|
+
/** User whose input is required (the parked side). */
|
|
140
67
|
userId: string;
|
|
141
|
-
/** Entity type that triggered this (
|
|
68
|
+
/** Entity type that triggered this (always "opportunity" for park payloads). */
|
|
142
69
|
sourceType: string;
|
|
143
70
|
/** ID of the triggering entity. */
|
|
144
71
|
sourceId: string;
|
|
145
|
-
/** Scoped
|
|
72
|
+
/** Scoped context carried through from the triggering surface. */
|
|
146
73
|
scopeType?: ToolScopeType;
|
|
147
|
-
/** Scoped
|
|
74
|
+
/** Scoped id. When scopeType is `network`, this is the network id. */
|
|
148
75
|
scopeId?: string;
|
|
149
|
-
/**
|
|
150
|
-
* Intent that triggered the run that generated these questions. Persisted as
|
|
151
|
-
* `detection.triggeredBy` so intent-scoped surfaces (e.g. the intent page)
|
|
152
|
-
* can find them. Independent of `scopeType`/`scopeId`, which may carry a
|
|
153
|
-
* network scope at the same time.
|
|
154
|
-
*/
|
|
76
|
+
/** Intent that triggered the run, when the producer knows it. */
|
|
155
77
|
triggeredByIntentId?: string;
|
|
156
|
-
/** Conversation ID — set when the question originates from a chat session. Persisted on the question row for frontend filtering. */
|
|
157
|
-
conversationId?: string;
|
|
158
|
-
/** Assistant message ID — set when we know which message triggered the question. Stored in detection.messageId for inline anchoring. */
|
|
159
|
-
messageId?: string;
|
|
160
78
|
/**
|
|
161
|
-
* Candidate exact binding
|
|
162
|
-
*
|
|
79
|
+
* Candidate exact binding. `recipientUserId`/`recipientIntentId` name the
|
|
80
|
+
* parked side — the user whose input is required and the signal whose DM
|
|
81
|
+
* carries the question-message.
|
|
163
82
|
*/
|
|
164
|
-
negotiation
|
|
165
|
-
}
|
|
166
|
-
/** Non-negotiation modes cannot smuggle negotiation purpose/provenance. */
|
|
167
|
-
interface StandardQuestionerInput extends QuestionerInputBase {
|
|
168
|
-
mode: Exclude<QuestionMode, "negotiation" | "negotiation_inflight">;
|
|
169
|
-
purpose?: never;
|
|
170
|
-
negotiation?: never;
|
|
171
|
-
context: Exclude<QuestionerContext, NegotiationContext | NegotiationInflightContext | RecoveryIntentContext>;
|
|
83
|
+
negotiation: NegotiationQuestionCandidate;
|
|
172
84
|
}
|
|
173
|
-
/**
|
|
85
|
+
/** Post-stall park payload, task-backed. */
|
|
174
86
|
export interface PostStallQuestionerInput extends QuestionerInputBase {
|
|
175
87
|
mode: "negotiation";
|
|
176
88
|
purpose: "stalled_followup";
|
|
@@ -180,7 +92,7 @@ export interface PostStallQuestionerInput extends QuestionerInputBase {
|
|
|
180
92
|
};
|
|
181
93
|
context: PostStallNegotiationContext;
|
|
182
94
|
}
|
|
183
|
-
/** Mid-negotiation consultation
|
|
95
|
+
/** Mid-negotiation consultation park payload, task-backed. */
|
|
184
96
|
export interface InflightQuestionerInput extends QuestionerInputBase {
|
|
185
97
|
mode: "negotiation_inflight";
|
|
186
98
|
purpose: "inflight_consultation";
|
|
@@ -190,27 +102,6 @@ export interface InflightQuestionerInput extends QuestionerInputBase {
|
|
|
190
102
|
};
|
|
191
103
|
context: NegotiationInflightContext;
|
|
192
104
|
}
|
|
193
|
-
/**
|
|
194
|
-
export
|
|
195
|
-
mode: "negotiation";
|
|
196
|
-
purpose: "uptake";
|
|
197
|
-
negotiation: NegotiationQuestionCandidate & {
|
|
198
|
-
purpose: "uptake";
|
|
199
|
-
taskId?: undefined;
|
|
200
|
-
};
|
|
201
|
-
context: UptakeNegotiationContext;
|
|
202
|
-
}
|
|
203
|
-
/** Intent-mode post-discovery recovery generation input. */
|
|
204
|
-
export interface RecoveryQuestionerInput extends QuestionerInputBase {
|
|
205
|
-
mode: "intent";
|
|
206
|
-
purpose: "recovery";
|
|
207
|
-
sourceType: "intent";
|
|
208
|
-
triggeredByIntentId: string;
|
|
209
|
-
negotiation?: never;
|
|
210
|
-
context: RecoveryIntentContext;
|
|
211
|
-
}
|
|
212
|
-
/** Top-level input discriminated by both mode and internal purpose. */
|
|
213
|
-
export type QuestionerInput = StandardQuestionerInput | PostStallQuestionerInput | InflightQuestionerInput | UptakeQuestionerInput | RecoveryQuestionerInput;
|
|
214
|
-
/** Runtime mirror of the mode/purpose/context discriminant used at queue boundaries. */
|
|
215
|
-
export declare function isValidQuestionerInputContract(input: QuestionerInput): boolean;
|
|
105
|
+
/** Park-path payload union, discriminated by mode + internal purpose. */
|
|
106
|
+
export type QuestionerInput = PostStallQuestionerInput | InflightQuestionerInput;
|
|
216
107
|
export {};
|
|
@@ -1,56 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/** Runtime mirror of the mode/purpose/context discriminant used at queue boundaries. */
|
|
3
|
-
export function isValidQuestionerInputContract(input) {
|
|
4
|
-
if (input.purpose === 'recovery') {
|
|
5
|
-
const context = input.context;
|
|
6
|
-
return input.mode === 'intent'
|
|
7
|
-
&& input.sourceType === 'intent'
|
|
8
|
-
&& input.triggeredByIntentId === input.sourceId
|
|
9
|
-
&& input.negotiation === undefined
|
|
10
|
-
&& context.purpose === 'recovery'
|
|
11
|
-
&& context.intentId === input.sourceId;
|
|
12
|
-
}
|
|
13
|
-
if (input.mode !== 'negotiation' && input.mode !== 'negotiation_inflight') {
|
|
14
|
-
return input.purpose === undefined && input.negotiation === undefined;
|
|
15
|
-
}
|
|
16
|
-
if (input.sourceType !== 'opportunity'
|
|
17
|
-
|| !input.negotiation
|
|
18
|
-
|| input.negotiation.opportunityId !== input.sourceId
|
|
19
|
-
|| input.negotiation.recipientUserId !== input.userId
|
|
20
|
-
|| input.negotiation.purpose !== input.purpose)
|
|
21
|
-
return false;
|
|
22
|
-
const context = input.context;
|
|
23
|
-
if (context.counterpartyHint !== NEGOTIATION_QUESTION_GENERIC_COUNTERPARTY
|
|
24
|
-
|| context.indexContext !== NEGOTIATION_QUESTION_GENERIC_NETWORK)
|
|
25
|
-
return false;
|
|
26
|
-
if (input.mode === 'negotiation_inflight') {
|
|
27
|
-
return input.purpose === 'inflight_consultation'
|
|
28
|
-
&& typeof input.negotiation.taskId === 'string'
|
|
29
|
-
&& input.negotiation.taskId.length > 0
|
|
30
|
-
&& context.negotiationId === input.negotiation.taskId
|
|
31
|
-
&& (context.consultationPolicyReason === 'unresolved_owner_constraint'
|
|
32
|
-
|| context.consultationPolicyReason === 'consequential_disclosure_permission'
|
|
33
|
-
|| context.consultationPolicyReason === 'repeated_non_convergence'
|
|
34
|
-
|| context.consultationPolicyReason === 'insufficient_commitment_authority');
|
|
35
|
-
}
|
|
36
|
-
if (input.purpose === 'uptake') {
|
|
37
|
-
return input.negotiation.taskId === undefined
|
|
38
|
-
&& typeof input.negotiation.counterpartyUserId === 'string'
|
|
39
|
-
&& input.negotiation.counterpartyUserId.length > 0
|
|
40
|
-
&& typeof input.negotiation.counterpartyIntentId === 'string'
|
|
41
|
-
&& input.negotiation.counterpartyIntentId.length > 0
|
|
42
|
-
&& typeof input.negotiation.counterpartyFelicityAuthority === 'number'
|
|
43
|
-
&& Number.isFinite(input.negotiation.counterpartyFelicityAuthority)
|
|
44
|
-
&& context.negotiationId === input.sourceId
|
|
45
|
-
&& context.purpose === 'uptake'
|
|
46
|
-
&& context.proposedActivity === NEGOTIATION_QUESTION_GENERIC_UPTAKE_ACTIVITY;
|
|
47
|
-
}
|
|
48
|
-
return input.purpose === 'stalled_followup'
|
|
49
|
-
&& typeof input.negotiation.taskId === 'string'
|
|
50
|
-
&& input.negotiation.taskId.length > 0
|
|
51
|
-
&& context.negotiationId === input.negotiation.taskId
|
|
52
|
-
&& context.purpose === undefined
|
|
53
|
-
&& (context.outcomeReason === 'turn_cap' || context.outcomeReason === 'timeout' || context.outcomeReason === 'stalled')
|
|
54
|
-
&& typeof context.recipientIntent === 'string'
|
|
55
|
-
&& context.recipientIntent.trim().length > 0;
|
|
56
|
-
}
|
|
1
|
+
export {};
|