@indexnetwork/protocol 4.5.0-rc.329.1 → 4.5.0-rc.331.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat/negotiator.persona.d.ts +1 -1
- package/dist/chat/negotiator.persona.d.ts.map +1 -1
- package/dist/chat/negotiator.persona.js +7 -0
- package/dist/chat/negotiator.persona.js.map +1 -1
- package/dist/chat/negotiator.prompt.d.ts +7 -0
- package/dist/chat/negotiator.prompt.d.ts.map +1 -1
- package/dist/chat/negotiator.prompt.js +40 -1
- package/dist/chat/negotiator.prompt.js.map +1 -1
- package/dist/questioner/questioner.tools.d.ts +4 -3
- package/dist/questioner/questioner.tools.d.ts.map +1 -1
- package/dist/questioner/questioner.tools.js +77 -3
- package/dist/questioner/questioner.tools.js.map +1 -1
- package/dist/shared/agent/tool.helpers.d.ts +21 -0
- package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
- package/dist/shared/agent/tool.helpers.js.map +1 -1
- package/package.json +1 -1
|
@@ -25,7 +25,7 @@ export declare const NEGOTIATOR_PERSONA_ID = "negotiator";
|
|
|
25
25
|
* - agent management (`register/update/delete_agent`, permission grants),
|
|
26
26
|
* - `confirm_opportunity_delivery` (OpenClaw ledger write, never chat).
|
|
27
27
|
*/
|
|
28
|
-
export declare const NEGOTIATOR_TOOL_NAMES: readonly ["list_negotiations", "get_negotiation", "respond_to_negotiation", "list_opportunities", "update_opportunity", "read_intents", "create_intent", "update_intent", "delete_intent", "search_intents", "read_intent_indexes", "create_intent_index", "delete_intent_index", "read_user_contexts", "create_user_context", "update_user_context", "confirm_user_context", "preview_user_context", "read_premises", "create_premise", "update_premise", "retract_premise", "read_networks", "read_network_memberships", "create_network_membership", "delete_network_membership", "list_contacts", "search_contacts", "add_contact", "remove_contact", "import_contacts", "import_gmail_contacts", "scrape_url"];
|
|
28
|
+
export declare const NEGOTIATOR_TOOL_NAMES: readonly ["list_negotiations", "get_negotiation", "respond_to_negotiation", "list_opportunities", "update_opportunity", "read_pending_questions", "answer_pending_question", "read_intents", "create_intent", "update_intent", "delete_intent", "search_intents", "read_intent_indexes", "create_intent_index", "delete_intent_index", "read_user_contexts", "create_user_context", "update_user_context", "confirm_user_context", "preview_user_context", "read_premises", "create_premise", "update_premise", "retract_premise", "read_networks", "read_network_memberships", "create_network_membership", "delete_network_membership", "list_contacts", "search_contacts", "add_contact", "remove_contact", "import_contacts", "import_gmail_contacts", "scrape_url"];
|
|
29
29
|
/**
|
|
30
30
|
* Filters a full chat-tool registry down to the negotiator allowlist.
|
|
31
31
|
* Exported separately so the scoping rule is unit-testable without
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiator.persona.d.ts","sourceRoot":"/","sources":["chat/negotiator.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC9H,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAgC,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAYpG;;;GAGG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"negotiator.persona.d.ts","sourceRoot":"/","sources":["chat/negotiator.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC9H,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAgC,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAYpG;;;GAGG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,qBAAqB,0uBAiDxB,CAAC;AAIX;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAEjF;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,WAAW,EACjB,kBAAkB,CAAC,EAAE,mBAAmB,GACvC,OAAO,CAAC,SAAS,CAAC,CAGpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,uBAAuB,GAAG,iBAAiB,CAUxF"}
|
|
@@ -40,6 +40,13 @@ export const NEGOTIATOR_TOOL_NAMES = [
|
|
|
40
40
|
"respond_to_negotiation",
|
|
41
41
|
"list_opportunities",
|
|
42
42
|
"update_opportunity",
|
|
43
|
+
// Pending questions — the system's open questions for the client. Added for
|
|
44
|
+
// intent-pinned sessions (P4.2/IND-403); the tool clamps itself to the
|
|
45
|
+
// focused intent scope when one is set. answer_pending_question (P4.3/IND-404)
|
|
46
|
+
// records the client's explicit answers through the same pipeline the
|
|
47
|
+
// question cards use.
|
|
48
|
+
"read_pending_questions",
|
|
49
|
+
"answer_pending_question",
|
|
43
50
|
// Signals — the input surface of signal-based discovery (P4.5)
|
|
44
51
|
"read_intents",
|
|
45
52
|
"create_intent",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiator.persona.js","sourceRoot":"/","sources":["chat/negotiator.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8D,MAAM,iCAAiC,CAAC;AAE9H,OAAO,EAAE,4BAA4B,EAAgC,MAAM,wBAAwB,CAAC;AAEpG,kFAAkF;AAClF,4BAA4B;AAC5B,kFAAkF;AAClF,EAAE;AACF,6EAA6E;AAC7E,0EAA0E;AAC1E,0EAA0E;AAC1E,iEAAiE;AACjE,kDAAkD;AAElD;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,gDAAgD;IAChD,mBAAmB;IACnB,iBAAiB;IACjB,wBAAwB;IACxB,oBAAoB;IACpB,oBAAoB;IACpB,+DAA+D;IAC/D,cAAc;IACd,eAAe;IACf,eAAe;IACf,eAAe;IACf,gBAAgB;IAChB,qBAAqB;IACrB,qBAAqB;IACrB,qBAAqB;IACrB,2BAA2B;IAC3B,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;IACrB,sBAAsB;IACtB,sBAAsB;IACtB,4CAA4C;IAC5C,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,iBAAiB;IACjB,iEAAiE;IACjE,eAAe;IACf,0BAA0B;IAC1B,2BAA2B;IAC3B,2BAA2B;IAC3B,yDAAyD;IACzD,eAAe;IACf,iBAAiB;IACjB,aAAa;IACb,gBAAgB;IAChB,iBAAiB;IACjB,uBAAuB;IACvB,wEAAwE;IACxE,kDAAkD;IAClD,YAAY;CACJ,CAAC;AAEX,MAAM,yBAAyB,GAAwB,IAAI,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAEtF;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAA6B,KAAU;IAC1E,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAiB,EACjB,kBAAwC;IAExC,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC9D,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAA6B;IACnE,OAAO;QACL,EAAE,EAAE,qBAAqB;QACzB,kBAAkB,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,4BAA4B,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC;QACtF,WAAW,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,kBAAkB,CAAC;QAC1F,aAAa,EAAE;YACb,oBAAoB,EAAE,KAAK;YAC3B,qBAAqB,EAAE,IAAI;SAC5B;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { createChatTools, type ChatTools, type ToolContext, type ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport type { ChatPersonaConfig } from \"./chat.persona.js\";\nimport { buildNegotiatorSystemContent, type NegotiatorPromptOptions } from \"./negotiator.prompt.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// NEGOTIATOR PERSONA (P4.1)\n// ═══════════════════════════════════════════════════════════════════════════════\n//\n// A pure persona addition on the P4.0 persona-neutral chat runtime: advocate\n// prompt, client-scoped toolset, and all orchestrator loop behaviors OFF.\n// Unlike the orchestrator (a static singleton), the negotiator persona is\n// created per session because its identity comes from the user's\n// `type='personal'` agent row (name/description).\n\n/**\n * Persona id for the user's personal negotiator. Matches the\n * `conversations.persona` column value for negotiator DM sessions.\n */\nexport const NEGOTIATOR_PERSONA_ID = \"negotiator\";\n\n/**\n * Client-scoped tool allowlist for the negotiator persona.\n *\n * P4.5 (IND-413) expanded this from the read-mostly P4.1 set: with direct\n * opportunity discovery retiring alongside the orchestrator, discovery is\n * purely signal-based — so the negotiator (the surviving personal-agent chat\n * surface) manages the client's signals, profile knowledge, memberships, and\n * contacts.\n *\n * Still deliberately excluded:\n * - discovery runs (`discover_opportunities`, `get/cancel_discovery_run`) —\n * retired capability; matching happens in the background from signals,\n * - whole-network administration (`create/update/delete_network`) — a\n * human/UI act for now (joins/leaves are allowed),\n * - onboarding plumbing (`complete_onboarding`,\n * `record_onboarding_privacy_consent`),\n * - agent management (`register/update/delete_agent`, permission grants),\n * - `confirm_opportunity_delivery` (OpenClaw ledger write, never chat).\n */\nexport const NEGOTIATOR_TOOL_NAMES = [\n // Negotiation record — the advocate core (P4.1)\n \"list_negotiations\",\n \"get_negotiation\",\n \"respond_to_negotiation\",\n \"list_opportunities\",\n \"update_opportunity\",\n // Signals — the input surface of signal-based discovery (P4.5)\n \"read_intents\",\n \"create_intent\",\n \"update_intent\",\n \"delete_intent\",\n \"search_intents\",\n \"read_intent_indexes\",\n \"create_intent_index\",\n \"delete_intent_index\",\n // Profile knowledge (P4.5)\n \"read_user_contexts\",\n \"create_user_context\",\n \"update_user_context\",\n \"confirm_user_context\",\n \"preview_user_context\",\n // Premises (P4.5; read was already in P4.1)\n \"read_premises\",\n \"create_premise\",\n \"update_premise\",\n \"retract_premise\",\n // Networks — joins/leaves only, no network administration (P4.5)\n \"read_networks\",\n \"read_network_memberships\",\n \"create_network_membership\",\n \"delete_network_membership\",\n // Contacts — dormant while CONTACTS_ENABLED=false (P4.5)\n \"list_contacts\",\n \"search_contacts\",\n \"add_contact\",\n \"remove_contact\",\n \"import_contacts\",\n \"import_gmail_contacts\",\n // Utility — create_intent's own contract instructs scraping pasted URLs\n // before synthesizing a signal description (P4.5)\n \"scrape_url\",\n] as const;\n\nconst NEGOTIATOR_TOOL_ALLOWLIST: ReadonlySet<string> = new Set(NEGOTIATOR_TOOL_NAMES);\n\n/**\n * Filters a full chat-tool registry down to the negotiator allowlist.\n * Exported separately so the scoping rule is unit-testable without\n * constructing the full tool factory dependency graph.\n */\nexport function filterNegotiatorTools<T extends { name: string }>(tools: T[]): T[] {\n return tools.filter((t) => NEGOTIATOR_TOOL_ALLOWLIST.has(t.name));\n}\n\n/**\n * Creates the negotiator persona's client-scoped toolset.\n *\n * Reuses the standard chat tool factory (so context resolution, scope\n * derivation, logging, and error handling stay identical) and filters the\n * registry to the allowlist. The negotiation tools are already context-bound\n * to `context.userId`, so every tool in this set can only read or act on the\n * calling client's own data.\n */\nexport async function createNegotiatorTools(\n deps: ToolContext,\n preResolvedContext?: ResolvedToolContext,\n): Promise<ChatTools> {\n const tools = await createChatTools(deps, preResolvedContext);\n return filterNegotiatorTools(tools);\n}\n\n/**\n * Creates a negotiator `ChatPersonaConfig` bound to the client's personal\n * negotiator agent row identity.\n *\n * Loop behaviors (P4.5):\n * - `hallucinationRecovery: true` — with `create_intent` in the toolset the\n * model can legitimately produce ```intent_proposal blocks, so unbacked\n * blocks must be detected/auto-invoked/stripped. The auto-invoke path is\n * confirm-safe: `create_intent` returns a proposal card that persists\n * nothing until the client approves it in the UI. A hallucinated\n * ```opportunity block maps to `discover_opportunities`, which is absent\n * from this toolset — the loop falls back to a correction message and the\n * final-response strip still removes the unbacked block.\n * - `createIntentCallback: false` — discovery-coupled (fires only off\n * `discover_opportunities` results); retired along with direct discovery.\n *\n * @param opts - Identity from the user's `type='personal'` agent row\n */\nexport function createNegotiatorPersona(opts: NegotiatorPromptOptions): ChatPersonaConfig {\n return {\n id: NEGOTIATOR_PERSONA_ID,\n buildSystemContent: (ctx, iterCtx) => buildNegotiatorSystemContent(ctx, opts, iterCtx),\n createTools: (deps, preResolvedContext) => createNegotiatorTools(deps, preResolvedContext),\n loopBehaviors: {\n createIntentCallback: false,\n hallucinationRecovery: true,\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"negotiator.persona.js","sourceRoot":"/","sources":["chat/negotiator.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8D,MAAM,iCAAiC,CAAC;AAE9H,OAAO,EAAE,4BAA4B,EAAgC,MAAM,wBAAwB,CAAC;AAEpG,kFAAkF;AAClF,4BAA4B;AAC5B,kFAAkF;AAClF,EAAE;AACF,6EAA6E;AAC7E,0EAA0E;AAC1E,0EAA0E;AAC1E,iEAAiE;AACjE,kDAAkD;AAElD;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,gDAAgD;IAChD,mBAAmB;IACnB,iBAAiB;IACjB,wBAAwB;IACxB,oBAAoB;IACpB,oBAAoB;IACpB,4EAA4E;IAC5E,uEAAuE;IACvE,+EAA+E;IAC/E,sEAAsE;IACtE,sBAAsB;IACtB,wBAAwB;IACxB,yBAAyB;IACzB,+DAA+D;IAC/D,cAAc;IACd,eAAe;IACf,eAAe;IACf,eAAe;IACf,gBAAgB;IAChB,qBAAqB;IACrB,qBAAqB;IACrB,qBAAqB;IACrB,2BAA2B;IAC3B,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;IACrB,sBAAsB;IACtB,sBAAsB;IACtB,4CAA4C;IAC5C,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,iBAAiB;IACjB,iEAAiE;IACjE,eAAe;IACf,0BAA0B;IAC1B,2BAA2B;IAC3B,2BAA2B;IAC3B,yDAAyD;IACzD,eAAe;IACf,iBAAiB;IACjB,aAAa;IACb,gBAAgB;IAChB,iBAAiB;IACjB,uBAAuB;IACvB,wEAAwE;IACxE,kDAAkD;IAClD,YAAY;CACJ,CAAC;AAEX,MAAM,yBAAyB,GAAwB,IAAI,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAEtF;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAA6B,KAAU;IAC1E,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAiB,EACjB,kBAAwC;IAExC,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC9D,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAA6B;IACnE,OAAO;QACL,EAAE,EAAE,qBAAqB;QACzB,kBAAkB,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,4BAA4B,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC;QACtF,WAAW,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,kBAAkB,CAAC;QAC1F,aAAa,EAAE;YACb,oBAAoB,EAAE,KAAK;YAC3B,qBAAqB,EAAE,IAAI;SAC5B;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { createChatTools, type ChatTools, type ToolContext, type ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport type { ChatPersonaConfig } from \"./chat.persona.js\";\nimport { buildNegotiatorSystemContent, type NegotiatorPromptOptions } from \"./negotiator.prompt.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// NEGOTIATOR PERSONA (P4.1)\n// ═══════════════════════════════════════════════════════════════════════════════\n//\n// A pure persona addition on the P4.0 persona-neutral chat runtime: advocate\n// prompt, client-scoped toolset, and all orchestrator loop behaviors OFF.\n// Unlike the orchestrator (a static singleton), the negotiator persona is\n// created per session because its identity comes from the user's\n// `type='personal'` agent row (name/description).\n\n/**\n * Persona id for the user's personal negotiator. Matches the\n * `conversations.persona` column value for negotiator DM sessions.\n */\nexport const NEGOTIATOR_PERSONA_ID = \"negotiator\";\n\n/**\n * Client-scoped tool allowlist for the negotiator persona.\n *\n * P4.5 (IND-413) expanded this from the read-mostly P4.1 set: with direct\n * opportunity discovery retiring alongside the orchestrator, discovery is\n * purely signal-based — so the negotiator (the surviving personal-agent chat\n * surface) manages the client's signals, profile knowledge, memberships, and\n * contacts.\n *\n * Still deliberately excluded:\n * - discovery runs (`discover_opportunities`, `get/cancel_discovery_run`) —\n * retired capability; matching happens in the background from signals,\n * - whole-network administration (`create/update/delete_network`) — a\n * human/UI act for now (joins/leaves are allowed),\n * - onboarding plumbing (`complete_onboarding`,\n * `record_onboarding_privacy_consent`),\n * - agent management (`register/update/delete_agent`, permission grants),\n * - `confirm_opportunity_delivery` (OpenClaw ledger write, never chat).\n */\nexport const NEGOTIATOR_TOOL_NAMES = [\n // Negotiation record — the advocate core (P4.1)\n \"list_negotiations\",\n \"get_negotiation\",\n \"respond_to_negotiation\",\n \"list_opportunities\",\n \"update_opportunity\",\n // Pending questions — the system's open questions for the client. Added for\n // intent-pinned sessions (P4.2/IND-403); the tool clamps itself to the\n // focused intent scope when one is set. answer_pending_question (P4.3/IND-404)\n // records the client's explicit answers through the same pipeline the\n // question cards use.\n \"read_pending_questions\",\n \"answer_pending_question\",\n // Signals — the input surface of signal-based discovery (P4.5)\n \"read_intents\",\n \"create_intent\",\n \"update_intent\",\n \"delete_intent\",\n \"search_intents\",\n \"read_intent_indexes\",\n \"create_intent_index\",\n \"delete_intent_index\",\n // Profile knowledge (P4.5)\n \"read_user_contexts\",\n \"create_user_context\",\n \"update_user_context\",\n \"confirm_user_context\",\n \"preview_user_context\",\n // Premises (P4.5; read was already in P4.1)\n \"read_premises\",\n \"create_premise\",\n \"update_premise\",\n \"retract_premise\",\n // Networks — joins/leaves only, no network administration (P4.5)\n \"read_networks\",\n \"read_network_memberships\",\n \"create_network_membership\",\n \"delete_network_membership\",\n // Contacts — dormant while CONTACTS_ENABLED=false (P4.5)\n \"list_contacts\",\n \"search_contacts\",\n \"add_contact\",\n \"remove_contact\",\n \"import_contacts\",\n \"import_gmail_contacts\",\n // Utility — create_intent's own contract instructs scraping pasted URLs\n // before synthesizing a signal description (P4.5)\n \"scrape_url\",\n] as const;\n\nconst NEGOTIATOR_TOOL_ALLOWLIST: ReadonlySet<string> = new Set(NEGOTIATOR_TOOL_NAMES);\n\n/**\n * Filters a full chat-tool registry down to the negotiator allowlist.\n * Exported separately so the scoping rule is unit-testable without\n * constructing the full tool factory dependency graph.\n */\nexport function filterNegotiatorTools<T extends { name: string }>(tools: T[]): T[] {\n return tools.filter((t) => NEGOTIATOR_TOOL_ALLOWLIST.has(t.name));\n}\n\n/**\n * Creates the negotiator persona's client-scoped toolset.\n *\n * Reuses the standard chat tool factory (so context resolution, scope\n * derivation, logging, and error handling stay identical) and filters the\n * registry to the allowlist. The negotiation tools are already context-bound\n * to `context.userId`, so every tool in this set can only read or act on the\n * calling client's own data.\n */\nexport async function createNegotiatorTools(\n deps: ToolContext,\n preResolvedContext?: ResolvedToolContext,\n): Promise<ChatTools> {\n const tools = await createChatTools(deps, preResolvedContext);\n return filterNegotiatorTools(tools);\n}\n\n/**\n * Creates a negotiator `ChatPersonaConfig` bound to the client's personal\n * negotiator agent row identity.\n *\n * Loop behaviors (P4.5):\n * - `hallucinationRecovery: true` — with `create_intent` in the toolset the\n * model can legitimately produce ```intent_proposal blocks, so unbacked\n * blocks must be detected/auto-invoked/stripped. The auto-invoke path is\n * confirm-safe: `create_intent` returns a proposal card that persists\n * nothing until the client approves it in the UI. A hallucinated\n * ```opportunity block maps to `discover_opportunities`, which is absent\n * from this toolset — the loop falls back to a correction message and the\n * final-response strip still removes the unbacked block.\n * - `createIntentCallback: false` — discovery-coupled (fires only off\n * `discover_opportunities` results); retired along with direct discovery.\n *\n * @param opts - Identity from the user's `type='personal'` agent row\n */\nexport function createNegotiatorPersona(opts: NegotiatorPromptOptions): ChatPersonaConfig {\n return {\n id: NEGOTIATOR_PERSONA_ID,\n buildSystemContent: (ctx, iterCtx) => buildNegotiatorSystemContent(ctx, opts, iterCtx),\n createTools: (deps, preResolvedContext) => createNegotiatorTools(deps, preResolvedContext),\n loopBehaviors: {\n createIntentCallback: false,\n hallucinationRecovery: true,\n },\n };\n}\n"]}
|
|
@@ -6,6 +6,13 @@ export interface NegotiatorPromptOptions {
|
|
|
6
6
|
agentName: string;
|
|
7
7
|
/** The negotiator agent's description, when set on the agent row. */
|
|
8
8
|
agentDescription?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Human-readable label for the pinned signal when the session is
|
|
11
|
+
* intent-scoped (P4.2/IND-403). The pin itself comes from the resolved
|
|
12
|
+
* context's scope envelope; this label just saves a tool round-trip for
|
|
13
|
+
* naming it. Ignored when the session has no intent scope.
|
|
14
|
+
*/
|
|
15
|
+
pinnedIntentLabel?: string;
|
|
9
16
|
}
|
|
10
17
|
/**
|
|
11
18
|
* Builds the system prompt for the negotiator chat persona.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiator.prompt.d.ts","sourceRoot":"/","sources":["chat/negotiator.prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"negotiator.prompt.d.ts","sourceRoot":"/","sources":["chat/negotiator.prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAkBjE,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAkCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,mBAAmB,EACxB,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,MAAM,CAgFR"}
|
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
import { focusedIntentId } from "../shared/agent/tool.scope.js";
|
|
2
|
+
/**
|
|
3
|
+
* Renders the pinned-signal section for intent-scoped sessions (P4.2).
|
|
4
|
+
* Awareness, not a sandbox: the conversation orbits this signal, but the
|
|
5
|
+
* negotiator may still reference the client's other knowledge.
|
|
6
|
+
*/
|
|
7
|
+
function buildPinnedSignalSection(intentId, label) {
|
|
8
|
+
const labelLine = label?.trim() ? ` — “${label.trim()}”` : "";
|
|
9
|
+
return `
|
|
10
|
+
## Pinned signal
|
|
11
|
+
This conversation was opened from one of the client's signals (intent id: ${intentId}${labelLine}). Treat it as the working focus of this chat:
|
|
12
|
+
- Open questions listed by read_pending_questions here are this signal's open questions — surface them early and work through them conversationally. The client answers them via the question cards shown in this chat, or conversationally: when they give you an explicit answer, record it with answer_pending_question.
|
|
13
|
+
- list_opportunities and read_pending_questions are automatically restricted to this signal in this session; use them to report matches, negotiations, and follow-ups that grew out of it.
|
|
14
|
+
- When the client restates or sharpens what they want here, propose an update to this signal (update_intent) or a new premise — on their confirmation — so background matching reflects it.
|
|
15
|
+
- This is a focus, not a wall: you may still read the client's profile, premises, and other signals when the conversation needs the fuller picture, and general questions about their negotiations remain fair game.`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Renders the question-inbox section for the unscoped DM (P4.3/IND-404).
|
|
19
|
+
* The DM is the client's primary surface for the system's open questions:
|
|
20
|
+
* signal refinements, negotiation follow-ups, profile gaps. Cards render in
|
|
21
|
+
* the chat; conversational answers are recorded via answer_pending_question.
|
|
22
|
+
*/
|
|
23
|
+
function buildQuestionInboxSection() {
|
|
24
|
+
return `
|
|
25
|
+
## Client question inbox
|
|
26
|
+
The system collects open questions for your client (signal refinements, negotiation follow-ups, profile gaps), and this chat is the primary place they get handled. Question cards also render directly in this chat.
|
|
27
|
+
- Early in a conversation — or whenever the client asks what needs their attention — call read_pending_questions and surface what is open, briefly and in plain language.
|
|
28
|
+
- When the client asks why something is being asked, explain the question's context from the record it came from (the negotiation, opportunity, or signal behind it) — look it up, don't guess.
|
|
29
|
+
- When the client answers a question conversationally, record it with answer_pending_question — pass exactly what they said (their chosen options and/or their own words), never an answer you inferred. If the tool reports the question was already answered or dismissed, tell them instead of retrying.
|
|
30
|
+
- Never pressure the client to answer; the questions keep for later and remain available in the app's Questions page.`;
|
|
31
|
+
}
|
|
1
32
|
/**
|
|
2
33
|
* Builds the system prompt for the negotiator chat persona.
|
|
3
34
|
*
|
|
@@ -19,6 +50,12 @@ export function buildNegotiatorSystemContent(ctx, opts, _iterCtx) {
|
|
|
19
50
|
const descriptionLine = opts.agentDescription?.trim()
|
|
20
51
|
? `\n${opts.agentDescription.trim()}\n`
|
|
21
52
|
: "";
|
|
53
|
+
const pinnedIntentId = focusedIntentId(ctx);
|
|
54
|
+
// Pinned sessions clamp the question tools to the signal and carry their own
|
|
55
|
+
// question guidance; the unscoped DM gets the full inbox instead.
|
|
56
|
+
const pinnedSignalSection = pinnedIntentId
|
|
57
|
+
? buildPinnedSignalSection(pinnedIntentId, opts.pinnedIntentLabel)
|
|
58
|
+
: buildQuestionInboxSection();
|
|
22
59
|
return `You are ${opts.agentName}, the personal negotiator agent working for ${ctx.userName}.
|
|
23
60
|
${descriptionLine}
|
|
24
61
|
You work for exactly one client: ${ctx.userName}. You represent them in negotiations with other members' agents across the network, and this chat is your direct line to them. Your job here is to keep your client informed about what you have been doing on their behalf, explain your reasoning honestly, and act only on their explicit instructions.
|
|
@@ -32,7 +69,7 @@ You work for exactly one client: ${ctx.userName}. You represent them in negotiat
|
|
|
32
69
|
- **Handle memberships**: list the communities they belong to and join or leave communities when they ask.
|
|
33
70
|
- **Manage their contacts**: look up, add, remove, or import contacts when they ask (when contact features are enabled).
|
|
34
71
|
- **Act on instruction**: every write — a negotiation response, an opportunity decision, a signal, a profile or premise change, a membership change, a contact change — happens only when the client explicitly asks for it in this conversation. Never write anything the client did not just ask for.
|
|
35
|
-
|
|
72
|
+
${pinnedSignalSection}
|
|
36
73
|
## What you cannot do here
|
|
37
74
|
- **No direct discovery.** You cannot run matching or search for people yourself. Matching happens automatically in the background from the client's signals — shaping the signals is how you steer it. New matches appear on the client's home page and in this chat as opportunities.
|
|
38
75
|
- **No community administration.** You can join or leave communities for the client, but you cannot create, rename, or delete communities — point them to the app for that.
|
|
@@ -59,6 +96,8 @@ ${profileContext}
|
|
|
59
96
|
| **get_negotiation** | negotiationId | Full negotiation record: messages, outcome, reasoning |
|
|
60
97
|
| **respond_to_negotiation** | negotiationId, ... | Act on a negotiation — ONLY on explicit client instruction |
|
|
61
98
|
| **list_opportunities** | — | List the client's actionable opportunities |
|
|
99
|
+
| **read_pending_questions** | limit? | The system's open questions for the client (clamped to the pinned signal when one is set) |
|
|
100
|
+
| **answer_pending_question** | questionId, selectedOptions?, freeText? | Record the client's explicit answer to a pending question — ONLY with an answer they actually gave |
|
|
62
101
|
| **update_opportunity** | opportunityId, status | Accept/pass an opportunity — ONLY on explicit client instruction |
|
|
63
102
|
| **read_intents** / **search_intents** | — / query | The client's active signals (what they're looking for) |
|
|
64
103
|
| **create_intent** | description, networkId? | Draft a new signal — returns a proposal card the client approves in the UI |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiator.prompt.js","sourceRoot":"/","sources":["chat/negotiator.prompt.ts"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,4BAA4B,CAC1C,GAAwB,EACxB,IAA6B,EAC7B,QAA2B;IAE3B,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,GAAG,CAAC,WAAW;QACpC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,MAAM,CAAC;IACX,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,EAAE;QACnD,CAAC,CAAC,KAAK,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI;QACvC,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,WAAW,IAAI,CAAC,SAAS,+CAA+C,GAAG,CAAC,QAAQ;EAC3F,eAAe;mCACkB,GAAG,CAAC,QAAQ;;;;;;;;;;;;;;;;;;YAkBnC,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,SAAS,UAAU,GAAG,CAAC,MAAM;;;;EAI5D,WAAW;;;;;EAKX,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8MAiC8L,CAAC;AAC/M,CAAC","sourcesContent":["import type { ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport type { IterationContext } from \"./chat.prompt.modules.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// NEGOTIATOR PERSONA SYSTEM PROMPT (P4.1)\n// ═══════════════════════════════════════════════════════════════════════════════\n//\n// The direct chat line between a user and their personal negotiator agent\n// (the `type='personal'` agent row). Unlike the orchestrator prompt, this\n// persona works for exactly one client: it reports on the client's\n// negotiations and opportunities, explains decisions from the negotiation\n// record, and acts only on explicit client instruction.\n//\n// P4.5 (IND-413): the negotiator also manages the client's signals, profile\n// knowledge, premises, community memberships, and contacts — discovery is\n// purely signal-based, so shaping signals here IS how the client steers\n// matching. It still has no direct discovery capability: matching runs in\n// the background from the signals.\n\n/** Identity options resolved from the user's personal negotiator agent row. */\nexport interface NegotiatorPromptOptions {\n /** The negotiator agent's display name (e.g. \"Ada's Negotiator\"). */\n agentName: string;\n /** The negotiator agent's description, when set on the agent row. */\n agentDescription?: string;\n}\n\n/**\n * Builds the system prompt for the negotiator chat persona.\n *\n * Grounded in the client's preloaded user/profile context; everything else\n * (negotiations, opportunities, signals, premises) must be fetched through\n * the client-scoped toolset each turn.\n *\n * @param ctx - Resolved tool context for the current session\n * @param opts - Identity from the client's personal negotiator agent row\n * @param _iterCtx - Iteration context (unused — the negotiator prompt has no\n * dynamic modules; the nudge is injected by the agent loop)\n * @returns The complete system prompt string\n */\nexport function buildNegotiatorSystemContent(\n ctx: ResolvedToolContext,\n opts: NegotiatorPromptOptions,\n _iterCtx?: IterationContext,\n): string {\n const userContext = JSON.stringify(ctx.user, null, 2);\n const profileContext = ctx.userProfile\n ? JSON.stringify(ctx.userProfile, null, 2)\n : \"null\";\n const descriptionLine = opts.agentDescription?.trim()\n ? `\\n${opts.agentDescription.trim()}\\n`\n : \"\";\n\n return `You are ${opts.agentName}, the personal negotiator agent working for ${ctx.userName}.\n${descriptionLine}\nYou work for exactly one client: ${ctx.userName}. You represent them in negotiations with other members' agents across the network, and this chat is your direct line to them. Your job here is to keep your client informed about what you have been doing on their behalf, explain your reasoning honestly, and act only on their explicit instructions.\n\n## What you do in this chat\n- **Report on negotiations**: when the client asks what is happening, look up their negotiations and summarize status, counterparties, and where things stand.\n- **Explain decisions**: when the client asks why something was pursued, declined, or stalled (\"why did you pass on X?\"), find the relevant negotiation and answer from the actual record — the messages, outcomes, and reasoning stored there. Never reconstruct a rationale from memory.\n- **Review and act on opportunities**: show the client the opportunities currently waiting on them and what accepting or passing would mean; accept or pass on one only when they explicitly say so.\n- **Manage their signals**: their active intents (signals) define what you negotiate for — and matching is driven entirely by them. When the client tells you what they are looking for, draft a clear, specific signal and create it; refine or retire signals when they ask. If a signal request is vague, read their profile and existing signals first, then propose a sharper wording before creating it. If they paste a link describing what they want, read it first and synthesize the signal from its content.\n- **Keep their knowledge current**: when the client shares a new fact about themselves (\"I moved to Berlin\", \"I stopped consulting\"), update their profile context or premises so future negotiations reflect reality. Read before you write — update the existing entry instead of duplicating it.\n- **Handle memberships**: list the communities they belong to and join or leave communities when they ask.\n- **Manage their contacts**: look up, add, remove, or import contacts when they ask (when contact features are enabled).\n- **Act on instruction**: every write — a negotiation response, an opportunity decision, a signal, a profile or premise change, a membership change, a contact change — happens only when the client explicitly asks for it in this conversation. Never write anything the client did not just ask for.\n\n## What you cannot do here\n- **No direct discovery.** You cannot run matching or search for people yourself. Matching happens automatically in the background from the client's signals — shaping the signals is how you steer it. New matches appear on the client's home page and in this chat as opportunities.\n- **No community administration.** You can join or leave communities for the client, but you cannot create, rename, or delete communities — point them to the app for that.\n- You cannot push updates after this conversation ends. You only report when asked.\n\n## Session\n- Client: ${ctx.userName} (${ctx.userEmail}), id: ${ctx.userId}\n\n### Client (preloaded context)\n\\`\\`\\`json\n${userContext}\n\\`\\`\\`\n\n### Client Context (preloaded context)\n\\`\\`\\`json\n${profileContext}\n\\`\\`\\`\n\n## Tools Reference\n\n| Tool | Params | What it does |\n|------|--------|-------------|\n| **list_negotiations** | status?, limit? | List the client's negotiations |\n| **get_negotiation** | negotiationId | Full negotiation record: messages, outcome, reasoning |\n| **respond_to_negotiation** | negotiationId, ... | Act on a negotiation — ONLY on explicit client instruction |\n| **list_opportunities** | — | List the client's actionable opportunities |\n| **update_opportunity** | opportunityId, status | Accept/pass an opportunity — ONLY on explicit client instruction |\n| **read_intents** / **search_intents** | — / query | The client's active signals (what they're looking for) |\n| **create_intent** | description, networkId? | Draft a new signal — returns a proposal card the client approves in the UI |\n| **update_intent** / **delete_intent** | intentId, ... | Refine or retire a signal on instruction |\n| **read_intent_indexes** / **create_intent_index** / **delete_intent_index** | intentId, networkId | Where a signal is placed across communities |\n| **read_user_contexts** / **create_user_context** / **update_user_context** | ... | The client's profile knowledge — read before writing |\n| **preview_user_context** / **confirm_user_context** | ... | Preview/confirm profile updates from sources |\n| **read_premises** / **create_premise** / **update_premise** / **retract_premise** | ... | The client's premises (facts they've established) |\n| **read_networks** / **read_network_memberships** | — | The client's communities and memberships |\n| **create_network_membership** / **delete_network_membership** | networkId | Join/leave a community on instruction |\n| **list_contacts** / **search_contacts** / **add_contact** / **remove_contact** | ... | The client's contacts |\n| **import_contacts** / **import_gmail_contacts** | ... | Bulk contact import on instruction |\n| **scrape_url** | url, objective | Read a link the client pasted (e.g. before drafting a signal from it) |\n\n## Grounding rules\n- **Never fabricate.** Every claim about a negotiation, opportunity, signal, or premise must come from a tool result in this conversation. If you have not looked it up this turn, look it up before answering. Only the client's identity and profile above are preloaded.\n- **Check tool results before confirming.** Never claim an action succeeded without a successful tool result for it.\n- **Be honest about your own actions.** If the record shows you made a judgment call the client disagrees with, explain the reasoning from the record — do not get defensive, and do not invent justifications the record does not support.\n- **Pass proposal cards through verbatim.** When a tool result contains a fenced code block meant for the app (e.g. \\`\\`\\`intent_proposal from create_intent), include that block verbatim in your reply — the app renders it as an interactive card the client approves or skips. Never write such a block yourself without a backing tool result.\n- **Never expose IDs, UUIDs, tool names, or raw JSON** to the client. Translate everything into natural language; refer to people and opportunities by name. (Fenced proposal blocks from tool results are the one exception — they are rendered as cards, not shown as JSON.)\n- **Respond in the language of the client's latest message.**\n- **Voice**: first person, loyal but candid, calm and concise. No hype, no networking clichés, no exaggeration. You are their agent, not a salesperson.\n- When calling tools, first write a short natural sentence plus a \\`>\\` blockquote describing what you are checking (e.g. \"> Checking the record with Alice\"), then leave an empty line after the blockquote.`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"negotiator.prompt.js","sourceRoot":"/","sources":["chat/negotiator.prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAkChE;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,QAAgB,EAAE,KAAc;IAChE,MAAM,SAAS,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,OAAO;;4EAEmE,QAAQ,GAAG,SAAS;;;;qNAIqH,CAAC;AACtN,CAAC;AAED;;;;;GAKG;AACH,SAAS,yBAAyB;IAChC,OAAO;;;;;;sHAM6G,CAAC;AACvH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,4BAA4B,CAC1C,GAAwB,EACxB,IAA6B,EAC7B,QAA2B;IAE3B,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,GAAG,CAAC,WAAW;QACpC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,MAAM,CAAC;IACX,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,EAAE;QACnD,CAAC,CAAC,KAAK,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI;QACvC,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,cAAc,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC5C,6EAA6E;IAC7E,kEAAkE;IAClE,MAAM,mBAAmB,GAAG,cAAc;QACxC,CAAC,CAAC,wBAAwB,CAAC,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC;QAClE,CAAC,CAAC,yBAAyB,EAAE,CAAC;IAEhC,OAAO,WAAW,IAAI,CAAC,SAAS,+CAA+C,GAAG,CAAC,QAAQ;EAC3F,eAAe;mCACkB,GAAG,CAAC,QAAQ;;;;;;;;;;;EAW7C,mBAAmB;;;;;;;YAOT,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,SAAS,UAAU,GAAG,CAAC,MAAM;;;;EAI5D,WAAW;;;;;EAKX,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8MAmC8L,CAAC;AAC/M,CAAC","sourcesContent":["import type { ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport { focusedIntentId } from \"../shared/agent/tool.scope.js\";\nimport type { IterationContext } from \"./chat.prompt.modules.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// NEGOTIATOR PERSONA SYSTEM PROMPT (P4.1)\n// ═══════════════════════════════════════════════════════════════════════════════\n//\n// The direct chat line between a user and their personal negotiator agent\n// (the `type='personal'` agent row). Unlike the orchestrator prompt, this\n// persona works for exactly one client: it reports on the client's\n// negotiations and opportunities, explains decisions from the negotiation\n// record, and acts only on explicit client instruction.\n//\n// P4.5 (IND-413): the negotiator also manages the client's signals, profile\n// knowledge, premises, community memberships, and contacts — discovery is\n// purely signal-based, so shaping signals here IS how the client steers\n// matching. It still has no direct discovery capability: matching runs in\n// the background from the signals.\n\n/** Identity options resolved from the user's personal negotiator agent row. */\nexport interface NegotiatorPromptOptions {\n /** The negotiator agent's display name (e.g. \"Ada's Negotiator\"). */\n agentName: string;\n /** The negotiator agent's description, when set on the agent row. */\n agentDescription?: string;\n /**\n * Human-readable label for the pinned signal when the session is\n * intent-scoped (P4.2/IND-403). The pin itself comes from the resolved\n * context's scope envelope; this label just saves a tool round-trip for\n * naming it. Ignored when the session has no intent scope.\n */\n pinnedIntentLabel?: string;\n}\n\n/**\n * Renders the pinned-signal section for intent-scoped sessions (P4.2).\n * Awareness, not a sandbox: the conversation orbits this signal, but the\n * negotiator may still reference the client's other knowledge.\n */\nfunction buildPinnedSignalSection(intentId: string, label?: string): string {\n const labelLine = label?.trim() ? ` — “${label.trim()}”` : \"\";\n return `\n## Pinned signal\nThis conversation was opened from one of the client's signals (intent id: ${intentId}${labelLine}). Treat it as the working focus of this chat:\n- Open questions listed by read_pending_questions here are this signal's open questions — surface them early and work through them conversationally. The client answers them via the question cards shown in this chat, or conversationally: when they give you an explicit answer, record it with answer_pending_question.\n- list_opportunities and read_pending_questions are automatically restricted to this signal in this session; use them to report matches, negotiations, and follow-ups that grew out of it.\n- When the client restates or sharpens what they want here, propose an update to this signal (update_intent) or a new premise — on their confirmation — so background matching reflects it.\n- This is a focus, not a wall: you may still read the client's profile, premises, and other signals when the conversation needs the fuller picture, and general questions about their negotiations remain fair game.`;\n}\n\n/**\n * Renders the question-inbox section for the unscoped DM (P4.3/IND-404).\n * The DM is the client's primary surface for the system's open questions:\n * signal refinements, negotiation follow-ups, profile gaps. Cards render in\n * the chat; conversational answers are recorded via answer_pending_question.\n */\nfunction buildQuestionInboxSection(): string {\n return `\n## Client question inbox\nThe system collects open questions for your client (signal refinements, negotiation follow-ups, profile gaps), and this chat is the primary place they get handled. Question cards also render directly in this chat.\n- Early in a conversation — or whenever the client asks what needs their attention — call read_pending_questions and surface what is open, briefly and in plain language.\n- When the client asks why something is being asked, explain the question's context from the record it came from (the negotiation, opportunity, or signal behind it) — look it up, don't guess.\n- When the client answers a question conversationally, record it with answer_pending_question — pass exactly what they said (their chosen options and/or their own words), never an answer you inferred. If the tool reports the question was already answered or dismissed, tell them instead of retrying.\n- Never pressure the client to answer; the questions keep for later and remain available in the app's Questions page.`;\n}\n\n/**\n * Builds the system prompt for the negotiator chat persona.\n *\n * Grounded in the client's preloaded user/profile context; everything else\n * (negotiations, opportunities, signals, premises) must be fetched through\n * the client-scoped toolset each turn.\n *\n * @param ctx - Resolved tool context for the current session\n * @param opts - Identity from the client's personal negotiator agent row\n * @param _iterCtx - Iteration context (unused — the negotiator prompt has no\n * dynamic modules; the nudge is injected by the agent loop)\n * @returns The complete system prompt string\n */\nexport function buildNegotiatorSystemContent(\n ctx: ResolvedToolContext,\n opts: NegotiatorPromptOptions,\n _iterCtx?: IterationContext,\n): string {\n const userContext = JSON.stringify(ctx.user, null, 2);\n const profileContext = ctx.userProfile\n ? JSON.stringify(ctx.userProfile, null, 2)\n : \"null\";\n const descriptionLine = opts.agentDescription?.trim()\n ? `\\n${opts.agentDescription.trim()}\\n`\n : \"\";\n const pinnedIntentId = focusedIntentId(ctx);\n // Pinned sessions clamp the question tools to the signal and carry their own\n // question guidance; the unscoped DM gets the full inbox instead.\n const pinnedSignalSection = pinnedIntentId\n ? buildPinnedSignalSection(pinnedIntentId, opts.pinnedIntentLabel)\n : buildQuestionInboxSection();\n\n return `You are ${opts.agentName}, the personal negotiator agent working for ${ctx.userName}.\n${descriptionLine}\nYou work for exactly one client: ${ctx.userName}. You represent them in negotiations with other members' agents across the network, and this chat is your direct line to them. Your job here is to keep your client informed about what you have been doing on their behalf, explain your reasoning honestly, and act only on their explicit instructions.\n\n## What you do in this chat\n- **Report on negotiations**: when the client asks what is happening, look up their negotiations and summarize status, counterparties, and where things stand.\n- **Explain decisions**: when the client asks why something was pursued, declined, or stalled (\"why did you pass on X?\"), find the relevant negotiation and answer from the actual record — the messages, outcomes, and reasoning stored there. Never reconstruct a rationale from memory.\n- **Review and act on opportunities**: show the client the opportunities currently waiting on them and what accepting or passing would mean; accept or pass on one only when they explicitly say so.\n- **Manage their signals**: their active intents (signals) define what you negotiate for — and matching is driven entirely by them. When the client tells you what they are looking for, draft a clear, specific signal and create it; refine or retire signals when they ask. If a signal request is vague, read their profile and existing signals first, then propose a sharper wording before creating it. If they paste a link describing what they want, read it first and synthesize the signal from its content.\n- **Keep their knowledge current**: when the client shares a new fact about themselves (\"I moved to Berlin\", \"I stopped consulting\"), update their profile context or premises so future negotiations reflect reality. Read before you write — update the existing entry instead of duplicating it.\n- **Handle memberships**: list the communities they belong to and join or leave communities when they ask.\n- **Manage their contacts**: look up, add, remove, or import contacts when they ask (when contact features are enabled).\n- **Act on instruction**: every write — a negotiation response, an opportunity decision, a signal, a profile or premise change, a membership change, a contact change — happens only when the client explicitly asks for it in this conversation. Never write anything the client did not just ask for.\n${pinnedSignalSection}\n## What you cannot do here\n- **No direct discovery.** You cannot run matching or search for people yourself. Matching happens automatically in the background from the client's signals — shaping the signals is how you steer it. New matches appear on the client's home page and in this chat as opportunities.\n- **No community administration.** You can join or leave communities for the client, but you cannot create, rename, or delete communities — point them to the app for that.\n- You cannot push updates after this conversation ends. You only report when asked.\n\n## Session\n- Client: ${ctx.userName} (${ctx.userEmail}), id: ${ctx.userId}\n\n### Client (preloaded context)\n\\`\\`\\`json\n${userContext}\n\\`\\`\\`\n\n### Client Context (preloaded context)\n\\`\\`\\`json\n${profileContext}\n\\`\\`\\`\n\n## Tools Reference\n\n| Tool | Params | What it does |\n|------|--------|-------------|\n| **list_negotiations** | status?, limit? | List the client's negotiations |\n| **get_negotiation** | negotiationId | Full negotiation record: messages, outcome, reasoning |\n| **respond_to_negotiation** | negotiationId, ... | Act on a negotiation — ONLY on explicit client instruction |\n| **list_opportunities** | — | List the client's actionable opportunities |\n| **read_pending_questions** | limit? | The system's open questions for the client (clamped to the pinned signal when one is set) |\n| **answer_pending_question** | questionId, selectedOptions?, freeText? | Record the client's explicit answer to a pending question — ONLY with an answer they actually gave |\n| **update_opportunity** | opportunityId, status | Accept/pass an opportunity — ONLY on explicit client instruction |\n| **read_intents** / **search_intents** | — / query | The client's active signals (what they're looking for) |\n| **create_intent** | description, networkId? | Draft a new signal — returns a proposal card the client approves in the UI |\n| **update_intent** / **delete_intent** | intentId, ... | Refine or retire a signal on instruction |\n| **read_intent_indexes** / **create_intent_index** / **delete_intent_index** | intentId, networkId | Where a signal is placed across communities |\n| **read_user_contexts** / **create_user_context** / **update_user_context** | ... | The client's profile knowledge — read before writing |\n| **preview_user_context** / **confirm_user_context** | ... | Preview/confirm profile updates from sources |\n| **read_premises** / **create_premise** / **update_premise** / **retract_premise** | ... | The client's premises (facts they've established) |\n| **read_networks** / **read_network_memberships** | — | The client's communities and memberships |\n| **create_network_membership** / **delete_network_membership** | networkId | Join/leave a community on instruction |\n| **list_contacts** / **search_contacts** / **add_contact** / **remove_contact** | ... | The client's contacts |\n| **import_contacts** / **import_gmail_contacts** | ... | Bulk contact import on instruction |\n| **scrape_url** | url, objective | Read a link the client pasted (e.g. before drafting a signal from it) |\n\n## Grounding rules\n- **Never fabricate.** Every claim about a negotiation, opportunity, signal, or premise must come from a tool result in this conversation. If you have not looked it up this turn, look it up before answering. Only the client's identity and profile above are preloaded.\n- **Check tool results before confirming.** Never claim an action succeeded without a successful tool result for it.\n- **Be honest about your own actions.** If the record shows you made a judgment call the client disagrees with, explain the reasoning from the record — do not get defensive, and do not invent justifications the record does not support.\n- **Pass proposal cards through verbatim.** When a tool result contains a fenced code block meant for the app (e.g. \\`\\`\\`intent_proposal from create_intent), include that block verbatim in your reply — the app renders it as an interactive card the client approves or skips. Never write such a block yourself without a backing tool result.\n- **Never expose IDs, UUIDs, tool names, or raw JSON** to the client. Translate everything into natural language; refer to people and opportunities by name. (Fenced proposal blocks from tool results are the one exception — they are rendered as cards, not shown as JSON.)\n- **Respond in the language of the client's latest message.**\n- **Voice**: first person, loyal but candid, calm and concise. No hype, no networking clichés, no exaggeration. You are their agent, not a salesperson.\n- When calling tools, first write a short natural sentence plus a \\`>\\` blockquote describing what you are checking (e.g. \"> Checking the record with Alice\"), then leave an empty line after the blockquote.`;\n}\n"]}
|
|
@@ -9,8 +9,9 @@ import type { DefineTool, ToolDeps } from "../shared/agent/tool.helpers.js";
|
|
|
9
9
|
* block mirroring the network-tools convention.
|
|
10
10
|
*
|
|
11
11
|
* @param defineTool - Tool factory provided by the composition root.
|
|
12
|
-
* @param deps - Shared tool dependencies; `findPendingQuestions`
|
|
13
|
-
*
|
|
12
|
+
* @param deps - Shared tool dependencies; `findPendingQuestions` and
|
|
13
|
+
* `answerPendingQuestion` are optional and the tools fail
|
|
14
|
+
* gracefully when absent.
|
|
14
15
|
*/
|
|
15
|
-
export declare function createQuestionerTools(defineTool: DefineTool, deps: ToolDeps): readonly [any];
|
|
16
|
+
export declare function createQuestionerTools(defineTool: DefineTool, deps: ToolDeps): readonly [any, any];
|
|
16
17
|
//# sourceMappingURL=questioner.tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.tools.d.ts","sourceRoot":"/","sources":["questioner/questioner.tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAwB5E
|
|
1
|
+
{"version":3,"file":"questioner.tools.d.ts","sourceRoot":"/","sources":["questioner/questioner.tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAwB5E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,uBA8K3E"}
|
|
@@ -26,8 +26,9 @@ function stripInternalActors(question) {
|
|
|
26
26
|
* block mirroring the network-tools convention.
|
|
27
27
|
*
|
|
28
28
|
* @param defineTool - Tool factory provided by the composition root.
|
|
29
|
-
* @param deps - Shared tool dependencies; `findPendingQuestions`
|
|
30
|
-
*
|
|
29
|
+
* @param deps - Shared tool dependencies; `findPendingQuestions` and
|
|
30
|
+
* `answerPendingQuestion` are optional and the tools fail
|
|
31
|
+
* gracefully when absent.
|
|
31
32
|
*/
|
|
32
33
|
export function createQuestionerTools(defineTool, deps) {
|
|
33
34
|
const readPendingQuestions = defineTool({
|
|
@@ -109,6 +110,79 @@ export function createQuestionerTools(defineTool, deps) {
|
|
|
109
110
|
}
|
|
110
111
|
},
|
|
111
112
|
});
|
|
112
|
-
|
|
113
|
+
const answerPendingQuestion = defineTool({
|
|
114
|
+
name: "answer_pending_question",
|
|
115
|
+
description: "Records the client's explicit answer to one of their pending questions (from " +
|
|
116
|
+
"read_pending_questions) through the standard answer pipeline — the same one the " +
|
|
117
|
+
"question cards in the app use. Downstream effects (signal refinement, negotiation " +
|
|
118
|
+
"context, profile enrichment) fire exactly as if the client answered the card.\n\n" +
|
|
119
|
+
"**Use ONLY with an answer the client explicitly gave in this conversation.** Never " +
|
|
120
|
+
"infer, summarize, or invent an answer on their behalf. Pass the client's chosen " +
|
|
121
|
+
"option labels in `selectedOptions` and/or their own words in `freeText`.\n\n" +
|
|
122
|
+
"**Returns:** `answered: true` on success. If the question was already answered, " +
|
|
123
|
+
"dismissed, or expired, the tool reports that — tell the client instead of retrying.",
|
|
124
|
+
querySchema: z.object({
|
|
125
|
+
questionId: z.string().min(1).describe("Id of the pending question being answered (from read_pending_questions)."),
|
|
126
|
+
selectedOptions: z
|
|
127
|
+
.array(z.string().min(1))
|
|
128
|
+
.max(10)
|
|
129
|
+
.optional()
|
|
130
|
+
.describe("Option labels the client explicitly chose, when the question has options."),
|
|
131
|
+
freeText: z
|
|
132
|
+
.string()
|
|
133
|
+
.max(2000)
|
|
134
|
+
.optional()
|
|
135
|
+
.describe("The client's answer in their own words, for free-form answers or an 'other' option."),
|
|
136
|
+
}),
|
|
137
|
+
handler: async ({ context, query }) => {
|
|
138
|
+
if (!deps.answerPendingQuestion || !deps.findPendingQuestions) {
|
|
139
|
+
return error("Question answering is not available.");
|
|
140
|
+
}
|
|
141
|
+
// Client-surface action: network-scoped agent keys act inside one
|
|
142
|
+
// community and must not settle the user's global question inbox
|
|
143
|
+
// (same leak class as the SELF_OWNED_MODES clamp above).
|
|
144
|
+
if (focusedNetworkId(context)) {
|
|
145
|
+
return error("Answering questions is not available for network-scoped agents.");
|
|
146
|
+
}
|
|
147
|
+
const selectedOptions = (query.selectedOptions ?? []).map((option) => option.trim()).filter(Boolean);
|
|
148
|
+
const freeText = query.freeText?.trim();
|
|
149
|
+
if (selectedOptions.length === 0 && !freeText) {
|
|
150
|
+
return error("No answer provided. Pass the client's explicit answer via selectedOptions and/or freeText — never answer on their behalf.");
|
|
151
|
+
}
|
|
152
|
+
const scopedIntentId = focusedIntentId(context);
|
|
153
|
+
try {
|
|
154
|
+
// Visibility check under the same clamps as read_pending_questions:
|
|
155
|
+
// an intent-pinned session may only answer questions it can list.
|
|
156
|
+
const pending = await deps.findPendingQuestions(context.userId, {
|
|
157
|
+
...(scopedIntentId ? { scopeType: 'intent', scopeId: scopedIntentId } : {}),
|
|
158
|
+
});
|
|
159
|
+
const target = pending.find((q) => q.id === query.questionId);
|
|
160
|
+
if (!target) {
|
|
161
|
+
return error("Question not found among the client's pending questions — it may already be answered or dismissed. Re-check with read_pending_questions.");
|
|
162
|
+
}
|
|
163
|
+
const answered = await deps.answerPendingQuestion(context.userId, query.questionId, {
|
|
164
|
+
selectedOptions,
|
|
165
|
+
...(freeText ? { freeText } : {}),
|
|
166
|
+
});
|
|
167
|
+
if (!answered) {
|
|
168
|
+
return error("The question was already answered or dismissed — nothing was recorded.");
|
|
169
|
+
}
|
|
170
|
+
return success({
|
|
171
|
+
answered: true,
|
|
172
|
+
question: { id: target.id, title: target.title, prompt: target.prompt },
|
|
173
|
+
recordedAnswer: { selectedOptions, ...(freeText ? { freeText } : {}) },
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
deps.reportToolError?.(err, {
|
|
178
|
+
operation: "answer-pending-question",
|
|
179
|
+
toolName: "answer_pending_question",
|
|
180
|
+
userId: context.userId,
|
|
181
|
+
});
|
|
182
|
+
return error("Failed to record the answer.");
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
return [readPendingQuestions, answerPendingQuestion];
|
|
113
187
|
}
|
|
114
188
|
//# sourceMappingURL=questioner.tools.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.tools.js","sourceRoot":"/","sources":["questioner/questioner.tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { error, success } from \"../shared/agent/tool.helpers.js\";\nimport { focusedIntentId, focusedNetworkId, focusedNetworkLabel } from \"../shared/agent/tool.scope.js\";\nimport type { PendingQuestionSummary } from \"../shared/schemas/pending-question.schema.js\";\nimport type { QuestionMode } from \"../shared/schemas/question.schema.js\";\n\n/**\n * Detection modes whose questions derive solely from the caller's own data\n * (profile gaps, own intents, own discovery sessions). Negotiation-mode\n * questions are excluded for network-scoped agents: their prompts are seeded\n * from opportunity metadata that can reference out-of-scope networks and\n * other users' content (same leak class as the getOpportunitiesForUser fix).\n */\nconst SELF_OWNED_MODES: QuestionMode[] = [\"enrichment\", \"intent\", \"discovery\"];\n\nfunction isVisibleInScopedNetwork(question: PendingQuestionSummary, userId: string, networkId: string): boolean {\n return question.actors?.some((actor) => actor.userId === userId && actor.networkId === networkId) === true;\n}\n\nfunction stripInternalActors(question: PendingQuestionSummary): Omit<PendingQuestionSummary, \"actors\"> {\n const { actors: _actors, ...publicQuestion } = question;\n return publicQuestion;\n}\n\n/**\n * Creates MCP tool definitions for the questioner domain.\n * Exposes `read_pending_questions` for retrieving the caller's pending\n * questions generated by QuestionerAgent (enrichment, intent, negotiation, discovery modes).\n *\n * Network-scoped agent keys (context.scopeType/scopeId set via applyNetworkScopeToContext)\n * are clamped to self-owned modes; the result then carries a `scopeRestriction`\n * block mirroring the network-tools convention.\n *\n * @param defineTool - Tool factory provided by the composition root.\n * @param deps - Shared tool dependencies; `findPendingQuestions` is optional\n * and the tool fails gracefully when absent.\n */\nexport function createQuestionerTools(defineTool: DefineTool, deps: ToolDeps) {\n const readPendingQuestions = defineTool({\n name: \"read_pending_questions\",\n description:\n \"Returns pending questions generated for the authenticated user across all modes \" +\n \"(profile, intent, negotiation, discovery). These are questions generated by the \" +\n \"system to help surface missing signals, refine intents, or capture engagement context.\\n\\n\" +\n \"**Returns:** List of pending questions, each with `id`, `title`, `prompt`, `options`, \" +\n \"`multiSelect`, `mode`, `sourceType`, `sourceId`, `createdAt`, and optional `expiresAt`. \" +\n \"Network-scoped agents receive only profile/intent/discovery questions for the scoped network plus a \" +\n \"`scopeRestriction` note.\\n\\n\" +\n \"**Use:** Call with no arguments to get all pending questions, or pass `limit` to cap the \" +\n \"count. For the daily brief the script calls with a small `limit` and renders the first \" +\n \"question that has not been delivered yet.\",\n querySchema: z.object({\n limit: z\n .number()\n .int()\n .min(1)\n .max(10)\n .optional()\n .describe(\"Maximum number of questions to return (1-10, default 10).\"),\n }),\n handler: async ({ context, query }) => {\n if (!deps.findPendingQuestions) {\n return error(\"Question lookup is not available.\");\n }\n\n const limit = query.limit ?? 10;\n // Scoped-key discriminator: scoped contexts carry a scope envelope.\n const scopedNetworkId = focusedNetworkId(context);\n const scopedIntentId = focusedIntentId(context);\n const isNetworkScoped = Boolean(scopedNetworkId);\n const isIntentScoped = Boolean(scopedIntentId);\n\n try {\n const fetched = await deps.findPendingQuestions(context.userId, {\n ...(isNetworkScoped ? { modes: SELF_OWNED_MODES, networkId: scopedNetworkId } : {}),\n ...(isIntentScoped ? { scopeType: 'intent' as const, scopeId: scopedIntentId } : {}),\n limit,\n });\n // Defense-in-depth: hosts apply `modes`/`networkId`/`limit` SQL-side;\n // re-apply all three here so the network clamp holds even when a custom\n // dep ignores the filters. Scoped rows without actor network metadata are\n // hidden fail-closed because they cannot prove membership in this scope.\n const visible = isNetworkScoped\n ? fetched.filter(\n (q) =>\n (SELF_OWNED_MODES as string[]).includes(q.mode) &&\n isVisibleInScopedNetwork(q, context.userId, scopedNetworkId!),\n )\n : fetched;\n const limited = visible.slice(0, limit).map(stripInternalActors);\n\n if (isIntentScoped) {\n return success({\n questions: limited,\n scopeRestriction: {\n isScoped: true,\n scopedToIntent: scopedIntentId,\n message: \"Results are restricted to the selected intent, including direct intent questions and negotiation questions from matching opportunities.\",\n },\n });\n }\n\n if (isNetworkScoped) {\n return success({\n questions: limited,\n scopeRestriction: {\n isScoped: true,\n scopedToIndex: focusedNetworkLabel(context),\n message:\n `Results are restricted to \"${context.indexName ?? \"this network\"}\" and ` +\n `exclude negotiation questions because this agent is scoped to that index.`,\n },\n });\n }\n\n return success({ questions: limited });\n } catch (err) {\n deps.reportToolError?.(err, {\n operation: \"read-pending-questions\",\n toolName: \"read_pending_questions\",\n userId: context.userId,\n });\n return error(\"Failed to read pending questions.\");\n }\n },\n });\n\n return [readPendingQuestions] as const;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"questioner.tools.js","sourceRoot":"/","sources":["questioner/questioner.tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { error, success } from \"../shared/agent/tool.helpers.js\";\nimport { focusedIntentId, focusedNetworkId, focusedNetworkLabel } from \"../shared/agent/tool.scope.js\";\nimport type { PendingQuestionSummary } from \"../shared/schemas/pending-question.schema.js\";\nimport type { QuestionMode } from \"../shared/schemas/question.schema.js\";\n\n/**\n * Detection modes whose questions derive solely from the caller's own data\n * (profile gaps, own intents, own discovery sessions). Negotiation-mode\n * questions are excluded for network-scoped agents: their prompts are seeded\n * from opportunity metadata that can reference out-of-scope networks and\n * other users' content (same leak class as the getOpportunitiesForUser fix).\n */\nconst SELF_OWNED_MODES: QuestionMode[] = [\"enrichment\", \"intent\", \"discovery\"];\n\nfunction isVisibleInScopedNetwork(question: PendingQuestionSummary, userId: string, networkId: string): boolean {\n return question.actors?.some((actor) => actor.userId === userId && actor.networkId === networkId) === true;\n}\n\nfunction stripInternalActors(question: PendingQuestionSummary): Omit<PendingQuestionSummary, \"actors\"> {\n const { actors: _actors, ...publicQuestion } = question;\n return publicQuestion;\n}\n\n/**\n * Creates MCP tool definitions for the questioner domain.\n * Exposes `read_pending_questions` for retrieving the caller's pending\n * questions generated by QuestionerAgent (enrichment, intent, negotiation, discovery modes).\n *\n * Network-scoped agent keys (context.scopeType/scopeId set via applyNetworkScopeToContext)\n * are clamped to self-owned modes; the result then carries a `scopeRestriction`\n * block mirroring the network-tools convention.\n *\n * @param defineTool - Tool factory provided by the composition root.\n * @param deps - Shared tool dependencies; `findPendingQuestions` and\n * `answerPendingQuestion` are optional and the tools fail\n * gracefully when absent.\n */\nexport function createQuestionerTools(defineTool: DefineTool, deps: ToolDeps) {\n const readPendingQuestions = defineTool({\n name: \"read_pending_questions\",\n description:\n \"Returns pending questions generated for the authenticated user across all modes \" +\n \"(profile, intent, negotiation, discovery). These are questions generated by the \" +\n \"system to help surface missing signals, refine intents, or capture engagement context.\\n\\n\" +\n \"**Returns:** List of pending questions, each with `id`, `title`, `prompt`, `options`, \" +\n \"`multiSelect`, `mode`, `sourceType`, `sourceId`, `createdAt`, and optional `expiresAt`. \" +\n \"Network-scoped agents receive only profile/intent/discovery questions for the scoped network plus a \" +\n \"`scopeRestriction` note.\\n\\n\" +\n \"**Use:** Call with no arguments to get all pending questions, or pass `limit` to cap the \" +\n \"count. For the daily brief the script calls with a small `limit` and renders the first \" +\n \"question that has not been delivered yet.\",\n querySchema: z.object({\n limit: z\n .number()\n .int()\n .min(1)\n .max(10)\n .optional()\n .describe(\"Maximum number of questions to return (1-10, default 10).\"),\n }),\n handler: async ({ context, query }) => {\n if (!deps.findPendingQuestions) {\n return error(\"Question lookup is not available.\");\n }\n\n const limit = query.limit ?? 10;\n // Scoped-key discriminator: scoped contexts carry a scope envelope.\n const scopedNetworkId = focusedNetworkId(context);\n const scopedIntentId = focusedIntentId(context);\n const isNetworkScoped = Boolean(scopedNetworkId);\n const isIntentScoped = Boolean(scopedIntentId);\n\n try {\n const fetched = await deps.findPendingQuestions(context.userId, {\n ...(isNetworkScoped ? { modes: SELF_OWNED_MODES, networkId: scopedNetworkId } : {}),\n ...(isIntentScoped ? { scopeType: 'intent' as const, scopeId: scopedIntentId } : {}),\n limit,\n });\n // Defense-in-depth: hosts apply `modes`/`networkId`/`limit` SQL-side;\n // re-apply all three here so the network clamp holds even when a custom\n // dep ignores the filters. Scoped rows without actor network metadata are\n // hidden fail-closed because they cannot prove membership in this scope.\n const visible = isNetworkScoped\n ? fetched.filter(\n (q) =>\n (SELF_OWNED_MODES as string[]).includes(q.mode) &&\n isVisibleInScopedNetwork(q, context.userId, scopedNetworkId!),\n )\n : fetched;\n const limited = visible.slice(0, limit).map(stripInternalActors);\n\n if (isIntentScoped) {\n return success({\n questions: limited,\n scopeRestriction: {\n isScoped: true,\n scopedToIntent: scopedIntentId,\n message: \"Results are restricted to the selected intent, including direct intent questions and negotiation questions from matching opportunities.\",\n },\n });\n }\n\n if (isNetworkScoped) {\n return success({\n questions: limited,\n scopeRestriction: {\n isScoped: true,\n scopedToIndex: focusedNetworkLabel(context),\n message:\n `Results are restricted to \"${context.indexName ?? \"this network\"}\" and ` +\n `exclude negotiation questions because this agent is scoped to that index.`,\n },\n });\n }\n\n return success({ questions: limited });\n } catch (err) {\n deps.reportToolError?.(err, {\n operation: \"read-pending-questions\",\n toolName: \"read_pending_questions\",\n userId: context.userId,\n });\n return error(\"Failed to read pending questions.\");\n }\n },\n });\n\n const answerPendingQuestion = defineTool({\n name: \"answer_pending_question\",\n description:\n \"Records the client's explicit answer to one of their pending questions (from \" +\n \"read_pending_questions) through the standard answer pipeline — the same one the \" +\n \"question cards in the app use. Downstream effects (signal refinement, negotiation \" +\n \"context, profile enrichment) fire exactly as if the client answered the card.\\n\\n\" +\n \"**Use ONLY with an answer the client explicitly gave in this conversation.** Never \" +\n \"infer, summarize, or invent an answer on their behalf. Pass the client's chosen \" +\n \"option labels in `selectedOptions` and/or their own words in `freeText`.\\n\\n\" +\n \"**Returns:** `answered: true` on success. If the question was already answered, \" +\n \"dismissed, or expired, the tool reports that — tell the client instead of retrying.\",\n querySchema: z.object({\n questionId: z.string().min(1).describe(\"Id of the pending question being answered (from read_pending_questions).\"),\n selectedOptions: z\n .array(z.string().min(1))\n .max(10)\n .optional()\n .describe(\"Option labels the client explicitly chose, when the question has options.\"),\n freeText: z\n .string()\n .max(2000)\n .optional()\n .describe(\"The client's answer in their own words, for free-form answers or an 'other' option.\"),\n }),\n handler: async ({ context, query }) => {\n if (!deps.answerPendingQuestion || !deps.findPendingQuestions) {\n return error(\"Question answering is not available.\");\n }\n\n // Client-surface action: network-scoped agent keys act inside one\n // community and must not settle the user's global question inbox\n // (same leak class as the SELF_OWNED_MODES clamp above).\n if (focusedNetworkId(context)) {\n return error(\"Answering questions is not available for network-scoped agents.\");\n }\n\n const selectedOptions = (query.selectedOptions ?? []).map((option) => option.trim()).filter(Boolean);\n const freeText = query.freeText?.trim();\n if (selectedOptions.length === 0 && !freeText) {\n return error(\n \"No answer provided. Pass the client's explicit answer via selectedOptions and/or freeText — never answer on their behalf.\",\n );\n }\n\n const scopedIntentId = focusedIntentId(context);\n try {\n // Visibility check under the same clamps as read_pending_questions:\n // an intent-pinned session may only answer questions it can list.\n const pending = await deps.findPendingQuestions(context.userId, {\n ...(scopedIntentId ? { scopeType: 'intent' as const, scopeId: scopedIntentId } : {}),\n });\n const target = pending.find((q) => q.id === query.questionId);\n if (!target) {\n return error(\n \"Question not found among the client's pending questions — it may already be answered or dismissed. Re-check with read_pending_questions.\",\n );\n }\n\n const answered = await deps.answerPendingQuestion(context.userId, query.questionId, {\n selectedOptions,\n ...(freeText ? { freeText } : {}),\n });\n if (!answered) {\n return error(\"The question was already answered or dismissed — nothing was recorded.\");\n }\n\n return success({\n answered: true,\n question: { id: target.id, title: target.title, prompt: target.prompt },\n recordedAnswer: { selectedOptions, ...(freeText ? { freeText } : {}) },\n });\n } catch (err) {\n deps.reportToolError?.(err, {\n operation: \"answer-pending-question\",\n toolName: \"answer_pending_question\",\n userId: context.userId,\n });\n return error(\"Failed to record the answer.\");\n }\n },\n });\n\n return [readPendingQuestions, answerPendingQuestion] as const;\n}\n"]}
|
|
@@ -174,6 +174,17 @@ export interface ToolContext {
|
|
|
174
174
|
modes?: QuestionMode[];
|
|
175
175
|
limit?: number;
|
|
176
176
|
}) => Promise<PendingQuestionSummary[]>;
|
|
177
|
+
/**
|
|
178
|
+
* Record the client's explicit answer to a pending question through the
|
|
179
|
+
* host's question-answer pipeline (atomic pending→answered flip + answered
|
|
180
|
+
* events). Returns false when the question is not pending for this user
|
|
181
|
+
* (already answered/dismissed, expired, or not theirs). Injected by the
|
|
182
|
+
* composition root — absent when question delivery is disabled.
|
|
183
|
+
*/
|
|
184
|
+
answerPendingQuestion?: (userId: string, questionId: string, answer: {
|
|
185
|
+
selectedOptions: string[];
|
|
186
|
+
freeText?: string;
|
|
187
|
+
}) => Promise<boolean>;
|
|
177
188
|
/** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */
|
|
178
189
|
negotiationSummary?: NegotiationSummaryReader;
|
|
179
190
|
/**
|
|
@@ -403,6 +414,16 @@ export interface ToolDeps {
|
|
|
403
414
|
/** Maximum rows to return; hosts should apply this in the query. */
|
|
404
415
|
limit?: number;
|
|
405
416
|
}) => Promise<PendingQuestionSummary[]>;
|
|
417
|
+
/**
|
|
418
|
+
* Record the client's explicit answer to a pending question through the
|
|
419
|
+
* host's question-answer pipeline (atomic pending→answered flip + answered
|
|
420
|
+
* events). Returns false when the question is not pending for this user.
|
|
421
|
+
* Injected by the composition root — absent when question delivery is disabled.
|
|
422
|
+
*/
|
|
423
|
+
answerPendingQuestion?: (userId: string, questionId: string, answer: {
|
|
424
|
+
selectedOptions: string[];
|
|
425
|
+
freeText?: string;
|
|
426
|
+
}) => Promise<boolean>;
|
|
406
427
|
/** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */
|
|
407
428
|
negotiationSummary?: NegotiationSummaryReader;
|
|
408
429
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.helpers.d.ts","sourceRoot":"/","sources":["shared/agent/tool.helpers.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tool.helpers.d.ts","sourceRoot":"/","sources":["shared/agent/tool.helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.helpers.js","sourceRoot":"/","sources":["shared/agent/tool.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport type { ModelConfig } from \"./model.config.js\";\nimport { deriveAllowedNetworkIds, scopeFromNetworkId } from \"./tool.scope.js\";\nimport type { ToolScopeType } from \"./tool.scope.js\";\nimport type { UserIdentity } from \"../schemas/identity.schema.js\";\nimport type { ChatGraphCompositeDatabase, NetworkMembership, UserRecord, UserDatabase, SystemDatabase, NegotiationGraphDatabase } from \"../interfaces/database.interface.js\";\nimport type { Scraper } from \"../interfaces/scraper.interface.js\";\nimport type { Cache, HydeCache } from \"../interfaces/cache.interface.js\";\nimport type { CompiledOpportunityGraph } from \"../../opportunity/opportunity.discover.js\";\nimport type { IntegrationAdapter } from \"../interfaces/integration.interface.js\";\nimport type { ContactServiceAdapter } from \"../interfaces/contact.interface.js\";\nimport type { ProfileEnricher } from \"../interfaces/enrichment.interface.js\";\nimport type { IntentGraphQueue } from \"../interfaces/queue.interface.js\";\nimport type { ChatSessionReader } from \"../interfaces/chat-session.interface.js\";\nimport type { ChatSummaryReader } from \"../interfaces/chat-summary.interface.js\";\nimport type { ChatMessageWriter } from \"../interfaces/chat-message-writer.interface.js\";\nimport type { QuestionGeneratorReader } from \"../interfaces/question-generator.interface.js\";\nimport type { NegotiationSummaryReader } from \"../interfaces/negotiation-summary.interface.js\";\nimport type { Embedder } from \"../interfaces/embedder.interface.js\";\nimport type { AgentDatabase } from \"../interfaces/agent.interface.js\";\nimport type { NegotiationTimeoutQueue } from \"../interfaces/negotiation-events.interface.js\";\nimport type { AgentDispatcher } from \"../interfaces/agent-dispatcher.interface.js\";\nimport type { DeliveryLedger } from \"../interfaces/delivery-ledger.interface.js\";\nimport type { MintConnectLink } from \"../interfaces/connect-link.interface.js\";\nimport type { ChatQuestionsHost, QuestionerDatabase } from \"../interfaces/questioner.interface.js\";\nimport type { QuestionerEnqueueFn } from \"../../questioner/questioner.types.js\";\nimport type { PendingQuestionSummary } from \"../schemas/pending-question.schema.js\";\nimport type { QuestionMode } from \"../schemas/question.schema.js\";\nimport type { DiscoveryRunQueue, DiscoveryRunStore } from \"../interfaces/discovery-run.interface.js\";\nimport type { EnrichmentRunQueue, EnrichmentRunStore } from \"../interfaces/enrichment-run.interface.js\";\n\nexport type IdentityContext = UserIdentity | null;\n\nexport interface ToolErrorReport {\n operation: string;\n subsystem?: string;\n toolName?: string;\n userId?: string;\n tags?: Record<string, string | number | boolean | null | undefined>;\n context?: Record<string, unknown>;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// COMPILED GRAPH TYPE\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** Minimal interface for an invokable compiled LangGraph. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type CompiledGraph = { invoke: (input: any) => Promise<any> };\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TOOL CONTEXT TYPES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Resolved context available to every tool handler.\n * Contains the current user and optional network identity, resolved from DB at init.\n * The LLM can see this context (via system prompt) but cannot change it.\n */\nexport interface ResolvedToolContext {\n // Legacy flat fields (kept for backwards compatibility in tools/prompts).\n userId: string;\n userName: string;\n userEmail: string;\n /** Legacy focused network alias. Prefer `scopeType`/`scopeId` in new code. */\n networkId?: string;\n /** Focused request scope type: `network` for community focus, `intent` for selected-intent focus. */\n scopeType?: ToolScopeType;\n /** Focused request scope id. Network scope uses a network id; intent scope uses an intent id. */\n scopeId?: string;\n indexName?: string;\n /** True when chat is network-scoped and the user owns the index. */\n isOwner?: boolean;\n // Rich identity context for prompt/tool orchestration.\n user: UserRecord;\n userProfile: IdentityContext;\n userNetworks: NetworkMembership[];\n /**\n * @deprecated indexScope is legacy concrete network reach. New code should derive reach\n * from `scopeType`/`scopeId` plus `userNetworks` via `tool.scope.ts`.\n * Removed after call sites are migrated in this plan.\n */\n indexScope: string[];\n scopedIndex?: {\n id: string;\n title: string;\n prompt: string | null;\n type?: string;\n metadata?: Record<string, unknown>;\n permissions?: Record<string, unknown>;\n };\n scopedMembershipRole?: \"owner\" | \"member\";\n /** True when user has not completed onboarding (onboarding.completedAt is null). */\n isOnboarding: boolean;\n /** True when the user has a non-empty name. */\n hasName: boolean;\n /** Chat session ID when tools are used in a chat; used for draft opportunities (context.conversationId). */\n sessionId?: string;\n /** True when the request originates from an MCP transport (no interactive UI available). */\n isMcp?: boolean;\n /** Agent ID when the request originates from an API key linked to an agent. */\n agentId?: string;\n /**\n * Receiver's rendering surface declared by the MCP client via the\n * `x-index-surface` request header. `'telegram'` means the MCP response is\n * being rendered inside a Telegram chat; anything\n * else (including `undefined`) is treated as web. Forwarded into\n * `mintConnectLink` so the click-time redirect can branch.\n */\n clientSurface?: 'telegram' | 'web';\n /**\n * True when the CONTACTS_ENABLED feature flag is on. Carried from the\n * composition root so prompt modules can gate contact-import guidance —\n * when false/unset, the contacts prompt module is not injected, so the\n * orchestrator never advertises Gmail import / add_contact (whose tools\n * are also de-registered). Fail-closed: treat only `true` as enabled.\n */\n contactsEnabled?: boolean;\n}\n\n/**\n * Dependencies passed when creating tools for a user session.\n * Includes DB adapters, embedder, and scraper.\n *\n * Note: userDb and systemDb are optional inputs - if not provided, createChatTools\n * will create them internally from the chatDatabaseAdapter singleton.\n */\nexport interface ToolContext {\n userId: string;\n /** @deprecated Use userDb or systemDb instead. Kept for backwards compatibility. */\n database: ChatGraphCompositeDatabase;\n /** Context-bound database for accessing the authenticated user's own resources. Created internally if not provided. */\n userDb?: UserDatabase;\n /** Context-bound database for LLM/system operations on cross-user resources within shared networks. Created internally if not provided. */\n systemDb?: SystemDatabase;\n embedder: Embedder;\n scraper: Scraper;\n /** When set, chat is scoped to this network; converted to `{ scopeType: 'network', scopeId: networkId }` at the boundary. */\n networkId?: string;\n /** Focused request scope type: `network` or `intent`. */\n scopeType?: ToolScopeType;\n /** Focused request scope id. Network scope uses a network id; intent scope uses an intent id. */\n scopeId?: string;\n /** @deprecated indexScope is legacy; use `scopeType`/`scopeId`, retained until wiring phases migrate call sites. */\n indexScope?: string[];\n /** Chat session ID when creating tools for a chat; enables draft opportunities with context.conversationId. */\n sessionId?: string;\n\n // ─── Protocol-level dependencies (injected by composition root) ──────────\n /** General-purpose cache (e.g. for tool results). */\n cache: Cache;\n /** Dedicated cache for HyDE graph (may be same instance as cache). */\n hydeCache: HydeCache;\n /** External integration platform adapter (OAuth, tool actions). */\n integration: IntegrationAdapter;\n /** Queue for enqueuing follow-up intent processing (HyDE generation/deletion). */\n intentQueue: IntentGraphQueue;\n /** Contact management operations. */\n contactService: ContactServiceAdapter;\n /**\n * When false (or unset), the contact import / manual-add tools\n * (import_contacts, add_contact, import_gmail_contacts) are not registered.\n * Injected by the composition root from CONTACTS_ENABLED. Read/remove/search\n * contact tools are always registered.\n */\n contactsEnabled?: boolean;\n /** Chat session reader for loading conversation history. */\n chatSession: ChatSessionReader;\n /** Read-through chat-session digest. Optional; consumers fall back to undefined `chatContext`. */\n chatSummary?: ChatSummaryReader;\n /** Writes user messages into the user's most-recent chat session (Slice 5 MCP elicitation). */\n chatMessageWriter?: ChatMessageWriter;\n /** Decision-question generator. Optional; consumers fall back to no `questions`. */\n questionGenerator?: QuestionGeneratorReader;\n /**\n * Optional async question enqueue callback. When provided, question generation\n * is dispatched asynchronously to the QuestionerQueue instead of running inline.\n * Injected by the composition root when QUESTIONER_ENABLED=true.\n */\n questionerEnqueue?: QuestionerEnqueueFn;\n /**\n * Lookup pending questions for a user, optionally filtered by source,\n * detection mode, selected intent scope, or capped by count.\n */\n findPendingQuestions?: (\n userId: string,\n filters?: {\n sourceType?: string;\n sourceId?: string;\n scopeType?: 'intent';\n scopeId?: string;\n networkId?: string;\n modes?: QuestionMode[];\n limit?: number;\n },\n ) => Promise<PendingQuestionSummary[]>;\n /** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */\n negotiationSummary?: NegotiationSummaryReader;\n /**\n * Host bridge for the orchestrator's blocking `ask_user_question` tool\n * (synchronous chat-question persist + in-stream answer wait). Injected by\n * the backend composition root; when absent the tool is not registered.\n */\n chatQuestions?: ChatQuestionsHost;\n /**\n * Resolve a user's global user_context paragraph (profile-replacing identity\n * text), generating it on demand when absent. Mirrors `ToolDeps.getUserContextText`\n * so chat-path tool factories can forward it.\n */\n getUserContextText?: (userId: string) => Promise<string>;\n /** Profile enrichment from external data sources. */\n enricher: ProfileEnricher;\n /** Database adapter for negotiation/conversation operations. */\n negotiationDatabase: NegotiationGraphDatabase;\n /** Integration importer for bulk contact import from toolkits. */\n integrationImporter: {\n importContacts(userId: string, toolkit: string): Promise<{\n imported: number;\n skipped: number;\n newContacts: number;\n existingContacts: number;\n }>;\n };\n /** Factory for user-scoped database access. */\n createUserDatabase: (db: ChatGraphCompositeDatabase, userId: string) => UserDatabase;\n /** Factory for system-scoped database access. */\n createSystemDatabase: (db: ChatGraphCompositeDatabase, userId: string, indexScope: string[], embedder?: Embedder) => SystemDatabase;\n /** Optional runtime LLM config. Pass to override env vars for API key, model, etc. */\n modelConfig?: ModelConfig;\n /** Manages negotiation timeout jobs (optional — enables AI fallback on external agent timeout). */\n negotiationTimeoutQueue?: NegotiationTimeoutQueue;\n /** Agent registry database adapter (optional — absent when host does not support agents). */\n agentDatabase?: AgentDatabase;\n /** Grants the default system-agent permissions after onboarding (optional). */\n grantDefaultSystemPermissions?: (userId: string) => Promise<void>;\n /** Dispatcher for routing negotiation turns to personal agents (optional — falls back to system AI). */\n agentDispatcher?: AgentDispatcher;\n /** Enqueue a negotiate_existing job after introducer approval (optional). */\n queueNegotiateExisting?: (opportunityId: string, userId: string) => Promise<void>;\n /** Delivery ledger for committing opportunity delivery rows (optional — absent in chat context). */\n deliveryLedger?: DeliveryLedger;\n /** Persistence for async MCP discovery runs (optional — absent in non-MCP/test contexts). */\n discoveryRuns?: DiscoveryRunStore;\n /** Queue for async MCP discovery run execution (optional — absent in non-MCP/test contexts). */\n discoveryRunQueue?: DiscoveryRunQueue;\n /** Persistence for async MCP profile runs (optional — absent in non-MCP/test contexts). */\n enrichmentRuns?: EnrichmentRunStore;\n /** Queue for async MCP profile run execution (optional — absent in non-MCP/test contexts). */\n enrichmentRunQueue?: EnrichmentRunQueue;\n /**\n * Legacy direct-token minting for opportunity accept redirects.\n * Prefer `mintConnectLink` for user-facing links.\n */\n mintConnectToken?: (userId: string, opportunityId: string) => Promise<string>;\n /** Mints (or reuses) a short connect link, snapshotting the greeting (optional — absent in non-MCP contexts). */\n mintConnectLink?: MintConnectLink;\n /** Frontend base URL for building profile links (e.g. https://index.network, optional). */\n frontendUrl?: string;\n /** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */\n apiBaseUrl?: string;\n /** Persistence for structured questions generated by the QuestionerAgent (optional). */\n questionerDatabase?: QuestionerDatabase;\n /** Optional host-side error reporter for swallowed protocol/tool errors. */\n reportToolError?: (error: unknown, report: ToolErrorReport) => void;\n /**\n * Optional host-side per-principal MCP call throttle. Invoked once per MCP\n * tool dispatch (after identity resolves, before any DB work). When the\n * returned decision is `allowed: false`, the dispatch short-circuits with a\n * rate-limit error carrying `retryAfterSec`. Absent in chat/test contexts.\n */\n mcpRateLimiter?: (input: { userId: string; agentId?: string; toolName: string }) => Promise<{\n allowed: boolean;\n retryAfterSec?: number;\n limit?: number;\n scope?: 'tool' | 'principal';\n }>;\n}\n\n/**\n * All external dependencies needed to initialize the protocol tool engine.\n * The host application (composition root) must provide concrete implementations.\n * This is the subset of ToolContext that is NOT per-request (no userId, indexId, sessionId).\n */\nexport type ProtocolDeps = Omit<ToolContext, 'userId' | 'indexId' | 'sessionId' | 'userDb' | 'systemDb'>;\n\n/**\n * Thrown when a requested chat scope is invalid for the authenticated user.\n * Controllers can map this to an HTTP status code.\n */\nexport class ChatContextAccessError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly code: \"USER_NOT_FOUND\" | \"INDEX_NOT_FOUND\" | \"INDEX_MEMBERSHIP_REQUIRED\"\n ) {\n super(message);\n this.name = \"ChatContextAccessError\";\n }\n}\n\n/**\n * Resolve the canonical context used by chat tools and system prompt.\n * This preloads user identity, profile, network memberships, and scoped index role.\n */\nexport async function resolveChatContext(params: {\n database: Pick<\n ChatGraphCompositeDatabase,\n \"getUser\" | \"getProfile\" | \"getNetworkMemberships\" | \"getNetworkMembership\" | \"getNetwork\" | \"isIndexOwner\" | \"isNetworkMember\" | \"getUserContext\"\n >;\n userId: string;\n networkId?: string;\n /** Chat session ID for draft opportunities (stored as context.conversationId). */\n sessionId?: string;\n /** CONTACTS_ENABLED flag, forwarded onto the resolved context for prompt gating. */\n contactsEnabled?: boolean;\n}): Promise<ResolvedToolContext> {\n const { database, userId, networkId, sessionId, contactsEnabled } = params;\n\n const [user, rawProfile, userNetworks, globalContext] = await Promise.all([\n database.getUser(userId),\n database.getProfile(userId),\n database.getNetworkMemberships(userId),\n // The premise-derived global user_context paragraph. getProfile deliberately\n // leaves `context` empty (WS8: narrative lives in user_contexts, not users);\n // without this read the system prompt's only narrative is the stale onboarding\n // bio, which resurrects facts the user has since retracted. Best-effort: a\n // missing row or a minimal test adapter degrades to the empty string.\n Promise.resolve()\n .then(() => database.getUserContext?.(userId, null))\n .catch(() => null),\n ]);\n\n const userProfile: IdentityContext = rawProfile ?? null;\n if (userProfile && !userProfile.context && globalContext?.text) {\n userProfile.context = globalContext.text;\n }\n\n if (!user) {\n throw new ChatContextAccessError(\n \"User not found\",\n 404,\n \"USER_NOT_FOUND\"\n );\n }\n\n let scopedIndex: ResolvedToolContext[\"scopedIndex\"] = undefined;\n let scopedMembershipRole: ResolvedToolContext[\"scopedMembershipRole\"] = undefined;\n let isOwner = false;\n let indexName: string | undefined;\n\n if (networkId) {\n const [index, isMember, owner] = await Promise.all([\n database.getNetwork(networkId),\n database.isNetworkMember(networkId, userId),\n database.isIndexOwner(networkId, userId),\n ]);\n\n if (!index) {\n throw new ChatContextAccessError(\n \"Index not found\",\n 404,\n \"INDEX_NOT_FOUND\"\n );\n }\n\n if (!isMember) {\n throw new ChatContextAccessError(\n \"You are not a member of this network\",\n 403,\n \"INDEX_MEMBERSHIP_REQUIRED\"\n );\n }\n\n let membership = userNetworks.find((m) => m.networkId === index.id);\n if (membership === undefined) {\n membership = (await database.getNetworkMembership(index.id, userId)) ?? undefined;\n }\n scopedIndex = {\n id: index.id,\n title: index.title,\n prompt: membership?.indexPrompt ?? null,\n type: index.type ?? 'community',\n metadata: index.metadata ?? {},\n permissions: index.permissions ?? {},\n };\n isOwner = owner;\n indexName = index.title;\n scopedMembershipRole = owner ? \"owner\" : \"member\";\n }\n\n const userName = user.name ?? \"Unknown\";\n const userEmail = user.email ?? \"\";\n const hasName = !!user.name?.trim();\n\n const scope = scopeFromNetworkId(networkId);\n\n // Deprecated compatibility reach. New call sites should call\n // deriveAllowedNetworkIds({ memberships: userNetworks, ...scope }) directly.\n const allowedNetworkIds = deriveAllowedNetworkIds({\n memberships: userNetworks,\n ...scope,\n });\n\n return {\n userId,\n userName,\n userEmail,\n networkId,\n ...scope,\n indexName,\n isOwner,\n user,\n userProfile,\n userNetworks,\n indexScope: allowedNetworkIds,\n scopedIndex,\n scopedMembershipRole,\n isOnboarding: !(user.onboarding?.completedAt),\n hasName,\n contactsEnabled,\n ...(sessionId !== undefined ? { sessionId } : {}),\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// DEFINE TOOL TYPE\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Type for the `defineTool` closure created in `createChatTools`.\n * Auto-injects resolved context and provides uniform logging / error handling.\n */\nexport type DefineTool = <T extends z.ZodType>(opts: {\n name: string;\n description: string;\n querySchema: T;\n handler: (input: { context: ResolvedToolContext; query: z.infer<T> }) => Promise<string>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n}) => any;\n\n/**\n * A raw tool definition before LangChain wrapping.\n * Used by the tool registry for direct HTTP invocation.\n */\nexport interface RawToolDefinition {\n name: string;\n description: string;\n schema: z.ZodType;\n handler: (input: { context: ResolvedToolContext; query: unknown }) => Promise<string>;\n}\n\n/**\n * Registry mapping tool names to their raw definitions.\n */\nexport type ToolRegistry = Map<string, RawToolDefinition>;\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TOOL DEPENDENCIES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Shared dependencies available to all tool domain factories.\n * Passed by `createChatTools` after compiling all subgraphs.\n */\nexport interface ToolDeps {\n /** @deprecated Use userDb or systemDb instead. Kept for backwards compatibility. */\n database: ChatGraphCompositeDatabase;\n /** Context-bound database for accessing the authenticated user's own resources. */\n userDb: UserDatabase;\n /** Context-bound database for LLM/system operations on cross-user resources within shared networks. */\n systemDb: SystemDatabase;\n scraper: Scraper;\n embedder: import('../interfaces/embedder.interface.js').Embedder;\n cache: Cache;\n integration: IntegrationAdapter;\n contactService: ContactServiceAdapter;\n /**\n * When false (or unset), the contact import / manual-add tools\n * (import_contacts, add_contact, import_gmail_contacts) are not registered.\n * Injected by the composition root from CONTACTS_ENABLED. Read/remove/search\n * contact tools are always registered.\n */\n contactsEnabled?: boolean;\n integrationImporter: {\n importContacts(userId: string, toolkit: string): Promise<{\n imported: number;\n skipped: number;\n newContacts: number;\n existingContacts: number;\n }>;\n };\n enricher: ProfileEnricher;\n /** Database adapter for negotiation/conversation operations. */\n negotiationDatabase: NegotiationGraphDatabase;\n /** Chat session reader for exposing the caller's past conversations as MCP tools. */\n chatSession?: ChatSessionReader;\n /** Read-through chat-session digest. Optional; consumers fall back to undefined `chatContext`. */\n chatSummary?: ChatSummaryReader;\n /**\n * Test seam for opportunity discovery helpers. Production compositions leave\n * this unset so tools call the real discovery module directly.\n */\n opportunityDiscovery?: {\n runDiscoverFromQuery?: (input: unknown) => Promise<unknown>;\n continueDiscovery?: (input: unknown) => Promise<unknown>;\n };\n /**\n * Test seam for opportunity card presentation helpers. Production\n * compositions leave this unset so tools construct the real presenter.\n */\n opportunityPresentation?: {\n createPresenter?: () => { presentHomeCard(input: unknown): Promise<unknown> };\n gatherPresenterContext?: (...args: unknown[]) => Promise<unknown>;\n };\n /** Writes user messages into the user's most-recent chat session (Slice 5 MCP elicitation). */\n chatMessageWriter?: ChatMessageWriter;\n /** Decision-question generator. Optional; consumers fall back to no `questions`. */\n questionGenerator?: QuestionGeneratorReader;\n /**\n * Optional async question enqueue callback. When provided, question generation\n * is dispatched asynchronously to the QuestionerQueue instead of running inline\n * via the `questionGenerator`. Injected by the composition root when\n * QUESTIONER_ENABLED=true.\n */\n questionerEnqueue?: QuestionerEnqueueFn;\n /**\n * Lookup pending questions for a user, optionally filtered by source,\n * detection mode, or capped by count (hosts apply `limit` SQL-side).\n * Used by tools to attach contextually relevant questions to their results.\n * Injected by the composition root — absent when question delivery is disabled.\n */\n findPendingQuestions?: (\n userId: string,\n filters?: {\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 /** Restrict to questions whose actor carries this network id. */\n networkId?: string;\n /** Restrict to questions whose detection mode is in this set. */\n modes?: QuestionMode[];\n /** Maximum rows to return; hosts should apply this in the query. */\n limit?: number;\n },\n ) => Promise<PendingQuestionSummary[]>;\n /** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */\n negotiationSummary?: NegotiationSummaryReader;\n /**\n * Host bridge for the orchestrator's blocking `ask_user_question` tool\n * (synchronous chat-question persist + in-stream answer wait). Injected by\n * the backend composition root; when absent the tool is not registered.\n */\n chatQuestions?: ChatQuestionsHost;\n /** Manages negotiation timeout jobs (optional — enables AI fallback on external agent timeout). */\n negotiationTimeoutQueue?: NegotiationTimeoutQueue;\n /** Agent registry database adapter (optional — absent when host does not support agents). */\n agentDatabase?: AgentDatabase;\n /** Grants the default system-agent permissions after onboarding (optional). */\n grantDefaultSystemPermissions?: (userId: string) => Promise<void>;\n /** Dispatcher for routing negotiation turns to personal agents (optional — falls back to system AI). */\n agentDispatcher?: AgentDispatcher;\n /** Delivery ledger for committing opportunity delivery rows (optional — absent in chat context). */\n deliveryLedger?: DeliveryLedger;\n /** Persistence for async MCP discovery runs (optional — absent in non-MCP/test contexts). */\n discoveryRuns?: DiscoveryRunStore;\n /** Queue for async MCP discovery run execution (optional — absent in non-MCP/test contexts). */\n discoveryRunQueue?: DiscoveryRunQueue;\n /** Persistence for async MCP profile runs (optional — absent in non-MCP/test contexts). */\n enrichmentRuns?: EnrichmentRunStore;\n /** Queue for async MCP profile run execution (optional — absent in non-MCP/test contexts). */\n enrichmentRunQueue?: EnrichmentRunQueue;\n /**\n * Legacy direct-token minting for opportunity accept redirects.\n * Prefer `mintConnectLink` for user-facing links.\n */\n mintConnectToken?: (userId: string, opportunityId: string) => Promise<string>;\n /** Mints (or reuses) a short connect link, snapshotting the greeting (optional — absent in non-MCP contexts). */\n mintConnectLink?: MintConnectLink;\n /** Frontend base URL for building profile links (e.g. https://index.network, optional). */\n frontendUrl?: string;\n /** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */\n apiBaseUrl?: string;\n /** Optional host-side error reporter for swallowed protocol/tool errors. */\n reportToolError?: (error: unknown, report: ToolErrorReport) => void;\n /**\n * Optional host-side per-principal MCP call throttle. Invoked once per MCP\n * tool dispatch (after identity resolves, before any DB work). When the\n * returned decision is `allowed: false`, the dispatch short-circuits with a\n * rate-limit error carrying `retryAfterSec`. Absent in chat/test contexts.\n */\n mcpRateLimiter?: (input: { userId: string; agentId?: string; toolName: string }) => Promise<{\n allowed: boolean;\n retryAfterSec?: number;\n limit?: number;\n scope?: 'tool' | 'principal';\n }>;\n graphs: {\n profile: CompiledGraph;\n intent: CompiledGraph;\n index: CompiledGraph;\n networkMembership: CompiledGraph;\n intentIndex: CompiledGraph;\n opportunity: CompiledOpportunityGraph;\n premise: CompiledGraph;\n };\n /**\n * Optional network ranking override for `read_networks`. Injected by tests or custom compositions.\n * When absent, defaults to `NetworkRecommender.invoke()` with a lazy module-level singleton.\n */\n networkRanker?: (input: {\n userContext: string;\n networks: Array<{ networkId: string; renderedContext: string }>;\n }) => Promise<{ rankedNetworkIds: string[] } | null>;\n /**\n * Resolve a user's global user_context paragraph (profile-replacing identity text),\n * generating it on demand when absent. Injected by the backend composition root\n * (`ensureGlobalUserContext`). When absent, onboarding network ranking is skipped.\n */\n getUserContextText?: (userId: string) => Promise<string>;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TOOL RESULT HELPERS\n// ═══════════════════════════════════════════════════════════════════════════════\n\nexport function success<T>(data: T): string {\n return JSON.stringify({ success: true, data });\n}\n\nexport function error(\n message: string,\n debugSteps?: Array<{ step: string; detail?: string; data?: Record<string, unknown> }>\n): string {\n return JSON.stringify({\n success: false,\n error: message,\n ...(debugSteps?.length ? { debugSteps } : {}),\n });\n}\n\n/** Return needsClarification for missing required fields. */\nexport function needsClarification(params: {\n missingFields: string[];\n message: string;\n}): string {\n return JSON.stringify({\n success: false,\n needsClarification: true,\n ...params,\n });\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CONSTANTS & UTILITIES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** Matches http/https URLs in text; captures full URL. */\nconst URL_IN_TEXT_REGEX = /https?:\\/\\/[^\\s\"'<>)\\]]+/gi;\n\n/**\n * Matches bare domain URLs without protocol (e.g. github.com/foo, www.example.com).\n * Requires at least a SLD.TLD pattern followed by optional path.\n * Negative lookbehind ensures we don't double-match URLs already caught by URL_IN_TEXT_REGEX.\n */\nconst BARE_URL_REGEX = /(?<!\\w:\\/\\/)(?<![/\\w])(?:www\\.)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.(?:com|org|net|io|dev|co|ai|app|xyz|me|info|gg|so|sh|cc|ly|fm|tv|to|tech|design|network|world|edu|gov|mil|int|us|uk|eu|de|fr|ca|au|jp|cn|in|br|nl|se|no|fi|dk|ch|at|be|it|es|pt|pl|cz|ru|kr|tw|hk|sg|nz|za|mx|ar|cl|id|ph|th|vn|my|ie)(?:\\/[^\\s\"'<>)\\]]*)?/gi;\n\n/** UUID v4 format: 8-4-4-4-12 hex chars (e.g. c2505011-2e45-426e-81dd-b9abb9b72023) */\nexport const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Resolves an array of network IDs to their display titles.\n * Skips any IDs that don't resolve (deleted or invalid networks).\n */\nexport async function resolveIndexNames(\n database: { getNetwork(id: string): Promise<{ id: string; title: string } | null> },\n networkIds: string[]\n): Promise<string[]> {\n if (networkIds.length === 0) return [];\n const results = await Promise.all(\n networkIds.map(id => database.getNetwork(id))\n );\n return results.filter(Boolean).map(idx => idx!.title);\n}\n\n/**\n * Normalize a URL string: if it lacks a protocol, prepend \"https://\".\n * Returns the normalized URL or null if the result is not a valid URL.\n */\nexport function normalizeUrl(raw: string): string | null {\n let url = raw.replace(/[.,;:!?)]+$/, \"\").trim();\n if (!/^https?:\\/\\//i.test(url)) {\n url = `https://${url}`;\n }\n try {\n new URL(url);\n return url;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract unique, valid URLs from a string (e.g. user message or details).\n * Handles both full URLs (https://...) and bare domains (github.com/...).\n */\nexport function extractUrls(text: string): string[] {\n if (!text || typeof text !== \"string\") return [];\n\n const seen = new Set<string>();\n const out: string[] = [];\n\n // Pass 1: full protocol URLs\n const fullMatches = text.match(URL_IN_TEXT_REGEX) ?? [];\n for (const raw of fullMatches) {\n const url = normalizeUrl(raw);\n if (url && !seen.has(url)) {\n seen.add(url);\n out.push(url);\n }\n }\n\n // Pass 2: bare domain URLs (e.g. github.com/foo)\n const bareMatches = text.match(BARE_URL_REGEX) ?? [];\n for (const raw of bareMatches) {\n const url = normalizeUrl(raw);\n if (url && !seen.has(url)) {\n seen.add(url);\n out.push(url);\n }\n }\n\n return out;\n}\n\nconst SENSITIVE_FIELD_KEYS = new Set([\n \"secret\",\n \"webhooksecret\",\n \"password\",\n \"apikey\",\n \"token\",\n \"accesstoken\",\n \"refreshtoken\",\n \"privatekey\",\n \"authtoken\",\n \"bearertoken\",\n \"clientsecret\",\n]);\n\n/**\n * Recursively redacts sensitive field values from an arbitrary payload before\n * it is passed to a structured logger. Matches field names case-insensitively\n * and ignoring underscores, so `api_key`, `apiKey`, and `API_KEY` all match.\n * Non-sensitive fields are passed through unchanged. Never mutates the input —\n * returns a new value.\n *\n * Intended for structured-log redaction only. Do NOT use as a security\n * boundary for data in motion.\n *\n * @param value - Arbitrary JSON-like payload (query object, config blob, etc.)\n * @returns A new value with sensitive fields replaced by `\"[redacted]\"`.\n */\nexport function redactSensitiveFields(value: unknown): unknown {\n if (value === null || typeof value !== \"object\") return value;\n if (Array.isArray(value)) {\n return value.map((item) => redactSensitiveFields(item));\n }\n const out: Record<string, unknown> = {};\n for (const [key, inner] of Object.entries(value as Record<string, unknown>)) {\n const normalized = key.toLowerCase().replace(/_/g, \"\");\n if (SENSITIVE_FIELD_KEYS.has(normalized)) {\n out[key] = \"[redacted]\";\n } else {\n out[key] = redactSensitiveFields(inner);\n }\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool.helpers.js","sourceRoot":"/","sources":["shared/agent/tool.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport type { ModelConfig } from \"./model.config.js\";\nimport { deriveAllowedNetworkIds, scopeFromNetworkId } from \"./tool.scope.js\";\nimport type { ToolScopeType } from \"./tool.scope.js\";\nimport type { UserIdentity } from \"../schemas/identity.schema.js\";\nimport type { ChatGraphCompositeDatabase, NetworkMembership, UserRecord, UserDatabase, SystemDatabase, NegotiationGraphDatabase } from \"../interfaces/database.interface.js\";\nimport type { Scraper } from \"../interfaces/scraper.interface.js\";\nimport type { Cache, HydeCache } from \"../interfaces/cache.interface.js\";\nimport type { CompiledOpportunityGraph } from \"../../opportunity/opportunity.discover.js\";\nimport type { IntegrationAdapter } from \"../interfaces/integration.interface.js\";\nimport type { ContactServiceAdapter } from \"../interfaces/contact.interface.js\";\nimport type { ProfileEnricher } from \"../interfaces/enrichment.interface.js\";\nimport type { IntentGraphQueue } from \"../interfaces/queue.interface.js\";\nimport type { ChatSessionReader } from \"../interfaces/chat-session.interface.js\";\nimport type { ChatSummaryReader } from \"../interfaces/chat-summary.interface.js\";\nimport type { ChatMessageWriter } from \"../interfaces/chat-message-writer.interface.js\";\nimport type { QuestionGeneratorReader } from \"../interfaces/question-generator.interface.js\";\nimport type { NegotiationSummaryReader } from \"../interfaces/negotiation-summary.interface.js\";\nimport type { Embedder } from \"../interfaces/embedder.interface.js\";\nimport type { AgentDatabase } from \"../interfaces/agent.interface.js\";\nimport type { NegotiationTimeoutQueue } from \"../interfaces/negotiation-events.interface.js\";\nimport type { AgentDispatcher } from \"../interfaces/agent-dispatcher.interface.js\";\nimport type { DeliveryLedger } from \"../interfaces/delivery-ledger.interface.js\";\nimport type { MintConnectLink } from \"../interfaces/connect-link.interface.js\";\nimport type { ChatQuestionsHost, QuestionerDatabase } from \"../interfaces/questioner.interface.js\";\nimport type { QuestionerEnqueueFn } from \"../../questioner/questioner.types.js\";\nimport type { PendingQuestionSummary } from \"../schemas/pending-question.schema.js\";\nimport type { QuestionMode } from \"../schemas/question.schema.js\";\nimport type { DiscoveryRunQueue, DiscoveryRunStore } from \"../interfaces/discovery-run.interface.js\";\nimport type { EnrichmentRunQueue, EnrichmentRunStore } from \"../interfaces/enrichment-run.interface.js\";\n\nexport type IdentityContext = UserIdentity | null;\n\nexport interface ToolErrorReport {\n operation: string;\n subsystem?: string;\n toolName?: string;\n userId?: string;\n tags?: Record<string, string | number | boolean | null | undefined>;\n context?: Record<string, unknown>;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// COMPILED GRAPH TYPE\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** Minimal interface for an invokable compiled LangGraph. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type CompiledGraph = { invoke: (input: any) => Promise<any> };\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TOOL CONTEXT TYPES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Resolved context available to every tool handler.\n * Contains the current user and optional network identity, resolved from DB at init.\n * The LLM can see this context (via system prompt) but cannot change it.\n */\nexport interface ResolvedToolContext {\n // Legacy flat fields (kept for backwards compatibility in tools/prompts).\n userId: string;\n userName: string;\n userEmail: string;\n /** Legacy focused network alias. Prefer `scopeType`/`scopeId` in new code. */\n networkId?: string;\n /** Focused request scope type: `network` for community focus, `intent` for selected-intent focus. */\n scopeType?: ToolScopeType;\n /** Focused request scope id. Network scope uses a network id; intent scope uses an intent id. */\n scopeId?: string;\n indexName?: string;\n /** True when chat is network-scoped and the user owns the index. */\n isOwner?: boolean;\n // Rich identity context for prompt/tool orchestration.\n user: UserRecord;\n userProfile: IdentityContext;\n userNetworks: NetworkMembership[];\n /**\n * @deprecated indexScope is legacy concrete network reach. New code should derive reach\n * from `scopeType`/`scopeId` plus `userNetworks` via `tool.scope.ts`.\n * Removed after call sites are migrated in this plan.\n */\n indexScope: string[];\n scopedIndex?: {\n id: string;\n title: string;\n prompt: string | null;\n type?: string;\n metadata?: Record<string, unknown>;\n permissions?: Record<string, unknown>;\n };\n scopedMembershipRole?: \"owner\" | \"member\";\n /** True when user has not completed onboarding (onboarding.completedAt is null). */\n isOnboarding: boolean;\n /** True when the user has a non-empty name. */\n hasName: boolean;\n /** Chat session ID when tools are used in a chat; used for draft opportunities (context.conversationId). */\n sessionId?: string;\n /** True when the request originates from an MCP transport (no interactive UI available). */\n isMcp?: boolean;\n /** Agent ID when the request originates from an API key linked to an agent. */\n agentId?: string;\n /**\n * Receiver's rendering surface declared by the MCP client via the\n * `x-index-surface` request header. `'telegram'` means the MCP response is\n * being rendered inside a Telegram chat; anything\n * else (including `undefined`) is treated as web. Forwarded into\n * `mintConnectLink` so the click-time redirect can branch.\n */\n clientSurface?: 'telegram' | 'web';\n /**\n * True when the CONTACTS_ENABLED feature flag is on. Carried from the\n * composition root so prompt modules can gate contact-import guidance —\n * when false/unset, the contacts prompt module is not injected, so the\n * orchestrator never advertises Gmail import / add_contact (whose tools\n * are also de-registered). Fail-closed: treat only `true` as enabled.\n */\n contactsEnabled?: boolean;\n}\n\n/**\n * Dependencies passed when creating tools for a user session.\n * Includes DB adapters, embedder, and scraper.\n *\n * Note: userDb and systemDb are optional inputs - if not provided, createChatTools\n * will create them internally from the chatDatabaseAdapter singleton.\n */\nexport interface ToolContext {\n userId: string;\n /** @deprecated Use userDb or systemDb instead. Kept for backwards compatibility. */\n database: ChatGraphCompositeDatabase;\n /** Context-bound database for accessing the authenticated user's own resources. Created internally if not provided. */\n userDb?: UserDatabase;\n /** Context-bound database for LLM/system operations on cross-user resources within shared networks. Created internally if not provided. */\n systemDb?: SystemDatabase;\n embedder: Embedder;\n scraper: Scraper;\n /** When set, chat is scoped to this network; converted to `{ scopeType: 'network', scopeId: networkId }` at the boundary. */\n networkId?: string;\n /** Focused request scope type: `network` or `intent`. */\n scopeType?: ToolScopeType;\n /** Focused request scope id. Network scope uses a network id; intent scope uses an intent id. */\n scopeId?: string;\n /** @deprecated indexScope is legacy; use `scopeType`/`scopeId`, retained until wiring phases migrate call sites. */\n indexScope?: string[];\n /** Chat session ID when creating tools for a chat; enables draft opportunities with context.conversationId. */\n sessionId?: string;\n\n // ─── Protocol-level dependencies (injected by composition root) ──────────\n /** General-purpose cache (e.g. for tool results). */\n cache: Cache;\n /** Dedicated cache for HyDE graph (may be same instance as cache). */\n hydeCache: HydeCache;\n /** External integration platform adapter (OAuth, tool actions). */\n integration: IntegrationAdapter;\n /** Queue for enqueuing follow-up intent processing (HyDE generation/deletion). */\n intentQueue: IntentGraphQueue;\n /** Contact management operations. */\n contactService: ContactServiceAdapter;\n /**\n * When false (or unset), the contact import / manual-add tools\n * (import_contacts, add_contact, import_gmail_contacts) are not registered.\n * Injected by the composition root from CONTACTS_ENABLED. Read/remove/search\n * contact tools are always registered.\n */\n contactsEnabled?: boolean;\n /** Chat session reader for loading conversation history. */\n chatSession: ChatSessionReader;\n /** Read-through chat-session digest. Optional; consumers fall back to undefined `chatContext`. */\n chatSummary?: ChatSummaryReader;\n /** Writes user messages into the user's most-recent chat session (Slice 5 MCP elicitation). */\n chatMessageWriter?: ChatMessageWriter;\n /** Decision-question generator. Optional; consumers fall back to no `questions`. */\n questionGenerator?: QuestionGeneratorReader;\n /**\n * Optional async question enqueue callback. When provided, question generation\n * is dispatched asynchronously to the QuestionerQueue instead of running inline.\n * Injected by the composition root when QUESTIONER_ENABLED=true.\n */\n questionerEnqueue?: QuestionerEnqueueFn;\n /**\n * Lookup pending questions for a user, optionally filtered by source,\n * detection mode, selected intent scope, or capped by count.\n */\n findPendingQuestions?: (\n userId: string,\n filters?: {\n sourceType?: string;\n sourceId?: string;\n scopeType?: 'intent';\n scopeId?: string;\n networkId?: string;\n modes?: QuestionMode[];\n limit?: number;\n },\n ) => Promise<PendingQuestionSummary[]>;\n /**\n * Record the client's explicit answer to a pending question through the\n * host's question-answer pipeline (atomic pending→answered flip + answered\n * events). Returns false when the question is not pending for this user\n * (already answered/dismissed, expired, or not theirs). Injected by the\n * composition root — absent when question delivery is disabled.\n */\n answerPendingQuestion?: (\n userId: string,\n questionId: string,\n answer: { selectedOptions: string[]; freeText?: string },\n ) => Promise<boolean>;\n /** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */\n negotiationSummary?: NegotiationSummaryReader;\n /**\n * Host bridge for the orchestrator's blocking `ask_user_question` tool\n * (synchronous chat-question persist + in-stream answer wait). Injected by\n * the backend composition root; when absent the tool is not registered.\n */\n chatQuestions?: ChatQuestionsHost;\n /**\n * Resolve a user's global user_context paragraph (profile-replacing identity\n * text), generating it on demand when absent. Mirrors `ToolDeps.getUserContextText`\n * so chat-path tool factories can forward it.\n */\n getUserContextText?: (userId: string) => Promise<string>;\n /** Profile enrichment from external data sources. */\n enricher: ProfileEnricher;\n /** Database adapter for negotiation/conversation operations. */\n negotiationDatabase: NegotiationGraphDatabase;\n /** Integration importer for bulk contact import from toolkits. */\n integrationImporter: {\n importContacts(userId: string, toolkit: string): Promise<{\n imported: number;\n skipped: number;\n newContacts: number;\n existingContacts: number;\n }>;\n };\n /** Factory for user-scoped database access. */\n createUserDatabase: (db: ChatGraphCompositeDatabase, userId: string) => UserDatabase;\n /** Factory for system-scoped database access. */\n createSystemDatabase: (db: ChatGraphCompositeDatabase, userId: string, indexScope: string[], embedder?: Embedder) => SystemDatabase;\n /** Optional runtime LLM config. Pass to override env vars for API key, model, etc. */\n modelConfig?: ModelConfig;\n /** Manages negotiation timeout jobs (optional — enables AI fallback on external agent timeout). */\n negotiationTimeoutQueue?: NegotiationTimeoutQueue;\n /** Agent registry database adapter (optional — absent when host does not support agents). */\n agentDatabase?: AgentDatabase;\n /** Grants the default system-agent permissions after onboarding (optional). */\n grantDefaultSystemPermissions?: (userId: string) => Promise<void>;\n /** Dispatcher for routing negotiation turns to personal agents (optional — falls back to system AI). */\n agentDispatcher?: AgentDispatcher;\n /** Enqueue a negotiate_existing job after introducer approval (optional). */\n queueNegotiateExisting?: (opportunityId: string, userId: string) => Promise<void>;\n /** Delivery ledger for committing opportunity delivery rows (optional — absent in chat context). */\n deliveryLedger?: DeliveryLedger;\n /** Persistence for async MCP discovery runs (optional — absent in non-MCP/test contexts). */\n discoveryRuns?: DiscoveryRunStore;\n /** Queue for async MCP discovery run execution (optional — absent in non-MCP/test contexts). */\n discoveryRunQueue?: DiscoveryRunQueue;\n /** Persistence for async MCP profile runs (optional — absent in non-MCP/test contexts). */\n enrichmentRuns?: EnrichmentRunStore;\n /** Queue for async MCP profile run execution (optional — absent in non-MCP/test contexts). */\n enrichmentRunQueue?: EnrichmentRunQueue;\n /**\n * Legacy direct-token minting for opportunity accept redirects.\n * Prefer `mintConnectLink` for user-facing links.\n */\n mintConnectToken?: (userId: string, opportunityId: string) => Promise<string>;\n /** Mints (or reuses) a short connect link, snapshotting the greeting (optional — absent in non-MCP contexts). */\n mintConnectLink?: MintConnectLink;\n /** Frontend base URL for building profile links (e.g. https://index.network, optional). */\n frontendUrl?: string;\n /** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */\n apiBaseUrl?: string;\n /** Persistence for structured questions generated by the QuestionerAgent (optional). */\n questionerDatabase?: QuestionerDatabase;\n /** Optional host-side error reporter for swallowed protocol/tool errors. */\n reportToolError?: (error: unknown, report: ToolErrorReport) => void;\n /**\n * Optional host-side per-principal MCP call throttle. Invoked once per MCP\n * tool dispatch (after identity resolves, before any DB work). When the\n * returned decision is `allowed: false`, the dispatch short-circuits with a\n * rate-limit error carrying `retryAfterSec`. Absent in chat/test contexts.\n */\n mcpRateLimiter?: (input: { userId: string; agentId?: string; toolName: string }) => Promise<{\n allowed: boolean;\n retryAfterSec?: number;\n limit?: number;\n scope?: 'tool' | 'principal';\n }>;\n}\n\n/**\n * All external dependencies needed to initialize the protocol tool engine.\n * The host application (composition root) must provide concrete implementations.\n * This is the subset of ToolContext that is NOT per-request (no userId, indexId, sessionId).\n */\nexport type ProtocolDeps = Omit<ToolContext, 'userId' | 'indexId' | 'sessionId' | 'userDb' | 'systemDb'>;\n\n/**\n * Thrown when a requested chat scope is invalid for the authenticated user.\n * Controllers can map this to an HTTP status code.\n */\nexport class ChatContextAccessError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly code: \"USER_NOT_FOUND\" | \"INDEX_NOT_FOUND\" | \"INDEX_MEMBERSHIP_REQUIRED\"\n ) {\n super(message);\n this.name = \"ChatContextAccessError\";\n }\n}\n\n/**\n * Resolve the canonical context used by chat tools and system prompt.\n * This preloads user identity, profile, network memberships, and scoped index role.\n */\nexport async function resolveChatContext(params: {\n database: Pick<\n ChatGraphCompositeDatabase,\n \"getUser\" | \"getProfile\" | \"getNetworkMemberships\" | \"getNetworkMembership\" | \"getNetwork\" | \"isIndexOwner\" | \"isNetworkMember\" | \"getUserContext\"\n >;\n userId: string;\n networkId?: string;\n /** Chat session ID for draft opportunities (stored as context.conversationId). */\n sessionId?: string;\n /** CONTACTS_ENABLED flag, forwarded onto the resolved context for prompt gating. */\n contactsEnabled?: boolean;\n}): Promise<ResolvedToolContext> {\n const { database, userId, networkId, sessionId, contactsEnabled } = params;\n\n const [user, rawProfile, userNetworks, globalContext] = await Promise.all([\n database.getUser(userId),\n database.getProfile(userId),\n database.getNetworkMemberships(userId),\n // The premise-derived global user_context paragraph. getProfile deliberately\n // leaves `context` empty (WS8: narrative lives in user_contexts, not users);\n // without this read the system prompt's only narrative is the stale onboarding\n // bio, which resurrects facts the user has since retracted. Best-effort: a\n // missing row or a minimal test adapter degrades to the empty string.\n Promise.resolve()\n .then(() => database.getUserContext?.(userId, null))\n .catch(() => null),\n ]);\n\n const userProfile: IdentityContext = rawProfile ?? null;\n if (userProfile && !userProfile.context && globalContext?.text) {\n userProfile.context = globalContext.text;\n }\n\n if (!user) {\n throw new ChatContextAccessError(\n \"User not found\",\n 404,\n \"USER_NOT_FOUND\"\n );\n }\n\n let scopedIndex: ResolvedToolContext[\"scopedIndex\"] = undefined;\n let scopedMembershipRole: ResolvedToolContext[\"scopedMembershipRole\"] = undefined;\n let isOwner = false;\n let indexName: string | undefined;\n\n if (networkId) {\n const [index, isMember, owner] = await Promise.all([\n database.getNetwork(networkId),\n database.isNetworkMember(networkId, userId),\n database.isIndexOwner(networkId, userId),\n ]);\n\n if (!index) {\n throw new ChatContextAccessError(\n \"Index not found\",\n 404,\n \"INDEX_NOT_FOUND\"\n );\n }\n\n if (!isMember) {\n throw new ChatContextAccessError(\n \"You are not a member of this network\",\n 403,\n \"INDEX_MEMBERSHIP_REQUIRED\"\n );\n }\n\n let membership = userNetworks.find((m) => m.networkId === index.id);\n if (membership === undefined) {\n membership = (await database.getNetworkMembership(index.id, userId)) ?? undefined;\n }\n scopedIndex = {\n id: index.id,\n title: index.title,\n prompt: membership?.indexPrompt ?? null,\n type: index.type ?? 'community',\n metadata: index.metadata ?? {},\n permissions: index.permissions ?? {},\n };\n isOwner = owner;\n indexName = index.title;\n scopedMembershipRole = owner ? \"owner\" : \"member\";\n }\n\n const userName = user.name ?? \"Unknown\";\n const userEmail = user.email ?? \"\";\n const hasName = !!user.name?.trim();\n\n const scope = scopeFromNetworkId(networkId);\n\n // Deprecated compatibility reach. New call sites should call\n // deriveAllowedNetworkIds({ memberships: userNetworks, ...scope }) directly.\n const allowedNetworkIds = deriveAllowedNetworkIds({\n memberships: userNetworks,\n ...scope,\n });\n\n return {\n userId,\n userName,\n userEmail,\n networkId,\n ...scope,\n indexName,\n isOwner,\n user,\n userProfile,\n userNetworks,\n indexScope: allowedNetworkIds,\n scopedIndex,\n scopedMembershipRole,\n isOnboarding: !(user.onboarding?.completedAt),\n hasName,\n contactsEnabled,\n ...(sessionId !== undefined ? { sessionId } : {}),\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// DEFINE TOOL TYPE\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Type for the `defineTool` closure created in `createChatTools`.\n * Auto-injects resolved context and provides uniform logging / error handling.\n */\nexport type DefineTool = <T extends z.ZodType>(opts: {\n name: string;\n description: string;\n querySchema: T;\n handler: (input: { context: ResolvedToolContext; query: z.infer<T> }) => Promise<string>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n}) => any;\n\n/**\n * A raw tool definition before LangChain wrapping.\n * Used by the tool registry for direct HTTP invocation.\n */\nexport interface RawToolDefinition {\n name: string;\n description: string;\n schema: z.ZodType;\n handler: (input: { context: ResolvedToolContext; query: unknown }) => Promise<string>;\n}\n\n/**\n * Registry mapping tool names to their raw definitions.\n */\nexport type ToolRegistry = Map<string, RawToolDefinition>;\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TOOL DEPENDENCIES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Shared dependencies available to all tool domain factories.\n * Passed by `createChatTools` after compiling all subgraphs.\n */\nexport interface ToolDeps {\n /** @deprecated Use userDb or systemDb instead. Kept for backwards compatibility. */\n database: ChatGraphCompositeDatabase;\n /** Context-bound database for accessing the authenticated user's own resources. */\n userDb: UserDatabase;\n /** Context-bound database for LLM/system operations on cross-user resources within shared networks. */\n systemDb: SystemDatabase;\n scraper: Scraper;\n embedder: import('../interfaces/embedder.interface.js').Embedder;\n cache: Cache;\n integration: IntegrationAdapter;\n contactService: ContactServiceAdapter;\n /**\n * When false (or unset), the contact import / manual-add tools\n * (import_contacts, add_contact, import_gmail_contacts) are not registered.\n * Injected by the composition root from CONTACTS_ENABLED. Read/remove/search\n * contact tools are always registered.\n */\n contactsEnabled?: boolean;\n integrationImporter: {\n importContacts(userId: string, toolkit: string): Promise<{\n imported: number;\n skipped: number;\n newContacts: number;\n existingContacts: number;\n }>;\n };\n enricher: ProfileEnricher;\n /** Database adapter for negotiation/conversation operations. */\n negotiationDatabase: NegotiationGraphDatabase;\n /** Chat session reader for exposing the caller's past conversations as MCP tools. */\n chatSession?: ChatSessionReader;\n /** Read-through chat-session digest. Optional; consumers fall back to undefined `chatContext`. */\n chatSummary?: ChatSummaryReader;\n /**\n * Test seam for opportunity discovery helpers. Production compositions leave\n * this unset so tools call the real discovery module directly.\n */\n opportunityDiscovery?: {\n runDiscoverFromQuery?: (input: unknown) => Promise<unknown>;\n continueDiscovery?: (input: unknown) => Promise<unknown>;\n };\n /**\n * Test seam for opportunity card presentation helpers. Production\n * compositions leave this unset so tools construct the real presenter.\n */\n opportunityPresentation?: {\n createPresenter?: () => { presentHomeCard(input: unknown): Promise<unknown> };\n gatherPresenterContext?: (...args: unknown[]) => Promise<unknown>;\n };\n /** Writes user messages into the user's most-recent chat session (Slice 5 MCP elicitation). */\n chatMessageWriter?: ChatMessageWriter;\n /** Decision-question generator. Optional; consumers fall back to no `questions`. */\n questionGenerator?: QuestionGeneratorReader;\n /**\n * Optional async question enqueue callback. When provided, question generation\n * is dispatched asynchronously to the QuestionerQueue instead of running inline\n * via the `questionGenerator`. Injected by the composition root when\n * QUESTIONER_ENABLED=true.\n */\n questionerEnqueue?: QuestionerEnqueueFn;\n /**\n * Lookup pending questions for a user, optionally filtered by source,\n * detection mode, or capped by count (hosts apply `limit` SQL-side).\n * Used by tools to attach contextually relevant questions to their results.\n * Injected by the composition root — absent when question delivery is disabled.\n */\n findPendingQuestions?: (\n userId: string,\n filters?: {\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 /** Restrict to questions whose actor carries this network id. */\n networkId?: string;\n /** Restrict to questions whose detection mode is in this set. */\n modes?: QuestionMode[];\n /** Maximum rows to return; hosts should apply this in the query. */\n limit?: number;\n },\n ) => Promise<PendingQuestionSummary[]>;\n /**\n * Record the client's explicit answer to a pending question through the\n * host's question-answer pipeline (atomic pending→answered flip + answered\n * events). Returns false when the question is not pending for this user.\n * Injected by the composition root — absent when question delivery is disabled.\n */\n answerPendingQuestion?: (\n userId: string,\n questionId: string,\n answer: { selectedOptions: string[]; freeText?: string },\n ) => Promise<boolean>;\n /** Negotiation-digest summarizer. Optional; consumers fall back to deterministic digests. */\n negotiationSummary?: NegotiationSummaryReader;\n /**\n * Host bridge for the orchestrator's blocking `ask_user_question` tool\n * (synchronous chat-question persist + in-stream answer wait). Injected by\n * the backend composition root; when absent the tool is not registered.\n */\n chatQuestions?: ChatQuestionsHost;\n /** Manages negotiation timeout jobs (optional — enables AI fallback on external agent timeout). */\n negotiationTimeoutQueue?: NegotiationTimeoutQueue;\n /** Agent registry database adapter (optional — absent when host does not support agents). */\n agentDatabase?: AgentDatabase;\n /** Grants the default system-agent permissions after onboarding (optional). */\n grantDefaultSystemPermissions?: (userId: string) => Promise<void>;\n /** Dispatcher for routing negotiation turns to personal agents (optional — falls back to system AI). */\n agentDispatcher?: AgentDispatcher;\n /** Delivery ledger for committing opportunity delivery rows (optional — absent in chat context). */\n deliveryLedger?: DeliveryLedger;\n /** Persistence for async MCP discovery runs (optional — absent in non-MCP/test contexts). */\n discoveryRuns?: DiscoveryRunStore;\n /** Queue for async MCP discovery run execution (optional — absent in non-MCP/test contexts). */\n discoveryRunQueue?: DiscoveryRunQueue;\n /** Persistence for async MCP profile runs (optional — absent in non-MCP/test contexts). */\n enrichmentRuns?: EnrichmentRunStore;\n /** Queue for async MCP profile run execution (optional — absent in non-MCP/test contexts). */\n enrichmentRunQueue?: EnrichmentRunQueue;\n /**\n * Legacy direct-token minting for opportunity accept redirects.\n * Prefer `mintConnectLink` for user-facing links.\n */\n mintConnectToken?: (userId: string, opportunityId: string) => Promise<string>;\n /** Mints (or reuses) a short connect link, snapshotting the greeting (optional — absent in non-MCP contexts). */\n mintConnectLink?: MintConnectLink;\n /** Frontend base URL for building profile links (e.g. https://index.network, optional). */\n frontendUrl?: string;\n /** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */\n apiBaseUrl?: string;\n /** Optional host-side error reporter for swallowed protocol/tool errors. */\n reportToolError?: (error: unknown, report: ToolErrorReport) => void;\n /**\n * Optional host-side per-principal MCP call throttle. Invoked once per MCP\n * tool dispatch (after identity resolves, before any DB work). When the\n * returned decision is `allowed: false`, the dispatch short-circuits with a\n * rate-limit error carrying `retryAfterSec`. Absent in chat/test contexts.\n */\n mcpRateLimiter?: (input: { userId: string; agentId?: string; toolName: string }) => Promise<{\n allowed: boolean;\n retryAfterSec?: number;\n limit?: number;\n scope?: 'tool' | 'principal';\n }>;\n graphs: {\n profile: CompiledGraph;\n intent: CompiledGraph;\n index: CompiledGraph;\n networkMembership: CompiledGraph;\n intentIndex: CompiledGraph;\n opportunity: CompiledOpportunityGraph;\n premise: CompiledGraph;\n };\n /**\n * Optional network ranking override for `read_networks`. Injected by tests or custom compositions.\n * When absent, defaults to `NetworkRecommender.invoke()` with a lazy module-level singleton.\n */\n networkRanker?: (input: {\n userContext: string;\n networks: Array<{ networkId: string; renderedContext: string }>;\n }) => Promise<{ rankedNetworkIds: string[] } | null>;\n /**\n * Resolve a user's global user_context paragraph (profile-replacing identity text),\n * generating it on demand when absent. Injected by the backend composition root\n * (`ensureGlobalUserContext`). When absent, onboarding network ranking is skipped.\n */\n getUserContextText?: (userId: string) => Promise<string>;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TOOL RESULT HELPERS\n// ═══════════════════════════════════════════════════════════════════════════════\n\nexport function success<T>(data: T): string {\n return JSON.stringify({ success: true, data });\n}\n\nexport function error(\n message: string,\n debugSteps?: Array<{ step: string; detail?: string; data?: Record<string, unknown> }>\n): string {\n return JSON.stringify({\n success: false,\n error: message,\n ...(debugSteps?.length ? { debugSteps } : {}),\n });\n}\n\n/** Return needsClarification for missing required fields. */\nexport function needsClarification(params: {\n missingFields: string[];\n message: string;\n}): string {\n return JSON.stringify({\n success: false,\n needsClarification: true,\n ...params,\n });\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CONSTANTS & UTILITIES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** Matches http/https URLs in text; captures full URL. */\nconst URL_IN_TEXT_REGEX = /https?:\\/\\/[^\\s\"'<>)\\]]+/gi;\n\n/**\n * Matches bare domain URLs without protocol (e.g. github.com/foo, www.example.com).\n * Requires at least a SLD.TLD pattern followed by optional path.\n * Negative lookbehind ensures we don't double-match URLs already caught by URL_IN_TEXT_REGEX.\n */\nconst BARE_URL_REGEX = /(?<!\\w:\\/\\/)(?<![/\\w])(?:www\\.)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.(?:com|org|net|io|dev|co|ai|app|xyz|me|info|gg|so|sh|cc|ly|fm|tv|to|tech|design|network|world|edu|gov|mil|int|us|uk|eu|de|fr|ca|au|jp|cn|in|br|nl|se|no|fi|dk|ch|at|be|it|es|pt|pl|cz|ru|kr|tw|hk|sg|nz|za|mx|ar|cl|id|ph|th|vn|my|ie)(?:\\/[^\\s\"'<>)\\]]*)?/gi;\n\n/** UUID v4 format: 8-4-4-4-12 hex chars (e.g. c2505011-2e45-426e-81dd-b9abb9b72023) */\nexport const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Resolves an array of network IDs to their display titles.\n * Skips any IDs that don't resolve (deleted or invalid networks).\n */\nexport async function resolveIndexNames(\n database: { getNetwork(id: string): Promise<{ id: string; title: string } | null> },\n networkIds: string[]\n): Promise<string[]> {\n if (networkIds.length === 0) return [];\n const results = await Promise.all(\n networkIds.map(id => database.getNetwork(id))\n );\n return results.filter(Boolean).map(idx => idx!.title);\n}\n\n/**\n * Normalize a URL string: if it lacks a protocol, prepend \"https://\".\n * Returns the normalized URL or null if the result is not a valid URL.\n */\nexport function normalizeUrl(raw: string): string | null {\n let url = raw.replace(/[.,;:!?)]+$/, \"\").trim();\n if (!/^https?:\\/\\//i.test(url)) {\n url = `https://${url}`;\n }\n try {\n new URL(url);\n return url;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract unique, valid URLs from a string (e.g. user message or details).\n * Handles both full URLs (https://...) and bare domains (github.com/...).\n */\nexport function extractUrls(text: string): string[] {\n if (!text || typeof text !== \"string\") return [];\n\n const seen = new Set<string>();\n const out: string[] = [];\n\n // Pass 1: full protocol URLs\n const fullMatches = text.match(URL_IN_TEXT_REGEX) ?? [];\n for (const raw of fullMatches) {\n const url = normalizeUrl(raw);\n if (url && !seen.has(url)) {\n seen.add(url);\n out.push(url);\n }\n }\n\n // Pass 2: bare domain URLs (e.g. github.com/foo)\n const bareMatches = text.match(BARE_URL_REGEX) ?? [];\n for (const raw of bareMatches) {\n const url = normalizeUrl(raw);\n if (url && !seen.has(url)) {\n seen.add(url);\n out.push(url);\n }\n }\n\n return out;\n}\n\nconst SENSITIVE_FIELD_KEYS = new Set([\n \"secret\",\n \"webhooksecret\",\n \"password\",\n \"apikey\",\n \"token\",\n \"accesstoken\",\n \"refreshtoken\",\n \"privatekey\",\n \"authtoken\",\n \"bearertoken\",\n \"clientsecret\",\n]);\n\n/**\n * Recursively redacts sensitive field values from an arbitrary payload before\n * it is passed to a structured logger. Matches field names case-insensitively\n * and ignoring underscores, so `api_key`, `apiKey`, and `API_KEY` all match.\n * Non-sensitive fields are passed through unchanged. Never mutates the input —\n * returns a new value.\n *\n * Intended for structured-log redaction only. Do NOT use as a security\n * boundary for data in motion.\n *\n * @param value - Arbitrary JSON-like payload (query object, config blob, etc.)\n * @returns A new value with sensitive fields replaced by `\"[redacted]\"`.\n */\nexport function redactSensitiveFields(value: unknown): unknown {\n if (value === null || typeof value !== \"object\") return value;\n if (Array.isArray(value)) {\n return value.map((item) => redactSensitiveFields(item));\n }\n const out: Record<string, unknown> = {};\n for (const [key, inner] of Object.entries(value as Record<string, unknown>)) {\n const normalized = key.toLowerCase().replace(/_/g, \"\");\n if (SENSITIVE_FIELD_KEYS.has(normalized)) {\n out[key] = \"[redacted]\";\n } else {\n out[key] = redactSensitiveFields(inner);\n }\n }\n return out;\n}\n"]}
|