@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
|
@@ -8,21 +8,15 @@
|
|
|
8
8
|
* - **question.schema** — Zod schemas and derived types for the whole question
|
|
9
9
|
* vocabulary: the public Question shape, generator envelopes, and the
|
|
10
10
|
* detection/provenance/pool/recovery persistence sub-schemas.
|
|
11
|
-
* - **question.input** —
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - **question.
|
|
15
|
-
*
|
|
16
|
-
* - **question.env** — the QUESTIONER_* env accessors. All reads go through it.
|
|
17
|
-
* - **question.tools** / **question.ask.tool** — foreground adapters: the
|
|
18
|
-
* authenticated MCP read/answer tools, and the blocking chat
|
|
19
|
-
* `ask_user_question` tool.
|
|
20
|
-
* - **question.persistence.port** / **question.tools.port** — the injected
|
|
21
|
-
* host contracts (question CRUD, chat host bridge, tool host capabilities).
|
|
11
|
+
* - **question.input** — the park-path payload types
|
|
12
|
+
* ({@link QuestionerEnqueueFn} and the two park families).
|
|
13
|
+
* - **question.env** — leftover question env constants.
|
|
14
|
+
* - **question.tools** — foreground adapters: the authenticated MCP
|
|
15
|
+
* read/answer tools.
|
|
22
16
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
17
|
+
* The QuestionerAgent, its presets, and the per-mode generation envelope are
|
|
18
|
+
* retired (conversational-questions plan): a park payload now routes to the
|
|
19
|
+
* question-message regeneration queue in the backend composition root.
|
|
26
20
|
*
|
|
27
21
|
* ## Boundary
|
|
28
22
|
*
|
|
@@ -30,13 +24,7 @@
|
|
|
30
24
|
* barrel — never from runtime/, host implementations, or other capability
|
|
31
25
|
* internals.
|
|
32
26
|
*/
|
|
33
|
-
export {
|
|
34
|
-
export {
|
|
35
|
-
export { createQuestionerTools } from "./question.tools.js";
|
|
36
|
-
export { INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, intentQuestionDailyCap, isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, } from "./question.env.js";
|
|
37
|
-
export { isValidQuestionerInputContract } from "./question.input.js";
|
|
38
|
-
export type { InflightQuestionerInput, PoolDiscoveryContext, PostStallQuestionerInput, QuestionerEnqueueFn, QuestionerEnqueuePayload, QuestionerInput, RecoveryQuestionerInput, UptakeQuestionerInput, } from "./question.input.js";
|
|
39
|
-
export type { ChatQuestionsHost, PersistableQuestion, PersistedQuestion, QuestionerDatabase, QuestionFilters, } from "./question.persistence.port.js";
|
|
40
|
-
export type { AskUserQuestionToolDeps, QuestionerToolDeps } from "./question.tools.port.js";
|
|
27
|
+
export { INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
|
|
28
|
+
export type { InflightQuestionerInput, PostStallQuestionerInput, QuestionerEnqueueFn, QuestionerEnqueuePayload, QuestionerInput, } from "./question.input.js";
|
|
41
29
|
export { NegotiationQuestionCandidateSchema, NegotiationQuestionProvenanceSchema, UnderspecificationTypeSchema, } from "./question.schema.js";
|
|
42
30
|
export type { NegotiationQuestionCandidate, NegotiationQuestionProvenance, NegotiationQuestionPurpose, Question, QuestionGenerationResult, QuestionOption, QuestionPoolDiscriminator, QuestionPoolPush, QuestionPoolPushRequestReason, QuestionPoolPushRequestStatus, QuestionPoolSnapshot, QuestionPurpose, QuestionRecoverySnapshot, QuestionStrategy, QuestionVoidedReason, UnderspecificationType, } from "./question.schema.js";
|
|
@@ -8,21 +8,15 @@
|
|
|
8
8
|
* - **question.schema** — Zod schemas and derived types for the whole question
|
|
9
9
|
* vocabulary: the public Question shape, generator envelopes, and the
|
|
10
10
|
* detection/provenance/pool/recovery persistence sub-schemas.
|
|
11
|
-
* - **question.input** —
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - **question.
|
|
15
|
-
*
|
|
16
|
-
* - **question.env** — the QUESTIONER_* env accessors. All reads go through it.
|
|
17
|
-
* - **question.tools** / **question.ask.tool** — foreground adapters: the
|
|
18
|
-
* authenticated MCP read/answer tools, and the blocking chat
|
|
19
|
-
* `ask_user_question` tool.
|
|
20
|
-
* - **question.persistence.port** / **question.tools.port** — the injected
|
|
21
|
-
* host contracts (question CRUD, chat host bridge, tool host capabilities).
|
|
11
|
+
* - **question.input** — the park-path payload types
|
|
12
|
+
* ({@link QuestionerEnqueueFn} and the two park families).
|
|
13
|
+
* - **question.env** — leftover question env constants.
|
|
14
|
+
* - **question.tools** — foreground adapters: the authenticated MCP
|
|
15
|
+
* read/answer tools.
|
|
22
16
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
17
|
+
* The QuestionerAgent, its presets, and the per-mode generation envelope are
|
|
18
|
+
* retired (conversational-questions plan): a park payload now routes to the
|
|
19
|
+
* question-message regeneration queue in the backend composition root.
|
|
26
20
|
*
|
|
27
21
|
* ## Boundary
|
|
28
22
|
*
|
|
@@ -30,9 +24,5 @@
|
|
|
30
24
|
* barrel — never from runtime/, host implementations, or other capability
|
|
31
25
|
* internals.
|
|
32
26
|
*/
|
|
33
|
-
export {
|
|
34
|
-
export { createAskUserQuestionTools } from "./question.ask.tool.js";
|
|
35
|
-
export { createQuestionerTools } from "./question.tools.js";
|
|
36
|
-
export { INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, intentQuestionDailyCap, isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, } from "./question.env.js";
|
|
37
|
-
export { isValidQuestionerInputContract } from "./question.input.js";
|
|
27
|
+
export { INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
|
|
38
28
|
export { NegotiationQuestionCandidateSchema, NegotiationQuestionProvenanceSchema, UnderspecificationTypeSchema, } from "./question.schema.js";
|
|
@@ -87,12 +87,12 @@ export declare const McpActivityCallerSchema: z.ZodObject<{
|
|
|
87
87
|
networkScopeId: z.ZodNullable<z.ZodString>;
|
|
88
88
|
}, "strict", z.ZodTypeAny, {
|
|
89
89
|
kind: "agent" | "human";
|
|
90
|
-
permissions: string[];
|
|
91
90
|
networkScopeId: string | null;
|
|
91
|
+
permissions: string[];
|
|
92
92
|
}, {
|
|
93
93
|
kind: "agent" | "human";
|
|
94
|
-
permissions: string[];
|
|
95
94
|
networkScopeId: string | null;
|
|
95
|
+
permissions: string[];
|
|
96
96
|
}>;
|
|
97
97
|
export type McpActivityCaller = z.infer<typeof McpActivityCallerSchema>;
|
|
98
98
|
/**
|
|
@@ -22,7 +22,6 @@ import { createContactTools } from "../../contacts/contact.module.js";
|
|
|
22
22
|
import { createAgentTools } from "../../agents/agent.tools.js";
|
|
23
23
|
import { createNegotiationTools } from "../../negotiations/negotiation.module.js";
|
|
24
24
|
import { createPremiseTools } from "../../premises/premise.tools.js";
|
|
25
|
-
import { createQuestionerTools, createAskUserQuestionTools } from "../../questions/question.module.js";
|
|
26
25
|
import { bindOwnerApprovalProvenance } from "../../opportunities/opportunity.owner-provenance.js";
|
|
27
26
|
const logger = protocolLogger("ChatTools");
|
|
28
27
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -102,21 +101,21 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
102
101
|
}, { name: opts.name, description: opts.description, schema: opts.querySchema });
|
|
103
102
|
}
|
|
104
103
|
// ─── Compile subgraphs ─────────────────────────────────────────────────────
|
|
105
|
-
// Wrap questionerEnqueue to include scoped
|
|
104
|
+
// Wrap questionerEnqueue to include scoped context when available. (The
|
|
105
|
+
// chat-session conversationId defaulting went with the retired chat-mode
|
|
106
|
+
// generator; park payloads carry their own recipient routing.)
|
|
106
107
|
const sessionAwareEnqueue = deps.questionerEnqueue
|
|
107
108
|
? (input) => deps.questionerEnqueue({
|
|
108
109
|
...input,
|
|
109
110
|
...(resolvedContext.scopeType && resolvedContext.scopeId && !input.scopeId
|
|
110
111
|
? { scopeType: resolvedContext.scopeType, scopeId: resolvedContext.scopeId }
|
|
111
112
|
: {}),
|
|
112
|
-
...(resolvedContext.sessionId && !input.conversationId ? { conversationId: resolvedContext.sessionId } : {}),
|
|
113
113
|
})
|
|
114
114
|
: undefined;
|
|
115
115
|
const intents = new Intents({
|
|
116
116
|
database,
|
|
117
117
|
embedder,
|
|
118
118
|
queue: deps.intentQueue,
|
|
119
|
-
questionerEnqueue: sessionAwareEnqueue,
|
|
120
119
|
});
|
|
121
120
|
const intentGraph = intents.createGraph();
|
|
122
121
|
const premiseGraph = new PremiseGraphFactory(database, embedder).createGraph();
|
|
@@ -170,10 +169,7 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
170
169
|
apiBaseUrl: deps.apiBaseUrl,
|
|
171
170
|
...(deps.chatSummary && { chatSummary: deps.chatSummary }),
|
|
172
171
|
...(sessionAwareEnqueue && { questionerEnqueue: sessionAwareEnqueue }),
|
|
173
|
-
...(deps.findPendingQuestions && { findPendingQuestions: deps.findPendingQuestions }),
|
|
174
|
-
...(deps.answerPendingQuestion && { answerPendingQuestion: deps.answerPendingQuestion }),
|
|
175
172
|
...(deps.negotiationSummary && { negotiationSummary: deps.negotiationSummary }),
|
|
176
|
-
...(deps.chatQuestions && { chatQuestions: deps.chatQuestions }),
|
|
177
173
|
...(deps.chatSession && { chatSession: deps.chatSession }),
|
|
178
174
|
...(deps.getUserContextText && { getUserContextText: deps.getUserContextText }),
|
|
179
175
|
...(deps.intentProposalStore && { intentProposalStore: deps.intentProposalStore }),
|
|
@@ -205,12 +201,6 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
205
201
|
? createNegotiationTools(defineTool, toolDeps)
|
|
206
202
|
: [];
|
|
207
203
|
const premiseTools = createPremiseTools(defineTool, toolDeps);
|
|
208
|
-
const questionerTools = createQuestionerTools(defineTool, toolDeps);
|
|
209
|
-
// Blocking mid-conversation questions — chat-only (never in the MCP registry),
|
|
210
|
-
// and only when the host provides the ChatQuestionsHost bridge.
|
|
211
|
-
const askUserQuestionTools = deps.chatQuestions
|
|
212
|
-
? createAskUserQuestionTools(defineTool, toolDeps)
|
|
213
|
-
: [];
|
|
214
204
|
// confirm_opportunity_delivery is an OpenClaw-delivery ledger write and must not be
|
|
215
205
|
// callable from regular chat sessions.
|
|
216
206
|
const chatOpportunityToolExclusions = new Set([
|
|
@@ -227,7 +217,5 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
227
217
|
...agentTools,
|
|
228
218
|
...negotiationTools,
|
|
229
219
|
...premiseTools,
|
|
230
|
-
...questionerTools,
|
|
231
|
-
...askUserQuestionTools,
|
|
232
220
|
];
|
|
233
221
|
}
|
|
@@ -20,11 +20,8 @@ import type { AgentDatabase } from "../../agents/agent.repository.port.js";
|
|
|
20
20
|
import type { NegotiationTimeoutQueue } from "../interfaces/negotiation-events.interface.js";
|
|
21
21
|
import type { AgentDispatcher } from "../interfaces/agent-dispatcher.interface.js";
|
|
22
22
|
import type { DeliveryLedger } from "../interfaces/delivery-ledger.interface.js";
|
|
23
|
-
import type { ChatQuestionsHost, QuestionerDatabase } from "../../questions/question.persistence.port.js";
|
|
24
23
|
import type { NegotiatorMemoryToolsHost } from "../interfaces/negotiator-memory.interface.js";
|
|
25
24
|
import type { QuestionerEnqueueFn } from "../../questions/question.input.js";
|
|
26
|
-
import type { PendingQuestionSummary } from "../schemas/pending-question.schema.js";
|
|
27
|
-
import type { QuestionMode, QuestionPurpose } from "../../questions/question.schema.js";
|
|
28
25
|
import type { EnrichmentRunQueue, EnrichmentRunStore } from "../interfaces/enrichment-run.interface.js";
|
|
29
26
|
import type { McpActivityCaller } from "./activity-projection.js";
|
|
30
27
|
export type IdentityContext = UserIdentity | null;
|
|
@@ -147,39 +144,8 @@ interface ToolContextBindings {
|
|
|
147
144
|
* Injected by the composition root when QUESTIONER_ENABLED=true.
|
|
148
145
|
*/
|
|
149
146
|
questionerEnqueue?: QuestionerEnqueueFn;
|
|
150
|
-
/**
|
|
151
|
-
* Lookup pending questions for a user, optionally filtered by source,
|
|
152
|
-
* detection mode, selected intent scope, or capped by count.
|
|
153
|
-
*/
|
|
154
|
-
findPendingQuestions?: (userId: string, filters?: {
|
|
155
|
-
sourceType?: string;
|
|
156
|
-
sourceId?: string;
|
|
157
|
-
scopeType?: 'intent';
|
|
158
|
-
scopeId?: string;
|
|
159
|
-
networkId?: string;
|
|
160
|
-
modes?: QuestionMode[];
|
|
161
|
-
purpose?: QuestionPurpose;
|
|
162
|
-
limit?: number;
|
|
163
|
-
}) => Promise<PendingQuestionSummary[]>;
|
|
164
|
-
/**
|
|
165
|
-
* Record the client's explicit answer to a pending question through the
|
|
166
|
-
* host's question-answer pipeline (atomic pending→answered flip + answered
|
|
167
|
-
* events). Returns false when the question is not pending for this user
|
|
168
|
-
* (already answered/dismissed, expired, or not theirs). Injected by the
|
|
169
|
-
* composition root — absent when question delivery is disabled.
|
|
170
|
-
*/
|
|
171
|
-
answerPendingQuestion?: (userId: string, questionId: string, answer: {
|
|
172
|
-
selectedOptions: string[];
|
|
173
|
-
freeText?: string;
|
|
174
|
-
}) => Promise<boolean>;
|
|
175
147
|
/** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */
|
|
176
148
|
negotiationSummary?: NegotiationSummaryReader;
|
|
177
|
-
/**
|
|
178
|
-
* Host bridge for the orchestrator's blocking `ask_user_question` tool
|
|
179
|
-
* (synchronous chat-question persist + in-stream answer wait). Injected by
|
|
180
|
-
* the backend composition root; when absent the tool is not registered.
|
|
181
|
-
*/
|
|
182
|
-
chatQuestions?: ChatQuestionsHost;
|
|
183
149
|
/** Durable host persistence for verified intent proposals shown in chat. */
|
|
184
150
|
intentProposalStore?: import('../../intents/intent.proposal.js').IntentProposalStore;
|
|
185
151
|
/**
|
|
@@ -228,8 +194,6 @@ interface ToolContextBindings {
|
|
|
228
194
|
frontendUrl?: string;
|
|
229
195
|
/** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */
|
|
230
196
|
apiBaseUrl?: string;
|
|
231
|
-
/** Persistence for structured questions generated by the QuestionerAgent (optional). */
|
|
232
|
-
questionerDatabase?: QuestionerDatabase;
|
|
233
197
|
/** Optional host-side error reporter for swallowed protocol/tool errors. */
|
|
234
198
|
reportToolError?: (error: unknown, report: ToolErrorReport) => void;
|
|
235
199
|
/**
|
|
@@ -366,45 +330,8 @@ interface ToolDepsBindings {
|
|
|
366
330
|
* composition root when QUESTIONER_ENABLED=true.
|
|
367
331
|
*/
|
|
368
332
|
questionerEnqueue?: QuestionerEnqueueFn;
|
|
369
|
-
/**
|
|
370
|
-
* Lookup pending questions for a user, optionally filtered by source,
|
|
371
|
-
* detection mode, or capped by count (hosts apply `limit` SQL-side).
|
|
372
|
-
* Used by tools to attach contextually relevant questions to their results.
|
|
373
|
-
* Injected by the composition root — absent when question delivery is disabled.
|
|
374
|
-
*/
|
|
375
|
-
findPendingQuestions?: (userId: string, filters?: {
|
|
376
|
-
sourceType?: string;
|
|
377
|
-
sourceId?: string;
|
|
378
|
-
/** Optional selected-intent scope. When `scopeType === 'intent'`, `scopeId` is the selected intent id. */
|
|
379
|
-
scopeType?: 'intent';
|
|
380
|
-
scopeId?: string;
|
|
381
|
-
/** Restrict to questions whose actor carries this network id. */
|
|
382
|
-
networkId?: string;
|
|
383
|
-
/** Restrict to questions whose detection mode is in this set. */
|
|
384
|
-
modes?: QuestionMode[];
|
|
385
|
-
/** Restrict to an internal generation purpose. */
|
|
386
|
-
purpose?: QuestionPurpose;
|
|
387
|
-
/** Maximum rows to return; hosts should apply this in the query. */
|
|
388
|
-
limit?: number;
|
|
389
|
-
}) => Promise<PendingQuestionSummary[]>;
|
|
390
|
-
/**
|
|
391
|
-
* Record the client's explicit answer to a pending question through the
|
|
392
|
-
* host's question-answer pipeline (atomic pending→answered flip + answered
|
|
393
|
-
* events). Returns false when the question is not pending for this user.
|
|
394
|
-
* Injected by the composition root — absent when question delivery is disabled.
|
|
395
|
-
*/
|
|
396
|
-
answerPendingQuestion?: (userId: string, questionId: string, answer: {
|
|
397
|
-
selectedOptions: string[];
|
|
398
|
-
freeText?: string;
|
|
399
|
-
}) => Promise<boolean>;
|
|
400
333
|
/** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */
|
|
401
334
|
negotiationSummary?: NegotiationSummaryReader;
|
|
402
|
-
/**
|
|
403
|
-
* Host bridge for the orchestrator's blocking `ask_user_question` tool
|
|
404
|
-
* (synchronous chat-question persist + in-stream answer wait). Injected by
|
|
405
|
-
* the backend composition root; when absent the tool is not registered.
|
|
406
|
-
*/
|
|
407
|
-
chatQuestions?: ChatQuestionsHost;
|
|
408
335
|
/** Manages negotiation timeout jobs (optional — enables AI fallback on external agent timeout). */
|
|
409
336
|
negotiationTimeoutQueue?: NegotiationTimeoutQueue;
|
|
410
337
|
/** Agent registry database adapter (optional — absent when host does not support agents). */
|
|
@@ -9,7 +9,6 @@ import { createAgentTools } from '../../agents/agent.module.js';
|
|
|
9
9
|
import { createNegotiationTools } from '../../negotiations/negotiation.module.js';
|
|
10
10
|
import { createChatTools } from '../../chat/chat.tools.js';
|
|
11
11
|
import { createPremiseTools } from '../../premises/premise.tools.js';
|
|
12
|
-
import { createQuestionerTools } from '../../questions/question.module.js';
|
|
13
12
|
import { protocolLogger } from '../observability/protocol.logger.js';
|
|
14
13
|
import { requestContext } from '../observability/request-context.js';
|
|
15
14
|
const logger = protocolLogger('ToolRegistry');
|
|
@@ -69,7 +68,6 @@ export function createToolRegistry(deps, options = {}) {
|
|
|
69
68
|
createAgentTools(dt, deps);
|
|
70
69
|
createNegotiationTools(dt, deps);
|
|
71
70
|
createPremiseTools(dt, deps);
|
|
72
|
-
createQuestionerTools(dt, deps);
|
|
73
71
|
if (deps.chatSession) {
|
|
74
72
|
createChatTools(dt, deps);
|
|
75
73
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TraceEmitter } from "../observability/request-context.js";
|
|
2
2
|
import type { RawToolDefinition, ResolvedToolContext } from "./tool.helpers.js";
|
|
3
|
-
export type ToolTimeoutClass = "fast" | "bounded_slow" | "async_candidate"
|
|
3
|
+
export type ToolTimeoutClass = "fast" | "bounded_slow" | "async_candidate";
|
|
4
4
|
export type ToolRuntimeErrorCode = "TOOL_TIMEOUT" | "TOOL_CANCELLED" | "TOOL_OUTPUT_TOO_LARGE";
|
|
5
5
|
export interface ToolTimeoutPolicy {
|
|
6
6
|
class: ToolTimeoutClass;
|
|
@@ -3,11 +3,6 @@ import { requestContext } from "../observability/request-context.js";
|
|
|
3
3
|
const FAST_TIMEOUT_MS = 10000;
|
|
4
4
|
const BOUNDED_SLOW_TIMEOUT_MS = 45000;
|
|
5
5
|
const ASYNC_CANDIDATE_TIMEOUT_MS = 50000;
|
|
6
|
-
// Interactive tools deliberately block on human input (ask_user_question).
|
|
7
|
-
// Must exceed the tool's own internal wait budget (QUESTIONER_CHAT_WAIT_TIMEOUT_MS,
|
|
8
|
-
// default 4 min) so the tool returns a graceful timeout result instead of
|
|
9
|
-
// being killed by the runtime.
|
|
10
|
-
const INTERACTIVE_TIMEOUT_MS = 300000;
|
|
11
6
|
const DEFAULT_MAX_OUTPUT_BYTES = 1000000;
|
|
12
7
|
const FAST_TOOLS = new Set([
|
|
13
8
|
"create_intent_index",
|
|
@@ -33,7 +28,6 @@ const FAST_TOOLS = new Set([
|
|
|
33
28
|
"revoke_agent_permission",
|
|
34
29
|
"retract_premise",
|
|
35
30
|
]);
|
|
36
|
-
const INTERACTIVE_TOOLS = new Set(["ask_user_question"]);
|
|
37
31
|
const ASYNC_CANDIDATE_TOOLS = new Set([
|
|
38
32
|
"read_user_contexts",
|
|
39
33
|
"preview_user_context",
|
|
@@ -64,19 +58,14 @@ function toolNameOutputEnv(toolName) {
|
|
|
64
58
|
export function getToolTimeoutPolicy(toolName) {
|
|
65
59
|
const classification = FAST_TOOLS.has(toolName)
|
|
66
60
|
? "fast"
|
|
67
|
-
:
|
|
68
|
-
? "
|
|
69
|
-
:
|
|
70
|
-
? "async_candidate"
|
|
71
|
-
: "bounded_slow";
|
|
61
|
+
: ASYNC_CANDIDATE_TOOLS.has(toolName)
|
|
62
|
+
? "async_candidate"
|
|
63
|
+
: "bounded_slow";
|
|
72
64
|
let classDefault;
|
|
73
65
|
switch (classification) {
|
|
74
66
|
case "fast":
|
|
75
67
|
classDefault = parsePositiveIntEnv("MCP_TOOL_TIMEOUT_FAST_MS", FAST_TIMEOUT_MS);
|
|
76
68
|
break;
|
|
77
|
-
case "interactive":
|
|
78
|
-
classDefault = parsePositiveIntEnv("MCP_TOOL_TIMEOUT_INTERACTIVE_MS", INTERACTIVE_TIMEOUT_MS);
|
|
79
|
-
break;
|
|
80
69
|
case "async_candidate":
|
|
81
70
|
classDefault = parsePositiveIntEnv("MCP_TOOL_TIMEOUT_ASYNC_CANDIDATE_MS", ASYNC_CANDIDATE_TIMEOUT_MS);
|
|
82
71
|
break;
|
package/package.json
CHANGED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { PendingQuestionSummary } from "../shared/schemas/pending-question.schema.js";
|
|
2
|
-
/** Maximum pending questions attached to a single tool result. */
|
|
3
|
-
export declare const MAX_PENDING_QUESTIONS = 3;
|
|
4
|
-
export interface MergePendingQuestionsInput {
|
|
5
|
-
findPendingQuestions?: (userId: string, filters?: {
|
|
6
|
-
sourceType?: string;
|
|
7
|
-
sourceId?: string;
|
|
8
|
-
networkId?: string;
|
|
9
|
-
scopeType?: 'intent';
|
|
10
|
-
scopeId?: string;
|
|
11
|
-
}) => Promise<PendingQuestionSummary[]>;
|
|
12
|
-
userId: string;
|
|
13
|
-
sourceType?: string;
|
|
14
|
-
sourceId?: string;
|
|
15
|
-
/** Restrict to questions whose actor carries this network id. */
|
|
16
|
-
networkId?: string;
|
|
17
|
-
/** Optional selected-intent scope. */
|
|
18
|
-
scopeType?: 'intent';
|
|
19
|
-
scopeId?: string;
|
|
20
|
-
/** IDs already shown in this chat session — skip them. */
|
|
21
|
-
surfacedQuestionIds: Set<string>;
|
|
22
|
-
}
|
|
23
|
-
export interface MergePendingQuestionsResult {
|
|
24
|
-
/** Questions to attach to the tool result (under the `questions` key). */
|
|
25
|
-
questions: PendingQuestionSummary[];
|
|
26
|
-
/** IDs of the questions that were included (caller should add to surfacedQuestionIds). */
|
|
27
|
-
surfacedIds: string[];
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Query pending questions and filter out already-surfaced ones.
|
|
31
|
-
* Returns at most MAX_PENDING_QUESTIONS entries.
|
|
32
|
-
*/
|
|
33
|
-
export declare function mergePendingQuestions(input: MergePendingQuestionsInput): Promise<MergePendingQuestionsResult>;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helper for merging pending questions from the DB into tool results.
|
|
3
|
-
* Extracted so it can be unit-tested independently of the tool handler.
|
|
4
|
-
*/
|
|
5
|
-
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
6
|
-
const logger = protocolLogger("PendingQuestions");
|
|
7
|
-
/** Maximum pending questions attached to a single tool result. */
|
|
8
|
-
export const MAX_PENDING_QUESTIONS = 3;
|
|
9
|
-
/**
|
|
10
|
-
* Query pending questions and filter out already-surfaced ones.
|
|
11
|
-
* Returns at most MAX_PENDING_QUESTIONS entries.
|
|
12
|
-
*/
|
|
13
|
-
export async function mergePendingQuestions(input) {
|
|
14
|
-
if (!input.findPendingQuestions) {
|
|
15
|
-
return { questions: [], surfacedIds: [] };
|
|
16
|
-
}
|
|
17
|
-
const hasFilters = Boolean(input.sourceType || input.networkId || input.scopeType);
|
|
18
|
-
const filters = hasFilters
|
|
19
|
-
? {
|
|
20
|
-
...(input.sourceType ? { sourceType: input.sourceType } : {}),
|
|
21
|
-
...(input.sourceId ? { sourceId: input.sourceId } : {}),
|
|
22
|
-
...(input.networkId ? { networkId: input.networkId } : {}),
|
|
23
|
-
...(input.scopeType && input.scopeId ? { scopeType: input.scopeType, scopeId: input.scopeId } : {}),
|
|
24
|
-
}
|
|
25
|
-
: undefined;
|
|
26
|
-
let pending;
|
|
27
|
-
try {
|
|
28
|
-
pending = await input.findPendingQuestions(input.userId, filters);
|
|
29
|
-
}
|
|
30
|
-
catch (err) {
|
|
31
|
-
logger.warn('Failed to fetch pending questions, returning empty', { error: err });
|
|
32
|
-
return { questions: [], surfacedIds: [] };
|
|
33
|
-
}
|
|
34
|
-
// Deduplicate against already-surfaced IDs in this session
|
|
35
|
-
const fresh = pending.filter((q) => !input.surfacedQuestionIds.has(q.id));
|
|
36
|
-
const capped = fresh.slice(0, MAX_PENDING_QUESTIONS);
|
|
37
|
-
const publicQuestions = capped.map(({ actors: _actors, purpose: _purpose, ...question }) => question);
|
|
38
|
-
return {
|
|
39
|
-
questions: publicQuestions,
|
|
40
|
-
surfacedIds: capped.map((q) => q.id),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type QuestionGenerationResult } from "./question.schema.js";
|
|
2
|
-
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
3
|
-
import { type QuestionerInput } from "./question.input.js";
|
|
4
|
-
export interface QuestionerAgentConfig {
|
|
5
|
-
/** Optional model config override. */
|
|
6
|
-
modelConfig?: Parameters<typeof createStructuredModel>[3];
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Stateless question-generation agent. Accepts a `QuestionerInput` envelope,
|
|
10
|
-
* selects the preset for the given mode, invokes the LLM, and applies
|
|
11
|
-
* guardrails (dedup + strategy diversity).
|
|
12
|
-
*/
|
|
13
|
-
export declare class QuestionerAgent {
|
|
14
|
-
private model;
|
|
15
|
-
constructor(config?: QuestionerAgentConfig);
|
|
16
|
-
/**
|
|
17
|
-
* Generate up to 3 decision questions from the given input.
|
|
18
|
-
*
|
|
19
|
-
* @param input Envelope with mode, userId, source info, and mode-specific context.
|
|
20
|
-
* @param options.signal Optional AbortSignal to cancel the in-flight LLM call.
|
|
21
|
-
* @returns A result with parallel questions[] and strategies[] arrays,
|
|
22
|
-
* or null when generation failed, guardrails dropped all candidates,
|
|
23
|
-
* the LLM threw, or the call was aborted.
|
|
24
|
-
*/
|
|
25
|
-
invoke(input: QuestionerInput, options?: {
|
|
26
|
-
signal?: AbortSignal;
|
|
27
|
-
}): Promise<QuestionGenerationResult | null>;
|
|
28
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* questions/question.agent — QuestionerAgent.
|
|
12
|
-
*
|
|
13
|
-
* Stateless, mode-driven agent that generates structured decision questions
|
|
14
|
-
* from arbitrary protocol contexts.
|
|
15
|
-
*
|
|
16
|
-
* Follows the IndexNegotiator pattern: constructor takes optional config,
|
|
17
|
-
* single public `invoke()` method receives the full context per call.
|
|
18
|
-
* The LLM model is bound once at construction; the preset (system prompt +
|
|
19
|
-
* builder) is selected per invocation based on `input.mode`.
|
|
20
|
-
*/
|
|
21
|
-
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
22
|
-
import { QuestionGeneratorResponseSchema } from "./question.schema.js";
|
|
23
|
-
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
24
|
-
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
25
|
-
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
26
|
-
import { Timed } from "../shared/observability/performance.js";
|
|
27
|
-
import { getPreset } from "./question.presets.js";
|
|
28
|
-
import { isValidQuestionerInputContract } from "./question.input.js";
|
|
29
|
-
const logger = protocolLogger("QuestionerAgent");
|
|
30
|
-
/** Maximum same-strategy questions allowed in a single emission. */
|
|
31
|
-
const MAX_SAME_STRATEGY = 2;
|
|
32
|
-
/**
|
|
33
|
-
* Stateless question-generation agent. Accepts a `QuestionerInput` envelope,
|
|
34
|
-
* selects the preset for the given mode, invokes the LLM, and applies
|
|
35
|
-
* guardrails (dedup + strategy diversity).
|
|
36
|
-
*/
|
|
37
|
-
export class QuestionerAgent {
|
|
38
|
-
constructor(config) {
|
|
39
|
-
this.model = createStructuredModel("questioner", QuestionGeneratorResponseSchema, {
|
|
40
|
-
name: "clarifying_questions",
|
|
41
|
-
}, config?.modelConfig);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Generate up to 3 decision questions from the given input.
|
|
45
|
-
*
|
|
46
|
-
* @param input Envelope with mode, userId, source info, and mode-specific context.
|
|
47
|
-
* @param options.signal Optional AbortSignal to cancel the in-flight LLM call.
|
|
48
|
-
* @returns A result with parallel questions[] and strategies[] arrays,
|
|
49
|
-
* or null when generation failed, guardrails dropped all candidates,
|
|
50
|
-
* the LLM threw, or the call was aborted.
|
|
51
|
-
*/
|
|
52
|
-
async invoke(input, options) {
|
|
53
|
-
if (!isValidQuestionerInputContract(input)) {
|
|
54
|
-
logger.warn('QuestionerAgent rejected invalid mode/purpose/context contract', { mode: input.mode });
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
const preset = getPreset(input.mode, input.purpose);
|
|
58
|
-
const userMessage = preset.buildPrompt(input.context);
|
|
59
|
-
let raw;
|
|
60
|
-
try {
|
|
61
|
-
raw = await invokeWithAbortSignal(this.model, [new SystemMessage(preset.systemPrompt), new HumanMessage(userMessage)], options?.signal);
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
const aborted = options?.signal?.aborted ?? false;
|
|
65
|
-
if (aborted) {
|
|
66
|
-
logger.info("QuestionerAgent aborted by signal", {
|
|
67
|
-
mode: input.mode,
|
|
68
|
-
reason: options?.signal?.reason instanceof Error
|
|
69
|
-
? options.signal.reason.message
|
|
70
|
-
: String(options?.signal?.reason ?? "unknown"),
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
logger.warn("QuestionerAgent LLM call failed", {
|
|
75
|
-
mode: input.mode,
|
|
76
|
-
error: err instanceof Error ? err.message : String(err),
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
const parsed = QuestionGeneratorResponseSchema.safeParse(raw);
|
|
82
|
-
if (!parsed.success) {
|
|
83
|
-
logger.warn("QuestionerAgent parse failed", {
|
|
84
|
-
mode: input.mode,
|
|
85
|
-
error: parsed.error.message,
|
|
86
|
-
});
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const filtered = applyGuardrails(parsed.data.questions);
|
|
90
|
-
if (filtered.length === 0)
|
|
91
|
-
return null;
|
|
92
|
-
return {
|
|
93
|
-
questions: filtered.map(stripInternalMetadata),
|
|
94
|
-
strategies: filtered.map((q) => q.strategy),
|
|
95
|
-
underspecificationTypes: filtered.map((q) => q.underspecificationType),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
__decorate([
|
|
100
|
-
Timed(),
|
|
101
|
-
__metadata("design:type", Function),
|
|
102
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
103
|
-
__metadata("design:returntype", Promise)
|
|
104
|
-
], QuestionerAgent.prototype, "invoke", null);
|
|
105
|
-
// --- Guardrails ---------------------------------------------------------------
|
|
106
|
-
function applyGuardrails(questions) {
|
|
107
|
-
const dedupedByTitle = dedupByTitle(questions);
|
|
108
|
-
return enforceStrategyDiversity(dedupedByTitle);
|
|
109
|
-
}
|
|
110
|
-
function dedupByTitle(questions) {
|
|
111
|
-
const seen = new Set();
|
|
112
|
-
const out = [];
|
|
113
|
-
for (const q of questions) {
|
|
114
|
-
if (seen.has(q.title))
|
|
115
|
-
continue;
|
|
116
|
-
seen.add(q.title);
|
|
117
|
-
out.push(q);
|
|
118
|
-
}
|
|
119
|
-
return out;
|
|
120
|
-
}
|
|
121
|
-
function enforceStrategyDiversity(questions) {
|
|
122
|
-
const counts = new Map();
|
|
123
|
-
const out = [];
|
|
124
|
-
for (const q of questions) {
|
|
125
|
-
const n = counts.get(q.strategy) ?? 0;
|
|
126
|
-
if (n >= MAX_SAME_STRATEGY)
|
|
127
|
-
continue;
|
|
128
|
-
counts.set(q.strategy, n + 1);
|
|
129
|
-
out.push(q);
|
|
130
|
-
}
|
|
131
|
-
return out;
|
|
132
|
-
}
|
|
133
|
-
function stripInternalMetadata(q) {
|
|
134
|
-
const { strategy: _strategy, underspecificationType: _underspecificationType, ...publicShape } = q;
|
|
135
|
-
return publicShape;
|
|
136
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { DefineTool } from "../shared/agent/tool.helpers.js";
|
|
2
|
-
import type { AskUserQuestionToolDeps } from "./question.tools.port.js";
|
|
3
|
-
import { QuestionerAgent } from "./question.agent.js";
|
|
4
|
-
/** Test seam: replace or reset the module-level QuestionerAgent singleton. */
|
|
5
|
-
export declare function setQuestionerAgentForTesting(agent: QuestionerAgent | null): void;
|
|
6
|
-
/**
|
|
7
|
-
* Creates the chat-only `ask_user_question` tool.
|
|
8
|
-
*
|
|
9
|
-
* @param defineTool - Tool factory provided by the composition root.
|
|
10
|
-
* @param deps - Shared tool dependencies; requires `chatQuestions`.
|
|
11
|
-
*/
|
|
12
|
-
export declare function createAskUserQuestionTools(defineTool: DefineTool, deps: AskUserQuestionToolDeps): readonly [any];
|