@indexnetwork/protocol 4.9.0-rc.348.1 → 4.10.0-rc.350.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 +3 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/intent/intent.clarifier.d.ts +26 -5
- package/dist/intent/intent.clarifier.d.ts.map +1 -1
- package/dist/intent/intent.clarifier.js +59 -29
- package/dist/intent/intent.clarifier.js.map +1 -1
- package/dist/intent/intent.tools.d.ts +5 -0
- package/dist/intent/intent.tools.d.ts.map +1 -1
- package/dist/intent/intent.tools.js +44 -5
- package/dist/intent/intent.tools.js.map +1 -1
- package/dist/opportunity/discriminator/discriminator.adjustments.d.ts +52 -0
- package/dist/opportunity/discriminator/discriminator.adjustments.d.ts.map +1 -0
- package/dist/opportunity/discriminator/discriminator.adjustments.js +97 -0
- package/dist/opportunity/discriminator/discriminator.adjustments.js.map +1 -0
- package/dist/opportunity/discriminator/discriminator.env.d.ts +25 -0
- package/dist/opportunity/discriminator/discriminator.env.d.ts.map +1 -1
- package/dist/opportunity/discriminator/discriminator.env.js +25 -0
- package/dist/opportunity/discriminator/discriminator.env.js.map +1 -1
- package/dist/opportunity/discriminator/discriminator.question.d.ts.map +1 -1
- package/dist/opportunity/discriminator/discriminator.question.js +14 -5
- package/dist/opportunity/discriminator/discriminator.question.js.map +1 -1
- package/dist/opportunity/feed/feed.graph.d.ts.map +1 -1
- package/dist/opportunity/feed/feed.graph.js +56 -13
- package/dist/opportunity/feed/feed.graph.js.map +1 -1
- package/dist/opportunity/feed/feed.state.d.ts +2 -0
- package/dist/opportunity/feed/feed.state.d.ts.map +1 -1
- package/dist/opportunity/feed/feed.state.js.map +1 -1
- package/dist/opportunity/opportunity.presenter.d.ts +6 -0
- package/dist/opportunity/opportunity.presenter.d.ts.map +1 -1
- package/dist/opportunity/opportunity.presenter.js +12 -3
- package/dist/opportunity/opportunity.presenter.js.map +1 -1
- package/dist/opportunity/question.generator.d.ts.map +1 -1
- package/dist/opportunity/question.generator.js +9 -4
- package/dist/opportunity/question.generator.js.map +1 -1
- package/dist/questioner/questioner.agent.d.ts.map +1 -1
- package/dist/questioner/questioner.agent.js +4 -3
- package/dist/questioner/questioner.agent.js.map +1 -1
- package/dist/questioner/questioner.ask.tool.d.ts.map +1 -1
- package/dist/questioner/questioner.ask.tool.js +4 -0
- package/dist/questioner/questioner.ask.tool.js.map +1 -1
- package/dist/questioner/questioner.presets.d.ts.map +1 -1
- package/dist/questioner/questioner.presets.js +10 -6
- package/dist/questioner/questioner.presets.js.map +1 -1
- package/dist/questioner/questioner.qud.d.ts +8 -0
- package/dist/questioner/questioner.qud.d.ts.map +1 -0
- package/dist/questioner/questioner.qud.js +12 -0
- package/dist/questioner/questioner.qud.js.map +1 -0
- package/dist/shared/interfaces/questioner.interface.d.ts +3 -1
- package/dist/shared/interfaces/questioner.interface.d.ts.map +1 -1
- package/dist/shared/interfaces/questioner.interface.js.map +1 -1
- package/dist/shared/schemas/question.schema.d.ts +29 -7
- package/dist/shared/schemas/question.schema.d.ts.map +1 -1
- package/dist/shared/schemas/question.schema.js +16 -4
- package/dist/shared/schemas/question.schema.js.map +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.ask.tool.js","sourceRoot":"/","sources":["questioner/questioner.ask.tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ask_user_question — blocking mid-conversation questions for the chat\n * orchestrator (AskUserQuestion-style human-in-the-loop).\n *\n * Flow (hybrid authoring):\n * 1. The orchestrator states what it needs to learn (`purpose`) plus optional\n * draft questions.\n * 2. The QuestionerAgent (mode `chat`) refines that into polished structured\n * questions, grounded in the recent conversation excerpt and the user's\n * global context.\n * 3. Questions are persisted (`questions` table, mode `chat`,\n * `conversationId = sessionId`) via the injected {@link ChatQuestionsHost}.\n * 4. A `user_question` trace event streams the persisted questions to the\n * frontend, which renders them inline while the turn stays open.\n * 5. The tool blocks on `awaitAnswers` until the user answers/dismisses\n * through the questions REST endpoints, the wait budget elapses, or the\n * run is aborted. Answers come back as the tool result so the model\n * continues the SAME turn.\n *\n * On timeout the questions remain `pending`: they survive reloads via the\n * conversation-linked question fetch, and a later answer re-enters the chat\n * as a new user turn (frontend responsibility).\n *\n * Chat-only: not registered in the MCP tool registry. The handler also fails\n * gracefully when the session/stream context or host bridge is missing.\n */\nimport { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { error, success } from \"../shared/agent/tool.helpers.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PersistableQuestion, PersistedQuestion, ChatQuestionAnswerOutcome } from \"../shared/interfaces/questioner.interface.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport { QuestionerAgent } from \"./questioner.agent.js\";\nimport { chatQuestionWaitTimeoutMs } from \"./questioner.env.js\";\nimport type { ChatContext } from \"./questioner.types.js\";\n\nconst logger = protocolLogger(\"AskUserQuestionTool\");\n\n\n/** Heartbeat interval while blocked, so SSE transports do not idle out. */\nconst WAIT_HEARTBEAT_MS = 15_000;\n\n/** Messages included in the conversation excerpt fed to the QuestionerAgent. */\nconst EXCERPT_MESSAGE_COUNT = 10;\n\n/**\n * Fetch window for the excerpt. Host adapters return the FIRST N messages\n * (ascending) when a limit is passed, so we fetch a wide window and keep the\n * tail to get the most recent exchange.\n */\nconst EXCERPT_FETCH_LIMIT = 100;\n\n/** Max characters per message inside the excerpt. */\nconst EXCERPT_MESSAGE_CHARS = 400;\n\n// Lazy singleton — construction binds the LLM once; invocations are stateless.\nlet questionerAgent: QuestionerAgent | null = null;\nfunction getQuestionerAgent(): QuestionerAgent {\n if (!questionerAgent) questionerAgent = new QuestionerAgent();\n return questionerAgent;\n}\n\n/** Test seam: replace or reset the module-level QuestionerAgent singleton. */\nexport function setQuestionerAgentForTesting(agent: QuestionerAgent | null): void {\n questionerAgent = agent;\n}\n\nconst draftQuestionSchema = z.object({\n prompt: z\n .string()\n .min(5)\n .max(400)\n .describe(\"The question to ask, ending in a question mark. Self-contained plain language.\"),\n options: z\n .array(z.string().min(1).max(120))\n .min(2)\n .max(4)\n .optional()\n .describe(\"2-4 mutually distinct answer options. Omit to let the question generator derive them.\"),\n multiSelect: z\n .boolean()\n .optional()\n .describe(\"True when several options can be picked together (priorities, bundles).\"),\n});\n\n/**\n * Build a fallback Question directly from an orchestrator draft when the\n * QuestionerAgent produced nothing. Requires the draft to carry options.\n */\nfunction questionFromDraft(draft: z.infer<typeof draftQuestionSchema>, index: number): Question | null {\n if (!draft.options || draft.options.length < 2) return null;\n return {\n title: `Question ${index + 1}`,\n prompt: draft.prompt.slice(0, 400),\n options: draft.options.slice(0, 4).map((label) => ({\n label: label.slice(0, 120),\n description: label.slice(0, 280),\n })),\n multiSelect: draft.multiSelect ?? false,\n };\n}\n\n/**\n * Creates the chat-only `ask_user_question` tool. Registered by\n * `createChatTools` only when `deps.chatQuestions` is provided — never part\n * of the MCP tool registry (MCP clients have their own elicitation surface).\n *\n * @param defineTool - Tool factory provided by the composition root.\n * @param deps - Shared tool dependencies; requires `chatQuestions`.\n */\nexport function createAskUserQuestionTools(defineTool: DefineTool, deps: ToolDeps) {\n const askUserQuestion = defineTool({\n name: \"ask_user_question\",\n description:\n \"Ask the user 1-3 structured clarifying questions and WAIT for their answer before continuing. \" +\n \"The conversation pauses: the user sees interactive question cards inline and your turn resumes \" +\n \"with their selections as the tool result.\\n\\n\" +\n \"**Use when** a decision materially changes what you do next — before an expensive operation \" +\n \"(discovery, creating an intent from ambiguous input), when facing meaningfully different \" +\n \"directions, or when one concrete missing detail (timing, scope, budget, format) blocks progress.\\n\\n\" +\n \"**Do not use** for facts already visible in the conversation or profile, procedural \" +\n \"confirmations (\\\"Should I proceed?\\\"), or open-ended questions better asked in your response text.\\n\\n\" +\n \"**Input:** `purpose` states what you need to learn and why. Optionally propose `questions` \" +\n \"drafts (prompt + 2-4 options); a question generator refines wording and option quality.\\n\\n\" +\n \"**Returns:** One entry per question with `status` (`answered`/`dismissed`/`timeout`) and the \" +\n \"user's `selectedOptions`/`freeText`. On `timeout` the questions stay visible in the \" +\n \"conversation — acknowledge briefly and end your turn; do NOT repeat the questions in text.\",\n querySchema: z.object({\n purpose: z\n .string()\n .min(10)\n .max(600)\n .describe(\"What you need to learn from the user and why it changes what you do next.\"),\n questions: z\n .array(draftQuestionSchema)\n .min(1)\n .max(3)\n .optional()\n .describe(\"Draft questions to ask. The question generator polishes them before display.\"),\n }),\n handler: async ({ context, query }) => {\n const host = deps.chatQuestions;\n if (!host) {\n return error(\n \"Interactive questions are not available in this environment. Ask the user directly in your response text instead.\",\n );\n }\n if (context.isMcp || !context.sessionId) {\n return error(\n \"Interactive questions require a live chat session. Ask the user directly in your response text instead.\",\n );\n }\n const store = requestContext.getStore();\n const emit = store?.traceEmitter;\n const signal = store?.abortSignal;\n if (!emit) {\n return error(\n \"Interactive questions require a streaming chat turn. Ask the user directly in your response text instead.\",\n );\n }\n\n const sessionId = context.sessionId;\n\n // ── 1. Gather grounding context ────────────────────────────────────\n const [conversationExcerpt, userContext] = await Promise.all([\n loadConversationExcerpt(deps, sessionId),\n deps.getUserContextText?.(context.userId).catch(() => \"\") ?? Promise.resolve(\"\"),\n ]);\n\n // ── 2. Generate polished questions (hybrid: drafts + QuestionerAgent) ──\n const chatContext: ChatContext = {\n purpose: query.purpose,\n ...(query.questions?.length ? { draftQuestions: query.questions } : {}),\n ...(conversationExcerpt ? { conversationExcerpt } : {}),\n ...(userContext ? { userContext } : {}),\n };\n\n let generated: { questions: Question[]; strategies: QuestionStrategy[] } | null = null;\n try {\n generated = await getQuestionerAgent().invoke(\n {\n mode: \"chat\",\n userId: context.userId,\n sourceType: \"conversation\",\n sourceId: sessionId,\n context: chatContext,\n conversationId: sessionId,\n },\n signal ? { signal } : undefined,\n );\n } catch (err) {\n logger.warn(\"QuestionerAgent invocation failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n let finalQuestions: Question[];\n let strategies: QuestionStrategy[];\n if (generated && generated.questions.length > 0) {\n finalQuestions = generated.questions;\n strategies = generated.strategies;\n } else {\n // Fallback: use the orchestrator's own drafts verbatim (options required).\n const fromDrafts = (query.questions ?? [])\n .map((d, i) => questionFromDraft(d, i))\n .filter((q): q is Question => q !== null);\n if (fromDrafts.length === 0) {\n return error(\n \"Could not prepare structured questions. Ask the user directly in your response text instead.\",\n );\n }\n finalQuestions = fromDrafts;\n strategies = fromDrafts.map(() => \"surface_missing_detail\" as const);\n }\n\n if (signal?.aborted) {\n return error(\"The chat turn was cancelled before the questions could be shown.\");\n }\n\n // ── 3. Persist (mode `chat`, linked to this conversation) ──────────\n const timestamp = new Date().toISOString();\n const batch: PersistableQuestion[] = finalQuestions.map((payload, i) => ({\n detection: {\n mode: \"chat\",\n sourceType: \"conversation\",\n sourceId: sessionId,\n timestamp,\n },\n actors: [{ userId: context.userId, role: \"subject\" as const }],\n payload,\n strategy: strategies[i] ?? \"surface_missing_detail\",\n conversationId: sessionId,\n }));\n\n let persisted: PersistedQuestion[];\n try {\n persisted = await host.persist(batch);\n } catch (err) {\n logger.error(\"Failed to persist chat questions\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return error(\"Could not deliver the questions to the user. Ask directly in your response text instead.\");\n }\n\n // ── 4. Stream the cards to the frontend ────────────────────────────\n emit({\n type: \"user_question\",\n questions: persisted.map((q) => ({\n id: q.id,\n title: q.payload.title,\n prompt: q.payload.prompt,\n options: q.payload.options,\n multiSelect: q.payload.multiSelect,\n })),\n });\n\n // ── 5. Block until answered / dismissed / timeout / abort ──────────\n const heartbeat = setInterval(() => {\n try {\n emit({ type: \"status\", message: \"Waiting for your answer…\" });\n } catch {\n /* stream may be closing; the wait resolves via timeout/abort */\n }\n }, WAIT_HEARTBEAT_MS);\n\n let outcomes: ChatQuestionAnswerOutcome[];\n try {\n outcomes = await host.awaitAnswers(\n persisted.map((q) => q.id),\n { timeoutMs: chatQuestionWaitTimeoutMs(), ...(signal ? { signal } : {}) },\n );\n } finally {\n clearInterval(heartbeat);\n }\n\n const byId = new Map(persisted.map((q) => [q.id, q]));\n const results = outcomes.map((o) => {\n const q = byId.get(o.questionId);\n return {\n questionId: o.questionId,\n prompt: q?.payload.prompt ?? \"\",\n status: o.status,\n ...(o.answer\n ? {\n selectedOptions: o.answer.selectedOptions,\n ...(o.answer.freeText ? { freeText: o.answer.freeText } : {}),\n }\n : {}),\n };\n });\n\n const answeredCount = results.filter((r) => r.status === \"answered\").length;\n const timedOut = results.some((r) => r.status === \"timeout\");\n\n return success({\n answers: results,\n summary: `${answeredCount} of ${results.length} question(s) answered`,\n ...(timedOut\n ? {\n guidance:\n \"The user has not answered the remaining question(s) yet. They stay visible in the conversation — acknowledge briefly, do NOT repeat the questions in text, and end your turn.\",\n }\n : {}),\n });\n },\n });\n\n return [askUserQuestion] as const;\n}\n\n/**\n * Load a compact excerpt of the most recent conversation messages for the\n * QuestionerAgent's grounding. Best-effort: returns \"\" on any failure or when\n * no chat session reader is available. Note: the in-flight user message is\n * not yet persisted; the orchestrator's `purpose` carries that context.\n */\nasync function loadConversationExcerpt(deps: ToolDeps, sessionId: string): Promise<string> {\n if (!deps.chatSession) return \"\";\n try {\n const messages = await deps.chatSession.getSessionMessages(sessionId, EXCERPT_FETCH_LIMIT);\n if (!messages || messages.length === 0) return \"\";\n return messages\n .slice(-EXCERPT_MESSAGE_COUNT)\n .map((m) => {\n const role = m.role === \"assistant\" ? \"Assistant\" : \"User\";\n const text = (m.content ?? \"\").replace(/\\s+/g, \" \").trim();\n return `${role}: ${text.slice(0, EXCERPT_MESSAGE_CHARS)}`;\n })\n .join(\"\\n\");\n } catch (err) {\n logger.warn(\"Failed to load conversation excerpt\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return \"\";\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"questioner.ask.tool.js","sourceRoot":"/","sources":["questioner/questioner.ask.tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ask_user_question — blocking mid-conversation questions for the chat\n * orchestrator (AskUserQuestion-style human-in-the-loop).\n *\n * Flow (hybrid authoring):\n * 1. The orchestrator states what it needs to learn (`purpose`) plus optional\n * draft questions.\n * 2. The QuestionerAgent (mode `chat`) refines that into polished structured\n * questions, grounded in the recent conversation excerpt and the user's\n * global context.\n * 3. Questions are persisted (`questions` table, mode `chat`,\n * `conversationId = sessionId`) via the injected {@link ChatQuestionsHost}.\n * 4. A `user_question` trace event streams the persisted questions to the\n * frontend, which renders them inline while the turn stays open.\n * 5. The tool blocks on `awaitAnswers` until the user answers/dismisses\n * through the questions REST endpoints, the wait budget elapses, or the\n * run is aborted. Answers come back as the tool result so the model\n * continues the SAME turn.\n *\n * On timeout the questions remain `pending`: they survive reloads via the\n * conversation-linked question fetch, and a later answer re-enters the chat\n * as a new user turn (frontend responsibility).\n *\n * Chat-only: not registered in the MCP tool registry. The handler also fails\n * gracefully when the session/stream context or host bridge is missing.\n */\nimport { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { error, success } from \"../shared/agent/tool.helpers.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PersistableQuestion, PersistedQuestion, ChatQuestionAnswerOutcome } from \"../shared/interfaces/questioner.interface.js\";\nimport type { Question, QuestionGenerationResult, QuestionStrategy, UnderspecificationType } from \"../shared/schemas/question.schema.js\";\nimport { QuestionerAgent } from \"./questioner.agent.js\";\nimport { chatQuestionWaitTimeoutMs } from \"./questioner.env.js\";\nimport type { ChatContext } from \"./questioner.types.js\";\n\nconst logger = protocolLogger(\"AskUserQuestionTool\");\n\n\n/** Heartbeat interval while blocked, so SSE transports do not idle out. */\nconst WAIT_HEARTBEAT_MS = 15_000;\n\n/** Messages included in the conversation excerpt fed to the QuestionerAgent. */\nconst EXCERPT_MESSAGE_COUNT = 10;\n\n/**\n * Fetch window for the excerpt. Host adapters return the FIRST N messages\n * (ascending) when a limit is passed, so we fetch a wide window and keep the\n * tail to get the most recent exchange.\n */\nconst EXCERPT_FETCH_LIMIT = 100;\n\n/** Max characters per message inside the excerpt. */\nconst EXCERPT_MESSAGE_CHARS = 400;\n\n// Lazy singleton — construction binds the LLM once; invocations are stateless.\nlet questionerAgent: QuestionerAgent | null = null;\nfunction getQuestionerAgent(): QuestionerAgent {\n if (!questionerAgent) questionerAgent = new QuestionerAgent();\n return questionerAgent;\n}\n\n/** Test seam: replace or reset the module-level QuestionerAgent singleton. */\nexport function setQuestionerAgentForTesting(agent: QuestionerAgent | null): void {\n questionerAgent = agent;\n}\n\nconst draftQuestionSchema = z.object({\n prompt: z\n .string()\n .min(5)\n .max(400)\n .describe(\"The question to ask, ending in a question mark. Self-contained plain language.\"),\n options: z\n .array(z.string().min(1).max(120))\n .min(2)\n .max(4)\n .optional()\n .describe(\"2-4 mutually distinct answer options. Omit to let the question generator derive them.\"),\n multiSelect: z\n .boolean()\n .optional()\n .describe(\"True when several options can be picked together (priorities, bundles).\"),\n});\n\n/**\n * Build a fallback Question directly from an orchestrator draft when the\n * QuestionerAgent produced nothing. Requires the draft to carry options.\n */\nfunction questionFromDraft(draft: z.infer<typeof draftQuestionSchema>, index: number): Question | null {\n if (!draft.options || draft.options.length < 2) return null;\n return {\n title: `Question ${index + 1}`,\n prompt: draft.prompt.slice(0, 400),\n options: draft.options.slice(0, 4).map((label) => ({\n label: label.slice(0, 120),\n description: label.slice(0, 280),\n })),\n multiSelect: draft.multiSelect ?? false,\n };\n}\n\n/**\n * Creates the chat-only `ask_user_question` tool. Registered by\n * `createChatTools` only when `deps.chatQuestions` is provided — never part\n * of the MCP tool registry (MCP clients have their own elicitation surface).\n *\n * @param defineTool - Tool factory provided by the composition root.\n * @param deps - Shared tool dependencies; requires `chatQuestions`.\n */\nexport function createAskUserQuestionTools(defineTool: DefineTool, deps: ToolDeps) {\n const askUserQuestion = defineTool({\n name: \"ask_user_question\",\n description:\n \"Ask the user 1-3 structured clarifying questions and WAIT for their answer before continuing. \" +\n \"The conversation pauses: the user sees interactive question cards inline and your turn resumes \" +\n \"with their selections as the tool result.\\n\\n\" +\n \"**Use when** a decision materially changes what you do next — before an expensive operation \" +\n \"(discovery, creating an intent from ambiguous input), when facing meaningfully different \" +\n \"directions, or when one concrete missing detail (timing, scope, budget, format) blocks progress.\\n\\n\" +\n \"**Do not use** for facts already visible in the conversation or profile, procedural \" +\n \"confirmations (\\\"Should I proceed?\\\"), or open-ended questions better asked in your response text.\\n\\n\" +\n \"**Input:** `purpose` states what you need to learn and why. Optionally propose `questions` \" +\n \"drafts (prompt + 2-4 options); a question generator refines wording and option quality.\\n\\n\" +\n \"**Returns:** One entry per question with `status` (`answered`/`dismissed`/`timeout`) and the \" +\n \"user's `selectedOptions`/`freeText`. On `timeout` the questions stay visible in the \" +\n \"conversation — acknowledge briefly and end your turn; do NOT repeat the questions in text.\",\n querySchema: z.object({\n purpose: z\n .string()\n .min(10)\n .max(600)\n .describe(\"What you need to learn from the user and why it changes what you do next.\"),\n questions: z\n .array(draftQuestionSchema)\n .min(1)\n .max(3)\n .optional()\n .describe(\"Draft questions to ask. The question generator polishes them before display.\"),\n }),\n handler: async ({ context, query }) => {\n const host = deps.chatQuestions;\n if (!host) {\n return error(\n \"Interactive questions are not available in this environment. Ask the user directly in your response text instead.\",\n );\n }\n if (context.isMcp || !context.sessionId) {\n return error(\n \"Interactive questions require a live chat session. Ask the user directly in your response text instead.\",\n );\n }\n const store = requestContext.getStore();\n const emit = store?.traceEmitter;\n const signal = store?.abortSignal;\n if (!emit) {\n return error(\n \"Interactive questions require a streaming chat turn. Ask the user directly in your response text instead.\",\n );\n }\n\n const sessionId = context.sessionId;\n\n // ── 1. Gather grounding context ────────────────────────────────────\n const [conversationExcerpt, userContext] = await Promise.all([\n loadConversationExcerpt(deps, sessionId),\n deps.getUserContextText?.(context.userId).catch(() => \"\") ?? Promise.resolve(\"\"),\n ]);\n\n // ── 2. Generate polished questions (hybrid: drafts + QuestionerAgent) ──\n const chatContext: ChatContext = {\n purpose: query.purpose,\n ...(query.questions?.length ? { draftQuestions: query.questions } : {}),\n ...(conversationExcerpt ? { conversationExcerpt } : {}),\n ...(userContext ? { userContext } : {}),\n };\n\n let generated: QuestionGenerationResult | null = null;\n try {\n generated = await getQuestionerAgent().invoke(\n {\n mode: \"chat\",\n userId: context.userId,\n sourceType: \"conversation\",\n sourceId: sessionId,\n context: chatContext,\n conversationId: sessionId,\n },\n signal ? { signal } : undefined,\n );\n } catch (err) {\n logger.warn(\"QuestionerAgent invocation failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n let finalQuestions: Question[];\n let strategies: QuestionStrategy[];\n let underspecificationTypes: Array<UnderspecificationType | null>;\n if (generated && generated.questions.length > 0) {\n finalQuestions = generated.questions;\n strategies = generated.strategies;\n underspecificationTypes = generated.underspecificationTypes;\n } else {\n // Fallback: use the orchestrator's own drafts verbatim (options required).\n const fromDrafts = (query.questions ?? [])\n .map((d, i) => questionFromDraft(d, i))\n .filter((q): q is Question => q !== null);\n if (fromDrafts.length === 0) {\n return error(\n \"Could not prepare structured questions. Ask the user directly in your response text instead.\",\n );\n }\n finalQuestions = fromDrafts;\n strategies = fromDrafts.map(() => \"surface_missing_detail\" as const);\n underspecificationTypes = fromDrafts.map(() => null);\n }\n\n if (signal?.aborted) {\n return error(\"The chat turn was cancelled before the questions could be shown.\");\n }\n\n // ── 3. Persist (mode `chat`, linked to this conversation) ──────────\n const timestamp = new Date().toISOString();\n const batch: PersistableQuestion[] = finalQuestions.map((payload, i) => ({\n detection: {\n mode: \"chat\",\n sourceType: \"conversation\",\n sourceId: sessionId,\n timestamp,\n },\n actors: [{ userId: context.userId, role: \"subject\" as const }],\n payload,\n strategy: strategies[i] ?? \"surface_missing_detail\",\n underspecificationType: underspecificationTypes[i] ?? null,\n conversationId: sessionId,\n }));\n\n let persisted: PersistedQuestion[];\n try {\n persisted = await host.persist(batch);\n } catch (err) {\n logger.error(\"Failed to persist chat questions\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return error(\"Could not deliver the questions to the user. Ask directly in your response text instead.\");\n }\n\n // ── 4. Stream the cards to the frontend ────────────────────────────\n emit({\n type: \"user_question\",\n questions: persisted.map((q) => ({\n id: q.id,\n title: q.payload.title,\n prompt: q.payload.prompt,\n options: q.payload.options,\n multiSelect: q.payload.multiSelect,\n })),\n });\n\n // ── 5. Block until answered / dismissed / timeout / abort ──────────\n const heartbeat = setInterval(() => {\n try {\n emit({ type: \"status\", message: \"Waiting for your answer…\" });\n } catch {\n /* stream may be closing; the wait resolves via timeout/abort */\n }\n }, WAIT_HEARTBEAT_MS);\n\n let outcomes: ChatQuestionAnswerOutcome[];\n try {\n outcomes = await host.awaitAnswers(\n persisted.map((q) => q.id),\n { timeoutMs: chatQuestionWaitTimeoutMs(), ...(signal ? { signal } : {}) },\n );\n } finally {\n clearInterval(heartbeat);\n }\n\n const byId = new Map(persisted.map((q) => [q.id, q]));\n const results = outcomes.map((o) => {\n const q = byId.get(o.questionId);\n return {\n questionId: o.questionId,\n prompt: q?.payload.prompt ?? \"\",\n status: o.status,\n ...(o.answer\n ? {\n selectedOptions: o.answer.selectedOptions,\n ...(o.answer.freeText ? { freeText: o.answer.freeText } : {}),\n }\n : {}),\n };\n });\n\n const answeredCount = results.filter((r) => r.status === \"answered\").length;\n const timedOut = results.some((r) => r.status === \"timeout\");\n\n return success({\n answers: results,\n summary: `${answeredCount} of ${results.length} question(s) answered`,\n ...(timedOut\n ? {\n guidance:\n \"The user has not answered the remaining question(s) yet. They stay visible in the conversation — acknowledge briefly, do NOT repeat the questions in text, and end your turn.\",\n }\n : {}),\n });\n },\n });\n\n return [askUserQuestion] as const;\n}\n\n/**\n * Load a compact excerpt of the most recent conversation messages for the\n * QuestionerAgent's grounding. Best-effort: returns \"\" on any failure or when\n * no chat session reader is available. Note: the in-flight user message is\n * not yet persisted; the orchestrator's `purpose` carries that context.\n */\nasync function loadConversationExcerpt(deps: ToolDeps, sessionId: string): Promise<string> {\n if (!deps.chatSession) return \"\";\n try {\n const messages = await deps.chatSession.getSessionMessages(sessionId, EXCERPT_FETCH_LIMIT);\n if (!messages || messages.length === 0) return \"\";\n return messages\n .slice(-EXCERPT_MESSAGE_COUNT)\n .map((m) => {\n const role = m.role === \"assistant\" ? \"Assistant\" : \"User\";\n const text = (m.content ?? \"\").replace(/\\s+/g, \" \").trim();\n return `${role}: ${text.slice(0, EXCERPT_MESSAGE_CHARS)}`;\n })\n .join(\"\\n\");\n } catch (err) {\n logger.warn(\"Failed to load conversation excerpt\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return \"\";\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;
|
|
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;AAsBzE,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;CAC3C;AAqYD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,gBAAgB,CAM9D"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SYSTEM_PROMPT as DISCOVERY_SYSTEM_PROMPT, buildQuestionPrompt as buildDiscoveryPrompt } from "../opportunity/question.prompt.js";
|
|
2
|
+
import { QUD_UNDERSPECIFICATION_RULES } from "./questioner.qud.js";
|
|
2
3
|
/**
|
|
3
4
|
* Shared rule block appended to every questioner system prompt. Enforces that
|
|
4
5
|
* the generated `prompt` resolves on its own — no demonstratives/anaphora that
|
|
@@ -334,29 +335,32 @@ function buildChatPrompt(ctx) {
|
|
|
334
335
|
* QuestionerAgent. `getPreset("pool_discovery")` therefore throws — the
|
|
335
336
|
* QuestionerQueue branches on the mode before invoking the agent.
|
|
336
337
|
*/
|
|
338
|
+
function withQudMetadataRules(systemPrompt) {
|
|
339
|
+
return `${systemPrompt}\n\n${QUD_UNDERSPECIFICATION_RULES}`;
|
|
340
|
+
}
|
|
337
341
|
const presets = {
|
|
338
342
|
discovery: {
|
|
339
|
-
systemPrompt: DISCOVERY_SYSTEM_PROMPT,
|
|
343
|
+
systemPrompt: withQudMetadataRules(DISCOVERY_SYSTEM_PROMPT),
|
|
340
344
|
buildPrompt: (context) => buildDiscoveryPrompt(context),
|
|
341
345
|
},
|
|
342
346
|
intent: {
|
|
343
|
-
systemPrompt: INTENT_SYSTEM_PROMPT,
|
|
347
|
+
systemPrompt: withQudMetadataRules(INTENT_SYSTEM_PROMPT),
|
|
344
348
|
buildPrompt: (context) => buildIntentPrompt(context),
|
|
345
349
|
},
|
|
346
350
|
enrichment: {
|
|
347
|
-
systemPrompt: PROFILE_SYSTEM_PROMPT,
|
|
351
|
+
systemPrompt: withQudMetadataRules(PROFILE_SYSTEM_PROMPT),
|
|
348
352
|
buildPrompt: (context) => buildProfilePrompt(context),
|
|
349
353
|
},
|
|
350
354
|
negotiation: {
|
|
351
|
-
systemPrompt: NEGOTIATION_SYSTEM_PROMPT,
|
|
355
|
+
systemPrompt: withQudMetadataRules(NEGOTIATION_SYSTEM_PROMPT),
|
|
352
356
|
buildPrompt: (context) => buildNegotiationPrompt(context),
|
|
353
357
|
},
|
|
354
358
|
negotiation_inflight: {
|
|
355
|
-
systemPrompt: NEGOTIATION_INFLIGHT_SYSTEM_PROMPT,
|
|
359
|
+
systemPrompt: withQudMetadataRules(NEGOTIATION_INFLIGHT_SYSTEM_PROMPT),
|
|
356
360
|
buildPrompt: (context) => buildNegotiationInflightPrompt(context),
|
|
357
361
|
},
|
|
358
362
|
chat: {
|
|
359
|
-
systemPrompt: CHAT_SYSTEM_PROMPT,
|
|
363
|
+
systemPrompt: withQudMetadataRules(CHAT_SYSTEM_PROMPT),
|
|
360
364
|
buildPrompt: (context) => buildChatPrompt(context),
|
|
361
365
|
},
|
|
362
366
|
};
|
|
@@ -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 { SYSTEM_PROMPT as DISCOVERY_SYSTEM_PROMPT, buildQuestionPrompt as buildDiscoveryPrompt } from \"../opportunity/question.prompt.js\";\n\nimport type { ChatContext, IntentContext, NegotiationContext, NegotiationInflightContext, ProfileContext } from \"./questioner.types.js\";\n\n/**\n * Shared rule block appended to every questioner system prompt. Enforces that\n * the generated `prompt` resolves on its own — no demonstratives/anaphora that\n * point at people, events, or prior turns the reader cannot see — and never\n * narrates Index's own matching pipeline. Closes the referential-leak class\n * surfaced in digest audits (\"…with these builders?\", \"the previous\n * negotiation stalled because the counterparty didn't mention …\").\n */\nconst REFERENTIAL_CLOSURE_RULES = `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 counterparty, 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 — 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: \"The previous negotiation stalled because the counterparty didn't mention 'matchmaking'. Should I broaden the search?\"\n- Good: \"Do you want to focus on dedicated matchmakers, or also people interested in relationships more broadly?\"`;\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/**\n * Renders the user-context block shared by every preset's user message from the\n * global user_context paragraph (the profile-replacing identity text).\n * @param userContext - The user's global context paragraph, if available.\n * @returns The trimmed context paragraph, or \"(no profile data)\" when empty.\n */\nfunction buildUserContextBlock(userContext?: string): string {\n const trimmed = userContext?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : \"(no profile data)\";\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\n${REFERENTIAL_CLOSURE_RULES}\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 profileBlock = buildUserContextBlock(ctx.userContext);\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\n${REFERENTIAL_CLOSURE_RULES}\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 profileBlock = buildUserContextBlock(ctx.userContext);\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 user's underlying goal or topic and the relevant community in the question text itself, in plain language drawn from their intent or profile — NOT the mechanics of the match attempt. 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 your search for AI infrastructure collaborators in the AI founders community, what kind of working relationship fits your immediate needs?\"\n\n${REFERENTIAL_CLOSURE_RULES}\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 profileBlock = buildUserContextBlock(ctx.userContext);\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\n// ─── Chat preset ─────────────────────────────────────────────────────────\n\nconst NEGOTIATION_INFLIGHT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user's own negotiator agent is MID-NEGOTIATION on their behalf and has paused: before continuing, it needs a decision or missing input from its client — most often permission to disclose a specific piece of information to the other side. The negotiation is WAITING until the user answers. Your job: turn the negotiator's stated need (and its draft question, when provided) into the minimum set of crisp, structured decision questions.\n\nBias toward disclosure gating. The most common question shape is \"may I share X with this person?\" — an enable/disable decision about revealing specific information. Phrase these as a clear yes/no choice: the first option authorizes sharing, the second declines. State in each option's description what the negotiator will DO next (share and continue, or continue without revealing it). When the need is a missing fact rather than a permission, ask for that concrete input instead.\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 input the negotiator needs to proceed (a fact, constraint, preference, or bound the client never stated).\n- reflective_summary: put a disclosure or stance decision in front of the client to confirm or decline — the enable/disable gate described above.\n\nHonor the negotiator's intent. When a draft question is provided, treat it as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions. Do not invent questions about topics the negotiator did not raise. When no draft is provided, derive the question strictly from the disclosure subject.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. The user may see this question hours later in an inbox, away from any negotiation view. Naturally include the disclosure subject and a concrete description of the other person (drawn from the counterparty hint — their attributes, e.g. \"a Berlin-based AI-infrastructure founder\") 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: \"Can I share your budget with them?\"\n- Good: \"May I share your budget range with a Berlin-based AI-infrastructure founder you're being matched with?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nException — describing the other side. Unlike other surfaces, this question is ABOUT a live counterparty, so you must reference them — do it by restating their concrete attributes from the counterparty hint (\"a fintech CTO exploring agent tooling\"), never as \"the counterparty\", \"them\", or \"this person\" without an attribute anchor in the same sentence, and never by implying a list or pipeline.\n\nCardinality. Default one question. Add a second ONLY when the negotiator's need genuinely spans two distinct decisions (e.g. one disclosure gate plus one missing fact). Never pad.\n\nOption construction. Each option must represent a meaningfully different outcome. For disclosure gates: authorize first, decline second; suffix the safer or more common path with \" (Recommended)\" and list it first when one clearly is. The description states the CONSEQUENCE for the negotiation — what the negotiator does next. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically, which also lets the user add nuance (\"share the range but not the exact figure\").\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Disclosure\", \"Budget\", \"Timing\", \"Intro\", \"Scope\", \"Contact\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I keep negotiating?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't broaden beyond the negotiator's stated disclosure subject or draft.\n- Don't reveal the counterparty's identity — attributes only.\n- Don't ask vague introspective questions.\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 or context shown already answers the negotiator's need, return \"questions\": [].`;\n\n/**\n * Build the user message for the negotiation-inflight preset from a NegotiationInflightContext.\n * @param ctx - The inflight context: disclosure subject, counterparty hint, optional draft, community, user context.\n * @returns The assembled user message string.\n */\nfunction buildNegotiationInflightPrompt(ctx: NegotiationInflightContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftBlock = ctx.draftQuestion?.trim()\n ? ctx.draftQuestion.trim()\n : \"(none — derive the question from the disclosure subject)\";\n\n return [\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Counterparty: ${ctx.counterpartyHint}`,\n \"\",\n \"## What the negotiator needs from its client\",\n ctx.disclosureSubject,\n \"\",\n \"## Draft question proposed by the negotiator\",\n draftBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the negotiator the permission or input it needs to continue.\",\n \"Honor the draft when provided; refine its wording and options rather than replacing its topic.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\nconst CHAT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The protocol's chat orchestrator is mid-conversation with the user and has decided it needs a decision or missing input from them before it can continue. The conversation is PAUSED until the user answers. Your job: turn the orchestrator's stated need (and any draft questions it proposed) into the minimum set of crisp, structured decision questions.\n\nUnlike other question surfaces, these questions render INLINE in the active conversation, immediately after the assistant's last message — the user has full conversational context. Still keep each prompt self-contained enough to make sense on its own line.\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 input the orchestrator needs to proceed (scope, timing, budget, format, preference, constraint, …).\n- refine_intent: ask the user to choose a direction when the orchestrator faces meaningfully different paths forward.\n\nHonor the orchestrator's intent. When draft questions are provided, treat them as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions, and drop redundant drafts. Do not invent questions about topics the orchestrator did not raise. When no drafts are provided, derive questions strictly from the stated purpose.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the conversation excerpt or user profile shown.\n2. The answer materially changes what the orchestrator does next.\n3. The question targets a different decision domain from any other question in this batch.\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Emit a second or third ONLY when the orchestrator's purpose or drafts genuinely require separate decisions in distinct domains. Never pad.\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 for what happens next in the conversation, 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: \"Direction\", \"Scope\", \"Timing\", \"Budget\", \"Format\", \"Priority\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I continue?\", \"Is that OK?\").\n- Don't re-ask for facts visible in the conversation excerpt or user profile.\n- Don't broaden beyond the orchestrator's stated purpose.\n- Don't ask vague introspective questions.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the purpose is already answerable from the context shown, return \"questions\": [].`;\n\n/**\n * Build the user message for the chat preset from a ChatContext.\n * @param ctx - The chat context: orchestrator purpose, optional drafts, conversation excerpt, user context.\n * @returns The assembled user message string.\n */\nfunction buildChatPrompt(ctx: ChatContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftsBlock =\n ctx.draftQuestions && ctx.draftQuestions.length > 0\n ? ctx.draftQuestions\n .map((d, i) => {\n const opts = d.options && d.options.length > 0 ? ` [options: ${d.options.join(\" | \")}]` : \"\";\n const multi = d.multiSelect ? \" [multi-select]\" : \"\";\n return `${i + 1}. ${d.prompt}${opts}${multi}`;\n })\n .join(\"\\n\")\n : \"(none — derive questions from the purpose)\";\n\n const excerptBlock = ctx.conversationExcerpt?.trim()\n ? ctx.conversationExcerpt.trim()\n : \"(not available)\";\n\n return [\n \"## What the orchestrator needs to learn\",\n ctx.purpose,\n \"\",\n \"## Draft questions proposed by the orchestrator\",\n draftsBlock,\n \"\",\n \"## Recent conversation excerpt\",\n excerptBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the orchestrator the decision or input it needs.\",\n \"Honor the drafts when provided; refine their wording and options rather than replacing their topics.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\n/**\n * pool_discovery has NO preset by design: those questions are synthesized\n * deterministically from mined discriminators (see\n * `opportunity/discriminator/discriminator.question.ts`) and never reach the\n * QuestionerAgent. `getPreset(\"pool_discovery\")` therefore throws — the\n * QuestionerQueue branches on the mode before invoking the agent.\n */\nconst presets: Partial<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 enrichment: {\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 negotiation_inflight: {\n systemPrompt: NEGOTIATION_INFLIGHT_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildNegotiationInflightPrompt(context as NegotiationInflightContext),\n },\n chat: {\n systemPrompt: CHAT_SYSTEM_PROMPT,\n buildPrompt: (context: unknown) => buildChatPrompt(context as ChatContext),\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 { SYSTEM_PROMPT as DISCOVERY_SYSTEM_PROMPT, buildQuestionPrompt as buildDiscoveryPrompt } from \"../opportunity/question.prompt.js\";\n\nimport { QUD_UNDERSPECIFICATION_RULES } from \"./questioner.qud.js\";\nimport type { ChatContext, IntentContext, NegotiationContext, NegotiationInflightContext, ProfileContext } from \"./questioner.types.js\";\n\n/**\n * Shared rule block appended to every questioner system prompt. Enforces that\n * the generated `prompt` resolves on its own — no demonstratives/anaphora that\n * point at people, events, or prior turns the reader cannot see — and never\n * narrates Index's own matching pipeline. Closes the referential-leak class\n * surfaced in digest audits (\"…with these builders?\", \"the previous\n * negotiation stalled because the counterparty didn't mention …\").\n */\nconst REFERENTIAL_CLOSURE_RULES = `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 counterparty, 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 — 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: \"The previous negotiation stalled because the counterparty didn't mention 'matchmaking'. Should I broaden the search?\"\n- Good: \"Do you want to focus on dedicated matchmakers, or also people interested in relationships more broadly?\"`;\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/**\n * Renders the user-context block shared by every preset's user message from the\n * global user_context paragraph (the profile-replacing identity text).\n * @param userContext - The user's global context paragraph, if available.\n * @returns The trimmed context paragraph, or \"(no profile data)\" when empty.\n */\nfunction buildUserContextBlock(userContext?: string): string {\n const trimmed = userContext?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : \"(no profile data)\";\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\n${REFERENTIAL_CLOSURE_RULES}\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 profileBlock = buildUserContextBlock(ctx.userContext);\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\n${REFERENTIAL_CLOSURE_RULES}\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 profileBlock = buildUserContextBlock(ctx.userContext);\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 user's underlying goal or topic and the relevant community in the question text itself, in plain language drawn from their intent or profile — NOT the mechanics of the match attempt. 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 your search for AI infrastructure collaborators in the AI founders community, what kind of working relationship fits your immediate needs?\"\n\n${REFERENTIAL_CLOSURE_RULES}\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 profileBlock = buildUserContextBlock(ctx.userContext);\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\n// ─── Chat preset ─────────────────────────────────────────────────────────\n\nconst NEGOTIATION_INFLIGHT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user's own negotiator agent is MID-NEGOTIATION on their behalf and has paused: before continuing, it needs a decision or missing input from its client — most often permission to disclose a specific piece of information to the other side. The negotiation is WAITING until the user answers. Your job: turn the negotiator's stated need (and its draft question, when provided) into the minimum set of crisp, structured decision questions.\n\nBias toward disclosure gating. The most common question shape is \"may I share X with this person?\" — an enable/disable decision about revealing specific information. Phrase these as a clear yes/no choice: the first option authorizes sharing, the second declines. State in each option's description what the negotiator will DO next (share and continue, or continue without revealing it). When the need is a missing fact rather than a permission, ask for that concrete input instead.\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 input the negotiator needs to proceed (a fact, constraint, preference, or bound the client never stated).\n- reflective_summary: put a disclosure or stance decision in front of the client to confirm or decline — the enable/disable gate described above.\n\nHonor the negotiator's intent. When a draft question is provided, treat it as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions. Do not invent questions about topics the negotiator did not raise. When no draft is provided, derive the question strictly from the disclosure subject.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. The user may see this question hours later in an inbox, away from any negotiation view. Naturally include the disclosure subject and a concrete description of the other person (drawn from the counterparty hint — their attributes, e.g. \"a Berlin-based AI-infrastructure founder\") 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: \"Can I share your budget with them?\"\n- Good: \"May I share your budget range with a Berlin-based AI-infrastructure founder you're being matched with?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nException — describing the other side. Unlike other surfaces, this question is ABOUT a live counterparty, so you must reference them — do it by restating their concrete attributes from the counterparty hint (\"a fintech CTO exploring agent tooling\"), never as \"the counterparty\", \"them\", or \"this person\" without an attribute anchor in the same sentence, and never by implying a list or pipeline.\n\nCardinality. Default one question. Add a second ONLY when the negotiator's need genuinely spans two distinct decisions (e.g. one disclosure gate plus one missing fact). Never pad.\n\nOption construction. Each option must represent a meaningfully different outcome. For disclosure gates: authorize first, decline second; suffix the safer or more common path with \" (Recommended)\" and list it first when one clearly is. The description states the CONSEQUENCE for the negotiation — what the negotiator does next. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically, which also lets the user add nuance (\"share the range but not the exact figure\").\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Disclosure\", \"Budget\", \"Timing\", \"Intro\", \"Scope\", \"Contact\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I keep negotiating?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't broaden beyond the negotiator's stated disclosure subject or draft.\n- Don't reveal the counterparty's identity — attributes only.\n- Don't ask vague introspective questions.\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 or context shown already answers the negotiator's need, return \"questions\": [].`;\n\n/**\n * Build the user message for the negotiation-inflight preset from a NegotiationInflightContext.\n * @param ctx - The inflight context: disclosure subject, counterparty hint, optional draft, community, user context.\n * @returns The assembled user message string.\n */\nfunction buildNegotiationInflightPrompt(ctx: NegotiationInflightContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftBlock = ctx.draftQuestion?.trim()\n ? ctx.draftQuestion.trim()\n : \"(none — derive the question from the disclosure subject)\";\n\n return [\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Counterparty: ${ctx.counterpartyHint}`,\n \"\",\n \"## What the negotiator needs from its client\",\n ctx.disclosureSubject,\n \"\",\n \"## Draft question proposed by the negotiator\",\n draftBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the negotiator the permission or input it needs to continue.\",\n \"Honor the draft when provided; refine its wording and options rather than replacing its topic.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\nconst CHAT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The protocol's chat orchestrator is mid-conversation with the user and has decided it needs a decision or missing input from them before it can continue. The conversation is PAUSED until the user answers. Your job: turn the orchestrator's stated need (and any draft questions it proposed) into the minimum set of crisp, structured decision questions.\n\nUnlike other question surfaces, these questions render INLINE in the active conversation, immediately after the assistant's last message — the user has full conversational context. Still keep each prompt self-contained enough to make sense on its own line.\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 input the orchestrator needs to proceed (scope, timing, budget, format, preference, constraint, …).\n- refine_intent: ask the user to choose a direction when the orchestrator faces meaningfully different paths forward.\n\nHonor the orchestrator's intent. When draft questions are provided, treat them as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions, and drop redundant drafts. Do not invent questions about topics the orchestrator did not raise. When no drafts are provided, derive questions strictly from the stated purpose.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the conversation excerpt or user profile shown.\n2. The answer materially changes what the orchestrator does next.\n3. The question targets a different decision domain from any other question in this batch.\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Emit a second or third ONLY when the orchestrator's purpose or drafts genuinely require separate decisions in distinct domains. Never pad.\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 for what happens next in the conversation, 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: \"Direction\", \"Scope\", \"Timing\", \"Budget\", \"Format\", \"Priority\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I continue?\", \"Is that OK?\").\n- Don't re-ask for facts visible in the conversation excerpt or user profile.\n- Don't broaden beyond the orchestrator's stated purpose.\n- Don't ask vague introspective questions.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the purpose is already answerable from the context shown, return \"questions\": [].`;\n\n/**\n * Build the user message for the chat preset from a ChatContext.\n * @param ctx - The chat context: orchestrator purpose, optional drafts, conversation excerpt, user context.\n * @returns The assembled user message string.\n */\nfunction buildChatPrompt(ctx: ChatContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftsBlock =\n ctx.draftQuestions && ctx.draftQuestions.length > 0\n ? ctx.draftQuestions\n .map((d, i) => {\n const opts = d.options && d.options.length > 0 ? ` [options: ${d.options.join(\" | \")}]` : \"\";\n const multi = d.multiSelect ? \" [multi-select]\" : \"\";\n return `${i + 1}. ${d.prompt}${opts}${multi}`;\n })\n .join(\"\\n\")\n : \"(none — derive questions from the purpose)\";\n\n const excerptBlock = ctx.conversationExcerpt?.trim()\n ? ctx.conversationExcerpt.trim()\n : \"(not available)\";\n\n return [\n \"## What the orchestrator needs to learn\",\n ctx.purpose,\n \"\",\n \"## Draft questions proposed by the orchestrator\",\n draftsBlock,\n \"\",\n \"## Recent conversation excerpt\",\n excerptBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the orchestrator the decision or input it needs.\",\n \"Honor the drafts when provided; refine their wording and options rather than replacing their topics.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\n/**\n * pool_discovery has NO preset by design: those questions are synthesized\n * deterministically from mined discriminators (see\n * `opportunity/discriminator/discriminator.question.ts`) and never reach the\n * QuestionerAgent. `getPreset(\"pool_discovery\")` therefore throws — the\n * QuestionerQueue branches on the mode before invoking the agent.\n */\nfunction withQudMetadataRules(systemPrompt: string): string {\n return `${systemPrompt}\\n\\n${QUD_UNDERSPECIFICATION_RULES}`;\n}\n\nconst presets: Partial<Record<QuestionMode, QuestionerPreset>> = {\n discovery: {\n systemPrompt: withQudMetadataRules(DISCOVERY_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) =>\n buildDiscoveryPrompt(context as Parameters<typeof buildDiscoveryPrompt>[0]),\n },\n intent: {\n systemPrompt: withQudMetadataRules(INTENT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildIntentPrompt(context as IntentContext),\n },\n enrichment: {\n systemPrompt: withQudMetadataRules(PROFILE_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildProfilePrompt(context as ProfileContext),\n },\n negotiation: {\n systemPrompt: withQudMetadataRules(NEGOTIATION_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildNegotiationPrompt(context as NegotiationContext),\n },\n negotiation_inflight: {\n systemPrompt: withQudMetadataRules(NEGOTIATION_INFLIGHT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildNegotiationInflightPrompt(context as NegotiationInflightContext),\n },\n chat: {\n systemPrompt: withQudMetadataRules(CHAT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildChatPrompt(context as ChatContext),\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"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Questions Under Discussion (QUD) taxonomy contract for structured
|
|
3
|
+
* question-generation prompts. Every Questioner mode uses this block because
|
|
4
|
+
* the structured output schema requires the internal metadata field; intent
|
|
5
|
+
* and discovery are the primary consumers of non-null classifications.
|
|
6
|
+
*/
|
|
7
|
+
export declare const QUD_UNDERSPECIFICATION_RULES = "QUD underspecification taxonomy. For every structured question, emit a required `underspecificationType` field. Use exactly one category only when the question repairs that kind of underspecification:\n- missing_constituent: an absent core participant, entity, or outcome (who/what).\n- missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).\n- open_alternative_set: an unresolved choice among materially different interpretations or scopes.\nUse null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: `strategy` describes the conversational move; `underspecificationType` describes the QUD defect repaired. Never infer one mechanically from the other.";
|
|
8
|
+
//# sourceMappingURL=questioner.qud.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questioner.qud.d.ts","sourceRoot":"/","sources":["questioner/questioner.qud.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,yyBAImR,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Questions Under Discussion (QUD) taxonomy contract for structured
|
|
3
|
+
* question-generation prompts. Every Questioner mode uses this block because
|
|
4
|
+
* the structured output schema requires the internal metadata field; intent
|
|
5
|
+
* and discovery are the primary consumers of non-null classifications.
|
|
6
|
+
*/
|
|
7
|
+
export const QUD_UNDERSPECIFICATION_RULES = `QUD underspecification taxonomy. For every structured question, emit a required \`underspecificationType\` field. Use exactly one category only when the question repairs that kind of underspecification:
|
|
8
|
+
- missing_constituent: an absent core participant, entity, or outcome (who/what).
|
|
9
|
+
- missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).
|
|
10
|
+
- open_alternative_set: an unresolved choice among materially different interpretations or scopes.
|
|
11
|
+
Use null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: \`strategy\` describes the conversational move; \`underspecificationType\` describes the QUD defect repaired. Never infer one mechanically from the other.`;
|
|
12
|
+
//# sourceMappingURL=questioner.qud.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questioner.qud.js","sourceRoot":"/","sources":["questioner/questioner.qud.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;;;;4TAIgR,CAAC","sourcesContent":["/**\n * Shared Questions Under Discussion (QUD) taxonomy contract for structured\n * question-generation prompts. Every Questioner mode uses this block because\n * the structured output schema requires the internal metadata field; intent\n * and discovery are the primary consumers of non-null classifications.\n */\nexport const QUD_UNDERSPECIFICATION_RULES = `QUD underspecification taxonomy. For every structured question, emit a required \\`underspecificationType\\` field. Use exactly one category only when the question repairs that kind of underspecification:\n- missing_constituent: an absent core participant, entity, or outcome (who/what).\n- missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).\n- open_alternative_set: an unresolved choice among materially different interpretations or scopes.\nUse null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: \\`strategy\\` describes the conversational move; \\`underspecificationType\\` describes the QUD defect repaired. Never infer one mechanically from the other.`;\n"]}
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
* the QuestionerAgent. Implementations live in the backend and are injected
|
|
4
4
|
* into ProtocolDeps.
|
|
5
5
|
*/
|
|
6
|
-
import type { Question, QuestionMode, QuestionStrategy, QuestionDetection, QuestionActor, QuestionAnswer } from "../schemas/question.schema.js";
|
|
6
|
+
import type { Question, QuestionMode, QuestionStrategy, QuestionDetection, QuestionActor, QuestionAnswer, UnderspecificationType } from "../schemas/question.schema.js";
|
|
7
7
|
/** Shape accepted by `persist()` — everything needed to insert a question row. */
|
|
8
8
|
export interface PersistableQuestion {
|
|
9
9
|
detection: QuestionDetection;
|
|
10
10
|
actors: QuestionActor[];
|
|
11
11
|
payload: Question;
|
|
12
12
|
strategy: QuestionStrategy;
|
|
13
|
+
/** Internal QUD repair category; null when the question repairs no underspecification. */
|
|
14
|
+
underspecificationType?: UnderspecificationType | null;
|
|
13
15
|
/** Conversation ID — set when the question originates from a chat session. */
|
|
14
16
|
conversationId?: string;
|
|
15
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.interface.d.ts","sourceRoot":"/","sources":["shared/interfaces/questioner.interface.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"questioner.interface.d.ts","sourceRoot":"/","sources":["shared/interfaces/questioner.interface.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAExK,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,EAAE,QAAQ,CAAC;IAClB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,0FAA0F;IAC1F,sBAAsB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACvD,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,0FAA0F;AAC1F,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,iBAAiB,CAAC;IAC7B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IAC7C,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0GAA0G;IAC1G,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;IAC7C,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACpE,YAAY,CACV,WAAW,EAAE,MAAM,EAAE,EACrB,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAClD,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IACjC;iDAC6C;IAC7C,OAAO,CAAC,SAAS,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE7D,6EAA6E;IAC7E,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAErF;;0FAEsF;IACtF,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErF;;0FAEsF;IACtF,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.interface.js","sourceRoot":"/","sources":["shared/interfaces/questioner.interface.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Protocol-level persistence contract for structured questions generated by\n * the QuestionerAgent. Implementations live in the backend and are injected\n * into ProtocolDeps.\n */\nimport type { Question, QuestionMode, QuestionStrategy, QuestionDetection, QuestionActor, QuestionAnswer } from \"../schemas/question.schema.js\";\n\n/** Shape accepted by `persist()` — everything needed to insert a question row. */\nexport interface PersistableQuestion {\n detection: QuestionDetection;\n actors: QuestionActor[];\n payload: Question;\n strategy: QuestionStrategy;\n /** Conversation ID — set when the question originates from a chat session. */\n conversationId?: string;\n}\n\n/** Shape returned by `findPending()` — a persisted question with its DB id and status. */\nexport interface PersistedQuestion {\n id: string;\n detection: QuestionDetection;\n actors: QuestionActor[];\n payload: Question;\n status: \"pending\" | \"answered\" | \"dismissed\";\n answer: QuestionAnswer | null;\n createdAt: string;\n}\n\n/** Optional filters for `findPending()`. */\nexport interface QuestionFilters {\n mode?: QuestionMode;\n sourceType?: string;\n sourceId?: string;\n /** Optional selected-intent scope. When `scopeType === 'intent'`, `scopeId` is the selected intent id. */\n scopeType?: 'intent';\n scopeId?: string;\n}\n\n/**\n * Resolution outcome for a single awaited chat question.\n * `timeout` means the wait budget elapsed (or the run was aborted) before the\n * user responded — the question stays `pending` in the database.\n */\nexport interface ChatQuestionAnswerOutcome {\n questionId: string;\n status: \"answered\" | \"dismissed\" | \"timeout\";\n answer?: QuestionAnswer;\n}\n\n/**\n * Host bridge for the orchestrator's blocking `ask_user_question` tool.\n * `persist` synchronously inserts chat-mode question rows; `awaitAnswers`\n * blocks until every question resolves (answer/dismiss via the questions\n * REST endpoints) or the wait times out / the run is aborted.\n *\n * Implementations live in the backend (in-memory per-question wait bus,\n * single-instance semantics like the chat steer/queue interrupt emitter).\n */\nexport interface ChatQuestionsHost {\n persist(batch: PersistableQuestion[]): Promise<PersistedQuestion[]>;\n awaitAnswers(\n questionIds: string[],\n opts?: { timeoutMs?: number; signal?: AbortSignal },\n ): Promise<ChatQuestionAnswerOutcome[]>;\n}\n\nexport interface QuestionerDatabase {\n /** Persist a batch of generated questions (up to 3 per generation).\n * @returns The IDs of the inserted rows. */\n persist(questions: PersistableQuestion[]): Promise<string[]>;\n\n /** Find pending questions for a user, optionally filtered by mode/source. */\n findPending(userId: string, filters?: QuestionFilters): Promise<PersistedQuestion[]>;\n\n /** Record an answer for a question. Sets status to \"answered\".\n * Only succeeds if the user is an actor on a pending question.\n * @returns `true` if updated, `false` if not found, not pending, or unauthorized. */\n answer(questionId: string, userId: string, answer: QuestionAnswer): Promise<boolean>;\n\n /** Dismiss a question. Sets status to \"dismissed\".\n * Only succeeds if the user is an actor on a pending question.\n * @returns `true` if updated, `false` if not found, not pending, or unauthorized. */\n dismiss(questionId: string, userId: string): Promise<boolean>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"questioner.interface.js","sourceRoot":"/","sources":["shared/interfaces/questioner.interface.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Protocol-level persistence contract for structured questions generated by\n * the QuestionerAgent. Implementations live in the backend and are injected\n * into ProtocolDeps.\n */\nimport type { Question, QuestionMode, QuestionStrategy, QuestionDetection, QuestionActor, QuestionAnswer, UnderspecificationType } from \"../schemas/question.schema.js\";\n\n/** Shape accepted by `persist()` — everything needed to insert a question row. */\nexport interface PersistableQuestion {\n detection: QuestionDetection;\n actors: QuestionActor[];\n payload: Question;\n strategy: QuestionStrategy;\n /** Internal QUD repair category; null when the question repairs no underspecification. */\n underspecificationType?: UnderspecificationType | null;\n /** Conversation ID — set when the question originates from a chat session. */\n conversationId?: string;\n}\n\n/** Shape returned by `findPending()` — a persisted question with its DB id and status. */\nexport interface PersistedQuestion {\n id: string;\n detection: QuestionDetection;\n actors: QuestionActor[];\n payload: Question;\n status: \"pending\" | \"answered\" | \"dismissed\";\n answer: QuestionAnswer | null;\n createdAt: string;\n}\n\n/** Optional filters for `findPending()`. */\nexport interface QuestionFilters {\n mode?: QuestionMode;\n sourceType?: string;\n sourceId?: string;\n /** Optional selected-intent scope. When `scopeType === 'intent'`, `scopeId` is the selected intent id. */\n scopeType?: 'intent';\n scopeId?: string;\n}\n\n/**\n * Resolution outcome for a single awaited chat question.\n * `timeout` means the wait budget elapsed (or the run was aborted) before the\n * user responded — the question stays `pending` in the database.\n */\nexport interface ChatQuestionAnswerOutcome {\n questionId: string;\n status: \"answered\" | \"dismissed\" | \"timeout\";\n answer?: QuestionAnswer;\n}\n\n/**\n * Host bridge for the orchestrator's blocking `ask_user_question` tool.\n * `persist` synchronously inserts chat-mode question rows; `awaitAnswers`\n * blocks until every question resolves (answer/dismiss via the questions\n * REST endpoints) or the wait times out / the run is aborted.\n *\n * Implementations live in the backend (in-memory per-question wait bus,\n * single-instance semantics like the chat steer/queue interrupt emitter).\n */\nexport interface ChatQuestionsHost {\n persist(batch: PersistableQuestion[]): Promise<PersistedQuestion[]>;\n awaitAnswers(\n questionIds: string[],\n opts?: { timeoutMs?: number; signal?: AbortSignal },\n ): Promise<ChatQuestionAnswerOutcome[]>;\n}\n\nexport interface QuestionerDatabase {\n /** Persist a batch of generated questions (up to 3 per generation).\n * @returns The IDs of the inserted rows. */\n persist(questions: PersistableQuestion[]): Promise<string[]>;\n\n /** Find pending questions for a user, optionally filtered by mode/source. */\n findPending(userId: string, filters?: QuestionFilters): Promise<PersistedQuestion[]>;\n\n /** Record an answer for a question. Sets status to \"answered\".\n * Only succeeds if the user is an actor on a pending question.\n * @returns `true` if updated, `false` if not found, not pending, or unauthorized. */\n answer(questionId: string, userId: string, answer: QuestionAnswer): Promise<boolean>;\n\n /** Dismiss a question. Sets status to \"dismissed\".\n * Only succeeds if the user is an actor on a pending question.\n * @returns `true` if updated, `false` if not found, not pending, or unauthorized. */\n dismiss(questionId: string, userId: string): Promise<boolean>;\n}\n"]}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* elicitation dispatch. Mirrors the brainstorming AskUserQuestion skill so a
|
|
4
4
|
* Question can be rendered identically across surfaces.
|
|
5
5
|
*
|
|
6
|
-
* `QuestionWithStrategy` extends the public shape with
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* generator — users never see
|
|
6
|
+
* `QuestionWithStrategy` extends the public shape with internal `strategy`
|
|
7
|
+
* and QUD underspecification tags used by generator guardrails and persisted
|
|
8
|
+
* metadata. Both tags are stripped before the public payload leaves the
|
|
9
|
+
* generator — users never see them.
|
|
10
10
|
*/
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
export declare const QuestionOptionSchema: z.ZodObject<{
|
|
@@ -66,6 +66,8 @@ export declare const QuestionSchema: z.ZodObject<{
|
|
|
66
66
|
multiSelect: boolean;
|
|
67
67
|
evidence?: string | undefined;
|
|
68
68
|
}>;
|
|
69
|
+
/** Canonical QUD repair categories for underspecified intents/questions. */
|
|
70
|
+
export declare const UnderspecificationTypeSchema: z.ZodEnum<["missing_constituent", "missing_constraint", "open_alternative_set"]>;
|
|
69
71
|
export declare const QuestionStrategySchema: z.ZodEnum<["refine_intent", "surface_missing_detail", "open_adjacent_thread", "reflective_summary", "surface_emergent_knowledge"]>;
|
|
70
72
|
export declare const QuestionWithStrategySchema: z.ZodObject<{
|
|
71
73
|
/** ≤12 chars. Noun of the decision domain — e.g. "Stage", "Timing", "Role". */
|
|
@@ -95,6 +97,8 @@ export declare const QuestionWithStrategySchema: z.ZodObject<{
|
|
|
95
97
|
evidence: z.ZodOptional<z.ZodString>;
|
|
96
98
|
} & {
|
|
97
99
|
strategy: z.ZodEnum<["refine_intent", "surface_missing_detail", "open_adjacent_thread", "reflective_summary", "surface_emergent_knowledge"]>;
|
|
100
|
+
/** QUD repair category, or null when the question is not an underspecification repair. */
|
|
101
|
+
underspecificationType: z.ZodNullable<z.ZodEnum<["missing_constituent", "missing_constraint", "open_alternative_set"]>>;
|
|
98
102
|
}, "strip", z.ZodTypeAny, {
|
|
99
103
|
options: {
|
|
100
104
|
description: string;
|
|
@@ -104,6 +108,7 @@ export declare const QuestionWithStrategySchema: z.ZodObject<{
|
|
|
104
108
|
title: string;
|
|
105
109
|
multiSelect: boolean;
|
|
106
110
|
strategy: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge";
|
|
111
|
+
underspecificationType: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null;
|
|
107
112
|
evidence?: string | undefined;
|
|
108
113
|
}, {
|
|
109
114
|
options: {
|
|
@@ -114,6 +119,7 @@ export declare const QuestionWithStrategySchema: z.ZodObject<{
|
|
|
114
119
|
title: string;
|
|
115
120
|
multiSelect: boolean;
|
|
116
121
|
strategy: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge";
|
|
122
|
+
underspecificationType: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null;
|
|
117
123
|
evidence?: string | undefined;
|
|
118
124
|
}>;
|
|
119
125
|
export declare const QuestionGeneratorResponseSchema: z.ZodObject<{
|
|
@@ -145,6 +151,8 @@ export declare const QuestionGeneratorResponseSchema: z.ZodObject<{
|
|
|
145
151
|
evidence: z.ZodOptional<z.ZodString>;
|
|
146
152
|
} & {
|
|
147
153
|
strategy: z.ZodEnum<["refine_intent", "surface_missing_detail", "open_adjacent_thread", "reflective_summary", "surface_emergent_knowledge"]>;
|
|
154
|
+
/** QUD repair category, or null when the question is not an underspecification repair. */
|
|
155
|
+
underspecificationType: z.ZodNullable<z.ZodEnum<["missing_constituent", "missing_constraint", "open_alternative_set"]>>;
|
|
148
156
|
}, "strip", z.ZodTypeAny, {
|
|
149
157
|
options: {
|
|
150
158
|
description: string;
|
|
@@ -154,6 +162,7 @@ export declare const QuestionGeneratorResponseSchema: z.ZodObject<{
|
|
|
154
162
|
title: string;
|
|
155
163
|
multiSelect: boolean;
|
|
156
164
|
strategy: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge";
|
|
165
|
+
underspecificationType: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null;
|
|
157
166
|
evidence?: string | undefined;
|
|
158
167
|
}, {
|
|
159
168
|
options: {
|
|
@@ -164,6 +173,7 @@ export declare const QuestionGeneratorResponseSchema: z.ZodObject<{
|
|
|
164
173
|
title: string;
|
|
165
174
|
multiSelect: boolean;
|
|
166
175
|
strategy: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge";
|
|
176
|
+
underspecificationType: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null;
|
|
167
177
|
evidence?: string | undefined;
|
|
168
178
|
}>, "many">;
|
|
169
179
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -176,6 +186,7 @@ export declare const QuestionGeneratorResponseSchema: z.ZodObject<{
|
|
|
176
186
|
title: string;
|
|
177
187
|
multiSelect: boolean;
|
|
178
188
|
strategy: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge";
|
|
189
|
+
underspecificationType: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null;
|
|
179
190
|
evidence?: string | undefined;
|
|
180
191
|
}[];
|
|
181
192
|
}, {
|
|
@@ -188,22 +199,25 @@ export declare const QuestionGeneratorResponseSchema: z.ZodObject<{
|
|
|
188
199
|
title: string;
|
|
189
200
|
multiSelect: boolean;
|
|
190
201
|
strategy: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge";
|
|
202
|
+
underspecificationType: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null;
|
|
191
203
|
evidence?: string | undefined;
|
|
192
204
|
}[];
|
|
193
205
|
}>;
|
|
194
206
|
export type QuestionOption = z.infer<typeof QuestionOptionSchema>;
|
|
195
207
|
export type Question = z.infer<typeof QuestionSchema>;
|
|
208
|
+
export type UnderspecificationType = z.infer<typeof UnderspecificationTypeSchema>;
|
|
196
209
|
export type QuestionStrategy = z.infer<typeof QuestionStrategySchema>;
|
|
197
210
|
export type QuestionWithStrategy = z.infer<typeof QuestionWithStrategySchema>;
|
|
198
211
|
export type QuestionGeneratorResponse = z.infer<typeof QuestionGeneratorResponseSchema>;
|
|
199
212
|
/**
|
|
200
|
-
* Internal generator output: public questions plus
|
|
201
|
-
*
|
|
202
|
-
* forward `questions` to renderers
|
|
213
|
+
* Internal generator output: public questions plus parallel strategy and QUD
|
|
214
|
+
* taxonomy arrays for metadata-only consumption. The generator emits this;
|
|
215
|
+
* callers forward only `questions` to renderers.
|
|
203
216
|
*/
|
|
204
217
|
export interface QuestionGenerationResult {
|
|
205
218
|
questions: Question[];
|
|
206
219
|
strategies: QuestionStrategy[];
|
|
220
|
+
underspecificationTypes: Array<UnderspecificationType | null>;
|
|
207
221
|
}
|
|
208
222
|
export declare const QuestionModeSchema: z.ZodEnum<["discovery", "intent", "enrichment", "negotiation", "negotiation_inflight", "chat", "pool_discovery"]>;
|
|
209
223
|
/** One server-side candidate→side assignment (never serialized to clients). */
|
|
@@ -430,6 +444,10 @@ export declare const QuestionDetectionSchema: z.ZodObject<{
|
|
|
430
444
|
triggeredBy: z.ZodOptional<z.ZodString>;
|
|
431
445
|
/** ISO-8601 timestamp of generation. */
|
|
432
446
|
timestamp: z.ZodString;
|
|
447
|
+
/** Generation strategy persisted as internal metadata. */
|
|
448
|
+
strategy: z.ZodOptional<z.ZodEnum<["refine_intent", "surface_missing_detail", "open_adjacent_thread", "reflective_summary", "surface_emergent_knowledge"]>>;
|
|
449
|
+
/** QUD repair category persisted as internal metadata. */
|
|
450
|
+
underspecificationType: z.ZodOptional<z.ZodNullable<z.ZodEnum<["missing_constituent", "missing_constraint", "open_alternative_set"]>>>;
|
|
433
451
|
/** ID of the assistant message that triggered this question. Used by the frontend to anchor the question card inline. */
|
|
434
452
|
messageId: z.ZodOptional<z.ZodString>;
|
|
435
453
|
/**
|
|
@@ -594,6 +612,8 @@ export declare const QuestionDetectionSchema: z.ZodObject<{
|
|
|
594
612
|
sourceType: string;
|
|
595
613
|
sourceId: string;
|
|
596
614
|
timestamp: string;
|
|
615
|
+
strategy?: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge" | undefined;
|
|
616
|
+
underspecificationType?: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null | undefined;
|
|
597
617
|
triggeredBy?: string | undefined;
|
|
598
618
|
messageId?: string | undefined;
|
|
599
619
|
pool?: {
|
|
@@ -631,6 +651,8 @@ export declare const QuestionDetectionSchema: z.ZodObject<{
|
|
|
631
651
|
sourceType: string;
|
|
632
652
|
sourceId: string;
|
|
633
653
|
timestamp: string;
|
|
654
|
+
strategy?: "refine_intent" | "surface_missing_detail" | "open_adjacent_thread" | "reflective_summary" | "surface_emergent_knowledge" | undefined;
|
|
655
|
+
underspecificationType?: "missing_constituent" | "missing_constraint" | "open_alternative_set" | null | undefined;
|
|
634
656
|
triggeredBy?: string | undefined;
|
|
635
657
|
messageId?: string | undefined;
|
|
636
658
|
pool?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.schema.d.ts","sourceRoot":"/","sources":["shared/schemas/question.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,oBAAoB;IAC/B,+EAA+E;;IAE/E,iFAAiF;;;;;;;;EAEjF,CAAC;AAEH,eAAO,MAAM,cAAc;IACzB,+EAA+E;;IAE/E,yDAAyD;;IAEzD,6EAA6E;;QAX7E,+EAA+E;;QAE/E,iFAAiF;;;;;;;;;IAWjF,0EAA0E;;IAE1E;;;;OAIG;;;;;;;;;;;;;;;;;;;;EAEH,CAAC;AAEH,eAAO,MAAM,sBAAsB,oIAMjC,CAAC;AAEH,eAAO,MAAM,0BAA0B;
|
|
1
|
+
{"version":3,"file":"question.schema.d.ts","sourceRoot":"/","sources":["shared/schemas/question.schema.ts"],"names":[],"mappings":"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"}
|