@indexnetwork/protocol 12.1.0-rc.463.1 → 13.0.0-rc.464.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 +31 -0
- package/dist/capabilities/questions.facade.d.ts +2 -2
- package/dist/capabilities/questions.facade.js +1 -1
- package/dist/capabilities/questions.runtime.facade.d.ts +1 -1
- package/dist/capabilities/questions.runtime.facade.js +1 -1
- package/dist/chat/reporter.persona.js +1 -1
- package/dist/enrichment/enrichment.graph.d.ts +1 -3
- package/dist/enrichment/enrichment.graph.js +1 -2
- package/dist/index.d.ts +2 -2
- package/dist/negotiation/application/negotiation.graph.d.ts +5 -5
- package/dist/negotiation/domain/negotiation.state.d.ts +1 -1
- package/dist/opportunity/application/opportunity.graph.d.ts +23 -23
- package/dist/opportunity/domain/opportunity.state.d.ts +6 -6
- package/dist/opportunity/ports/opportunity.tools.port.d.ts +1 -1
- package/dist/questions/application/index.d.ts +2 -2
- package/dist/questions/application/index.js +1 -1
- package/dist/questions/application/question.env.d.ts +0 -30
- package/dist/questions/application/question.env.js +0 -38
- package/dist/questions/application/question.input.d.ts +2 -16
- package/dist/questions/application/question.presets.js +0 -66
- package/dist/questions/application/question.tools.js +3 -3
- package/dist/questions/domain/question.schema.d.ts +58 -58
- package/dist/questions/domain/question.schema.js +0 -2
- package/dist/questions/ports/index.d.ts +0 -2
- package/dist/questions/ports/index.js +0 -1
- package/dist/questions/public/index.d.ts +2 -2
- package/dist/questions/public/index.js +1 -1
- package/dist/runtime/foreground/composition/tool.factory.js +1 -2
- package/dist/shared/agent/activity-projection.d.ts +4 -4
- package/dist/shared/agent/activity-projection.js +6 -0
- package/dist/shared/agent/tool.helpers.d.ts +2 -8
- package/dist/shared/schemas/discovery-question.schema.d.ts +10 -28
- package/dist/shared/schemas/discovery-question.schema.js +2 -4
- package/dist/shared/schemas/negotiation-digest.schema.d.ts +5 -5
- package/package.json +1 -1
- package/dist/questions/application/question.discovery.prompt.d.ts +0 -8
- package/dist/questions/application/question.discovery.prompt.js +0 -181
- package/dist/questions/ports/question.generator.port.d.ts +0 -33
- package/dist/questions/ports/question.generator.port.js +0 -1
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
export * from "../domain/index.js";
|
|
41
41
|
export { QuestionerAgent } from "../application/index.js";
|
|
42
42
|
export type { QuestionerAgentConfig } from "../application/index.js";
|
|
43
|
-
export { isQuestionerEnabled,
|
|
43
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, } from "../application/index.js";
|
|
44
44
|
export { isValidQuestionerInputContract, } from "../application/index.js";
|
|
45
45
|
export type { QuestionerInput, QuestionerEnqueuePayload, QuestionerEnqueueFn, PoolDiscoveryContext, RecoveryQuestionerInput, UptakeQuestionerInput, PostStallQuestionerInput, InflightQuestionerInput, } from "../application/index.js";
|
|
46
46
|
export { createQuestionerTools, createAskUserQuestionTools } from "../application/index.js";
|
|
47
|
-
export type { AskUserQuestionToolDeps, ChatQuestionAnswerOutcome, ChatQuestionsHost, PersistableQuestion, PersistedQuestion, QuestionFilters,
|
|
47
|
+
export type { AskUserQuestionToolDeps, ChatQuestionAnswerOutcome, ChatQuestionsHost, PersistableQuestion, PersistedQuestion, QuestionFilters, QuestionerDatabase, QuestionerToolDeps, } from "../ports/index.js";
|
|
@@ -42,7 +42,7 @@ export * from "../domain/index.js";
|
|
|
42
42
|
// ── Application: agent ────────────────────────────────────────────────────────
|
|
43
43
|
export { QuestionerAgent } from "../application/index.js";
|
|
44
44
|
// ── Application: env accessors ────────────────────────────────────────────────
|
|
45
|
-
export { isQuestionerEnabled,
|
|
45
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, } from "../application/index.js";
|
|
46
46
|
// ── Application: input types and validation ───────────────────────────────────
|
|
47
47
|
export { isValidQuestionerInputContract, } from "../application/index.js";
|
|
48
48
|
// ── Application: foreground adapter tools ─────────────────────────────────────
|
|
@@ -117,7 +117,7 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
117
117
|
: undefined;
|
|
118
118
|
const intentGraph = new IntentGraphFactory(database, embedder, deps.intentQueue, sessionAwareEnqueue).createGraph();
|
|
119
119
|
const premiseGraph = new PremiseGraphFactory(database, embedder).createGraph();
|
|
120
|
-
const profileGraph = new EnrichmentGraphFactory(database, scraper, deps.enricher,
|
|
120
|
+
const profileGraph = new EnrichmentGraphFactory(database, scraper, deps.enricher, premiseGraph).createGraph();
|
|
121
121
|
const hydeCache = deps.hydeCache;
|
|
122
122
|
const lensInferrer = new LensInferrer();
|
|
123
123
|
const hydeGenerator = new HydeGenerator();
|
|
@@ -169,7 +169,6 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
169
169
|
frontendUrl: deps.frontendUrl,
|
|
170
170
|
apiBaseUrl: deps.apiBaseUrl,
|
|
171
171
|
...(deps.chatSummary && { chatSummary: deps.chatSummary }),
|
|
172
|
-
...(deps.questionGenerator && { questionGenerator: deps.questionGenerator }),
|
|
173
172
|
...(sessionAwareEnqueue && { questionerEnqueue: sessionAwareEnqueue }),
|
|
174
173
|
...(deps.findPendingQuestions && { findPendingQuestions: deps.findPendingQuestions }),
|
|
175
174
|
...(deps.answerPendingQuestion && { answerPendingQuestion: deps.answerPendingQuestion }),
|
|
@@ -136,13 +136,13 @@ export declare const ActivitySummaryResponseSchema: z.ZodObject<{
|
|
|
136
136
|
title: z.ZodString;
|
|
137
137
|
count: z.ZodNumber;
|
|
138
138
|
}, "strict", z.ZodTypeAny, {
|
|
139
|
+
count: number;
|
|
139
140
|
title: string;
|
|
140
141
|
intentId: string;
|
|
141
|
-
count: number;
|
|
142
142
|
}, {
|
|
143
|
+
count: number;
|
|
143
144
|
title: string;
|
|
144
145
|
intentId: string;
|
|
145
|
-
count: number;
|
|
146
146
|
}>, "many">>;
|
|
147
147
|
/** questions domain (meta-network) — counts grouped by affected domain. */
|
|
148
148
|
pendingQuestionsByDomain: z.ZodOptional<z.ZodObject<{
|
|
@@ -199,9 +199,9 @@ export declare const ActivitySummaryResponseSchema: z.ZodObject<{
|
|
|
199
199
|
liveSignalsWatched?: number | undefined;
|
|
200
200
|
opportunitiesSurfaced?: number | undefined;
|
|
201
201
|
opportunitiesBySignal?: {
|
|
202
|
+
count: number;
|
|
202
203
|
title: string;
|
|
203
204
|
intentId: string;
|
|
204
|
-
count: number;
|
|
205
205
|
}[] | undefined;
|
|
206
206
|
pendingQuestionsByDomain?: {
|
|
207
207
|
chat?: number | undefined;
|
|
@@ -226,9 +226,9 @@ export declare const ActivitySummaryResponseSchema: z.ZodObject<{
|
|
|
226
226
|
liveSignalsWatched?: number | undefined;
|
|
227
227
|
opportunitiesSurfaced?: number | undefined;
|
|
228
228
|
opportunitiesBySignal?: {
|
|
229
|
+
count: number;
|
|
229
230
|
title: string;
|
|
230
231
|
intentId: string;
|
|
231
|
-
count: number;
|
|
232
232
|
}[] | undefined;
|
|
233
233
|
pendingQuestionsByDomain?: {
|
|
234
234
|
chat?: number | undefined;
|
|
@@ -53,6 +53,12 @@ export const ActivityQuestionDomainSchema = z.enum([
|
|
|
53
53
|
* bucket so a future protocol mode can never leak to an agent caller.
|
|
54
54
|
*/
|
|
55
55
|
export const QUESTION_MODE_TO_DOMAIN = {
|
|
56
|
+
// `enrichment` and `discovery` are retired generators — no new question is
|
|
57
|
+
// ever produced in either mode. Their rows predate the removal and remain
|
|
58
|
+
// answerable, so both keep their original affected-domain mapping: dropping
|
|
59
|
+
// them here would silently fall back to the "chat" domain and change which
|
|
60
|
+
// permission an agent needs to answer a pre-existing row.
|
|
61
|
+
//
|
|
56
62
|
// Enrichment answers run the PremiseGraph lifecycle (createPremiseFromAnswer →
|
|
57
63
|
// PremiseEvents.onCreated), so enrichment questions affect the premises domain.
|
|
58
64
|
enrichment: "premises",
|
|
@@ -12,7 +12,6 @@ import type { IntentGraphQueue } from "../interfaces/queue.interface.js";
|
|
|
12
12
|
import type { ChatSessionReader } from "../interfaces/chat-session.interface.js";
|
|
13
13
|
import type { ChatSummaryReader } from "../interfaces/chat-summary.interface.js";
|
|
14
14
|
import type { ChatMessageWriter } from "../interfaces/chat-message-writer.interface.js";
|
|
15
|
-
import type { QuestionGeneratorReader } from "../../questions/ports/question.generator.port.js";
|
|
16
15
|
import type { NegotiationSummaryReader } from "../interfaces/negotiation-summary.interface.js";
|
|
17
16
|
import type { Embedder } from "../interfaces/embedder.interface.js";
|
|
18
17
|
import type { AgentDatabase } from "../../participant-agents/ports/index.js";
|
|
@@ -161,8 +160,6 @@ interface ToolContextBindings {
|
|
|
161
160
|
chatSummary?: ChatSummaryReader;
|
|
162
161
|
/** Writes user messages into the user's most-recent chat session (Slice 5 MCP elicitation). */
|
|
163
162
|
chatMessageWriter?: ChatMessageWriter;
|
|
164
|
-
/** Decision-question generator. Optional; consumers fall back to no `questions`. */
|
|
165
|
-
questionGenerator?: QuestionGeneratorReader;
|
|
166
163
|
/**
|
|
167
164
|
* Optional async question enqueue callback. When provided, question generation
|
|
168
165
|
* is dispatched asynchronously to the QuestionerQueue instead of running inline.
|
|
@@ -413,13 +410,10 @@ interface ToolDepsBindings {
|
|
|
413
410
|
};
|
|
414
411
|
/** Writes user messages into the user's most-recent chat session (Slice 5 MCP elicitation). */
|
|
415
412
|
chatMessageWriter?: ChatMessageWriter;
|
|
416
|
-
/** Decision-question generator. Optional; consumers fall back to no `questions`. */
|
|
417
|
-
questionGenerator?: QuestionGeneratorReader;
|
|
418
413
|
/**
|
|
419
414
|
* Optional async question enqueue callback. When provided, question generation
|
|
420
|
-
* is dispatched asynchronously to the QuestionerQueue
|
|
421
|
-
*
|
|
422
|
-
* QUESTIONER_ENABLED=true.
|
|
415
|
+
* is dispatched asynchronously to the QuestionerQueue. Injected by the
|
|
416
|
+
* composition root when QUESTIONER_ENABLED=true.
|
|
423
417
|
*/
|
|
424
418
|
questionerEnqueue?: QuestionerEnqueueFn;
|
|
425
419
|
/**
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Leaf types
|
|
4
|
-
* a pure interface referencing cross-schema types (DiscoveryNegotiationDigest,
|
|
5
|
-
* ChatContextDigest) to avoid Zod cross-schema runtime coupling.
|
|
2
|
+
* Discovery negotiation summary types shared by the opportunity graph and its
|
|
3
|
+
* negotiation-summary builder. Leaf types carry full Zod schemas.
|
|
6
4
|
*/
|
|
7
5
|
import { z } from "zod";
|
|
8
|
-
import type { DiscoveryNegotiationDigest } from "./negotiation-digest.schema.js";
|
|
9
|
-
import type { ChatContextDigest } from "./chat-context.schema.js";
|
|
10
6
|
export declare const NegotiationRoleSchema: z.ZodEnum<["agent", "patient", "peer"]>;
|
|
11
7
|
export type NegotiationRole = z.infer<typeof NegotiationRoleSchema>;
|
|
12
8
|
export declare const DiscoveryTurnSchema: z.ZodObject<{
|
|
@@ -24,18 +20,18 @@ export declare const DiscoveryTurnSchema: z.ZodObject<{
|
|
|
24
20
|
}>;
|
|
25
21
|
}, "strip", z.ZodTypeAny, {
|
|
26
22
|
reasoning: string;
|
|
23
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
27
24
|
suggestedRoles: {
|
|
28
25
|
ownUser: "agent" | "patient" | "peer";
|
|
29
26
|
otherUser: "agent" | "patient" | "peer";
|
|
30
27
|
};
|
|
31
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
32
28
|
}, {
|
|
33
29
|
reasoning: string;
|
|
30
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
34
31
|
suggestedRoles: {
|
|
35
32
|
ownUser: "agent" | "patient" | "peer";
|
|
36
33
|
otherUser: "agent" | "patient" | "peer";
|
|
37
34
|
};
|
|
38
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
39
35
|
}>;
|
|
40
36
|
export type DiscoveryTurn = z.infer<typeof DiscoveryTurnSchema>;
|
|
41
37
|
export declare const DiscoveryOutcomeSchema: z.ZodObject<{
|
|
@@ -89,18 +85,18 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
89
85
|
}>;
|
|
90
86
|
}, "strip", z.ZodTypeAny, {
|
|
91
87
|
reasoning: string;
|
|
88
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
92
89
|
suggestedRoles: {
|
|
93
90
|
ownUser: "agent" | "patient" | "peer";
|
|
94
91
|
otherUser: "agent" | "patient" | "peer";
|
|
95
92
|
};
|
|
96
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
97
93
|
}, {
|
|
98
94
|
reasoning: string;
|
|
95
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
99
96
|
suggestedRoles: {
|
|
100
97
|
ownUser: "agent" | "patient" | "peer";
|
|
101
98
|
otherUser: "agent" | "patient" | "peer";
|
|
102
99
|
};
|
|
103
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
104
100
|
}>, "many">;
|
|
105
101
|
outcome: z.ZodObject<{
|
|
106
102
|
hasOpportunity: z.ZodBoolean;
|
|
@@ -135,16 +131,16 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
135
131
|
}>;
|
|
136
132
|
seedAssessmentScore: z.ZodOptional<z.ZodNumber>;
|
|
137
133
|
}, "strip", z.ZodTypeAny, {
|
|
134
|
+
counterpartyId: string;
|
|
138
135
|
counterpartyHint: string;
|
|
139
136
|
indexContext: string;
|
|
140
|
-
counterpartyId: string;
|
|
141
137
|
turns: {
|
|
142
138
|
reasoning: string;
|
|
139
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
143
140
|
suggestedRoles: {
|
|
144
141
|
ownUser: "agent" | "patient" | "peer";
|
|
145
142
|
otherUser: "agent" | "patient" | "peer";
|
|
146
143
|
};
|
|
147
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
148
144
|
}[];
|
|
149
145
|
outcome: {
|
|
150
146
|
reasoning: string;
|
|
@@ -157,16 +153,16 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
157
153
|
};
|
|
158
154
|
seedAssessmentScore?: number | undefined;
|
|
159
155
|
}, {
|
|
156
|
+
counterpartyId: string;
|
|
160
157
|
counterpartyHint: string;
|
|
161
158
|
indexContext: string;
|
|
162
|
-
counterpartyId: string;
|
|
163
159
|
turns: {
|
|
164
160
|
reasoning: string;
|
|
161
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
165
162
|
suggestedRoles: {
|
|
166
163
|
ownUser: "agent" | "patient" | "peer";
|
|
167
164
|
otherUser: "agent" | "patient" | "peer";
|
|
168
165
|
};
|
|
169
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
170
166
|
}[];
|
|
171
167
|
outcome: {
|
|
172
168
|
reasoning: string;
|
|
@@ -226,17 +222,3 @@ export declare const DiscoverySourceProfileSchema: z.ZodObject<{
|
|
|
226
222
|
interests?: string[] | undefined;
|
|
227
223
|
}>;
|
|
228
224
|
export type DiscoverySourceProfile = z.infer<typeof DiscoverySourceProfileSchema>;
|
|
229
|
-
/**
|
|
230
|
-
* Full input to the question generator.
|
|
231
|
-
* Defined as a pure interface so it can reference DiscoveryNegotiationDigest
|
|
232
|
-
* and ChatContextDigest from sibling schemas without Zod runtime coupling.
|
|
233
|
-
*/
|
|
234
|
-
export interface DiscoveryQuestionInput {
|
|
235
|
-
query: string;
|
|
236
|
-
/** The seeker's global user_context paragraph (profile-replacing identity text). */
|
|
237
|
-
userContext: string;
|
|
238
|
-
negotiationDigests: DiscoveryNegotiationDigest[];
|
|
239
|
-
summary: DiscoverySummary;
|
|
240
|
-
chatContext?: ChatContextDigest;
|
|
241
|
-
now: string;
|
|
242
|
-
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Leaf types
|
|
4
|
-
* a pure interface referencing cross-schema types (DiscoveryNegotiationDigest,
|
|
5
|
-
* ChatContextDigest) to avoid Zod cross-schema runtime coupling.
|
|
2
|
+
* Discovery negotiation summary types shared by the opportunity graph and its
|
|
3
|
+
* negotiation-summary builder. Leaf types carry full Zod schemas.
|
|
6
4
|
*/
|
|
7
5
|
import { z } from "zod";
|
|
8
6
|
// ─── Primitives ───────────────────────────────────────────────────────────────
|
|
@@ -35,22 +35,22 @@ export declare const DiscoveryNegotiationDigestSchema: z.ZodObject<{
|
|
|
35
35
|
otherUser: "agent" | "patient" | "peer";
|
|
36
36
|
}>>;
|
|
37
37
|
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
suggestedRoles: {
|
|
39
|
+
ownUser: "agent" | "patient" | "peer";
|
|
40
|
+
otherUser: "agent" | "patient" | "peer";
|
|
41
|
+
} | null;
|
|
38
42
|
counterpartyHint: string;
|
|
39
43
|
indexContext: string;
|
|
40
44
|
outcomeRole: "opportunity" | "no-opportunity";
|
|
41
45
|
outcomeReason: "timeout" | "stalled" | "rejected" | "turn_cap" | "screened_out" | null;
|
|
42
46
|
keyTake: string;
|
|
47
|
+
}, {
|
|
43
48
|
suggestedRoles: {
|
|
44
49
|
ownUser: "agent" | "patient" | "peer";
|
|
45
50
|
otherUser: "agent" | "patient" | "peer";
|
|
46
51
|
} | null;
|
|
47
|
-
}, {
|
|
48
52
|
outcomeRole: "opportunity" | "no-opportunity";
|
|
49
53
|
outcomeReason: "timeout" | "stalled" | "rejected" | "turn_cap" | "screened_out" | null;
|
|
50
|
-
suggestedRoles: {
|
|
51
|
-
ownUser: "agent" | "patient" | "peer";
|
|
52
|
-
otherUser: "agent" | "patient" | "peer";
|
|
53
|
-
} | null;
|
|
54
54
|
counterpartyHint?: unknown;
|
|
55
55
|
indexContext?: unknown;
|
|
56
56
|
keyTake?: unknown;
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { DiscoveryQuestionInput } from "../../shared/schemas/discovery-question.schema.js";
|
|
2
|
-
/** System prompt for the QuestionerAgent's `discovery` mode. */
|
|
3
|
-
export declare const DISCOVERY_SYSTEM_PROMPT = "You help write user-facing follow-up questions after Index has reviewed potential connections for a human. Your job: surface the minimum set of structured decision questions the human must answer to make the next discovery turn sharper, or improve their outlook on the intent.\n\nYou may pick from five strategies. Choose contextually; mix when multiple questions genuinely complement.\n- refine_intent: ask the user to sharpen or pivot their original signal.\n- surface_missing_detail: ask for one concrete missing input (stage, location, timing, scope, \u2026).\n- open_adjacent_thread: offer a pivot suggested by recurring connection signals.\n- reflective_summary: mirror what the connection review revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from the connection review and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. Index cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which people surface next.\n3. The same fact is NOT already in chatContext.statedFacts, NOT already asked in chatContext.openQuestions, and NOT already shared in chatContext.surfacedFindings.\n\nStandalone prompt rule. Every generated `prompt` must be understandable outside the conversation where it was created. Naturally include the original query, discovery pattern, connection pattern, or concrete learned fact in the question text itself. Do not rely on `title`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about. For example, prefer \"For your AI crypto decentralized deep-tech search, which area is most critical right now?\" over \"Which area is most critical right now?\"\n\nReferential closure. The prompt must resolve entirely on its own, with no dangling references. The reader sees ONLY the question text \u2014 never the people you reviewed, the events on their calendar, or this conversation. Do not use demonstratives or definite anaphora that point at things the reader cannot see: \"these builders\", \"those founders\", \"these researchers\", \"these conversations\", \"this lunch\", \"the speaker\". If you reference a person, name them. If you reference a group, restate the concrete shared attribute inside the question itself (\"founders working on decentralized identity\"), never \"these founders\". Never imply a list, set, or prior exchange the reader is not currently looking at.\n- Bad: \"What kind of collaboration are you looking for with these builders?\"\n- Good: \"You're meeting people building agent infrastructure \u2014 what kind of collaboration are you looking for?\"\n\nNo process narration. Never describe Index's own activity or internal state. Forbidden: \"the previous negotiation\", \"the negotiation stalled\", \"opportunities found so far\", \"my search\", \"the counterparty\", \"candidates reviewed\", restating why a match did or did not happen, or quoting words a counterparty did or did not use. Ask about the user's goal or intent directly, never about the matching pipeline.\n- Bad: \"All opportunities found so far are related to 'Edge Esmeralda'. Would you like to broaden the search?\"\n- Good: \"Do you want to focus on people at Edge Esmeralda, or also connect beyond it?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first (e.g. one surface_emergent_knowledge + one refine_intent). Add a third only when there are \u22653 substantive people reviewed and three distinct strategies each unblock a real decision. Two questions of the same strategy are acceptable only if their decision domains differ (different titles). Avoid stacking three pulls (info-from-user); balance with pushes (info-to-user via reflective_summary / surface_emergent_knowledge).\n\nOrdering. Questions whose answer unblocks the most connection reviews come first; then highest-impact; then ambiguity-clarifying. Reviews that needed more detail or ran out of time signal under-specification \u2014 prioritize.\n\nUser-facing language. Every title, prompt, option label, and option description is shown directly to the user. Never mention raw protocol mechanics or internal labels such as \"agent\", \"patient\", \"peer\", \"suggestedRoles\", \"role distribution\", \"counterparty\", \"negotiation\", \"turn_cap\", \"timeout\", or \"candidate\". Use natural language instead: people, matches, connections, mutual collaboration, someone who can help, or someone seeking help.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option, not its definition. 2\u20134 options. Never add an \"Other\" option \u2014 clients provide a free-text fallback automatically. For surface_emergent_knowledge questions, anchor the prompt in the concrete cited fact (\"Multiple people flagged that\u2026\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. \u226412 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns \u2014 never do these.\n- Don't ask procedural confirmations (\"Should I look again?\").\n- Don't ask about hypothetical edge cases that didn't occur.\n- Don't ask about specific person identities; treat the provided person summary as the only allowed reference.\n- Don't repeat anything in chatContext.openQuestions.\n- Don't re-surface anything in chatContext.surfacedFindings.\n- Don't ask for facts in chatContext.statedFacts.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the five values). If nothing is worth asking, return \"questions\": [].";
|
|
4
|
-
/**
|
|
5
|
-
* Pure builder: assembles the discovery-mode user message string from a
|
|
6
|
-
* structured input.
|
|
7
|
-
*/
|
|
8
|
-
export declare function buildDiscoveryQuestionPrompt(input: DiscoveryQuestionInput): string;
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/** System prompt for the QuestionerAgent's `discovery` mode. */
|
|
2
|
-
export const DISCOVERY_SYSTEM_PROMPT = `You help write user-facing follow-up questions after Index has reviewed potential connections for a human. Your job: surface the minimum set of structured decision questions the human must answer to make the next discovery turn sharper, or improve their outlook on the intent.
|
|
3
|
-
|
|
4
|
-
You may pick from five strategies. Choose contextually; mix when multiple questions genuinely complement.
|
|
5
|
-
- refine_intent: ask the user to sharpen or pivot their original signal.
|
|
6
|
-
- surface_missing_detail: ask for one concrete missing input (stage, location, timing, scope, …).
|
|
7
|
-
- open_adjacent_thread: offer a pivot suggested by recurring connection signals.
|
|
8
|
-
- reflective_summary: mirror what the connection review revealed and ask the user to decide.
|
|
9
|
-
- surface_emergent_knowledge: cite a fact you learned from the connection review and ask the user to decide in light of it.
|
|
10
|
-
|
|
11
|
-
Ask a question only when ALL of these hold:
|
|
12
|
-
1. Index cannot resolve the decision autonomously from the evidence shown.
|
|
13
|
-
2. The answer would materially change which people surface next.
|
|
14
|
-
3. The same fact is NOT already in chatContext.statedFacts, NOT already asked in chatContext.openQuestions, and NOT already shared in chatContext.surfacedFindings.
|
|
15
|
-
|
|
16
|
-
Standalone prompt rule. Every generated \`prompt\` must be understandable outside the conversation where it was created. Naturally include the original query, discovery pattern, connection pattern, or concrete learned fact in the question text itself. Do not rely on \`title\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about. For example, prefer "For your AI crypto decentralized deep-tech search, which area is most critical right now?" over "Which area is most critical right now?"
|
|
17
|
-
|
|
18
|
-
Referential closure. The prompt must resolve entirely on its own, with no dangling references. The reader sees ONLY the question text — never the people you reviewed, the events on their calendar, or this conversation. Do not use demonstratives or definite anaphora that point at things the reader cannot see: "these builders", "those founders", "these researchers", "these conversations", "this lunch", "the speaker". If you reference a person, name them. If you reference a group, restate the concrete shared attribute inside the question itself ("founders working on decentralized identity"), never "these founders". Never imply a list, set, or prior exchange the reader is not currently looking at.
|
|
19
|
-
- Bad: "What kind of collaboration are you looking for with these builders?"
|
|
20
|
-
- Good: "You're meeting people building agent infrastructure — what kind of collaboration are you looking for?"
|
|
21
|
-
|
|
22
|
-
No process narration. Never describe Index's own activity or internal state. Forbidden: "the previous negotiation", "the negotiation stalled", "opportunities found so far", "my search", "the counterparty", "candidates reviewed", restating why a match did or did not happen, or quoting words a counterparty did or did not use. Ask about the user's goal or intent directly, never about the matching pipeline.
|
|
23
|
-
- Bad: "All opportunities found so far are related to 'Edge Esmeralda'. Would you like to broaden the search?"
|
|
24
|
-
- Good: "Do you want to focus on people at Edge Esmeralda, or also connect beyond it?"
|
|
25
|
-
|
|
26
|
-
Cardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first (e.g. one surface_emergent_knowledge + one refine_intent). Add a third only when there are ≥3 substantive people reviewed and three distinct strategies each unblock a real decision. Two questions of the same strategy are acceptable only if their decision domains differ (different titles). Avoid stacking three pulls (info-from-user); balance with pushes (info-to-user via reflective_summary / surface_emergent_knowledge).
|
|
27
|
-
|
|
28
|
-
Ordering. Questions whose answer unblocks the most connection reviews come first; then highest-impact; then ambiguity-clarifying. Reviews that needed more detail or ran out of time signal under-specification — prioritize.
|
|
29
|
-
|
|
30
|
-
User-facing language. Every title, prompt, option label, and option description is shown directly to the user. Never mention raw protocol mechanics or internal labels such as "agent", "patient", "peer", "suggestedRoles", "role distribution", "counterparty", "negotiation", "turn_cap", "timeout", or "candidate". Use natural language instead: people, matches, connections, mutual collaboration, someone who can help, or someone seeking help.
|
|
31
|
-
|
|
32
|
-
Option construction. Each option must represent a meaningfully different outcome. Suffix the safest path with " (Recommended)" and list it first. The description states the CONSEQUENCE of choosing the option, not its definition. 2–4 options. Never add an "Other" option — clients provide a free-text fallback automatically. For surface_emergent_knowledge questions, anchor the prompt in the concrete cited fact ("Multiple people flagged that…") and let the options represent decisions in light of that fact, not different versions of the fact.
|
|
33
|
-
|
|
34
|
-
Title rules. ≤12 chars. Noun of the decision domain. Discovery examples: "Stage", "Timing", "Role", "Location", "Stack", "Budget", "Scope", "Format".
|
|
35
|
-
|
|
36
|
-
Anti-patterns — never do these.
|
|
37
|
-
- Don't ask procedural confirmations ("Should I look again?").
|
|
38
|
-
- Don't ask about hypothetical edge cases that didn't occur.
|
|
39
|
-
- Don't ask about specific person identities; treat the provided person summary as the only allowed reference.
|
|
40
|
-
- Don't repeat anything in chatContext.openQuestions.
|
|
41
|
-
- Don't re-surface anything in chatContext.surfacedFindings.
|
|
42
|
-
- Don't ask for facts in chatContext.statedFacts.
|
|
43
|
-
|
|
44
|
-
Output. Return at most 3 entries in the "questions" array. Each entry must include a "strategy" field (one of the five values). If nothing is worth asking, return "questions": [].`;
|
|
45
|
-
/**
|
|
46
|
-
* Pure builder: assembles the discovery-mode user message string from a
|
|
47
|
-
* structured input.
|
|
48
|
-
*/
|
|
49
|
-
export function buildDiscoveryQuestionPrompt(input) {
|
|
50
|
-
const profileSummary = input.userContext?.trim() || "(no profile data)";
|
|
51
|
-
const connectionReviewBlocks = renderConnectionReviewDigests(input.negotiationDigests);
|
|
52
|
-
const chatContextBlock = input.chatContext
|
|
53
|
-
? renderDigest(input.chatContext)
|
|
54
|
-
: "(no chat context available)";
|
|
55
|
-
const engagementPattern = renderEngagementPattern(input.summary.roleDistribution);
|
|
56
|
-
return [
|
|
57
|
-
"## Seeker's query",
|
|
58
|
-
input.query,
|
|
59
|
-
"",
|
|
60
|
-
"## Seeker profile",
|
|
61
|
-
profileSummary,
|
|
62
|
-
"",
|
|
63
|
-
"## This discovery turn",
|
|
64
|
-
`- ${input.summary.totalCandidates} people reviewed`,
|
|
65
|
-
`- ${input.summary.opportunitiesFound} promising connections found`,
|
|
66
|
-
`- ${input.summary.noOpportunityCount} reviews did not find enough fit (${input.summary.timeoutCount} needed more detail or time)`,
|
|
67
|
-
`- Engagement pattern: ${engagementPattern}`,
|
|
68
|
-
"",
|
|
69
|
-
"## Connection review evidence (compact digests)",
|
|
70
|
-
connectionReviewBlocks,
|
|
71
|
-
"",
|
|
72
|
-
"## What the user has already said in this session",
|
|
73
|
-
chatContextBlock,
|
|
74
|
-
"",
|
|
75
|
-
"## Now",
|
|
76
|
-
input.now,
|
|
77
|
-
"",
|
|
78
|
-
"## Your task",
|
|
79
|
-
"Identify the minimum set of decision questions the seeker must answer to make",
|
|
80
|
-
"the next discovery turn sharper. Apply every rule from your system prompt",
|
|
81
|
-
"before outputting. Return an empty `questions` array if nothing is worth asking.",
|
|
82
|
-
].join("\n");
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Render the negotiation-digest collection into compact one-liners. Each digest
|
|
86
|
-
* is fixed-size (≤ ~400 chars after rendering), so the rendered block scales
|
|
87
|
-
* linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.
|
|
88
|
-
*/
|
|
89
|
-
function renderConnectionReviewDigests(digests) {
|
|
90
|
-
if (digests.length === 0)
|
|
91
|
-
return "(no connection reviews)";
|
|
92
|
-
return digests
|
|
93
|
-
.map((d) => {
|
|
94
|
-
const relationshipSignal = d.suggestedRoles
|
|
95
|
-
? [` Relationship signal: ${renderRelationshipSignal(d.suggestedRoles)}`]
|
|
96
|
-
: [];
|
|
97
|
-
return [
|
|
98
|
-
`- Person: ${d.counterpartyHint}`,
|
|
99
|
-
` Community context: ${d.indexContext}`,
|
|
100
|
-
` Outcome: ${renderOutcome(d)}`,
|
|
101
|
-
...relationshipSignal,
|
|
102
|
-
` Take: ${d.keyTake}`,
|
|
103
|
-
].join("\n");
|
|
104
|
-
})
|
|
105
|
-
.join("\n\n");
|
|
106
|
-
}
|
|
107
|
-
function renderEngagementPattern(dist) {
|
|
108
|
-
const parts = [];
|
|
109
|
-
if ((dist.peer ?? 0) > 0) {
|
|
110
|
-
parts.push(`${dist.peer} mutual collaboration${dist.peer === 1 ? "" : "s"}`);
|
|
111
|
-
}
|
|
112
|
-
if ((dist.agent ?? 0) > 0) {
|
|
113
|
-
parts.push(`${dist.agent} where the user could offer help or expertise`);
|
|
114
|
-
}
|
|
115
|
-
if ((dist.patient ?? 0) > 0) {
|
|
116
|
-
parts.push(`${dist.patient} where the user seemed to be seeking help or expertise`);
|
|
117
|
-
}
|
|
118
|
-
return parts.length > 0 ? parts.join(", ") : "(no engagement pattern available)";
|
|
119
|
-
}
|
|
120
|
-
function renderOutcome(digest) {
|
|
121
|
-
const outcome = digest.outcomeRole === "opportunity"
|
|
122
|
-
? "promising connection"
|
|
123
|
-
: "not enough fit";
|
|
124
|
-
const reason = renderOutcomeReason(digest.outcomeReason);
|
|
125
|
-
return reason ? `${outcome} (${reason})` : outcome;
|
|
126
|
-
}
|
|
127
|
-
function renderOutcomeReason(reason) {
|
|
128
|
-
switch (reason) {
|
|
129
|
-
case "turn_cap":
|
|
130
|
-
return "needed more detail";
|
|
131
|
-
case "timeout":
|
|
132
|
-
return "ran out of time";
|
|
133
|
-
case "rejected":
|
|
134
|
-
return "not enough mutual interest";
|
|
135
|
-
case "stalled":
|
|
136
|
-
return "stalled";
|
|
137
|
-
case "screened_out":
|
|
138
|
-
return "didn't look like a strong enough fit to pursue";
|
|
139
|
-
case null:
|
|
140
|
-
return "";
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
function renderRelationshipSignal(roles) {
|
|
144
|
-
if (roles.ownUser === "peer" && roles.otherUser === "peer")
|
|
145
|
-
return "mutual collaboration";
|
|
146
|
-
if (roles.ownUser === "agent" && roles.otherUser === "patient") {
|
|
147
|
-
return "the user could offer help or expertise";
|
|
148
|
-
}
|
|
149
|
-
if (roles.ownUser === "patient" && roles.otherUser === "agent") {
|
|
150
|
-
return "the user seemed to be seeking help or expertise";
|
|
151
|
-
}
|
|
152
|
-
if (roles.ownUser === "agent")
|
|
153
|
-
return "the user could offer help or expertise";
|
|
154
|
-
if (roles.ownUser === "patient")
|
|
155
|
-
return "the user seemed to be seeking help or expertise";
|
|
156
|
-
return "collaboration fit";
|
|
157
|
-
}
|
|
158
|
-
function renderDigest(d) {
|
|
159
|
-
const lines = [];
|
|
160
|
-
if (d.statedFacts.length > 0) {
|
|
161
|
-
lines.push("Stated facts:");
|
|
162
|
-
for (const f of d.statedFacts)
|
|
163
|
-
lines.push(` - ${f}`);
|
|
164
|
-
}
|
|
165
|
-
if (d.openQuestions.length > 0) {
|
|
166
|
-
lines.push("Open questions (assistant already asked):");
|
|
167
|
-
for (const q of d.openQuestions)
|
|
168
|
-
lines.push(` - ${q}`);
|
|
169
|
-
}
|
|
170
|
-
if (d.rejectionReasons.length > 0) {
|
|
171
|
-
lines.push("User pushback / rejections:");
|
|
172
|
-
for (const r of d.rejectionReasons)
|
|
173
|
-
lines.push(` - ${r}`);
|
|
174
|
-
}
|
|
175
|
-
if (d.surfacedFindings.length > 0) {
|
|
176
|
-
lines.push("Findings already surfaced to user:");
|
|
177
|
-
for (const f of d.surfacedFindings)
|
|
178
|
-
lines.push(` - ${f}`);
|
|
179
|
-
}
|
|
180
|
-
return lines.length > 0 ? lines.join("\n") : "(digest is empty)";
|
|
181
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* questions/ports/question.generator.port — inline question generator port.
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Inline question generation is superseded by the async
|
|
5
|
-
* QuestionerQueue path (`questionerEnqueue`). Will be removed once the inline
|
|
6
|
-
* fallback in `opportunity.discover.ts` is retired.
|
|
7
|
-
*
|
|
8
|
-
* Protocol-level read contract for decision-question generation. Implementations
|
|
9
|
-
* live in the backend (see `QuestionGeneratorService`, which delegates to the
|
|
10
|
-
* QuestionerAgent's `discovery` mode) and are injected into the protocol via
|
|
11
|
-
* `ProtocolDeps`/`ToolContext`. The protocol module never constructs its own
|
|
12
|
-
* LLM-bound generator — callers inject one (or `undefined` to opt out).
|
|
13
|
-
*
|
|
14
|
-
* IND-547: canonical question generator port.
|
|
15
|
-
*/
|
|
16
|
-
import type { DiscoveryQuestionInput } from "../../shared/schemas/discovery-question.schema.js";
|
|
17
|
-
import type { QuestionGenerationResult } from "../domain/question.schema.js";
|
|
18
|
-
export interface QuestionGeneratorReader {
|
|
19
|
-
/**
|
|
20
|
-
* Run the question generator over a single discovery turn.
|
|
21
|
-
*
|
|
22
|
-
* @param input Discovery turn payload (query + negotiation digests + chat context).
|
|
23
|
-
* @param options.signal Optional AbortSignal. When aborted (deadline reached or
|
|
24
|
-
* upstream cancel) the in-flight LLM call is cancelled and `null` is returned —
|
|
25
|
-
* discovery still emits its response, just without questions.
|
|
26
|
-
* @returns The structured result, or `null` when generation failed,
|
|
27
|
-
* guardrails dropped all candidates, the underlying LLM threw, or
|
|
28
|
-
* the call was aborted.
|
|
29
|
-
*/
|
|
30
|
-
generate(input: DiscoveryQuestionInput, options?: {
|
|
31
|
-
signal?: AbortSignal;
|
|
32
|
-
}): Promise<QuestionGenerationResult | null>;
|
|
33
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|