@indexnetwork/protocol 6.6.0-rc.386.1 → 6.6.1-rc.387.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/dist/chat/chat.agent.d.ts +6 -0
- package/dist/chat/chat.agent.d.ts.map +1 -1
- package/dist/chat/chat.agent.js +119 -0
- package/dist/chat/chat.agent.js.map +1 -1
- package/dist/chat/chat.persona.d.ts +5 -0
- package/dist/chat/chat.persona.d.ts.map +1 -1
- package/dist/chat/chat.persona.js.map +1 -1
- package/dist/chat/chat.prompt.modules.d.ts +2 -0
- package/dist/chat/chat.prompt.modules.d.ts.map +1 -1
- package/dist/chat/chat.prompt.modules.js.map +1 -1
- package/dist/chat/reporter.persona.d.ts.map +1 -1
- package/dist/chat/reporter.persona.js +2 -1
- package/dist/chat/reporter.persona.js.map +1 -1
- package/dist/chat/reporter.prompt.d.ts +4 -0
- package/dist/chat/reporter.prompt.d.ts.map +1 -1
- package/dist/chat/reporter.prompt.js +39 -5
- package/dist/chat/reporter.prompt.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,7 @@ See [STABILITY.md](./STABILITY.md) for the public-contract and tier definitions.
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
15
|
### Added
|
|
16
|
+
- Harden reporter turn handling so only the exact kickoff produces the detailed briefing, focused follow-ups stay narrow, and one-turn-local contextual natural-language confirmation deterministically bypasses the model and tools in favor of the visible confirmation card (IND-493).
|
|
16
17
|
- Dark-gated reporter cleanup-action proposals for retracting owner premises, narrowing owned signals, and pausing owned signals (IND-490 PR1). `propose_cleanup_actions` is conditionally registered only when `WEB_AGENT_ACTIONS_ENABLED` is enabled alongside the reporter surface; it validates full owner UUIDs, requires pause evidence, persists a confirmation request, and never mutates data in chat.
|
|
17
18
|
- Read-only `reporter` chat persona for Agent-surface activity reporting (IND-476 PR1), with an exact positive allowlist, self-only narrowing, aggregate-only opportunity reporting, grounded `report_agent_activity` metrics, and a public briefing kickoff marker. Mutation, discovery, negotiation, memory, question-answering, scraping, and counterparty identity surfaces remain unavailable.
|
|
18
19
|
- Restricted `signal` chat persona for the main-web cutover (IND-449), built on the existing persona-neutral runtime with a custom signals/profile prompt, an exact positive allowlist, proposal hallucination recovery, and the discovery-coupled create-intent callback disabled. Signal-specific wrappers clamp focused intent/network reads to owned active intents and current memberships, prohibit other-user membership enumeration, and validate live membership before forwarding network-scoped proposals. Shared orchestrator, MCP, and direct-tool registries are unchanged.
|
|
@@ -235,6 +235,12 @@ export declare class ChatAgent {
|
|
|
235
235
|
* Extracts the text content of the most recent HumanMessage.
|
|
236
236
|
*/
|
|
237
237
|
private static getCurrentUserMessage;
|
|
238
|
+
/**
|
|
239
|
+
* Detects a prior visible action proposal without considering current-turn
|
|
240
|
+
* tool calls. The reporter uses this only to make typed confirmation
|
|
241
|
+
* language contextual rather than executable on its own.
|
|
242
|
+
*/
|
|
243
|
+
static hasPriorAgentActionProposal(messages: BaseMessage[]): boolean;
|
|
238
244
|
/**
|
|
239
245
|
* Async factory: creates a ChatAgent with resolved user/index context.
|
|
240
246
|
* Resolves user/network identity from DB during tool initialization.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.agent.d.ts","sourceRoot":"/","sources":["chat/chat.agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,WAAW,EAA8C,MAAM,0BAA0B,CAAC;AAC9G,OAAO,KAAK,EAAa,WAAW,EAAuB,MAAM,iCAAiC,CAAC;AAInG,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAMjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,iCAAiC,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACjJ,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4CAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"chat.agent.d.ts","sourceRoot":"/","sources":["chat/chat.agent.ts"],"names":[],"mappings":"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"}
|
package/dist/chat/chat.agent.js
CHANGED
|
@@ -20,6 +20,55 @@ import { sanitizeForDebugMeta } from "../shared/observability/debug-meta.sanitiz
|
|
|
20
20
|
import { Timed } from "../shared/observability/performance.js";
|
|
21
21
|
import { requestContext } from "../shared/observability/request-context.js";
|
|
22
22
|
import { deduplicateQuestions } from "./chat.question-dedup.js";
|
|
23
|
+
const AGENT_ACTION_PROPOSAL_FENCE_PATTERN = /```agent_action_proposal\s*\n([\s\S]*?)\n```/g;
|
|
24
|
+
const AGENT_ACTION_PROPOSAL_KEYS = new Set(["proposalId", "actions"]);
|
|
25
|
+
const AGENT_ACTION_KEYS = new Set([
|
|
26
|
+
"type",
|
|
27
|
+
"entityId",
|
|
28
|
+
"currentState",
|
|
29
|
+
"proposedOperation",
|
|
30
|
+
"skipped",
|
|
31
|
+
"reason",
|
|
32
|
+
"description",
|
|
33
|
+
"evidence",
|
|
34
|
+
]);
|
|
35
|
+
const AGENT_ACTION_OPERATIONS = {
|
|
36
|
+
retract_premise: "RETRACT_PREMISE",
|
|
37
|
+
narrow_signal: "NARROW_SIGNAL",
|
|
38
|
+
pause_signal: "PAUSE_SIGNAL",
|
|
39
|
+
};
|
|
40
|
+
function isVisibleAgentActionProposal(payload) {
|
|
41
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
42
|
+
return false;
|
|
43
|
+
const proposal = payload;
|
|
44
|
+
if (Object.keys(proposal).some((key) => !AGENT_ACTION_PROPOSAL_KEYS.has(key)))
|
|
45
|
+
return false;
|
|
46
|
+
if (typeof proposal.proposalId !== "string"
|
|
47
|
+
|| !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(proposal.proposalId)
|
|
48
|
+
|| !Array.isArray(proposal.actions)
|
|
49
|
+
|| proposal.actions.length < 1
|
|
50
|
+
|| proposal.actions.length > 5)
|
|
51
|
+
return false;
|
|
52
|
+
return proposal.actions.every((rawAction) => {
|
|
53
|
+
if (!rawAction || typeof rawAction !== "object" || Array.isArray(rawAction))
|
|
54
|
+
return false;
|
|
55
|
+
const action = rawAction;
|
|
56
|
+
if (Object.keys(action).some((key) => !AGENT_ACTION_KEYS.has(key)))
|
|
57
|
+
return false;
|
|
58
|
+
if (typeof action.type !== "string" || !(action.type in AGENT_ACTION_OPERATIONS))
|
|
59
|
+
return false;
|
|
60
|
+
const type = action.type;
|
|
61
|
+
if (action.proposedOperation !== AGENT_ACTION_OPERATIONS[type])
|
|
62
|
+
return false;
|
|
63
|
+
if (typeof action.entityId !== "string" || !action.entityId.trim())
|
|
64
|
+
return false;
|
|
65
|
+
if (typeof action.currentState !== "string" || !action.currentState.trim())
|
|
66
|
+
return false;
|
|
67
|
+
if (action.skipped !== undefined && typeof action.skipped !== "boolean")
|
|
68
|
+
return false;
|
|
69
|
+
return ["reason", "description", "evidence"].every((key) => action[key] === undefined || typeof action[key] === "string");
|
|
70
|
+
});
|
|
71
|
+
}
|
|
23
72
|
const logger = protocolLogger("ChatAgent");
|
|
24
73
|
// Re-export for external consumers
|
|
25
74
|
export { ITERATION_NUDGE } from "./chat.prompt.js";
|
|
@@ -95,6 +144,48 @@ export class ChatAgent {
|
|
|
95
144
|
}
|
|
96
145
|
return undefined;
|
|
97
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Detects a prior visible action proposal without considering current-turn
|
|
149
|
+
* tool calls. The reporter uses this only to make typed confirmation
|
|
150
|
+
* language contextual rather than executable on its own.
|
|
151
|
+
*/
|
|
152
|
+
static hasPriorAgentActionProposal(messages) {
|
|
153
|
+
let currentHumanIndex = -1;
|
|
154
|
+
let previousHumanIndex = -1;
|
|
155
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
156
|
+
if (messages[index]._getType() !== "human")
|
|
157
|
+
continue;
|
|
158
|
+
if (currentHumanIndex < 0) {
|
|
159
|
+
currentHumanIndex = index;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
previousHumanIndex = index;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (currentHumanIndex < 0 || previousHumanIndex < 0)
|
|
167
|
+
return false;
|
|
168
|
+
let latestAssistant;
|
|
169
|
+
for (let index = currentHumanIndex - 1; index > previousHumanIndex; index -= 1) {
|
|
170
|
+
if (messages[index]._getType() === "ai") {
|
|
171
|
+
latestAssistant = messages[index];
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!latestAssistant || typeof latestAssistant.content !== "string")
|
|
176
|
+
return false;
|
|
177
|
+
AGENT_ACTION_PROPOSAL_FENCE_PATTERN.lastIndex = 0;
|
|
178
|
+
for (const match of latestAssistant.content.matchAll(AGENT_ACTION_PROPOSAL_FENCE_PATTERN)) {
|
|
179
|
+
try {
|
|
180
|
+
if (isVisibleAgentActionProposal(JSON.parse(match[1])))
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// An invalid prior fence is not visible proposal context.
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
98
189
|
/**
|
|
99
190
|
* Async factory: creates a ChatAgent with resolved user/index context.
|
|
100
191
|
* Resolves user/network identity from DB during tool initialization.
|
|
@@ -135,8 +226,18 @@ export class ChatAgent {
|
|
|
135
226
|
const iterCtx = {
|
|
136
227
|
recentTools: extractRecentToolCalls(messages),
|
|
137
228
|
currentMessage: ChatAgent.getCurrentUserMessage(messages),
|
|
229
|
+
hasPriorAgentActionProposal: ChatAgent.hasPriorAgentActionProposal(messages),
|
|
138
230
|
ctx: this.resolvedContext,
|
|
139
231
|
};
|
|
232
|
+
const deterministicResponse = this.persona.resolveDeterministicResponse?.(this.resolvedContext, iterCtx);
|
|
233
|
+
if (deterministicResponse !== undefined && deterministicResponse !== null) {
|
|
234
|
+
const response = new AIMessage(deterministicResponse);
|
|
235
|
+
return {
|
|
236
|
+
shouldContinue: false,
|
|
237
|
+
responseText: deterministicResponse,
|
|
238
|
+
messages: [...messages, response],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
140
241
|
const systemContent = this.persona.buildSystemContent(this.resolvedContext, iterCtx);
|
|
141
242
|
const fullMessages = [
|
|
142
243
|
new SystemMessage(systemContent),
|
|
@@ -579,8 +680,26 @@ export class ChatAgent {
|
|
|
579
680
|
const iterCtx = {
|
|
580
681
|
recentTools: extractRecentToolCalls(messages),
|
|
581
682
|
currentMessage: ChatAgent.getCurrentUserMessage(messages),
|
|
683
|
+
hasPriorAgentActionProposal: ChatAgent.hasPriorAgentActionProposal(messages),
|
|
582
684
|
ctx: this.resolvedContext,
|
|
583
685
|
};
|
|
686
|
+
const deterministicResponse = this.persona.resolveDeterministicResponse?.(this.resolvedContext, iterCtx);
|
|
687
|
+
if (deterministicResponse !== undefined && deterministicResponse !== null) {
|
|
688
|
+
emit({ type: "text_chunk", content: deterministicResponse });
|
|
689
|
+
messages = [...messages, new AIMessage(deterministicResponse)];
|
|
690
|
+
iterationCount++;
|
|
691
|
+
return {
|
|
692
|
+
responseText: deterministicResponse,
|
|
693
|
+
messages,
|
|
694
|
+
iterationCount,
|
|
695
|
+
debugMeta: {
|
|
696
|
+
graph: "agent_loop",
|
|
697
|
+
iterations: iterationCount,
|
|
698
|
+
tools: toolsDebug,
|
|
699
|
+
llm,
|
|
700
|
+
},
|
|
701
|
+
};
|
|
702
|
+
}
|
|
584
703
|
const systemContent = this.persona.buildSystemContent(this.resolvedContext, iterCtx);
|
|
585
704
|
const fullMessages = [
|
|
586
705
|
new SystemMessage(systemContent),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.agent.js","sourceRoot":"/","sources":["chat/chat.agent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatOpenAI } from \"@langchain/openai\";\nimport { AIMessage, BaseMessage, SystemMessage, ToolMessage, AIMessageChunk } from \"@langchain/core/messages\";\nimport type { ChatTools, ToolContext, ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport { resolveChatContext } from \"../shared/agent/tool.helpers.js\";\nimport { scopeFromNetworkId } from \"../shared/agent/tool.scope.js\";\nimport { ITERATION_NUDGE } from \"./chat.prompt.js\";\nimport { ORCHESTRATOR_PERSONA, type ChatPersonaConfig } from \"./chat.persona.js\";\nimport { extractRecentToolCalls, type IterationContext } from \"./chat.prompt.modules.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { createModel, type ModelConfig } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\nimport { sanitizeForDebugMeta } from \"../shared/observability/debug-meta.sanitizer.js\";\nimport type { DebugMetaToolCall, DebugMetaLlm, DebugMetaOrchestratorNegotiations, DebugMetaDiscoveryQuestions } from \"./chat-streaming.types.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport type { Opportunity } from \"../shared/interfaces/database.interface.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { deduplicateQuestions } from \"./chat.question-dedup.js\";\n\nconst logger = protocolLogger(\"ChatAgent\");\n\n// Re-export for external consumers\nexport { ITERATION_NUDGE } from \"./chat.prompt.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Writer callback for streaming custom data out of the graph node.\n * Matches the `config.writer` signature from LangGraphRunnableConfig.\n */\nexport type StreamWriter = (data: unknown) => void;\n\n/**\n * Events emitted by `streamRun()` via the writer callback.\n *\n * - `iteration_start` — new agent loop iteration begins\n * - `llm_start` — LLM begins generating response\n * - `text_chunk` — a token (or group of tokens) of model text\n * - `llm_end` — LLM finished generating (may have tool calls)\n * - `tool_activity` — tool starts or finishes execution\n * - `graph_start` — a LangGraph sub-graph begins inside a tool\n * - `graph_end` — a LangGraph sub-graph completes\n * - `agent_start` — an LLM agent begins inside a graph node\n * - `agent_end` — an LLM agent completes\n * - `opportunity_draft_ready` — an orchestrator-triggered negotiation finalized\n * to `draft` and the card is ready to render inline\n */\nexport type AgentStreamEvent =\n | { type: \"iteration_start\"; iteration: number }\n | { type: \"llm_start\"; iteration: number }\n | { type: \"text_chunk\"; content: string }\n | { type: \"llm_end\"; iteration: number; hasToolCalls: boolean; toolNames?: string[] }\n | { type: \"tool_activity\"; phase: \"start\"; name: string }\n | {\n type: \"tool_activity\";\n phase: \"end\";\n name: string;\n success: boolean;\n summary?: string;\n steps?: Array<{ step: string; detail?: string; data?: Record<string, unknown> }>;\n }\n | { type: \"response_reset\"; reason: string }\n | { type: \"hallucination_detected\"; blockType: string; tool: string }\n | { type: \"graph_start\"; name: string }\n | { type: \"graph_end\"; name: string; durationMs: number }\n | { type: \"phase_start\"; name: string }\n | { type: \"phase_end\"; name: string; durationMs: number }\n | { type: \"agent_start\"; name: string }\n | { type: \"agent_end\"; name: string; durationMs: number; summary: string }\n | {\n // Emitted from the orchestrator branch of OpportunityGraph.negotiateNode\n // each time a per-candidate negotiation resolves to an accepted draft.\n // Carries the opportunity row plus the counterparty's display basics so\n // the frontend can append an inline card to the chat timeline without a\n // second round-trip user lookup.\n type: \"opportunity_draft_ready\";\n opportunityId: string;\n opportunity: Opportunity;\n /** Viewer-centric summary derived from interpretation.reasoning via viewerCentricCardSummary. */\n personalizedSummary?: string;\n counterparty: {\n userId: string;\n name?: string;\n };\n }\n | {\n type: \"negotiation_session_start\";\n opportunityId: string;\n negotiationConversationId: string;\n sourceUserId: string;\n candidateUserId: string;\n candidateName?: string;\n trigger: \"orchestrator\" | \"ambient\";\n startedAt: number;\n }\n | {\n type: \"negotiation_session_end\";\n opportunityId: string;\n negotiationConversationId: string;\n durationMs: number;\n }\n | {\n type: \"negotiation_turn\";\n opportunityId: string;\n negotiationConversationId: string;\n turnIndex: number;\n actor: \"source\" | \"candidate\";\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\" | \"outreach\" | \"withdraw\" | \"decline\" | \"ask_user\";\n reasoning?: string;\n message?: string;\n suggestedRoles?: { ownUser?: string; otherUser?: string };\n durationMs: number;\n }\n | {\n type: \"negotiation_outcome\";\n opportunityId: string;\n outcome:\n | \"accepted\"\n | \"rejected_stalled\"\n | \"waiting_for_agent\"\n | \"timed_out\"\n | \"turn_cap\"\n | \"screened_out\";\n turnCount: number;\n reasoning?: string;\n agreedRoles?: { ownUser?: string; otherUser?: string };\n }\n | {\n // Emitted by the ask_user_question tool after persisting chat-mode\n // questions: the turn is blocked awaiting the user's inline answer.\n type: \"user_question\";\n questions: Array<{\n id: string;\n title: string;\n prompt: string;\n options: Array<{ label: string; description: string }>;\n multiSelect: boolean;\n }>;\n }\n | { type: \"status\"; message: string }\n | { type: \"decision_questions\"; questions: Question[] }\n | { type: \"chat_summarizer_start\"; payload: { sessionId: string } }\n | { type: \"chat_summarizer_end\"; payload: { durationMs: number } }\n | { type: \"question_generator_start\"; payload: { inputMode: \"transcripts\" | \"insights\"; negotiationCount: number; hasChatContext: boolean; truncated?: { originalCount: number; keptCount: number } } }\n | { type: \"question_generator_end\"; payload: { finalCount: number; strategies: QuestionStrategy[]; durationMs: number; inputMode: \"transcripts\" | \"insights\" } };\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CONFIGURATION\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Soft limit: After this many iterations, inject a nudge message.\n */\nexport const SOFT_ITERATION_LIMIT = 8;\n\n/**\n * Hard limit: Force exit after this many iterations to prevent infinite loops.\n */\nexport const HARD_ITERATION_LIMIT = 12;\n\n/**\n * Extract plain text from message content (string or structured block array).\n * Filters to only `type: \"text\"` blocks, discarding tool metadata.\n */\nfunction extractTextContent(content: string | Array<Record<string, unknown>>): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .filter((b): b is { type: \"text\"; text?: string } => (b as { type?: string }).type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n }\n return \"\";\n}\n\n/**\n * Extract plain text from an AIMessageChunk (string content or text blocks).\n */\nfunction extractTextFromChunk(chunk: AIMessageChunk): string {\n return extractTextContent(chunk.content as string | Array<Record<string, unknown>>);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CHAT AGENT CLASS\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Result of a single agent iteration.\n */\nexport interface AgentIterationResult {\n /** Whether the agent wants to continue (made tool calls) or stop (produced final response) */\n shouldContinue: boolean;\n /** Tool calls made in this iteration (if any) */\n toolCalls?: Array<{\n id: string;\n name: string;\n args: Record<string, unknown>;\n }>;\n /** Tool results from executing the tool calls */\n toolResults?: Array<{\n toolCallId: string;\n name: string;\n result: string;\n }>;\n /** Final response text (if agent is done) */\n responseText?: string;\n /** Updated messages array */\n messages: BaseMessage[];\n}\n\n/**\n * ChatAgent: ReAct-style agent that uses tools to help users.\n *\n * The agent operates in a loop:\n * 1. Receive messages (conversation history + tool results)\n * 2. Decide: call tools OR respond to user\n * 3. If tools called: execute them, add results, loop back\n * 4. If response: return final text\n *\n * Use `ChatAgent.create(context)` to construct (async factory).\n */\nexport class ChatAgent {\n private model: ChatOpenAI;\n private tools: ChatTools;\n private toolsByName: Map<string, any>;\n\n /**\n * Private constructor — use `ChatAgent.create()` instead.\n */\n private constructor(\n private resolvedContext: ResolvedToolContext,\n private persona: ChatPersonaConfig,\n tools: ChatTools,\n modelConfig?: ModelConfig,\n ) {\n this.model = createModel(\"chat\", modelConfig);\n\n // Store tools and index by name\n this.tools = tools;\n this.toolsByName = new Map();\n for (const tool of this.tools) {\n this.toolsByName.set(tool.name, tool);\n }\n\n // Bind tools to model\n this.model = this.model.bindTools(this.tools) as ChatOpenAI;\n }\n\n /**\n * Extracts the text content of the most recent HumanMessage.\n */\n private static getCurrentUserMessage(messages: BaseMessage[]): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]._getType() === \"human\") {\n const content = messages[i].content;\n return typeof content === \"string\" ? content : undefined;\n }\n }\n return undefined;\n }\n\n /**\n * Async factory: creates a ChatAgent with resolved user/index context.\n * Resolves user/network identity from DB during tool initialization.\n *\n * @param context - Tool context (database, userId, scope, deps)\n * @param persona - Persona config (prompt builder, toolset, loop behaviors).\n * Defaults to the orchestrator persona.\n */\n static async create(\n context: ToolContext,\n persona: ChatPersonaConfig = ORCHESTRATOR_PERSONA,\n ): Promise<ChatAgent> {\n const { networkId: legacyNetworkId } = context;\n const explicitScope = context.scopeType && context.scopeId\n ? { scopeType: context.scopeType, scopeId: context.scopeId }\n : scopeFromNetworkId(legacyNetworkId);\n const scopedNetworkId = explicitScope.scopeType === 'network' ? explicitScope.scopeId : undefined;\n const resolved: ResolvedToolContext = await resolveChatContext({\n database: context.database,\n userId: context.userId,\n networkId: scopedNetworkId,\n sessionId: context.sessionId,\n contactsEnabled: context.contactsEnabled,\n actionToolsEnabled: context.actionToolsEnabled,\n });\n if (explicitScope.scopeType && explicitScope.scopeId) {\n resolved.scopeType = explicitScope.scopeType;\n resolved.scopeId = explicitScope.scopeId;\n }\n const tools = await persona.createTools(context, resolved);\n return new ChatAgent(resolved, persona, tools, context.modelConfig);\n }\n\n /**\n * Run a single iteration of the agent loop.\n *\n * @param messages - Current conversation including any tool results\n * @param iterationCount - Current iteration number (for soft limit)\n * @returns Result indicating whether to continue and any tool calls/response\n */\n @Timed()\n async runIteration(\n messages: BaseMessage[],\n iterationCount: number,\n ): Promise<AgentIterationResult> {\n const iterCtx: IterationContext = {\n recentTools: extractRecentToolCalls(messages),\n currentMessage: ChatAgent.getCurrentUserMessage(messages),\n ctx: this.resolvedContext,\n };\n const systemContent = this.persona.buildSystemContent(this.resolvedContext, iterCtx);\n\n const fullMessages: BaseMessage[] = [\n new SystemMessage(systemContent),\n ...messages,\n ];\n\n // Add nudge if past soft limit\n if (iterationCount >= SOFT_ITERATION_LIMIT) {\n fullMessages.push(new SystemMessage(ITERATION_NUDGE));\n }\n\n logger.verbose(\"Agent iteration\", {\n iteration: iterationCount,\n messageCount: messages.length,\n pastSoftLimit: iterationCount >= SOFT_ITERATION_LIMIT,\n });\n\n // Invoke model\n const response = await invokeWithAbortSignal(this.model, fullMessages);\n logger.debug(\"Chat model response\", {\n content:\n typeof response.content === \"string\"\n ? response.content\n : JSON.stringify(response.content),\n toolCalls: response.tool_calls?.length ?? 0,\n toolCallNames: response.tool_calls?.map((tc) => tc.name) ?? [],\n });\n\n // Check if model made tool calls\n const toolCalls = response.tool_calls || [];\n\n if (toolCalls.length > 0) {\n logger.verbose(\"Agent made tool calls\", {\n iteration: iterationCount,\n toolCount: toolCalls.length,\n tools: toolCalls.map((tc) => tc.name),\n });\n\n // Execute tools (can be parallelized if independent)\n const toolResults = await this.executeToolCalls(toolCalls);\n\n // Build updated messages\n const updatedMessages = [\n ...messages,\n response, // AIMessage with tool_calls\n ...toolResults.map(\n (tr) =>\n new ToolMessage({\n tool_call_id: tr.toolCallId,\n content: tr.result,\n name: tr.name,\n }),\n ),\n ];\n\n return {\n shouldContinue: true,\n toolCalls: toolCalls.map((tc) => ({\n id: tc.id!,\n name: tc.name,\n args: tc.args as Record<string, unknown>,\n })),\n toolResults,\n messages: updatedMessages,\n };\n }\n\n // No tool calls - agent is responding\n const responseText = extractTextContent(\n response.content as string | Array<Record<string, unknown>>,\n );\n logger.debug(\"Agent produced response (raw)\", {\n iteration: iterationCount,\n responseText,\n });\n logger.verbose(\"Agent produced response\", {\n iteration: iterationCount,\n responseLength: responseText.length,\n });\n\n return {\n shouldContinue: false,\n responseText,\n messages: [...messages, response],\n };\n }\n\n /**\n * Execute tool calls, potentially in parallel.\n */\n private async executeToolCalls(\n toolCalls: Array<{\n id?: string;\n name: string;\n args: Record<string, unknown>;\n }>,\n ): Promise<Array<{ toolCallId: string; name: string; result: string }>> {\n // Execute all tool calls in parallel\n const results = await Promise.all(\n toolCalls.map(async (tc) => {\n const tool = this.toolsByName.get(tc.name);\n\n if (!tool) {\n logger.error(\"Unknown tool\", { name: tc.name });\n return {\n toolCallId: tc.id || `unknown-${Date.now()}`,\n name: tc.name,\n result: JSON.stringify({\n success: false,\n error: `Unknown tool: ${tc.name}`,\n }),\n };\n }\n\n try {\n logger.verbose(\"Executing tool\", { name: tc.name, args: tc.args });\n let result = await tool.invoke(tc.args);\n let resultStr =\n typeof result === \"string\" ? result : JSON.stringify(result);\n\n if (tc.name === \"discover_opportunities\" && this.persona.loopBehaviors.createIntentCallback) {\n const newResult = await this.handleCreateIntentCallback(resultStr, tc.args);\n if (newResult !== null) {\n resultStr = newResult;\n result = newResult;\n }\n }\n\n logger.debug(\"Tool response\", { name: tc.name, result: resultStr });\n logger.verbose(\"Tool completed\", {\n name: tc.name,\n resultLength: resultStr.length,\n });\n\n return {\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: resultStr,\n };\n } catch (error) {\n logger.error(\"Tool execution failed\", {\n name: tc.name,\n error: error instanceof Error ? error.message : String(error),\n });\n\n return {\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: JSON.stringify({\n success: false,\n error: `Tool execution failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n }),\n };\n }\n }),\n );\n\n return results;\n }\n\n /**\n * When discover_opportunities returned createIntentSuggested, call create_intent then discover_opportunities.\n * Returns the new discover_opportunities result string or null if no callback / create_intent failed.\n */\n private async handleCreateIntentCallback(\n resultStr: string,\n originalArgs: Record<string, unknown>\n ): Promise<string | null> {\n let parsed: { success?: boolean; error?: string; data?: { createIntentSuggested?: boolean; suggestedIntentDescription?: string } };\n try {\n parsed = JSON.parse(resultStr) as typeof parsed;\n } catch {\n return null;\n }\n if (\n !parsed?.data?.createIntentSuggested ||\n typeof parsed.data.suggestedIntentDescription !== \"string\"\n ) {\n return null;\n }\n // Never auto-create intents during introducer flows — signals are personal\n if ((originalArgs as { introTargetUserId?: string }).introTargetUserId) {\n return null;\n }\n const createIntentTool = this.toolsByName.get(\"create_intent\");\n const discoverOpportunitiesTool = this.toolsByName.get(\"discover_opportunities\");\n if (!createIntentTool || !discoverOpportunitiesTool) return null;\n\n logger.verbose(\"Create-intent signal: auto-calling create_intent then discover_opportunities\");\n const createIntentResult = await createIntentTool.invoke({\n description: parsed.data.suggestedIntentDescription,\n networkId: (originalArgs as { networkId?: string }).networkId,\n });\n const createIntentStr =\n typeof createIntentResult === \"string\" ? createIntentResult : JSON.stringify(createIntentResult);\n let createIntentParsed: { success?: boolean; error?: string };\n try {\n createIntentParsed = JSON.parse(createIntentStr) as { success?: boolean; error?: string };\n } catch {\n createIntentParsed = {};\n }\n if (createIntentParsed.success === false) {\n logger.warn(\"Create-intent failed; not re-running discover_opportunities\", {\n error: createIntentParsed.error,\n });\n return null;\n }\n\n const newResult = await discoverOpportunitiesTool.invoke(originalArgs);\n return typeof newResult === \"string\" ? newResult : JSON.stringify(newResult);\n }\n\n /**\n * Check whether any tool call produced valid opportunity blocks.\n * Both `discover_opportunities` and `list_opportunities` can return\n * ```opportunity code blocks — either one counts as a valid source.\n */\n private static hasOpportunitySource(\n toolsUsed: Array<{ name: string; success: boolean; resultSummary?: string }>,\n ): boolean {\n return toolsUsed.some(\n (t) =>\n (t.name === \"discover_opportunities\" || t.name === \"list_opportunities\") &&\n t.success &&\n !t.resultSummary?.startsWith(\"Found 0\") &&\n !t.resultSummary?.startsWith(\"No matches\") &&\n !t.resultSummary?.startsWith(\"No opportunities\"),\n );\n }\n\n /**\n * Detect hallucinated ```intent_proposal or ```opportunity blocks in model text\n * that were NOT generated by the corresponding tool call.\n *\n * A tool call that returned 0 cards (e.g. \"Found 0 match(es)\") counts as\n * NOT having produced valid blocks — the LLM must not fabricate them.\n *\n * @returns Block info if hallucination detected, null otherwise\n */\n private detectHallucinatedBlock(\n text: string,\n toolsUsed: Array<{ name: string; success: boolean; resultSummary?: string }>,\n userMessage?: string,\n ): { type: string; tool: string; description: string } | null {\n const hasSuccessfulCreateIntent = toolsUsed.some(\n (t) => t.name === \"create_intent\" && t.success,\n );\n\n // Check for hallucinated intent_proposal\n if (text.includes(\"```intent_proposal\") && !hasSuccessfulCreateIntent) {\n const match = text.match(/```intent_proposal\\s*\\n\\s*\\{[^}]*\"description\"\\s*:\\s*\"([^\"]+)\"/);\n if (match) {\n return { type: \"intent_proposal\", tool: \"create_intent\", description: match[1] };\n }\n }\n\n // Check for hallucinated opportunity blocks\n if (text.includes(\"```opportunity\") && !ChatAgent.hasOpportunitySource(toolsUsed)) {\n // Use the user's original message as the search query — NOT fields from the\n // hallucinated JSON. The model fabricates person names and reasoning that have\n // nothing to do with the user's actual request, leading to wrong results and\n // the model re-calling the tool with the correct query (doubling negotiation cost).\n const description = userMessage?.trim() || \"find connections\";\n return { type: \"opportunity\", tool: \"discover_opportunities\", description };\n }\n\n return null;\n }\n\n /**\n * Strip ```opportunity and ```intent_proposal code blocks from text\n * when no corresponding successful tool call was made.\n * Defense-in-depth: catches hallucinated blocks that slip past detectHallucinatedBlock\n * (e.g. after a correction iteration that still hallucinates).\n *\n * @param text - The response text to sanitize\n * @param toolsUsed - Tool call records from the agent loop\n * @returns Sanitized text with unbacked blocks removed\n */\n private stripUnbackedBlocks(\n text: string,\n toolsUsed: Array<{ name: string; success: boolean; resultSummary?: string }>,\n ): string {\n let result = text;\n let removedBlock = false;\n\n const hasSuccessfulCreateIntent = toolsUsed.some(\n (t) => t.name === \"create_intent\" && t.success,\n );\n\n if (!ChatAgent.hasOpportunitySource(toolsUsed) && result.includes(\"```opportunity\")) {\n const next = result.replace(/```opportunity\\s*\\n[\\s\\S]*?```/g, \"\");\n removedBlock ||= next !== result;\n result = next;\n }\n if (!hasSuccessfulCreateIntent && result.includes(\"```intent_proposal\")) {\n const next = result.replace(/```intent_proposal\\s*\\n[\\s\\S]*?```/g, \"\");\n removedBlock ||= next !== result;\n result = next;\n }\n\n // Clean up leftover double blank lines only when a block was actually removed\n if (removedBlock) {\n result = result.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n }\n\n return result;\n }\n\n // ─── Phantom write detection ─────────────────────────────────────────────\n\n private static readonly PHANTOM_WRITE_PATTERNS = [\n /\\bI(?:'ve| have) (?:updated|adjusted|changed|modified|edited|created|added|removed|deleted|saved|set up)\\b/i,\n /\\bI (?:updated|adjusted|changed|modified|edited|created|added|removed|deleted|saved|set up)\\b/i,\n /\\b(?:Updated|Adjusted|Changed|Modified|Edited|Created|Added|Removed|Deleted|Saved) (?:your|the|their)\\b/i,\n /\\bEverything is (?:now )?(?:updated|changed|adjusted|saved|set)\\b/i,\n /\\b(?:profile|bio|premise|signal|intent|membership|narrative) (?:has been|is now) (?:updated|changed|modified|adjusted|saved)\\b/i,\n ];\n\n /**\n * Detect when the model claims to have performed a write action\n * without having called any tools in the turn.\n */\n private static detectPhantomWrite(\n responseText: string,\n toolsUsed: Array<{ name: string }>,\n ): boolean {\n if (toolsUsed.length > 0) return false;\n return ChatAgent.PHANTOM_WRITE_PATTERNS.some(pattern => pattern.test(responseText));\n }\n\n // ─── Shared tool-result post-processing types ─────────────────────────────\n private static readonly STEP_DETAIL_MAX = 300;\n\n private static readonly STEP_NAME_MAX = 100;\n\n /**\n * Post-process a tool result: strip _graphTimings, extract summary/debugSteps,\n * and optionally run discover_opportunities → create_intent callback.\n *\n * Returns the normalized result string and extracted debug metadata so both\n * the normal streaming tool loop and the hallucination-recovery branch\n * produce identical LLM-facing payloads.\n */\n private async normalizeToolResult(\n toolName: string,\n resultStr: string,\n toolArgs: Record<string, unknown>,\n ): Promise<{\n resultStr: string;\n summary: string;\n debugSteps?: Array<{ step: string; detail?: string; data?: Record<string, unknown> }>;\n graphTimings?: Array<{ name: string; durationMs: number; agents: Array<{ name: string; durationMs: number }> }>;\n decisionQuestions?: Question[];\n discoveryQuestionsDebug?: DebugMetaDiscoveryQuestions;\n }> {\n let normalized = resultStr;\n\n // Run create_intent callback for discover_opportunities results (orchestrator behavior)\n if (toolName === \"discover_opportunities\" && this.persona.loopBehaviors.createIntentCallback) {\n const callbackResult = await this.handleCreateIntentCallback(normalized, toolArgs);\n if (callbackResult !== null) {\n normalized = callbackResult;\n }\n }\n\n type StepData = Record<string, unknown>;\n type DebugStep = { step: string; detail?: string; data?: StepData };\n type GraphTiming = { name: string; durationMs: number; agents: Array<{ name: string; durationMs: number }> };\n\n let summary = \"Done\";\n let debugSteps: DebugStep[] | undefined;\n let graphTimings: GraphTiming[] | undefined;\n let decisionQuestions: Question[] | undefined;\n let discoveryQuestionsDebug: DebugMetaDiscoveryQuestions | undefined;\n\n try {\n const parsed = JSON.parse(normalized) as {\n success?: boolean;\n data?: {\n summary?: string;\n debugSteps?: DebugStep[];\n _graphTimings?: GraphTiming[];\n };\n summary?: string;\n debugSteps?: DebugStep[];\n _graphTimings?: GraphTiming[];\n };\n const payload = parsed.success && parsed.data != null ? parsed.data : parsed;\n summary = payload.summary ?? parsed.summary ?? \"Done\";\n\n const rawSteps = payload.debugSteps ?? parsed.debugSteps;\n if (Array.isArray(rawSteps) && rawSteps.length > 0) {\n debugSteps = rawSteps.map((s) => ({\n step: String(s.step ?? \"\").slice(0, ChatAgent.STEP_NAME_MAX),\n detail:\n s.detail != null\n ? String(s.detail).slice(0, ChatAgent.STEP_DETAIL_MAX)\n : undefined,\n ...(s.data && typeof s.data === \"object\" ? { data: s.data } : {}),\n }));\n }\n\n const rawGraphTimings = payload._graphTimings ?? parsed._graphTimings;\n if (Array.isArray(rawGraphTimings) && rawGraphTimings.length > 0) {\n graphTimings = rawGraphTimings as GraphTiming[];\n // Strip _graphTimings from the result string sent back to the LLM\n try {\n const cleanedResult = JSON.parse(normalized) as Record<string, unknown>;\n delete cleanedResult._graphTimings;\n if (cleanedResult.data && typeof cleanedResult.data === \"object\") {\n delete (cleanedResult.data as Record<string, unknown>)._graphTimings;\n }\n normalized = JSON.stringify(cleanedResult);\n } catch { /* keep original if can't clean */ }\n }\n\n const rawQuestions = (payload as { questions?: unknown }).questions ?? (parsed as { questions?: unknown }).questions;\n const rawQuestionDebug = (payload as { _discoveryQuestionsDebug?: unknown })._discoveryQuestionsDebug\n ?? (parsed as { _discoveryQuestionsDebug?: unknown })._discoveryQuestionsDebug;\n if (Array.isArray(rawQuestions)) {\n decisionQuestions = rawQuestions as Question[];\n }\n if (rawQuestionDebug && typeof rawQuestionDebug === \"object\") {\n discoveryQuestionsDebug = rawQuestionDebug as DebugMetaDiscoveryQuestions;\n }\n // `_discoveryQuestionsDebug` is internal trace data — strip from the LLM-facing\n // tool result. `questions` is intentionally kept visible so the agent can\n // follow the prompt addendum and reference the decision prompts in its reply.\n if (discoveryQuestionsDebug !== undefined) {\n try {\n const cleaned = JSON.parse(normalized) as Record<string, unknown>;\n const stripFrom = (obj: Record<string, unknown>) => {\n delete obj._discoveryQuestionsDebug;\n };\n stripFrom(cleaned);\n if (cleaned.data && typeof cleaned.data === \"object\") {\n stripFrom(cleaned.data as Record<string, unknown>);\n }\n normalized = JSON.stringify(cleaned);\n } catch { /* keep original */ }\n }\n } catch {\n /* not JSON, keep default */\n }\n\n return {\n resultStr: normalized,\n summary,\n debugSteps,\n graphTimings,\n ...(decisionQuestions !== undefined ? { decisionQuestions } : {}),\n ...(discoveryQuestionsDebug !== undefined ? { discoveryQuestionsDebug } : {}),\n };\n }\n\n /**\n * Run the full agent loop until completion or hard limit.\n *\n * @param initialMessages - Starting conversation messages\n * @returns Final response text and full message history\n */\n @Timed()\n async run(initialMessages: BaseMessage[]): Promise<{\n responseText: string;\n messages: BaseMessage[];\n iterationCount: number;\n }> {\n let messages = initialMessages;\n let iterationCount = 0;\n\n while (iterationCount < HARD_ITERATION_LIMIT) {\n const result = await this.runIteration(messages, iterationCount);\n iterationCount++;\n messages = result.messages;\n\n if (!result.shouldContinue) {\n const responseText =\n result.responseText ||\n \"I apologize, but I couldn't generate a response.\";\n logger.debug(\"Agent final response\", { responseText });\n return {\n responseText,\n messages,\n iterationCount,\n };\n }\n }\n\n // Hit hard limit - force a response\n logger.warn(\"Hit hard iteration limit\", { iterationCount });\n\n const forceResponseMessages = [\n ...messages,\n new SystemMessage(\n \"You have reached the maximum number of tool calls. You MUST provide a final response now. Summarize what you've accomplished and what might still be needed.\",\n ),\n ];\n\n const forcedResponse = await invokeWithAbortSignal(this.model, forceResponseMessages);\n const responseText = extractTextContent(\n forcedResponse.content as string | Array<Record<string, unknown>>,\n );\n logger.debug(\"Agent forced response\", { responseText });\n\n return {\n responseText,\n messages: [...messages, forcedResponse],\n iterationCount,\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // STREAMING RUN (for narration-style output)\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Run the full agent loop with streaming narration.\n *\n * Instead of returning a single blob at the end, this method calls\n * `writer()` for every text token and tool-activity event so the\n * consumer (graph node) can push them out via `config.writer`.\n *\n * @param initialMessages - Starting conversation messages\n * @param writer - Callback to emit streaming events (from `config.writer`)\n * @param signal - Optional AbortSignal to cancel the streaming LLM call and tool execution\n * @returns Final response metadata (same shape as `run()`)\n */\n @Timed()\n async streamRun(\n initialMessages: BaseMessage[],\n writer?: StreamWriter,\n signal?: AbortSignal,\n ): Promise<{\n responseText: string;\n messages: BaseMessage[];\n iterationCount: number;\n debugMeta: { graph: string; iterations: number; tools: DebugMetaToolCall[]; llm: DebugMetaLlm; orchestratorNegotiations?: DebugMetaOrchestratorNegotiations; discoveryQuestions?: DebugMetaDiscoveryQuestions };\n }> {\n const llm: DebugMetaLlm = { calls: 0, totalDurationMs: 0, resets: [], hallucinations: [] };\n const orchestratorNegotiationIds = new Set<string>();\n let lastLlmStart = 0;\n let latestDiscoveryQuestionsDebug: DebugMetaDiscoveryQuestions | undefined;\n\n const emit = (event: AgentStreamEvent) => {\n if (event.type === \"llm_start\") {\n llm.calls += 1;\n lastLlmStart = Date.now();\n } else if (event.type === \"llm_end\") {\n if (lastLlmStart > 0) {\n llm.totalDurationMs += Date.now() - lastLlmStart;\n lastLlmStart = 0;\n }\n } else if (event.type === \"response_reset\") {\n llm.resets.push({ reason: event.reason, at: Date.now() });\n } else if (event.type === \"hallucination_detected\") {\n llm.hallucinations.push({ blockType: event.blockType, tool: event.tool, at: Date.now() });\n } else if (event.type === \"negotiation_session_start\") {\n orchestratorNegotiationIds.add(event.opportunityId);\n }\n try {\n writer?.(event);\n } catch {\n /* swallow if writer is gone */\n }\n };\n\n let messages = initialMessages;\n let iterationCount = 0;\n const toolsDebug: DebugMetaToolCall[] = [];\n const surfacedQuestionIds = new Set<string>();\n const hallucinationAutoInvokeCounts = new Map<string, number>();\n\n while (iterationCount < HARD_ITERATION_LIMIT) {\n if (signal?.aborted) {\n logger.verbose(\"Stream aborted by client\", { iterationCount });\n break;\n }\n emit({ type: \"iteration_start\", iteration: iterationCount });\n\n const iterCtx: IterationContext = {\n recentTools: extractRecentToolCalls(messages),\n currentMessage: ChatAgent.getCurrentUserMessage(messages),\n ctx: this.resolvedContext,\n };\n const systemContent = this.persona.buildSystemContent(this.resolvedContext, iterCtx);\n const fullMessages: BaseMessage[] = [\n new SystemMessage(systemContent),\n ...messages,\n ];\n if (iterationCount >= SOFT_ITERATION_LIMIT) {\n fullMessages.push(new SystemMessage(ITERATION_NUDGE));\n }\n\n logger.verbose(\"Streaming iteration\", {\n iteration: iterationCount,\n messageCount: messages.length,\n pastSoftLimit: iterationCount >= SOFT_ITERATION_LIMIT,\n });\n\n // ── Stream the model response token-by-token ──────────────────────\n emit({ type: \"llm_start\", iteration: iterationCount });\n\n let accumulated: AIMessageChunk | undefined;\n let iterationText = \"\";\n\n try {\n const stream = await this.model.stream(fullMessages, { signal });\n for await (const chunk of stream) {\n // Accumulate using AIMessageChunk.concat() so tool_call_chunks merge and tool_calls is populated\n accumulated = accumulated ? accumulated.concat(chunk) : chunk;\n\n // Emit text content tokens to the user immediately\n const textPart = extractTextFromChunk(chunk);\n if (textPart) {\n emit({ type: \"text_chunk\", content: textPart });\n iterationText += textPart;\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n logger.verbose(\"LLM stream aborted by client\", { iterationCount });\n break; // breaks the outer while loop\n }\n throw err; // re-throw non-abort errors\n }\n\n if (!accumulated) {\n logger.warn(\"Empty model response in streaming iteration\", {\n iterationCount,\n });\n iterationCount++;\n continue;\n }\n\n // ── Check for tool calls ──────────────────────────────────────────\n const toolCalls = accumulated.tool_calls || [];\n\n emit({\n type: \"llm_end\",\n iteration: iterationCount,\n hasToolCalls: toolCalls.length > 0,\n toolNames: toolCalls.length > 0 ? toolCalls.map((tc) => tc.name) : undefined,\n });\n\n if (toolCalls.length > 0) {\n logger.verbose(\"Streaming: agent made tool calls\", {\n iteration: iterationCount,\n tools: toolCalls.map((tc) => tc.name),\n });\n\n // Clear any narration text streamed before tool calls — this text is\n // intermediate reasoning and should not appear in the final response.\n // The next iteration (after tool execution) will produce the real response.\n if (iterationText) {\n emit({ type: \"response_reset\", reason: \"Tool calls detected\" });\n }\n\n // Execute tools one-by-one.\n const toolResults: Array<{\n toolCallId: string;\n name: string;\n result: string;\n }> = [];\n for (const tc of toolCalls) {\n if (signal?.aborted) {\n logger.verbose(\"Stream aborted by client during tool execution\");\n break;\n }\n emit({ type: \"tool_activity\", phase: \"start\", name: tc.name });\n\n const tool = this.toolsByName.get(tc.name);\n if (!tool) {\n const errResult = JSON.stringify({\n success: false,\n error: `Unknown tool: ${tc.name}`,\n });\n toolsDebug.push({\n name: tc.name,\n args: sanitizeForDebugMeta(tc.args) as Record<string, unknown>,\n resultSummary: \"Unknown tool\",\n success: false,\n durationMs: 0,\n });\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: tc.name,\n success: false,\n summary: \"Unknown tool\",\n });\n toolResults.push({\n toolCallId: tc.id || `unknown-${Date.now()}`,\n name: tc.name,\n result: errResult,\n });\n continue;\n }\n\n const toolStart = Date.now();\n try {\n logger.verbose(\"Streaming: executing tool\", { name: tc.name });\n const currentCtx = requestContext.getStore() ?? {};\n let result = await requestContext.run(\n {\n ...currentCtx,\n traceEmitter: (e) => emit(e as AgentStreamEvent),\n // Propagate the caller's AbortSignal into requestContext so\n // long-running graph nodes (orchestrator negotiation fan-out)\n // can suppress event emits after the chat session closes.\n ...(signal && { abortSignal: signal }),\n },\n () => tool.invoke(tc.args),\n );\n const toolDurationMs = Date.now() - toolStart;\n let resultStr =\n typeof result === \"string\" ? result : JSON.stringify(result);\n\n const normalized = await this.normalizeToolResult(tc.name, resultStr, tc.args);\n if (normalized.discoveryQuestionsDebug) latestDiscoveryQuestionsDebug = normalized.discoveryQuestionsDebug;\n resultStr = normalized.resultStr;\n result = resultStr;\n\n if (normalized.decisionQuestions && normalized.decisionQuestions.length > 0) {\n const { fresh, newIds } = deduplicateQuestions(normalized.decisionQuestions, surfacedQuestionIds);\n if (fresh.length > 0) {\n emit({ type: \"decision_questions\", questions: fresh });\n for (const id of newIds) surfacedQuestionIds.add(id);\n }\n }\n\n logger.verbose(\"Streaming: tool completed\", {\n name: tc.name,\n resultLength: resultStr.length,\n });\n\n toolsDebug.push({\n name: tc.name,\n args: sanitizeForDebugMeta(tc.args) as Record<string, unknown>,\n resultSummary: normalized.summary,\n success: true,\n durationMs: toolDurationMs,\n ...(normalized.debugSteps?.length ? { steps: normalized.debugSteps } : {}),\n ...(normalized.graphTimings?.length ? { graphs: normalized.graphTimings } : {}),\n });\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: tc.name,\n success: true,\n summary: normalized.summary,\n steps: normalized.debugSteps,\n });\n\n toolResults.push({\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: resultStr,\n });\n } catch (error) {\n const errMsg =\n error instanceof Error ? error.message : \"Unknown error\";\n logger.error(\"Streaming: tool failed\", {\n name: tc.name,\n error: errMsg,\n });\n toolsDebug.push({\n name: tc.name,\n args: sanitizeForDebugMeta(tc.args) as Record<string, unknown>,\n resultSummary: errMsg,\n success: false,\n durationMs: Date.now() - toolStart,\n });\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: tc.name,\n success: false,\n summary: errMsg,\n });\n toolResults.push({\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: JSON.stringify({\n success: false,\n error: `Tool execution failed: ${errMsg}`,\n }),\n });\n }\n }\n\n // If aborted during tool execution, discard partial results\n if (signal?.aborted) {\n logger.verbose(\"Stream aborted after partial tool execution, discarding results\");\n break; // break outer while loop — don't append partial toolResults to messages\n }\n\n // Build updated messages and loop\n messages = [\n ...messages,\n accumulated, // AIMessage with tool_calls\n ...toolResults.map(\n (tr) =>\n new ToolMessage({\n tool_call_id: tr.toolCallId,\n content: tr.result,\n name: tr.name,\n }),\n ),\n ];\n iterationCount++;\n continue;\n }\n\n // ── No tool calls → check for hallucinated code blocks ──────────\n // LLMs sometimes write ```intent_proposal or ```opportunity blocks\n // directly instead of calling the corresponding tool. These blocks\n // lack valid proposalIds / data and won't work in the frontend.\n // Auto-invoke the correct tool directly instead of re-asking the LLM.\n // Persona-gated: only personas with hallucinationRecovery enabled (orchestrator)\n // run detection/auto-invoke — other personas never trigger this branch.\n const hallucinatedBlock = this.persona.loopBehaviors.hallucinationRecovery\n ? this.detectHallucinatedBlock(iterationText, toolsDebug, iterCtx.currentMessage)\n : null;\n const priorAutoInvokes = hallucinatedBlock ? (hallucinationAutoInvokeCounts.get(hallucinatedBlock.type) ?? 0) : 0;\n if (hallucinatedBlock && priorAutoInvokes < 2 && iterationCount < HARD_ITERATION_LIMIT - 1) {\n hallucinationAutoInvokeCounts.set(hallucinatedBlock.type, priorAutoInvokes + 1);\n logger.warn(\"Streaming: detected hallucinated block, auto-invoking tool\", {\n iteration: iterationCount,\n blockType: hallucinatedBlock.type,\n tool: hallucinatedBlock.tool,\n extractedDescription: hallucinatedBlock.description,\n autoInvokeAttempt: priorAutoInvokes + 1,\n });\n // Tell the frontend to discard all streamed tokens from this iteration\n emit({ type: \"response_reset\", reason: `Hallucinated ${hallucinatedBlock.type} block detected` });\n emit({ type: \"hallucination_detected\", blockType: hallucinatedBlock.type, tool: hallucinatedBlock.tool });\n\n const tool = this.toolsByName.get(hallucinatedBlock.tool);\n if (tool) {\n const toolCallId = `auto-${hallucinatedBlock.tool}-${Date.now()}`;\n const toolArgs = hallucinatedBlock.type === \"opportunity\"\n ? { searchQuery: hallucinatedBlock.description }\n : { description: hallucinatedBlock.description };\n\n emit({ type: \"tool_activity\", phase: \"start\", name: hallucinatedBlock.tool });\n const toolStart = Date.now();\n try {\n const currentCtx = requestContext.getStore() ?? {};\n const result = await requestContext.run(\n {\n ...currentCtx,\n traceEmitter: (e) => emit(e as AgentStreamEvent),\n // Propagate the caller's AbortSignal into requestContext so\n // long-running graph nodes (orchestrator negotiation fan-out)\n // can suppress event emits after the chat session closes.\n ...(signal && { abortSignal: signal }),\n },\n () => tool.invoke(toolArgs),\n );\n const rawResultStr = typeof result === \"string\" ? result : JSON.stringify(result);\n const toolDurationMs = Date.now() - toolStart;\n\n // Same normalization as the main tool loop: callback + _graphTimings strip\n const normalized = await this.normalizeToolResult(hallucinatedBlock.tool, rawResultStr, toolArgs);\n\n toolsDebug.push({\n name: hallucinatedBlock.tool,\n args: sanitizeForDebugMeta(toolArgs) as Record<string, unknown>,\n resultSummary: normalized.summary,\n success: true,\n durationMs: toolDurationMs,\n ...(normalized.debugSteps?.length ? { steps: normalized.debugSteps } : {}),\n ...(normalized.graphTimings?.length ? { graphs: normalized.graphTimings } : {}),\n });\n // Mirror the main tool loop's handling: forward decision questions\n // and capture debug metadata even when the discovery tool was invoked\n // via the hallucination-recovery path.\n if (normalized.discoveryQuestionsDebug) {\n latestDiscoveryQuestionsDebug = normalized.discoveryQuestionsDebug;\n }\n if (normalized.decisionQuestions && normalized.decisionQuestions.length > 0) {\n const { fresh: freshHallucination, newIds: newIdsHallucination } = deduplicateQuestions(normalized.decisionQuestions, surfacedQuestionIds);\n if (freshHallucination.length > 0) {\n emit({ type: \"decision_questions\", questions: freshHallucination });\n for (const id of newIdsHallucination) surfacedQuestionIds.add(id);\n }\n }\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: hallucinatedBlock.tool,\n success: true,\n summary: normalized.summary,\n steps: normalized.debugSteps,\n });\n\n // Build synthetic tool call message + tool result so the next LLM\n // iteration can narrate around real data instead of hallucinated blocks.\n const syntheticAIMessage = new AIMessage({\n content: \"\",\n tool_calls: [{ id: toolCallId, name: hallucinatedBlock.tool, args: toolArgs }],\n });\n messages = [\n ...messages,\n syntheticAIMessage,\n new ToolMessage({ tool_call_id: toolCallId, content: normalized.resultStr, name: hallucinatedBlock.tool }),\n ];\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : \"Unknown error\";\n logger.error(\"Streaming: auto-invoked tool failed after hallucination\", {\n tool: hallucinatedBlock.tool,\n error: errMsg,\n });\n toolsDebug.push({\n name: hallucinatedBlock.tool,\n args: sanitizeForDebugMeta(toolArgs) as Record<string, unknown>,\n resultSummary: errMsg,\n success: false,\n durationMs: Date.now() - toolStart,\n });\n emit({ type: \"tool_activity\", phase: \"end\", name: hallucinatedBlock.tool, success: false, summary: errMsg });\n\n // Fall back to correction message if tool invocation fails\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n `CORRECTION: You wrote a \\`\\`\\`${hallucinatedBlock.type} block without calling ${hallucinatedBlock.tool}. ` +\n `The auto-retry failed (${errMsg}). Please try calling the tool directly.`\n ),\n ];\n }\n } else {\n // Tool not found — fall back to correction message\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n `CORRECTION: You wrote a \\`\\`\\`${hallucinatedBlock.type} block without calling ${hallucinatedBlock.tool}. ` +\n `That block is INVALID. Call the tool directly instead.`\n ),\n ];\n }\n iterationCount++;\n continue;\n }\n\n // ── Circuit breaker: hallucination detected but auto-invoke cap reached ──\n if (hallucinatedBlock && priorAutoInvokes >= 2) {\n logger.warn(\"Streaming: hallucination auto-invoke cap reached, stripping blocks\", {\n iteration: iterationCount,\n blockType: hallucinatedBlock.type,\n attempts: priorAutoInvokes,\n });\n emit({ type: \"response_reset\", reason: `Hallucination cap reached for ${hallucinatedBlock.type}` });\n const stripped = this.stripUnbackedBlocks(iterationText, toolsDebug);\n if (stripped.trim()) {\n emit({ type: \"text_chunk\", content: stripped });\n } else {\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n \"Your previous response only contained invalid code blocks that were removed. \" +\n \"Write a plain text response now — summarize the results of the tools you used. \" +\n \"Do NOT include ```opportunity or ```intent_proposal blocks.\",\n ),\n ];\n iterationCount++;\n continue;\n }\n }\n\n // ── Phantom write: model claims a write action without calling any tools ──\n if (\n ChatAgent.detectPhantomWrite(iterationText, toolsDebug) &&\n iterationCount < HARD_ITERATION_LIMIT - 1\n ) {\n logger.warn(\"Streaming: detected phantom write claim without tool calls\", {\n iteration: iterationCount,\n });\n emit({ type: \"response_reset\", reason: \"Phantom write detected — no tools were called\" });\n emit({ type: \"hallucination_detected\", blockType: \"phantom_write\", tool: \"none\" });\n\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n \"CORRECTION: You claimed to have performed an action (update, create, modify) but you did NOT call any tools. \" +\n \"The user's request has NOT been fulfilled. You MUST call the appropriate tool(s) to actually make the change, \" +\n \"then confirm based on the tool result. Do it now.\",\n ),\n ];\n iterationCount++;\n continue;\n }\n\n // ── Final response already streamed ─────────────────────────────\n // Defense-in-depth: strip any code blocks that require tool backing\n // but slipped through without a successful tool call (persona-gated,\n // same flag as detection since both police tool-backed block types).\n const sanitizedText = this.persona.loopBehaviors.hallucinationRecovery\n ? this.stripUnbackedBlocks(iterationText, toolsDebug)\n : iterationText;\n if (sanitizedText !== iterationText) {\n logger.warn(\"Streaming: stripped unbacked code blocks from final response\", {\n originalLength: iterationText.length,\n sanitizedLength: sanitizedText.length,\n });\n emit({ type: \"response_reset\", reason: \"Sanitized unbacked blocks from response\" });\n // Re-emit the sanitized text so the frontend displays clean content\n if (sanitizedText.trim()) {\n emit({ type: \"text_chunk\", content: sanitizedText });\n }\n\n // If stripping removed ALL content, force a recovery iteration so the\n // user sees an actual response instead of a blank message.\n if (!sanitizedText.trim() && iterationCount < HARD_ITERATION_LIMIT - 1) {\n logger.warn(\"Streaming: sanitized text is empty, forcing recovery iteration\", {\n iteration: iterationCount,\n });\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n \"Your previous response only contained invalid code blocks that were removed. \" +\n \"Write a plain text response now — summarize the results of the tools you used. \" +\n \"Do NOT include ```opportunity or ```intent_proposal blocks.\",\n ),\n ];\n iterationCount++;\n continue;\n }\n }\n\n logger.verbose(\"Streaming: agent produced response\", {\n iteration: iterationCount,\n responseLength: sanitizedText.length,\n });\n messages = [...messages, accumulated];\n iterationCount++;\n\n return {\n responseText: sanitizedText,\n messages,\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n ...(orchestratorNegotiationIds.size > 0 && {\n orchestratorNegotiations: { opportunityIds: [...orchestratorNegotiationIds] },\n }),\n ...(latestDiscoveryQuestionsDebug && { discoveryQuestions: latestDiscoveryQuestionsDebug }),\n },\n };\n }\n\n // If aborted, return immediately without making another LLM call\n if (signal?.aborted) {\n return {\n responseText: \"\",\n messages,\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n ...(orchestratorNegotiationIds.size > 0 && {\n orchestratorNegotiations: { opportunityIds: [...orchestratorNegotiationIds] },\n }),\n ...(latestDiscoveryQuestionsDebug && { discoveryQuestions: latestDiscoveryQuestionsDebug }),\n },\n };\n }\n\n // ── Hard limit: force a response ──────────────────────────────────────\n logger.warn(\"Streaming: hit hard iteration limit\", { iterationCount });\n\n const forceMessages = [\n ...messages,\n new SystemMessage(\n \"You have reached the maximum number of tool calls. You MUST provide a final response now. Summarize what you've accomplished and what might still be needed.\",\n ),\n ];\n\n let forcedAccumulated: AIMessageChunk | undefined;\n let forcedResponseText = \"\";\n const forceStream = await this.model.stream(forceMessages);\n for await (const chunk of forceStream) {\n forcedAccumulated = forcedAccumulated\n ? forcedAccumulated.concat(chunk)\n : chunk;\n const textPart = extractTextFromChunk(chunk);\n if (textPart) {\n emit({ type: \"text_chunk\", content: textPart });\n forcedResponseText += textPart;\n }\n }\n\n return {\n responseText: forcedResponseText,\n messages: [\n ...messages,\n ...(forcedAccumulated ? [forcedAccumulated] : []),\n ],\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n ...(orchestratorNegotiationIds.size > 0 && {\n orchestratorNegotiations: { opportunityIds: [...orchestratorNegotiationIds] },\n }),\n ...(latestDiscoveryQuestionsDebug && { discoveryQuestions: latestDiscoveryQuestionsDebug }),\n },\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat.agent.js","sourceRoot":"/","sources":["chat/chat.agent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatOpenAI } from \"@langchain/openai\";\nimport { AIMessage, BaseMessage, SystemMessage, ToolMessage, AIMessageChunk } from \"@langchain/core/messages\";\nimport type { ChatTools, ToolContext, ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport { resolveChatContext } from \"../shared/agent/tool.helpers.js\";\nimport { scopeFromNetworkId } from \"../shared/agent/tool.scope.js\";\nimport { ITERATION_NUDGE } from \"./chat.prompt.js\";\nimport { ORCHESTRATOR_PERSONA, type ChatPersonaConfig } from \"./chat.persona.js\";\nimport { extractRecentToolCalls, type IterationContext } from \"./chat.prompt.modules.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { createModel, type ModelConfig } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\nimport { sanitizeForDebugMeta } from \"../shared/observability/debug-meta.sanitizer.js\";\nimport type { DebugMetaToolCall, DebugMetaLlm, DebugMetaOrchestratorNegotiations, DebugMetaDiscoveryQuestions } from \"./chat-streaming.types.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport type { Opportunity } from \"../shared/interfaces/database.interface.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { deduplicateQuestions } from \"./chat.question-dedup.js\";\n\nconst AGENT_ACTION_PROPOSAL_FENCE_PATTERN = /```agent_action_proposal\\s*\\n([\\s\\S]*?)\\n```/g;\nconst AGENT_ACTION_PROPOSAL_KEYS = new Set([\"proposalId\", \"actions\"]);\nconst AGENT_ACTION_KEYS = new Set([\n \"type\",\n \"entityId\",\n \"currentState\",\n \"proposedOperation\",\n \"skipped\",\n \"reason\",\n \"description\",\n \"evidence\",\n]);\nconst AGENT_ACTION_OPERATIONS = {\n retract_premise: \"RETRACT_PREMISE\",\n narrow_signal: \"NARROW_SIGNAL\",\n pause_signal: \"PAUSE_SIGNAL\",\n} as const;\n\nfunction isVisibleAgentActionProposal(payload: unknown): boolean {\n if (!payload || typeof payload !== \"object\" || Array.isArray(payload)) return false;\n const proposal = payload as Record<string, unknown>;\n if (Object.keys(proposal).some((key) => !AGENT_ACTION_PROPOSAL_KEYS.has(key))) return false;\n if (\n typeof proposal.proposalId !== \"string\"\n || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(proposal.proposalId)\n || !Array.isArray(proposal.actions)\n || proposal.actions.length < 1\n || proposal.actions.length > 5\n ) return false;\n\n return proposal.actions.every((rawAction) => {\n if (!rawAction || typeof rawAction !== \"object\" || Array.isArray(rawAction)) return false;\n const action = rawAction as Record<string, unknown>;\n if (Object.keys(action).some((key) => !AGENT_ACTION_KEYS.has(key))) return false;\n if (typeof action.type !== \"string\" || !(action.type in AGENT_ACTION_OPERATIONS)) return false;\n const type = action.type as keyof typeof AGENT_ACTION_OPERATIONS;\n if (action.proposedOperation !== AGENT_ACTION_OPERATIONS[type]) return false;\n if (typeof action.entityId !== \"string\" || !action.entityId.trim()) return false;\n if (typeof action.currentState !== \"string\" || !action.currentState.trim()) return false;\n if (action.skipped !== undefined && typeof action.skipped !== \"boolean\") return false;\n return [\"reason\", \"description\", \"evidence\"].every(\n (key) => action[key] === undefined || typeof action[key] === \"string\",\n );\n });\n}\n\nconst logger = protocolLogger(\"ChatAgent\");\n\n// Re-export for external consumers\nexport { ITERATION_NUDGE } from \"./chat.prompt.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Writer callback for streaming custom data out of the graph node.\n * Matches the `config.writer` signature from LangGraphRunnableConfig.\n */\nexport type StreamWriter = (data: unknown) => void;\n\n/**\n * Events emitted by `streamRun()` via the writer callback.\n *\n * - `iteration_start` — new agent loop iteration begins\n * - `llm_start` — LLM begins generating response\n * - `text_chunk` — a token (or group of tokens) of model text\n * - `llm_end` — LLM finished generating (may have tool calls)\n * - `tool_activity` — tool starts or finishes execution\n * - `graph_start` — a LangGraph sub-graph begins inside a tool\n * - `graph_end` — a LangGraph sub-graph completes\n * - `agent_start` — an LLM agent begins inside a graph node\n * - `agent_end` — an LLM agent completes\n * - `opportunity_draft_ready` — an orchestrator-triggered negotiation finalized\n * to `draft` and the card is ready to render inline\n */\nexport type AgentStreamEvent =\n | { type: \"iteration_start\"; iteration: number }\n | { type: \"llm_start\"; iteration: number }\n | { type: \"text_chunk\"; content: string }\n | { type: \"llm_end\"; iteration: number; hasToolCalls: boolean; toolNames?: string[] }\n | { type: \"tool_activity\"; phase: \"start\"; name: string }\n | {\n type: \"tool_activity\";\n phase: \"end\";\n name: string;\n success: boolean;\n summary?: string;\n steps?: Array<{ step: string; detail?: string; data?: Record<string, unknown> }>;\n }\n | { type: \"response_reset\"; reason: string }\n | { type: \"hallucination_detected\"; blockType: string; tool: string }\n | { type: \"graph_start\"; name: string }\n | { type: \"graph_end\"; name: string; durationMs: number }\n | { type: \"phase_start\"; name: string }\n | { type: \"phase_end\"; name: string; durationMs: number }\n | { type: \"agent_start\"; name: string }\n | { type: \"agent_end\"; name: string; durationMs: number; summary: string }\n | {\n // Emitted from the orchestrator branch of OpportunityGraph.negotiateNode\n // each time a per-candidate negotiation resolves to an accepted draft.\n // Carries the opportunity row plus the counterparty's display basics so\n // the frontend can append an inline card to the chat timeline without a\n // second round-trip user lookup.\n type: \"opportunity_draft_ready\";\n opportunityId: string;\n opportunity: Opportunity;\n /** Viewer-centric summary derived from interpretation.reasoning via viewerCentricCardSummary. */\n personalizedSummary?: string;\n counterparty: {\n userId: string;\n name?: string;\n };\n }\n | {\n type: \"negotiation_session_start\";\n opportunityId: string;\n negotiationConversationId: string;\n sourceUserId: string;\n candidateUserId: string;\n candidateName?: string;\n trigger: \"orchestrator\" | \"ambient\";\n startedAt: number;\n }\n | {\n type: \"negotiation_session_end\";\n opportunityId: string;\n negotiationConversationId: string;\n durationMs: number;\n }\n | {\n type: \"negotiation_turn\";\n opportunityId: string;\n negotiationConversationId: string;\n turnIndex: number;\n actor: \"source\" | \"candidate\";\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\" | \"outreach\" | \"withdraw\" | \"decline\" | \"ask_user\";\n reasoning?: string;\n message?: string;\n suggestedRoles?: { ownUser?: string; otherUser?: string };\n durationMs: number;\n }\n | {\n type: \"negotiation_outcome\";\n opportunityId: string;\n outcome:\n | \"accepted\"\n | \"rejected_stalled\"\n | \"waiting_for_agent\"\n | \"timed_out\"\n | \"turn_cap\"\n | \"screened_out\";\n turnCount: number;\n reasoning?: string;\n agreedRoles?: { ownUser?: string; otherUser?: string };\n }\n | {\n // Emitted by the ask_user_question tool after persisting chat-mode\n // questions: the turn is blocked awaiting the user's inline answer.\n type: \"user_question\";\n questions: Array<{\n id: string;\n title: string;\n prompt: string;\n options: Array<{ label: string; description: string }>;\n multiSelect: boolean;\n }>;\n }\n | { type: \"status\"; message: string }\n | { type: \"decision_questions\"; questions: Question[] }\n | { type: \"chat_summarizer_start\"; payload: { sessionId: string } }\n | { type: \"chat_summarizer_end\"; payload: { durationMs: number } }\n | { type: \"question_generator_start\"; payload: { inputMode: \"transcripts\" | \"insights\"; negotiationCount: number; hasChatContext: boolean; truncated?: { originalCount: number; keptCount: number } } }\n | { type: \"question_generator_end\"; payload: { finalCount: number; strategies: QuestionStrategy[]; durationMs: number; inputMode: \"transcripts\" | \"insights\" } };\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CONFIGURATION\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Soft limit: After this many iterations, inject a nudge message.\n */\nexport const SOFT_ITERATION_LIMIT = 8;\n\n/**\n * Hard limit: Force exit after this many iterations to prevent infinite loops.\n */\nexport const HARD_ITERATION_LIMIT = 12;\n\n/**\n * Extract plain text from message content (string or structured block array).\n * Filters to only `type: \"text\"` blocks, discarding tool metadata.\n */\nfunction extractTextContent(content: string | Array<Record<string, unknown>>): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .filter((b): b is { type: \"text\"; text?: string } => (b as { type?: string }).type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n }\n return \"\";\n}\n\n/**\n * Extract plain text from an AIMessageChunk (string content or text blocks).\n */\nfunction extractTextFromChunk(chunk: AIMessageChunk): string {\n return extractTextContent(chunk.content as string | Array<Record<string, unknown>>);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CHAT AGENT CLASS\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Result of a single agent iteration.\n */\nexport interface AgentIterationResult {\n /** Whether the agent wants to continue (made tool calls) or stop (produced final response) */\n shouldContinue: boolean;\n /** Tool calls made in this iteration (if any) */\n toolCalls?: Array<{\n id: string;\n name: string;\n args: Record<string, unknown>;\n }>;\n /** Tool results from executing the tool calls */\n toolResults?: Array<{\n toolCallId: string;\n name: string;\n result: string;\n }>;\n /** Final response text (if agent is done) */\n responseText?: string;\n /** Updated messages array */\n messages: BaseMessage[];\n}\n\n/**\n * ChatAgent: ReAct-style agent that uses tools to help users.\n *\n * The agent operates in a loop:\n * 1. Receive messages (conversation history + tool results)\n * 2. Decide: call tools OR respond to user\n * 3. If tools called: execute them, add results, loop back\n * 4. If response: return final text\n *\n * Use `ChatAgent.create(context)` to construct (async factory).\n */\nexport class ChatAgent {\n private model: ChatOpenAI;\n private tools: ChatTools;\n private toolsByName: Map<string, any>;\n\n /**\n * Private constructor — use `ChatAgent.create()` instead.\n */\n private constructor(\n private resolvedContext: ResolvedToolContext,\n private persona: ChatPersonaConfig,\n tools: ChatTools,\n modelConfig?: ModelConfig,\n ) {\n this.model = createModel(\"chat\", modelConfig);\n\n // Store tools and index by name\n this.tools = tools;\n this.toolsByName = new Map();\n for (const tool of this.tools) {\n this.toolsByName.set(tool.name, tool);\n }\n\n // Bind tools to model\n this.model = this.model.bindTools(this.tools) as ChatOpenAI;\n }\n\n /**\n * Extracts the text content of the most recent HumanMessage.\n */\n private static getCurrentUserMessage(messages: BaseMessage[]): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]._getType() === \"human\") {\n const content = messages[i].content;\n return typeof content === \"string\" ? content : undefined;\n }\n }\n return undefined;\n }\n\n /**\n * Detects a prior visible action proposal without considering current-turn\n * tool calls. The reporter uses this only to make typed confirmation\n * language contextual rather than executable on its own.\n */\n static hasPriorAgentActionProposal(messages: BaseMessage[]): boolean {\n let currentHumanIndex = -1;\n let previousHumanIndex = -1;\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index]._getType() !== \"human\") continue;\n if (currentHumanIndex < 0) {\n currentHumanIndex = index;\n } else {\n previousHumanIndex = index;\n break;\n }\n }\n if (currentHumanIndex < 0 || previousHumanIndex < 0) return false;\n\n let latestAssistant: BaseMessage | undefined;\n for (let index = currentHumanIndex - 1; index > previousHumanIndex; index -= 1) {\n if (messages[index]._getType() === \"ai\") {\n latestAssistant = messages[index];\n break;\n }\n }\n if (!latestAssistant || typeof latestAssistant.content !== \"string\") return false;\n\n AGENT_ACTION_PROPOSAL_FENCE_PATTERN.lastIndex = 0;\n for (const match of latestAssistant.content.matchAll(AGENT_ACTION_PROPOSAL_FENCE_PATTERN)) {\n try {\n if (isVisibleAgentActionProposal(JSON.parse(match[1]))) return true;\n } catch {\n // An invalid prior fence is not visible proposal context.\n }\n }\n return false;\n }\n\n /**\n * Async factory: creates a ChatAgent with resolved user/index context.\n * Resolves user/network identity from DB during tool initialization.\n *\n * @param context - Tool context (database, userId, scope, deps)\n * @param persona - Persona config (prompt builder, toolset, loop behaviors).\n * Defaults to the orchestrator persona.\n */\n static async create(\n context: ToolContext,\n persona: ChatPersonaConfig = ORCHESTRATOR_PERSONA,\n ): Promise<ChatAgent> {\n const { networkId: legacyNetworkId } = context;\n const explicitScope = context.scopeType && context.scopeId\n ? { scopeType: context.scopeType, scopeId: context.scopeId }\n : scopeFromNetworkId(legacyNetworkId);\n const scopedNetworkId = explicitScope.scopeType === 'network' ? explicitScope.scopeId : undefined;\n const resolved: ResolvedToolContext = await resolveChatContext({\n database: context.database,\n userId: context.userId,\n networkId: scopedNetworkId,\n sessionId: context.sessionId,\n contactsEnabled: context.contactsEnabled,\n actionToolsEnabled: context.actionToolsEnabled,\n });\n if (explicitScope.scopeType && explicitScope.scopeId) {\n resolved.scopeType = explicitScope.scopeType;\n resolved.scopeId = explicitScope.scopeId;\n }\n const tools = await persona.createTools(context, resolved);\n return new ChatAgent(resolved, persona, tools, context.modelConfig);\n }\n\n /**\n * Run a single iteration of the agent loop.\n *\n * @param messages - Current conversation including any tool results\n * @param iterationCount - Current iteration number (for soft limit)\n * @returns Result indicating whether to continue and any tool calls/response\n */\n @Timed()\n async runIteration(\n messages: BaseMessage[],\n iterationCount: number,\n ): Promise<AgentIterationResult> {\n const iterCtx: IterationContext = {\n recentTools: extractRecentToolCalls(messages),\n currentMessage: ChatAgent.getCurrentUserMessage(messages),\n hasPriorAgentActionProposal: ChatAgent.hasPriorAgentActionProposal(messages),\n ctx: this.resolvedContext,\n };\n const deterministicResponse = this.persona.resolveDeterministicResponse?.(\n this.resolvedContext,\n iterCtx,\n );\n if (deterministicResponse !== undefined && deterministicResponse !== null) {\n const response = new AIMessage(deterministicResponse);\n return {\n shouldContinue: false,\n responseText: deterministicResponse,\n messages: [...messages, response],\n };\n }\n const systemContent = this.persona.buildSystemContent(this.resolvedContext, iterCtx);\n\n const fullMessages: BaseMessage[] = [\n new SystemMessage(systemContent),\n ...messages,\n ];\n\n // Add nudge if past soft limit\n if (iterationCount >= SOFT_ITERATION_LIMIT) {\n fullMessages.push(new SystemMessage(ITERATION_NUDGE));\n }\n\n logger.verbose(\"Agent iteration\", {\n iteration: iterationCount,\n messageCount: messages.length,\n pastSoftLimit: iterationCount >= SOFT_ITERATION_LIMIT,\n });\n\n // Invoke model\n const response = await invokeWithAbortSignal(this.model, fullMessages);\n logger.debug(\"Chat model response\", {\n content:\n typeof response.content === \"string\"\n ? response.content\n : JSON.stringify(response.content),\n toolCalls: response.tool_calls?.length ?? 0,\n toolCallNames: response.tool_calls?.map((tc) => tc.name) ?? [],\n });\n\n // Check if model made tool calls\n const toolCalls = response.tool_calls || [];\n\n if (toolCalls.length > 0) {\n logger.verbose(\"Agent made tool calls\", {\n iteration: iterationCount,\n toolCount: toolCalls.length,\n tools: toolCalls.map((tc) => tc.name),\n });\n\n // Execute tools (can be parallelized if independent)\n const toolResults = await this.executeToolCalls(toolCalls);\n\n // Build updated messages\n const updatedMessages = [\n ...messages,\n response, // AIMessage with tool_calls\n ...toolResults.map(\n (tr) =>\n new ToolMessage({\n tool_call_id: tr.toolCallId,\n content: tr.result,\n name: tr.name,\n }),\n ),\n ];\n\n return {\n shouldContinue: true,\n toolCalls: toolCalls.map((tc) => ({\n id: tc.id!,\n name: tc.name,\n args: tc.args as Record<string, unknown>,\n })),\n toolResults,\n messages: updatedMessages,\n };\n }\n\n // No tool calls - agent is responding\n const responseText = extractTextContent(\n response.content as string | Array<Record<string, unknown>>,\n );\n logger.debug(\"Agent produced response (raw)\", {\n iteration: iterationCount,\n responseText,\n });\n logger.verbose(\"Agent produced response\", {\n iteration: iterationCount,\n responseLength: responseText.length,\n });\n\n return {\n shouldContinue: false,\n responseText,\n messages: [...messages, response],\n };\n }\n\n /**\n * Execute tool calls, potentially in parallel.\n */\n private async executeToolCalls(\n toolCalls: Array<{\n id?: string;\n name: string;\n args: Record<string, unknown>;\n }>,\n ): Promise<Array<{ toolCallId: string; name: string; result: string }>> {\n // Execute all tool calls in parallel\n const results = await Promise.all(\n toolCalls.map(async (tc) => {\n const tool = this.toolsByName.get(tc.name);\n\n if (!tool) {\n logger.error(\"Unknown tool\", { name: tc.name });\n return {\n toolCallId: tc.id || `unknown-${Date.now()}`,\n name: tc.name,\n result: JSON.stringify({\n success: false,\n error: `Unknown tool: ${tc.name}`,\n }),\n };\n }\n\n try {\n logger.verbose(\"Executing tool\", { name: tc.name, args: tc.args });\n let result = await tool.invoke(tc.args);\n let resultStr =\n typeof result === \"string\" ? result : JSON.stringify(result);\n\n if (tc.name === \"discover_opportunities\" && this.persona.loopBehaviors.createIntentCallback) {\n const newResult = await this.handleCreateIntentCallback(resultStr, tc.args);\n if (newResult !== null) {\n resultStr = newResult;\n result = newResult;\n }\n }\n\n logger.debug(\"Tool response\", { name: tc.name, result: resultStr });\n logger.verbose(\"Tool completed\", {\n name: tc.name,\n resultLength: resultStr.length,\n });\n\n return {\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: resultStr,\n };\n } catch (error) {\n logger.error(\"Tool execution failed\", {\n name: tc.name,\n error: error instanceof Error ? error.message : String(error),\n });\n\n return {\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: JSON.stringify({\n success: false,\n error: `Tool execution failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n }),\n };\n }\n }),\n );\n\n return results;\n }\n\n /**\n * When discover_opportunities returned createIntentSuggested, call create_intent then discover_opportunities.\n * Returns the new discover_opportunities result string or null if no callback / create_intent failed.\n */\n private async handleCreateIntentCallback(\n resultStr: string,\n originalArgs: Record<string, unknown>\n ): Promise<string | null> {\n let parsed: { success?: boolean; error?: string; data?: { createIntentSuggested?: boolean; suggestedIntentDescription?: string } };\n try {\n parsed = JSON.parse(resultStr) as typeof parsed;\n } catch {\n return null;\n }\n if (\n !parsed?.data?.createIntentSuggested ||\n typeof parsed.data.suggestedIntentDescription !== \"string\"\n ) {\n return null;\n }\n // Never auto-create intents during introducer flows — signals are personal\n if ((originalArgs as { introTargetUserId?: string }).introTargetUserId) {\n return null;\n }\n const createIntentTool = this.toolsByName.get(\"create_intent\");\n const discoverOpportunitiesTool = this.toolsByName.get(\"discover_opportunities\");\n if (!createIntentTool || !discoverOpportunitiesTool) return null;\n\n logger.verbose(\"Create-intent signal: auto-calling create_intent then discover_opportunities\");\n const createIntentResult = await createIntentTool.invoke({\n description: parsed.data.suggestedIntentDescription,\n networkId: (originalArgs as { networkId?: string }).networkId,\n });\n const createIntentStr =\n typeof createIntentResult === \"string\" ? createIntentResult : JSON.stringify(createIntentResult);\n let createIntentParsed: { success?: boolean; error?: string };\n try {\n createIntentParsed = JSON.parse(createIntentStr) as { success?: boolean; error?: string };\n } catch {\n createIntentParsed = {};\n }\n if (createIntentParsed.success === false) {\n logger.warn(\"Create-intent failed; not re-running discover_opportunities\", {\n error: createIntentParsed.error,\n });\n return null;\n }\n\n const newResult = await discoverOpportunitiesTool.invoke(originalArgs);\n return typeof newResult === \"string\" ? newResult : JSON.stringify(newResult);\n }\n\n /**\n * Check whether any tool call produced valid opportunity blocks.\n * Both `discover_opportunities` and `list_opportunities` can return\n * ```opportunity code blocks — either one counts as a valid source.\n */\n private static hasOpportunitySource(\n toolsUsed: Array<{ name: string; success: boolean; resultSummary?: string }>,\n ): boolean {\n return toolsUsed.some(\n (t) =>\n (t.name === \"discover_opportunities\" || t.name === \"list_opportunities\") &&\n t.success &&\n !t.resultSummary?.startsWith(\"Found 0\") &&\n !t.resultSummary?.startsWith(\"No matches\") &&\n !t.resultSummary?.startsWith(\"No opportunities\"),\n );\n }\n\n /**\n * Detect hallucinated ```intent_proposal or ```opportunity blocks in model text\n * that were NOT generated by the corresponding tool call.\n *\n * A tool call that returned 0 cards (e.g. \"Found 0 match(es)\") counts as\n * NOT having produced valid blocks — the LLM must not fabricate them.\n *\n * @returns Block info if hallucination detected, null otherwise\n */\n private detectHallucinatedBlock(\n text: string,\n toolsUsed: Array<{ name: string; success: boolean; resultSummary?: string }>,\n userMessage?: string,\n ): { type: string; tool: string; description: string } | null {\n const hasSuccessfulCreateIntent = toolsUsed.some(\n (t) => t.name === \"create_intent\" && t.success,\n );\n\n // Check for hallucinated intent_proposal\n if (text.includes(\"```intent_proposal\") && !hasSuccessfulCreateIntent) {\n const match = text.match(/```intent_proposal\\s*\\n\\s*\\{[^}]*\"description\"\\s*:\\s*\"([^\"]+)\"/);\n if (match) {\n return { type: \"intent_proposal\", tool: \"create_intent\", description: match[1] };\n }\n }\n\n // Check for hallucinated opportunity blocks\n if (text.includes(\"```opportunity\") && !ChatAgent.hasOpportunitySource(toolsUsed)) {\n // Use the user's original message as the search query — NOT fields from the\n // hallucinated JSON. The model fabricates person names and reasoning that have\n // nothing to do with the user's actual request, leading to wrong results and\n // the model re-calling the tool with the correct query (doubling negotiation cost).\n const description = userMessage?.trim() || \"find connections\";\n return { type: \"opportunity\", tool: \"discover_opportunities\", description };\n }\n\n return null;\n }\n\n /**\n * Strip ```opportunity and ```intent_proposal code blocks from text\n * when no corresponding successful tool call was made.\n * Defense-in-depth: catches hallucinated blocks that slip past detectHallucinatedBlock\n * (e.g. after a correction iteration that still hallucinates).\n *\n * @param text - The response text to sanitize\n * @param toolsUsed - Tool call records from the agent loop\n * @returns Sanitized text with unbacked blocks removed\n */\n private stripUnbackedBlocks(\n text: string,\n toolsUsed: Array<{ name: string; success: boolean; resultSummary?: string }>,\n ): string {\n let result = text;\n let removedBlock = false;\n\n const hasSuccessfulCreateIntent = toolsUsed.some(\n (t) => t.name === \"create_intent\" && t.success,\n );\n\n if (!ChatAgent.hasOpportunitySource(toolsUsed) && result.includes(\"```opportunity\")) {\n const next = result.replace(/```opportunity\\s*\\n[\\s\\S]*?```/g, \"\");\n removedBlock ||= next !== result;\n result = next;\n }\n if (!hasSuccessfulCreateIntent && result.includes(\"```intent_proposal\")) {\n const next = result.replace(/```intent_proposal\\s*\\n[\\s\\S]*?```/g, \"\");\n removedBlock ||= next !== result;\n result = next;\n }\n\n // Clean up leftover double blank lines only when a block was actually removed\n if (removedBlock) {\n result = result.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n }\n\n return result;\n }\n\n // ─── Phantom write detection ─────────────────────────────────────────────\n\n private static readonly PHANTOM_WRITE_PATTERNS = [\n /\\bI(?:'ve| have) (?:updated|adjusted|changed|modified|edited|created|added|removed|deleted|saved|set up)\\b/i,\n /\\bI (?:updated|adjusted|changed|modified|edited|created|added|removed|deleted|saved|set up)\\b/i,\n /\\b(?:Updated|Adjusted|Changed|Modified|Edited|Created|Added|Removed|Deleted|Saved) (?:your|the|their)\\b/i,\n /\\bEverything is (?:now )?(?:updated|changed|adjusted|saved|set)\\b/i,\n /\\b(?:profile|bio|premise|signal|intent|membership|narrative) (?:has been|is now) (?:updated|changed|modified|adjusted|saved)\\b/i,\n ];\n\n /**\n * Detect when the model claims to have performed a write action\n * without having called any tools in the turn.\n */\n private static detectPhantomWrite(\n responseText: string,\n toolsUsed: Array<{ name: string }>,\n ): boolean {\n if (toolsUsed.length > 0) return false;\n return ChatAgent.PHANTOM_WRITE_PATTERNS.some(pattern => pattern.test(responseText));\n }\n\n // ─── Shared tool-result post-processing types ─────────────────────────────\n private static readonly STEP_DETAIL_MAX = 300;\n\n private static readonly STEP_NAME_MAX = 100;\n\n /**\n * Post-process a tool result: strip _graphTimings, extract summary/debugSteps,\n * and optionally run discover_opportunities → create_intent callback.\n *\n * Returns the normalized result string and extracted debug metadata so both\n * the normal streaming tool loop and the hallucination-recovery branch\n * produce identical LLM-facing payloads.\n */\n private async normalizeToolResult(\n toolName: string,\n resultStr: string,\n toolArgs: Record<string, unknown>,\n ): Promise<{\n resultStr: string;\n summary: string;\n debugSteps?: Array<{ step: string; detail?: string; data?: Record<string, unknown> }>;\n graphTimings?: Array<{ name: string; durationMs: number; agents: Array<{ name: string; durationMs: number }> }>;\n decisionQuestions?: Question[];\n discoveryQuestionsDebug?: DebugMetaDiscoveryQuestions;\n }> {\n let normalized = resultStr;\n\n // Run create_intent callback for discover_opportunities results (orchestrator behavior)\n if (toolName === \"discover_opportunities\" && this.persona.loopBehaviors.createIntentCallback) {\n const callbackResult = await this.handleCreateIntentCallback(normalized, toolArgs);\n if (callbackResult !== null) {\n normalized = callbackResult;\n }\n }\n\n type StepData = Record<string, unknown>;\n type DebugStep = { step: string; detail?: string; data?: StepData };\n type GraphTiming = { name: string; durationMs: number; agents: Array<{ name: string; durationMs: number }> };\n\n let summary = \"Done\";\n let debugSteps: DebugStep[] | undefined;\n let graphTimings: GraphTiming[] | undefined;\n let decisionQuestions: Question[] | undefined;\n let discoveryQuestionsDebug: DebugMetaDiscoveryQuestions | undefined;\n\n try {\n const parsed = JSON.parse(normalized) as {\n success?: boolean;\n data?: {\n summary?: string;\n debugSteps?: DebugStep[];\n _graphTimings?: GraphTiming[];\n };\n summary?: string;\n debugSteps?: DebugStep[];\n _graphTimings?: GraphTiming[];\n };\n const payload = parsed.success && parsed.data != null ? parsed.data : parsed;\n summary = payload.summary ?? parsed.summary ?? \"Done\";\n\n const rawSteps = payload.debugSteps ?? parsed.debugSteps;\n if (Array.isArray(rawSteps) && rawSteps.length > 0) {\n debugSteps = rawSteps.map((s) => ({\n step: String(s.step ?? \"\").slice(0, ChatAgent.STEP_NAME_MAX),\n detail:\n s.detail != null\n ? String(s.detail).slice(0, ChatAgent.STEP_DETAIL_MAX)\n : undefined,\n ...(s.data && typeof s.data === \"object\" ? { data: s.data } : {}),\n }));\n }\n\n const rawGraphTimings = payload._graphTimings ?? parsed._graphTimings;\n if (Array.isArray(rawGraphTimings) && rawGraphTimings.length > 0) {\n graphTimings = rawGraphTimings as GraphTiming[];\n // Strip _graphTimings from the result string sent back to the LLM\n try {\n const cleanedResult = JSON.parse(normalized) as Record<string, unknown>;\n delete cleanedResult._graphTimings;\n if (cleanedResult.data && typeof cleanedResult.data === \"object\") {\n delete (cleanedResult.data as Record<string, unknown>)._graphTimings;\n }\n normalized = JSON.stringify(cleanedResult);\n } catch { /* keep original if can't clean */ }\n }\n\n const rawQuestions = (payload as { questions?: unknown }).questions ?? (parsed as { questions?: unknown }).questions;\n const rawQuestionDebug = (payload as { _discoveryQuestionsDebug?: unknown })._discoveryQuestionsDebug\n ?? (parsed as { _discoveryQuestionsDebug?: unknown })._discoveryQuestionsDebug;\n if (Array.isArray(rawQuestions)) {\n decisionQuestions = rawQuestions as Question[];\n }\n if (rawQuestionDebug && typeof rawQuestionDebug === \"object\") {\n discoveryQuestionsDebug = rawQuestionDebug as DebugMetaDiscoveryQuestions;\n }\n // `_discoveryQuestionsDebug` is internal trace data — strip from the LLM-facing\n // tool result. `questions` is intentionally kept visible so the agent can\n // follow the prompt addendum and reference the decision prompts in its reply.\n if (discoveryQuestionsDebug !== undefined) {\n try {\n const cleaned = JSON.parse(normalized) as Record<string, unknown>;\n const stripFrom = (obj: Record<string, unknown>) => {\n delete obj._discoveryQuestionsDebug;\n };\n stripFrom(cleaned);\n if (cleaned.data && typeof cleaned.data === \"object\") {\n stripFrom(cleaned.data as Record<string, unknown>);\n }\n normalized = JSON.stringify(cleaned);\n } catch { /* keep original */ }\n }\n } catch {\n /* not JSON, keep default */\n }\n\n return {\n resultStr: normalized,\n summary,\n debugSteps,\n graphTimings,\n ...(decisionQuestions !== undefined ? { decisionQuestions } : {}),\n ...(discoveryQuestionsDebug !== undefined ? { discoveryQuestionsDebug } : {}),\n };\n }\n\n /**\n * Run the full agent loop until completion or hard limit.\n *\n * @param initialMessages - Starting conversation messages\n * @returns Final response text and full message history\n */\n @Timed()\n async run(initialMessages: BaseMessage[]): Promise<{\n responseText: string;\n messages: BaseMessage[];\n iterationCount: number;\n }> {\n let messages = initialMessages;\n let iterationCount = 0;\n\n while (iterationCount < HARD_ITERATION_LIMIT) {\n const result = await this.runIteration(messages, iterationCount);\n iterationCount++;\n messages = result.messages;\n\n if (!result.shouldContinue) {\n const responseText =\n result.responseText ||\n \"I apologize, but I couldn't generate a response.\";\n logger.debug(\"Agent final response\", { responseText });\n return {\n responseText,\n messages,\n iterationCount,\n };\n }\n }\n\n // Hit hard limit - force a response\n logger.warn(\"Hit hard iteration limit\", { iterationCount });\n\n const forceResponseMessages = [\n ...messages,\n new SystemMessage(\n \"You have reached the maximum number of tool calls. You MUST provide a final response now. Summarize what you've accomplished and what might still be needed.\",\n ),\n ];\n\n const forcedResponse = await invokeWithAbortSignal(this.model, forceResponseMessages);\n const responseText = extractTextContent(\n forcedResponse.content as string | Array<Record<string, unknown>>,\n );\n logger.debug(\"Agent forced response\", { responseText });\n\n return {\n responseText,\n messages: [...messages, forcedResponse],\n iterationCount,\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // STREAMING RUN (for narration-style output)\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Run the full agent loop with streaming narration.\n *\n * Instead of returning a single blob at the end, this method calls\n * `writer()` for every text token and tool-activity event so the\n * consumer (graph node) can push them out via `config.writer`.\n *\n * @param initialMessages - Starting conversation messages\n * @param writer - Callback to emit streaming events (from `config.writer`)\n * @param signal - Optional AbortSignal to cancel the streaming LLM call and tool execution\n * @returns Final response metadata (same shape as `run()`)\n */\n @Timed()\n async streamRun(\n initialMessages: BaseMessage[],\n writer?: StreamWriter,\n signal?: AbortSignal,\n ): Promise<{\n responseText: string;\n messages: BaseMessage[];\n iterationCount: number;\n debugMeta: { graph: string; iterations: number; tools: DebugMetaToolCall[]; llm: DebugMetaLlm; orchestratorNegotiations?: DebugMetaOrchestratorNegotiations; discoveryQuestions?: DebugMetaDiscoveryQuestions };\n }> {\n const llm: DebugMetaLlm = { calls: 0, totalDurationMs: 0, resets: [], hallucinations: [] };\n const orchestratorNegotiationIds = new Set<string>();\n let lastLlmStart = 0;\n let latestDiscoveryQuestionsDebug: DebugMetaDiscoveryQuestions | undefined;\n\n const emit = (event: AgentStreamEvent) => {\n if (event.type === \"llm_start\") {\n llm.calls += 1;\n lastLlmStart = Date.now();\n } else if (event.type === \"llm_end\") {\n if (lastLlmStart > 0) {\n llm.totalDurationMs += Date.now() - lastLlmStart;\n lastLlmStart = 0;\n }\n } else if (event.type === \"response_reset\") {\n llm.resets.push({ reason: event.reason, at: Date.now() });\n } else if (event.type === \"hallucination_detected\") {\n llm.hallucinations.push({ blockType: event.blockType, tool: event.tool, at: Date.now() });\n } else if (event.type === \"negotiation_session_start\") {\n orchestratorNegotiationIds.add(event.opportunityId);\n }\n try {\n writer?.(event);\n } catch {\n /* swallow if writer is gone */\n }\n };\n\n let messages = initialMessages;\n let iterationCount = 0;\n const toolsDebug: DebugMetaToolCall[] = [];\n const surfacedQuestionIds = new Set<string>();\n const hallucinationAutoInvokeCounts = new Map<string, number>();\n\n while (iterationCount < HARD_ITERATION_LIMIT) {\n if (signal?.aborted) {\n logger.verbose(\"Stream aborted by client\", { iterationCount });\n break;\n }\n emit({ type: \"iteration_start\", iteration: iterationCount });\n\n const iterCtx: IterationContext = {\n recentTools: extractRecentToolCalls(messages),\n currentMessage: ChatAgent.getCurrentUserMessage(messages),\n hasPriorAgentActionProposal: ChatAgent.hasPriorAgentActionProposal(messages),\n ctx: this.resolvedContext,\n };\n const deterministicResponse = this.persona.resolveDeterministicResponse?.(\n this.resolvedContext,\n iterCtx,\n );\n if (deterministicResponse !== undefined && deterministicResponse !== null) {\n emit({ type: \"text_chunk\", content: deterministicResponse });\n messages = [...messages, new AIMessage(deterministicResponse)];\n iterationCount++;\n return {\n responseText: deterministicResponse,\n messages,\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n },\n };\n }\n const systemContent = this.persona.buildSystemContent(this.resolvedContext, iterCtx);\n const fullMessages: BaseMessage[] = [\n new SystemMessage(systemContent),\n ...messages,\n ];\n if (iterationCount >= SOFT_ITERATION_LIMIT) {\n fullMessages.push(new SystemMessage(ITERATION_NUDGE));\n }\n\n logger.verbose(\"Streaming iteration\", {\n iteration: iterationCount,\n messageCount: messages.length,\n pastSoftLimit: iterationCount >= SOFT_ITERATION_LIMIT,\n });\n\n // ── Stream the model response token-by-token ──────────────────────\n emit({ type: \"llm_start\", iteration: iterationCount });\n\n let accumulated: AIMessageChunk | undefined;\n let iterationText = \"\";\n\n try {\n const stream = await this.model.stream(fullMessages, { signal });\n for await (const chunk of stream) {\n // Accumulate using AIMessageChunk.concat() so tool_call_chunks merge and tool_calls is populated\n accumulated = accumulated ? accumulated.concat(chunk) : chunk;\n\n // Emit text content tokens to the user immediately\n const textPart = extractTextFromChunk(chunk);\n if (textPart) {\n emit({ type: \"text_chunk\", content: textPart });\n iterationText += textPart;\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n logger.verbose(\"LLM stream aborted by client\", { iterationCount });\n break; // breaks the outer while loop\n }\n throw err; // re-throw non-abort errors\n }\n\n if (!accumulated) {\n logger.warn(\"Empty model response in streaming iteration\", {\n iterationCount,\n });\n iterationCount++;\n continue;\n }\n\n // ── Check for tool calls ──────────────────────────────────────────\n const toolCalls = accumulated.tool_calls || [];\n\n emit({\n type: \"llm_end\",\n iteration: iterationCount,\n hasToolCalls: toolCalls.length > 0,\n toolNames: toolCalls.length > 0 ? toolCalls.map((tc) => tc.name) : undefined,\n });\n\n if (toolCalls.length > 0) {\n logger.verbose(\"Streaming: agent made tool calls\", {\n iteration: iterationCount,\n tools: toolCalls.map((tc) => tc.name),\n });\n\n // Clear any narration text streamed before tool calls — this text is\n // intermediate reasoning and should not appear in the final response.\n // The next iteration (after tool execution) will produce the real response.\n if (iterationText) {\n emit({ type: \"response_reset\", reason: \"Tool calls detected\" });\n }\n\n // Execute tools one-by-one.\n const toolResults: Array<{\n toolCallId: string;\n name: string;\n result: string;\n }> = [];\n for (const tc of toolCalls) {\n if (signal?.aborted) {\n logger.verbose(\"Stream aborted by client during tool execution\");\n break;\n }\n emit({ type: \"tool_activity\", phase: \"start\", name: tc.name });\n\n const tool = this.toolsByName.get(tc.name);\n if (!tool) {\n const errResult = JSON.stringify({\n success: false,\n error: `Unknown tool: ${tc.name}`,\n });\n toolsDebug.push({\n name: tc.name,\n args: sanitizeForDebugMeta(tc.args) as Record<string, unknown>,\n resultSummary: \"Unknown tool\",\n success: false,\n durationMs: 0,\n });\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: tc.name,\n success: false,\n summary: \"Unknown tool\",\n });\n toolResults.push({\n toolCallId: tc.id || `unknown-${Date.now()}`,\n name: tc.name,\n result: errResult,\n });\n continue;\n }\n\n const toolStart = Date.now();\n try {\n logger.verbose(\"Streaming: executing tool\", { name: tc.name });\n const currentCtx = requestContext.getStore() ?? {};\n let result = await requestContext.run(\n {\n ...currentCtx,\n traceEmitter: (e) => emit(e as AgentStreamEvent),\n // Propagate the caller's AbortSignal into requestContext so\n // long-running graph nodes (orchestrator negotiation fan-out)\n // can suppress event emits after the chat session closes.\n ...(signal && { abortSignal: signal }),\n },\n () => tool.invoke(tc.args),\n );\n const toolDurationMs = Date.now() - toolStart;\n let resultStr =\n typeof result === \"string\" ? result : JSON.stringify(result);\n\n const normalized = await this.normalizeToolResult(tc.name, resultStr, tc.args);\n if (normalized.discoveryQuestionsDebug) latestDiscoveryQuestionsDebug = normalized.discoveryQuestionsDebug;\n resultStr = normalized.resultStr;\n result = resultStr;\n\n if (normalized.decisionQuestions && normalized.decisionQuestions.length > 0) {\n const { fresh, newIds } = deduplicateQuestions(normalized.decisionQuestions, surfacedQuestionIds);\n if (fresh.length > 0) {\n emit({ type: \"decision_questions\", questions: fresh });\n for (const id of newIds) surfacedQuestionIds.add(id);\n }\n }\n\n logger.verbose(\"Streaming: tool completed\", {\n name: tc.name,\n resultLength: resultStr.length,\n });\n\n toolsDebug.push({\n name: tc.name,\n args: sanitizeForDebugMeta(tc.args) as Record<string, unknown>,\n resultSummary: normalized.summary,\n success: true,\n durationMs: toolDurationMs,\n ...(normalized.debugSteps?.length ? { steps: normalized.debugSteps } : {}),\n ...(normalized.graphTimings?.length ? { graphs: normalized.graphTimings } : {}),\n });\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: tc.name,\n success: true,\n summary: normalized.summary,\n steps: normalized.debugSteps,\n });\n\n toolResults.push({\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: resultStr,\n });\n } catch (error) {\n const errMsg =\n error instanceof Error ? error.message : \"Unknown error\";\n logger.error(\"Streaming: tool failed\", {\n name: tc.name,\n error: errMsg,\n });\n toolsDebug.push({\n name: tc.name,\n args: sanitizeForDebugMeta(tc.args) as Record<string, unknown>,\n resultSummary: errMsg,\n success: false,\n durationMs: Date.now() - toolStart,\n });\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: tc.name,\n success: false,\n summary: errMsg,\n });\n toolResults.push({\n toolCallId: tc.id || `${tc.name}-${Date.now()}`,\n name: tc.name,\n result: JSON.stringify({\n success: false,\n error: `Tool execution failed: ${errMsg}`,\n }),\n });\n }\n }\n\n // If aborted during tool execution, discard partial results\n if (signal?.aborted) {\n logger.verbose(\"Stream aborted after partial tool execution, discarding results\");\n break; // break outer while loop — don't append partial toolResults to messages\n }\n\n // Build updated messages and loop\n messages = [\n ...messages,\n accumulated, // AIMessage with tool_calls\n ...toolResults.map(\n (tr) =>\n new ToolMessage({\n tool_call_id: tr.toolCallId,\n content: tr.result,\n name: tr.name,\n }),\n ),\n ];\n iterationCount++;\n continue;\n }\n\n // ── No tool calls → check for hallucinated code blocks ──────────\n // LLMs sometimes write ```intent_proposal or ```opportunity blocks\n // directly instead of calling the corresponding tool. These blocks\n // lack valid proposalIds / data and won't work in the frontend.\n // Auto-invoke the correct tool directly instead of re-asking the LLM.\n // Persona-gated: only personas with hallucinationRecovery enabled (orchestrator)\n // run detection/auto-invoke — other personas never trigger this branch.\n const hallucinatedBlock = this.persona.loopBehaviors.hallucinationRecovery\n ? this.detectHallucinatedBlock(iterationText, toolsDebug, iterCtx.currentMessage)\n : null;\n const priorAutoInvokes = hallucinatedBlock ? (hallucinationAutoInvokeCounts.get(hallucinatedBlock.type) ?? 0) : 0;\n if (hallucinatedBlock && priorAutoInvokes < 2 && iterationCount < HARD_ITERATION_LIMIT - 1) {\n hallucinationAutoInvokeCounts.set(hallucinatedBlock.type, priorAutoInvokes + 1);\n logger.warn(\"Streaming: detected hallucinated block, auto-invoking tool\", {\n iteration: iterationCount,\n blockType: hallucinatedBlock.type,\n tool: hallucinatedBlock.tool,\n extractedDescription: hallucinatedBlock.description,\n autoInvokeAttempt: priorAutoInvokes + 1,\n });\n // Tell the frontend to discard all streamed tokens from this iteration\n emit({ type: \"response_reset\", reason: `Hallucinated ${hallucinatedBlock.type} block detected` });\n emit({ type: \"hallucination_detected\", blockType: hallucinatedBlock.type, tool: hallucinatedBlock.tool });\n\n const tool = this.toolsByName.get(hallucinatedBlock.tool);\n if (tool) {\n const toolCallId = `auto-${hallucinatedBlock.tool}-${Date.now()}`;\n const toolArgs = hallucinatedBlock.type === \"opportunity\"\n ? { searchQuery: hallucinatedBlock.description }\n : { description: hallucinatedBlock.description };\n\n emit({ type: \"tool_activity\", phase: \"start\", name: hallucinatedBlock.tool });\n const toolStart = Date.now();\n try {\n const currentCtx = requestContext.getStore() ?? {};\n const result = await requestContext.run(\n {\n ...currentCtx,\n traceEmitter: (e) => emit(e as AgentStreamEvent),\n // Propagate the caller's AbortSignal into requestContext so\n // long-running graph nodes (orchestrator negotiation fan-out)\n // can suppress event emits after the chat session closes.\n ...(signal && { abortSignal: signal }),\n },\n () => tool.invoke(toolArgs),\n );\n const rawResultStr = typeof result === \"string\" ? result : JSON.stringify(result);\n const toolDurationMs = Date.now() - toolStart;\n\n // Same normalization as the main tool loop: callback + _graphTimings strip\n const normalized = await this.normalizeToolResult(hallucinatedBlock.tool, rawResultStr, toolArgs);\n\n toolsDebug.push({\n name: hallucinatedBlock.tool,\n args: sanitizeForDebugMeta(toolArgs) as Record<string, unknown>,\n resultSummary: normalized.summary,\n success: true,\n durationMs: toolDurationMs,\n ...(normalized.debugSteps?.length ? { steps: normalized.debugSteps } : {}),\n ...(normalized.graphTimings?.length ? { graphs: normalized.graphTimings } : {}),\n });\n // Mirror the main tool loop's handling: forward decision questions\n // and capture debug metadata even when the discovery tool was invoked\n // via the hallucination-recovery path.\n if (normalized.discoveryQuestionsDebug) {\n latestDiscoveryQuestionsDebug = normalized.discoveryQuestionsDebug;\n }\n if (normalized.decisionQuestions && normalized.decisionQuestions.length > 0) {\n const { fresh: freshHallucination, newIds: newIdsHallucination } = deduplicateQuestions(normalized.decisionQuestions, surfacedQuestionIds);\n if (freshHallucination.length > 0) {\n emit({ type: \"decision_questions\", questions: freshHallucination });\n for (const id of newIdsHallucination) surfacedQuestionIds.add(id);\n }\n }\n emit({\n type: \"tool_activity\",\n phase: \"end\",\n name: hallucinatedBlock.tool,\n success: true,\n summary: normalized.summary,\n steps: normalized.debugSteps,\n });\n\n // Build synthetic tool call message + tool result so the next LLM\n // iteration can narrate around real data instead of hallucinated blocks.\n const syntheticAIMessage = new AIMessage({\n content: \"\",\n tool_calls: [{ id: toolCallId, name: hallucinatedBlock.tool, args: toolArgs }],\n });\n messages = [\n ...messages,\n syntheticAIMessage,\n new ToolMessage({ tool_call_id: toolCallId, content: normalized.resultStr, name: hallucinatedBlock.tool }),\n ];\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : \"Unknown error\";\n logger.error(\"Streaming: auto-invoked tool failed after hallucination\", {\n tool: hallucinatedBlock.tool,\n error: errMsg,\n });\n toolsDebug.push({\n name: hallucinatedBlock.tool,\n args: sanitizeForDebugMeta(toolArgs) as Record<string, unknown>,\n resultSummary: errMsg,\n success: false,\n durationMs: Date.now() - toolStart,\n });\n emit({ type: \"tool_activity\", phase: \"end\", name: hallucinatedBlock.tool, success: false, summary: errMsg });\n\n // Fall back to correction message if tool invocation fails\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n `CORRECTION: You wrote a \\`\\`\\`${hallucinatedBlock.type} block without calling ${hallucinatedBlock.tool}. ` +\n `The auto-retry failed (${errMsg}). Please try calling the tool directly.`\n ),\n ];\n }\n } else {\n // Tool not found — fall back to correction message\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n `CORRECTION: You wrote a \\`\\`\\`${hallucinatedBlock.type} block without calling ${hallucinatedBlock.tool}. ` +\n `That block is INVALID. Call the tool directly instead.`\n ),\n ];\n }\n iterationCount++;\n continue;\n }\n\n // ── Circuit breaker: hallucination detected but auto-invoke cap reached ──\n if (hallucinatedBlock && priorAutoInvokes >= 2) {\n logger.warn(\"Streaming: hallucination auto-invoke cap reached, stripping blocks\", {\n iteration: iterationCount,\n blockType: hallucinatedBlock.type,\n attempts: priorAutoInvokes,\n });\n emit({ type: \"response_reset\", reason: `Hallucination cap reached for ${hallucinatedBlock.type}` });\n const stripped = this.stripUnbackedBlocks(iterationText, toolsDebug);\n if (stripped.trim()) {\n emit({ type: \"text_chunk\", content: stripped });\n } else {\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n \"Your previous response only contained invalid code blocks that were removed. \" +\n \"Write a plain text response now — summarize the results of the tools you used. \" +\n \"Do NOT include ```opportunity or ```intent_proposal blocks.\",\n ),\n ];\n iterationCount++;\n continue;\n }\n }\n\n // ── Phantom write: model claims a write action without calling any tools ──\n if (\n ChatAgent.detectPhantomWrite(iterationText, toolsDebug) &&\n iterationCount < HARD_ITERATION_LIMIT - 1\n ) {\n logger.warn(\"Streaming: detected phantom write claim without tool calls\", {\n iteration: iterationCount,\n });\n emit({ type: \"response_reset\", reason: \"Phantom write detected — no tools were called\" });\n emit({ type: \"hallucination_detected\", blockType: \"phantom_write\", tool: \"none\" });\n\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n \"CORRECTION: You claimed to have performed an action (update, create, modify) but you did NOT call any tools. \" +\n \"The user's request has NOT been fulfilled. You MUST call the appropriate tool(s) to actually make the change, \" +\n \"then confirm based on the tool result. Do it now.\",\n ),\n ];\n iterationCount++;\n continue;\n }\n\n // ── Final response already streamed ─────────────────────────────\n // Defense-in-depth: strip any code blocks that require tool backing\n // but slipped through without a successful tool call (persona-gated,\n // same flag as detection since both police tool-backed block types).\n const sanitizedText = this.persona.loopBehaviors.hallucinationRecovery\n ? this.stripUnbackedBlocks(iterationText, toolsDebug)\n : iterationText;\n if (sanitizedText !== iterationText) {\n logger.warn(\"Streaming: stripped unbacked code blocks from final response\", {\n originalLength: iterationText.length,\n sanitizedLength: sanitizedText.length,\n });\n emit({ type: \"response_reset\", reason: \"Sanitized unbacked blocks from response\" });\n // Re-emit the sanitized text so the frontend displays clean content\n if (sanitizedText.trim()) {\n emit({ type: \"text_chunk\", content: sanitizedText });\n }\n\n // If stripping removed ALL content, force a recovery iteration so the\n // user sees an actual response instead of a blank message.\n if (!sanitizedText.trim() && iterationCount < HARD_ITERATION_LIMIT - 1) {\n logger.warn(\"Streaming: sanitized text is empty, forcing recovery iteration\", {\n iteration: iterationCount,\n });\n messages = [\n ...messages,\n accumulated,\n new SystemMessage(\n \"Your previous response only contained invalid code blocks that were removed. \" +\n \"Write a plain text response now — summarize the results of the tools you used. \" +\n \"Do NOT include ```opportunity or ```intent_proposal blocks.\",\n ),\n ];\n iterationCount++;\n continue;\n }\n }\n\n logger.verbose(\"Streaming: agent produced response\", {\n iteration: iterationCount,\n responseLength: sanitizedText.length,\n });\n messages = [...messages, accumulated];\n iterationCount++;\n\n return {\n responseText: sanitizedText,\n messages,\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n ...(orchestratorNegotiationIds.size > 0 && {\n orchestratorNegotiations: { opportunityIds: [...orchestratorNegotiationIds] },\n }),\n ...(latestDiscoveryQuestionsDebug && { discoveryQuestions: latestDiscoveryQuestionsDebug }),\n },\n };\n }\n\n // If aborted, return immediately without making another LLM call\n if (signal?.aborted) {\n return {\n responseText: \"\",\n messages,\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n ...(orchestratorNegotiationIds.size > 0 && {\n orchestratorNegotiations: { opportunityIds: [...orchestratorNegotiationIds] },\n }),\n ...(latestDiscoveryQuestionsDebug && { discoveryQuestions: latestDiscoveryQuestionsDebug }),\n },\n };\n }\n\n // ── Hard limit: force a response ──────────────────────────────────────\n logger.warn(\"Streaming: hit hard iteration limit\", { iterationCount });\n\n const forceMessages = [\n ...messages,\n new SystemMessage(\n \"You have reached the maximum number of tool calls. You MUST provide a final response now. Summarize what you've accomplished and what might still be needed.\",\n ),\n ];\n\n let forcedAccumulated: AIMessageChunk | undefined;\n let forcedResponseText = \"\";\n const forceStream = await this.model.stream(forceMessages);\n for await (const chunk of forceStream) {\n forcedAccumulated = forcedAccumulated\n ? forcedAccumulated.concat(chunk)\n : chunk;\n const textPart = extractTextFromChunk(chunk);\n if (textPart) {\n emit({ type: \"text_chunk\", content: textPart });\n forcedResponseText += textPart;\n }\n }\n\n return {\n responseText: forcedResponseText,\n messages: [\n ...messages,\n ...(forcedAccumulated ? [forcedAccumulated] : []),\n ],\n iterationCount,\n debugMeta: {\n graph: \"agent_loop\",\n iterations: iterationCount,\n tools: toolsDebug,\n llm,\n ...(orchestratorNegotiationIds.size > 0 && {\n orchestratorNegotiations: { opportunityIds: [...orchestratorNegotiationIds] },\n }),\n ...(latestDiscoveryQuestionsDebug && { discoveryQuestions: latestDiscoveryQuestionsDebug }),\n },\n };\n }\n}\n"]}
|
|
@@ -35,6 +35,11 @@ export interface ChatPersonaConfig {
|
|
|
35
35
|
buildSystemContent: (ctx: ResolvedToolContext, iterCtx: IterationContext) => string;
|
|
36
36
|
/** Creates the persona's toolset bound to the resolved user context. */
|
|
37
37
|
createTools: (deps: ToolContext, preResolvedContext?: ResolvedToolContext) => Promise<ChatTools>;
|
|
38
|
+
/**
|
|
39
|
+
* Optionally resolves a turn without an LLM or tools. Use only for narrow,
|
|
40
|
+
* deterministic safety redirects derived entirely from iteration context.
|
|
41
|
+
*/
|
|
42
|
+
resolveDeterministicResponse?: (ctx: ResolvedToolContext, iterCtx: IterationContext) => string | null;
|
|
38
43
|
/** Orchestrator-specific loop behaviors this persona opts into. */
|
|
39
44
|
loopBehaviors: ChatPersonaLoopBehaviors;
|
|
40
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.persona.d.ts","sourceRoot":"/","sources":["chat/chat.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE9H,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAejE;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,kBAAkB,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC;IACpF,wEAAwE;IACxE,WAAW,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,kBAAkB,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACjG,mEAAmE;IACnE,aAAa,EAAE,wBAAwB,CAAC;CACzC;AAED,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAQlC,CAAC"}
|
|
1
|
+
{"version":3,"file":"chat.persona.d.ts","sourceRoot":"/","sources":["chat/chat.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE9H,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAejE;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,kBAAkB,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC;IACpF,wEAAwE;IACxE,WAAW,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,kBAAkB,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACjG;;;OAGG;IACH,4BAA4B,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,KAAK,MAAM,GAAG,IAAI,CAAC;IACtG,mEAAmE;IACnE,aAAa,EAAE,wBAAwB,CAAC;CACzC;AAED,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAQlC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.persona.js","sourceRoot":"/","sources":["chat/chat.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8D,MAAM,iCAAiC,CAAC;AAC9H,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"chat.persona.js","sourceRoot":"/","sources":["chat/chat.persona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8D,MAAM,iCAAiC,CAAC;AAC9H,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA6DtD,kEAAkE;AAClE,MAAM,CAAC,MAAM,uBAAuB,GAAG,cAAc,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,EAAE,EAAE,uBAAuB;IAC3B,kBAAkB,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC;IACtE,WAAW,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,kBAAkB,CAAC;IACpF,aAAa,EAAE;QACb,oBAAoB,EAAE,IAAI;QAC1B,qBAAqB,EAAE,IAAI;KAC5B;CACF,CAAC","sourcesContent":["import { createChatTools, type ChatTools, type ToolContext, type ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport { buildSystemContent } from \"./chat.prompt.js\";\nimport type { IterationContext } from \"./chat.prompt.modules.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// CHAT PERSONA CONFIG\n// ═══════════════════════════════════════════════════════════════════════════════\n//\n// The chat runtime (ChatAgent + ChatGraphFactory) is persona-neutral infrastructure:\n// prompt, toolset, and orchestrator-specific loop behaviors are injected via a\n// ChatPersonaConfig rather than hardcoded. The orchestrator is the default (and\n// currently only) registered persona — its config is exactly the pre-refactor\n// wiring, so behavior is byte-identical for existing chat sessions.\n//\n// Future personas (e.g. the per-user negotiator, P4.1) provide their own prompt\n// builder and toolset, and default all orchestrator loop behaviors OFF.\n\n/**\n * Orchestrator-specific behaviors that live in the agent loop itself\n * (not in the prompt or toolset). Each persona opts in explicitly.\n */\nexport interface ChatPersonaLoopBehaviors {\n /**\n * When `discover_opportunities` returns `createIntentSuggested`, auto-invoke\n * `create_intent` and then re-run `discover_opportunities` with the original\n * arguments.\n */\n createIntentCallback: boolean;\n /**\n * Detect hallucinated ```opportunity / ```intent_proposal code blocks in model\n * text, auto-invoke the corresponding tool, and strip unbacked blocks from the\n * final response. Only meaningful for personas whose toolset can legitimately\n * produce those blocks.\n */\n hallucinationRecovery: boolean;\n}\n\n/**\n * Persona configuration injected into `ChatAgent.create()`.\n *\n * A persona bundles the three orchestrator-coupled seams of the chat runtime:\n * system-prompt construction, toolset creation, and loop behaviors.\n */\nexport interface ChatPersonaConfig {\n /**\n * Stable persona identifier. Matches the `conversations.persona` column value\n * for sessions driven by this persona.\n */\n id: string;\n /** Builds the system prompt for each agent-loop iteration. */\n buildSystemContent: (ctx: ResolvedToolContext, iterCtx: IterationContext) => string;\n /** Creates the persona's toolset bound to the resolved user context. */\n createTools: (deps: ToolContext, preResolvedContext?: ResolvedToolContext) => Promise<ChatTools>;\n /**\n * Optionally resolves a turn without an LLM or tools. Use only for narrow,\n * deterministic safety redirects derived entirely from iteration context.\n */\n resolveDeterministicResponse?: (ctx: ResolvedToolContext, iterCtx: IterationContext) => string | null;\n /** Orchestrator-specific loop behaviors this persona opts into. */\n loopBehaviors: ChatPersonaLoopBehaviors;\n}\n\n/** Persona id for the default orchestrator (\"You are Index…\"). */\nexport const ORCHESTRATOR_PERSONA_ID = \"orchestrator\";\n\n/**\n * The orchestrator persona — exactly the pre-personafication wiring:\n * `buildSystemContent` from chat.prompt, `createChatTools` from tool.factory,\n * and all loop behaviors enabled.\n *\n * Both functions delegate lazily (arrow wrappers) instead of capturing the\n * imported symbols at module-load time. This preserves ESM live-binding\n * semantics: the pre-refactor code read `createChatTools` through its import\n * binding at call time, which is what lets test suites swap the module via\n * `mock.module` — a snapshot in this object literal would pin whichever\n * version was loaded first.\n */\nexport const ORCHESTRATOR_PERSONA: ChatPersonaConfig = {\n id: ORCHESTRATOR_PERSONA_ID,\n buildSystemContent: (ctx, iterCtx) => buildSystemContent(ctx, iterCtx),\n createTools: (deps, preResolvedContext) => createChatTools(deps, preResolvedContext),\n loopBehaviors: {\n createIntentCallback: true,\n hallucinationRecovery: true,\n },\n};\n"]}
|
|
@@ -28,6 +28,8 @@ export interface IterationContext {
|
|
|
28
28
|
}>;
|
|
29
29
|
/** Text of the latest user message (for regex matching). */
|
|
30
30
|
currentMessage?: string;
|
|
31
|
+
/** Whether an earlier assistant turn visibly contained a valid action proposal. */
|
|
32
|
+
hasPriorAgentActionProposal?: boolean;
|
|
31
33
|
/** Resolved tool context (user, profile, indexes, etc.). */
|
|
32
34
|
ctx: ResolvedToolContext;
|
|
33
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.prompt.modules.d.ts","sourceRoot":"/","sources":["chat/chat.prompt.modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,0BAA0B,CAAC;AAEvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAM3E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oGAAoG;IACpG,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACvD,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,OAAO,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,MAAM,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACpE,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,GAAG,EAAE,mBAAmB,CAAC;CAC1B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,WAAW,EAAE,GACtB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CA6BxD;AAoSD,qCAAqC;AACrC,eAAO,MAAM,cAAc,EAAE,YAAY,EAWxC,CAAC;AAMF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CA8ChE"}
|
|
1
|
+
{"version":3,"file":"chat.prompt.modules.d.ts","sourceRoot":"/","sources":["chat/chat.prompt.modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,0BAA0B,CAAC;AAEvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAM3E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oGAAoG;IACpG,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACvD,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,OAAO,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,MAAM,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACpE,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,4DAA4D;IAC5D,GAAG,EAAE,mBAAmB,CAAC;CAC1B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,WAAW,EAAE,GACtB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CA6BxD;AAoSD,qCAAqC;AACrC,eAAO,MAAM,cAAc,EAAE,YAAY,EAWxC,CAAC;AAMF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CA8ChE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.prompt.modules.js","sourceRoot":"/","sources":["chat/chat.prompt.modules.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseMessage, AIMessage } from \"@langchain/core/messages\";\n\nimport type { ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * A conditional prompt section injected into the system prompt based on triggers.\n */\nexport interface PromptModule {\n /** Unique module identifier. */\n id: string;\n /** Tool names that activate this module. */\n triggers: string[];\n /** Module IDs to suppress when this module activates (unidirectional). */\n excludes?: string[];\n /** Optional filter applied after tool trigger match. Return false to skip despite trigger match. */\n triggerFilter?: (iterCtx: IterationContext) => boolean;\n /** User message pattern that activates this module (secondary trigger). */\n regex?: RegExp;\n /** Returns the prompt text to inject. */\n content: (ctx: ResolvedToolContext) => string;\n}\n\n/**\n * State available to module resolution at each iteration.\n */\nexport interface IterationContext {\n /** Tool calls from all iterations since the last user message. */\n recentTools: Array<{ name: string; args: Record<string, unknown> }>;\n /** Text of the latest user message (for regex matching). */\n currentMessage?: string;\n /** Resolved tool context (user, profile, indexes, etc.). */\n ctx: ResolvedToolContext;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// EXTRACTION\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Extracts tool calls from all AI messages since the last HumanMessage.\n *\n * Scans backwards to find the last HumanMessage, then collects all tool calls\n * from AIMessages after that point. This ensures multi-iteration tool history\n * is available for module resolution within a single user turn.\n *\n * @param messages - The current conversation message array\n * @returns Flattened array of tool name + args from the current agent turn\n */\nexport function extractRecentToolCalls(\n messages: BaseMessage[],\n): Array<{ name: string; args: Record<string, unknown> }> {\n // Find the index of the last HumanMessage\n let lastHumanIdx = -1;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]._getType() === \"human\") {\n lastHumanIdx = i;\n break;\n }\n }\n\n // Collect tool calls from all AIMessages after the last HumanMessage\n const toolCalls: Array<{ name: string; args: Record<string, unknown> }> = [];\n const startIdx = lastHumanIdx + 1;\n\n for (let i = startIdx; i < messages.length; i++) {\n const msg = messages[i];\n if (msg._getType() === \"ai\") {\n const aiMsg = msg as AIMessage;\n const calls = aiMsg.tool_calls ?? [];\n for (const tc of calls) {\n toolCalls.push({\n name: tc.name,\n args: (tc.args ?? {}) as Record<string, unknown>,\n });\n }\n }\n }\n\n return toolCalls;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// HELPERS\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Checks whether recent tool calls include discover_opportunities with\n * introduction-specific arguments (partyUserIds or introTargetUserId).\n */\nfunction hasIntroductionArgs(recentTools: IterationContext[\"recentTools\"]): boolean {\n return recentTools.some(\n (t) =>\n t.name === \"discover_opportunities\" &&\n (t.args.partyUserIds || t.args.introTargetUserId),\n );\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// MODULE DEFINITIONS\n// ═══════════════════════════════════════════════════════════════════════════════\n\nconst discoveryModule: PromptModule = {\n id: \"discovery\",\n triggers: [\"discover_opportunities\", \"update_opportunity\", \"list_opportunities\"],\n triggerFilter: (iterCtx) => !hasIntroductionArgs(iterCtx.recentTools),\n content: () => `\n### 1. User wants to find connections or discover (default for connection-seeking)\n\nFor open-ended connection-seeking (\"find me a mentor\", \"who needs a React dev\", \"I want to meet people in AI\", \"looking for investors\", \"find me X\"), run **discovery first**.\n\n**CRITICAL: DO NOT create an intent first. Discovery comes FIRST.**\n\n**Network scoping**: When the user says \"in my network\", \"from my contacts\", \"people I know\", \"among my connections\", or similar network-scoping language, pass the user's **personal network ID** as \\`networkId\\`. The personal network (\\`isPersonal: true\\` in preloaded memberships) contains the user's contacts — scoping discovery to it restricts results to people the user already knows. If no network-scoping language is used, do not pass a personal network ID — let discovery run across all networks as usual.\n\n- Call \\`discover_opportunities(searchQuery=user's request)\\` IMMEDIATELY (with networkId when scoped).\n- Do NOT call \\`create_intent\\` unless the user **explicitly** asks to \"create\", \"save\", \"add\", or \"remember\" an intent/signal.\n- Phrases like \"looking for X\", \"find me X\", \"I want to meet X\", \"I need X\" are discovery requests — NOT intent creation requests.\n- If the tool returns \\`createIntentSuggested\\` and \\`suggestedIntentDescription\\`, the system will create an intent and retry discovery automatically; use the final result (candidates or \"no matches\") for your reply.\n- If the tool returns \\`suggestIntentCreationForVisibility: true\\` and \\`suggestedIntentDescription\\`, after presenting the opportunity cards ask the user whether they'd also like to create a signal so others can find them (e.g. *\"Would you also like to create a signal for this so others can find you?\"*). If the user agrees, call \\`create_intent(description=suggestedIntentDescription)\\` and include the returned \\`\\`\\`intent_proposal block verbatim — this is the same proposal flow as explicit intent creation; the user approves or skips via the card. Ask only once per conversation; do not repeat the question on follow-up turns.\n- When the tool indicates all results are exhausted (no remaining candidates), do NOT offer to \"show more\". Instead suggest the user create a signal so others can find them. This uses the same \\`create_intent\\` flow as above.\n- If the user **explicitly** says they want to create/save an intent (e.g. \"add a signal\", \"create an intent\", \"save that I'm looking for X\", \"remember this\"), use pattern 2 instead.\n\n### 1a. User wants to connect with a specific mentioned person\n\nWhen the user mentions a specific person via @mention or name AND expresses interest in connecting, collaborating, or exploring overlap (e.g. \"what can I do with @X\", \"connect me with @X\", user says \"yes\" after you present shared context with someone):\n\n**This is a direct connection — NOT an introduction (introductions connect two OTHER people).**\n\n\\`\\`\\`\n1. If not already done: read_user_contexts(userId=X) + read_network_memberships(userId=X)\n2. Find shared networks with the user (intersect with preloaded memberships)\n3. If no shared networks: tell the user you can't find a connection path\n4. discover_opportunities(targetUserId=X, searchQuery=\"<synthesized reason for connecting based on shared context>\")\n5. Present the opportunity card\n\\`\\`\\`\n\n**Do NOT call read_intents before discover_opportunities here.** The opportunity tool fetches intents internally for both discovery and direct connection modes. Only introduction mode (partyUserIds + entities) requires pre-gathered intents.\n\nThe searchQuery should be a brief description of why they'd connect (e.g. \"shared interest in design and technology, both in Kernel community\"). This gives the evaluator context for scoring.\n\n### 7. Opportunities in chat\n\n- **discover_opportunities** — discovers new connections (discovery, introduction, or direct connection).\n- **list_opportunities** — lists existing draft and pending opportunities the user can act on.\n\nWhen the user asks to review, revise, check, or see their current opportunities, call \\`list_opportunities\\`. Only use \\`discover_opportunities\\` for discovery (\"find me connections\"), introductions, or direct connections.\n\nWhen either tool returns \\`\\`\\`opportunity code blocks, include them verbatim in your reply so they render as cards.\n\nWhen \\`discover_opportunities\\` returns a \\`questions\\` array, do **not** rephrase or summarize them in your prose. The frontend renders them as an interactive decision card surface. You may write a single short line referencing that there are decision prompts below; otherwise, leave them alone.\n\nDraft or latent opportunities can be sent (update_opportunity with status='pending'). Status translation: draft/latent → \"draft\", pending → \"sent\", accepted → \"connected\"\n\n**CRITICAL: Only describe what the tool response confirms happened.** \"pending\" sends a notification — not a message or invite. \"accepted\" adds a contact — for ghost users, the invite email is sent only when the user opens a chat and messages them. Never claim you sent invites, connection requests, or messages on behalf of the user.\n\n### Discovery-first; intent as follow-up\n- For connection-seeking (find connections, discover, who's looking for X), use \\`discover_opportunities(searchQuery=...)\\` first. Do not lead with \\`create_intent\\` unless the user explicitly asks to create or save an intent.\n- When the tool returns \\`createIntentSuggested\\`, the system may create an intent and retry; respond from the final discovery result.\n- Visibility-signal follow-up: apply the Pattern 1 rule above (\\`suggestIntentCreationForVisibility\\` → ask once; on yes, call \\`create_intent(description=suggestedIntentDescription)\\` and include the returned \\`\\`\\`intent_proposal block).\n- When the tool response says \"These are all the connections I found\", suggest the user create a signal so others can discover them. Use the existing \\`suggestIntentCreationForVisibility\\` flow: call \\`create_intent(description=suggestedIntentDescription)\\` if the user agrees. Do not ask \"Would you like to see more?\" when there are no more candidates.\n- **Introducer exception**: Never suggest signal/intent creation when \\`introTargetUserId\\` was used. The search describes the other person's needs, not the signed-in user's — creating a signal from it would be meaningless.\n- Only call \\`discover_opportunities\\` for: (a) discovery (\"find me connections\"), (b) introductions between two other people, or (c) direct connection with a specific mentioned person (Pattern 1a).\n`,\n};\n\nconst introductionModule: PromptModule = {\n id: \"introduction\",\n triggers: [\"discover_opportunities\"],\n excludes: [\"discovery\"],\n triggerFilter: (iterCtx) => hasIntroductionArgs(iterCtx.recentTools),\n content: () => `\n### 6. Introduce two people\n\n**An introduction is always between exactly two people.** Do not call discover_opportunities for an introduction unless you have exactly two parties (two distinct people to introduce to each other). The entities array must have exactly two entities. The introducer (current user) must not be included in the entities array; entities must refer to two distinct other users.\n\n**You MUST gather all context before calling discover_opportunities. The tool does NOT fetch data internally.**\n\n\\`\\`\\`\n1. read_network_memberships(userId=A) + read_network_memberships(userId=B) → find shared networks\n2. If no shared networks: tell user they're not in any shared community\n3. read_user_contexts(userId=A) + read_user_contexts(userId=B)\n4. For each shared network: read_intents(networkId=X, userId=A) + read_intents(networkId=X, userId=B)\n5. Summarize to user: \"Here's what I found about A and B...\"\n6. discover_opportunities(partyUserIds=[A,B], entities=[{userId:A, profile:{...}, intents:[...], networkId:shared}, {userId:B, ...}], hint=\"user's reason\")\n7. Present the draft introduction\n\\`\\`\\`\n\nThe entities array must include each party's userId, profile data, intents from shared networks, and the shared networkId. The hint is the user's stated reason (e.g. \"both AI devs\"). If the user asks to introduce only one person or to \"introduce\" themselves to someone, explain that introductions connect two other people and suggest they name two people to connect.\n\n### 6a. Discover who to introduce to someone\n\n**When the user asks \"who should I introduce to @Person\" or \"find connections for @Person\"** — they want YOU to discover good connections for that person, presented as introduction cards.\n\n\\`\\`\\`\n1. Identify the person's userId from the @mention (call it mentionedUserId)\n2. discover_opportunities(introTargetUserId=mentionedUserId, searchQuery=\"<optional refinement>\")\n3. Present the returned cards (they will be formatted as introduction cards automatically)\n\\`\\`\\`\n\nThis is different from Pattern 6 (where user names BOTH parties). Here the user names ONE person and asks you to find connections for them. Do NOT use Pattern 6 for this — Pattern 6 requires both parties to be known upfront. Do NOT ask the user for a second person. Do NOT use targetUserId or partyUserIds. The system will find connections automatically.\n\n**CRITICAL — no signal creation in introducer flows:** When \\`introTargetUserId\\` is used (Patterns 6 and 6a), the user is searching for connections on behalf of someone else — the search reflects the other person's needs, not the user's own. Do NOT suggest creating a signal or intent in this context. The search query describes what the *other person* needs (e.g. \"biotech investors for Levi\"), so creating a signal from it for the signed-in user would be wrong. Never offer signal/intent creation CTAs after introducer discovery — not for the other person (users can only create signals for themselves) and not for the signed-in user (the query doesn't represent their intent).\n`,\n};\n\nconst intentCreationModule: PromptModule = {\n id: \"intent-creation\",\n triggers: [\"create_intent\"],\n content: () => `\n### 2. User explicitly wants to create or save an intent\n\n**YOU decide if it's specific enough. The tool proposes — the user confirms.**\n\n\\`\\`\\`\nIF description is vague (\"find a job\", \"meet people\", \"learn something\"):\n 1. read_user_contexts() → get their background\n 2. read_intents() → see existing intents for context\n 3. THINK: given their profile and existing intents, suggest a refined version\n 4. Reply: \"Based on your background in X, did you mean something like 'Y'?\"\n 5. Wait for confirmation\n 6. On \"yes\" → create_intent(description=exact_refined_text)\n\nIF description is specific enough (\"contribute to an open-source LLM project\"):\n → create_intent(description=...) directly\n\\`\\`\\`\n\n**CRITICAL: Never write a \\`\\`\\`intent_proposal block yourself.** To propose an intent you MUST call create_intent(description=...). The tool returns a \\`\\`\\`intent_proposal code block (with proposalId and description). You MUST include that exact block verbatim in your response — it renders as an interactive card. Do not summarize or invent the block; only the tool provides a valid one. Add a brief explanation that creating this intent will let the system look for relevant people in the background.\n\nSpecificity test: Does it contain a concrete domain, action, or scope? If just a single generic verb+noun (\"find a job\"), it's vague. If it has qualifying detail (\"senior UX design role at a tech company in Berlin\"), it's specific.\n`,\n};\n\nconst intentManagementModule: PromptModule = {\n id: \"intent-management\",\n triggers: [\"update_intent\", \"delete_intent\"],\n content: () => `\n### 4. Update or delete an intent\n\n**YOU look up the ID first.**\n\n\\`\\`\\`\n1. read_intents() → get current intents with IDs\n2. Match user's request to the right intent\n3. update_intent(intentId=exact_id, description=...) or delete_intent(intentId=exact_id)\n\\`\\`\\`\n`,\n};\n\nconst personLookupModule: PromptModule = {\n id: \"person-lookup\",\n triggers: [\"read_user_contexts\"],\n content: () => `\n### 0. User asks about a specific person by name\n\nWhen the user mentions a specific person by name (\"find [name]\", \"look up [name]\", \"who is [name]?\", \"tell me about [name]\"), look them up by name first — do NOT use discovery.\n\n- Call \\`read_user_contexts(query=\"the name\")\\` — this finds members by name across the user's indexes\n- If one match: the result already includes their full profile; present it naturally\n- If multiple matches: present the list and ask the user to clarify which person\n- If no matches: tell the user you couldn't find anyone by that name in their network\n- If the user then asks for semantic discovery (e.g. \"find people like them\"), use Pattern 1.\n- If the user wants to connect with this specific person (e.g. \"yes, connect us\", \"what can I do with them\", \"I'd like to reach out\"), use Pattern 1a.\n`,\n};\n\nconst urlScrapingModule: PromptModule = {\n id: \"url-scraping\",\n triggers: [\"scrape_url\"],\n regex: /(https?:\\/\\/)/i,\n content: () => `\n### 3. User includes a URL\n\n**YOU handle scraping before intent creation.**\n\n\\`\\`\\`\n1. scrape_url(url, objective=\"Extract key details for an intent\")\n2. Synthesize a conceptual description from scraped content\n3. create_intent(description=synthesized_summary)\n\\`\\`\\`\n\nException: for profile creation, pass URLs directly to create_user_context (it handles scraping internally).\n\nIf the user pastes or types a profile URL (e.g. linkedin.com/..., github.com/...) to create or update their profile, you MUST pass that exact URL in the corresponding parameter (e.g. linkedinUrl, githubUrl, twitterUrl) to create_user_context, or use scrape_url with that URL then update_user_context; do not use the user's stored social links for that request.\n`,\n};\n\nconst communityModule: PromptModule = {\n id: \"community\",\n triggers: [\"read_networks\", \"create_network\", \"create_network_membership\", \"update_network\", \"delete_network\", \"delete_network_membership\"],\n content: () => `\n### 8. Explore what a community is about\n\n\\`\\`\\`\n0. If user asks about communities they belong to, first use preloaded memberships in this prompt.\n1. read_networks() → get network details (title, prompt)\n2. read_intents(networkId=X) → what members are looking for\n3. read_network_memberships(networkId=X) → who's in it\n4. Synthesize: community purpose, active needs, member composition\n\\`\\`\\`\n\n### When to mention community/index\nIndex and community membership is background: handle it without talking about indexes unless the user asks or it's sign-up, leave, or owner settings. Do not proactively mention \"your indexes\", \"your communities\", \"which index\", \"in your current communities\", or similar. Only mention indexes (or communities, lists) when: (i) post-onboarding sign-up to a community, (ii) user explicitly asked about their indexes/communities, (iii) user wants to leave one, (iv) owner is changing index/community settings. Otherwise use neutral language (\"where you're connected\", \"people you're connected with\") and do not narrate \"your indexes\", \"your current communities\", \"in this network\", etc.\n`,\n};\n\nconst contactsModule: PromptModule = {\n id: \"contacts\",\n triggers: [\"import_gmail_contacts\", \"add_contact\", \"list_contacts\", \"remove_contact\"],\n // Gate on the CONTACTS_ENABLED flag (fail-closed: only `true` enables). When\n // contacts are disabled the import/add tools are de-registered, so this module\n // must not be injected — otherwise the orchestrator keeps advertising Gmail\n // import / add_contact and offers an action that then fails as \"Unknown tool\".\n triggerFilter: (iterCtx) => iterCtx.ctx.contactsEnabled === true,\n content: () => `\n### 9. Import contacts from Gmail\n\n**Single-step workflow:**\n\n\\`\\`\\`\nimport_gmail_contacts()\n→ If not connected: returns { requiresAuth: true, authUrl: \"...\" } — share the URL with the user\n→ If connected: imports contacts directly and returns stats { imported, skipped, newContacts, existingContacts }\n\\`\\`\\`\n\nGhost users are contacts without accounts — they're enriched with public data (LinkedIn, GitHub, X) and can appear in opportunity discovery once enriched.\n\n### 10. Add or manage contacts manually\n\n\\`\\`\\`\n# Add a single contact\nadd_contact(email=\"alice@example.com\", name=\"Alice Smith\")\n\n# List user's network\nlist_contacts() → returns contacts with names, emails, and whether they're ghost users\n\n# Remove a contact\nremove_contact(contactId=X)\n\\`\\`\\`\n`,\n};\n\nconst sharedContextModule: PromptModule = {\n id: \"shared-context\",\n triggers: [\"read_network_memberships\"],\n content: () => `\n### 5. Find shared context between two users\n\n\\`\\`\\`\n1. read_network_memberships(userId=me) → my networks\n2. read_network_memberships(userId=other) → their networks\n3. Intersect networkIds\n4. For each shared network: read_intents(networkId=shared)\n5. read_user_contexts(userId=other)\n6. Synthesize: what overlaps, where they could collaborate\n\\`\\`\\`\n`,\n};\n\nconst mentionsModule: PromptModule = {\n id: \"mentions\",\n triggers: [],\n regex: /@\\[.*?\\]\\(.*?\\)/,\n content: () =>\n `- Messages may contain \\`@[Display Name](userId)\\` markup. The value in parentheses is the userId.\n`,\n};\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// MODULE REGISTRY\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** All registered prompt modules. */\nexport const PROMPT_MODULES: PromptModule[] = [\n discoveryModule,\n introductionModule,\n intentCreationModule,\n intentManagementModule,\n personLookupModule,\n urlScrapingModule,\n communityModule,\n contactsModule,\n sharedContextModule,\n mentionsModule,\n];\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// RESOLUTION\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Resolves which prompt modules should be injected for the current iteration.\n *\n * Phase 1: Skip all modules when onboarding is active (early exit).\n * Phase 2: Collect candidate modules by checking triggers and regex.\n * Phase 3: Apply exclusions (unidirectional — the excluding module stays).\n *\n * @param iterCtx - Current iteration context (tool history, user message, resolved context)\n * @returns Concatenated prompt text from all matched modules\n */\nexport function resolveModules(iterCtx: IterationContext): string {\n // Phase 1 (early exit): Skip all modules during onboarding\n if (iterCtx.ctx.isOnboarding) {\n return \"\";\n }\n\n const toolNames = new Set(iterCtx.recentTools.map((t) => t.name));\n\n // Phase 2: Collect candidates\n const candidates = new Map<string, PromptModule>();\n\n for (const mod of PROMPT_MODULES) {\n let matched = false;\n\n // Check tool triggers (with optional filter for arg-based disambiguation)\n if (mod.triggers.length > 0 && mod.triggers.some((t) => toolNames.has(t))) {\n matched = mod.triggerFilter ? mod.triggerFilter(iterCtx) : true;\n }\n\n // Check regex trigger\n if (!matched && mod.regex && iterCtx.currentMessage && mod.regex.test(iterCtx.currentMessage)) {\n matched = true;\n }\n\n if (matched) {\n candidates.set(mod.id, mod);\n }\n }\n\n // Phase 3: Apply exclusions (skip self-exclusion)\n for (const mod of candidates.values()) {\n if (mod.excludes) {\n for (const excludedId of mod.excludes) {\n if (excludedId !== mod.id) {\n candidates.delete(excludedId);\n }\n }\n }\n }\n\n // Build output\n const sections: string[] = [];\n for (const mod of candidates.values()) {\n sections.push(mod.content(iterCtx.ctx));\n }\n return sections.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat.prompt.modules.js","sourceRoot":"/","sources":["chat/chat.prompt.modules.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseMessage, AIMessage } from \"@langchain/core/messages\";\n\nimport type { ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * A conditional prompt section injected into the system prompt based on triggers.\n */\nexport interface PromptModule {\n /** Unique module identifier. */\n id: string;\n /** Tool names that activate this module. */\n triggers: string[];\n /** Module IDs to suppress when this module activates (unidirectional). */\n excludes?: string[];\n /** Optional filter applied after tool trigger match. Return false to skip despite trigger match. */\n triggerFilter?: (iterCtx: IterationContext) => boolean;\n /** User message pattern that activates this module (secondary trigger). */\n regex?: RegExp;\n /** Returns the prompt text to inject. */\n content: (ctx: ResolvedToolContext) => string;\n}\n\n/**\n * State available to module resolution at each iteration.\n */\nexport interface IterationContext {\n /** Tool calls from all iterations since the last user message. */\n recentTools: Array<{ name: string; args: Record<string, unknown> }>;\n /** Text of the latest user message (for regex matching). */\n currentMessage?: string;\n /** Whether an earlier assistant turn visibly contained a valid action proposal. */\n hasPriorAgentActionProposal?: boolean;\n /** Resolved tool context (user, profile, indexes, etc.). */\n ctx: ResolvedToolContext;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// EXTRACTION\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Extracts tool calls from all AI messages since the last HumanMessage.\n *\n * Scans backwards to find the last HumanMessage, then collects all tool calls\n * from AIMessages after that point. This ensures multi-iteration tool history\n * is available for module resolution within a single user turn.\n *\n * @param messages - The current conversation message array\n * @returns Flattened array of tool name + args from the current agent turn\n */\nexport function extractRecentToolCalls(\n messages: BaseMessage[],\n): Array<{ name: string; args: Record<string, unknown> }> {\n // Find the index of the last HumanMessage\n let lastHumanIdx = -1;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]._getType() === \"human\") {\n lastHumanIdx = i;\n break;\n }\n }\n\n // Collect tool calls from all AIMessages after the last HumanMessage\n const toolCalls: Array<{ name: string; args: Record<string, unknown> }> = [];\n const startIdx = lastHumanIdx + 1;\n\n for (let i = startIdx; i < messages.length; i++) {\n const msg = messages[i];\n if (msg._getType() === \"ai\") {\n const aiMsg = msg as AIMessage;\n const calls = aiMsg.tool_calls ?? [];\n for (const tc of calls) {\n toolCalls.push({\n name: tc.name,\n args: (tc.args ?? {}) as Record<string, unknown>,\n });\n }\n }\n }\n\n return toolCalls;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// HELPERS\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Checks whether recent tool calls include discover_opportunities with\n * introduction-specific arguments (partyUserIds or introTargetUserId).\n */\nfunction hasIntroductionArgs(recentTools: IterationContext[\"recentTools\"]): boolean {\n return recentTools.some(\n (t) =>\n t.name === \"discover_opportunities\" &&\n (t.args.partyUserIds || t.args.introTargetUserId),\n );\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// MODULE DEFINITIONS\n// ═══════════════════════════════════════════════════════════════════════════════\n\nconst discoveryModule: PromptModule = {\n id: \"discovery\",\n triggers: [\"discover_opportunities\", \"update_opportunity\", \"list_opportunities\"],\n triggerFilter: (iterCtx) => !hasIntroductionArgs(iterCtx.recentTools),\n content: () => `\n### 1. User wants to find connections or discover (default for connection-seeking)\n\nFor open-ended connection-seeking (\"find me a mentor\", \"who needs a React dev\", \"I want to meet people in AI\", \"looking for investors\", \"find me X\"), run **discovery first**.\n\n**CRITICAL: DO NOT create an intent first. Discovery comes FIRST.**\n\n**Network scoping**: When the user says \"in my network\", \"from my contacts\", \"people I know\", \"among my connections\", or similar network-scoping language, pass the user's **personal network ID** as \\`networkId\\`. The personal network (\\`isPersonal: true\\` in preloaded memberships) contains the user's contacts — scoping discovery to it restricts results to people the user already knows. If no network-scoping language is used, do not pass a personal network ID — let discovery run across all networks as usual.\n\n- Call \\`discover_opportunities(searchQuery=user's request)\\` IMMEDIATELY (with networkId when scoped).\n- Do NOT call \\`create_intent\\` unless the user **explicitly** asks to \"create\", \"save\", \"add\", or \"remember\" an intent/signal.\n- Phrases like \"looking for X\", \"find me X\", \"I want to meet X\", \"I need X\" are discovery requests — NOT intent creation requests.\n- If the tool returns \\`createIntentSuggested\\` and \\`suggestedIntentDescription\\`, the system will create an intent and retry discovery automatically; use the final result (candidates or \"no matches\") for your reply.\n- If the tool returns \\`suggestIntentCreationForVisibility: true\\` and \\`suggestedIntentDescription\\`, after presenting the opportunity cards ask the user whether they'd also like to create a signal so others can find them (e.g. *\"Would you also like to create a signal for this so others can find you?\"*). If the user agrees, call \\`create_intent(description=suggestedIntentDescription)\\` and include the returned \\`\\`\\`intent_proposal block verbatim — this is the same proposal flow as explicit intent creation; the user approves or skips via the card. Ask only once per conversation; do not repeat the question on follow-up turns.\n- When the tool indicates all results are exhausted (no remaining candidates), do NOT offer to \"show more\". Instead suggest the user create a signal so others can find them. This uses the same \\`create_intent\\` flow as above.\n- If the user **explicitly** says they want to create/save an intent (e.g. \"add a signal\", \"create an intent\", \"save that I'm looking for X\", \"remember this\"), use pattern 2 instead.\n\n### 1a. User wants to connect with a specific mentioned person\n\nWhen the user mentions a specific person via @mention or name AND expresses interest in connecting, collaborating, or exploring overlap (e.g. \"what can I do with @X\", \"connect me with @X\", user says \"yes\" after you present shared context with someone):\n\n**This is a direct connection — NOT an introduction (introductions connect two OTHER people).**\n\n\\`\\`\\`\n1. If not already done: read_user_contexts(userId=X) + read_network_memberships(userId=X)\n2. Find shared networks with the user (intersect with preloaded memberships)\n3. If no shared networks: tell the user you can't find a connection path\n4. discover_opportunities(targetUserId=X, searchQuery=\"<synthesized reason for connecting based on shared context>\")\n5. Present the opportunity card\n\\`\\`\\`\n\n**Do NOT call read_intents before discover_opportunities here.** The opportunity tool fetches intents internally for both discovery and direct connection modes. Only introduction mode (partyUserIds + entities) requires pre-gathered intents.\n\nThe searchQuery should be a brief description of why they'd connect (e.g. \"shared interest in design and technology, both in Kernel community\"). This gives the evaluator context for scoring.\n\n### 7. Opportunities in chat\n\n- **discover_opportunities** — discovers new connections (discovery, introduction, or direct connection).\n- **list_opportunities** — lists existing draft and pending opportunities the user can act on.\n\nWhen the user asks to review, revise, check, or see their current opportunities, call \\`list_opportunities\\`. Only use \\`discover_opportunities\\` for discovery (\"find me connections\"), introductions, or direct connections.\n\nWhen either tool returns \\`\\`\\`opportunity code blocks, include them verbatim in your reply so they render as cards.\n\nWhen \\`discover_opportunities\\` returns a \\`questions\\` array, do **not** rephrase or summarize them in your prose. The frontend renders them as an interactive decision card surface. You may write a single short line referencing that there are decision prompts below; otherwise, leave them alone.\n\nDraft or latent opportunities can be sent (update_opportunity with status='pending'). Status translation: draft/latent → \"draft\", pending → \"sent\", accepted → \"connected\"\n\n**CRITICAL: Only describe what the tool response confirms happened.** \"pending\" sends a notification — not a message or invite. \"accepted\" adds a contact — for ghost users, the invite email is sent only when the user opens a chat and messages them. Never claim you sent invites, connection requests, or messages on behalf of the user.\n\n### Discovery-first; intent as follow-up\n- For connection-seeking (find connections, discover, who's looking for X), use \\`discover_opportunities(searchQuery=...)\\` first. Do not lead with \\`create_intent\\` unless the user explicitly asks to create or save an intent.\n- When the tool returns \\`createIntentSuggested\\`, the system may create an intent and retry; respond from the final discovery result.\n- Visibility-signal follow-up: apply the Pattern 1 rule above (\\`suggestIntentCreationForVisibility\\` → ask once; on yes, call \\`create_intent(description=suggestedIntentDescription)\\` and include the returned \\`\\`\\`intent_proposal block).\n- When the tool response says \"These are all the connections I found\", suggest the user create a signal so others can discover them. Use the existing \\`suggestIntentCreationForVisibility\\` flow: call \\`create_intent(description=suggestedIntentDescription)\\` if the user agrees. Do not ask \"Would you like to see more?\" when there are no more candidates.\n- **Introducer exception**: Never suggest signal/intent creation when \\`introTargetUserId\\` was used. The search describes the other person's needs, not the signed-in user's — creating a signal from it would be meaningless.\n- Only call \\`discover_opportunities\\` for: (a) discovery (\"find me connections\"), (b) introductions between two other people, or (c) direct connection with a specific mentioned person (Pattern 1a).\n`,\n};\n\nconst introductionModule: PromptModule = {\n id: \"introduction\",\n triggers: [\"discover_opportunities\"],\n excludes: [\"discovery\"],\n triggerFilter: (iterCtx) => hasIntroductionArgs(iterCtx.recentTools),\n content: () => `\n### 6. Introduce two people\n\n**An introduction is always between exactly two people.** Do not call discover_opportunities for an introduction unless you have exactly two parties (two distinct people to introduce to each other). The entities array must have exactly two entities. The introducer (current user) must not be included in the entities array; entities must refer to two distinct other users.\n\n**You MUST gather all context before calling discover_opportunities. The tool does NOT fetch data internally.**\n\n\\`\\`\\`\n1. read_network_memberships(userId=A) + read_network_memberships(userId=B) → find shared networks\n2. If no shared networks: tell user they're not in any shared community\n3. read_user_contexts(userId=A) + read_user_contexts(userId=B)\n4. For each shared network: read_intents(networkId=X, userId=A) + read_intents(networkId=X, userId=B)\n5. Summarize to user: \"Here's what I found about A and B...\"\n6. discover_opportunities(partyUserIds=[A,B], entities=[{userId:A, profile:{...}, intents:[...], networkId:shared}, {userId:B, ...}], hint=\"user's reason\")\n7. Present the draft introduction\n\\`\\`\\`\n\nThe entities array must include each party's userId, profile data, intents from shared networks, and the shared networkId. The hint is the user's stated reason (e.g. \"both AI devs\"). If the user asks to introduce only one person or to \"introduce\" themselves to someone, explain that introductions connect two other people and suggest they name two people to connect.\n\n### 6a. Discover who to introduce to someone\n\n**When the user asks \"who should I introduce to @Person\" or \"find connections for @Person\"** — they want YOU to discover good connections for that person, presented as introduction cards.\n\n\\`\\`\\`\n1. Identify the person's userId from the @mention (call it mentionedUserId)\n2. discover_opportunities(introTargetUserId=mentionedUserId, searchQuery=\"<optional refinement>\")\n3. Present the returned cards (they will be formatted as introduction cards automatically)\n\\`\\`\\`\n\nThis is different from Pattern 6 (where user names BOTH parties). Here the user names ONE person and asks you to find connections for them. Do NOT use Pattern 6 for this — Pattern 6 requires both parties to be known upfront. Do NOT ask the user for a second person. Do NOT use targetUserId or partyUserIds. The system will find connections automatically.\n\n**CRITICAL — no signal creation in introducer flows:** When \\`introTargetUserId\\` is used (Patterns 6 and 6a), the user is searching for connections on behalf of someone else — the search reflects the other person's needs, not the user's own. Do NOT suggest creating a signal or intent in this context. The search query describes what the *other person* needs (e.g. \"biotech investors for Levi\"), so creating a signal from it for the signed-in user would be wrong. Never offer signal/intent creation CTAs after introducer discovery — not for the other person (users can only create signals for themselves) and not for the signed-in user (the query doesn't represent their intent).\n`,\n};\n\nconst intentCreationModule: PromptModule = {\n id: \"intent-creation\",\n triggers: [\"create_intent\"],\n content: () => `\n### 2. User explicitly wants to create or save an intent\n\n**YOU decide if it's specific enough. The tool proposes — the user confirms.**\n\n\\`\\`\\`\nIF description is vague (\"find a job\", \"meet people\", \"learn something\"):\n 1. read_user_contexts() → get their background\n 2. read_intents() → see existing intents for context\n 3. THINK: given their profile and existing intents, suggest a refined version\n 4. Reply: \"Based on your background in X, did you mean something like 'Y'?\"\n 5. Wait for confirmation\n 6. On \"yes\" → create_intent(description=exact_refined_text)\n\nIF description is specific enough (\"contribute to an open-source LLM project\"):\n → create_intent(description=...) directly\n\\`\\`\\`\n\n**CRITICAL: Never write a \\`\\`\\`intent_proposal block yourself.** To propose an intent you MUST call create_intent(description=...). The tool returns a \\`\\`\\`intent_proposal code block (with proposalId and description). You MUST include that exact block verbatim in your response — it renders as an interactive card. Do not summarize or invent the block; only the tool provides a valid one. Add a brief explanation that creating this intent will let the system look for relevant people in the background.\n\nSpecificity test: Does it contain a concrete domain, action, or scope? If just a single generic verb+noun (\"find a job\"), it's vague. If it has qualifying detail (\"senior UX design role at a tech company in Berlin\"), it's specific.\n`,\n};\n\nconst intentManagementModule: PromptModule = {\n id: \"intent-management\",\n triggers: [\"update_intent\", \"delete_intent\"],\n content: () => `\n### 4. Update or delete an intent\n\n**YOU look up the ID first.**\n\n\\`\\`\\`\n1. read_intents() → get current intents with IDs\n2. Match user's request to the right intent\n3. update_intent(intentId=exact_id, description=...) or delete_intent(intentId=exact_id)\n\\`\\`\\`\n`,\n};\n\nconst personLookupModule: PromptModule = {\n id: \"person-lookup\",\n triggers: [\"read_user_contexts\"],\n content: () => `\n### 0. User asks about a specific person by name\n\nWhen the user mentions a specific person by name (\"find [name]\", \"look up [name]\", \"who is [name]?\", \"tell me about [name]\"), look them up by name first — do NOT use discovery.\n\n- Call \\`read_user_contexts(query=\"the name\")\\` — this finds members by name across the user's indexes\n- If one match: the result already includes their full profile; present it naturally\n- If multiple matches: present the list and ask the user to clarify which person\n- If no matches: tell the user you couldn't find anyone by that name in their network\n- If the user then asks for semantic discovery (e.g. \"find people like them\"), use Pattern 1.\n- If the user wants to connect with this specific person (e.g. \"yes, connect us\", \"what can I do with them\", \"I'd like to reach out\"), use Pattern 1a.\n`,\n};\n\nconst urlScrapingModule: PromptModule = {\n id: \"url-scraping\",\n triggers: [\"scrape_url\"],\n regex: /(https?:\\/\\/)/i,\n content: () => `\n### 3. User includes a URL\n\n**YOU handle scraping before intent creation.**\n\n\\`\\`\\`\n1. scrape_url(url, objective=\"Extract key details for an intent\")\n2. Synthesize a conceptual description from scraped content\n3. create_intent(description=synthesized_summary)\n\\`\\`\\`\n\nException: for profile creation, pass URLs directly to create_user_context (it handles scraping internally).\n\nIf the user pastes or types a profile URL (e.g. linkedin.com/..., github.com/...) to create or update their profile, you MUST pass that exact URL in the corresponding parameter (e.g. linkedinUrl, githubUrl, twitterUrl) to create_user_context, or use scrape_url with that URL then update_user_context; do not use the user's stored social links for that request.\n`,\n};\n\nconst communityModule: PromptModule = {\n id: \"community\",\n triggers: [\"read_networks\", \"create_network\", \"create_network_membership\", \"update_network\", \"delete_network\", \"delete_network_membership\"],\n content: () => `\n### 8. Explore what a community is about\n\n\\`\\`\\`\n0. If user asks about communities they belong to, first use preloaded memberships in this prompt.\n1. read_networks() → get network details (title, prompt)\n2. read_intents(networkId=X) → what members are looking for\n3. read_network_memberships(networkId=X) → who's in it\n4. Synthesize: community purpose, active needs, member composition\n\\`\\`\\`\n\n### When to mention community/index\nIndex and community membership is background: handle it without talking about indexes unless the user asks or it's sign-up, leave, or owner settings. Do not proactively mention \"your indexes\", \"your communities\", \"which index\", \"in your current communities\", or similar. Only mention indexes (or communities, lists) when: (i) post-onboarding sign-up to a community, (ii) user explicitly asked about their indexes/communities, (iii) user wants to leave one, (iv) owner is changing index/community settings. Otherwise use neutral language (\"where you're connected\", \"people you're connected with\") and do not narrate \"your indexes\", \"your current communities\", \"in this network\", etc.\n`,\n};\n\nconst contactsModule: PromptModule = {\n id: \"contacts\",\n triggers: [\"import_gmail_contacts\", \"add_contact\", \"list_contacts\", \"remove_contact\"],\n // Gate on the CONTACTS_ENABLED flag (fail-closed: only `true` enables). When\n // contacts are disabled the import/add tools are de-registered, so this module\n // must not be injected — otherwise the orchestrator keeps advertising Gmail\n // import / add_contact and offers an action that then fails as \"Unknown tool\".\n triggerFilter: (iterCtx) => iterCtx.ctx.contactsEnabled === true,\n content: () => `\n### 9. Import contacts from Gmail\n\n**Single-step workflow:**\n\n\\`\\`\\`\nimport_gmail_contacts()\n→ If not connected: returns { requiresAuth: true, authUrl: \"...\" } — share the URL with the user\n→ If connected: imports contacts directly and returns stats { imported, skipped, newContacts, existingContacts }\n\\`\\`\\`\n\nGhost users are contacts without accounts — they're enriched with public data (LinkedIn, GitHub, X) and can appear in opportunity discovery once enriched.\n\n### 10. Add or manage contacts manually\n\n\\`\\`\\`\n# Add a single contact\nadd_contact(email=\"alice@example.com\", name=\"Alice Smith\")\n\n# List user's network\nlist_contacts() → returns contacts with names, emails, and whether they're ghost users\n\n# Remove a contact\nremove_contact(contactId=X)\n\\`\\`\\`\n`,\n};\n\nconst sharedContextModule: PromptModule = {\n id: \"shared-context\",\n triggers: [\"read_network_memberships\"],\n content: () => `\n### 5. Find shared context between two users\n\n\\`\\`\\`\n1. read_network_memberships(userId=me) → my networks\n2. read_network_memberships(userId=other) → their networks\n3. Intersect networkIds\n4. For each shared network: read_intents(networkId=shared)\n5. read_user_contexts(userId=other)\n6. Synthesize: what overlaps, where they could collaborate\n\\`\\`\\`\n`,\n};\n\nconst mentionsModule: PromptModule = {\n id: \"mentions\",\n triggers: [],\n regex: /@\\[.*?\\]\\(.*?\\)/,\n content: () =>\n `- Messages may contain \\`@[Display Name](userId)\\` markup. The value in parentheses is the userId.\n`,\n};\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// MODULE REGISTRY\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** All registered prompt modules. */\nexport const PROMPT_MODULES: PromptModule[] = [\n discoveryModule,\n introductionModule,\n intentCreationModule,\n intentManagementModule,\n personLookupModule,\n urlScrapingModule,\n communityModule,\n contactsModule,\n sharedContextModule,\n mentionsModule,\n];\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// RESOLUTION\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/**\n * Resolves which prompt modules should be injected for the current iteration.\n *\n * Phase 1: Skip all modules when onboarding is active (early exit).\n * Phase 2: Collect candidate modules by checking triggers and regex.\n * Phase 3: Apply exclusions (unidirectional — the excluding module stays).\n *\n * @param iterCtx - Current iteration context (tool history, user message, resolved context)\n * @returns Concatenated prompt text from all matched modules\n */\nexport function resolveModules(iterCtx: IterationContext): string {\n // Phase 1 (early exit): Skip all modules during onboarding\n if (iterCtx.ctx.isOnboarding) {\n return \"\";\n }\n\n const toolNames = new Set(iterCtx.recentTools.map((t) => t.name));\n\n // Phase 2: Collect candidates\n const candidates = new Map<string, PromptModule>();\n\n for (const mod of PROMPT_MODULES) {\n let matched = false;\n\n // Check tool triggers (with optional filter for arg-based disambiguation)\n if (mod.triggers.length > 0 && mod.triggers.some((t) => toolNames.has(t))) {\n matched = mod.triggerFilter ? mod.triggerFilter(iterCtx) : true;\n }\n\n // Check regex trigger\n if (!matched && mod.regex && iterCtx.currentMessage && mod.regex.test(iterCtx.currentMessage)) {\n matched = true;\n }\n\n if (matched) {\n candidates.set(mod.id, mod);\n }\n }\n\n // Phase 3: Apply exclusions (skip self-exclusion)\n for (const mod of candidates.values()) {\n if (mod.excludes) {\n for (const excludedId of mod.excludes) {\n if (excludedId !== mod.id) {\n candidates.delete(excludedId);\n }\n }\n }\n }\n\n // Build output\n const sections: string[] = [];\n for (const mod of candidates.values()) {\n sections.push(mod.content(iterCtx.ctx));\n }\n return sections.join(\"\\n\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.persona.d.ts","sourceRoot":"/","sources":["chat/reporter.persona.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9H,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAE/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D,uFAAuF;AACvF,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,kOAWtB,CAAC;AAIX,UAAU,oBAAoB;IAC5B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,oBAAoB,CAAC,EAAE,WAAW,CAAC,sBAAsB,CAAC,CAAC;CAC5D;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAE/E;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,oBAAoB,GAC7B,SAAS,CAkKX;AAED,iEAAiE;AACjE,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,WAAW,EACjB,kBAAkB,CAAC,EAAE,mBAAmB,GACvC,OAAO,CAAC,SAAS,CAAC,CA0BpB;AAED,mDAAmD;AACnD,eAAO,MAAM,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"reporter.persona.d.ts","sourceRoot":"/","sources":["chat/reporter.persona.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9H,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAE/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D,uFAAuF;AACvF,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,kOAWtB,CAAC;AAIX,UAAU,oBAAoB;IAC5B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,oBAAoB,CAAC,EAAE,WAAW,CAAC,sBAAsB,CAAC,CAAC;CAC5D;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAE/E;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,oBAAoB,GAC7B,SAAS,CAkKX;AAED,iEAAiE;AACjE,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,WAAW,EACjB,kBAAkB,CAAC,EAAE,mBAAmB,GACvC,OAAO,CAAC,SAAS,CAAC,CA0BpB;AAED,mDAAmD;AACnD,eAAO,MAAM,gBAAgB,EAAE,iBAS9B,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { createChatTools } from "../shared/agent/tool.factory.js";
|
|
4
4
|
import { error, resolveChatContext, success } from "../shared/agent/tool.helpers.js";
|
|
5
5
|
import { focusedNetworkId, scopeFromNetworkId } from "../shared/agent/tool.scope.js";
|
|
6
|
-
import { buildReporterSystemContent } from "./reporter.prompt.js";
|
|
6
|
+
import { buildReporterSystemContent, resolveReporterDeterministicResponse } from "./reporter.prompt.js";
|
|
7
7
|
import { createReporterActionTool } from "./reporter.action.tools.js";
|
|
8
8
|
/** Public kickoff marker used by the Agent surface to request its opening briefing. */
|
|
9
9
|
export { REPORTER_BRIEFING_KICKOFF } from "./reporter.prompt.js";
|
|
@@ -201,6 +201,7 @@ export const REPORTER_PERSONA = {
|
|
|
201
201
|
id: REPORTER_PERSONA_ID,
|
|
202
202
|
buildSystemContent: (ctx, iterCtx) => buildReporterSystemContent(ctx, iterCtx),
|
|
203
203
|
createTools: (deps, preResolvedContext) => createReporterTools(deps, preResolvedContext),
|
|
204
|
+
resolveDeterministicResponse: (_ctx, iterCtx) => resolveReporterDeterministicResponse(iterCtx),
|
|
204
205
|
loopBehaviors: {
|
|
205
206
|
createIntentCallback: false,
|
|
206
207
|
hallucinationRecovery: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.persona.js","sourceRoot":"/","sources":["chat/reporter.persona.ts"],"names":[],"mappings":"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","sourcesContent":["import { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\n\nimport { createChatTools, type ChatTools, type ResolvedToolContext, type ToolContext } from \"../shared/agent/tool.factory.js\";\nimport { error, resolveChatContext, success } from \"../shared/agent/tool.helpers.js\";\nimport type { UserDatabase } from \"../shared/interfaces/database.interface.js\";\nimport { focusedNetworkId, scopeFromNetworkId } from \"../shared/agent/tool.scope.js\";\nimport type { ChatPersonaConfig } from \"./chat.persona.js\";\nimport { buildReporterSystemContent } from \"./reporter.prompt.js\";\nimport { createReporterActionTool } from \"./reporter.action.tools.js\";\n\n/** Public kickoff marker used by the Agent surface to request its opening briefing. */\nexport { REPORTER_BRIEFING_KICKOFF } from \"./reporter.prompt.js\";\n\n/** Stable persona id persisted for read-only Agent reporting sessions. */\nexport const REPORTER_PERSONA_ID = \"reporter\";\n\n/**\n * Exact positive allowlist for the reporter persona. New shared tools remain\n * unavailable until they are explicitly reviewed here.\n */\nexport const REPORTER_TOOL_NAMES = [\n \"read_intents\",\n \"search_intents\",\n \"read_user_contexts\",\n \"preview_user_context\",\n \"read_premises\",\n \"read_networks\",\n \"read_network_memberships\",\n \"read_pending_questions\",\n \"list_opportunities\",\n \"report_agent_activity\",\n] as const;\n\nconst REPORTER_TOOL_ALLOWLIST: ReadonlySet<string> = new Set(REPORTER_TOOL_NAMES);\n\ninterface ReporterToolBoundary {\n context: ResolvedToolContext;\n userDb: UserDatabase;\n findPendingQuestions?: ToolContext[\"findPendingQuestions\"];\n}\n\n/** Filters a shared registry through the reporter's positive allowlist. */\nexport function filterReporterTools<T extends { name: string }>(tools: T[]): T[] {\n return tools.filter((candidate) => REPORTER_TOOL_ALLOWLIST.has(candidate.name));\n}\n\nfunction invokeSharedTool(sharedTool: { invoke: (input: unknown) => unknown }, input: unknown): Promise<string> {\n return sharedTool.invoke(input) as Promise<string>;\n}\n\n/**\n * Replaces shared tools whose normal modes can enumerate other users with\n * reporter-safe, self-only read contracts. Opportunity listing is deliberately\n * aggregate-only: it never returns a counterpart name, row, or explanation.\n */\nexport function narrowReporterTools(\n allowed: ChatTools,\n boundary: ReporterToolBoundary,\n): ChatTools {\n const { context, userDb } = boundary;\n\n return allowed.map((sharedTool) => {\n if (sharedTool.name === \"read_intents\") {\n return tool(\n async (query: { limit?: number; page?: number }) => {\n const limit = query.limit ?? 100;\n const page = query.page ?? 1;\n const intents = await userDb.getActiveIntents();\n const start = (page - 1) * limit;\n return success({\n intents: intents.slice(start, start + limit),\n page,\n limit,\n total: intents.length,\n });\n },\n {\n name: \"read_intents\",\n description: \"Read the authenticated user's own active signals only.\",\n schema: z.object({\n limit: z.number().int().min(1).max(100).optional(),\n page: z.number().int().min(1).optional(),\n }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"search_intents\") {\n return tool(\n async (query: { query: string; limit?: number }) => success({\n intents: await userDb.searchOwnIntents(query.query, query.limit ?? 20),\n }),\n {\n name: \"search_intents\",\n description: \"Search the authenticated user's own active signals only.\",\n schema: z.object({\n query: z.string().trim().min(1),\n limit: z.number().int().min(1).max(100).optional(),\n }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_user_contexts\") {\n return tool(\n async () => invokeSharedTool(sharedTool, {}),\n {\n name: \"read_user_contexts\",\n description: \"Read the authenticated user's own identity and global context only.\",\n schema: z.object({}).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_premises\") {\n return tool(\n async (query: { includeRetracted?: boolean }) => invokeSharedTool(sharedTool, {\n includeRetracted: query.includeRetracted ?? false,\n userId: context.userId,\n }),\n {\n name: \"read_premises\",\n description: \"Read the authenticated user's own premises only.\",\n schema: z.object({ includeRetracted: z.boolean().optional() }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_network_memberships\") {\n return tool(\n async () => invokeSharedTool(sharedTool, {}),\n {\n name: \"read_network_memberships\",\n description: \"Read the authenticated user's own network memberships only.\",\n schema: z.object({}).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_networks\") {\n return tool(\n async () => invokeSharedTool(sharedTool, { userId: context.userId }),\n {\n name: \"read_networks\",\n description: \"Read networks available to the authenticated user.\",\n schema: z.object({}).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_pending_questions\") {\n return tool(\n async (query: { limit?: number }) => {\n if (!boundary.findPendingQuestions) return error(\"Question lookup is not available.\");\n const questions = await boundary.findPendingQuestions(context.userId, {\n modes: [\"enrichment\", \"intent\", \"discovery\"],\n limit: query.limit ?? 10,\n });\n return success({ questions: questions.slice(0, query.limit ?? 10) });\n },\n {\n name: \"read_pending_questions\",\n description: \"Read the user's own non-negotiation pending questions; answering is unavailable here.\",\n schema: z.object({ limit: z.number().int().min(1).max(10).optional() }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"list_opportunities\") {\n return tool(\n async (query: { networkId?: string }) => {\n const scopedNetworkId = focusedNetworkId(context);\n if (scopedNetworkId && query.networkId && query.networkId !== scopedNetworkId) {\n return error(\"This chat is scoped to a different network.\");\n }\n const activeIntents = await userDb.getActiveIntents();\n const intentById = new Map(activeIntents.map((intent) => [intent.id, intent]));\n const opportunities = await userDb.getOpportunitiesForUser({\n ...(query.networkId || scopedNetworkId ? { networkId: query.networkId || scopedNetworkId } : {}),\n statuses: [\"draft\", \"pending\", \"latent\"],\n limit: 100,\n });\n const counts = new Map<string, { intentId: string; title: string; count: number }>();\n const seen = new Set<string>();\n for (const opportunity of opportunities) {\n const ownIntentIds = new Set(\n opportunity.actors\n .filter((actor) => actor.userId === context.userId && actor.intent && intentById.has(actor.intent))\n .map((actor) => actor.intent as string),\n );\n if (ownIntentIds.size === 0) continue;\n seen.add(opportunity.id);\n for (const intentId of ownIntentIds) {\n const intent = intentById.get(intentId);\n if (!intent) continue;\n const existing = counts.get(intentId) ?? {\n intentId,\n title: intent.summary?.trim() || intent.payload,\n count: 0,\n };\n existing.count += 1;\n counts.set(intentId, existing);\n }\n }\n return success({\n found: seen.size > 0,\n count: seen.size,\n bySignal: [...counts.values()],\n });\n },\n {\n name: \"list_opportunities\",\n description: \"Report current opportunity counts by the user's own signal, without counterpart identities or rows.\",\n schema: z.object({ networkId: z.string().uuid().optional() }).strict(),\n },\n );\n }\n\n return sharedTool;\n }) as ChatTools;\n}\n\n/** Creates the reporter's context-bound, allowlisted toolset. */\nexport async function createReporterTools(\n deps: ToolContext,\n preResolvedContext?: ResolvedToolContext,\n): Promise<ChatTools> {\n const explicitScope = deps.scopeType && deps.scopeId\n ? { scopeType: deps.scopeType, scopeId: deps.scopeId }\n : scopeFromNetworkId(deps.networkId);\n const resolvedContext = preResolvedContext ?? await resolveChatContext({\n database: deps.database,\n userId: deps.userId,\n networkId: explicitScope.scopeType === \"network\" ? explicitScope.scopeId : deps.networkId,\n sessionId: deps.sessionId,\n contactsEnabled: deps.contactsEnabled,\n actionToolsEnabled: deps.actionToolsEnabled,\n });\n if (explicitScope.scopeType && explicitScope.scopeId) {\n resolvedContext.scopeType = explicitScope.scopeType;\n resolvedContext.scopeId = explicitScope.scopeId;\n }\n\n const userDb = deps.userDb ?? deps.createUserDatabase(deps.database, resolvedContext.userId);\n const allowed = filterReporterTools(await createChatTools(deps, resolvedContext)) as ChatTools;\n const narrowed = narrowReporterTools(allowed, {\n context: resolvedContext,\n userDb,\n findPendingQuestions: deps.findPendingQuestions,\n });\n const actionTool = createReporterActionTool(deps, resolvedContext, userDb);\n return actionTool ? [...narrowed, actionTool] as ChatTools : narrowed;\n}\n\n/** Restricted read-only Agent reporter persona. */\nexport const REPORTER_PERSONA: ChatPersonaConfig = {\n id: REPORTER_PERSONA_ID,\n buildSystemContent: (ctx, iterCtx) => buildReporterSystemContent(ctx, iterCtx),\n createTools: (deps, preResolvedContext) => createReporterTools(deps, preResolvedContext),\n loopBehaviors: {\n createIntentCallback: false,\n hallucinationRecovery: false,\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"reporter.persona.js","sourceRoot":"/","sources":["chat/reporter.persona.ts"],"names":[],"mappings":"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","sourcesContent":["import { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\n\nimport { createChatTools, type ChatTools, type ResolvedToolContext, type ToolContext } from \"../shared/agent/tool.factory.js\";\nimport { error, resolveChatContext, success } from \"../shared/agent/tool.helpers.js\";\nimport type { UserDatabase } from \"../shared/interfaces/database.interface.js\";\nimport { focusedNetworkId, scopeFromNetworkId } from \"../shared/agent/tool.scope.js\";\nimport type { ChatPersonaConfig } from \"./chat.persona.js\";\nimport { buildReporterSystemContent, resolveReporterDeterministicResponse } from \"./reporter.prompt.js\";\nimport { createReporterActionTool } from \"./reporter.action.tools.js\";\n\n/** Public kickoff marker used by the Agent surface to request its opening briefing. */\nexport { REPORTER_BRIEFING_KICKOFF } from \"./reporter.prompt.js\";\n\n/** Stable persona id persisted for read-only Agent reporting sessions. */\nexport const REPORTER_PERSONA_ID = \"reporter\";\n\n/**\n * Exact positive allowlist for the reporter persona. New shared tools remain\n * unavailable until they are explicitly reviewed here.\n */\nexport const REPORTER_TOOL_NAMES = [\n \"read_intents\",\n \"search_intents\",\n \"read_user_contexts\",\n \"preview_user_context\",\n \"read_premises\",\n \"read_networks\",\n \"read_network_memberships\",\n \"read_pending_questions\",\n \"list_opportunities\",\n \"report_agent_activity\",\n] as const;\n\nconst REPORTER_TOOL_ALLOWLIST: ReadonlySet<string> = new Set(REPORTER_TOOL_NAMES);\n\ninterface ReporterToolBoundary {\n context: ResolvedToolContext;\n userDb: UserDatabase;\n findPendingQuestions?: ToolContext[\"findPendingQuestions\"];\n}\n\n/** Filters a shared registry through the reporter's positive allowlist. */\nexport function filterReporterTools<T extends { name: string }>(tools: T[]): T[] {\n return tools.filter((candidate) => REPORTER_TOOL_ALLOWLIST.has(candidate.name));\n}\n\nfunction invokeSharedTool(sharedTool: { invoke: (input: unknown) => unknown }, input: unknown): Promise<string> {\n return sharedTool.invoke(input) as Promise<string>;\n}\n\n/**\n * Replaces shared tools whose normal modes can enumerate other users with\n * reporter-safe, self-only read contracts. Opportunity listing is deliberately\n * aggregate-only: it never returns a counterpart name, row, or explanation.\n */\nexport function narrowReporterTools(\n allowed: ChatTools,\n boundary: ReporterToolBoundary,\n): ChatTools {\n const { context, userDb } = boundary;\n\n return allowed.map((sharedTool) => {\n if (sharedTool.name === \"read_intents\") {\n return tool(\n async (query: { limit?: number; page?: number }) => {\n const limit = query.limit ?? 100;\n const page = query.page ?? 1;\n const intents = await userDb.getActiveIntents();\n const start = (page - 1) * limit;\n return success({\n intents: intents.slice(start, start + limit),\n page,\n limit,\n total: intents.length,\n });\n },\n {\n name: \"read_intents\",\n description: \"Read the authenticated user's own active signals only.\",\n schema: z.object({\n limit: z.number().int().min(1).max(100).optional(),\n page: z.number().int().min(1).optional(),\n }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"search_intents\") {\n return tool(\n async (query: { query: string; limit?: number }) => success({\n intents: await userDb.searchOwnIntents(query.query, query.limit ?? 20),\n }),\n {\n name: \"search_intents\",\n description: \"Search the authenticated user's own active signals only.\",\n schema: z.object({\n query: z.string().trim().min(1),\n limit: z.number().int().min(1).max(100).optional(),\n }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_user_contexts\") {\n return tool(\n async () => invokeSharedTool(sharedTool, {}),\n {\n name: \"read_user_contexts\",\n description: \"Read the authenticated user's own identity and global context only.\",\n schema: z.object({}).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_premises\") {\n return tool(\n async (query: { includeRetracted?: boolean }) => invokeSharedTool(sharedTool, {\n includeRetracted: query.includeRetracted ?? false,\n userId: context.userId,\n }),\n {\n name: \"read_premises\",\n description: \"Read the authenticated user's own premises only.\",\n schema: z.object({ includeRetracted: z.boolean().optional() }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_network_memberships\") {\n return tool(\n async () => invokeSharedTool(sharedTool, {}),\n {\n name: \"read_network_memberships\",\n description: \"Read the authenticated user's own network memberships only.\",\n schema: z.object({}).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_networks\") {\n return tool(\n async () => invokeSharedTool(sharedTool, { userId: context.userId }),\n {\n name: \"read_networks\",\n description: \"Read networks available to the authenticated user.\",\n schema: z.object({}).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"read_pending_questions\") {\n return tool(\n async (query: { limit?: number }) => {\n if (!boundary.findPendingQuestions) return error(\"Question lookup is not available.\");\n const questions = await boundary.findPendingQuestions(context.userId, {\n modes: [\"enrichment\", \"intent\", \"discovery\"],\n limit: query.limit ?? 10,\n });\n return success({ questions: questions.slice(0, query.limit ?? 10) });\n },\n {\n name: \"read_pending_questions\",\n description: \"Read the user's own non-negotiation pending questions; answering is unavailable here.\",\n schema: z.object({ limit: z.number().int().min(1).max(10).optional() }).strict(),\n },\n );\n }\n\n if (sharedTool.name === \"list_opportunities\") {\n return tool(\n async (query: { networkId?: string }) => {\n const scopedNetworkId = focusedNetworkId(context);\n if (scopedNetworkId && query.networkId && query.networkId !== scopedNetworkId) {\n return error(\"This chat is scoped to a different network.\");\n }\n const activeIntents = await userDb.getActiveIntents();\n const intentById = new Map(activeIntents.map((intent) => [intent.id, intent]));\n const opportunities = await userDb.getOpportunitiesForUser({\n ...(query.networkId || scopedNetworkId ? { networkId: query.networkId || scopedNetworkId } : {}),\n statuses: [\"draft\", \"pending\", \"latent\"],\n limit: 100,\n });\n const counts = new Map<string, { intentId: string; title: string; count: number }>();\n const seen = new Set<string>();\n for (const opportunity of opportunities) {\n const ownIntentIds = new Set(\n opportunity.actors\n .filter((actor) => actor.userId === context.userId && actor.intent && intentById.has(actor.intent))\n .map((actor) => actor.intent as string),\n );\n if (ownIntentIds.size === 0) continue;\n seen.add(opportunity.id);\n for (const intentId of ownIntentIds) {\n const intent = intentById.get(intentId);\n if (!intent) continue;\n const existing = counts.get(intentId) ?? {\n intentId,\n title: intent.summary?.trim() || intent.payload,\n count: 0,\n };\n existing.count += 1;\n counts.set(intentId, existing);\n }\n }\n return success({\n found: seen.size > 0,\n count: seen.size,\n bySignal: [...counts.values()],\n });\n },\n {\n name: \"list_opportunities\",\n description: \"Report current opportunity counts by the user's own signal, without counterpart identities or rows.\",\n schema: z.object({ networkId: z.string().uuid().optional() }).strict(),\n },\n );\n }\n\n return sharedTool;\n }) as ChatTools;\n}\n\n/** Creates the reporter's context-bound, allowlisted toolset. */\nexport async function createReporterTools(\n deps: ToolContext,\n preResolvedContext?: ResolvedToolContext,\n): Promise<ChatTools> {\n const explicitScope = deps.scopeType && deps.scopeId\n ? { scopeType: deps.scopeType, scopeId: deps.scopeId }\n : scopeFromNetworkId(deps.networkId);\n const resolvedContext = preResolvedContext ?? await resolveChatContext({\n database: deps.database,\n userId: deps.userId,\n networkId: explicitScope.scopeType === \"network\" ? explicitScope.scopeId : deps.networkId,\n sessionId: deps.sessionId,\n contactsEnabled: deps.contactsEnabled,\n actionToolsEnabled: deps.actionToolsEnabled,\n });\n if (explicitScope.scopeType && explicitScope.scopeId) {\n resolvedContext.scopeType = explicitScope.scopeType;\n resolvedContext.scopeId = explicitScope.scopeId;\n }\n\n const userDb = deps.userDb ?? deps.createUserDatabase(deps.database, resolvedContext.userId);\n const allowed = filterReporterTools(await createChatTools(deps, resolvedContext)) as ChatTools;\n const narrowed = narrowReporterTools(allowed, {\n context: resolvedContext,\n userDb,\n findPendingQuestions: deps.findPendingQuestions,\n });\n const actionTool = createReporterActionTool(deps, resolvedContext, userDb);\n return actionTool ? [...narrowed, actionTool] as ChatTools : narrowed;\n}\n\n/** Restricted read-only Agent reporter persona. */\nexport const REPORTER_PERSONA: ChatPersonaConfig = {\n id: REPORTER_PERSONA_ID,\n buildSystemContent: (ctx, iterCtx) => buildReporterSystemContent(ctx, iterCtx),\n createTools: (deps, preResolvedContext) => createReporterTools(deps, preResolvedContext),\n resolveDeterministicResponse: (_ctx, iterCtx) => resolveReporterDeterministicResponse(iterCtx),\n loopBehaviors: {\n createIntentCallback: false,\n hallucinationRecovery: false,\n },\n};\n"]}
|
|
@@ -10,6 +10,10 @@ export declare const REPORTER_BRIEFING_KICKOFF = "reporter-briefing-kickoff";
|
|
|
10
10
|
* @returns Whether this turn is the Agent-surface briefing kickoff
|
|
11
11
|
*/
|
|
12
12
|
export declare function isReporterBriefingKickoff(message?: string): boolean;
|
|
13
|
+
/** Recognizes a short acknowledgement only when a prior proposal is visible. */
|
|
14
|
+
export declare function isReporterActionConfirmation(message?: string, hasPriorProposal?: boolean): boolean;
|
|
15
|
+
/** Deterministic reporter response for contextual typed acknowledgements. */
|
|
16
|
+
export declare function resolveReporterDeterministicResponse(iterCtx: IterationContext): string | null;
|
|
13
17
|
/**
|
|
14
18
|
* Builds the read-only reporter persona prompt.
|
|
15
19
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.prompt.d.ts","sourceRoot":"/","sources":["chat/reporter.prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"reporter.prompt.d.ts","sourceRoot":"/","sources":["chat/reporter.prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAOnE;AAED,gFAAgF;AAChF,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,gBAAgB,UAAQ,GAAG,OAAO,CAoBhG;AAED,6EAA6E;AAC7E,wBAAgB,oCAAoC,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CAM7F;AA8BD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,mBAAmB,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CA6ER"}
|
|
@@ -13,13 +13,37 @@ export function isReporterBriefingKickoff(message) {
|
|
|
13
13
|
.replace(/^_+|_+$/g, "");
|
|
14
14
|
if (!normalized)
|
|
15
15
|
return false;
|
|
16
|
+
return normalized === REPORTER_BRIEFING_KICKOFF;
|
|
17
|
+
}
|
|
18
|
+
/** Recognizes a short acknowledgement only when a prior proposal is visible. */
|
|
19
|
+
export function isReporterActionConfirmation(message, hasPriorProposal = false) {
|
|
20
|
+
const normalized = message?.trim().toLocaleLowerCase()
|
|
21
|
+
.replace(/[.!?,;:]+$/g, "")
|
|
22
|
+
.replace(/\s+/g, " ");
|
|
23
|
+
if (!normalized || !hasPriorProposal)
|
|
24
|
+
return false;
|
|
16
25
|
return new Set([
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
26
|
+
"i confirm",
|
|
27
|
+
"confirm",
|
|
28
|
+
"confirm it",
|
|
29
|
+
"approve",
|
|
30
|
+
"approved",
|
|
31
|
+
"approve it",
|
|
32
|
+
"i approve",
|
|
33
|
+
"yes",
|
|
34
|
+
"yes i confirm",
|
|
35
|
+
"yes please",
|
|
36
|
+
"please do it",
|
|
37
|
+
"proceed",
|
|
38
|
+
"go ahead",
|
|
21
39
|
]).has(normalized);
|
|
22
40
|
}
|
|
41
|
+
/** Deterministic reporter response for contextual typed acknowledgements. */
|
|
42
|
+
export function resolveReporterDeterministicResponse(iterCtx) {
|
|
43
|
+
if (!isReporterActionConfirmation(iterCtx.currentMessage, iterCtx.hasPriorAgentActionProposal === true))
|
|
44
|
+
return null;
|
|
45
|
+
return "Use the visible proposal card's Confirm control to approve this request. I won't run or recreate it from a chat acknowledgement.";
|
|
46
|
+
}
|
|
23
47
|
function buildBriefingGuidance(iterCtx) {
|
|
24
48
|
if (!isReporterBriefingKickoff(iterCtx?.currentMessage))
|
|
25
49
|
return "";
|
|
@@ -33,6 +57,16 @@ This is the Agent-surface briefing kickoff. Call report_agent_activity first wit
|
|
|
33
57
|
4. what should I sharpen?
|
|
34
58
|
Do not claim a metric unless it appears in a tool result from this turn. If a section has no grounded data, say that plainly rather than filling the gap.`;
|
|
35
59
|
}
|
|
60
|
+
function buildTurnGuidance(iterCtx) {
|
|
61
|
+
const currentMessage = iterCtx?.currentMessage;
|
|
62
|
+
const confirmation = isReporterActionConfirmation(currentMessage, iterCtx?.hasPriorAgentActionProposal === true);
|
|
63
|
+
return `
|
|
64
|
+
|
|
65
|
+
## Turn discipline
|
|
66
|
+
- The detailed four-section opening briefing is reserved for the exact reporter-briefing-kickoff marker. Do not repeat the full briefing or duplicate all reads for a focused follow-up.
|
|
67
|
+
- For every non-kickoff message, answer only the user's current request and perform only the reads needed to answer it.
|
|
68
|
+
${confirmation ? `- This message is only a natural-language acknowledgement. Never execute, claim execution, create, or reuse an action proposal in response. Do not call report_agent_activity or propose_cleanup_actions. Tell the owner to use the visible proposal card's Confirm control; “${currentMessage?.trim()}” is not endpoint confirmation.` : ""}`;
|
|
69
|
+
}
|
|
36
70
|
/**
|
|
37
71
|
* Builds the read-only reporter persona prompt.
|
|
38
72
|
*
|
|
@@ -111,6 +145,6 @@ ${profileContext}
|
|
|
111
145
|
${membershipContext}
|
|
112
146
|
\`\`\`
|
|
113
147
|
|
|
114
|
-
Only the identity, context, and membership metadata above are preloaded. Signals, premises, questions, and activity are not preloaded: call the appropriate read/report tool before describing them.${buildBriefingGuidance(iterCtx)}`;
|
|
148
|
+
Only the identity, context, and membership metadata above are preloaded. Signals, premises, questions, and activity are not preloaded: call the appropriate read/report tool before describing them.${buildTurnGuidance(iterCtx)}${buildBriefingGuidance(iterCtx)}`;
|
|
115
149
|
}
|
|
116
150
|
//# sourceMappingURL=reporter.prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.prompt.js","sourceRoot":"/","sources":["chat/reporter.prompt.ts"],"names":[],"mappings":"AAGA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,MAAM,UAAU,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,iBAAiB,EAAE;SACnD,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAE9B,OAAO,IAAI,GAAG,CAAC;QACb,yBAAyB;QACzB,mBAAmB;QACnB,mBAAmB;QACnB,gBAAgB;KACjB,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACrB,CAAC;AAED,SAAS,qBAAqB,CAAC,OAA0B;IACvD,IAAI,CAAC,yBAAyB,CAAC,OAAO,EAAE,cAAc,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnE,OAAO;;;;;;;;0JAQiJ,CAAC;AAC3J,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,GAAwB,EACxB,OAA0B;IAE1B,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,iBAAiB,GAAG,IAAI,CAAC,SAAS,CACtC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACjC,EAAE,EAAE,OAAO,CAAC,SAAS;QACrB,KAAK,EAAE,OAAO,CAAC,YAAY;QAC3B,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC,EACH,IAAI,EACJ,CAAC,CACF,CAAC;IACF,MAAM,YAAY,GAAG,GAAG,CAAC,kBAAkB;QACzC,CAAC,CAAC,mOAAmO;QACrO,CAAC,CAAC,uTAAuT,CAAC;IAC5T,MAAM,YAAY,GAAG,GAAG,CAAC,kBAAkB;QACzC,CAAC,CAAC,oNAAoN;QACtN,CAAC,CAAC,kLAAkL,CAAC;IACvL,MAAM,cAAc,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;;;;;;;;CAQjD,CAAC,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,qEAAqE,GAAG,CAAC,QAAQ;;EAExF,YAAY,GAAG,cAAc;;;;;;EAM7B,YAAY;;;;;;;;;;;;;;;;;;oGAkBsF,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,sGAAsG,CAAC,CAAC,CAAC,EAAE;;;UAG9N,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,SAAS,UAAU,GAAG,CAAC,MAAM;;;;EAI1D,WAAW;;;;;EAKX,cAAc;;;;;EAKd,iBAAiB;;;sMAGmL,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;AACvO,CAAC","sourcesContent":["import type { ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport type { IterationContext } from \"./chat.prompt.modules.js\";\n\n/** Stable marker used by the Agent surface to request its opening briefing. */\nexport const REPORTER_BRIEFING_KICKOFF = \"reporter-briefing-kickoff\";\n\n/**\n * Recognizes the explicit opening briefing marker without putting ordinary\n * reporter conversations into briefing mode accidentally.\n *\n * @param message - Latest user message in the current turn\n * @returns Whether this turn is the Agent-surface briefing kickoff\n */\nexport function isReporterBriefingKickoff(message?: string): boolean {\n const normalized = message?.trim().toLocaleLowerCase()\n .replace(/[–—]/g, \"-\")\n .replace(/^_+|_+$/g, \"\");\n if (!normalized) return false;\n\n return new Set([\n REPORTER_BRIEFING_KICKOFF,\n \"reporter-briefing\",\n \"reporter briefing\",\n \"agent briefing\",\n ]).has(normalized);\n}\n\nfunction buildBriefingGuidance(iterCtx?: IterationContext): string {\n if (!isReporterBriefingKickoff(iterCtx?.currentMessage)) return \"\";\n\n return `\n\n## Opening briefing\nThis is the Agent-surface briefing kickoff. Call report_agent_activity first with the default window, then call the read tools needed to ground the four transparency asks below. Present one concise briefing covering:\n1. summarize all my signals;\n2. what did you do today?;\n3. how do I look to others?;\n4. what should I sharpen?\nDo not claim a metric unless it appears in a tool result from this turn. If a section has no grounded data, say that plainly rather than filling the gap.`;\n}\n\n/**\n * Builds the read-only reporter persona prompt.\n *\n * @param ctx - Resolved authenticated user context\n * @param iterCtx - Current agent-loop context used for briefing kickoff\n * @returns Complete reporter system content\n */\nexport function buildReporterSystemContent(\n ctx: ResolvedToolContext,\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 membershipContext = JSON.stringify(\n ctx.userNetworks.map((network) => ({\n id: network.networkId,\n title: network.networkTitle,\n isPersonal: network.isPersonal,\n })),\n null,\n 2,\n );\n const roleGuidance = ctx.actionToolsEnabled\n ? \"Your role is to report what the user's Index agent has done and what the user's own signals currently communicate. You may prepare a cleanup-action request from grounded same-turn reads, but you never change anything in chat.\"\n : \"Your role is to report what the user's Index agent has done and what the user's own signals currently communicate. You observe; you never change anything. Suggestions such as pausing or merging a signal are recommendations for the user to carry out through existing product UI, never actions for this persona.\";\n const mutationRule = ctx.actionToolsEnabled\n ? \"- Never mutate data in chat. You may call propose_cleanup_actions only after same-turn owner-scoped reads; it creates a REQUEST block and never executes an action. The owner must confirm through the product UI.\"\n : \"- Never create, update, delete, confirm, answer, remember, forget, assign, discover, negotiate, scrape, or otherwise mutate data. Do not ask the user a question through a tool.\";\n const actionGuidance = ctx.actionToolsEnabled ? `\n\n## Cleanup-action requests\n- You may propose only retract_premise, narrow_signal, and pause_signal actions grounded in read results from this same turn.\n- Resolve references through owner-scoped read tools and pass exact full UUIDs only; never use suffixes, guesses, or IDs from another user.\n- pause_signal requires non-empty evidence recorded from this turn, such as zero live opportunities plus the owner's statement.\n- The proposal block is a REQUEST for owner confirmation. Never narrate an action as completed and never mutate inside chat.\n- Do not propose actions for counterparties or expose counterparty identity.\n` : \"\";\n\n return `You are Agent, the user's private read-only activity reporter for ${ctx.userName}.\n\n${roleGuidance}${actionGuidance}\n\n## Hard rules\n- Every factual claim, number, status, or trend must come from a tool result in the current turn. Never invent, estimate, or reuse an unverified metric.\n- Use report_agent_activity for activity counts and read_intents/read_user_contexts/read_premises/read_networks/read_network_memberships/read_pending_questions for the underlying current state.\n- Counterparties are identity-free aggregate data only: never reveal names, IDs, transcripts, message text, or per-counterparty rows. Do not infer what another person thinks from a match or negotiation.\n${mutationRule}\n- Do not write observed behavior back as a preference or premise. The user decides whether to act on a suggestion.\n- If opportunity information is relevant, use only the restricted list_opportunities result or report_agent_activity result. Do not expose raw evaluator reasoning, matchReason, or internal JSON. Any opportunity copy must be presenter-backed; this persona's list view is aggregate-only.\n- Be transparent about missing data and the reporting window. Keep the response concise, calm, and useful without hype.\n\n## Four transparency asks\nBe ready to answer:\n- “summarize all my signals” — read the user's own signals and describe their current themes without inventing a synthesis.\n- “what did you do today?” — report only grounded activity counts from the requested window.\n- “how do I look to others?” — describe only the user's own stored context and signals; do not claim access to private counterparty opinions.\n- “what should I sharpen?” — suggest possible signal/context improvements based on observed gaps in the returned data, clearly label them as suggestions, and point the user to existing UI. Never apply them.\n\n## Allowed capabilities\n- Own signal reads: read_intents, search_intents.\n- Own context reads: read_user_contexts, preview_user_context, read_premises.\n- Own community context: read_networks, read_network_memberships.\n- Own pending-question reads: read_pending_questions (never answer them).\n- Aggregate activity reporting: report_agent_activity.\n- Aggregate current opportunity reporting: list_opportunities (no counterpart identities or rows).${ctx.actionToolsEnabled ? \"\\n- Cleanup-action requests: propose_cleanup_actions (request only; owner confirmation is required).\" : \"\"}\n\n## Session identity (preloaded)\n- User: ${ctx.userName} (${ctx.userEmail}), id: ${ctx.userId}\n\n### User record\n\\`\\`\\`json\n${userContext}\n\\`\\`\\`\n\n### User context\n\\`\\`\\`json\n${profileContext}\n\\`\\`\\`\n\n### Current memberships\n\\`\\`\\`json\n${membershipContext}\n\\`\\`\\`\n\nOnly the identity, context, and membership metadata above are preloaded. Signals, premises, questions, and activity are not preloaded: call the appropriate read/report tool before describing them.${buildBriefingGuidance(iterCtx)}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reporter.prompt.js","sourceRoot":"/","sources":["chat/reporter.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResolvedToolContext } from \"../shared/agent/tool.factory.js\";\nimport type { IterationContext } from \"./chat.prompt.modules.js\";\n\n/** Stable marker used by the Agent surface to request its opening briefing. */\nexport const REPORTER_BRIEFING_KICKOFF = \"reporter-briefing-kickoff\";\n\n/**\n * Recognizes the explicit opening briefing marker without putting ordinary\n * reporter conversations into briefing mode accidentally.\n *\n * @param message - Latest user message in the current turn\n * @returns Whether this turn is the Agent-surface briefing kickoff\n */\nexport function isReporterBriefingKickoff(message?: string): boolean {\n const normalized = message?.trim().toLocaleLowerCase()\n .replace(/[–—]/g, \"-\")\n .replace(/^_+|_+$/g, \"\");\n if (!normalized) return false;\n\n return normalized === REPORTER_BRIEFING_KICKOFF;\n}\n\n/** Recognizes a short acknowledgement only when a prior proposal is visible. */\nexport function isReporterActionConfirmation(message?: string, hasPriorProposal = false): boolean {\n const normalized = message?.trim().toLocaleLowerCase()\n .replace(/[.!?,;:]+$/g, \"\")\n .replace(/\\s+/g, \" \");\n if (!normalized || !hasPriorProposal) return false;\n return new Set([\n \"i confirm\",\n \"confirm\",\n \"confirm it\",\n \"approve\",\n \"approved\",\n \"approve it\",\n \"i approve\",\n \"yes\",\n \"yes i confirm\",\n \"yes please\",\n \"please do it\",\n \"proceed\",\n \"go ahead\",\n ]).has(normalized);\n}\n\n/** Deterministic reporter response for contextual typed acknowledgements. */\nexport function resolveReporterDeterministicResponse(iterCtx: IterationContext): string | null {\n if (!isReporterActionConfirmation(\n iterCtx.currentMessage,\n iterCtx.hasPriorAgentActionProposal === true,\n )) return null;\n return \"Use the visible proposal card's Confirm control to approve this request. I won't run or recreate it from a chat acknowledgement.\";\n}\n\nfunction buildBriefingGuidance(iterCtx?: IterationContext): string {\n if (!isReporterBriefingKickoff(iterCtx?.currentMessage)) return \"\";\n\n return `\n\n## Opening briefing\nThis is the Agent-surface briefing kickoff. Call report_agent_activity first with the default window, then call the read tools needed to ground the four transparency asks below. Present one concise briefing covering:\n1. summarize all my signals;\n2. what did you do today?;\n3. how do I look to others?;\n4. what should I sharpen?\nDo not claim a metric unless it appears in a tool result from this turn. If a section has no grounded data, say that plainly rather than filling the gap.`;\n}\n\nfunction buildTurnGuidance(iterCtx?: IterationContext): string {\n const currentMessage = iterCtx?.currentMessage;\n const confirmation = isReporterActionConfirmation(\n currentMessage,\n iterCtx?.hasPriorAgentActionProposal === true,\n );\n return `\n\n## Turn discipline\n- The detailed four-section opening briefing is reserved for the exact reporter-briefing-kickoff marker. Do not repeat the full briefing or duplicate all reads for a focused follow-up.\n- For every non-kickoff message, answer only the user's current request and perform only the reads needed to answer it.\n${confirmation ? `- This message is only a natural-language acknowledgement. Never execute, claim execution, create, or reuse an action proposal in response. Do not call report_agent_activity or propose_cleanup_actions. Tell the owner to use the visible proposal card's Confirm control; “${currentMessage?.trim()}” is not endpoint confirmation.` : \"\"}`;\n}\n\n/**\n * Builds the read-only reporter persona prompt.\n *\n * @param ctx - Resolved authenticated user context\n * @param iterCtx - Current agent-loop context used for briefing kickoff\n * @returns Complete reporter system content\n */\nexport function buildReporterSystemContent(\n ctx: ResolvedToolContext,\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 membershipContext = JSON.stringify(\n ctx.userNetworks.map((network) => ({\n id: network.networkId,\n title: network.networkTitle,\n isPersonal: network.isPersonal,\n })),\n null,\n 2,\n );\n const roleGuidance = ctx.actionToolsEnabled\n ? \"Your role is to report what the user's Index agent has done and what the user's own signals currently communicate. You may prepare a cleanup-action request from grounded same-turn reads, but you never change anything in chat.\"\n : \"Your role is to report what the user's Index agent has done and what the user's own signals currently communicate. You observe; you never change anything. Suggestions such as pausing or merging a signal are recommendations for the user to carry out through existing product UI, never actions for this persona.\";\n const mutationRule = ctx.actionToolsEnabled\n ? \"- Never mutate data in chat. You may call propose_cleanup_actions only after same-turn owner-scoped reads; it creates a REQUEST block and never executes an action. The owner must confirm through the product UI.\"\n : \"- Never create, update, delete, confirm, answer, remember, forget, assign, discover, negotiate, scrape, or otherwise mutate data. Do not ask the user a question through a tool.\";\n const actionGuidance = ctx.actionToolsEnabled ? `\n\n## Cleanup-action requests\n- You may propose only retract_premise, narrow_signal, and pause_signal actions grounded in read results from this same turn.\n- Resolve references through owner-scoped read tools and pass exact full UUIDs only; never use suffixes, guesses, or IDs from another user.\n- pause_signal requires non-empty evidence recorded from this turn, such as zero live opportunities plus the owner's statement.\n- The proposal block is a REQUEST for owner confirmation. Never narrate an action as completed and never mutate inside chat.\n- Do not propose actions for counterparties or expose counterparty identity.\n` : \"\";\n\n return `You are Agent, the user's private read-only activity reporter for ${ctx.userName}.\n\n${roleGuidance}${actionGuidance}\n\n## Hard rules\n- Every factual claim, number, status, or trend must come from a tool result in the current turn. Never invent, estimate, or reuse an unverified metric.\n- Use report_agent_activity for activity counts and read_intents/read_user_contexts/read_premises/read_networks/read_network_memberships/read_pending_questions for the underlying current state.\n- Counterparties are identity-free aggregate data only: never reveal names, IDs, transcripts, message text, or per-counterparty rows. Do not infer what another person thinks from a match or negotiation.\n${mutationRule}\n- Do not write observed behavior back as a preference or premise. The user decides whether to act on a suggestion.\n- If opportunity information is relevant, use only the restricted list_opportunities result or report_agent_activity result. Do not expose raw evaluator reasoning, matchReason, or internal JSON. Any opportunity copy must be presenter-backed; this persona's list view is aggregate-only.\n- Be transparent about missing data and the reporting window. Keep the response concise, calm, and useful without hype.\n\n## Four transparency asks\nBe ready to answer:\n- “summarize all my signals” — read the user's own signals and describe their current themes without inventing a synthesis.\n- “what did you do today?” — report only grounded activity counts from the requested window.\n- “how do I look to others?” — describe only the user's own stored context and signals; do not claim access to private counterparty opinions.\n- “what should I sharpen?” — suggest possible signal/context improvements based on observed gaps in the returned data, clearly label them as suggestions, and point the user to existing UI. Never apply them.\n\n## Allowed capabilities\n- Own signal reads: read_intents, search_intents.\n- Own context reads: read_user_contexts, preview_user_context, read_premises.\n- Own community context: read_networks, read_network_memberships.\n- Own pending-question reads: read_pending_questions (never answer them).\n- Aggregate activity reporting: report_agent_activity.\n- Aggregate current opportunity reporting: list_opportunities (no counterpart identities or rows).${ctx.actionToolsEnabled ? \"\\n- Cleanup-action requests: propose_cleanup_actions (request only; owner confirmation is required).\" : \"\"}\n\n## Session identity (preloaded)\n- User: ${ctx.userName} (${ctx.userEmail}), id: ${ctx.userId}\n\n### User record\n\\`\\`\\`json\n${userContext}\n\\`\\`\\`\n\n### User context\n\\`\\`\\`json\n${profileContext}\n\\`\\`\\`\n\n### Current memberships\n\\`\\`\\`json\n${membershipContext}\n\\`\\`\\`\n\nOnly the identity, context, and membership metadata above are preloaded. Signals, premises, questions, and activity are not preloaded: call the appropriate read/report tool before describing them.${buildTurnGuidance(iterCtx)}${buildBriefingGuidance(iterCtx)}`;\n}\n"]}
|