@indexnetwork/protocol 3.6.1 → 3.6.2-rc.263.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/opportunity/question.prompt.d.ts +1 -1
- package/dist/opportunity/question.prompt.d.ts.map +1 -1
- package/dist/opportunity/question.prompt.js +2 -0
- package/dist/opportunity/question.prompt.js.map +1 -1
- package/dist/questioner/questioner.presets.d.ts.map +1 -1
- package/dist/questioner/questioner.presets.js +12 -0
- package/dist/questioner/questioner.presets.js.map +1 -1
- package/package.json +1 -1
|
@@ -87,7 +87,7 @@ export interface DiscoveryQuestionInput {
|
|
|
87
87
|
now: string;
|
|
88
88
|
}
|
|
89
89
|
/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */
|
|
90
|
-
export declare const SYSTEM_PROMPT = "You sit between a human and a discovery protocol that just ran negotiations on their behalf. 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 counterparty signals.\n- reflective_summary: mirror what the negotiations revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from negotiations and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. The agent cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which candidates 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\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 candidates 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 failed negotiations come first; then highest-impact; then ambiguity-clarifying. Negotiations whose outcome.reason is \"turn_cap\" or \"timeout\" signal under-specification \u2014 prioritize.\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 candidates 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 candidate identities; treat counterpartyHint 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\": [].";
|
|
90
|
+
export declare const SYSTEM_PROMPT = "You sit between a human and a discovery protocol that just ran negotiations on their behalf. 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 counterparty signals.\n- reflective_summary: mirror what the negotiations revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from negotiations and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. The agent cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which candidates 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, negotiation 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\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 candidates 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 failed negotiations come first; then highest-impact; then ambiguity-clarifying. Negotiations whose outcome.reason is \"turn_cap\" or \"timeout\" signal under-specification \u2014 prioritize.\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 candidates 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 candidate identities; treat counterpartyHint 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\": [].";
|
|
91
91
|
/**
|
|
92
92
|
* @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.
|
|
93
93
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.prompt.d.ts","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAEjG,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3D,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;CAC1E;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAED,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,2FAA2F;IAC3F,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,sBAAsB,CAAC;IACtC;;;;;OAKG;IACH,kBAAkB,EAAE,0BAA0B,EAAE,CAAC;IACjD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"question.prompt.d.ts","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAEjG,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3D,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;CAC1E;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAED,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,2FAA2F;IAC3F,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,sBAAsB,CAAC;IACtC;;;;;OAKG;IACH,kBAAkB,EAAE,0BAA0B,EAAE,CAAC;IACjD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,eAAO,MAAM,aAAa,6zHAgC0J,CAAC;AAErL;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAmCzE"}
|
|
@@ -13,6 +13,8 @@ Ask a question only when ALL of these hold:
|
|
|
13
13
|
2. The answer would materially change which candidates surface next.
|
|
14
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
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, negotiation 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
|
+
|
|
16
18
|
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 candidates 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).
|
|
17
19
|
|
|
18
20
|
Ordering. Questions whose answer unblocks the most failed negotiations come first; then highest-impact; then ambiguity-clarifying. Negotiations whose outcome.reason is "turn_cap" or "timeout" signal under-specification — prioritize.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.prompt.js","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Prompt module for the decision-question generator: the system prompt\n * constant, the `DiscoveryQuestionInput` contract, and a pure string-building\n * `buildQuestionPrompt` that assembles the user message.\n *\n * Pure: no I/O, no LLM call. The generator class (`question.generator.ts`)\n * orchestrates this module + an LLM client.\n */\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\n\n/** Roles used in the existing negotiation framework. */\nexport type NegotiationRole = \"agent\" | \"patient\" | \"peer\";\n\n/** One turn within a negotiation. */\nexport interface DiscoveryTurn {\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\";\n reasoning: string;\n suggestedRoles: { ownUser: NegotiationRole; otherUser: NegotiationRole };\n}\n\n/** Outcome of a negotiation. */\nexport interface DiscoveryOutcome {\n hasOpportunity: boolean;\n reasoning: string;\n agreedRoles?: Array<{ userId: string; role: NegotiationRole }>;\n /** Why the negotiation stopped, when not by an explicit accept/reject. */\n reason?: \"turn_cap\" | \"timeout\";\n}\n\n/** One negotiation that ran during this discovery turn. */\nexport interface DiscoveryNegotiation {\n /** Opaque counterparty identifier; NEVER surfaced to the user (kept out of the prompt). */\n counterpartyId: string;\n /** Abstract profile slice for the LLM (e.g. \"AI infra founder, Berlin\"). */\n counterpartyHint: string;\n /** The network/community prompt this negotiation ran under. */\n indexContext: string;\n /** Last 6 turns are retained; earlier ones are dropped. */\n turns: DiscoveryTurn[];\n outcome: DiscoveryOutcome;\n /**\n * Optional pre-negotiation evaluator score (0..1). When more than\n * `MAX_NEGOTIATIONS` candidates exist, this is used as a tie-breaker after\n * `turns.length` to decide which to keep.\n */\n seedAssessmentScore?: number;\n}\n\n/** Aggregate counters across all negotiations in this discovery turn. */\nexport interface DiscoverySummary {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n /** Subset of `noOpportunityCount` where the negotiation hit a turn-cap or timeout. */\n timeoutCount: number;\n /** Map of role → count across all outcomes' `agreedRoles`. */\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n}\n\n/** The seeker's profile slice the generator sees. All fields optional. */\nexport interface DiscoverySourceProfile {\n name?: string;\n bio?: string;\n location?: string;\n skills?: string[];\n interests?: string[];\n}\n\n/** Full input to the question generator. */\nexport interface DiscoveryQuestionInput {\n /** The seeker's original natural-language query / signal that triggered discovery. */\n query: string;\n sourceProfile: DiscoverySourceProfile;\n /**\n * Compact per-negotiation digests from THIS discovery turn. Each digest is a\n * fixed-size structured summary (counterparty hint, index, outcome role,\n * keyTake) — pre-summarized so this prompt stays small regardless of how\n * many candidates were negotiated. Raw negotiations are NOT passed here.\n */\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n /** Distilled chat-session digest, when a session is in scope. */\n chatContext?: ChatContextDigest;\n /** ISO timestamp used as the \"now\" anchor in the prompt. */\n now: string;\n}\n\n/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */\nexport const SYSTEM_PROMPT = `You sit between a human and a discovery protocol that just ran negotiations on their behalf. 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, …).\n- open_adjacent_thread: offer a pivot suggested by recurring counterparty signals.\n- reflective_summary: mirror what the negotiations revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from negotiations and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. The agent cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which candidates 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\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 ≥3 substantive candidates 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 failed negotiations come first; then highest-impact; then ambiguity-clarifying. Negotiations whose outcome.reason is \"turn_cap\" or \"timeout\" signal under-specification — prioritize.\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–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 candidates flagged that…\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns — 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 candidate identities; treat counterpartyHint 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\": [].`;\n\n/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Pure builder: assembles the user message string from a structured input.\n */\nexport function buildQuestionPrompt(input: DiscoveryQuestionInput): string {\n const profileSummary = renderProfile(input.sourceProfile);\n const negotiationBlocks = renderDiscoveryNegotiationDigests(input.negotiationDigests);\n const chatContextBlock = input.chatContext\n ? renderDigest(input.chatContext)\n : \"(no chat context available)\";\n const roleDistribution = renderRoleDistribution(input.summary.roleDistribution);\n\n return [\n \"## Seeker's query\",\n input.query,\n \"\",\n \"## Seeker profile\",\n profileSummary,\n \"\",\n \"## This discovery turn\",\n `- ${input.summary.totalCandidates} candidates evaluated`,\n `- ${input.summary.opportunitiesFound} opportunities found`,\n `- ${input.summary.noOpportunityCount} ended without opportunity (${input.summary.timeoutCount} hit turn-cap/timeout)`,\n `- Role distribution across outcomes: ${roleDistribution}`,\n \"\",\n \"## Negotiation evidence (compact digests)\",\n negotiationBlocks,\n \"\",\n \"## What the user has already said in this session\",\n chatContextBlock,\n \"\",\n \"## Now\",\n input.now,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of decision questions the seeker must answer to make\",\n \"the next discovery turn sharper. Apply every rule from your system prompt\",\n \"before outputting. Return an empty `questions` array if nothing is worth asking.\",\n ].join(\"\\n\");\n}\n\n/**\n * Render the negotiation-digest collection into compact one-liners. Each digest\n * is fixed-size (≤ ~400 chars after rendering), so the rendered block scales\n * linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.\n */\nfunction renderDiscoveryNegotiationDigests(digests: DiscoveryNegotiationDigest[]): string {\n if (digests.length === 0) return \"(no negotiations)\";\n return digests\n .map((d) => {\n const reasonSuffix = d.outcomeReason ? ` (${d.outcomeReason})` : \"\";\n const rolesSuffix = d.suggestedRoles\n ? ` — roles=${d.suggestedRoles.ownUser}↔${d.suggestedRoles.otherUser}`\n : \"\";\n return [\n `- Counterparty: ${d.counterpartyHint}`,\n ` Index: ${d.indexContext}`,\n ` Outcome: ${d.outcomeRole}${reasonSuffix}${rolesSuffix}`,\n ` Take: ${d.keyTake}`,\n ].join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\nfunction renderProfile(p: DiscoverySourceProfile): string {\n const lines: string[] = [];\n if (p.name) lines.push(`Name: ${p.name}`);\n if (p.bio) lines.push(`Bio: ${p.bio}`);\n if (p.location) lines.push(`Location: ${p.location}`);\n if (p.skills && p.skills.length > 0) lines.push(`Skills: ${p.skills.join(\", \")}`);\n if (p.interests && p.interests.length > 0) lines.push(`Interests: ${p.interests.join(\", \")}`);\n return lines.length > 0 ? lines.join(\"\\n\") : \"(no profile data)\";\n}\n\nfunction renderRoleDistribution(dist: Partial<Record<NegotiationRole, number>>): string {\n const entries = (Object.entries(dist) as Array<[NegotiationRole, number]>)\n .filter(([, n]) => n > 0);\n if (entries.length === 0) return \"(none)\";\n return entries.map(([role, n]) => `${role}=${n}`).join(\", \");\n}\n\nfunction renderDigest(d: ChatContextDigest): string {\n const lines: string[] = [];\n if (d.statedFacts.length > 0) {\n lines.push(\"Stated facts:\");\n for (const f of d.statedFacts) lines.push(` - ${f}`);\n }\n if (d.openQuestions.length > 0) {\n lines.push(\"Open questions (assistant already asked):\");\n for (const q of d.openQuestions) lines.push(` - ${q}`);\n }\n if (d.rejectionReasons.length > 0) {\n lines.push(\"User pushback / rejections:\");\n for (const r of d.rejectionReasons) lines.push(` - ${r}`);\n }\n if (d.surfacedFindings.length > 0) {\n lines.push(\"Findings already surfaced to user:\");\n for (const f of d.surfacedFindings) lines.push(` - ${f}`);\n }\n return lines.length > 0 ? lines.join(\"\\n\") : \"(digest is empty)\";\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"question.prompt.js","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Prompt module for the decision-question generator: the system prompt\n * constant, the `DiscoveryQuestionInput` contract, and a pure string-building\n * `buildQuestionPrompt` that assembles the user message.\n *\n * Pure: no I/O, no LLM call. The generator class (`question.generator.ts`)\n * orchestrates this module + an LLM client.\n */\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\n\n/** Roles used in the existing negotiation framework. */\nexport type NegotiationRole = \"agent\" | \"patient\" | \"peer\";\n\n/** One turn within a negotiation. */\nexport interface DiscoveryTurn {\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\";\n reasoning: string;\n suggestedRoles: { ownUser: NegotiationRole; otherUser: NegotiationRole };\n}\n\n/** Outcome of a negotiation. */\nexport interface DiscoveryOutcome {\n hasOpportunity: boolean;\n reasoning: string;\n agreedRoles?: Array<{ userId: string; role: NegotiationRole }>;\n /** Why the negotiation stopped, when not by an explicit accept/reject. */\n reason?: \"turn_cap\" | \"timeout\";\n}\n\n/** One negotiation that ran during this discovery turn. */\nexport interface DiscoveryNegotiation {\n /** Opaque counterparty identifier; NEVER surfaced to the user (kept out of the prompt). */\n counterpartyId: string;\n /** Abstract profile slice for the LLM (e.g. \"AI infra founder, Berlin\"). */\n counterpartyHint: string;\n /** The network/community prompt this negotiation ran under. */\n indexContext: string;\n /** Last 6 turns are retained; earlier ones are dropped. */\n turns: DiscoveryTurn[];\n outcome: DiscoveryOutcome;\n /**\n * Optional pre-negotiation evaluator score (0..1). When more than\n * `MAX_NEGOTIATIONS` candidates exist, this is used as a tie-breaker after\n * `turns.length` to decide which to keep.\n */\n seedAssessmentScore?: number;\n}\n\n/** Aggregate counters across all negotiations in this discovery turn. */\nexport interface DiscoverySummary {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n /** Subset of `noOpportunityCount` where the negotiation hit a turn-cap or timeout. */\n timeoutCount: number;\n /** Map of role → count across all outcomes' `agreedRoles`. */\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n}\n\n/** The seeker's profile slice the generator sees. All fields optional. */\nexport interface DiscoverySourceProfile {\n name?: string;\n bio?: string;\n location?: string;\n skills?: string[];\n interests?: string[];\n}\n\n/** Full input to the question generator. */\nexport interface DiscoveryQuestionInput {\n /** The seeker's original natural-language query / signal that triggered discovery. */\n query: string;\n sourceProfile: DiscoverySourceProfile;\n /**\n * Compact per-negotiation digests from THIS discovery turn. Each digest is a\n * fixed-size structured summary (counterparty hint, index, outcome role,\n * keyTake) — pre-summarized so this prompt stays small regardless of how\n * many candidates were negotiated. Raw negotiations are NOT passed here.\n */\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n /** Distilled chat-session digest, when a session is in scope. */\n chatContext?: ChatContextDigest;\n /** ISO timestamp used as the \"now\" anchor in the prompt. */\n now: string;\n}\n\n/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */\nexport const SYSTEM_PROMPT = `You sit between a human and a discovery protocol that just ran negotiations on their behalf. 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, …).\n- open_adjacent_thread: offer a pivot suggested by recurring counterparty signals.\n- reflective_summary: mirror what the negotiations revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from negotiations and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. The agent cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which candidates 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, negotiation 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\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 ≥3 substantive candidates 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 failed negotiations come first; then highest-impact; then ambiguity-clarifying. Negotiations whose outcome.reason is \"turn_cap\" or \"timeout\" signal under-specification — prioritize.\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–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 candidates flagged that…\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns — 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 candidate identities; treat counterpartyHint 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\": [].`;\n\n/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Pure builder: assembles the user message string from a structured input.\n */\nexport function buildQuestionPrompt(input: DiscoveryQuestionInput): string {\n const profileSummary = renderProfile(input.sourceProfile);\n const negotiationBlocks = renderDiscoveryNegotiationDigests(input.negotiationDigests);\n const chatContextBlock = input.chatContext\n ? renderDigest(input.chatContext)\n : \"(no chat context available)\";\n const roleDistribution = renderRoleDistribution(input.summary.roleDistribution);\n\n return [\n \"## Seeker's query\",\n input.query,\n \"\",\n \"## Seeker profile\",\n profileSummary,\n \"\",\n \"## This discovery turn\",\n `- ${input.summary.totalCandidates} candidates evaluated`,\n `- ${input.summary.opportunitiesFound} opportunities found`,\n `- ${input.summary.noOpportunityCount} ended without opportunity (${input.summary.timeoutCount} hit turn-cap/timeout)`,\n `- Role distribution across outcomes: ${roleDistribution}`,\n \"\",\n \"## Negotiation evidence (compact digests)\",\n negotiationBlocks,\n \"\",\n \"## What the user has already said in this session\",\n chatContextBlock,\n \"\",\n \"## Now\",\n input.now,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of decision questions the seeker must answer to make\",\n \"the next discovery turn sharper. Apply every rule from your system prompt\",\n \"before outputting. Return an empty `questions` array if nothing is worth asking.\",\n ].join(\"\\n\");\n}\n\n/**\n * Render the negotiation-digest collection into compact one-liners. Each digest\n * is fixed-size (≤ ~400 chars after rendering), so the rendered block scales\n * linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.\n */\nfunction renderDiscoveryNegotiationDigests(digests: DiscoveryNegotiationDigest[]): string {\n if (digests.length === 0) return \"(no negotiations)\";\n return digests\n .map((d) => {\n const reasonSuffix = d.outcomeReason ? ` (${d.outcomeReason})` : \"\";\n const rolesSuffix = d.suggestedRoles\n ? ` — roles=${d.suggestedRoles.ownUser}↔${d.suggestedRoles.otherUser}`\n : \"\";\n return [\n `- Counterparty: ${d.counterpartyHint}`,\n ` Index: ${d.indexContext}`,\n ` Outcome: ${d.outcomeRole}${reasonSuffix}${rolesSuffix}`,\n ` Take: ${d.keyTake}`,\n ].join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\nfunction renderProfile(p: DiscoverySourceProfile): string {\n const lines: string[] = [];\n if (p.name) lines.push(`Name: ${p.name}`);\n if (p.bio) lines.push(`Bio: ${p.bio}`);\n if (p.location) lines.push(`Location: ${p.location}`);\n if (p.skills && p.skills.length > 0) lines.push(`Skills: ${p.skills.join(\", \")}`);\n if (p.interests && p.interests.length > 0) lines.push(`Interests: ${p.interests.join(\", \")}`);\n return lines.length > 0 ? lines.join(\"\\n\") : \"(no profile data)\";\n}\n\nfunction renderRoleDistribution(dist: Partial<Record<NegotiationRole, number>>): string {\n const entries = (Object.entries(dist) as Array<[NegotiationRole, number]>)\n .filter(([, n]) => n > 0);\n if (entries.length === 0) return \"(none)\";\n return entries.map(([role, n]) => `${role}=${n}`).join(\", \");\n}\n\nfunction renderDigest(d: ChatContextDigest): string {\n const lines: string[] = [];\n if (d.statedFacts.length > 0) {\n lines.push(\"Stated facts:\");\n for (const f of d.statedFacts) lines.push(` - ${f}`);\n }\n if (d.openQuestions.length > 0) {\n lines.push(\"Open questions (assistant already asked):\");\n for (const q of d.openQuestions) lines.push(` - ${q}`);\n }\n if (d.rejectionReasons.length > 0) {\n lines.push(\"User pushback / rejections:\");\n for (const r of d.rejectionReasons) lines.push(` - ${r}`);\n }\n if (d.surfacedFindings.length > 0) {\n lines.push(\"Findings already surfaced to user:\");\n for (const f of d.surfacedFindings) lines.push(` - ${f}`);\n }\n return lines.length > 0 ? lines.join(\"\\n\") : \"(digest is empty)\";\n}\n\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.presets.d.ts","sourceRoot":"/","sources":["questioner/questioner.presets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAQzE,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"questioner.presets.d.ts","sourceRoot":"/","sources":["questioner/questioner.presets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAQzE,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;CAC3C;AA+OD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,gBAAgB,CAM9D"}
|
|
@@ -11,6 +11,10 @@ Ask a question only when ALL of these hold:
|
|
|
11
11
|
2. The answer would materially change which candidates surface.
|
|
12
12
|
3. The question targets a different decision domain from any other question in this batch.
|
|
13
13
|
|
|
14
|
+
Standalone prompt rule. Every generated \`prompt\` must be understandable outside the conversation where it was created. Naturally include the source intent/topic in the question text itself, using concise plain language from the intent or summary. Do not rely on \`title\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.
|
|
15
|
+
- Bad: "What kind of collaboration are you looking for?"
|
|
16
|
+
- Good: "For your decentralized identity protocol-design search, what kind of collaboration are you looking for?"
|
|
17
|
+
|
|
14
18
|
Cardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ (different titles).
|
|
15
19
|
|
|
16
20
|
Option construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.
|
|
@@ -74,6 +78,10 @@ Ask a question only when ALL of these hold:
|
|
|
74
78
|
3. The answer would meaningfully change which opportunities surface for this user.
|
|
75
79
|
4. The question targets a different profile domain from any other question in this batch.
|
|
76
80
|
|
|
81
|
+
Standalone prompt rule. Every generated \`prompt\` must be understandable outside the conversation where it was created. Naturally include the profile signal or gap being clarified in the question text itself, using concise plain language from the current profile, existing premises, or identified gaps. Do not rely on \`title\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.
|
|
82
|
+
- Bad: "What kind of role are you looking for?"
|
|
83
|
+
- Good: "To improve matches from your founder/operator profile, what kind of role are you looking for?"
|
|
84
|
+
|
|
77
85
|
Cardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.
|
|
78
86
|
|
|
79
87
|
Option construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.
|
|
@@ -139,6 +147,10 @@ Ask a question only when ALL of these hold:
|
|
|
139
147
|
2. The answer would materially change how the next attempt surfaces or engages candidates.
|
|
140
148
|
3. The question targets a different decision domain from any other question in this batch.
|
|
141
149
|
|
|
150
|
+
Standalone prompt rule. Every generated \`prompt\` must be understandable outside the conversation where it was created. Naturally include the stalled negotiation context, counterparty hint, community, or key takeaway 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.
|
|
151
|
+
- Bad: "Which role is a better fit for your immediate needs?"
|
|
152
|
+
- Good: "For the stalled match with an AI infra founder in the AI founders community, which role is a better fit for your immediate needs?"
|
|
153
|
+
|
|
142
154
|
Cardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.
|
|
143
155
|
|
|
144
156
|
Option construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.presets.js","sourceRoot":"/","sources":["questioner/questioner.presets.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mode presets for the QuestionerAgent. Each preset provides a system prompt\n * and a buildPrompt function that assembles the user message from a typed\n * context object. Only the `discovery` preset ships in Slice 1; others throw\n * until their implementation slices land.\n */\nimport type { QuestionMode } from \"../shared/schemas/question.schema.js\";\nimport {\n SYSTEM_PROMPT as DISCOVERY_SYSTEM_PROMPT,\n buildQuestionPrompt as buildDiscoveryPrompt,\n} from \"../opportunity/question.prompt.js\";\n\nimport type { IntentContext, NegotiationContext, ProfileContext } from \"./questioner.types.js\";\n\nexport interface QuestionerPreset {\n /** The LLM system prompt for this mode. */\n systemPrompt: string;\n /** Builds the user-message string from the mode-specific context. */\n buildPrompt: (context: unknown) => string;\n}\n\n// ─── Intent preset ──────────────────────────────────────────────────────────\n\nconst INTENT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has stated an intent — what they are looking for. Your job: surface the minimum set of structured questions that help the user sharpen that intent before the protocol runs discovery on their behalf.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: ask the user to sharpen or pivot the core signal (scope, scale, specificity, direction).\n- surface_missing_detail: ask for one concrete missing input that would change which candidates surface (stage, location, timing, budget, constraints, format, …).\n\nAsk a question only when ALL of these hold:\n1. The agent cannot infer the answer from the intent text or user profile already shown.\n2. The answer would materially change which candidates surface.\n3. The question targets a different decision domain from any other question in this batch.\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ (different titles).\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Stage\", \"Timing\", \"Location\", \"Scope\", \"Budget\", \"Format\", \"Skills\", \"Collab\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I start searching?\").\n- Don't ask about hypothetical edge cases not implied by the intent.\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the intent is already specific enough, return \"questions\": [].`;\n\n/**\n * Build the user message for the intent preset from an IntentContext.\n * @param ctx - The intent context.\n * @returns The assembled user message string.\n */\nfunction buildIntentPrompt(ctx: IntentContext): string {\n const profileLines: string[] = [];\n if (ctx.userProfile.name) profileLines.push(`Name: ${ctx.userProfile.name}`);\n if (ctx.userProfile.bio) profileLines.push(`Bio: ${ctx.userProfile.bio}`);\n if (ctx.userProfile.skills && ctx.userProfile.skills.length > 0) {\n profileLines.push(`Skills: ${ctx.userProfile.skills.join(\", \")}`);\n }\n if (ctx.userProfile.interests && ctx.userProfile.interests.length > 0) {\n profileLines.push(`Interests: ${ctx.userProfile.interests.join(\", \")}`);\n }\n const profileBlock = profileLines.length > 0 ? profileLines.join(\"\\n\") : \"(no profile data)\";\n\n const summaryBlock = ctx.summary ? ctx.summary : \"(no summary available)\";\n\n return [\n \"## Intent\",\n ctx.payload,\n \"\",\n \"## Summary\",\n summaryBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to sharpen this intent.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the intent is already specific enough.\",\n ].join(\"\\n\");\n}\n\n// ─── Profile preset ─────────────────────────────────────────────────────────\n\nconst PROFILE_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has a profile that is incomplete. Your job: surface the minimum set of structured questions that fill the identified gaps — asking about location, skills, interests, current work, or goals — so the protocol can run better discovery on their behalf.\n\nThe user may already have premises — atomic self-descriptions they have stated. These cover specific profile domains. Do not ask about domains already addressed by existing premises. Focus only on gaps not covered by any premise.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing piece of profile data (location, current role, skills, interests, goals, availability, …).\n- refine_intent: ask the user to clarify or sharpen an existing profile signal so candidates can be ranked more accurately.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the profile data shown.\n2. The answer is not already covered by an existing premise listed below the profile.\n3. The answer would meaningfully change which opportunities surface for this user.\n4. The question targets a different profile domain from any other question in this batch.\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the profile domain. Examples: \"Location\", \"Role\", \"Skills\", \"Goals\", \"Interests\", \"Availability\", \"Stage\".\n\nAnti-patterns — never do these.\n- Don't ask about fields already filled in the profile.\n- Don't ask about information already captured in an existing premise.\n- Don't ask procedural confirmations (\"Should I update your profile?\").\n- Don't ask vague introspective questions (\"Who are you really?\").\n- Don't re-ask for facts visible anywhere in the profile data or premises shown.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the profile is already complete enough for discovery, return \"questions\": [].`;\n\n/**\n * Build the user message for the profile preset from a ProfileContext.\n * @param ctx - The profile context including current profile data and identified gaps.\n * @returns The assembled user message string.\n */\nfunction buildProfilePrompt(ctx: ProfileContext): string {\n const profileLines: string[] = [];\n if (ctx.userProfile.name) profileLines.push(`Name: ${ctx.userProfile.name}`);\n if (ctx.userProfile.bio) profileLines.push(`Bio: ${ctx.userProfile.bio}`);\n if (ctx.userProfile.location) profileLines.push(`Location: ${ctx.userProfile.location}`);\n if (ctx.userProfile.skills && ctx.userProfile.skills.length > 0) {\n profileLines.push(`Skills: ${ctx.userProfile.skills.join(\", \")}`);\n }\n if (ctx.userProfile.interests && ctx.userProfile.interests.length > 0) {\n profileLines.push(`Interests: ${ctx.userProfile.interests.join(\", \")}`);\n }\n const profileBlock = profileLines.length > 0 ? profileLines.join(\"\\n\") : \"(no profile data)\";\n\n const premisesBlock =\n ctx.existingPremises && ctx.existingPremises.length > 0\n ? ctx.existingPremises.map((p, i) => `${i + 1}. ${p}`).join(\"\\n\")\n : \"(none)\";\n\n const gapsBlock = ctx.gaps.length > 0 ? ctx.gaps.join(\", \") : \"(none identified)\";\n\n const parts: string[] = [\n \"## Current profile\",\n profileBlock,\n \"\",\n \"## Existing premises\",\n premisesBlock,\n \"\",\n \"## Identified gaps\",\n gapsBlock,\n \"\",\n ];\n\n parts.push(\n \"## Your task\",\n \"Generate the minimum set of questions needed to fill the identified gaps.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the profile is already complete enough.\",\n );\n\n return parts.join(\"\\n\");\n}\n\n// ─── Negotiation preset ──────────────────────────────────────────────────────\n\nconst NEGOTIATION_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. A negotiation between this user and a counterparty has ended without a clear outcome — either the turn budget was exhausted, the session timed out, or conversation stalled. Your job: surface the minimum set of structured questions that help the user provide the missing signal needed to unblock or refine the next discovery attempt on their behalf.\n\nYou may pick from three strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: help the user sharpen their underlying signal based on what the negotiation revealed (scope, scale, priority, direction).\n- surface_missing_detail: ask for one concrete piece of information that was absent and would have moved the negotiation forward (timeline, budget, format, constraints, decision criteria, …).\n- reflective_summary: mirror the key takeaway from the negotiation and ask the user to confirm, correct, or decide — useful when the conversation revealed partial signal worth locking in.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the negotiation context or user profile shown.\n2. The answer would materially change how the next attempt surfaces or engages candidates.\n3. The question targets a different decision domain from any other question in this batch.\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Scope\", \"Timeline\", \"Budget\", \"Priority\", \"Format\", \"Stance\", \"Criteria\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I try again?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n- Don't ask about hypothetical edge cases not implied by the negotiation context.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the three values above). If the context already contains enough signal to proceed, return \"questions\": [].`;\n\n/**\n * Build the user message for the negotiation preset from a NegotiationContext.\n * @param ctx - The negotiation context including counterparty hint, stall reason, and key takeaway.\n * @returns The assembled user message string.\n */\nfunction buildNegotiationPrompt(ctx: NegotiationContext): string {\n const profileLines: string[] = [];\n if (ctx.userProfile.name) profileLines.push(`Name: ${ctx.userProfile.name}`);\n if (ctx.userProfile.bio) profileLines.push(`Bio: ${ctx.userProfile.bio}`);\n if (ctx.userProfile.skills && ctx.userProfile.skills.length > 0) {\n profileLines.push(`Skills: ${ctx.userProfile.skills.join(\", \")}`);\n }\n if (ctx.userProfile.interests && ctx.userProfile.interests.length > 0) {\n profileLines.push(`Interests: ${ctx.userProfile.interests.join(\", \")}`);\n }\n const profileBlock = profileLines.length > 0 ? profileLines.join(\"\\n\") : \"(no profile data)\";\n\n return [\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Counterparty: ${ctx.counterpartyHint}`,\n `Stall reason: ${ctx.outcomeReason}`,\n \"\",\n \"## Key takeaway\",\n ctx.keyTake,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to unblock the next discovery attempt.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the context already contains enough signal to proceed.\",\n ].join(\"\\n\");\n}\n\nconst presets: Record<QuestionMode, QuestionerPreset> = {\n discovery: {\n systemPrompt: DISCOVERY_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) =>\n buildDiscoveryPrompt(context as Parameters<typeof buildDiscoveryPrompt>[0]),\n },\n intent: {\n systemPrompt: INTENT_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildIntentPrompt(context as IntentContext),\n },\n profile: {\n systemPrompt: PROFILE_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildProfilePrompt(context as ProfileContext),\n },\n negotiation: {\n systemPrompt: NEGOTIATION_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildNegotiationPrompt(context as NegotiationContext),\n },\n};\n\n/**\n * Retrieve the preset for the given mode.\n * @param mode - The question mode to look up.\n * @returns The matching preset with systemPrompt and buildPrompt.\n * @throws Error if the mode's preset is not yet implemented.\n */\nexport function getPreset(mode: QuestionMode): QuestionerPreset {\n const preset = presets[mode];\n if (!preset) {\n throw new Error(`QuestionerAgent preset \"${mode}\" is not implemented yet`);\n }\n return preset;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"questioner.presets.js","sourceRoot":"/","sources":["questioner/questioner.presets.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mode presets for the QuestionerAgent. Each preset provides a system prompt\n * and a buildPrompt function that assembles the user message from a typed\n * context object. Only the `discovery` preset ships in Slice 1; others throw\n * until their implementation slices land.\n */\nimport type { QuestionMode } from \"../shared/schemas/question.schema.js\";\nimport {\n SYSTEM_PROMPT as DISCOVERY_SYSTEM_PROMPT,\n buildQuestionPrompt as buildDiscoveryPrompt,\n} from \"../opportunity/question.prompt.js\";\n\nimport type { IntentContext, NegotiationContext, ProfileContext } from \"./questioner.types.js\";\n\nexport interface QuestionerPreset {\n /** The LLM system prompt for this mode. */\n systemPrompt: string;\n /** Builds the user-message string from the mode-specific context. */\n buildPrompt: (context: unknown) => string;\n}\n\n// ─── Intent preset ──────────────────────────────────────────────────────────\n\nconst INTENT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has stated an intent — what they are looking for. Your job: surface the minimum set of structured questions that help the user sharpen that intent before the protocol runs discovery on their behalf.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: ask the user to sharpen or pivot the core signal (scope, scale, specificity, direction).\n- surface_missing_detail: ask for one concrete missing input that would change which candidates surface (stage, location, timing, budget, constraints, format, …).\n\nAsk a question only when ALL of these hold:\n1. The agent cannot infer the answer from the intent text or user profile already shown.\n2. The answer would materially change which candidates surface.\n3. The question targets a different decision domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the source intent/topic in the question text itself, using concise plain language from the intent or summary. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"What kind of collaboration are you looking for?\"\n- Good: \"For your decentralized identity protocol-design search, what kind of collaboration are you looking for?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ (different titles).\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Stage\", \"Timing\", \"Location\", \"Scope\", \"Budget\", \"Format\", \"Skills\", \"Collab\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I start searching?\").\n- Don't ask about hypothetical edge cases not implied by the intent.\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the intent is already specific enough, return \"questions\": [].`;\n\n/**\n * Build the user message for the intent preset from an IntentContext.\n * @param ctx - The intent context.\n * @returns The assembled user message string.\n */\nfunction buildIntentPrompt(ctx: IntentContext): string {\n const profileLines: string[] = [];\n if (ctx.userProfile.name) profileLines.push(`Name: ${ctx.userProfile.name}`);\n if (ctx.userProfile.bio) profileLines.push(`Bio: ${ctx.userProfile.bio}`);\n if (ctx.userProfile.skills && ctx.userProfile.skills.length > 0) {\n profileLines.push(`Skills: ${ctx.userProfile.skills.join(\", \")}`);\n }\n if (ctx.userProfile.interests && ctx.userProfile.interests.length > 0) {\n profileLines.push(`Interests: ${ctx.userProfile.interests.join(\", \")}`);\n }\n const profileBlock = profileLines.length > 0 ? profileLines.join(\"\\n\") : \"(no profile data)\";\n\n const summaryBlock = ctx.summary ? ctx.summary : \"(no summary available)\";\n\n return [\n \"## Intent\",\n ctx.payload,\n \"\",\n \"## Summary\",\n summaryBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to sharpen this intent.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the intent is already specific enough.\",\n ].join(\"\\n\");\n}\n\n// ─── Profile preset ─────────────────────────────────────────────────────────\n\nconst PROFILE_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has a profile that is incomplete. Your job: surface the minimum set of structured questions that fill the identified gaps — asking about location, skills, interests, current work, or goals — so the protocol can run better discovery on their behalf.\n\nThe user may already have premises — atomic self-descriptions they have stated. These cover specific profile domains. Do not ask about domains already addressed by existing premises. Focus only on gaps not covered by any premise.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing piece of profile data (location, current role, skills, interests, goals, availability, …).\n- refine_intent: ask the user to clarify or sharpen an existing profile signal so candidates can be ranked more accurately.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the profile data shown.\n2. The answer is not already covered by an existing premise listed below the profile.\n3. The answer would meaningfully change which opportunities surface for this user.\n4. The question targets a different profile domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the profile signal or gap being clarified in the question text itself, using concise plain language from the current profile, existing premises, or identified gaps. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"What kind of role are you looking for?\"\n- Good: \"To improve matches from your founder/operator profile, what kind of role are you looking for?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the profile domain. Examples: \"Location\", \"Role\", \"Skills\", \"Goals\", \"Interests\", \"Availability\", \"Stage\".\n\nAnti-patterns — never do these.\n- Don't ask about fields already filled in the profile.\n- Don't ask about information already captured in an existing premise.\n- Don't ask procedural confirmations (\"Should I update your profile?\").\n- Don't ask vague introspective questions (\"Who are you really?\").\n- Don't re-ask for facts visible anywhere in the profile data or premises shown.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the profile is already complete enough for discovery, return \"questions\": [].`;\n\n/**\n * Build the user message for the profile preset from a ProfileContext.\n * @param ctx - The profile context including current profile data and identified gaps.\n * @returns The assembled user message string.\n */\nfunction buildProfilePrompt(ctx: ProfileContext): string {\n const profileLines: string[] = [];\n if (ctx.userProfile.name) profileLines.push(`Name: ${ctx.userProfile.name}`);\n if (ctx.userProfile.bio) profileLines.push(`Bio: ${ctx.userProfile.bio}`);\n if (ctx.userProfile.location) profileLines.push(`Location: ${ctx.userProfile.location}`);\n if (ctx.userProfile.skills && ctx.userProfile.skills.length > 0) {\n profileLines.push(`Skills: ${ctx.userProfile.skills.join(\", \")}`);\n }\n if (ctx.userProfile.interests && ctx.userProfile.interests.length > 0) {\n profileLines.push(`Interests: ${ctx.userProfile.interests.join(\", \")}`);\n }\n const profileBlock = profileLines.length > 0 ? profileLines.join(\"\\n\") : \"(no profile data)\";\n\n const premisesBlock =\n ctx.existingPremises && ctx.existingPremises.length > 0\n ? ctx.existingPremises.map((p, i) => `${i + 1}. ${p}`).join(\"\\n\")\n : \"(none)\";\n\n const gapsBlock = ctx.gaps.length > 0 ? ctx.gaps.join(\", \") : \"(none identified)\";\n\n const parts: string[] = [\n \"## Current profile\",\n profileBlock,\n \"\",\n \"## Existing premises\",\n premisesBlock,\n \"\",\n \"## Identified gaps\",\n gapsBlock,\n \"\",\n ];\n\n parts.push(\n \"## Your task\",\n \"Generate the minimum set of questions needed to fill the identified gaps.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the profile is already complete enough.\",\n );\n\n return parts.join(\"\\n\");\n}\n\n// ─── Negotiation preset ──────────────────────────────────────────────────────\n\nconst NEGOTIATION_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. A negotiation between this user and a counterparty has ended without a clear outcome — either the turn budget was exhausted, the session timed out, or conversation stalled. Your job: surface the minimum set of structured questions that help the user provide the missing signal needed to unblock or refine the next discovery attempt on their behalf.\n\nYou may pick from three strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: help the user sharpen their underlying signal based on what the negotiation revealed (scope, scale, priority, direction).\n- surface_missing_detail: ask for one concrete piece of information that was absent and would have moved the negotiation forward (timeline, budget, format, constraints, decision criteria, …).\n- reflective_summary: mirror the key takeaway from the negotiation and ask the user to confirm, correct, or decide — useful when the conversation revealed partial signal worth locking in.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the negotiation context or user profile shown.\n2. The answer would materially change how the next attempt surfaces or engages candidates.\n3. The question targets a different decision domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the stalled negotiation context, counterparty hint, community, or key takeaway 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.\n- Bad: \"Which role is a better fit for your immediate needs?\"\n- Good: \"For the stalled match with an AI infra founder in the AI founders community, which role is a better fit for your immediate needs?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Scope\", \"Timeline\", \"Budget\", \"Priority\", \"Format\", \"Stance\", \"Criteria\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I try again?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n- Don't ask about hypothetical edge cases not implied by the negotiation context.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the three values above). If the context already contains enough signal to proceed, return \"questions\": [].`;\n\n/**\n * Build the user message for the negotiation preset from a NegotiationContext.\n * @param ctx - The negotiation context including counterparty hint, stall reason, and key takeaway.\n * @returns The assembled user message string.\n */\nfunction buildNegotiationPrompt(ctx: NegotiationContext): string {\n const profileLines: string[] = [];\n if (ctx.userProfile.name) profileLines.push(`Name: ${ctx.userProfile.name}`);\n if (ctx.userProfile.bio) profileLines.push(`Bio: ${ctx.userProfile.bio}`);\n if (ctx.userProfile.skills && ctx.userProfile.skills.length > 0) {\n profileLines.push(`Skills: ${ctx.userProfile.skills.join(\", \")}`);\n }\n if (ctx.userProfile.interests && ctx.userProfile.interests.length > 0) {\n profileLines.push(`Interests: ${ctx.userProfile.interests.join(\", \")}`);\n }\n const profileBlock = profileLines.length > 0 ? profileLines.join(\"\\n\") : \"(no profile data)\";\n\n return [\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Counterparty: ${ctx.counterpartyHint}`,\n `Stall reason: ${ctx.outcomeReason}`,\n \"\",\n \"## Key takeaway\",\n ctx.keyTake,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to unblock the next discovery attempt.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the context already contains enough signal to proceed.\",\n ].join(\"\\n\");\n}\n\nconst presets: Record<QuestionMode, QuestionerPreset> = {\n discovery: {\n systemPrompt: DISCOVERY_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) =>\n buildDiscoveryPrompt(context as Parameters<typeof buildDiscoveryPrompt>[0]),\n },\n intent: {\n systemPrompt: INTENT_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildIntentPrompt(context as IntentContext),\n },\n profile: {\n systemPrompt: PROFILE_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildProfilePrompt(context as ProfileContext),\n },\n negotiation: {\n systemPrompt: NEGOTIATION_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildNegotiationPrompt(context as NegotiationContext),\n },\n};\n\n/**\n * Retrieve the preset for the given mode.\n * @param mode - The question mode to look up.\n * @returns The matching preset with systemPrompt and buildPrompt.\n * @throws Error if the mode's preset is not yet implemented.\n */\nexport function getPreset(mode: QuestionMode): QuestionerPreset {\n const preset = presets[mode];\n if (!preset) {\n throw new Error(`QuestionerAgent preset \"${mode}\" is not implemented yet`);\n }\n return preset;\n}\n"]}
|