@indexnetwork/protocol 4.4.1-rc.320.1 → 4.5.0-rc.322.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat/chat.interrupt.classifier.d.ts.map +1 -1
- package/dist/chat/chat.interrupt.classifier.js +2 -2
- package/dist/chat/chat.interrupt.classifier.js.map +1 -1
- package/dist/chat/chat.suggester.d.ts.map +1 -1
- package/dist/chat/chat.suggester.js +2 -3
- package/dist/chat/chat.suggester.js.map +1 -1
- package/dist/chat/chat.summarizer.d.ts.map +1 -1
- package/dist/chat/chat.summarizer.js +11 -3
- package/dist/chat/chat.summarizer.js.map +1 -1
- package/dist/chat/chat.title.generator.d.ts.map +1 -1
- package/dist/chat/chat.title.generator.js +2 -2
- package/dist/chat/chat.title.generator.js.map +1 -1
- package/dist/contact/contact.inviter.d.ts.map +1 -1
- package/dist/contact/contact.inviter.js +2 -3
- package/dist/contact/contact.inviter.js.map +1 -1
- package/dist/context/context.generator.d.ts.map +1 -1
- package/dist/context/context.generator.js +2 -2
- package/dist/context/context.generator.js.map +1 -1
- package/dist/enrichment/enrichment.generator.d.ts +1 -1
- package/dist/enrichment/enrichment.generator.d.ts.map +1 -1
- package/dist/enrichment/enrichment.generator.js +3 -4
- package/dist/enrichment/enrichment.generator.js.map +1 -1
- package/dist/intent/intent.clarifier.d.ts.map +1 -1
- package/dist/intent/intent.clarifier.js +4 -5
- package/dist/intent/intent.clarifier.js.map +1 -1
- package/dist/intent/intent.indexer.d.ts.map +1 -1
- package/dist/intent/intent.indexer.js +2 -3
- package/dist/intent/intent.indexer.js.map +1 -1
- package/dist/intent/intent.inferrer.d.ts.map +1 -1
- package/dist/intent/intent.inferrer.js +2 -3
- package/dist/intent/intent.inferrer.js.map +1 -1
- package/dist/intent/intent.reconciler.d.ts.map +1 -1
- package/dist/intent/intent.reconciler.js +2 -3
- package/dist/intent/intent.reconciler.js.map +1 -1
- package/dist/intent/intent.verifier.d.ts.map +1 -1
- package/dist/intent/intent.verifier.js +2 -3
- package/dist/intent/intent.verifier.js.map +1 -1
- package/dist/negotiation/insight.generator.d.ts.map +1 -1
- package/dist/negotiation/insight.generator.js +2 -2
- package/dist/negotiation/insight.generator.js.map +1 -1
- package/dist/negotiation/negotiation.agent.js +2 -2
- package/dist/negotiation/negotiation.agent.js.map +1 -1
- package/dist/negotiation/negotiation.summarizer.d.ts +11 -0
- package/dist/negotiation/negotiation.summarizer.d.ts.map +1 -1
- package/dist/negotiation/negotiation.summarizer.js +13 -3
- package/dist/negotiation/negotiation.summarizer.js.map +1 -1
- package/dist/network/network.recommender.d.ts.map +1 -1
- package/dist/network/network.recommender.js +2 -3
- package/dist/network/network.recommender.js.map +1 -1
- package/dist/opportunity/feed/feed.categorizer.d.ts.map +1 -1
- package/dist/opportunity/feed/feed.categorizer.js +2 -3
- package/dist/opportunity/feed/feed.categorizer.js.map +1 -1
- package/dist/opportunity/opportunity.evaluator.d.ts.map +1 -1
- package/dist/opportunity/opportunity.evaluator.js +3 -4
- package/dist/opportunity/opportunity.evaluator.js.map +1 -1
- package/dist/opportunity/opportunity.presenter.d.ts.map +1 -1
- package/dist/opportunity/opportunity.presenter.js +3 -4
- package/dist/opportunity/opportunity.presenter.js.map +1 -1
- package/dist/opportunity/question.generator.d.ts.map +1 -1
- package/dist/opportunity/question.generator.js +17 -3
- package/dist/opportunity/question.generator.js.map +1 -1
- package/dist/premise/premise.analyzer.d.ts.map +1 -1
- package/dist/premise/premise.analyzer.js +2 -3
- package/dist/premise/premise.analyzer.js.map +1 -1
- package/dist/premise/premise.decomposer.d.ts.map +1 -1
- package/dist/premise/premise.decomposer.js +2 -3
- package/dist/premise/premise.decomposer.js.map +1 -1
- package/dist/premise/premise.indexer.d.ts.map +1 -1
- package/dist/premise/premise.indexer.js +2 -3
- package/dist/premise/premise.indexer.js.map +1 -1
- package/dist/questioner/questioner.agent.d.ts +2 -2
- package/dist/questioner/questioner.agent.d.ts.map +1 -1
- package/dist/questioner/questioner.agent.js +12 -4
- package/dist/questioner/questioner.agent.js.map +1 -1
- package/dist/shared/agent/model.config.d.ts +41 -2
- package/dist/shared/agent/model.config.d.ts.map +1 -1
- package/dist/shared/agent/model.config.js +98 -1
- package/dist/shared/agent/model.config.js.map +1 -1
- package/dist/shared/hyde/hyde.generator.d.ts.map +1 -1
- package/dist/shared/hyde/hyde.generator.js +2 -3
- package/dist/shared/hyde/hyde.generator.js.map +1 -1
- package/dist/shared/hyde/lens.inferrer.d.ts.map +1 -1
- package/dist/shared/hyde/lens.inferrer.js +2 -3
- package/dist/shared/hyde/lens.inferrer.js.map +1 -1
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ import { tool } from "@langchain/core/tools";
|
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
import { log } from "../shared/observability/log.js";
|
|
14
14
|
import { Timed } from "../shared/observability/performance.js";
|
|
15
|
-
import {
|
|
15
|
+
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
16
16
|
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
17
17
|
// ──────────────────────────────────────────────────────────────
|
|
18
18
|
// Response schema
|
|
@@ -23,7 +23,6 @@ export const IntentIndexerOutputSchema = z.object({
|
|
|
23
23
|
reasoning: z.string().describe("Brief reasoning for the scores"),
|
|
24
24
|
});
|
|
25
25
|
const logger = log.lib.from("IntentIndexer");
|
|
26
|
-
const model = createModel("intentIndexer");
|
|
27
26
|
// ──────────────────────────────────────────────────────────────
|
|
28
27
|
// 1. SYSTEM PROMPT
|
|
29
28
|
// ──────────────────────────────────────────────────────────────
|
|
@@ -67,7 +66,7 @@ const responseFormat = IntentIndexerOutputSchema;
|
|
|
67
66
|
// ──────────────────────────────────────────────────────────────
|
|
68
67
|
export class IntentIndexer {
|
|
69
68
|
constructor() {
|
|
70
|
-
this.model =
|
|
69
|
+
this.model = createStructuredModel("intentIndexer", responseFormat, {
|
|
71
70
|
name: "intent_indexer",
|
|
72
71
|
});
|
|
73
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.indexer.js","sourceRoot":"/","sources":["intent/intent.indexer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatOpenAI } from \"@langchain/openai\";\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { log } from \"../shared/observability/log.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\n// ──────────────────────────────────────────────────────────────\n// Response schema\n// ──────────────────────────────────────────────────────────────\n\nexport const IntentIndexerOutputSchema = z.object({\n indexScore: z.number().min(0).max(1).describe(\"Score for index appropriateness (0.0-1.0)\"),\n memberScore: z.number().min(0).max(1).describe(\"Score for member preference match (0.0-1.0)\"),\n reasoning: z.string().describe(\"Brief reasoning for the scores\"),\n});\n\n/**\n * Output structure for the Intent Indexer agent.\n */\nexport type IntentIndexerOutput = z.infer<typeof IntentIndexerOutputSchema>;\n\nconst logger = log.lib.from(\"IntentIndexer\");\n\nconst model = createModel(\"intentIndexer\");\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\nconst systemPrompt = `\nYou are an expert Intent Evaluator for a social networking protocol.\n\nTASK:\nDetermine if a User Intent is appropriate for a specific Index (community) and matches a Member's sharing preferences.\n\nINPUTS:\n1. Intent: The content/action the user wants to perform.\n2. Network Prompt: The purpose/scope of the target community (Index).\n3. Member Prompt: The specific sharing preferences of the user in that community (optional).\n4. Source: Origin of the intent (file, link, etc.) (optional).\n5. Network Context: Rendered context about the network including type, dates, location, and events (optional).\n\nNETWORK TYPE AWARENESS:\n- When Network Context is provided, use it to inform your scoring.\n- For EVENT networks: consider temporal relevance. An intent about \"meeting at the venue\" is highly relevant to an upcoming event but irrelevant after it ends. Intents about topics aligned with the event's themes should score higher.\n- For COMMUNITY networks: score based on the network prompt and member preferences as usual.\n- If the network context includes dates and the intent is time-sensitive, factor temporal proximity into the score.\n\nSCORING RUBRIC:\n- 0.9-1.0: Highly appropriate, perfect match.\n- 0.7-0.8: Good match, relevant.\n- 0.5-0.6: Moderate, borderline.\n- 0.3-0.4: Low appropriateness, poor fit.\n- 0.0-0.2: Not appropriate.\n\nOUTPUT RULES:\n- Provide \\`indexScore\\` based on how well the Intent fits the Network Prompt.\n- Provide \\`memberScore\\` based on how well the Intent fits the Member Prompt (if provided). If Member Prompt is missing/empty, return 0.0 for memberScore.\n- Provide concise \\`reasoning\\`.\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst responseFormat = IntentIndexerOutputSchema;\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS\n// ──────────────────────────────────────────────────────────────\n\ntype ResponseType = z.infer<typeof responseFormat>;\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class IntentIndexer {\n private model: ReturnType<ChatOpenAI[\"withStructuredOutput\"]>;\n\n constructor() {\n this.model = model.withStructuredOutput(responseFormat, {\n name: \"intent_indexer\",\n });\n }\n\n /**\n * Converts the structured response into a string for logging or embedding.\n * Used when the output needs to be serialized (e.g. for traces).\n */\n private toString(output: ResponseType): string {\n return [\n `indexScore: ${output.indexScore}`,\n `memberScore: ${output.memberScore}`,\n `reasoning: ${output.reasoning}`,\n ].join(\"\\n\");\n }\n\n /**\n * Main entry point. Evaluates the appropriateness of an intent for a given index and member context.\n *\n * @param intent - The intent payload.\n * @param indexPrompt - The purpose of the index (community).\n * @param memberPrompt - The member's sharing preferences (optional).\n * @param sourceName - Optional source name for context (e.g. file, link).\n * @param networkContext - Optional rendered network context (type, dates, metadata).\n * @returns Structured output with indexScore, memberScore, and reasoning, or null on error.\n */\n @Timed()\n public async invoke(\n intent: string,\n indexPrompt: string | null,\n memberPrompt: string | null,\n sourceName?: string | null,\n networkContext?: string | null\n ): Promise<IntentIndexerOutput | null> {\n logger.verbose(\"[IntentIndexer.invoke] Evaluating intent\");\n\n const contextParts: string[] = [];\n if (sourceName) contextParts.push(`Source: ${sourceName}`);\n contextParts.push(indexPrompt ? `Index Purpose: ${indexPrompt}` : \"Index Purpose: (Not provided)\");\n contextParts.push(memberPrompt ? `Member Preferences: ${memberPrompt}` : \"Member Preferences: (Not provided)\");\n if (networkContext) contextParts.push(`Network Context:\\n${networkContext}`);\n\n const prompt = `\n # Context\n ${contextParts.join(\"\\n\")}\n\n # Intent\n ${intent}\n\n Evaluate the appropriateness of this intent.\n `;\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt),\n ];\n\n try {\n const result = await invokeWithAbortSignal(this.model, messages);\n const output = responseFormat.parse(result) as IntentIndexerOutput;\n\n logger.verbose(\"[IntentIndexer.invoke] Evaluation complete\", {\n indexScore: output.indexScore,\n memberScore: output.memberScore,\n });\n return output;\n } catch (error) {\n logger.error(\"[IntentIndexer] Error during execution\", { error });\n return null;\n }\n }\n\n /**\n * Alias for invoke. Evaluates the appropriateness of an intent for a given index and member context.\n * Kept for compatibility with callers (e.g. Network Graph) that use evaluate().\n */\n @Timed()\n public async evaluate(\n intent: string,\n indexPrompt: string | null,\n memberPrompt: string | null,\n sourceName?: string | null,\n networkContext?: string | null\n ): Promise<IntentIndexerOutput | null> {\n return this.invoke(intent, indexPrompt, memberPrompt, sourceName, networkContext);\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n * Useful for composing agents into larger graphs.\n */\n public static asTool() {\n return tool(\n async (args: {\n intent: string;\n indexPrompt: string | null;\n memberPrompt: string | null;\n sourceName?: string | null;\n networkContext?: string | null;\n }) => {\n const agent = new IntentIndexer();\n return await agent.invoke(\n args.intent,\n args.indexPrompt,\n args.memberPrompt,\n args.sourceName,\n args.networkContext\n );\n },\n {\n name: \"intent_indexer\",\n description:\n \"Evaluates whether an intent is appropriate for a specific index (community or event) and matches member sharing preferences.\",\n schema: z.object({\n intent: z.string().describe(\"The intent payload to evaluate\"),\n indexPrompt: z.string().nullable().describe(\"The purpose of the index (community)\"),\n memberPrompt: z.string().nullable().describe(\"The member's sharing preferences\"),\n sourceName: z.string().nullable().optional().describe(\"Optional source name for context\"),\n networkContext: z.string().nullable().optional().describe(\"Optional rendered network context (type, dates, metadata)\"),\n }),\n }\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"intent.indexer.js","sourceRoot":"/","sources":["intent/intent.indexer.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { log } from \"../shared/observability/log.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\n// ──────────────────────────────────────────────────────────────\n// Response schema\n// ──────────────────────────────────────────────────────────────\n\nexport const IntentIndexerOutputSchema = z.object({\n indexScore: z.number().min(0).max(1).describe(\"Score for index appropriateness (0.0-1.0)\"),\n memberScore: z.number().min(0).max(1).describe(\"Score for member preference match (0.0-1.0)\"),\n reasoning: z.string().describe(\"Brief reasoning for the scores\"),\n});\n\n/**\n * Output structure for the Intent Indexer agent.\n */\nexport type IntentIndexerOutput = z.infer<typeof IntentIndexerOutputSchema>;\n\nconst logger = log.lib.from(\"IntentIndexer\");\n\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\nconst systemPrompt = `\nYou are an expert Intent Evaluator for a social networking protocol.\n\nTASK:\nDetermine if a User Intent is appropriate for a specific Index (community) and matches a Member's sharing preferences.\n\nINPUTS:\n1. Intent: The content/action the user wants to perform.\n2. Network Prompt: The purpose/scope of the target community (Index).\n3. Member Prompt: The specific sharing preferences of the user in that community (optional).\n4. Source: Origin of the intent (file, link, etc.) (optional).\n5. Network Context: Rendered context about the network including type, dates, location, and events (optional).\n\nNETWORK TYPE AWARENESS:\n- When Network Context is provided, use it to inform your scoring.\n- For EVENT networks: consider temporal relevance. An intent about \"meeting at the venue\" is highly relevant to an upcoming event but irrelevant after it ends. Intents about topics aligned with the event's themes should score higher.\n- For COMMUNITY networks: score based on the network prompt and member preferences as usual.\n- If the network context includes dates and the intent is time-sensitive, factor temporal proximity into the score.\n\nSCORING RUBRIC:\n- 0.9-1.0: Highly appropriate, perfect match.\n- 0.7-0.8: Good match, relevant.\n- 0.5-0.6: Moderate, borderline.\n- 0.3-0.4: Low appropriateness, poor fit.\n- 0.0-0.2: Not appropriate.\n\nOUTPUT RULES:\n- Provide \\`indexScore\\` based on how well the Intent fits the Network Prompt.\n- Provide \\`memberScore\\` based on how well the Intent fits the Member Prompt (if provided). If Member Prompt is missing/empty, return 0.0 for memberScore.\n- Provide concise \\`reasoning\\`.\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst responseFormat = IntentIndexerOutputSchema;\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS\n// ──────────────────────────────────────────────────────────────\n\ntype ResponseType = z.infer<typeof responseFormat>;\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class IntentIndexer {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"intentIndexer\", responseFormat, {\n name: \"intent_indexer\",\n });\n }\n\n /**\n * Converts the structured response into a string for logging or embedding.\n * Used when the output needs to be serialized (e.g. for traces).\n */\n private toString(output: ResponseType): string {\n return [\n `indexScore: ${output.indexScore}`,\n `memberScore: ${output.memberScore}`,\n `reasoning: ${output.reasoning}`,\n ].join(\"\\n\");\n }\n\n /**\n * Main entry point. Evaluates the appropriateness of an intent for a given index and member context.\n *\n * @param intent - The intent payload.\n * @param indexPrompt - The purpose of the index (community).\n * @param memberPrompt - The member's sharing preferences (optional).\n * @param sourceName - Optional source name for context (e.g. file, link).\n * @param networkContext - Optional rendered network context (type, dates, metadata).\n * @returns Structured output with indexScore, memberScore, and reasoning, or null on error.\n */\n @Timed()\n public async invoke(\n intent: string,\n indexPrompt: string | null,\n memberPrompt: string | null,\n sourceName?: string | null,\n networkContext?: string | null\n ): Promise<IntentIndexerOutput | null> {\n logger.verbose(\"[IntentIndexer.invoke] Evaluating intent\");\n\n const contextParts: string[] = [];\n if (sourceName) contextParts.push(`Source: ${sourceName}`);\n contextParts.push(indexPrompt ? `Index Purpose: ${indexPrompt}` : \"Index Purpose: (Not provided)\");\n contextParts.push(memberPrompt ? `Member Preferences: ${memberPrompt}` : \"Member Preferences: (Not provided)\");\n if (networkContext) contextParts.push(`Network Context:\\n${networkContext}`);\n\n const prompt = `\n # Context\n ${contextParts.join(\"\\n\")}\n\n # Intent\n ${intent}\n\n Evaluate the appropriateness of this intent.\n `;\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt),\n ];\n\n try {\n const result = await invokeWithAbortSignal(this.model, messages);\n const output = responseFormat.parse(result) as IntentIndexerOutput;\n\n logger.verbose(\"[IntentIndexer.invoke] Evaluation complete\", {\n indexScore: output.indexScore,\n memberScore: output.memberScore,\n });\n return output;\n } catch (error) {\n logger.error(\"[IntentIndexer] Error during execution\", { error });\n return null;\n }\n }\n\n /**\n * Alias for invoke. Evaluates the appropriateness of an intent for a given index and member context.\n * Kept for compatibility with callers (e.g. Network Graph) that use evaluate().\n */\n @Timed()\n public async evaluate(\n intent: string,\n indexPrompt: string | null,\n memberPrompt: string | null,\n sourceName?: string | null,\n networkContext?: string | null\n ): Promise<IntentIndexerOutput | null> {\n return this.invoke(intent, indexPrompt, memberPrompt, sourceName, networkContext);\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n * Useful for composing agents into larger graphs.\n */\n public static asTool() {\n return tool(\n async (args: {\n intent: string;\n indexPrompt: string | null;\n memberPrompt: string | null;\n sourceName?: string | null;\n networkContext?: string | null;\n }) => {\n const agent = new IntentIndexer();\n return await agent.invoke(\n args.intent,\n args.indexPrompt,\n args.memberPrompt,\n args.sourceName,\n args.networkContext\n );\n },\n {\n name: \"intent_indexer\",\n description:\n \"Evaluates whether an intent is appropriate for a specific index (community or event) and matches member sharing preferences.\",\n schema: z.object({\n intent: z.string().describe(\"The intent payload to evaluate\"),\n indexPrompt: z.string().nullable().describe(\"The purpose of the index (community)\"),\n memberPrompt: z.string().nullable().describe(\"The member's sharing preferences\"),\n sourceName: z.string().nullable().optional().describe(\"Optional source name for context\"),\n networkContext: z.string().nullable().optional().describe(\"Optional rendered network context (type, dates, metadata)\"),\n }),\n }\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.inferrer.d.ts","sourceRoot":"/","sources":["intent/intent.inferrer.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEpF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAE/C;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,WAAW,EAAE,CAAC;CACrC;AA2ED,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;EAKxB,CAAC;AAWH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAMlE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"intent.inferrer.d.ts","sourceRoot":"/","sources":["intent/intent.inferrer.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEpF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAE/C;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,WAAW,EAAE,CAAC;CACrC;AA2ED,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;EAKxB,CAAC;AAWH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAMlE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,KAAK,CAA2C;;IAQxD;;;;;OAKG;IAEU,MAAM,CACjB,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,eAAoB;;;;;;;;IAuF/B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAuBjC;;;OAGG;WACW,MAAM;;;;;;;;;;;;;;;;;;;;;;;CAgBrB"}
|
|
@@ -12,7 +12,7 @@ import { tool } from "@langchain/core/tools";
|
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
14
14
|
import { Timed } from "../shared/observability/performance.js";
|
|
15
|
-
import {
|
|
15
|
+
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
16
16
|
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
17
17
|
const logger = protocolLogger("ExplicitIntentInferrer");
|
|
18
18
|
// ──────────────────────────────────────────────────────────────
|
|
@@ -99,8 +99,7 @@ const responseFormat = z.object({
|
|
|
99
99
|
// ──────────────────────────────────────────────────────────────
|
|
100
100
|
export class ExplicitIntentInferrer {
|
|
101
101
|
constructor() {
|
|
102
|
-
|
|
103
|
-
this.model = model.withStructuredOutput(responseFormat, {
|
|
102
|
+
this.model = createStructuredModel("intentInferrer", responseFormat, {
|
|
104
103
|
name: "intent_inferrer"
|
|
105
104
|
});
|
|
106
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.inferrer.js","sourceRoot":"/","sources":["intent/intent.inferrer.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage, BaseMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"ExplicitIntentInferrer\");\n\n// ──────────────────────────────────────────────────────────────\n// 0. INFERRER OPTIONS\n// ──────────────────────────────────────────────────────────────\n\n/**\n * Options to control inferrer behavior.\n * Used to implement safety controls for read/write separation.\n */\nexport interface InferrerOptions {\n /**\n * Whether to fallback to profile inference when content is empty.\n * Should be TRUE for create operations without explicit content.\n * Should be FALSE for query operations.\n * Default: true (for backward compatibility).\n */\n allowProfileFallback?: boolean;\n \n /**\n * The operation mode for context.\n * Helps inferrer understand the user's intent.\n */\n operationMode?: 'create' | 'update' | 'delete';\n \n /**\n * Conversation history for anaphoric resolution.\n * Used to resolve references like \"that intent\", \"this goal\", etc.\n * Optional - if not provided, inference uses only current content.\n */\n conversationContext?: BaseMessage[];\n}\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\nconst systemPrompt = `\n You are an expert Intent Analyst. Your goal is to infer the user's current intentions based on their profile and new content.\n\n You have access to:\n 1. User Memory Profile (Identity, Narrative, Attributes) - The long-term context.\n 2. New Content - What they just said/did.\n 3. Conversation History (when available) - Recent messages for resolving references.\n 4. Operation Context - What type of operation is being performed.\n\n YOUR TASK:\n Analyze the \"New Content\" in the context of the \"Profile\", \"Conversation History\", and \"Operation Context\".\n Extract a list of **Inferred Intents**.\n\n INTENT TYPES:\n - 'goal': The user wants to start, continue, or achieve something. (e.g., \"I want to learn Rust\", \"Looking for a co-founder\")\n - 'tombstone': The user explicitly states they have COMPLETED, stopped, or abandoned a goal. (e.g., \"I finished the course\", \"I'm done with crypto\", \"Delete my running goal\")\n\n CRITICAL RULES:\n - Only analyze the \"New Content\" section if it exists.\n - If New Content says \"Return empty intents list\", you MUST return an empty intents array.\n - If New Content says \"No content to analyze\", return an empty intents array.\n - Be precise and self-contained in descriptions (e.g., \"Learn Rust programming\" instead of \"Learn it\").\n - Do NOT try to manage existing IDs or check for duplicates.\n - IGNORE purely phatic communication (e.g., \"Hello\", \"Hi\", \"Good morning\") - return empty intents.\n - For CREATE operations: Extract what the user wants to ADD.\n - For UPDATE operations: Extract what the user wants to CHANGE.\n - For queries/questions: You should not see these - return empty intents.\n\n CONTENT GROUNDING (CRITICAL):\n - When New Content is present, EVERY inferred intent MUST be directly related to the New Content.\n - The User Profile is ENRICHMENT CONTEXT ONLY — use it to add specificity or domain detail to content-derived intents.\n - Do NOT generate intents from the profile that are unrelated to the New Content.\n - If the New Content is a short phrase (e.g., \"artist\", \"photographer\"), treat it as the user's stated goal — infer what they want regarding that topic.\n - Example: New Content = \"artist\", Profile = \"Building a decentralized protocol\" → Intent: \"Find or connect with artists\" (NOT \"Secure partnerships for decentralized protocol\")\n - Example: New Content = \"looking for a photographer\", Profile = \"AI startup founder\" → Intent: \"Find a photographer\" (NOT \"Recruit AI engineers\")\n\n CONCEPT EXTRACTION (CRITICAL FOR MATCHING):\n - Intents must be SELF-CONTAINED and understandable to strangers with no prior context.\n - When a document describes a project, the project's NAME is irrelevant - only WHAT IT DOES and WHAT TECH IT USES matters.\n - STRIP OUT completely (do not include in any form):\n * ANY project/company/product names from the source document - these mean nothing to outsiders\n * URLs and links (https://..., http://...) - NEVER include URLs in intent descriptions\n * Phrases that reference URLs: \"More details at\", \"See ... for more\", \"Project details:\", \"mentioned in\", \"from the document\", \"as discussed\"\n * File names (\"Claude.md\", \"README\", \"the PDF\")\n - Describe the WORK and TECHNOLOGIES, never the project name.\n - Examples:\n * Source mentions \"FooBar Project\" using React/Node → Intent: \"Seeking React/Node.js developers for real-time web apps\" (NO \"FooBar\")\n * Source mentions \"Index Network\" with LangGraph → Intent: \"Seeking LangGraph/PostgreSQL developers for AI agent systems\" (NO \"Index Network\")\n * Source mentions \"Acme Corp\" doing ML → Intent: \"Seeking ML engineers for computer vision pipelines\" (NO \"Acme\")\n \n ANAPHORIC RESOLUTION (UPDATE operations):\n - When conversation history is provided, use it to resolve references like \"that intent\", \"this goal\", \"the project\", etc.\n - Look for previously mentioned intents in the conversation history.\n - If the user says \"make that intent X\", find what \"that intent\" refers to in the history and include ALL its details.\n - PRESERVE all existing details from the referenced intent and only MODIFY the specified parts.\n - Example: If history mentions \"text-based RPG game\" and user says \"make that intent have LLM narration\",\n the output should be \"Create a text-based RPG game with LLM-enhanced narration\" (preserving \"text-based\").\n \n WHEN TO FALLBACK TO PROFILE:\n - Only when explicitly instructed: \"(No content provided. Please infer intents from Profile Narrative and Aspirations)\"\n - This should ONLY happen for CREATE operations with no explicit user input\n - Never infer from profile for query operations\n - When content IS present: profile may inform HOW to describe the intent (e.g., adding domain context), but must NOT change WHAT the intent is about\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst InferredIntentSchema = z.object({\n type: z.enum(['goal', 'tombstone']).describe(\"The type of intent inferred\"),\n description: z.string().describe(\"Concise description of the intent\"),\n reasoning: z.string().describe(\"Why this intent was inferred\"),\n confidence: z.enum(['high', 'medium', 'low']).describe(\"Confidence level of the inference\")\n});\n\nconst responseFormat = z.object({\n intents: z.array(InferredIntentSchema).describe(\"List of inferred intents\")\n});\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS\n// ──────────────────────────────────────────────────────────────\n\ntype ResponseType = z.infer<typeof responseFormat>;\nexport type InferredIntent = z.infer<typeof InferredIntentSchema>;\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class ExplicitIntentInferrer {\n private model: any;\n\n constructor() {\n const model = createModel(\"intentInferrer\");\n this.model = model.withStructuredOutput(responseFormat, {\n name: \"intent_inferrer\"\n });\n }\n\n /**\n * Main entry point. Invokes the agent with input and returns structured output.\n * @param content - The raw string content to analyze.\n * @param profileContext - The formatted profile context string.\n * @param options - Options controlling inference behavior (fallback, operation mode, conversation context).\n */\n @Timed()\n public async invoke(\n content: string | null,\n profileContext: string,\n options: InferrerOptions = {}\n ) {\n const {\n allowProfileFallback = true, // Default TRUE for backward compatibility\n operationMode = 'create',\n conversationContext = undefined\n } = options;\n \n logger.verbose(\"invoke: received input\", {\n contentPreview: content?.substring(0, 50),\n allowProfileFallback,\n operationMode,\n hasConversationContext: !!conversationContext,\n conversationMessageCount: conversationContext?.length || 0,\n });\n\n // CRITICAL: Don't fallback to profile when explicitly disabled\n // This prevents auto-generation of intents from profile during query operations\n if (!content && !allowProfileFallback) {\n logger.verbose(\"invoke: no content and fallback disabled, returning empty\");\n return { intents: [] };\n }\n\n // Build conversation history section for anaphoric resolution\n const formattedHistory = conversationContext && conversationContext.length > 0\n ? this.formatConversationHistory(conversationContext)\n : '';\n \n const conversationSection = formattedHistory\n ? `# Conversation History (for reference resolution)\\n${formattedHistory}\\n`\n : '';\n\n // Build content section based on fallback setting\n const contentSection = content\n ? `## New Content\\n\\n${content}`\n : allowProfileFallback\n ? '(No content provided. Please infer intents from Profile Narrative and Aspirations)'\n : '(No content to analyze. Return empty intents list.)';\n\n const prompt = `\n Context:\n # User Memory Profile\n ${profileContext}\n\n ${conversationSection}${contentSection}\n \n # Operation Context\n This analysis is for a ${operationMode} operation.\n ${operationMode === 'create' ? 'Extract NEW intents the user wants to add.' : ''}\n ${operationMode === 'update' ? 'Extract MODIFICATIONS to existing intents. Use conversation history to resolve references like \"that intent\".' : ''}\n ${operationMode === 'delete' ? 'This should not execute - delete operations skip inference.' : ''}\n `;\n \n logger.debug(\"invoke: prompt details\", {\n hasConversationHistory: !!conversationSection,\n conversationHistoryLength: formattedHistory.length,\n conversationHistoryPreview: formattedHistory.substring(0, 300),\n contentLength: content?.length ?? 0,\n promptLength: prompt.length,\n promptPreview: prompt.substring(0, 500),\n });\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt)\n ];\n\n try {\n const result = await invokeWithAbortSignal(this.model, messages);\n const output = responseFormat.parse(result);\n\n logger.verbose(`invoke: found ${output.intents.length} intents`, {\n operationMode,\n allowedFallback: allowProfileFallback,\n usedFallback: !content && allowProfileFallback,\n });\n return output;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n logger.error(\"invoke: error during invocation\", {\n message: err.message,\n stack: err.stack,\n });\n return { intents: [] };\n }\n }\n\n /**\n * Formats conversation history for inclusion in the prompt.\n * Converts BaseMessage[] to readable string format.\n */\n private formatConversationHistory(messages: BaseMessage[]): string {\n const formatted = messages.map((msg, index) => {\n const role = msg._getType() === 'human' ? 'User' : 'Assistant';\n const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);\n // Truncate long messages for token efficiency\n const truncated = content.length > 200 ? content.substring(0, 200) + '...' : content;\n return `[${index + 1}] ${role}: ${truncated}`;\n }).join('\\n');\n \n logger.debug(\"formatConversationHistory: full conversation history\", {\n messageCount: messages.length,\n fullHistory: messages\n .map((msg, index) => {\n const role = msg._getType() === \"human\" ? \"User\" : \"Assistant\";\n const content = typeof msg.content === \"string\" ? msg.content : JSON.stringify(msg.content);\n return `[${index + 1}] ${role}: ${content}`;\n })\n .join(\"\\n\"),\n });\n\n return formatted;\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n * Useful for composing agents into larger graphs.\n */\n public static asTool() {\n return tool(\n async (args: { content: string | null; profileContext: string }) => {\n const agent = new ExplicitIntentInferrer();\n return await agent.invoke(args.content, args.profileContext);\n },\n {\n name: 'explicit_intent_inferrer',\n description: 'Extracts explicit intents from user content and profile context.',\n schema: z.object({\n content: z.string().nullable().describe('The new content to analyze'),\n profileContext: z.string().describe('The user profile context')\n })\n }\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"intent.inferrer.js","sourceRoot":"/","sources":["intent/intent.inferrer.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage, BaseMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"ExplicitIntentInferrer\");\n\n// ──────────────────────────────────────────────────────────────\n// 0. INFERRER OPTIONS\n// ──────────────────────────────────────────────────────────────\n\n/**\n * Options to control inferrer behavior.\n * Used to implement safety controls for read/write separation.\n */\nexport interface InferrerOptions {\n /**\n * Whether to fallback to profile inference when content is empty.\n * Should be TRUE for create operations without explicit content.\n * Should be FALSE for query operations.\n * Default: true (for backward compatibility).\n */\n allowProfileFallback?: boolean;\n \n /**\n * The operation mode for context.\n * Helps inferrer understand the user's intent.\n */\n operationMode?: 'create' | 'update' | 'delete';\n \n /**\n * Conversation history for anaphoric resolution.\n * Used to resolve references like \"that intent\", \"this goal\", etc.\n * Optional - if not provided, inference uses only current content.\n */\n conversationContext?: BaseMessage[];\n}\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\nconst systemPrompt = `\n You are an expert Intent Analyst. Your goal is to infer the user's current intentions based on their profile and new content.\n\n You have access to:\n 1. User Memory Profile (Identity, Narrative, Attributes) - The long-term context.\n 2. New Content - What they just said/did.\n 3. Conversation History (when available) - Recent messages for resolving references.\n 4. Operation Context - What type of operation is being performed.\n\n YOUR TASK:\n Analyze the \"New Content\" in the context of the \"Profile\", \"Conversation History\", and \"Operation Context\".\n Extract a list of **Inferred Intents**.\n\n INTENT TYPES:\n - 'goal': The user wants to start, continue, or achieve something. (e.g., \"I want to learn Rust\", \"Looking for a co-founder\")\n - 'tombstone': The user explicitly states they have COMPLETED, stopped, or abandoned a goal. (e.g., \"I finished the course\", \"I'm done with crypto\", \"Delete my running goal\")\n\n CRITICAL RULES:\n - Only analyze the \"New Content\" section if it exists.\n - If New Content says \"Return empty intents list\", you MUST return an empty intents array.\n - If New Content says \"No content to analyze\", return an empty intents array.\n - Be precise and self-contained in descriptions (e.g., \"Learn Rust programming\" instead of \"Learn it\").\n - Do NOT try to manage existing IDs or check for duplicates.\n - IGNORE purely phatic communication (e.g., \"Hello\", \"Hi\", \"Good morning\") - return empty intents.\n - For CREATE operations: Extract what the user wants to ADD.\n - For UPDATE operations: Extract what the user wants to CHANGE.\n - For queries/questions: You should not see these - return empty intents.\n\n CONTENT GROUNDING (CRITICAL):\n - When New Content is present, EVERY inferred intent MUST be directly related to the New Content.\n - The User Profile is ENRICHMENT CONTEXT ONLY — use it to add specificity or domain detail to content-derived intents.\n - Do NOT generate intents from the profile that are unrelated to the New Content.\n - If the New Content is a short phrase (e.g., \"artist\", \"photographer\"), treat it as the user's stated goal — infer what they want regarding that topic.\n - Example: New Content = \"artist\", Profile = \"Building a decentralized protocol\" → Intent: \"Find or connect with artists\" (NOT \"Secure partnerships for decentralized protocol\")\n - Example: New Content = \"looking for a photographer\", Profile = \"AI startup founder\" → Intent: \"Find a photographer\" (NOT \"Recruit AI engineers\")\n\n CONCEPT EXTRACTION (CRITICAL FOR MATCHING):\n - Intents must be SELF-CONTAINED and understandable to strangers with no prior context.\n - When a document describes a project, the project's NAME is irrelevant - only WHAT IT DOES and WHAT TECH IT USES matters.\n - STRIP OUT completely (do not include in any form):\n * ANY project/company/product names from the source document - these mean nothing to outsiders\n * URLs and links (https://..., http://...) - NEVER include URLs in intent descriptions\n * Phrases that reference URLs: \"More details at\", \"See ... for more\", \"Project details:\", \"mentioned in\", \"from the document\", \"as discussed\"\n * File names (\"Claude.md\", \"README\", \"the PDF\")\n - Describe the WORK and TECHNOLOGIES, never the project name.\n - Examples:\n * Source mentions \"FooBar Project\" using React/Node → Intent: \"Seeking React/Node.js developers for real-time web apps\" (NO \"FooBar\")\n * Source mentions \"Index Network\" with LangGraph → Intent: \"Seeking LangGraph/PostgreSQL developers for AI agent systems\" (NO \"Index Network\")\n * Source mentions \"Acme Corp\" doing ML → Intent: \"Seeking ML engineers for computer vision pipelines\" (NO \"Acme\")\n \n ANAPHORIC RESOLUTION (UPDATE operations):\n - When conversation history is provided, use it to resolve references like \"that intent\", \"this goal\", \"the project\", etc.\n - Look for previously mentioned intents in the conversation history.\n - If the user says \"make that intent X\", find what \"that intent\" refers to in the history and include ALL its details.\n - PRESERVE all existing details from the referenced intent and only MODIFY the specified parts.\n - Example: If history mentions \"text-based RPG game\" and user says \"make that intent have LLM narration\",\n the output should be \"Create a text-based RPG game with LLM-enhanced narration\" (preserving \"text-based\").\n \n WHEN TO FALLBACK TO PROFILE:\n - Only when explicitly instructed: \"(No content provided. Please infer intents from Profile Narrative and Aspirations)\"\n - This should ONLY happen for CREATE operations with no explicit user input\n - Never infer from profile for query operations\n - When content IS present: profile may inform HOW to describe the intent (e.g., adding domain context), but must NOT change WHAT the intent is about\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst InferredIntentSchema = z.object({\n type: z.enum(['goal', 'tombstone']).describe(\"The type of intent inferred\"),\n description: z.string().describe(\"Concise description of the intent\"),\n reasoning: z.string().describe(\"Why this intent was inferred\"),\n confidence: z.enum(['high', 'medium', 'low']).describe(\"Confidence level of the inference\")\n});\n\nconst responseFormat = z.object({\n intents: z.array(InferredIntentSchema).describe(\"List of inferred intents\")\n});\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS\n// ──────────────────────────────────────────────────────────────\n\ntype ResponseType = z.infer<typeof responseFormat>;\nexport type InferredIntent = z.infer<typeof InferredIntentSchema>;\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class ExplicitIntentInferrer {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"intentInferrer\", responseFormat, {\n name: \"intent_inferrer\"\n });\n }\n\n /**\n * Main entry point. Invokes the agent with input and returns structured output.\n * @param content - The raw string content to analyze.\n * @param profileContext - The formatted profile context string.\n * @param options - Options controlling inference behavior (fallback, operation mode, conversation context).\n */\n @Timed()\n public async invoke(\n content: string | null,\n profileContext: string,\n options: InferrerOptions = {}\n ) {\n const {\n allowProfileFallback = true, // Default TRUE for backward compatibility\n operationMode = 'create',\n conversationContext = undefined\n } = options;\n \n logger.verbose(\"invoke: received input\", {\n contentPreview: content?.substring(0, 50),\n allowProfileFallback,\n operationMode,\n hasConversationContext: !!conversationContext,\n conversationMessageCount: conversationContext?.length || 0,\n });\n\n // CRITICAL: Don't fallback to profile when explicitly disabled\n // This prevents auto-generation of intents from profile during query operations\n if (!content && !allowProfileFallback) {\n logger.verbose(\"invoke: no content and fallback disabled, returning empty\");\n return { intents: [] };\n }\n\n // Build conversation history section for anaphoric resolution\n const formattedHistory = conversationContext && conversationContext.length > 0\n ? this.formatConversationHistory(conversationContext)\n : '';\n \n const conversationSection = formattedHistory\n ? `# Conversation History (for reference resolution)\\n${formattedHistory}\\n`\n : '';\n\n // Build content section based on fallback setting\n const contentSection = content\n ? `## New Content\\n\\n${content}`\n : allowProfileFallback\n ? '(No content provided. Please infer intents from Profile Narrative and Aspirations)'\n : '(No content to analyze. Return empty intents list.)';\n\n const prompt = `\n Context:\n # User Memory Profile\n ${profileContext}\n\n ${conversationSection}${contentSection}\n \n # Operation Context\n This analysis is for a ${operationMode} operation.\n ${operationMode === 'create' ? 'Extract NEW intents the user wants to add.' : ''}\n ${operationMode === 'update' ? 'Extract MODIFICATIONS to existing intents. Use conversation history to resolve references like \"that intent\".' : ''}\n ${operationMode === 'delete' ? 'This should not execute - delete operations skip inference.' : ''}\n `;\n \n logger.debug(\"invoke: prompt details\", {\n hasConversationHistory: !!conversationSection,\n conversationHistoryLength: formattedHistory.length,\n conversationHistoryPreview: formattedHistory.substring(0, 300),\n contentLength: content?.length ?? 0,\n promptLength: prompt.length,\n promptPreview: prompt.substring(0, 500),\n });\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt)\n ];\n\n try {\n const result = await invokeWithAbortSignal(this.model, messages);\n const output = responseFormat.parse(result);\n\n logger.verbose(`invoke: found ${output.intents.length} intents`, {\n operationMode,\n allowedFallback: allowProfileFallback,\n usedFallback: !content && allowProfileFallback,\n });\n return output;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n logger.error(\"invoke: error during invocation\", {\n message: err.message,\n stack: err.stack,\n });\n return { intents: [] };\n }\n }\n\n /**\n * Formats conversation history for inclusion in the prompt.\n * Converts BaseMessage[] to readable string format.\n */\n private formatConversationHistory(messages: BaseMessage[]): string {\n const formatted = messages.map((msg, index) => {\n const role = msg._getType() === 'human' ? 'User' : 'Assistant';\n const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);\n // Truncate long messages for token efficiency\n const truncated = content.length > 200 ? content.substring(0, 200) + '...' : content;\n return `[${index + 1}] ${role}: ${truncated}`;\n }).join('\\n');\n \n logger.debug(\"formatConversationHistory: full conversation history\", {\n messageCount: messages.length,\n fullHistory: messages\n .map((msg, index) => {\n const role = msg._getType() === \"human\" ? \"User\" : \"Assistant\";\n const content = typeof msg.content === \"string\" ? msg.content : JSON.stringify(msg.content);\n return `[${index + 1}] ${role}: ${content}`;\n })\n .join(\"\\n\"),\n });\n\n return formatted;\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n * Useful for composing agents into larger graphs.\n */\n public static asTool() {\n return tool(\n async (args: { content: string | null; profileContext: string }) => {\n const agent = new ExplicitIntentInferrer();\n return await agent.invoke(args.content, args.profileContext);\n },\n {\n name: 'explicit_intent_inferrer',\n description: 'Extracts explicit intents from user content and profile context.',\n schema: z.object({\n content: z.string().nullable().describe('The new content to analyze'),\n profileContext: z.string().describe('The user profile context')\n })\n }\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.reconciler.d.ts","sourceRoot":"/","sources":["intent/intent.reconciler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"intent.reconciler.d.ts","sourceRoot":"/","sources":["intent/intent.reconciler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0ExB,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;EAS5B,CAAC;AAEH,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;EAO5B,CAAC;AAEH,QAAA,MAAM,wBAAwB;;;;;;;;;;;;EAI5B,CAAC;AAcH,MAAM,MAAM,sBAAsB,GAC9B,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3E,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3E,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IAAE,OAAO,EAAE,sBAAsB,EAAE,CAAA;CAAE,CAAC;AAe3E,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAA2C;;IAQxD;;;;OAIG;IAEU,MAAM,CAAC,wBAAwB,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM;;;IAqClF;;OAEG;WACW,MAAM;;;;;;;;;;;;;;;;;;CAgBrB"}
|
|
@@ -12,10 +12,9 @@ import { tool } from "@langchain/core/tools";
|
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
14
14
|
import { Timed } from "../shared/observability/performance.js";
|
|
15
|
-
import {
|
|
15
|
+
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
16
16
|
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
17
17
|
const logger = protocolLogger("IntentReconciler");
|
|
18
|
-
const model = createModel("intentReconciler");
|
|
19
18
|
const CreateActionTypeSchema = z.union([z.literal("create"), z.literal("CREATE")]);
|
|
20
19
|
const UpdateActionTypeSchema = z.union([z.literal("update"), z.literal("UPDATE")]);
|
|
21
20
|
const ExpireActionTypeSchema = z.union([z.literal("expire"), z.literal("EXPIRE")]);
|
|
@@ -119,7 +118,7 @@ const normalizeActionType = (type) => {
|
|
|
119
118
|
// ──────────────────────────────────────────────────────────────
|
|
120
119
|
export class IntentReconciler {
|
|
121
120
|
constructor() {
|
|
122
|
-
this.model =
|
|
121
|
+
this.model = createStructuredModel("intentReconciler", responseFormat, {
|
|
123
122
|
name: "intent_reconciler"
|
|
124
123
|
});
|
|
125
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.reconciler.js","sourceRoot":"/","sources":["intent/intent.reconciler.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"IntentReconciler\");\n\nconst model = createModel(\"intentReconciler\");\n\nconst CreateActionTypeSchema = z.union([z.literal(\"create\"), z.literal(\"CREATE\")]);\nconst UpdateActionTypeSchema = z.union([z.literal(\"update\"), z.literal(\"UPDATE\")]);\nconst ExpireActionTypeSchema = z.union([z.literal(\"expire\"), z.literal(\"EXPIRE\")]);\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\n\nconst systemPrompt = `\nYou are an expert Intent Manager. Your goal is to reconcile NEWLY INFERRED intents with the user's ACTIVE intents.\n\nYou have access to:\n1. Inferred Intents: Goals or Tombstones extracted from recent user activity.\n2. Active Intents: What the user is currently working on.\n\nYOUR TASK:\nCompare the Inferred Intents against the Active Intents and decide on the necessary ACTIONS (Create, Update, Expire).\n\nMATCHING LOGIC:\n- You must determine if an Inferred Intent refers to the same underlying goal as an Active Intent.\n- You must detect if an Inferred Intent CONTRADICTS an Active Intent (Change of Mind).\n\nSEMANTIC GOVERNANCE RULES (Donnellan's Distinction):\n- **REFERENTIAL Intents** (Anchor != NULL): These point to specific entities (e.g., \"Google\").\n - Matching logic: Match if the Anchor is the SAME.\n - If Anchor is different (e.g. \"Join Google\" vs \"Join Meta\"), they are DIFFERENT intents.\n- **ATTRIBUTIVE Intents** (Anchor == NULL): These describe a class of things.\n - Matching logic: Match if the description is semantically similar content.\n - E.g. \"Join a startup\" and \"Work for a small tech company\" are the SAME.\n\nACTIONS:\n- CREATE: If an Inferred Goal does NOT match any Active Intent, CREATE it.\n- UPDATE: If an Inferred Goal matches an Active Intent but offers a better/different description, UPDATE it. When the match is an exact duplicate (same goal, no change needed), still output an UPDATE action with that Active Intent's id and the same payload—this allows the caller to link the intent to an index (e.g. add it to a community).\n CRITICAL UPDATE MERGE RULES:\n * When UPDATING an intent, you MUST PRESERVE all existing details from the Active Intent.\n * Only MODIFY or ADD the specific aspects mentioned in the Inferred Intent.\n * NEVER remove existing details unless explicitly contradicted.\n * Examples:\n - Active: \"Create a text-based RPG game\"\n - Inferred: \"Create an RPG game with LLM-enhanced narration\"\n - CORRECT UPDATE: \"Create a text-based RPG game with LLM-enhanced narration\" (preserved \"text-based\")\n - WRONG UPDATE: \"Create an RPG game with LLM-enhanced narration\" (lost \"text-based\")\n * Think of updates as REFINEMENTS or ADDITIONS, not REPLACEMENTS.\n * If the Inferred Intent is a complete restatement, it's fine to use it directly.\n * If the Inferred Intent adds/modifies specific aspects, merge it with existing details.\n\n COMPOUND INTENT SANITY CHECK (CRITICAL):\n * NEVER produce a compound intent — an intent with multiple distinct goals joined by \"and\", \"as well as\", commas, or similar.\n * If merging would create a compound (e.g., \"Find an artist for X, and collaborate on Y\"), the intents are NOT the same — CREATE the new one instead.\n * Valid UPDATE: adding detail to ONE goal (e.g., \"Find a developer\" → \"Find a senior React developer in Berlin\")\n * Invalid UPDATE (compound): joining TWO goals (e.g., \"Find an artist\" + \"Collaborate on art direction\" → \"Find an artist and collaborate on art direction\")\n * When in doubt, CREATE a new intent rather than risk a compound.\n- EXPIRE: If an Inferred Tombstone matches an Active Intent (semantically), EXPIRE it.\n- CONFLICT RESOLUTION: If a NEW Goal contradicts an Active Intent, EXPIRE the old and CREATE the new.\n- DEDUPLICATION: Use Donnellan's Distinction above to merge duplicates. For duplicates, output UPDATE (not an empty list) so the intent can be linked to an index.\n\nOutput a list of specific actions to apply.\nIMPORTANT: The type field MUST be exactly one of: \"create\", \"update\", \"expire\" (lowercase).\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst CreateIntentActionSchema = z.object({\n type: CreateActionTypeSchema,\n payload: z.string().describe(\"The new intent description\"),\n score: z.number().nullable().describe(\"The felicity score (0-100)\"),\n reasoning: z.string().nullable().describe(\"Reasoning for the creation (including felicity)\"),\n // Semantic Governance Fields\n intentMode: z.enum(['REFERENTIAL', 'ATTRIBUTIVE']).nullable().describe(\"Donnellan's Distinction\"),\n referentialAnchor: z.string().nullable().describe(\"Entity anchored to\"),\n semanticEntropy: z.number().nullable().describe(\"Constraint Density Score (0-1)\"),\n});\n\nconst UpdateIntentActionSchema = z.object({\n type: UpdateActionTypeSchema,\n id: z.string().describe(\"The ID of the intent to update\"),\n payload: z.string().describe(\"The updated intent description\"),\n score: z.number().nullable().describe(\"The felicity score (0-100)\"),\n reasoning: z.string().nullable().describe(\"Reasoning for the update\"),\n intentMode: z.enum(['REFERENTIAL', 'ATTRIBUTIVE']).nullable(),\n});\n\nconst ExpireIntentActionSchema = z.object({\n type: ExpireActionTypeSchema,\n id: z.string().describe(\"The ID of the intent to expire\"),\n reason: z.string().describe(\"Why it is expired\")\n});\n\nconst responseFormat = z.object({\n actions: z.array(z.union([\n CreateIntentActionSchema,\n UpdateIntentActionSchema,\n ExpireIntentActionSchema\n ])).describe(\"List of actions to apply\")\n});\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS (match invoke() return shape: normalized lowercase action types)\n// ──────────────────────────────────────────────────────────────\n\nexport type NormalizedIntentAction =\n | Omit<z.infer<typeof CreateIntentActionSchema>, \"type\"> & { type: \"create\" }\n | Omit<z.infer<typeof UpdateIntentActionSchema>, \"type\"> & { type: \"update\" }\n | Omit<z.infer<typeof ExpireIntentActionSchema>, \"type\"> & { type: \"expire\" };\n\nexport type IntentReconcilerOutput = { actions: NormalizedIntentAction[] };\n\nconst normalizeActionType = (type: string): \"create\" | \"update\" | \"expire\" => {\n const normalized = type.toLowerCase();\n if (normalized === \"create\" || normalized === \"update\" || normalized === \"expire\") {\n return normalized;\n }\n logger.warn(`normalizeActionType: unexpected action type \"${type}\", defaulting to \"create\"`);\n return \"create\";\n};\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class IntentReconciler {\n private model: any;\n\n constructor() {\n this.model = model.withStructuredOutput(responseFormat, {\n name: \"intent_reconciler\"\n });\n }\n\n /**\n * Reconciles inferred intents with active intents.\n * @param inferredIntentsFormatted - Formatted string of inferred intents.\n * @param activeIntentsContext - Formatted string of active intents.\n */\n @Timed()\n public async invoke(inferredIntentsFormatted: string, activeIntentsContext: string) {\n logger.verbose(`[IntentReconciler.invoke] Reconciling intents...`);\n\n const prompt = `\n # Active Intents\n ${activeIntentsContext}\n\n # Inferred Intents (Candidates)\n ${inferredIntentsFormatted}\n\n Based on the Inferred Intents, determine the actions to modify the Active Intents state.\n IMPORTANT:\n - If you CREATE or UPDATE an intent, you MUST popuate the 'score' and 'reasoning' fields.\n - Extract the 'score', 'semanticEntropy', 'referentialAnchor' from the Inferred Intent's data.\n - Include the verification details in the 'reasoning'.\n `;\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt)\n ];\n\n try {\n const output = responseFormat.parse(await invokeWithAbortSignal(this.model, messages));\n const normalizedActions = output.actions.map((action: z.infer<typeof responseFormat>[\"actions\"][number]) => ({ \n ...action,\n type: normalizeActionType(action.type),\n })) as NormalizedIntentAction[];\n\n logger.verbose(`[IntentReconciler.invoke] Decision: ${normalizedActions.length} actions.`);\n return { actions: normalizedActions };\n } catch (error) {\n logger.error(\"[IntentReconciler] Error during invocation\", { error });\n return { actions: [] };\n }\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n */\n public static asTool() {\n return tool(\n async (args: { inferredIntents: string; activeIntents: string }) => {\n const agent = new IntentReconciler();\n return await agent.invoke(args.inferredIntents, args.activeIntents);\n },\n {\n name: 'intent_reconciler',\n description: 'Reconciles inferred intents with active intents to determine state changes.',\n schema: z.object({\n inferredIntents: z.string().describe('Formatted string of inferred intents'),\n activeIntents: z.string().describe('Formatted string of active intents')\n })\n }\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"intent.reconciler.js","sourceRoot":"/","sources":["intent/intent.reconciler.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"IntentReconciler\");\n\n\nconst CreateActionTypeSchema = z.union([z.literal(\"create\"), z.literal(\"CREATE\")]);\nconst UpdateActionTypeSchema = z.union([z.literal(\"update\"), z.literal(\"UPDATE\")]);\nconst ExpireActionTypeSchema = z.union([z.literal(\"expire\"), z.literal(\"EXPIRE\")]);\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\n\nconst systemPrompt = `\nYou are an expert Intent Manager. Your goal is to reconcile NEWLY INFERRED intents with the user's ACTIVE intents.\n\nYou have access to:\n1. Inferred Intents: Goals or Tombstones extracted from recent user activity.\n2. Active Intents: What the user is currently working on.\n\nYOUR TASK:\nCompare the Inferred Intents against the Active Intents and decide on the necessary ACTIONS (Create, Update, Expire).\n\nMATCHING LOGIC:\n- You must determine if an Inferred Intent refers to the same underlying goal as an Active Intent.\n- You must detect if an Inferred Intent CONTRADICTS an Active Intent (Change of Mind).\n\nSEMANTIC GOVERNANCE RULES (Donnellan's Distinction):\n- **REFERENTIAL Intents** (Anchor != NULL): These point to specific entities (e.g., \"Google\").\n - Matching logic: Match if the Anchor is the SAME.\n - If Anchor is different (e.g. \"Join Google\" vs \"Join Meta\"), they are DIFFERENT intents.\n- **ATTRIBUTIVE Intents** (Anchor == NULL): These describe a class of things.\n - Matching logic: Match if the description is semantically similar content.\n - E.g. \"Join a startup\" and \"Work for a small tech company\" are the SAME.\n\nACTIONS:\n- CREATE: If an Inferred Goal does NOT match any Active Intent, CREATE it.\n- UPDATE: If an Inferred Goal matches an Active Intent but offers a better/different description, UPDATE it. When the match is an exact duplicate (same goal, no change needed), still output an UPDATE action with that Active Intent's id and the same payload—this allows the caller to link the intent to an index (e.g. add it to a community).\n CRITICAL UPDATE MERGE RULES:\n * When UPDATING an intent, you MUST PRESERVE all existing details from the Active Intent.\n * Only MODIFY or ADD the specific aspects mentioned in the Inferred Intent.\n * NEVER remove existing details unless explicitly contradicted.\n * Examples:\n - Active: \"Create a text-based RPG game\"\n - Inferred: \"Create an RPG game with LLM-enhanced narration\"\n - CORRECT UPDATE: \"Create a text-based RPG game with LLM-enhanced narration\" (preserved \"text-based\")\n - WRONG UPDATE: \"Create an RPG game with LLM-enhanced narration\" (lost \"text-based\")\n * Think of updates as REFINEMENTS or ADDITIONS, not REPLACEMENTS.\n * If the Inferred Intent is a complete restatement, it's fine to use it directly.\n * If the Inferred Intent adds/modifies specific aspects, merge it with existing details.\n\n COMPOUND INTENT SANITY CHECK (CRITICAL):\n * NEVER produce a compound intent — an intent with multiple distinct goals joined by \"and\", \"as well as\", commas, or similar.\n * If merging would create a compound (e.g., \"Find an artist for X, and collaborate on Y\"), the intents are NOT the same — CREATE the new one instead.\n * Valid UPDATE: adding detail to ONE goal (e.g., \"Find a developer\" → \"Find a senior React developer in Berlin\")\n * Invalid UPDATE (compound): joining TWO goals (e.g., \"Find an artist\" + \"Collaborate on art direction\" → \"Find an artist and collaborate on art direction\")\n * When in doubt, CREATE a new intent rather than risk a compound.\n- EXPIRE: If an Inferred Tombstone matches an Active Intent (semantically), EXPIRE it.\n- CONFLICT RESOLUTION: If a NEW Goal contradicts an Active Intent, EXPIRE the old and CREATE the new.\n- DEDUPLICATION: Use Donnellan's Distinction above to merge duplicates. For duplicates, output UPDATE (not an empty list) so the intent can be linked to an index.\n\nOutput a list of specific actions to apply.\nIMPORTANT: The type field MUST be exactly one of: \"create\", \"update\", \"expire\" (lowercase).\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst CreateIntentActionSchema = z.object({\n type: CreateActionTypeSchema,\n payload: z.string().describe(\"The new intent description\"),\n score: z.number().nullable().describe(\"The felicity score (0-100)\"),\n reasoning: z.string().nullable().describe(\"Reasoning for the creation (including felicity)\"),\n // Semantic Governance Fields\n intentMode: z.enum(['REFERENTIAL', 'ATTRIBUTIVE']).nullable().describe(\"Donnellan's Distinction\"),\n referentialAnchor: z.string().nullable().describe(\"Entity anchored to\"),\n semanticEntropy: z.number().nullable().describe(\"Constraint Density Score (0-1)\"),\n});\n\nconst UpdateIntentActionSchema = z.object({\n type: UpdateActionTypeSchema,\n id: z.string().describe(\"The ID of the intent to update\"),\n payload: z.string().describe(\"The updated intent description\"),\n score: z.number().nullable().describe(\"The felicity score (0-100)\"),\n reasoning: z.string().nullable().describe(\"Reasoning for the update\"),\n intentMode: z.enum(['REFERENTIAL', 'ATTRIBUTIVE']).nullable(),\n});\n\nconst ExpireIntentActionSchema = z.object({\n type: ExpireActionTypeSchema,\n id: z.string().describe(\"The ID of the intent to expire\"),\n reason: z.string().describe(\"Why it is expired\")\n});\n\nconst responseFormat = z.object({\n actions: z.array(z.union([\n CreateIntentActionSchema,\n UpdateIntentActionSchema,\n ExpireIntentActionSchema\n ])).describe(\"List of actions to apply\")\n});\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS (match invoke() return shape: normalized lowercase action types)\n// ──────────────────────────────────────────────────────────────\n\nexport type NormalizedIntentAction =\n | Omit<z.infer<typeof CreateIntentActionSchema>, \"type\"> & { type: \"create\" }\n | Omit<z.infer<typeof UpdateIntentActionSchema>, \"type\"> & { type: \"update\" }\n | Omit<z.infer<typeof ExpireIntentActionSchema>, \"type\"> & { type: \"expire\" };\n\nexport type IntentReconcilerOutput = { actions: NormalizedIntentAction[] };\n\nconst normalizeActionType = (type: string): \"create\" | \"update\" | \"expire\" => {\n const normalized = type.toLowerCase();\n if (normalized === \"create\" || normalized === \"update\" || normalized === \"expire\") {\n return normalized;\n }\n logger.warn(`normalizeActionType: unexpected action type \"${type}\", defaulting to \"create\"`);\n return \"create\";\n};\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class IntentReconciler {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"intentReconciler\", responseFormat, {\n name: \"intent_reconciler\"\n });\n }\n\n /**\n * Reconciles inferred intents with active intents.\n * @param inferredIntentsFormatted - Formatted string of inferred intents.\n * @param activeIntentsContext - Formatted string of active intents.\n */\n @Timed()\n public async invoke(inferredIntentsFormatted: string, activeIntentsContext: string) {\n logger.verbose(`[IntentReconciler.invoke] Reconciling intents...`);\n\n const prompt = `\n # Active Intents\n ${activeIntentsContext}\n\n # Inferred Intents (Candidates)\n ${inferredIntentsFormatted}\n\n Based on the Inferred Intents, determine the actions to modify the Active Intents state.\n IMPORTANT:\n - If you CREATE or UPDATE an intent, you MUST popuate the 'score' and 'reasoning' fields.\n - Extract the 'score', 'semanticEntropy', 'referentialAnchor' from the Inferred Intent's data.\n - Include the verification details in the 'reasoning'.\n `;\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt)\n ];\n\n try {\n const output = responseFormat.parse(await invokeWithAbortSignal(this.model, messages));\n const normalizedActions = output.actions.map((action: z.infer<typeof responseFormat>[\"actions\"][number]) => ({ \n ...action,\n type: normalizeActionType(action.type),\n })) as NormalizedIntentAction[];\n\n logger.verbose(`[IntentReconciler.invoke] Decision: ${normalizedActions.length} actions.`);\n return { actions: normalizedActions };\n } catch (error) {\n logger.error(\"[IntentReconciler] Error during invocation\", { error });\n return { actions: [] };\n }\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n */\n public static asTool() {\n return tool(\n async (args: { inferredIntents: string; activeIntents: string }) => {\n const agent = new IntentReconciler();\n return await agent.invoke(args.inferredIntents, args.activeIntents);\n },\n {\n name: 'intent_reconciler',\n description: 'Reconciles inferred intents with active intents to determine state changes.',\n schema: z.object({\n inferredIntents: z.string().describe('Formatted string of inferred intents'),\n activeIntents: z.string().describe('Formatted string of active intents')\n })\n }\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.verifier.d.ts","sourceRoot":"/","sources":["intent/intent.verifier.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,QAAA,MAAM,wBAAwB,4CAA0C,CAAC;AACzE,QAAA,MAAM,kCAAkC,oFAOtC,CAAC;
|
|
1
|
+
{"version":3,"file":"intent.verifier.d.ts","sourceRoot":"/","sources":["intent/intent.verifier.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,QAAA,MAAM,wBAAwB,4CAA0C,CAAC;AACzE,QAAA,MAAM,kCAAkC,oFAOtC,CAAC;AAuJH,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+ClB,CAAC;AAMH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAC9F,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAMpE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAA2C;;IAQxD;;;;OAIG;IAEU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;IA8BpD;;OAEG;WACW,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBrB"}
|
|
@@ -12,7 +12,7 @@ import { tool } from "@langchain/core/tools";
|
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
14
14
|
import { Timed } from "../shared/observability/performance.js";
|
|
15
|
-
import {
|
|
15
|
+
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
16
16
|
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
17
17
|
const logger = protocolLogger("SemanticVerifier");
|
|
18
18
|
const referentialBreadthSchema = z.enum(["narrow", "moderate", "broad"]);
|
|
@@ -24,7 +24,6 @@ const missingSelectionalConstraintSchema = z.enum([
|
|
|
24
24
|
"domain",
|
|
25
25
|
"concrete_need",
|
|
26
26
|
]);
|
|
27
|
-
const model = createModel("intentVerifier");
|
|
28
27
|
// ──────────────────────────────────────────────────────────────
|
|
29
28
|
// 1. SYSTEM PROMPT
|
|
30
29
|
// ──────────────────────────────────────────────────────────────
|
|
@@ -202,7 +201,7 @@ const responseFormat = z.object({
|
|
|
202
201
|
// ──────────────────────────────────────────────────────────────
|
|
203
202
|
export class SemanticVerifier {
|
|
204
203
|
constructor() {
|
|
205
|
-
this.model =
|
|
204
|
+
this.model = createStructuredModel("intentVerifier", responseFormat, {
|
|
206
205
|
name: "semantic_verifier"
|
|
207
206
|
});
|
|
208
207
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.verifier.js","sourceRoot":"/","sources":["intent/intent.verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"SemanticVerifier\");\n\nconst referentialBreadthSchema = z.enum([\"narrow\", \"moderate\", \"broad\"]);\nconst missingSelectionalConstraintSchema = z.enum([\n \"role\",\n \"outcome\",\n \"location\",\n \"timeframe\",\n \"domain\",\n \"concrete_need\",\n]);\n\nconst model = createModel(\"intentVerifier\");\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\nconst systemPrompt = `\nYou are the Semantic Verification Engine for the Index Network — an intent-driven discovery protocol.\n\nYour job: classify a user utterance using Searle's Speech Act Theory, then score its felicity conditions.\n\nAlways reason before classifying. Output reasoning first.\n\n═══════════════════════════════════════════════════\nSTEP 1 — CLASSIFY THE ILLOCUTIONARY ACT\n═══════════════════════════════════════════════════\n\nWork through this decision tree in order. Stop at the first matching branch.\n\nIF the utterance cancels, terminates, or declares a state change (e.g., \"I quit\", \"Project cancelled\", \"This position is closed\"):\n → DECLARATION\n\nELSE IF the utterance expresses a search, need, or request for another party — even without an explicit verb or first-person subject:\n → DIRECTIVE\n\n DIRECTIVE trigger patterns (any of these → DIRECTIVE):\n · \"Looking for [X]\" · \"Seeking [X]\"\n · \"In search of [X]\" · \"Need a [X]\"\n · \"Want to find [X]\" · \"Interested in connecting with [X]\"\n · \"Open to [X]\" · \"Hiring [X]\"\n · \"Would love to meet [X]\" · \"Anyone know [X]\"\n\n KEY RULE: A verbless gerundive like \"Looking for artists for collaboration\" IS a DIRECTIVE.\n The missing first-person subject (\"I am\") is routinely elided in natural intent language.\n The illocutionary force is a search directive aimed at the system, not an assertion about reality.\n\n DIRECTIVE positive examples:\n · \"Looking for artists for collaboration\" → DIRECTIVE (elided subject, search intent)\n · \"Seeking a technical co-founder in NYC\" → DIRECTIVE\n · \"Need a PyTorch expert for a 3-month contract\" → DIRECTIVE\n · \"Open to angel investment opportunities\" → DIRECTIVE\n · \"Anyone building in the DeSci space?\" → DIRECTIVE\n\n DIRECTIVE negative examples (do NOT classify these as DIRECTIVE):\n · \"AI is changing the creative industry\" → ASSERTIVE (states a belief, no search)\n · \"I built a collaboration platform\" → ASSERTIVE/COMMISSIVE (past action, no request)\n · \"Collaboration is important\" → ASSERTIVE (general belief)\n\nELSE IF the utterance commits the speaker to a future action:\n → COMMISSIVE\n\n COMMISSIVE positive examples:\n · \"I will deploy the contract by Friday\" → COMMISSIVE\n · \"I'm going to learn Rust this quarter\" → COMMISSIVE\n · \"I commit to mentoring two junior devs\" → COMMISSIVE\n\n COMMISSIVE negative examples (do NOT classify these as COMMISSIVE):\n · \"I could probably look into it\" → too hedged; score sincerity low instead\n · \"We should build something cool\" → vague, no personal commitment\n\nELSE IF the utterance states a fact, belief, or opinion with no implied request or commitment:\n → ASSERTIVE\n\n ASSERTIVE positive examples:\n · \"Rust is faster than C++\" → ASSERTIVE\n · \"I have 10 years of experience in ML\" → ASSERTIVE (profile statement, not a request)\n · \"The crypto market is volatile\" → ASSERTIVE\n\nELSE IF the utterance expresses a psychological state or social ritual:\n → EXPRESSIVE\n\n EXPRESSIVE examples: \"I'm so excited!\", \"Hello everyone\", \"Congrats to the team\"\n\nIf none of the above apply cleanly:\n → UNKNOWN\n\n═══════════════════════════════════════════════════\nSTEP 2 — SCORE THE FELICITY CONDITIONS (0–100)\n═══════════════════════════════════════════════════\n\nScore AFTER classification. Do not let scores influence the category decision.\n\nCLARITY (Essential Condition)\n How unambiguous and actionable is the utterance?\n 100 → \"Deploy the Solidity contract to Mainnet by March 15\"\n 60 → \"Looking for a developer\" (clear direction, vague spec)\n 20 → \"We should do something cool\"\n\nAUTHORITY (Preparatory Condition)\n Does the speaker's profile support this act?\n Compare stated skills/role against the action or search domain.\n 100 → Profile: Senior ML Engineer | Utterance: \"Seeking a research collaborator on transformers\"\n 20 → Profile: Junior Marketer | Utterance: \"I will rewrite the Rust compiler\"\n For DIRECTIVEs: authority = plausibility that this person would make this search.\n\nSINCERITY (Sincerity Condition)\n Does the linguistic form imply genuine commitment or genuine need?\n For COMMISSIVEs: check modality (will > going to > might > could).\n For DIRECTIVEs: check specificity of the search (specific need > vague wish).\n 100 → \"I need a Rails contractor starting next week, $150/hr, remote\"\n 40 → \"I could maybe try to find someone\"\n\nSEMANTIC ENTROPY (Constraint Density) → semantic_entropy field, range 0.0–1.0\n 0.0 = maximally constrained (time, location, tech stack, quantifiers all present)\n 1.0 = no constraints at all\n 0.0 example: \"Meet 50 senior React devs in SF by Friday\"\n 1.0 example: \"Network\"\n\nREFERENTIAL ANCHOR → referential_anchor field\n Does the utterance name a specific unique entity (Donnellan referential use)?\n If YES → output the entity name string.\n If NO (attributive reference to any member of a class) → output null.\n \"I want to join Google\" → \"Google\"\n \"I want to join a startup\" → null\n\nREFERENTIAL BREADTH → referential_breadth field\n Estimate the extension size of the open candidate class: how many people could plausibly satisfy the description.\n This is NOT the same as semantic_entropy. Semantic entropy measures underspecification/constraint density;\n referential breadth measures whether the attributive description narrows the satisfier class enough for discovery.\n\n narrow → a small satisfier class due to concrete role/outcome/location/timeframe/specific need.\n Example: \"Find a robotics founder in Healdsburg this week to test my meditation hardware prototype\"\n moderate → a bounded professional/community class, but some constraints are still missing.\n Example: \"Meet AI safety researchers working on evals in London\"\n broad → a large satisfier class; many people could plausibly match even if topical constraints are present.\n Example: \"Meet creative people, builders, and makers interested in AI, meditation, and tech exploration\"\n\nMISSING SELECTIONAL CONSTRAINTS → missing_selectional_constraints field\n Report the constraints whose absence keeps the candidate class too broad:\n role, outcome, location, timeframe, domain, concrete_need.\n\nSPECIFICITY WARNING → specificity_warning field\n If referential_breadth is broad, provide a concise user-facing warning asking for a more concrete role,\n outcome, location, timeframe, domain, or need. Otherwise output null.\n\n═══════════════════════════════════════════════════\nSTEP 3 — FLAGS\n═══════════════════════════════════════════════════\n\nAdd flags when scores fall below threshold:\n authority < 70 → \"SKILL_MISMATCH\"\n sincerity < 70 → \"WEAK_COMMITMENT\"\n clarity < 50 → \"VAGUE_INTENT\"\n classification is ASSERTIVE or EXPRESSIVE → \"NOISE\"\n referential_breadth is broad → \"BROAD_ATTRIBUTIVE_REFERENCE\"\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst responseFormat = z.object({\n // reasoning comes first so the model commits to its analysis\n // before the classification token is generated (chain-of-thought anchor)\n reasoning: z.string().describe(\n \"Step-by-step analysis: (1) which decision-tree branch fired and why, \" +\n \"(2) key surface features of the utterance (trigger keywords, elided subject, modality), \" +\n \"(3) felicity condition assessment.\"\n ),\n\n classification: z.enum([\n \"COMMISSIVE\",\n \"DIRECTIVE\",\n \"ASSERTIVE\",\n \"EXPRESSIVE\",\n \"DECLARATION\",\n \"UNKNOWN\"\n ]).describe(\"Searle's Speech Act category — determined by the decision tree in STEP 1\"),\n\n felicity_scores: z.object({\n clarity: z.number().min(0).max(100).describe(\"Essential Condition: how unambiguous and actionable is the utterance (0–100)\"),\n authority: z.number().min(0).max(100).describe(\"Preparatory Condition: does the speaker's profile support this act (0–100)\"),\n sincerity: z.number().min(0).max(100).describe(\"Sincerity Condition: does the linguistic form imply genuine commitment or need (0–100)\"),\n }),\n\n semantic_entropy: z.number().min(0).max(1).describe(\n \"Constraint density: 0.0 = maximally specific (time + location + tech + quantifiers), 1.0 = completely unconstrained\"\n ),\n\n referential_anchor: z.string().nullable().describe(\n \"Named specific entity the utterance refers to (Donnellan referential), or null for attributive reference\"\n ),\n\n referential_breadth: referentialBreadthSchema.describe(\n \"Extension size of the open candidate class: narrow, moderate, or broad. Distinct from semantic entropy.\"\n ),\n\n missing_selectional_constraints: z.array(missingSelectionalConstraintSchema).describe(\n \"Selectional constraints whose absence leaves the satisfier class too broad.\"\n ),\n\n specificity_warning: z.string().nullable().describe(\n \"Concise user-facing warning when referential_breadth is broad; otherwise null.\"\n ),\n\n flags: z.array(z.string()).describe(\n \"Semantic violation tags: SKILL_MISMATCH (authority<70), WEAK_COMMITMENT (sincerity<70), VAGUE_INTENT (clarity<50), NOISE (ASSERTIVE or EXPRESSIVE), BROAD_ATTRIBUTIVE_REFERENCE (referential_breadth=broad)\"\n ),\n});\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS\n// ──────────────────────────────────────────────────────────────\n\nexport type ReferentialBreadth = z.infer<typeof referentialBreadthSchema>;\nexport type MissingSelectionalConstraint = z.infer<typeof missingSelectionalConstraintSchema>;\nexport type SemanticVerifierOutput = z.infer<typeof responseFormat>;\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class SemanticVerifier {\n private model: any;\n\n constructor() {\n this.model = model.withStructuredOutput(responseFormat, {\n name: \"semantic_verifier\"\n });\n }\n\n /**\n * Verifies the semantic validity of an intent.\n * @param content - The user's raw utterance.\n * @param context - The User Profile as a JSON string.\n */\n @Timed()\n public async invoke(content: string, context: string) {\n logger.verbose(`[SemanticVerifier.invoke] Verifying: \"${content.substring(0, 30)}...\"`);\n\n const prompt = `\n # User Profile (Context)\n ${context}\n\n # User Utterance (Content)\n \"${content}\"\n \n Verify the Felicity Conditions and Semantic Metrics for this utterance.\n `;\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt)\n ];\n\n try {\n const result = await invokeWithAbortSignal(this.model, messages);\n const output = responseFormat.parse(result);\n\n logger.verbose(`[SemanticVerifier.invoke] Verdict: ${output.classification} Entropy: ${output.semantic_entropy}`);\n return output;\n } catch (error) {\n logger.error(\"[SemanticVerifier] Error during invocation\", { error });\n throw error;\n }\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n */\n public static asTool() {\n return tool(\n async (args: { content: string; context: string }) => {\n const agent = new SemanticVerifier();\n return await agent.invoke(args.content, args.context);\n },\n {\n name: 'semantic_verifier',\n description: 'Verifies the semantic validity and felicity conditions of an intent.',\n schema: z.object({\n content: z.string().describe('The intent content to verify'),\n context: z.string().describe('The user profile context')\n })\n }\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"intent.verifier.js","sourceRoot":"/","sources":["intent/intent.verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"SemanticVerifier\");\n\nconst referentialBreadthSchema = z.enum([\"narrow\", \"moderate\", \"broad\"]);\nconst missingSelectionalConstraintSchema = z.enum([\n \"role\",\n \"outcome\",\n \"location\",\n \"timeframe\",\n \"domain\",\n \"concrete_need\",\n]);\n\n// ──────────────────────────────────────────────────────────────\n// 1. SYSTEM PROMPT\n// ──────────────────────────────────────────────────────────────\n\nconst systemPrompt = `\nYou are the Semantic Verification Engine for the Index Network — an intent-driven discovery protocol.\n\nYour job: classify a user utterance using Searle's Speech Act Theory, then score its felicity conditions.\n\nAlways reason before classifying. Output reasoning first.\n\n═══════════════════════════════════════════════════\nSTEP 1 — CLASSIFY THE ILLOCUTIONARY ACT\n═══════════════════════════════════════════════════\n\nWork through this decision tree in order. Stop at the first matching branch.\n\nIF the utterance cancels, terminates, or declares a state change (e.g., \"I quit\", \"Project cancelled\", \"This position is closed\"):\n → DECLARATION\n\nELSE IF the utterance expresses a search, need, or request for another party — even without an explicit verb or first-person subject:\n → DIRECTIVE\n\n DIRECTIVE trigger patterns (any of these → DIRECTIVE):\n · \"Looking for [X]\" · \"Seeking [X]\"\n · \"In search of [X]\" · \"Need a [X]\"\n · \"Want to find [X]\" · \"Interested in connecting with [X]\"\n · \"Open to [X]\" · \"Hiring [X]\"\n · \"Would love to meet [X]\" · \"Anyone know [X]\"\n\n KEY RULE: A verbless gerundive like \"Looking for artists for collaboration\" IS a DIRECTIVE.\n The missing first-person subject (\"I am\") is routinely elided in natural intent language.\n The illocutionary force is a search directive aimed at the system, not an assertion about reality.\n\n DIRECTIVE positive examples:\n · \"Looking for artists for collaboration\" → DIRECTIVE (elided subject, search intent)\n · \"Seeking a technical co-founder in NYC\" → DIRECTIVE\n · \"Need a PyTorch expert for a 3-month contract\" → DIRECTIVE\n · \"Open to angel investment opportunities\" → DIRECTIVE\n · \"Anyone building in the DeSci space?\" → DIRECTIVE\n\n DIRECTIVE negative examples (do NOT classify these as DIRECTIVE):\n · \"AI is changing the creative industry\" → ASSERTIVE (states a belief, no search)\n · \"I built a collaboration platform\" → ASSERTIVE/COMMISSIVE (past action, no request)\n · \"Collaboration is important\" → ASSERTIVE (general belief)\n\nELSE IF the utterance commits the speaker to a future action:\n → COMMISSIVE\n\n COMMISSIVE positive examples:\n · \"I will deploy the contract by Friday\" → COMMISSIVE\n · \"I'm going to learn Rust this quarter\" → COMMISSIVE\n · \"I commit to mentoring two junior devs\" → COMMISSIVE\n\n COMMISSIVE negative examples (do NOT classify these as COMMISSIVE):\n · \"I could probably look into it\" → too hedged; score sincerity low instead\n · \"We should build something cool\" → vague, no personal commitment\n\nELSE IF the utterance states a fact, belief, or opinion with no implied request or commitment:\n → ASSERTIVE\n\n ASSERTIVE positive examples:\n · \"Rust is faster than C++\" → ASSERTIVE\n · \"I have 10 years of experience in ML\" → ASSERTIVE (profile statement, not a request)\n · \"The crypto market is volatile\" → ASSERTIVE\n\nELSE IF the utterance expresses a psychological state or social ritual:\n → EXPRESSIVE\n\n EXPRESSIVE examples: \"I'm so excited!\", \"Hello everyone\", \"Congrats to the team\"\n\nIf none of the above apply cleanly:\n → UNKNOWN\n\n═══════════════════════════════════════════════════\nSTEP 2 — SCORE THE FELICITY CONDITIONS (0–100)\n═══════════════════════════════════════════════════\n\nScore AFTER classification. Do not let scores influence the category decision.\n\nCLARITY (Essential Condition)\n How unambiguous and actionable is the utterance?\n 100 → \"Deploy the Solidity contract to Mainnet by March 15\"\n 60 → \"Looking for a developer\" (clear direction, vague spec)\n 20 → \"We should do something cool\"\n\nAUTHORITY (Preparatory Condition)\n Does the speaker's profile support this act?\n Compare stated skills/role against the action or search domain.\n 100 → Profile: Senior ML Engineer | Utterance: \"Seeking a research collaborator on transformers\"\n 20 → Profile: Junior Marketer | Utterance: \"I will rewrite the Rust compiler\"\n For DIRECTIVEs: authority = plausibility that this person would make this search.\n\nSINCERITY (Sincerity Condition)\n Does the linguistic form imply genuine commitment or genuine need?\n For COMMISSIVEs: check modality (will > going to > might > could).\n For DIRECTIVEs: check specificity of the search (specific need > vague wish).\n 100 → \"I need a Rails contractor starting next week, $150/hr, remote\"\n 40 → \"I could maybe try to find someone\"\n\nSEMANTIC ENTROPY (Constraint Density) → semantic_entropy field, range 0.0–1.0\n 0.0 = maximally constrained (time, location, tech stack, quantifiers all present)\n 1.0 = no constraints at all\n 0.0 example: \"Meet 50 senior React devs in SF by Friday\"\n 1.0 example: \"Network\"\n\nREFERENTIAL ANCHOR → referential_anchor field\n Does the utterance name a specific unique entity (Donnellan referential use)?\n If YES → output the entity name string.\n If NO (attributive reference to any member of a class) → output null.\n \"I want to join Google\" → \"Google\"\n \"I want to join a startup\" → null\n\nREFERENTIAL BREADTH → referential_breadth field\n Estimate the extension size of the open candidate class: how many people could plausibly satisfy the description.\n This is NOT the same as semantic_entropy. Semantic entropy measures underspecification/constraint density;\n referential breadth measures whether the attributive description narrows the satisfier class enough for discovery.\n\n narrow → a small satisfier class due to concrete role/outcome/location/timeframe/specific need.\n Example: \"Find a robotics founder in Healdsburg this week to test my meditation hardware prototype\"\n moderate → a bounded professional/community class, but some constraints are still missing.\n Example: \"Meet AI safety researchers working on evals in London\"\n broad → a large satisfier class; many people could plausibly match even if topical constraints are present.\n Example: \"Meet creative people, builders, and makers interested in AI, meditation, and tech exploration\"\n\nMISSING SELECTIONAL CONSTRAINTS → missing_selectional_constraints field\n Report the constraints whose absence keeps the candidate class too broad:\n role, outcome, location, timeframe, domain, concrete_need.\n\nSPECIFICITY WARNING → specificity_warning field\n If referential_breadth is broad, provide a concise user-facing warning asking for a more concrete role,\n outcome, location, timeframe, domain, or need. Otherwise output null.\n\n═══════════════════════════════════════════════════\nSTEP 3 — FLAGS\n═══════════════════════════════════════════════════\n\nAdd flags when scores fall below threshold:\n authority < 70 → \"SKILL_MISMATCH\"\n sincerity < 70 → \"WEAK_COMMITMENT\"\n clarity < 50 → \"VAGUE_INTENT\"\n classification is ASSERTIVE or EXPRESSIVE → \"NOISE\"\n referential_breadth is broad → \"BROAD_ATTRIBUTIVE_REFERENCE\"\n`;\n\n// ──────────────────────────────────────────────────────────────\n// 2. RESPONSE SCHEMA (Zod)\n// ──────────────────────────────────────────────────────────────\n\nconst responseFormat = z.object({\n // reasoning comes first so the model commits to its analysis\n // before the classification token is generated (chain-of-thought anchor)\n reasoning: z.string().describe(\n \"Step-by-step analysis: (1) which decision-tree branch fired and why, \" +\n \"(2) key surface features of the utterance (trigger keywords, elided subject, modality), \" +\n \"(3) felicity condition assessment.\"\n ),\n\n classification: z.enum([\n \"COMMISSIVE\",\n \"DIRECTIVE\",\n \"ASSERTIVE\",\n \"EXPRESSIVE\",\n \"DECLARATION\",\n \"UNKNOWN\"\n ]).describe(\"Searle's Speech Act category — determined by the decision tree in STEP 1\"),\n\n felicity_scores: z.object({\n clarity: z.number().min(0).max(100).describe(\"Essential Condition: how unambiguous and actionable is the utterance (0–100)\"),\n authority: z.number().min(0).max(100).describe(\"Preparatory Condition: does the speaker's profile support this act (0–100)\"),\n sincerity: z.number().min(0).max(100).describe(\"Sincerity Condition: does the linguistic form imply genuine commitment or need (0–100)\"),\n }),\n\n semantic_entropy: z.number().min(0).max(1).describe(\n \"Constraint density: 0.0 = maximally specific (time + location + tech + quantifiers), 1.0 = completely unconstrained\"\n ),\n\n referential_anchor: z.string().nullable().describe(\n \"Named specific entity the utterance refers to (Donnellan referential), or null for attributive reference\"\n ),\n\n referential_breadth: referentialBreadthSchema.describe(\n \"Extension size of the open candidate class: narrow, moderate, or broad. Distinct from semantic entropy.\"\n ),\n\n missing_selectional_constraints: z.array(missingSelectionalConstraintSchema).describe(\n \"Selectional constraints whose absence leaves the satisfier class too broad.\"\n ),\n\n specificity_warning: z.string().nullable().describe(\n \"Concise user-facing warning when referential_breadth is broad; otherwise null.\"\n ),\n\n flags: z.array(z.string()).describe(\n \"Semantic violation tags: SKILL_MISMATCH (authority<70), WEAK_COMMITMENT (sincerity<70), VAGUE_INTENT (clarity<50), NOISE (ASSERTIVE or EXPRESSIVE), BROAD_ATTRIBUTIVE_REFERENCE (referential_breadth=broad)\"\n ),\n});\n\n// ──────────────────────────────────────────────────────────────\n// 3. TYPE DEFINITIONS\n// ──────────────────────────────────────────────────────────────\n\nexport type ReferentialBreadth = z.infer<typeof referentialBreadthSchema>;\nexport type MissingSelectionalConstraint = z.infer<typeof missingSelectionalConstraintSchema>;\nexport type SemanticVerifierOutput = z.infer<typeof responseFormat>;\n\n// ──────────────────────────────────────────────────────────────\n// 4. CLASS DEFINITION\n// ──────────────────────────────────────────────────────────────\n\nexport class SemanticVerifier {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"intentVerifier\", responseFormat, {\n name: \"semantic_verifier\"\n });\n }\n\n /**\n * Verifies the semantic validity of an intent.\n * @param content - The user's raw utterance.\n * @param context - The User Profile as a JSON string.\n */\n @Timed()\n public async invoke(content: string, context: string) {\n logger.verbose(`[SemanticVerifier.invoke] Verifying: \"${content.substring(0, 30)}...\"`);\n\n const prompt = `\n # User Profile (Context)\n ${context}\n\n # User Utterance (Content)\n \"${content}\"\n \n Verify the Felicity Conditions and Semantic Metrics for this utterance.\n `;\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt)\n ];\n\n try {\n const result = await invokeWithAbortSignal(this.model, messages);\n const output = responseFormat.parse(result);\n\n logger.verbose(`[SemanticVerifier.invoke] Verdict: ${output.classification} Entropy: ${output.semantic_entropy}`);\n return output;\n } catch (error) {\n logger.error(\"[SemanticVerifier] Error during invocation\", { error });\n throw error;\n }\n }\n\n /**\n * Factory method to expose the agent as a LangChain tool.\n */\n public static asTool() {\n return tool(\n async (args: { content: string; context: string }) => {\n const agent = new SemanticVerifier();\n return await agent.invoke(args.content, args.context);\n },\n {\n name: 'semantic_verifier',\n description: 'Verifies the semantic validity and felicity conditions of an intent.',\n schema: z.object({\n content: z.string().describe('The intent content to verify'),\n context: z.string().describe('The user profile context')\n })\n }\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insight.generator.d.ts","sourceRoot":"/","sources":["negotiation/insight.generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"insight.generator.d.ts","sourceRoot":"/","sources":["negotiation/insight.generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2BH,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,qBAAa,4BAA4B;IACvC,OAAO,CAAC,KAAK,CAA0C;;IAMvD;;;;OAIG;IAEG,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAqDhE"}
|
|
@@ -17,7 +17,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
17
17
|
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
18
18
|
import { log } from "../shared/observability/log.js";
|
|
19
19
|
import { Timed } from "../shared/observability/performance.js";
|
|
20
|
-
import {
|
|
20
|
+
import { createResilientModel } from "../shared/agent/model.config.js";
|
|
21
21
|
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
22
22
|
const logger = log.lib.from("NegotiationInsightsGenerator");
|
|
23
23
|
const SYSTEM_PROMPT = `You are an analyst summarizing a user's negotiation history on a discovery network.
|
|
@@ -40,7 +40,7 @@ Guidelines:
|
|
|
40
40
|
*/
|
|
41
41
|
export class NegotiationInsightsGenerator {
|
|
42
42
|
constructor() {
|
|
43
|
-
this.model =
|
|
43
|
+
this.model = createResilientModel("negotiationInsights");
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Produces a narrative summary from a negotiation digest.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insight.generator.js","sourceRoot":"/","sources":["negotiation/insight.generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"insight.generator.js","sourceRoot":"/","sources":["negotiation/insight.generator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Negotiation Insights Generator\n *\n * Produces an aggregated, second-person narrative summarizing a user's\n * negotiation history — topics they're sought for, role patterns,\n * opportunity trends, and interesting signals from recent activity.\n */\n\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\n\nimport { log } from \"../shared/observability/log.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\n\nimport { createResilientModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = log.lib.from(\"NegotiationInsightsGenerator\");\n\nconst SYSTEM_PROMPT = `You are an analyst summarizing a user's negotiation history on a discovery network.\nAgents negotiate on behalf of users to find collaboration opportunities.\n\nGiven a digest of past negotiations, write a concise insight paragraph (2-4 sentences) addressed to the user in second person (\"you\").\n\nGuidelines:\n- Be conversational and insightful, not just statistical.\n- Highlight what others seek the user for, and what the user tends to seek.\n- Mention role patterns: Helper (they assist others), Seeker (they need something), Peer (mutual collaboration).\n- Note opportunity rate trends or interesting shifts if apparent.\n- Reference specific topics or counterparty names when they form patterns.\n- If there are very few negotiations (1-2), keep it brief and forward-looking.\n- Do NOT use bullet points or lists. Write flowing prose.\n- Do NOT start with \"You have\" or \"Your negotiations\". Be more creative.`;\n\n/** Compressed digest of a user's negotiation history for the LLM. */\nexport interface NegotiationDigest {\n totalCount: number;\n opportunityCount: number;\n noOpportunityCount: number;\n inProgressCount: number;\n roleDistribution: Record<string, number>;\n counterparties: string[];\n reasoningExcerpts: string[];\n}\n\n/**\n * Generates an aggregated insight summary from a user's negotiation history.\n * @remarks Lightweight single-call agent; no DB access, no side effects.\n */\nexport class NegotiationInsightsGenerator {\n private model: ReturnType<typeof createResilientModel>;\n\n constructor() {\n this.model = createResilientModel(\"negotiationInsights\");\n }\n\n /**\n * Produces a narrative summary from a negotiation digest.\n * @param digest - Pre-computed statistics and excerpts from the user's negotiations\n * @returns A 2-4 sentence insight paragraph, or null on failure\n */\n @Timed()\n async invoke(digest: NegotiationDigest): Promise<string | null> {\n if (digest.totalCount === 0) return null;\n\n const lines: string[] = [\n `Total negotiations: ${digest.totalCount}`,\n `Opportunities: ${digest.opportunityCount}, No opportunity: ${digest.noOpportunityCount}, In progress: ${digest.inProgressCount}`,\n ];\n\n const roles = Object.entries(digest.roleDistribution);\n if (roles.length > 0) {\n lines.push(`Role distribution: ${roles.map(([r, n]) => `${r}: ${n}`).join(\", \")}`);\n }\n\n if (digest.counterparties.length > 0) {\n lines.push(`Counterparties: ${digest.counterparties.join(\", \")}`);\n }\n\n if (digest.reasoningExcerpts.length > 0) {\n lines.push(`Sample reasoning excerpts:\\n${digest.reasoningExcerpts.map((r) => `- ${r}`).join(\"\\n\")}`);\n }\n\n const userMessage = `Negotiation digest:\\n${lines.join(\"\\n\")}\\n\\nWrite the insight summary:`;\n\n try {\n const response = await invokeWithAbortSignal(this.model, [\n new SystemMessage(SYSTEM_PROMPT),\n new HumanMessage(userMessage),\n ]);\n\n let text: string;\n if (typeof response.content === \"string\") {\n text = response.content.trim();\n } else if (Array.isArray(response.content)) {\n text = (response.content as Array<Record<string, unknown>>)\n .filter((b): b is { type: \"text\"; text?: string } => (b as { type?: string }).type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n .trim();\n } else {\n text = \"\";\n }\n\n if (!text) return null;\n\n logger.verbose(\"[NegotiationInsightsGenerator.invoke] Insights generated\", { length: text.length });\n return text;\n } catch (error) {\n logger.warn(\"[NegotiationInsightsGenerator.invoke] Failed to generate insights\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
2
2
|
import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
|
|
3
3
|
import { SystemNegotiationTurnSchema, FinalNegotiationTurnSchema } from "./negotiation.state.js";
|
|
4
4
|
const SYSTEM_PROMPT = `You are the Index Negotiator, an AI agent acting on behalf of {userName}. You represent their interests in a bilateral negotiation about a potential connection on a discovery network.
|
|
@@ -60,7 +60,7 @@ export class IndexNegotiator {
|
|
|
60
60
|
*/
|
|
61
61
|
async invoke(input) {
|
|
62
62
|
const schema = input.isFinalTurn ? FinalNegotiationTurnSchema : SystemNegotiationTurnSchema;
|
|
63
|
-
const model =
|
|
63
|
+
const model = createStructuredModel("negotiator", schema, { name: "index_negotiator" });
|
|
64
64
|
const userName = input.ownUser.profile.name ?? "your user";
|
|
65
65
|
const role = input.seedAssessment.valencyRole || "peer";
|
|
66
66
|
const networkContext = input.indexContext.prompt || "General discovery";
|