@indexnetwork/protocol 4.5.0-rc.339.1 → 4.5.0
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-streaming.types.d.ts +1 -1
- package/dist/chat/chat-streaming.types.d.ts.map +1 -1
- package/dist/chat/chat-streaming.types.js.map +1 -1
- package/dist/chat/chat.agent.d.ts +1 -1
- package/dist/chat/chat.agent.d.ts.map +1 -1
- package/dist/chat/chat.agent.js.map +1 -1
- package/dist/negotiation/negotiation.graph.d.ts +26 -26
- package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
- package/dist/negotiation/negotiation.graph.js +42 -21
- package/dist/negotiation/negotiation.graph.js.map +1 -1
- package/dist/negotiation/negotiation.screen.d.ts +5 -3
- package/dist/negotiation/negotiation.screen.d.ts.map +1 -1
- package/dist/negotiation/negotiation.screen.js +5 -3
- package/dist/negotiation/negotiation.screen.js.map +1 -1
- package/dist/negotiation/negotiation.state.d.ts +6 -6
- package/dist/negotiation/negotiation.state.js +1 -1
- package/dist/negotiation/negotiation.state.js.map +1 -1
- package/dist/negotiation/negotiation.summarizer.js +1 -1
- package/dist/negotiation/negotiation.summarizer.js.map +1 -1
- package/dist/opportunity/negotiation-context.loader.d.ts +5 -0
- package/dist/opportunity/negotiation-context.loader.d.ts.map +1 -1
- package/dist/opportunity/negotiation-context.loader.js +9 -0
- package/dist/opportunity/negotiation-context.loader.js.map +1 -1
- package/dist/opportunity/question.prompt.d.ts +1 -1
- package/dist/opportunity/question.prompt.d.ts.map +1 -1
- package/dist/opportunity/question.prompt.js +2 -0
- package/dist/opportunity/question.prompt.js.map +1 -1
- package/dist/shared/schemas/discovery-question.schema.d.ts +8 -8
- package/dist/shared/schemas/discovery-question.schema.js +1 -1
- package/dist/shared/schemas/discovery-question.schema.js.map +1 -1
- package/dist/shared/schemas/negotiation-digest.schema.d.ts +3 -3
- package/dist/shared/schemas/negotiation-digest.schema.js +1 -1
- package/dist/shared/schemas/negotiation-digest.schema.js.map +1 -1
- package/dist/shared/schemas/negotiation-state.schema.d.ts +3 -3
- package/dist/shared/schemas/negotiation-state.schema.js +1 -1
- package/dist/shared/schemas/negotiation-state.schema.js.map +1 -1
- package/package.json +1 -1
|
@@ -192,7 +192,7 @@ export declare const NegotiationOutcomeSchema: z.ZodObject<{
|
|
|
192
192
|
}>, "many">;
|
|
193
193
|
reasoning: z.ZodString;
|
|
194
194
|
turnCount: z.ZodNumber;
|
|
195
|
-
reason: z.ZodOptional<z.ZodEnum<["turn_cap", "timeout"]>>;
|
|
195
|
+
reason: z.ZodOptional<z.ZodEnum<["turn_cap", "timeout", "screened_out"]>>;
|
|
196
196
|
}, "strip", z.ZodTypeAny, {
|
|
197
197
|
reasoning: string;
|
|
198
198
|
turnCount: number;
|
|
@@ -201,7 +201,7 @@ export declare const NegotiationOutcomeSchema: z.ZodObject<{
|
|
|
201
201
|
role: "agent" | "patient" | "peer";
|
|
202
202
|
}[];
|
|
203
203
|
hasOpportunity: boolean;
|
|
204
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
204
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
205
205
|
}, {
|
|
206
206
|
reasoning: string;
|
|
207
207
|
turnCount: number;
|
|
@@ -210,7 +210,7 @@ export declare const NegotiationOutcomeSchema: z.ZodObject<{
|
|
|
210
210
|
role: "agent" | "patient" | "peer";
|
|
211
211
|
}[];
|
|
212
212
|
hasOpportunity: boolean;
|
|
213
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
213
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
214
214
|
}>;
|
|
215
215
|
export type NegotiationOutcome = z.infer<typeof NegotiationOutcomeSchema>;
|
|
216
216
|
/** Context each agent receives about its user. */
|
|
@@ -401,7 +401,7 @@ export declare const NegotiationGraphState: import("@langchain/langgraph").Annot
|
|
|
401
401
|
role: "agent" | "patient" | "peer";
|
|
402
402
|
}[];
|
|
403
403
|
hasOpportunity: boolean;
|
|
404
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
404
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
405
405
|
} | null, {
|
|
406
406
|
reasoning: string;
|
|
407
407
|
turnCount: number;
|
|
@@ -410,7 +410,7 @@ export declare const NegotiationGraphState: import("@langchain/langgraph").Annot
|
|
|
410
410
|
role: "agent" | "patient" | "peer";
|
|
411
411
|
}[];
|
|
412
412
|
hasOpportunity: boolean;
|
|
413
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
413
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
414
414
|
} | import("@langchain/langgraph").OverwriteValue<{
|
|
415
415
|
reasoning: string;
|
|
416
416
|
turnCount: number;
|
|
@@ -419,7 +419,7 @@ export declare const NegotiationGraphState: import("@langchain/langgraph").Annot
|
|
|
419
419
|
role: "agent" | "patient" | "peer";
|
|
420
420
|
}[];
|
|
421
421
|
hasOpportunity: boolean;
|
|
422
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
422
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
423
423
|
} | null> | null, unknown>;
|
|
424
424
|
error: import("@langchain/langgraph").BaseChannel<string | null, string | import("@langchain/langgraph").OverwriteValue<string | null> | null, unknown>;
|
|
425
425
|
}>;
|
|
@@ -52,7 +52,7 @@ export const NegotiationOutcomeSchema = z.object({
|
|
|
52
52
|
})),
|
|
53
53
|
reasoning: z.string(),
|
|
54
54
|
turnCount: z.number(),
|
|
55
|
-
reason: z.enum(["turn_cap", "timeout"]).optional(),
|
|
55
|
+
reason: z.enum(["turn_cap", "timeout", "screened_out"]).optional(),
|
|
56
56
|
});
|
|
57
57
|
/** LangGraph state annotation for the negotiation graph. */
|
|
58
58
|
export const NegotiationGraphState = Annotation.Root({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiation.state.js","sourceRoot":"/","sources":["negotiation/negotiation.state.ts"],"names":[],"mappings":"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","sourcesContent":["import { Annotation } from \"@langchain/langgraph\";\nimport { z } from \"zod\";\nimport type { NegotiationUserAnswer } from \"../shared/interfaces/database.interface.js\";\nimport type { ScreenDecisionRecord } from \"./negotiation.screen.js\";\nimport type { NegotiatorMemoryEntry } from \"./negotiation.memory.js\";\nimport { AskUserPayloadSchema, NEGOTIATION_ACTIONS, type NegotiationProtocolVersion } from \"../shared/schemas/negotiation-state.schema.js\";\n\n/**\n * Zod schema for a single negotiation turn (DataPart payload in A2A message).\n * Accepts the full v1+v2 action union — which subset is valid for a given turn\n * is enforced by the seat-scoped schemas in `negotiation.protocol.ts`.\n */\nexport const NegotiationTurnSchema = z.object({\n action: z.enum(NEGOTIATION_ACTIONS),\n assessment: z.object({\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n }),\n }),\n message: z.string().nullable().optional(),\n /** Present when action is `ask_user` (v2, P3.2). */\n askUser: AskUserPayloadSchema.nullable().optional(),\n});\n\n/** Restricted v1 turn schema for the system agent (no question action). */\nexport const SystemNegotiationTurnSchema = z.object({\n action: z.enum([\"propose\", \"accept\", \"reject\", \"counter\"]),\n assessment: z.object({\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n }),\n }),\n message: z.string().nullable().optional(),\n});\n\n/** v1 turn schema for system agent's final allowed turn (must decide). */\nexport const FinalNegotiationTurnSchema = z.object({\n action: z.enum([\"accept\", \"reject\"]),\n assessment: z.object({\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n }),\n }),\n message: z.string().nullable().optional(),\n});\n\nexport type NegotiationTurn = z.infer<typeof NegotiationTurnSchema>;\n\n/** Zod schema for the negotiation outcome (Artifact payload on COMPLETED task). */\nexport const NegotiationOutcomeSchema = z.object({\n hasOpportunity: z.boolean(),\n agreedRoles: z.array(z.object({\n userId: z.string(),\n role: z.enum([\"agent\", \"patient\", \"peer\"]),\n })),\n reasoning: z.string(),\n turnCount: z.number(),\n reason: z.enum([\"turn_cap\", \"timeout\"]).optional(),\n});\n\nexport type NegotiationOutcome = z.infer<typeof NegotiationOutcomeSchema>;\n\n/** Context each agent receives about its user. */\nexport interface UserNegotiationContext {\n id: string;\n intents: Array<{ id: string; title: string; description: string; confidence: number }>;\n profile: { name?: string; bio?: string; location?: string; interests?: string[]; skills?: string[] };\n}\n\n/** Seed assessment from the evaluator pre-filter. */\nexport interface SeedAssessment {\n reasoning: string;\n valencyRole: string;\n actors?: Array<{ userId: string; role: string }>;\n}\n\n/** Typed interface for a negotiation graph's invoke signature. */\nexport interface NegotiationGraphLike {\n invoke(input: {\n sourceUser: UserNegotiationContext;\n candidateUser: UserNegotiationContext;\n indexContext: { networkId: string; prompt: string };\n seedAssessment: Omit<SeedAssessment, \"actors\">;\n discoveryQuery?: string;\n opportunityId?: string;\n maxTurns?: number;\n timeoutMs?: number;\n /**\n * The user who holds the initiating seat for this match (v2 client-advocate\n * protocol). Stamped into task metadata by the init node. When omitted, the\n * init node resolves it: inherit from the prior task for the same\n * opportunity → conversation-scoped tie-break → fall back to sourceUser.id.\n */\n initiatorUserId?: string;\n }): Promise<{\n outcome: NegotiationOutcome | null;\n messages?: NegotiationMessage[];\n conversationId?: string;\n isContinuation?: boolean;\n priorTurnCount?: number;\n }>;\n}\n\n/** A2A message record shape (matches messages table). */\nexport interface NegotiationMessage {\n id: string;\n senderId: string;\n role: \"agent\";\n parts: unknown[];\n createdAt: Date;\n}\n\n/** LangGraph state annotation for the negotiation graph. */\nexport const NegotiationGraphState = Annotation.Root({\n sourceUser: Annotation<UserNegotiationContext>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ id: \"\", intents: [], profile: {} }),\n }),\n candidateUser: Annotation<UserNegotiationContext>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ id: \"\", intents: [], profile: {} }),\n }),\n indexContext: Annotation<{ networkId: string; prompt: string }>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ networkId: \"\", prompt: \"\" }),\n }),\n seedAssessment: Annotation<SeedAssessment>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ reasoning: \"\", valencyRole: \"\" }),\n }),\n\n /**\n * Explicit initiator seat for this match (purely additive metadata — no seat\n * rules attach to it yet). Resolution when unset happens in the init node;\n * the resolved value is written back to state and into task metadata.\n */\n initiatorUserId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /** The explicit search query that triggered discovery (if any). */\n discoveryQuery: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n /**\n * Negotiation protocol version for this session's task. Resolved by the\n * init node: inherited from the prior task on the conversation when one\n * exists (never re-stamped — a v1 conversation stays v1 mid-flight), else\n * stamped from `NEGOTIATION_PROTOCOL_VERSION` for genuinely fresh runs.\n */\n protocolVersion: Annotation<NegotiationProtocolVersion>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"v1\" as const,\n }),\n\n /**\n * Screen-gate decision for this fresh run (P2.1 shadow mode). Written by the\n * screen node; null when the gate is off, on continuations, or before the\n * node runs. Mirrors `tasks.metadata.screenDecision`.\n */\n screenDecision: Annotation<ScreenDecisionRecord | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n\n /**\n * Per-side negotiator-memory cache (P5.3 read path). Populated lazily the\n * first time each side's memory is retrieved (screen node for the client,\n * turn node for the speaker) so a multi-turn session pays for retrieval at\n * most once per side. `undefined` per side = not yet retrieved; `[]` =\n * retrieved and empty (flag off / no rows / retrieval failed).\n */\n memoryBySide: Annotation<Partial<Record<\"source\" | \"candidate\", NegotiatorMemoryEntry[]>>>({\n reducer: (curr, next) => ({ ...curr, ...next }),\n default: () => ({}),\n }),\n\n /** Whether this run is continuing a prior conversation with the same pair. */\n isContinuation: Annotation<boolean>({\n reducer: (curr, next) => next ?? curr,\n default: () => false,\n }),\n opportunityId: Annotation<string>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"\",\n }),\n conversationId: Annotation<string>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"\",\n }),\n taskId: Annotation<string>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"\",\n }),\n messages: Annotation<NegotiationMessage[]>({\n reducer: (curr, next) => [...curr, ...(next || [])],\n default: () => [],\n }),\n turnCount: Annotation<number>({\n reducer: (curr, next) => next ?? curr,\n default: () => 0,\n }),\n maxTurns: Annotation<number | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n /**\n * Park-window budget in milliseconds. Ambient callers pass `AMBIENT_PARK_WINDOW_MS`\n * (5 minutes); orchestrator callers pass a shorter window. This annotation default\n * is a safety net for any caller that omits the field — keep it aligned with\n * `AMBIENT_PARK_WINDOW_MS` in packages/protocol/src/negotiation/negotiation.tools.ts.\n * Inlined rather than imported to avoid a state↔tools cycle.\n */\n timeoutMs: Annotation<number>({\n reducer: (curr, next) => next ?? curr,\n default: () => 5 * 60 * 1000,\n }),\n\n currentSpeaker: Annotation<\"source\" | \"candidate\">({\n reducer: (curr, next) => next ?? curr,\n default: () => \"source\" as const,\n }),\n lastTurn: Annotation<NegotiationTurn | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n\n /**\n * Graph status.\n * - `active` — agents are exchanging turns (default)\n * - `waiting_for_agent` — graph suspended; awaiting external agent response or timeout\n * - `input_required` — graph suspended on an `ask_user` pause; awaiting the\n * negotiator's own client (answer or 24 h window expiry resumes it)\n * - `completed` — negotiation finalized (accept/reject/turn-cap/timeout)\n */\n status: Annotation<'active' | 'waiting_for_agent' | 'input_required' | 'completed'>({\n reducer: (curr, next) => next ?? curr,\n default: () => 'active' as const,\n }),\n\n /** Number of turns present in the conversation before this session started. */\n priorTurnCount: Annotation<number>({\n reducer: (curr, next) => next ?? curr,\n default: () => 0,\n }),\n\n /** User answers collected by the questioner between negotiation sessions. */\n userAnswers: Annotation<NegotiationUserAnswer[]>({\n reducer: (curr, next) => next ?? curr,\n default: () => [],\n }),\n\n outcome: Annotation<NegotiationOutcome | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n error: Annotation<string | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n});\n"]}
|
|
1
|
+
{"version":3,"file":"negotiation.state.js","sourceRoot":"/","sources":["negotiation/negotiation.state.ts"],"names":[],"mappings":"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","sourcesContent":["import { Annotation } from \"@langchain/langgraph\";\nimport { z } from \"zod\";\nimport type { NegotiationUserAnswer } from \"../shared/interfaces/database.interface.js\";\nimport type { ScreenDecisionRecord } from \"./negotiation.screen.js\";\nimport type { NegotiatorMemoryEntry } from \"./negotiation.memory.js\";\nimport { AskUserPayloadSchema, NEGOTIATION_ACTIONS, type NegotiationProtocolVersion } from \"../shared/schemas/negotiation-state.schema.js\";\n\n/**\n * Zod schema for a single negotiation turn (DataPart payload in A2A message).\n * Accepts the full v1+v2 action union — which subset is valid for a given turn\n * is enforced by the seat-scoped schemas in `negotiation.protocol.ts`.\n */\nexport const NegotiationTurnSchema = z.object({\n action: z.enum(NEGOTIATION_ACTIONS),\n assessment: z.object({\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n }),\n }),\n message: z.string().nullable().optional(),\n /** Present when action is `ask_user` (v2, P3.2). */\n askUser: AskUserPayloadSchema.nullable().optional(),\n});\n\n/** Restricted v1 turn schema for the system agent (no question action). */\nexport const SystemNegotiationTurnSchema = z.object({\n action: z.enum([\"propose\", \"accept\", \"reject\", \"counter\"]),\n assessment: z.object({\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n }),\n }),\n message: z.string().nullable().optional(),\n});\n\n/** v1 turn schema for system agent's final allowed turn (must decide). */\nexport const FinalNegotiationTurnSchema = z.object({\n action: z.enum([\"accept\", \"reject\"]),\n assessment: z.object({\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n }),\n }),\n message: z.string().nullable().optional(),\n});\n\nexport type NegotiationTurn = z.infer<typeof NegotiationTurnSchema>;\n\n/** Zod schema for the negotiation outcome (Artifact payload on COMPLETED task). */\nexport const NegotiationOutcomeSchema = z.object({\n hasOpportunity: z.boolean(),\n agreedRoles: z.array(z.object({\n userId: z.string(),\n role: z.enum([\"agent\", \"patient\", \"peer\"]),\n })),\n reasoning: z.string(),\n turnCount: z.number(),\n reason: z.enum([\"turn_cap\", \"timeout\", \"screened_out\"]).optional(),\n});\n\nexport type NegotiationOutcome = z.infer<typeof NegotiationOutcomeSchema>;\n\n/** Context each agent receives about its user. */\nexport interface UserNegotiationContext {\n id: string;\n intents: Array<{ id: string; title: string; description: string; confidence: number }>;\n profile: { name?: string; bio?: string; location?: string; interests?: string[]; skills?: string[] };\n}\n\n/** Seed assessment from the evaluator pre-filter. */\nexport interface SeedAssessment {\n reasoning: string;\n valencyRole: string;\n actors?: Array<{ userId: string; role: string }>;\n}\n\n/** Typed interface for a negotiation graph's invoke signature. */\nexport interface NegotiationGraphLike {\n invoke(input: {\n sourceUser: UserNegotiationContext;\n candidateUser: UserNegotiationContext;\n indexContext: { networkId: string; prompt: string };\n seedAssessment: Omit<SeedAssessment, \"actors\">;\n discoveryQuery?: string;\n opportunityId?: string;\n maxTurns?: number;\n timeoutMs?: number;\n /**\n * The user who holds the initiating seat for this match (v2 client-advocate\n * protocol). Stamped into task metadata by the init node. When omitted, the\n * init node resolves it: inherit from the prior task for the same\n * opportunity → conversation-scoped tie-break → fall back to sourceUser.id.\n */\n initiatorUserId?: string;\n }): Promise<{\n outcome: NegotiationOutcome | null;\n messages?: NegotiationMessage[];\n conversationId?: string;\n isContinuation?: boolean;\n priorTurnCount?: number;\n }>;\n}\n\n/** A2A message record shape (matches messages table). */\nexport interface NegotiationMessage {\n id: string;\n senderId: string;\n role: \"agent\";\n parts: unknown[];\n createdAt: Date;\n}\n\n/** LangGraph state annotation for the negotiation graph. */\nexport const NegotiationGraphState = Annotation.Root({\n sourceUser: Annotation<UserNegotiationContext>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ id: \"\", intents: [], profile: {} }),\n }),\n candidateUser: Annotation<UserNegotiationContext>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ id: \"\", intents: [], profile: {} }),\n }),\n indexContext: Annotation<{ networkId: string; prompt: string }>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ networkId: \"\", prompt: \"\" }),\n }),\n seedAssessment: Annotation<SeedAssessment>({\n reducer: (curr, next) => next ?? curr,\n default: () => ({ reasoning: \"\", valencyRole: \"\" }),\n }),\n\n /**\n * Explicit initiator seat for this match (purely additive metadata — no seat\n * rules attach to it yet). Resolution when unset happens in the init node;\n * the resolved value is written back to state and into task metadata.\n */\n initiatorUserId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /** The explicit search query that triggered discovery (if any). */\n discoveryQuery: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n /**\n * Negotiation protocol version for this session's task. Resolved by the\n * init node: inherited from the prior task on the conversation when one\n * exists (never re-stamped — a v1 conversation stays v1 mid-flight), else\n * stamped from `NEGOTIATION_PROTOCOL_VERSION` for genuinely fresh runs.\n */\n protocolVersion: Annotation<NegotiationProtocolVersion>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"v1\" as const,\n }),\n\n /**\n * Screen-gate decision for this fresh run (P2.1 shadow mode). Written by the\n * screen node; null when the gate is off, on continuations, or before the\n * node runs. Mirrors `tasks.metadata.screenDecision`.\n */\n screenDecision: Annotation<ScreenDecisionRecord | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n\n /**\n * Per-side negotiator-memory cache (P5.3 read path). Populated lazily the\n * first time each side's memory is retrieved (screen node for the client,\n * turn node for the speaker) so a multi-turn session pays for retrieval at\n * most once per side. `undefined` per side = not yet retrieved; `[]` =\n * retrieved and empty (flag off / no rows / retrieval failed).\n */\n memoryBySide: Annotation<Partial<Record<\"source\" | \"candidate\", NegotiatorMemoryEntry[]>>>({\n reducer: (curr, next) => ({ ...curr, ...next }),\n default: () => ({}),\n }),\n\n /** Whether this run is continuing a prior conversation with the same pair. */\n isContinuation: Annotation<boolean>({\n reducer: (curr, next) => next ?? curr,\n default: () => false,\n }),\n opportunityId: Annotation<string>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"\",\n }),\n conversationId: Annotation<string>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"\",\n }),\n taskId: Annotation<string>({\n reducer: (curr, next) => next ?? curr,\n default: () => \"\",\n }),\n messages: Annotation<NegotiationMessage[]>({\n reducer: (curr, next) => [...curr, ...(next || [])],\n default: () => [],\n }),\n turnCount: Annotation<number>({\n reducer: (curr, next) => next ?? curr,\n default: () => 0,\n }),\n maxTurns: Annotation<number | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n /**\n * Park-window budget in milliseconds. Ambient callers pass `AMBIENT_PARK_WINDOW_MS`\n * (5 minutes); orchestrator callers pass a shorter window. This annotation default\n * is a safety net for any caller that omits the field — keep it aligned with\n * `AMBIENT_PARK_WINDOW_MS` in packages/protocol/src/negotiation/negotiation.tools.ts.\n * Inlined rather than imported to avoid a state↔tools cycle.\n */\n timeoutMs: Annotation<number>({\n reducer: (curr, next) => next ?? curr,\n default: () => 5 * 60 * 1000,\n }),\n\n currentSpeaker: Annotation<\"source\" | \"candidate\">({\n reducer: (curr, next) => next ?? curr,\n default: () => \"source\" as const,\n }),\n lastTurn: Annotation<NegotiationTurn | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n\n /**\n * Graph status.\n * - `active` — agents are exchanging turns (default)\n * - `waiting_for_agent` — graph suspended; awaiting external agent response or timeout\n * - `input_required` — graph suspended on an `ask_user` pause; awaiting the\n * negotiator's own client (answer or 24 h window expiry resumes it)\n * - `completed` — negotiation finalized (accept/reject/turn-cap/timeout)\n */\n status: Annotation<'active' | 'waiting_for_agent' | 'input_required' | 'completed'>({\n reducer: (curr, next) => next ?? curr,\n default: () => 'active' as const,\n }),\n\n /** Number of turns present in the conversation before this session started. */\n priorTurnCount: Annotation<number>({\n reducer: (curr, next) => next ?? curr,\n default: () => 0,\n }),\n\n /** User answers collected by the questioner between negotiation sessions. */\n userAnswers: Annotation<NegotiationUserAnswer[]>({\n reducer: (curr, next) => next ?? curr,\n default: () => [],\n }),\n\n outcome: Annotation<NegotiationOutcome | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n error: Annotation<string | null>({\n reducer: (curr, next) => next ?? curr,\n default: () => null,\n }),\n});\n"]}
|
|
@@ -21,7 +21,7 @@ Output requirements (ALL fields — set optional fields to null when not applica
|
|
|
21
21
|
- counterpartyHint: copy the input field verbatim, truncated to ≤120 chars.
|
|
22
22
|
- indexContext: copy the input field verbatim, truncated to ≤120 chars.
|
|
23
23
|
- outcomeRole: "opportunity" when hasOpportunity=true, else "no-opportunity".
|
|
24
|
-
- outcomeReason: when outcomeRole="no-opportunity", set to "turn_cap" / "timeout" if the input's reason matches; else "rejected" (if a turn explicitly rejected) or "stalled". When outcomeRole="opportunity", set to null.
|
|
24
|
+
- outcomeReason: when outcomeRole="no-opportunity", set to "turn_cap" / "timeout" / "screened_out" if the input's reason matches; else "rejected" (if a turn explicitly rejected) or "stalled". When outcomeRole="opportunity", set to null. "screened_out" means the seeker's own agent chose not to reach out before any turn was exchanged — never describe it as the candidate declining or stalling.
|
|
25
25
|
- keyTake: ONE sentence (≤180 chars). Describe the decisive moment, the alignment gap, or the recurring signal — anything a question generator could use to formulate a clarifying question. NOT a generic outcome restatement. Anchor in a concrete detail from the negotiation if possible (a role mismatch, a missing input the candidate flagged, a pivot one party suggested).
|
|
26
26
|
- suggestedRoles: when both parties agreed on roles (the last turn's suggestedRoles), copy them from input. Otherwise set to null.
|
|
27
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiation.summarizer.js","sourceRoot":"/","sources":["negotiation/negotiation.summarizer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"negotiation.summarizer.js","sourceRoot":"/","sources":["negotiation/negotiation.summarizer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * NegotiationSummarizer — pure LLM pass that compresses one DiscoveryNegotiation\n * (potentially several KB of turn reasoning + outcome reasoning) into a\n * DiscoveryNegotiationDigest (≤256 bytes structured). The digest is what the decision-\n * question generator consumes, replacing the raw negotiation blob.\n *\n * Why: a 10-candidate discovery turn used to produce a 60+ KB prompt for the\n * question generator, which stalled upstream Gemini/OpenRouter routes and\n * dropped the connection at ~3 minutes. Per-negotiation summarization caps\n * the question-generator input at a fixed, predictable size.\n */\n\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\n\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { DiscoveryNegotiationDigestSchema, type DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\nimport type { DiscoveryNegotiation } from \"../opportunity/question.prompt.js\";\n\nconst logger = protocolLogger(\"NegotiationSummarizer\");\n\nconst SYSTEM_PROMPT = `You summarize one negotiation between a seeker's agent and a candidate's agent into a structured digest for downstream decision-question generation.\n\nOutput requirements (ALL fields — set optional fields to null when not applicable):\n- counterpartyHint: copy the input field verbatim, truncated to ≤120 chars.\n- indexContext: copy the input field verbatim, truncated to ≤120 chars.\n- outcomeRole: \"opportunity\" when hasOpportunity=true, else \"no-opportunity\".\n- outcomeReason: when outcomeRole=\"no-opportunity\", set to \"turn_cap\" / \"timeout\" / \"screened_out\" if the input's reason matches; else \"rejected\" (if a turn explicitly rejected) or \"stalled\". When outcomeRole=\"opportunity\", set to null. \"screened_out\" means the seeker's own agent chose not to reach out before any turn was exchanged — never describe it as the candidate declining or stalling.\n- keyTake: ONE sentence (≤180 chars). Describe the decisive moment, the alignment gap, or the recurring signal — anything a question generator could use to formulate a clarifying question. NOT a generic outcome restatement. Anchor in a concrete detail from the negotiation if possible (a role mismatch, a missing input the candidate flagged, a pivot one party suggested).\n- suggestedRoles: when both parties agreed on roles (the last turn's suggestedRoles), copy them from input. Otherwise set to null.\n\nDo not include candidate identity, PII, names, or IDs. Reuse only counterpartyHint and indexContext as provided.`;\n\nfunction buildUserPrompt(n: DiscoveryNegotiation): string {\n const turnLines = n.turns\n .map(\n (t, i) =>\n `[${i + 1}] action=${t.action} roles=${t.suggestedRoles.ownUser}↔${t.suggestedRoles.otherUser} reasoning=${t.reasoning}`,\n )\n .join(\"\\n\");\n return [\n `counterpartyHint: ${n.counterpartyHint}`,\n `indexContext: ${n.indexContext}`,\n `turns (${n.turns.length}):`,\n turnLines || \"(no turns)\",\n `outcome.hasOpportunity: ${n.outcome.hasOpportunity}`,\n `outcome.reasoning: ${n.outcome.reasoning}`,\n n.outcome.reason ? `outcome.reason: ${n.outcome.reason}` : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nexport class NegotiationSummarizer {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"negotiationSummarizer\", DiscoveryNegotiationDigestSchema, {\n name: \"negotiation_digest\",\n });\n }\n\n async summarize(\n negotiation: DiscoveryNegotiation,\n options?: { signal?: AbortSignal },\n ): Promise<DiscoveryNegotiationDigest | null> {\n const user = buildUserPrompt(negotiation);\n let raw: unknown;\n try {\n raw = await invokeWithAbortSignal(\n this.model,\n [new SystemMessage(SYSTEM_PROMPT), new HumanMessage(user)],\n options?.signal,\n );\n } catch (err) {\n const aborted = options?.signal?.aborted ?? false;\n if (aborted) {\n logger.info(\"NegotiationSummarizer aborted by signal\", {\n reason: options?.signal?.reason instanceof Error ? options.signal.reason.message : String(options?.signal?.reason ?? \"unknown\"),\n });\n } else {\n logger.warn(\"NegotiationSummarizer LLM call failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n return null;\n }\n\n const parsed = DiscoveryNegotiationDigestSchema.safeParse(raw);\n if (!parsed.success) {\n logger.warn(\"NegotiationSummarizer parse failed\", { error: parsed.error.message });\n return null;\n }\n return parsed.data;\n }\n}\n\n/**\n * Deterministic fallback when the LLM summarizer fails or isn't wired. Produces\n * a minimal but valid digest so the question generator still has *some* signal.\n */\nexport function buildFallbackDigest(n: DiscoveryNegotiation): DiscoveryNegotiationDigest {\n const outcomeRole = n.outcome.hasOpportunity ? \"opportunity\" : \"no-opportunity\";\n const lastTurn = n.turns[n.turns.length - 1];\n const keyTakeRaw =\n n.outcome.reasoning && n.outcome.reasoning.trim().length > 0\n ? n.outcome.reasoning\n : `${n.turns.length} turn(s); ended ${outcomeRole}`;\n return {\n counterpartyHint: n.counterpartyHint.slice(0, 120),\n indexContext: n.indexContext.slice(0, 120),\n outcomeRole,\n outcomeReason:\n outcomeRole === \"no-opportunity\"\n ? ((n.outcome.reason ?? \"stalled\") as \"turn_cap\" | \"timeout\" | \"stalled\" | \"screened_out\")\n : null,\n keyTake: keyTakeRaw.slice(0, 180),\n suggestedRoles:\n lastTurn?.action === \"accept\" && lastTurn.suggestedRoles\n ? lastTurn.suggestedRoles\n : null,\n };\n}\n"]}
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
* For `pending`, `stalled`, `accepted`, and `rejected` opportunities, the
|
|
13
13
|
* full transcript and outcome are included so the prompt can ground its
|
|
14
14
|
* explanation in concrete turn content.
|
|
15
|
+
*
|
|
16
|
+
* Screened-out negotiations (P2.2 — the client's own outreach gate declined
|
|
17
|
+
* before any turn was exchanged) return null: presentation treats them as
|
|
18
|
+
* never-happened, so no card, feed, or digest surface can frame the client's
|
|
19
|
+
* private gate decision as a "counterparty declined" event.
|
|
15
20
|
*/
|
|
16
21
|
import type { NegotiationGraphDatabase, OpportunityStatus } from '../shared/interfaces/database.interface.js';
|
|
17
22
|
import type { NegotiationOutcome, NegotiationTurn } from '../negotiation/negotiation.state.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiation-context.loader.d.ts","sourceRoot":"/","sources":["opportunity/negotiation-context.loader.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"negotiation-context.loader.d.ts","sourceRoot":"/","sources":["opportunity/negotiation-context.loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC9G,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAK/F;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC3C,wBAAwB,EACxB,kCAAkC,GAAG,4BAA4B,GAAG,qBAAqB,CAC1F,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,qDAAqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;CAC3B;AAKD;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,0BAA0B,EAC9B,aAAa,EAAE,MAAM,EACrB,iBAAiB,EAAE,iBAAiB,GACnC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAqCpC"}
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
* For `pending`, `stalled`, `accepted`, and `rejected` opportunities, the
|
|
13
13
|
* full transcript and outcome are included so the prompt can ground its
|
|
14
14
|
* explanation in concrete turn content.
|
|
15
|
+
*
|
|
16
|
+
* Screened-out negotiations (P2.2 — the client's own outreach gate declined
|
|
17
|
+
* before any turn was exchanged) return null: presentation treats them as
|
|
18
|
+
* never-happened, so no card, feed, or digest surface can frame the client's
|
|
19
|
+
* private gate decision as a "counterparty declined" event.
|
|
15
20
|
*/
|
|
16
21
|
import { protocolLogger } from '../shared/observability/protocol.logger.js';
|
|
17
22
|
const logger = protocolLogger('NegotiationContextLoader');
|
|
@@ -45,6 +50,10 @@ export async function loadNegotiationContext(db, opportunityId, opportunityStatu
|
|
|
45
50
|
}
|
|
46
51
|
const artifacts = await db.getArtifactsForTask(task.id);
|
|
47
52
|
const outcome = extractOutcome(artifacts);
|
|
53
|
+
// P2.2: screened_out is the client's private gate decision, not a negotiation.
|
|
54
|
+
if (outcome?.reason === 'screened_out') {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
48
57
|
return {
|
|
49
58
|
status: opportunityStatus,
|
|
50
59
|
conversationId: task.conversationId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiation-context.loader.js","sourceRoot":"/","sources":["opportunity/negotiation-context.loader.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"negotiation-context.loader.js","sourceRoot":"/","sources":["opportunity/negotiation-context.loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Negotiation context loader: given an opportunity, fetches the attached\n * negotiation task's transcript and outcome so the home-card presenter can\n * explain *why* the opportunity surfaced.\n *\n * For `draft`, `latent`, and `expired` opportunities, no negotiation has\n * happened (or no longer matters) so the loader returns null.\n *\n * For `negotiating` opportunities, only `turnCount` / `turnCap` are returned\n * — the presenter renders a templated chip without invoking the LLM.\n *\n * For `pending`, `stalled`, `accepted`, and `rejected` opportunities, the\n * full transcript and outcome are included so the prompt can ground its\n * explanation in concrete turn content.\n *\n * Screened-out negotiations (P2.2 — the client's own outreach gate declined\n * before any turn was exchanged) return null: presentation treats them as\n * never-happened, so no card, feed, or digest surface can frame the client's\n * private gate decision as a \"counterparty declined\" event.\n */\n\nimport type { NegotiationGraphDatabase, OpportunityStatus } from '../shared/interfaces/database.interface.js';\nimport type { NegotiationOutcome, NegotiationTurn } from '../negotiation/negotiation.state.js';\nimport { protocolLogger } from '../shared/observability/protocol.logger.js';\n\nconst logger = protocolLogger('NegotiationContextLoader');\n\n/**\n * Narrow slice of {@link NegotiationGraphDatabase} required by the loader. Kept\n * minimal so call sites can opt into a smaller surface.\n */\nexport type NegotiationContextDatabase = Pick<\n NegotiationGraphDatabase,\n 'getNegotiationTaskForOpportunity' | 'getMessagesForConversation' | 'getArtifactsForTask'\n>;\n\n/**\n * Snapshot of a negotiation surfaced to the presenter. `turns` and `outcome`\n * are only populated for post-negotiation statuses (pending/stalled/\n * accepted/rejected); `negotiating` gets only the counters.\n */\nexport interface NegotiationContext {\n status: OpportunityStatus;\n /**\n * Conversation/task id of the A2A negotiation that produced this opportunity.\n * Lets callers deep-link to the negotiation trace (e.g. `/chat/:conversationId`).\n * Present whenever a negotiation task exists (i.e. context is non-null).\n */\n conversationId: string;\n turnCount: number;\n /** Max turns allowed for this negotiation (0 = unlimited). */\n turnCap: number;\n /** Only present when status is not `negotiating`. */\n outcome?: NegotiationOutcome;\n /** Only present when status is not `negotiating`. */\n turns?: NegotiationTurn[];\n}\n\nconst STATUSES_WITH_NO_NEGOTIATION: ReadonlyArray<OpportunityStatus> = ['draft', 'latent', 'expired'];\nconst NEGOTIATION_OUTCOME_ARTIFACT_NAME = 'negotiation-outcome';\n\n/**\n * Loads the negotiation context for an opportunity.\n *\n * @param db - Narrow slice of NegotiationGraphDatabase.\n * @param opportunityId - Opportunity to load negotiation context for.\n * @param opportunityStatus - Current opportunity status. Used to gate loading\n * and to decide which fields to populate.\n * @returns NegotiationContext, or null when no meaningful negotiation exists\n * (draft/latent/expired) or when the task lookup fails.\n */\nexport async function loadNegotiationContext(\n db: NegotiationContextDatabase,\n opportunityId: string,\n opportunityStatus: OpportunityStatus,\n): Promise<NegotiationContext | null> {\n if (STATUSES_WITH_NO_NEGOTIATION.includes(opportunityStatus)) {\n return null;\n }\n\n const task = await db.getNegotiationTaskForOpportunity(opportunityId);\n if (!task) {\n logger.verbose('No negotiation task found for opportunity', { opportunityId, opportunityStatus });\n return null;\n }\n\n const turnCap = readNumber(task.metadata, 'maxTurns') ?? 0;\n\n const messages = await db.getMessagesForConversation(task.conversationId);\n const turns = extractTurns(messages);\n const turnCount = turns.length;\n\n if (opportunityStatus === 'negotiating') {\n return { status: opportunityStatus, conversationId: task.conversationId, turnCount, turnCap };\n }\n\n const artifacts = await db.getArtifactsForTask(task.id);\n const outcome = extractOutcome(artifacts);\n\n // P2.2: screened_out is the client's private gate decision, not a negotiation.\n if (outcome?.reason === 'screened_out') {\n return null;\n }\n\n return {\n status: opportunityStatus,\n conversationId: task.conversationId,\n turnCount,\n turnCap,\n ...(outcome ? { outcome } : {}),\n turns,\n };\n}\n\nfunction readNumber(metadata: Record<string, unknown> | null, key: string): number | undefined {\n if (!metadata) return undefined;\n const value = metadata[key];\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction extractTurns(messages: Array<{ parts: unknown[] }>): NegotiationTurn[] {\n const turns: NegotiationTurn[] = [];\n for (const message of messages) {\n const dataPart = (message.parts as Array<{ kind?: string; data?: unknown }>).find((p) => p.kind === 'data');\n if (dataPart?.data) {\n turns.push(dataPart.data as NegotiationTurn);\n }\n }\n return turns;\n}\n\nfunction extractOutcome(\n artifacts: Array<{ name: string | null; parts: unknown[] }>,\n): NegotiationOutcome | undefined {\n const outcomeArtifact = artifacts.find((a) => a.name === NEGOTIATION_OUTCOME_ARTIFACT_NAME);\n if (!outcomeArtifact) return undefined;\n\n const dataPart = (outcomeArtifact.parts as Array<{ kind?: string; data?: unknown }>).find(\n (p) => p.kind === 'data',\n );\n return dataPart?.data as NegotiationOutcome | undefined;\n}\n"]}
|
|
@@ -30,7 +30,7 @@ export interface DiscoveryOutcome {
|
|
|
30
30
|
role: NegotiationRole;
|
|
31
31
|
}>;
|
|
32
32
|
/** Why the negotiation stopped, when not by an explicit accept/reject. */
|
|
33
|
-
reason?: "turn_cap" | "timeout";
|
|
33
|
+
reason?: "turn_cap" | "timeout" | "screened_out";
|
|
34
34
|
}
|
|
35
35
|
/** One negotiation that ran during this discovery turn. */
|
|
36
36
|
export interface DiscoveryNegotiation {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.prompt.d.ts","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAEjG,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3D,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;IACpH,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;CAC1E;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"question.prompt.d.ts","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAEjG,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3D,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;IACpH,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;CAC1E;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,cAAc,CAAC;CAClD;AAED,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,2FAA2F;IAC3F,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,EAAE,0BAA0B,EAAE,CAAC;IACjD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,eAAO,MAAM,aAAa,yyLA0C0J,CAAC;AAErL;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAmCzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.prompt.js","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Prompt module for the decision-question generator: the system prompt\n * constant, the `DiscoveryQuestionInput` contract, and a pure string-building\n * `buildQuestionPrompt` that assembles the user message.\n *\n * Pure: no I/O, no LLM call. The generator class (`question.generator.ts`)\n * orchestrates this module + an LLM client.\n */\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\n\n/** Roles used in the existing negotiation framework. */\nexport type NegotiationRole = \"agent\" | \"patient\" | \"peer\";\n\n/** One turn within a negotiation. */\nexport interface DiscoveryTurn {\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\" | \"outreach\" | \"withdraw\" | \"decline\" | \"ask_user\";\n reasoning: string;\n suggestedRoles: { ownUser: NegotiationRole; otherUser: NegotiationRole };\n}\n\n/** Outcome of a negotiation. */\nexport interface DiscoveryOutcome {\n hasOpportunity: boolean;\n reasoning: string;\n agreedRoles?: Array<{ userId: string; role: NegotiationRole }>;\n /** Why the negotiation stopped, when not by an explicit accept/reject. */\n reason?: \"turn_cap\" | \"timeout\";\n}\n\n/** One negotiation that ran during this discovery turn. */\nexport interface DiscoveryNegotiation {\n /** Opaque counterparty identifier; NEVER surfaced to the user (kept out of the prompt). */\n counterpartyId: string;\n /** Abstract profile slice for the LLM (e.g. \"AI infra founder, Berlin\"). */\n counterpartyHint: string;\n /** The network/community prompt this negotiation ran under. */\n indexContext: string;\n /** Last 6 turns are retained; earlier ones are dropped. */\n turns: DiscoveryTurn[];\n outcome: DiscoveryOutcome;\n /**\n * Optional pre-negotiation evaluator score (0..1). When more than\n * `MAX_NEGOTIATIONS` candidates exist, this is used as a tie-breaker after\n * `turns.length` to decide which to keep.\n */\n seedAssessmentScore?: number;\n}\n\n/** Aggregate counters across all negotiations in this discovery turn. */\nexport interface DiscoverySummary {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n /** Subset of `noOpportunityCount` where the negotiation hit a turn-cap or timeout. */\n timeoutCount: number;\n /** Map of role → count across all outcomes' `agreedRoles`. */\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n}\n\n/**\n * The seeker's profile slice the generator used to see. Retained as an exported\n * type for backward compatibility; the question prompt now consumes the global\n * `userContext` paragraph instead of these discrete fields.\n */\nexport interface DiscoverySourceProfile {\n name?: string;\n bio?: string;\n location?: string;\n skills?: string[];\n interests?: string[];\n}\n\n/** Full input to the question generator. */\nexport interface DiscoveryQuestionInput {\n /** The seeker's original natural-language query / signal that triggered discovery. */\n query: string;\n /** The seeker's global user_context paragraph (profile-replacing identity text). */\n userContext: string;\n /**\n * Compact per-negotiation digests from THIS discovery turn. Each digest is a\n * fixed-size structured summary (counterparty hint, index, outcome role,\n * keyTake) — pre-summarized so this prompt stays small regardless of how\n * many candidates were negotiated. Raw negotiations are NOT passed here.\n */\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n /** Distilled chat-session digest, when a session is in scope. */\n chatContext?: ChatContextDigest;\n /** ISO timestamp used as the \"now\" anchor in the prompt. */\n now: string;\n}\n\n/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */\nexport const SYSTEM_PROMPT = `You help write user-facing follow-up questions after Index has reviewed potential connections for a human. Your job: surface the minimum set of structured decision questions the human must answer to make the next discovery turn sharper, or improve their outlook on the intent.\n\nYou may pick from five strategies. Choose contextually; mix when multiple questions genuinely complement.\n- refine_intent: ask the user to sharpen or pivot their original signal.\n- surface_missing_detail: ask for one concrete missing input (stage, location, timing, scope, …).\n- open_adjacent_thread: offer a pivot suggested by recurring connection signals.\n- reflective_summary: mirror what the connection review revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from the connection review and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. Index cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which people surface next.\n3. The same fact is NOT already in chatContext.statedFacts, NOT already asked in chatContext.openQuestions, and NOT already shared in chatContext.surfacedFindings.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the original query, discovery pattern, connection pattern, or concrete learned fact in the question text itself. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about. For example, prefer \"For your AI crypto decentralized deep-tech search, which area is most critical right now?\" over \"Which area is most critical right now?\"\n\nReferential closure. The prompt must resolve entirely on its own, with no dangling references. The reader sees ONLY the question text — never the people you reviewed, the events on their calendar, or this conversation. Do not use demonstratives or definite anaphora that point at things the reader cannot see: \"these builders\", \"those founders\", \"these researchers\", \"these conversations\", \"this lunch\", \"the speaker\". If you reference a person, name them. If you reference a group, restate the concrete shared attribute inside the question itself (\"founders working on decentralized identity\"), never \"these founders\". Never imply a list, set, or prior exchange the reader is not currently looking at.\n- Bad: \"What kind of collaboration are you looking for with these builders?\"\n- Good: \"You're meeting people building agent infrastructure — what kind of collaboration are you looking for?\"\n\nNo process narration. Never describe Index's own activity or internal state. Forbidden: \"the previous negotiation\", \"the negotiation stalled\", \"opportunities found so far\", \"my search\", \"the counterparty\", \"candidates reviewed\", restating why a match did or did not happen, or quoting words a counterparty did or did not use. Ask about the user's goal or intent directly, never about the matching pipeline.\n- Bad: \"All opportunities found so far are related to 'Edge Esmeralda'. Would you like to broaden the search?\"\n- Good: \"Do you want to focus on people at Edge Esmeralda, or also connect beyond it?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first (e.g. one surface_emergent_knowledge + one refine_intent). Add a third only when there are ≥3 substantive people reviewed and three distinct strategies each unblock a real decision. Two questions of the same strategy are acceptable only if their decision domains differ (different titles). Avoid stacking three pulls (info-from-user); balance with pushes (info-to-user via reflective_summary / surface_emergent_knowledge).\n\nOrdering. Questions whose answer unblocks the most connection reviews come first; then highest-impact; then ambiguity-clarifying. Reviews that needed more detail or ran out of time signal under-specification — prioritize.\n\nUser-facing language. Every title, prompt, option label, and option description is shown directly to the user. Never mention raw protocol mechanics or internal labels such as \"agent\", \"patient\", \"peer\", \"suggestedRoles\", \"role distribution\", \"counterparty\", \"negotiation\", \"turn_cap\", \"timeout\", or \"candidate\". Use natural language instead: people, matches, connections, mutual collaboration, someone who can help, or someone seeking help.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option, not its definition. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically. For surface_emergent_knowledge questions, anchor the prompt in the concrete cited fact (\"Multiple people flagged that…\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I look again?\").\n- Don't ask about hypothetical edge cases that didn't occur.\n- Don't ask about specific person identities; treat the provided person summary as the only allowed reference.\n- Don't repeat anything in chatContext.openQuestions.\n- Don't re-surface anything in chatContext.surfacedFindings.\n- Don't ask for facts in chatContext.statedFacts.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the five values). If nothing is worth asking, return \"questions\": [].`;\n\n/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Pure builder: assembles the user message string from a structured input.\n */\nexport function buildQuestionPrompt(input: DiscoveryQuestionInput): string {\n const profileSummary = input.userContext?.trim() || \"(no profile data)\";\n const connectionReviewBlocks = renderConnectionReviewDigests(input.negotiationDigests);\n const chatContextBlock = input.chatContext\n ? renderDigest(input.chatContext)\n : \"(no chat context available)\";\n const engagementPattern = renderEngagementPattern(input.summary.roleDistribution);\n\n return [\n \"## Seeker's query\",\n input.query,\n \"\",\n \"## Seeker profile\",\n profileSummary,\n \"\",\n \"## This discovery turn\",\n `- ${input.summary.totalCandidates} people reviewed`,\n `- ${input.summary.opportunitiesFound} promising connections found`,\n `- ${input.summary.noOpportunityCount} reviews did not find enough fit (${input.summary.timeoutCount} needed more detail or time)`,\n `- Engagement pattern: ${engagementPattern}`,\n \"\",\n \"## Connection review evidence (compact digests)\",\n connectionReviewBlocks,\n \"\",\n \"## What the user has already said in this session\",\n chatContextBlock,\n \"\",\n \"## Now\",\n input.now,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of decision questions the seeker must answer to make\",\n \"the next discovery turn sharper. Apply every rule from your system prompt\",\n \"before outputting. Return an empty `questions` array if nothing is worth asking.\",\n ].join(\"\\n\");\n}\n\n/**\n * Render the negotiation-digest collection into compact one-liners. Each digest\n * is fixed-size (≤ ~400 chars after rendering), so the rendered block scales\n * linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.\n */\nfunction renderConnectionReviewDigests(digests: DiscoveryNegotiationDigest[]): string {\n if (digests.length === 0) return \"(no connection reviews)\";\n return digests\n .map((d) => {\n const relationshipSignal = d.suggestedRoles\n ? [` Relationship signal: ${renderRelationshipSignal(d.suggestedRoles)}`]\n : [];\n return [\n `- Person: ${d.counterpartyHint}`,\n ` Community context: ${d.indexContext}`,\n ` Outcome: ${renderOutcome(d)}`,\n ...relationshipSignal,\n ` Take: ${d.keyTake}`,\n ].join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\nfunction renderEngagementPattern(dist: Partial<Record<NegotiationRole, number>>): string {\n const parts: string[] = [];\n if ((dist.peer ?? 0) > 0) {\n parts.push(`${dist.peer} mutual collaboration${dist.peer === 1 ? \"\" : \"s\"}`);\n }\n if ((dist.agent ?? 0) > 0) {\n parts.push(`${dist.agent} where the user could offer help or expertise`);\n }\n if ((dist.patient ?? 0) > 0) {\n parts.push(`${dist.patient} where the user seemed to be seeking help or expertise`);\n }\n return parts.length > 0 ? parts.join(\", \") : \"(no engagement pattern available)\";\n}\n\nfunction renderOutcome(digest: DiscoveryNegotiationDigest): string {\n const outcome = digest.outcomeRole === \"opportunity\"\n ? \"promising connection\"\n : \"not enough fit\";\n const reason = renderOutcomeReason(digest.outcomeReason);\n return reason ? `${outcome} (${reason})` : outcome;\n}\n\nfunction renderOutcomeReason(reason: DiscoveryNegotiationDigest[\"outcomeReason\"]): string {\n switch (reason) {\n case \"turn_cap\":\n return \"needed more detail\";\n case \"timeout\":\n return \"ran out of time\";\n case \"rejected\":\n return \"not enough mutual interest\";\n case \"stalled\":\n return \"stalled\";\n case null:\n return \"\";\n }\n}\n\nfunction renderRelationshipSignal(roles: NonNullable<DiscoveryNegotiationDigest[\"suggestedRoles\"]>): string {\n if (roles.ownUser === \"peer\" && roles.otherUser === \"peer\") return \"mutual collaboration\";\n if (roles.ownUser === \"agent\" && roles.otherUser === \"patient\") {\n return \"the user could offer help or expertise\";\n }\n if (roles.ownUser === \"patient\" && roles.otherUser === \"agent\") {\n return \"the user seemed to be seeking help or expertise\";\n }\n if (roles.ownUser === \"agent\") return \"the user could offer help or expertise\";\n if (roles.ownUser === \"patient\") return \"the user seemed to be seeking help or expertise\";\n return \"collaboration fit\";\n}\n\nfunction renderDigest(d: ChatContextDigest): string {\n const lines: string[] = [];\n if (d.statedFacts.length > 0) {\n lines.push(\"Stated facts:\");\n for (const f of d.statedFacts) lines.push(` - ${f}`);\n }\n if (d.openQuestions.length > 0) {\n lines.push(\"Open questions (assistant already asked):\");\n for (const q of d.openQuestions) lines.push(` - ${q}`);\n }\n if (d.rejectionReasons.length > 0) {\n lines.push(\"User pushback / rejections:\");\n for (const r of d.rejectionReasons) lines.push(` - ${r}`);\n }\n if (d.surfacedFindings.length > 0) {\n lines.push(\"Findings already surfaced to user:\");\n for (const f of d.surfacedFindings) lines.push(` - ${f}`);\n }\n return lines.length > 0 ? lines.join(\"\\n\") : \"(digest is empty)\";\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"question.prompt.js","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Prompt module for the decision-question generator: the system prompt\n * constant, the `DiscoveryQuestionInput` contract, and a pure string-building\n * `buildQuestionPrompt` that assembles the user message.\n *\n * Pure: no I/O, no LLM call. The generator class (`question.generator.ts`)\n * orchestrates this module + an LLM client.\n */\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\n\n/** Roles used in the existing negotiation framework. */\nexport type NegotiationRole = \"agent\" | \"patient\" | \"peer\";\n\n/** One turn within a negotiation. */\nexport interface DiscoveryTurn {\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\" | \"outreach\" | \"withdraw\" | \"decline\" | \"ask_user\";\n reasoning: string;\n suggestedRoles: { ownUser: NegotiationRole; otherUser: NegotiationRole };\n}\n\n/** Outcome of a negotiation. */\nexport interface DiscoveryOutcome {\n hasOpportunity: boolean;\n reasoning: string;\n agreedRoles?: Array<{ userId: string; role: NegotiationRole }>;\n /** Why the negotiation stopped, when not by an explicit accept/reject. */\n reason?: \"turn_cap\" | \"timeout\" | \"screened_out\";\n}\n\n/** One negotiation that ran during this discovery turn. */\nexport interface DiscoveryNegotiation {\n /** Opaque counterparty identifier; NEVER surfaced to the user (kept out of the prompt). */\n counterpartyId: string;\n /** Abstract profile slice for the LLM (e.g. \"AI infra founder, Berlin\"). */\n counterpartyHint: string;\n /** The network/community prompt this negotiation ran under. */\n indexContext: string;\n /** Last 6 turns are retained; earlier ones are dropped. */\n turns: DiscoveryTurn[];\n outcome: DiscoveryOutcome;\n /**\n * Optional pre-negotiation evaluator score (0..1). When more than\n * `MAX_NEGOTIATIONS` candidates exist, this is used as a tie-breaker after\n * `turns.length` to decide which to keep.\n */\n seedAssessmentScore?: number;\n}\n\n/** Aggregate counters across all negotiations in this discovery turn. */\nexport interface DiscoverySummary {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n /** Subset of `noOpportunityCount` where the negotiation hit a turn-cap or timeout. */\n timeoutCount: number;\n /** Map of role → count across all outcomes' `agreedRoles`. */\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n}\n\n/**\n * The seeker's profile slice the generator used to see. Retained as an exported\n * type for backward compatibility; the question prompt now consumes the global\n * `userContext` paragraph instead of these discrete fields.\n */\nexport interface DiscoverySourceProfile {\n name?: string;\n bio?: string;\n location?: string;\n skills?: string[];\n interests?: string[];\n}\n\n/** Full input to the question generator. */\nexport interface DiscoveryQuestionInput {\n /** The seeker's original natural-language query / signal that triggered discovery. */\n query: string;\n /** The seeker's global user_context paragraph (profile-replacing identity text). */\n userContext: string;\n /**\n * Compact per-negotiation digests from THIS discovery turn. Each digest is a\n * fixed-size structured summary (counterparty hint, index, outcome role,\n * keyTake) — pre-summarized so this prompt stays small regardless of how\n * many candidates were negotiated. Raw negotiations are NOT passed here.\n */\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n /** Distilled chat-session digest, when a session is in scope. */\n chatContext?: ChatContextDigest;\n /** ISO timestamp used as the \"now\" anchor in the prompt. */\n now: string;\n}\n\n/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */\nexport const SYSTEM_PROMPT = `You help write user-facing follow-up questions after Index has reviewed potential connections for a human. Your job: surface the minimum set of structured decision questions the human must answer to make the next discovery turn sharper, or improve their outlook on the intent.\n\nYou may pick from five strategies. Choose contextually; mix when multiple questions genuinely complement.\n- refine_intent: ask the user to sharpen or pivot their original signal.\n- surface_missing_detail: ask for one concrete missing input (stage, location, timing, scope, …).\n- open_adjacent_thread: offer a pivot suggested by recurring connection signals.\n- reflective_summary: mirror what the connection review revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from the connection review and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. Index cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which people surface next.\n3. The same fact is NOT already in chatContext.statedFacts, NOT already asked in chatContext.openQuestions, and NOT already shared in chatContext.surfacedFindings.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the original query, discovery pattern, connection pattern, or concrete learned fact in the question text itself. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about. For example, prefer \"For your AI crypto decentralized deep-tech search, which area is most critical right now?\" over \"Which area is most critical right now?\"\n\nReferential closure. The prompt must resolve entirely on its own, with no dangling references. The reader sees ONLY the question text — never the people you reviewed, the events on their calendar, or this conversation. Do not use demonstratives or definite anaphora that point at things the reader cannot see: \"these builders\", \"those founders\", \"these researchers\", \"these conversations\", \"this lunch\", \"the speaker\". If you reference a person, name them. If you reference a group, restate the concrete shared attribute inside the question itself (\"founders working on decentralized identity\"), never \"these founders\". Never imply a list, set, or prior exchange the reader is not currently looking at.\n- Bad: \"What kind of collaboration are you looking for with these builders?\"\n- Good: \"You're meeting people building agent infrastructure — what kind of collaboration are you looking for?\"\n\nNo process narration. Never describe Index's own activity or internal state. Forbidden: \"the previous negotiation\", \"the negotiation stalled\", \"opportunities found so far\", \"my search\", \"the counterparty\", \"candidates reviewed\", restating why a match did or did not happen, or quoting words a counterparty did or did not use. Ask about the user's goal or intent directly, never about the matching pipeline.\n- Bad: \"All opportunities found so far are related to 'Edge Esmeralda'. Would you like to broaden the search?\"\n- Good: \"Do you want to focus on people at Edge Esmeralda, or also connect beyond it?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first (e.g. one surface_emergent_knowledge + one refine_intent). Add a third only when there are ≥3 substantive people reviewed and three distinct strategies each unblock a real decision. Two questions of the same strategy are acceptable only if their decision domains differ (different titles). Avoid stacking three pulls (info-from-user); balance with pushes (info-to-user via reflective_summary / surface_emergent_knowledge).\n\nOrdering. Questions whose answer unblocks the most connection reviews come first; then highest-impact; then ambiguity-clarifying. Reviews that needed more detail or ran out of time signal under-specification — prioritize.\n\nUser-facing language. Every title, prompt, option label, and option description is shown directly to the user. Never mention raw protocol mechanics or internal labels such as \"agent\", \"patient\", \"peer\", \"suggestedRoles\", \"role distribution\", \"counterparty\", \"negotiation\", \"turn_cap\", \"timeout\", or \"candidate\". Use natural language instead: people, matches, connections, mutual collaboration, someone who can help, or someone seeking help.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option, not its definition. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically. For surface_emergent_knowledge questions, anchor the prompt in the concrete cited fact (\"Multiple people flagged that…\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I look again?\").\n- Don't ask about hypothetical edge cases that didn't occur.\n- Don't ask about specific person identities; treat the provided person summary as the only allowed reference.\n- Don't repeat anything in chatContext.openQuestions.\n- Don't re-surface anything in chatContext.surfacedFindings.\n- Don't ask for facts in chatContext.statedFacts.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the five values). If nothing is worth asking, return \"questions\": [].`;\n\n/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Pure builder: assembles the user message string from a structured input.\n */\nexport function buildQuestionPrompt(input: DiscoveryQuestionInput): string {\n const profileSummary = input.userContext?.trim() || \"(no profile data)\";\n const connectionReviewBlocks = renderConnectionReviewDigests(input.negotiationDigests);\n const chatContextBlock = input.chatContext\n ? renderDigest(input.chatContext)\n : \"(no chat context available)\";\n const engagementPattern = renderEngagementPattern(input.summary.roleDistribution);\n\n return [\n \"## Seeker's query\",\n input.query,\n \"\",\n \"## Seeker profile\",\n profileSummary,\n \"\",\n \"## This discovery turn\",\n `- ${input.summary.totalCandidates} people reviewed`,\n `- ${input.summary.opportunitiesFound} promising connections found`,\n `- ${input.summary.noOpportunityCount} reviews did not find enough fit (${input.summary.timeoutCount} needed more detail or time)`,\n `- Engagement pattern: ${engagementPattern}`,\n \"\",\n \"## Connection review evidence (compact digests)\",\n connectionReviewBlocks,\n \"\",\n \"## What the user has already said in this session\",\n chatContextBlock,\n \"\",\n \"## Now\",\n input.now,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of decision questions the seeker must answer to make\",\n \"the next discovery turn sharper. Apply every rule from your system prompt\",\n \"before outputting. Return an empty `questions` array if nothing is worth asking.\",\n ].join(\"\\n\");\n}\n\n/**\n * Render the negotiation-digest collection into compact one-liners. Each digest\n * is fixed-size (≤ ~400 chars after rendering), so the rendered block scales\n * linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.\n */\nfunction renderConnectionReviewDigests(digests: DiscoveryNegotiationDigest[]): string {\n if (digests.length === 0) return \"(no connection reviews)\";\n return digests\n .map((d) => {\n const relationshipSignal = d.suggestedRoles\n ? [` Relationship signal: ${renderRelationshipSignal(d.suggestedRoles)}`]\n : [];\n return [\n `- Person: ${d.counterpartyHint}`,\n ` Community context: ${d.indexContext}`,\n ` Outcome: ${renderOutcome(d)}`,\n ...relationshipSignal,\n ` Take: ${d.keyTake}`,\n ].join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\nfunction renderEngagementPattern(dist: Partial<Record<NegotiationRole, number>>): string {\n const parts: string[] = [];\n if ((dist.peer ?? 0) > 0) {\n parts.push(`${dist.peer} mutual collaboration${dist.peer === 1 ? \"\" : \"s\"}`);\n }\n if ((dist.agent ?? 0) > 0) {\n parts.push(`${dist.agent} where the user could offer help or expertise`);\n }\n if ((dist.patient ?? 0) > 0) {\n parts.push(`${dist.patient} where the user seemed to be seeking help or expertise`);\n }\n return parts.length > 0 ? parts.join(\", \") : \"(no engagement pattern available)\";\n}\n\nfunction renderOutcome(digest: DiscoveryNegotiationDigest): string {\n const outcome = digest.outcomeRole === \"opportunity\"\n ? \"promising connection\"\n : \"not enough fit\";\n const reason = renderOutcomeReason(digest.outcomeReason);\n return reason ? `${outcome} (${reason})` : outcome;\n}\n\nfunction renderOutcomeReason(reason: DiscoveryNegotiationDigest[\"outcomeReason\"]): string {\n switch (reason) {\n case \"turn_cap\":\n return \"needed more detail\";\n case \"timeout\":\n return \"ran out of time\";\n case \"rejected\":\n return \"not enough mutual interest\";\n case \"stalled\":\n return \"stalled\";\n case \"screened_out\":\n return \"didn't look like a strong enough fit to pursue\";\n case null:\n return \"\";\n }\n}\n\nfunction renderRelationshipSignal(roles: NonNullable<DiscoveryNegotiationDigest[\"suggestedRoles\"]>): string {\n if (roles.ownUser === \"peer\" && roles.otherUser === \"peer\") return \"mutual collaboration\";\n if (roles.ownUser === \"agent\" && roles.otherUser === \"patient\") {\n return \"the user could offer help or expertise\";\n }\n if (roles.ownUser === \"patient\" && roles.otherUser === \"agent\") {\n return \"the user seemed to be seeking help or expertise\";\n }\n if (roles.ownUser === \"agent\") return \"the user could offer help or expertise\";\n if (roles.ownUser === \"patient\") return \"the user seemed to be seeking help or expertise\";\n return \"collaboration fit\";\n}\n\nfunction renderDigest(d: ChatContextDigest): string {\n const lines: string[] = [];\n if (d.statedFacts.length > 0) {\n lines.push(\"Stated facts:\");\n for (const f of d.statedFacts) lines.push(` - ${f}`);\n }\n if (d.openQuestions.length > 0) {\n lines.push(\"Open questions (assistant already asked):\");\n for (const q of d.openQuestions) lines.push(` - ${q}`);\n }\n if (d.rejectionReasons.length > 0) {\n lines.push(\"User pushback / rejections:\");\n for (const r of d.rejectionReasons) lines.push(` - ${r}`);\n }\n if (d.surfacedFindings.length > 0) {\n lines.push(\"Findings already surfaced to user:\");\n for (const f of d.surfacedFindings) lines.push(` - ${f}`);\n }\n return lines.length > 0 ? lines.join(\"\\n\") : \"(digest is empty)\";\n}\n\n"]}
|
|
@@ -51,11 +51,11 @@ export declare const DiscoveryOutcomeSchema: z.ZodObject<{
|
|
|
51
51
|
userId: string;
|
|
52
52
|
role: "agent" | "patient" | "peer";
|
|
53
53
|
}>, "many">>;
|
|
54
|
-
reason: z.ZodOptional<z.ZodEnum<["turn_cap", "timeout"]>>;
|
|
54
|
+
reason: z.ZodOptional<z.ZodEnum<["turn_cap", "timeout", "screened_out"]>>;
|
|
55
55
|
}, "strip", z.ZodTypeAny, {
|
|
56
56
|
reasoning: string;
|
|
57
57
|
hasOpportunity: boolean;
|
|
58
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
58
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
59
59
|
agreedRoles?: {
|
|
60
60
|
userId: string;
|
|
61
61
|
role: "agent" | "patient" | "peer";
|
|
@@ -63,7 +63,7 @@ export declare const DiscoveryOutcomeSchema: z.ZodObject<{
|
|
|
63
63
|
}, {
|
|
64
64
|
reasoning: string;
|
|
65
65
|
hasOpportunity: boolean;
|
|
66
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
66
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
67
67
|
agreedRoles?: {
|
|
68
68
|
userId: string;
|
|
69
69
|
role: "agent" | "patient" | "peer";
|
|
@@ -115,11 +115,11 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
115
115
|
userId: string;
|
|
116
116
|
role: "agent" | "patient" | "peer";
|
|
117
117
|
}>, "many">>;
|
|
118
|
-
reason: z.ZodOptional<z.ZodEnum<["turn_cap", "timeout"]>>;
|
|
118
|
+
reason: z.ZodOptional<z.ZodEnum<["turn_cap", "timeout", "screened_out"]>>;
|
|
119
119
|
}, "strip", z.ZodTypeAny, {
|
|
120
120
|
reasoning: string;
|
|
121
121
|
hasOpportunity: boolean;
|
|
122
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
122
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
123
123
|
agreedRoles?: {
|
|
124
124
|
userId: string;
|
|
125
125
|
role: "agent" | "patient" | "peer";
|
|
@@ -127,7 +127,7 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
127
127
|
}, {
|
|
128
128
|
reasoning: string;
|
|
129
129
|
hasOpportunity: boolean;
|
|
130
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
130
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
131
131
|
agreedRoles?: {
|
|
132
132
|
userId: string;
|
|
133
133
|
role: "agent" | "patient" | "peer";
|
|
@@ -138,7 +138,7 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
138
138
|
outcome: {
|
|
139
139
|
reasoning: string;
|
|
140
140
|
hasOpportunity: boolean;
|
|
141
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
141
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
142
142
|
agreedRoles?: {
|
|
143
143
|
userId: string;
|
|
144
144
|
role: "agent" | "patient" | "peer";
|
|
@@ -160,7 +160,7 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
160
160
|
outcome: {
|
|
161
161
|
reasoning: string;
|
|
162
162
|
hasOpportunity: boolean;
|
|
163
|
-
reason?: "timeout" | "turn_cap" | undefined;
|
|
163
|
+
reason?: "timeout" | "turn_cap" | "screened_out" | undefined;
|
|
164
164
|
agreedRoles?: {
|
|
165
165
|
userId: string;
|
|
166
166
|
role: "agent" | "patient" | "peer";
|
|
@@ -22,7 +22,7 @@ export const DiscoveryOutcomeSchema = z.object({
|
|
|
22
22
|
userId: z.string(),
|
|
23
23
|
role: NegotiationRoleSchema,
|
|
24
24
|
})).optional(),
|
|
25
|
-
reason: z.enum(["turn_cap", "timeout"]).optional(),
|
|
25
|
+
reason: z.enum(["turn_cap", "timeout", "screened_out"]).optional(),
|
|
26
26
|
});
|
|
27
27
|
export const DiscoveryNegotiationSchema = z.object({
|
|
28
28
|
counterpartyId: z.string(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery-question.schema.js","sourceRoot":"/","sources":["shared/schemas/discovery-question.schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,iFAAiF;AAEjF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAG1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACrH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC;QACvB,OAAO,EAAE,qBAAqB;QAC9B,SAAS,EAAE,qBAAqB;KACjC,CAAC;CACH,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;IAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,IAAI,EAAE,qBAAqB;KAC5B,CAAC,CAAC,CAAC,QAAQ,EAAE;IACd,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"discovery-question.schema.js","sourceRoot":"/","sources":["shared/schemas/discovery-question.schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,iFAAiF;AAEjF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAG1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACrH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC;QACvB,OAAO,EAAE,qBAAqB;QAC9B,SAAS,EAAE,qBAAqB;KACjC,CAAC;CACH,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;IAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,IAAI,EAAE,qBAAqB;KAC5B,CAAC,CAAC,CAAC,QAAQ,EAAE;IACd,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE;CACnE,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACnC,OAAO,EAAE,sBAAsB;IAC/B,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC3C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;IAC3B,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC9B,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC9B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;CAC9D,CAAC,CAAC;AASH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAC","sourcesContent":["/**\n * DiscoveryQuestionInput and nested types.\n * Leaf types have full Zod schemas. The composite DiscoveryQuestionInput is\n * a pure interface referencing cross-schema types (DiscoveryNegotiationDigest,\n * ChatContextDigest) to avoid Zod cross-schema runtime coupling.\n */\nimport { z } from \"zod\";\nimport type { DiscoveryNegotiationDigest } from \"./negotiation-digest.schema.js\";\nimport type { ChatContextDigest } from \"./chat-context.schema.js\";\n\n// ─── Primitives ───────────────────────────────────────────────────────────────\n\nexport const NegotiationRoleSchema = z.enum([\"agent\", \"patient\", \"peer\"]);\nexport type NegotiationRole = z.infer<typeof NegotiationRoleSchema>;\n\nexport const DiscoveryTurnSchema = z.object({\n action: z.enum([\"propose\", \"accept\", \"reject\", \"counter\", \"question\", \"outreach\", \"withdraw\", \"decline\", \"ask_user\"]),\n reasoning: z.string(),\n suggestedRoles: z.object({\n ownUser: NegotiationRoleSchema,\n otherUser: NegotiationRoleSchema,\n }),\n});\nexport type DiscoveryTurn = z.infer<typeof DiscoveryTurnSchema>;\n\nexport const DiscoveryOutcomeSchema = z.object({\n hasOpportunity: z.boolean(),\n reasoning: z.string(),\n agreedRoles: z.array(z.object({\n userId: z.string(),\n role: NegotiationRoleSchema,\n })).optional(),\n reason: z.enum([\"turn_cap\", \"timeout\", \"screened_out\"]).optional(),\n});\nexport type DiscoveryOutcome = z.infer<typeof DiscoveryOutcomeSchema>;\n\nexport const DiscoveryNegotiationSchema = z.object({\n counterpartyId: z.string(),\n counterpartyHint: z.string(),\n indexContext: z.string(),\n turns: z.array(DiscoveryTurnSchema),\n outcome: DiscoveryOutcomeSchema,\n seedAssessmentScore: z.number().optional(),\n});\nexport type DiscoveryNegotiation = z.infer<typeof DiscoveryNegotiationSchema>;\n\nexport const DiscoverySummarySchema = z.object({\n totalCandidates: z.number(),\n opportunitiesFound: z.number(),\n noOpportunityCount: z.number(),\n timeoutCount: z.number(),\n roleDistribution: z.record(NegotiationRoleSchema, z.number()),\n});\nexport type DiscoverySummary = {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n timeoutCount: number;\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n};\n\nexport const DiscoverySourceProfileSchema = z.object({\n name: z.string().optional(),\n bio: z.string().optional(),\n location: z.string().optional(),\n skills: z.array(z.string()).optional(),\n interests: z.array(z.string()).optional(),\n});\nexport type DiscoverySourceProfile = z.infer<typeof DiscoverySourceProfileSchema>;\n\n// ─── Composite input (pure interface — references cross-schema types) ─────────\n\n/**\n * Full input to the question generator.\n * Defined as a pure interface so it can reference DiscoveryNegotiationDigest\n * and ChatContextDigest from sibling schemas without Zod runtime coupling.\n */\nexport interface DiscoveryQuestionInput {\n query: string;\n /** The seeker's global user_context paragraph (profile-replacing identity text). */\n userContext: string;\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n chatContext?: ChatContextDigest;\n now: string;\n}"]}
|
|
@@ -16,7 +16,7 @@ export declare const DiscoveryNegotiationDigestSchema: z.ZodObject<{
|
|
|
16
16
|
/** Whether the negotiation produced an opportunity. */
|
|
17
17
|
outcomeRole: z.ZodEnum<["opportunity", "no-opportunity"]>;
|
|
18
18
|
/** When `outcomeRole === "no-opportunity"`, why the negotiation didn't yield one. Null otherwise. */
|
|
19
|
-
outcomeReason: z.ZodNullable<z.ZodEnum<["turn_cap", "timeout", "rejected", "stalled"]>>;
|
|
19
|
+
outcomeReason: z.ZodNullable<z.ZodEnum<["turn_cap", "timeout", "rejected", "stalled", "screened_out"]>>;
|
|
20
20
|
/**
|
|
21
21
|
* One-sentence (≤180 chars) summary of the decisive moment or pattern in
|
|
22
22
|
* this negotiation. Written for the downstream question generator — should
|
|
@@ -42,7 +42,7 @@ export declare const DiscoveryNegotiationDigestSchema: z.ZodObject<{
|
|
|
42
42
|
counterpartyHint: string;
|
|
43
43
|
indexContext: string;
|
|
44
44
|
outcomeRole: "opportunity" | "no-opportunity";
|
|
45
|
-
outcomeReason: "stalled" | "rejected" | "timeout" | "turn_cap" | null;
|
|
45
|
+
outcomeReason: "stalled" | "rejected" | "timeout" | "turn_cap" | "screened_out" | null;
|
|
46
46
|
keyTake: string;
|
|
47
47
|
}, {
|
|
48
48
|
suggestedRoles: {
|
|
@@ -50,7 +50,7 @@ export declare const DiscoveryNegotiationDigestSchema: z.ZodObject<{
|
|
|
50
50
|
otherUser: "agent" | "patient" | "peer";
|
|
51
51
|
} | null;
|
|
52
52
|
outcomeRole: "opportunity" | "no-opportunity";
|
|
53
|
-
outcomeReason: "stalled" | "rejected" | "timeout" | "turn_cap" | null;
|
|
53
|
+
outcomeReason: "stalled" | "rejected" | "timeout" | "turn_cap" | "screened_out" | null;
|
|
54
54
|
counterpartyHint?: unknown;
|
|
55
55
|
indexContext?: unknown;
|
|
56
56
|
keyTake?: unknown;
|
|
@@ -21,7 +21,7 @@ export const DiscoveryNegotiationDigestSchema = z.object({
|
|
|
21
21
|
/** Whether the negotiation produced an opportunity. */
|
|
22
22
|
outcomeRole: z.enum(["opportunity", "no-opportunity"]),
|
|
23
23
|
/** When `outcomeRole === "no-opportunity"`, why the negotiation didn't yield one. Null otherwise. */
|
|
24
|
-
outcomeReason: z.enum(["turn_cap", "timeout", "rejected", "stalled"]).nullable(),
|
|
24
|
+
outcomeReason: z.enum(["turn_cap", "timeout", "rejected", "stalled", "screened_out"]).nullable(),
|
|
25
25
|
/**
|
|
26
26
|
* One-sentence (≤180 chars) summary of the decisive moment or pattern in
|
|
27
27
|
* this negotiation. Written for the downstream question generator — should
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiation-digest.schema.js","sourceRoot":"/","sources":["shared/schemas/negotiation-digest.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4EAA4E;AAC5E,gFAAgF;AAChF,+EAA+E;AAC/E,oBAAoB;AACpB,MAAM,aAAa,GAAG,CAAC,MAAc,EAAE,EAAE,CACvC,CAAC,CAAC,UAAU,CACV,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACvD,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAC9B,CAAC;AAEJ,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC,MAAM,CAAC;IACvD,0FAA0F;IAC1F,gBAAgB,EAAE,aAAa,CAAC,GAAG,CAAC;IACpC,gEAAgE;IAChE,YAAY,EAAE,aAAa,CAAC,GAAG,CAAC;IAChC,uDAAuD;IACvD,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IACtD,qGAAqG;IACrG,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"negotiation-digest.schema.js","sourceRoot":"/","sources":["shared/schemas/negotiation-digest.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4EAA4E;AAC5E,gFAAgF;AAChF,+EAA+E;AAC/E,oBAAoB;AACpB,MAAM,aAAa,GAAG,CAAC,MAAc,EAAE,EAAE,CACvC,CAAC,CAAC,UAAU,CACV,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACvD,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAC9B,CAAC;AAEJ,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC,MAAM,CAAC;IACvD,0FAA0F;IAC1F,gBAAgB,EAAE,aAAa,CAAC,GAAG,CAAC;IACpC,gEAAgE;IAChE,YAAY,EAAE,aAAa,CAAC,GAAG,CAAC;IAChC,uDAAuD;IACvD,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IACtD,qGAAqG;IACrG,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE;IAChG;;;;OAIG;IACH,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC;IAC3B,8EAA8E;IAC9E,cAAc,EAAE,CAAC;SACd,MAAM,CAAC;QACN,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC7C,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;KAChD,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC","sourcesContent":["/**\n * NegotiationDigest — compact, fixed-size structured summary of one discovery\n * negotiation. Produced by the negotiation summarizer; consumed by the\n * decision-question generator in place of raw negotiations.\n *\n * Goal: cap the question generator's per-negotiation prompt budget so that a\n * 10-candidate discovery turn produces a ~1.5 KB prompt instead of a 60+ KB\n * blob that stalls upstream LLM providers.\n */\nimport { z } from \"zod\";\n\n// LLMs ignore .max() length constraints often enough that strict validation\n// throws every call and forces a fallback. Slice strings down before validating\n// so JSON schema still advertises the limit but a small overshoot doesn't drop\n// the whole digest.\nconst clampedString = (maxLen: number) =>\n z.preprocess(\n (v) => (typeof v === \"string\" ? v.slice(0, maxLen) : v),\n z.string().min(1).max(maxLen),\n );\n\nexport const DiscoveryNegotiationDigestSchema = z.object({\n /** Abstract counterparty descriptor (no PII, no IDs). E.g. \"AI infra founder, Berlin\". */\n counterpartyHint: clampedString(120),\n /** The network the negotiation ran under (community prompt). */\n indexContext: clampedString(120),\n /** Whether the negotiation produced an opportunity. */\n outcomeRole: z.enum([\"opportunity\", \"no-opportunity\"]),\n /** When `outcomeRole === \"no-opportunity\"`, why the negotiation didn't yield one. Null otherwise. */\n outcomeReason: z.enum([\"turn_cap\", \"timeout\", \"rejected\", \"stalled\", \"screened_out\"]).nullable(),\n /**\n * One-sentence (≤180 chars) summary of the decisive moment or pattern in\n * this negotiation. Written for the downstream question generator — should\n * highlight a fact or tension that could inform a clarifying question.\n */\n keyTake: clampedString(180),\n /** Suggested roles agreed by both parties. Null when no agreement reached. */\n suggestedRoles: z\n .object({\n ownUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n otherUser: z.enum([\"agent\", \"patient\", \"peer\"]),\n })\n .nullable(),\n});\n\nexport type DiscoveryNegotiationDigest = z.infer<typeof DiscoveryNegotiationDigestSchema>;\n"]}
|