import { createStructuredModel } from "../../shared/agent/model.config.js"; import type { UserNegotiationContext, SeedAssessment } from "../../shared/schemas/negotiation-state.schema.js"; import { type NegotiatorMemoryEntry } from "../domain/negotiation.memory.js"; import type { NegotiationTurn } from "../domain/negotiation.state.js"; import { type AttributedPriorDialogue } from "../negotiation.attribution.js"; export { NEGOTIATION_SCREEN_MODES, configuredScreenMode, ScreenDecisionSchema, blocksNegotiationBeforeFirstTurn, } from "../domain/negotiation.screen.contracts.js"; export type { NegotiationScreenMode, ScreenDecision, ScreenDecisionRecord, } from "../domain/negotiation.screen.contracts.js"; import type { ScreenDecision } from "../domain/negotiation.screen.contracts.js"; export interface NegotiationScreenerInput { /** The client — the user whose negotiator is deciding whether to reach out. */ clientUser: UserNegotiationContext; /** The counterparty the client's negotiator would be reaching out to. */ counterpartyUser: UserNegotiationContext; /** The counterparty's `user_contexts` paragraph (empty string when absent). */ counterpartyContext?: string; /** The explicit search query that triggered discovery (if any). */ discoveryQuery?: string; seedAssessment: Omit; indexContext: { networkId: string; prompt?: string; }; /** * Retrieved negotiator memories for the client (P5.3 read path). Rendered * as a private prompt section with a memoryHints instruction. Absent/empty * → the prompt is byte-identical to before. */ memory?: NegotiatorMemoryEntry[]; /** * Whether this screen is for a continuation — a match against a counterparty * this client already has prior dialogue with (IND-563). When set with * `priorDialogue`, the gate evaluates the NEW signal on its own merits with * that dialogue as context. Absent → the prompt is byte-identical to before. */ isContinuation?: boolean; /** * Prior negotiation turns with this counterparty (continuations only). * Rendered as read-only context so the gate can tell a materially-new signal * from a rehash of an already-settled one. Never treated as this task's own * outreach. */ priorDialogue?: NegotiationTurn[]; /** * Attributed form of the prior dialogue (IND-569). When present it supersedes * the flat `priorDialogue` list: earlier concluded opportunities and legacy * unattributed turns render as labeled, separated blocks so the gate can see * which prior turns belonged to OTHER opportunities. Absent → the flat * `priorDialogue` rendering is used (byte-identical to before). */ priorDialogueAttributed?: AttributedPriorDialogue; } export interface NegotiationScreenerConfig { /** Hard ceiling on the screen LLM round-trip, in ms (default 15000). */ timeoutMs?: number; } /** * The outreach gate (P2.1). One structured LLM call deciding * `reach_out | pass` for a fresh negotiation, from the reaching client's * perspective. Throws on LLM/validation failure — the screen graph node owns * the fail-open policy (a failed screen never blocks the negotiation). */ export declare class NegotiationScreener { private readonly timeoutMs; constructor(config?: NegotiationScreenerConfig); /** * Produce a screen decision for a fresh match. * @throws When the LLM call times out or returns schema-invalid output. */ invoke(input: NegotiationScreenerInput): Promise; /** * Raw structured-model round trip. Split out as a seam so tests can drive * the schema-validation and fail-open paths without a live provider. */ protected callModel(model: ReturnType, chatMessages: Array<{ role: string; content: string; }>): Promise; }