@indexnetwork/protocol 6.10.1-rc.399.1 → 6.10.2-rc.400.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/dist/opportunity/opportunity.persist.d.ts.map +1 -1
- package/dist/opportunity/opportunity.persist.js +33 -2
- package/dist/opportunity/opportunity.persist.js.map +1 -1
- package/dist/questioner/questioner.presets.js +1 -1
- package/dist/questioner/questioner.presets.js.map +1 -1
- package/dist/shared/schemas/question.schema.d.ts +10 -10
- package/dist/shared/schemas/question.schema.js +1 -1
- package/dist/shared/schemas/question.schema.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,9 @@ See [STABILITY.md](./STABILITY.md) for the public-contract and tier definitions.
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
### Fixed
|
|
16
|
+
- Allow the private intent-refinement provenance snapshot to identify intent creation as a producer and make the shared refinement prompt independent of no-opportunity process state, enabling creation and authoritative discovery producers to converge on one ordinary intent-page question cadence.
|
|
17
|
+
|
|
15
18
|
### Added
|
|
16
19
|
- Add the private `recovery` Questioner purpose and one-question intent recovery preset for post-discovery signal refinement (IND-506). The preset receives only the owned intent, global owner context, and an optional bounded aggregate count of fail-closed validated no-opportunity outcomes; it forbids candidate/counterparty/process narration, preserves the existing creation-time intent preset, persists publicly as ordinary `mode='intent'` questions with versioned internal recovery metadata, and carries optional material-fingerprint plus expected-owner guards through answer-only updates so the final database write can recheck lifecycle as well as content.
|
|
17
20
|
- Add versioned internal negotiation-question provenance and explicit source/candidate opportunity-actor intent threading for ordinary follow-up, inflight consultation, and uptake questions (IND-507). Runtime mode/purpose discriminants, structured `askUser` safety validation, neutral uptake context, and visible-field output gates exclude raw counterparty profile/identity/intent, private transcript, evaluator reasoning, match reasons, event/community inference, evidence, and internal IDs. Exact settlement/task correlation now threads through run-existing continuation admission without changing producer triggers or the ≤2 ordinary/inflight and ≤1 uptake cardinality.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunity.persist.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.persist.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,wCAAwC,EAAE,WAAW,EAAE,wBAAwB,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC3N,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"opportunity.persist.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.persist.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,wCAAwC,EAAE,WAAW,EAAE,wBAAwB,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC3N,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAuClE,MAAM,MAAM,0BAA0B,GAAG,gBAAgB,GAAG;IAC1D,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrE,kCAAkC,CAAC,CACjC,IAAI,EAAE,qBAAqB,EAC3B,WAAW,EAAE,6BAA6B,GACzC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC/B,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,GAAG,WAAW,GAAG,IAAI,CAAC,CAAC;IACnG,6BAA6B,CAAC,CAC5B,IAAI,EAAE,qBAAqB,EAC3B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC;QAAE,OAAO,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC,CAAC;IAC7D,8CAA8C,CAAC,CAC7C,IAAI,EAAE,qBAAqB,EAC3B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,6BAA6B,GACzC,OAAO,CAAC;QAAE,OAAO,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,WAAW,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACpE,+CAA+C,CAAC,CAC9C,IAAI,EAAE,qBAAqB,EAC3B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,6BAA6B,GAAG;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE,EACxE,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,wCAAwC,GAAG,IAAI,CAAC,CAAC;IAC5D,kEAAkE;IAClE,cAAc,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC1D,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,0BAA0B,CAAC;IACrC,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,6BAA6B,CAAC;IACnD,gFAAgF;IAChF,gBAAgB,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACvE;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,4BAA4B,EAAE,CAAC;IAC1C,MAAM,CAAC,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA0HlH"}
|
|
@@ -6,6 +6,31 @@ import { enrichOrCreate } from './opportunity.enricher.js';
|
|
|
6
6
|
import { normalizeCreateOpportunityActorIntents } from './opportunity.actor.js';
|
|
7
7
|
import { protocolLogger } from '../shared/observability/protocol.logger.js';
|
|
8
8
|
const logger = protocolLogger('OpportunityPersist');
|
|
9
|
+
/** Bind owned-intent discovery actors to the already-authorized trigger intent. */
|
|
10
|
+
function bindOwnedIntentActors(data, ownerUserId, triggerIntentId) {
|
|
11
|
+
const actors = [];
|
|
12
|
+
const boundActorIndexes = new Map();
|
|
13
|
+
for (const actor of data.actors) {
|
|
14
|
+
if (actor.userId !== ownerUserId || actor.role === 'introducer') {
|
|
15
|
+
actors.push(actor);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const boundActor = {
|
|
19
|
+
...actor,
|
|
20
|
+
intent: triggerIntentId,
|
|
21
|
+
};
|
|
22
|
+
const key = JSON.stringify([boundActor.networkId, boundActor.userId, triggerIntentId]);
|
|
23
|
+
const existingIndex = boundActorIndexes.get(key);
|
|
24
|
+
if (existingIndex === undefined) {
|
|
25
|
+
boundActorIndexes.set(key, actors.length);
|
|
26
|
+
actors.push(boundActor);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
actors[existingIndex] = boundActor;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return { ...data, actors };
|
|
33
|
+
}
|
|
9
34
|
/**
|
|
10
35
|
* Persist one or more opportunities: enrich (merge overlapping), create, expire replaced, optional chat injection.
|
|
11
36
|
* When the database has createOpportunityAndExpireIds and enrichment produced expireIds, uses it for atomic create+expire.
|
|
@@ -25,7 +50,10 @@ export async function persistOpportunities(params) {
|
|
|
25
50
|
&& intentDedupScope.triggerIntentId !== networkEligibility?.triggerIntentId) {
|
|
26
51
|
throw new Error('Intent-scoped dedup trigger must match network eligibility');
|
|
27
52
|
}
|
|
28
|
-
const
|
|
53
|
+
const scopedData = intentDedupScope && networkEligibility
|
|
54
|
+
? bindOwnedIntentActors(normalizedData, networkEligibility.ownerUserId, intentDedupScope.triggerIntentId)
|
|
55
|
+
: normalizedData;
|
|
56
|
+
const enrichment = await enrichOrCreate(database, embedder, scopedData, intentDedupScope && networkEligibility
|
|
29
57
|
? {
|
|
30
58
|
ownedIntentScope: {
|
|
31
59
|
triggerIntentId: intentDedupScope.triggerIntentId,
|
|
@@ -33,7 +61,10 @@ export async function persistOpportunities(params) {
|
|
|
33
61
|
},
|
|
34
62
|
}
|
|
35
63
|
: undefined);
|
|
36
|
-
const
|
|
64
|
+
const normalizedToCreate = normalizeCreateOpportunityActorIntents(enrichment.data);
|
|
65
|
+
const toCreate = intentDedupScope && networkEligibility
|
|
66
|
+
? bindOwnedIntentActors(normalizedToCreate, networkEligibility.ownerUserId, intentDedupScope.triggerIntentId)
|
|
67
|
+
: normalizedToCreate;
|
|
37
68
|
if (enrichment.enriched) {
|
|
38
69
|
toCreate.status = enrichment.resolvedStatus;
|
|
39
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunity.persist.js","sourceRoot":"/","sources":["opportunity/opportunity.persist.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared persist phase for opportunity creation: enrichOrCreate → create (or create+expire) → optional chat injection.\n * Used by the opportunity graph persist node and by the manual opportunity service for consistency.\n */\n\nimport type { CreateOpportunityData, IntentScopedOpportunityPersistenceResult, Opportunity, OpportunityDedupConflict, OpportunityNetworkEligibility, OpportunityStatus } from '../shared/interfaces/database.interface.js';\nimport type { Embedder } from '../shared/interfaces/embedder.interface.js';\nimport type { EnricherDatabase } from './opportunity.enricher.js';\nimport { enrichOrCreate } from './opportunity.enricher.js';\nimport { normalizeCreateOpportunityActorIntents } from './opportunity.actor.js';\nimport { protocolLogger } from '../shared/observability/protocol.logger.js';\n\nconst logger = protocolLogger('OpportunityPersist');\n\nexport type PersistOpportunityDatabase = EnricherDatabase & {\n createOpportunity(data: CreateOpportunityData): Promise<Opportunity>;\n createOpportunityIfNetworkEligible?(\n data: CreateOpportunityData,\n eligibility: OpportunityNetworkEligibility,\n ): Promise<Opportunity | null>;\n updateOpportunityStatus(id: string, status: OpportunityStatus): Promise<void | Opportunity | null>;\n createOpportunityAndExpireIds?(\n data: CreateOpportunityData,\n expireIds: string[]\n ): Promise<{ created: Opportunity; expired: Opportunity[] }>;\n createOpportunityAndExpireIdsIfNetworkEligible?(\n data: CreateOpportunityData,\n expireIds: string[],\n eligibility: OpportunityNetworkEligibility,\n ): Promise<{ created: Opportunity; expired: Opportunity[] } | null>;\n persistIntentScopedOpportunityIfNetworkEligible?(\n data: CreateOpportunityData,\n expireIds: string[],\n eligibility: OpportunityNetworkEligibility & { triggerIntentId: string },\n dedupWindowMs: number,\n ): Promise<IntentScopedOpportunityPersistenceResult | null>;\n /** Optional: used to populate expired list in non-atomic path. */\n getOpportunity?(id: string): Promise<Opportunity | null>;\n};\n\nexport interface PersistOpportunitiesParams {\n database: PersistOpportunityDatabase;\n embedder: Embedder;\n items: CreateOpportunityData[];\n injectChat?: (opportunity: Opportunity) => Promise<unknown>;\n /** Require adapter-level membership/assignment locks for discovery-created rows. */\n networkEligibility?: OpportunityNetworkEligibility;\n /** Scope dedup/enrichment and the final atomic re-check to one owned intent. */\n intentDedupScope?: { triggerIntentId: string; dedupWindowMs: number };\n}\n\nexport interface PersistOpportunitiesError {\n itemIndex: number;\n error: unknown;\n}\n\nexport interface PersistOpportunitiesConflict extends OpportunityDedupConflict {\n itemIndex: number;\n finalAtomic: true;\n}\n\nexport interface PersistOpportunitiesResult {\n created: Opportunity[];\n expired: Opportunity[];\n conflicts: PersistOpportunitiesConflict[];\n errors?: PersistOpportunitiesError[];\n}\n\n/**\n * Persist one or more opportunities: enrich (merge overlapping), create, expire replaced, optional chat injection.\n * When the database has createOpportunityAndExpireIds and enrichment produced expireIds, uses it for atomic create+expire.\n * Returns both created and expired so callers can emit events (e.g. manual service).\n */\nexport async function persistOpportunities(params: PersistOpportunitiesParams): Promise<PersistOpportunitiesResult> {\n const { database, embedder, items, injectChat, networkEligibility, intentDedupScope } = params;\n const created: Opportunity[] = [];\n const expired: Opportunity[] = [];\n const conflicts: PersistOpportunitiesConflict[] = [];\n const errors: PersistOpportunitiesError[] = [];\n\n for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n const data = items[itemIndex];\n try {\n const normalizedData = normalizeCreateOpportunityActorIntents(data);\n if (\n intentDedupScope\n && intentDedupScope.triggerIntentId !== networkEligibility?.triggerIntentId\n ) {\n throw new Error('Intent-scoped dedup trigger must match network eligibility');\n }\n const enrichment = await enrichOrCreate(database, embedder, normalizedData, intentDedupScope && networkEligibility\n ? {\n ownedIntentScope: {\n triggerIntentId: intentDedupScope.triggerIntentId,\n ownerUserId: networkEligibility.ownerUserId,\n },\n }\n : undefined);\n const toCreate = normalizeCreateOpportunityActorIntents(enrichment.data);\n if (enrichment.enriched) {\n toCreate.status = enrichment.resolvedStatus;\n }\n\n if (intentDedupScope) {\n if (!networkEligibility?.triggerIntentId) {\n throw new Error('Intent-scoped dedup requires trigger-intent network eligibility');\n }\n if (!database.persistIntentScopedOpportunityIfNetworkEligible) {\n throw new Error('Intent-scoped atomic persistence is required for owned-intent discovery');\n }\n const result = await database.persistIntentScopedOpportunityIfNetworkEligible(\n toCreate,\n enrichment.enriched ? enrichment.expiredIds : [],\n { ...networkEligibility, triggerIntentId: networkEligibility.triggerIntentId },\n intentDedupScope.dedupWindowMs,\n );\n if (!result) continue;\n if ('conflict' in result) {\n conflicts.push({ itemIndex, finalAtomic: true, ...result.conflict });\n continue;\n }\n created.push(result.created);\n expired.push(...result.expired);\n } else if (networkEligibility) {\n if (enrichment.enriched && enrichment.expiredIds.length > 0) {\n if (!database.createOpportunityAndExpireIdsIfNetworkEligible) {\n throw new Error('Network-eligible create+expire is required for discovery persistence');\n }\n const result = await database.createOpportunityAndExpireIdsIfNetworkEligible(\n toCreate,\n enrichment.expiredIds,\n networkEligibility,\n );\n if (!result) continue;\n created.push(result.created);\n expired.push(...result.expired);\n } else {\n if (!database.createOpportunityIfNetworkEligible) {\n throw new Error('Network-eligible create is required for discovery persistence');\n }\n const c = await database.createOpportunityIfNetworkEligible(toCreate, networkEligibility);\n if (!c) continue;\n created.push(c);\n }\n } else if (\n database.createOpportunityAndExpireIds &&\n enrichment.enriched &&\n enrichment.expiredIds.length > 0\n ) {\n const result = await database.createOpportunityAndExpireIds(toCreate, enrichment.expiredIds);\n created.push(result.created);\n expired.push(...result.expired);\n } else {\n const c = await database.createOpportunity(toCreate);\n created.push(c);\n if (enrichment.enriched && enrichment.expiredIds.length > 0) {\n for (const id of enrichment.expiredIds) {\n await database.updateOpportunityStatus(id, 'expired');\n }\n if (database.getOpportunity) {\n for (const id of enrichment.expiredIds) {\n const opp = await database.getOpportunity(id);\n if (opp) expired.push(opp);\n }\n }\n }\n }\n\n const lastCreated = created[created.length - 1];\n if (lastCreated?.status === 'pending' && injectChat) {\n await injectChat(lastCreated).catch((err) => {\n logger.warn('Chat injection failed', { opportunityId: lastCreated.id, error: err });\n });\n }\n } catch (err) {\n errors.push({ itemIndex, error: err });\n logger.warn('Item failed', { itemIndex, error: err });\n }\n }\n\n return { created, expired, conflicts, ...(errors.length > 0 ? { errors } : {}) };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"opportunity.persist.js","sourceRoot":"/","sources":["opportunity/opportunity.persist.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared persist phase for opportunity creation: enrichOrCreate → create (or create+expire) → optional chat injection.\n * Used by the opportunity graph persist node and by the manual opportunity service for consistency.\n */\n\nimport type { CreateOpportunityData, IntentScopedOpportunityPersistenceResult, Opportunity, OpportunityDedupConflict, OpportunityNetworkEligibility, OpportunityStatus } from '../shared/interfaces/database.interface.js';\nimport type { Embedder } from '../shared/interfaces/embedder.interface.js';\nimport type { EnricherDatabase } from './opportunity.enricher.js';\nimport { enrichOrCreate } from './opportunity.enricher.js';\nimport { normalizeCreateOpportunityActorIntents } from './opportunity.actor.js';\nimport { protocolLogger } from '../shared/observability/protocol.logger.js';\n\nconst logger = protocolLogger('OpportunityPersist');\n\n/** Bind owned-intent discovery actors to the already-authorized trigger intent. */\nfunction bindOwnedIntentActors(\n data: CreateOpportunityData,\n ownerUserId: string,\n triggerIntentId: string,\n): CreateOpportunityData {\n const actors: CreateOpportunityData['actors'] = [];\n const boundActorIndexes = new Map<string, number>();\n\n for (const actor of data.actors) {\n if (actor.userId !== ownerUserId || actor.role === 'introducer') {\n actors.push(actor);\n continue;\n }\n\n const boundActor = {\n ...actor,\n intent: triggerIntentId as NonNullable<typeof actor.intent>,\n };\n const key = JSON.stringify([boundActor.networkId, boundActor.userId, triggerIntentId]);\n const existingIndex = boundActorIndexes.get(key);\n if (existingIndex === undefined) {\n boundActorIndexes.set(key, actors.length);\n actors.push(boundActor);\n } else {\n actors[existingIndex] = boundActor;\n }\n }\n\n return { ...data, actors };\n}\n\nexport type PersistOpportunityDatabase = EnricherDatabase & {\n createOpportunity(data: CreateOpportunityData): Promise<Opportunity>;\n createOpportunityIfNetworkEligible?(\n data: CreateOpportunityData,\n eligibility: OpportunityNetworkEligibility,\n ): Promise<Opportunity | null>;\n updateOpportunityStatus(id: string, status: OpportunityStatus): Promise<void | Opportunity | null>;\n createOpportunityAndExpireIds?(\n data: CreateOpportunityData,\n expireIds: string[]\n ): Promise<{ created: Opportunity; expired: Opportunity[] }>;\n createOpportunityAndExpireIdsIfNetworkEligible?(\n data: CreateOpportunityData,\n expireIds: string[],\n eligibility: OpportunityNetworkEligibility,\n ): Promise<{ created: Opportunity; expired: Opportunity[] } | null>;\n persistIntentScopedOpportunityIfNetworkEligible?(\n data: CreateOpportunityData,\n expireIds: string[],\n eligibility: OpportunityNetworkEligibility & { triggerIntentId: string },\n dedupWindowMs: number,\n ): Promise<IntentScopedOpportunityPersistenceResult | null>;\n /** Optional: used to populate expired list in non-atomic path. */\n getOpportunity?(id: string): Promise<Opportunity | null>;\n};\n\nexport interface PersistOpportunitiesParams {\n database: PersistOpportunityDatabase;\n embedder: Embedder;\n items: CreateOpportunityData[];\n injectChat?: (opportunity: Opportunity) => Promise<unknown>;\n /** Require adapter-level membership/assignment locks for discovery-created rows. */\n networkEligibility?: OpportunityNetworkEligibility;\n /** Scope dedup/enrichment and the final atomic re-check to one owned intent. */\n intentDedupScope?: { triggerIntentId: string; dedupWindowMs: number };\n}\n\nexport interface PersistOpportunitiesError {\n itemIndex: number;\n error: unknown;\n}\n\nexport interface PersistOpportunitiesConflict extends OpportunityDedupConflict {\n itemIndex: number;\n finalAtomic: true;\n}\n\nexport interface PersistOpportunitiesResult {\n created: Opportunity[];\n expired: Opportunity[];\n conflicts: PersistOpportunitiesConflict[];\n errors?: PersistOpportunitiesError[];\n}\n\n/**\n * Persist one or more opportunities: enrich (merge overlapping), create, expire replaced, optional chat injection.\n * When the database has createOpportunityAndExpireIds and enrichment produced expireIds, uses it for atomic create+expire.\n * Returns both created and expired so callers can emit events (e.g. manual service).\n */\nexport async function persistOpportunities(params: PersistOpportunitiesParams): Promise<PersistOpportunitiesResult> {\n const { database, embedder, items, injectChat, networkEligibility, intentDedupScope } = params;\n const created: Opportunity[] = [];\n const expired: Opportunity[] = [];\n const conflicts: PersistOpportunitiesConflict[] = [];\n const errors: PersistOpportunitiesError[] = [];\n\n for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n const data = items[itemIndex];\n try {\n const normalizedData = normalizeCreateOpportunityActorIntents(data);\n if (\n intentDedupScope\n && intentDedupScope.triggerIntentId !== networkEligibility?.triggerIntentId\n ) {\n throw new Error('Intent-scoped dedup trigger must match network eligibility');\n }\n const scopedData = intentDedupScope && networkEligibility\n ? bindOwnedIntentActors(\n normalizedData,\n networkEligibility.ownerUserId,\n intentDedupScope.triggerIntentId,\n )\n : normalizedData;\n const enrichment = await enrichOrCreate(database, embedder, scopedData, intentDedupScope && networkEligibility\n ? {\n ownedIntentScope: {\n triggerIntentId: intentDedupScope.triggerIntentId,\n ownerUserId: networkEligibility.ownerUserId,\n },\n }\n : undefined);\n const normalizedToCreate = normalizeCreateOpportunityActorIntents(enrichment.data);\n const toCreate = intentDedupScope && networkEligibility\n ? bindOwnedIntentActors(\n normalizedToCreate,\n networkEligibility.ownerUserId,\n intentDedupScope.triggerIntentId,\n )\n : normalizedToCreate;\n if (enrichment.enriched) {\n toCreate.status = enrichment.resolvedStatus;\n }\n\n if (intentDedupScope) {\n if (!networkEligibility?.triggerIntentId) {\n throw new Error('Intent-scoped dedup requires trigger-intent network eligibility');\n }\n if (!database.persistIntentScopedOpportunityIfNetworkEligible) {\n throw new Error('Intent-scoped atomic persistence is required for owned-intent discovery');\n }\n const result = await database.persistIntentScopedOpportunityIfNetworkEligible(\n toCreate,\n enrichment.enriched ? enrichment.expiredIds : [],\n { ...networkEligibility, triggerIntentId: networkEligibility.triggerIntentId },\n intentDedupScope.dedupWindowMs,\n );\n if (!result) continue;\n if ('conflict' in result) {\n conflicts.push({ itemIndex, finalAtomic: true, ...result.conflict });\n continue;\n }\n created.push(result.created);\n expired.push(...result.expired);\n } else if (networkEligibility) {\n if (enrichment.enriched && enrichment.expiredIds.length > 0) {\n if (!database.createOpportunityAndExpireIdsIfNetworkEligible) {\n throw new Error('Network-eligible create+expire is required for discovery persistence');\n }\n const result = await database.createOpportunityAndExpireIdsIfNetworkEligible(\n toCreate,\n enrichment.expiredIds,\n networkEligibility,\n );\n if (!result) continue;\n created.push(result.created);\n expired.push(...result.expired);\n } else {\n if (!database.createOpportunityIfNetworkEligible) {\n throw new Error('Network-eligible create is required for discovery persistence');\n }\n const c = await database.createOpportunityIfNetworkEligible(toCreate, networkEligibility);\n if (!c) continue;\n created.push(c);\n }\n } else if (\n database.createOpportunityAndExpireIds &&\n enrichment.enriched &&\n enrichment.expiredIds.length > 0\n ) {\n const result = await database.createOpportunityAndExpireIds(toCreate, enrichment.expiredIds);\n created.push(result.created);\n expired.push(...result.expired);\n } else {\n const c = await database.createOpportunity(toCreate);\n created.push(c);\n if (enrichment.enriched && enrichment.expiredIds.length > 0) {\n for (const id of enrichment.expiredIds) {\n await database.updateOpportunityStatus(id, 'expired');\n }\n if (database.getOpportunity) {\n for (const id of enrichment.expiredIds) {\n const opp = await database.getOpportunity(id);\n if (opp) expired.push(opp);\n }\n }\n }\n }\n\n const lastCreated = created[created.length - 1];\n if (lastCreated?.status === 'pending' && injectChat) {\n await injectChat(lastCreated).catch((err) => {\n logger.warn('Chat injection failed', { opportunityId: lastCreated.id, error: err });\n });\n }\n } catch (err) {\n errors.push({ itemIndex, error: err });\n logger.warn('Item failed', { itemIndex, error: err });\n }\n }\n\n return { created, expired, conflicts, ...(errors.length > 0 ? { errors } : {}) };\n}\n"]}
|
|
@@ -80,7 +80,7 @@ function buildIntentPrompt(ctx) {
|
|
|
80
80
|
"Return an empty `questions` array if the intent is already specific enough.",
|
|
81
81
|
].join("\n");
|
|
82
82
|
}
|
|
83
|
-
const RECOVERY_INTENT_SYSTEM_PROMPT = `You help a user materially refine one of their own discovery signals
|
|
83
|
+
const RECOVERY_INTENT_SYSTEM_PROMPT = `You help a user materially refine one of their own discovery signals. Ask directly about the user's goal, desired counterpart attributes, or constraints. Never describe internal processing or imply that any specific person was reviewed.
|
|
84
84
|
|
|
85
85
|
Choose exactly one of these strategies:
|
|
86
86
|
- refine_intent: sharpen or pivot the core signal in a way that changes who should surface.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questioner.presets.js","sourceRoot":"/","sources":["questioner/questioner.presets.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mode presets for the QuestionerAgent. Each preset provides a system prompt\n * and a buildPrompt function that assembles the user message from a typed\n * context object. Only the `discovery` preset ships in Slice 1; others throw\n * until their implementation slices land.\n */\nimport type { QuestionMode, QuestionPurpose } from \"../shared/schemas/question.schema.js\";\nimport { DISCOVERY_SYSTEM_PROMPT, buildDiscoveryQuestionPrompt } from \"./questioner.discovery.prompt.js\";\n\nimport { QUD_UNDERSPECIFICATION_RULES } from \"./questioner.qud.js\";\nimport type { ChatContext, IntentContext, NegotiationContext, NegotiationInflightContext, PostStallNegotiationContext, ProfileContext, RecoveryIntentContext, UptakeNegotiationContext } from \"./questioner.types.js\";\n\n/**\n * Shared rule block appended to every questioner system prompt. Enforces that\n * the generated `prompt` resolves on its own — no demonstratives/anaphora that\n * point at people, events, or prior turns the reader cannot see — and never\n * narrates Index's own matching pipeline. Closes the referential-leak class\n * surfaced in digest audits (\"…with these builders?\", \"the previous\n * negotiation stalled because the counterparty didn't mention …\").\n */\nconst REFERENTIAL_CLOSURE_RULES = `Referential 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 counterparty, 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: \"The previous negotiation stalled because the counterparty didn't mention 'matchmaking'. Should I broaden the search?\"\n- Good: \"Do you want to focus on dedicated matchmakers, or also people interested in relationships more broadly?\"`;\n\nexport interface QuestionerPreset {\n /** The LLM system prompt for this mode. */\n systemPrompt: string;\n /** Builds the user-message string from the mode-specific context. */\n buildPrompt: (context: unknown) => string;\n}\n\n/**\n * Renders the user-context block shared by every preset's user message from the\n * global user_context paragraph (the profile-replacing identity text).\n * @param userContext - The user's global context paragraph, if available.\n * @returns The trimmed context paragraph, or \"(no profile data)\" when empty.\n */\nfunction buildUserContextBlock(userContext?: string): string {\n const trimmed = userContext?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : \"(no profile data)\";\n}\n\n// ─── Intent preset ──────────────────────────────────────────────────────────\n\nconst INTENT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has stated an intent — what they are looking for. Your job: surface the minimum set of structured questions that help the user sharpen that intent before the protocol runs discovery on their behalf.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: ask the user to sharpen or pivot the core signal (scope, scale, specificity, direction).\n- surface_missing_detail: ask for one concrete missing input that would change which candidates surface (stage, location, timing, budget, constraints, format, …).\n\nAsk a question only when ALL of these hold:\n1. The agent cannot infer the answer from the intent text or user profile already shown.\n2. The answer would materially change which candidates surface.\n3. The question targets a different decision domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the source intent/topic in the question text itself, using concise plain language from the intent or summary. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"What kind of collaboration are you looking for?\"\n- Good: \"For your decentralized identity protocol-design search, what kind of collaboration are you looking for?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ (different titles).\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Stage\", \"Timing\", \"Location\", \"Scope\", \"Budget\", \"Format\", \"Skills\", \"Collab\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I start searching?\").\n- Don't ask about hypothetical edge cases not implied by the intent.\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the intent is already specific enough, return \"questions\": [].`;\n\n/**\n * Build the user message for the intent preset from an IntentContext.\n * @param ctx - The intent context.\n * @returns The assembled user message string.\n */\nfunction buildIntentPrompt(ctx: IntentContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const summaryBlock = ctx.summary ? ctx.summary : \"(no summary available)\";\n\n return [\n \"## Intent\",\n ctx.payload,\n \"\",\n \"## Summary\",\n summaryBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to sharpen this intent.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the intent is already specific enough.\",\n ].join(\"\\n\");\n}\n\nconst RECOVERY_INTENT_SYSTEM_PROMPT = `You help a user materially refine one of their own discovery signals after an authoritative discovery run completed without leaving a currently actionable opportunity. Ask directly about the user's goal, desired counterpart attributes, or constraints. Never describe the run or imply that any specific person was reviewed.\n\nChoose exactly one of these strategies:\n- refine_intent: sharpen or pivot the core signal in a way that changes who should surface.\n- surface_missing_detail: ask for one concrete missing constraint such as stage, location, timing, budget, format, or required capability.\n\nAsk a question only when the answer is not already inferable from the intent, summary, or user profile and would materially change discovery. If no safe, useful missing axis exists, return an empty questions array.\n\nStandalone prompt rule. The prompt must identify the user's intent topic in plain language and ask about their own goal or constraints. It must make sense without UI labels or hidden metadata.\n\n${REFERENTIAL_CLOSURE_RULES}\n\nPrivacy and process boundary. You may receive only a bounded aggregate count of validated prior outcomes. Use it solely as a weak signal to choose a missing axis. Never mention or imply counts, matches, no matches, rejections, negotiations, candidates, counterparties, searches, retries, pipeline state, evidence, or what another person did or did not say. Never invent people or facts.\n\nCardinality. Return at most ONE question. Use only refine_intent or surface_missing_detail. The question must nudge a material edit, not ask whether to search again.\n\nOption construction. Provide 2–4 materially different outcomes. Put the safest or most common path first with \" (Recommended)\" when appropriate. Descriptions state the discovery consequence. Never add an Other option.\n\nTitle rules. ≤12 chars and name the decision domain, such as Scope, Timing, Location, Stage, Budget, Format, or Skills.\n\nOutput. Return zero or one question. Set underspecificationType to the applicable QUD category, or null when none applies.`;\n\nfunction buildRecoveryIntentPrompt(ctx: RecoveryIntentContext): string {\n return [\n \"## Intent\",\n ctx.payload,\n \"\",\n \"## Summary\",\n ctx.summary?.trim() || \"(no summary available)\",\n \"\",\n \"## User profile\",\n buildUserContextBlock(ctx.userContext),\n ...(ctx.rejectedNegotiationCount\n ? [\n \"\",\n \"## Private aggregate signal\",\n `Validated prior outcomes without an actionable connection: ${ctx.rejectedNegotiationCount}`,\n ]\n : []),\n \"\",\n \"## Your task\",\n \"Ask at most one direct question whose answer would materially refine this intent.\",\n \"Do not narrate discovery outcomes or internal process state in the question.\",\n \"Return an empty `questions` array when no safe useful axis is missing.\",\n ].join(\"\\n\");\n}\n\n// ─── Profile preset ─────────────────────────────────────────────────────────\n\nconst PROFILE_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has a profile that is incomplete. Your job: surface the minimum set of structured questions that fill the identified gaps — asking about location, skills, interests, current work, or goals — so the protocol can run better discovery on their behalf.\n\nThe user may already have premises — atomic self-descriptions they have stated. These cover specific profile domains. Do not ask about domains already addressed by existing premises. Focus only on gaps not covered by any premise.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing piece of profile data (location, current role, skills, interests, goals, availability, …).\n- refine_intent: ask the user to clarify or sharpen an existing profile signal so candidates can be ranked more accurately.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the profile data shown.\n2. The answer is not already covered by an existing premise listed below the profile.\n3. The answer would meaningfully change which opportunities surface for this user.\n4. The question targets a different profile domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the profile signal or gap being clarified in the question text itself, using concise plain language from the current profile, existing premises, or identified gaps. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"What kind of role are you looking for?\"\n- Good: \"To improve matches from your founder/operator profile, what kind of role are you looking for?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the profile domain. Examples: \"Location\", \"Role\", \"Skills\", \"Goals\", \"Interests\", \"Availability\", \"Stage\".\n\nAnti-patterns — never do these.\n- Don't ask about fields already filled in the profile.\n- Don't ask about information already captured in an existing premise.\n- Don't ask procedural confirmations (\"Should I update your profile?\").\n- Don't ask vague introspective questions (\"Who are you really?\").\n- Don't re-ask for facts visible anywhere in the profile data or premises shown.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the profile is already complete enough for discovery, return \"questions\": [].`;\n\n/**\n * Build the user message for the profile preset from a ProfileContext.\n * @param ctx - The profile context including current profile data and identified gaps.\n * @returns The assembled user message string.\n */\nfunction buildProfilePrompt(ctx: ProfileContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const premisesBlock =\n ctx.existingPremises && ctx.existingPremises.length > 0\n ? ctx.existingPremises.map((p, i) => `${i + 1}. ${p}`).join(\"\\n\")\n : \"(none)\";\n\n const gapsBlock = ctx.gaps.length > 0 ? ctx.gaps.join(\", \") : \"(none identified)\";\n\n const parts: string[] = [\n \"## Current profile\",\n profileBlock,\n \"\",\n \"## Existing premises\",\n premisesBlock,\n \"\",\n \"## Identified gaps\",\n gapsBlock,\n \"\",\n ];\n\n parts.push(\n \"## Your task\",\n \"Generate the minimum set of questions needed to fill the identified gaps.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the profile is already complete enough.\",\n );\n\n return parts.join(\"\\n\");\n}\n\n// ─── Negotiation preset ──────────────────────────────────────────────────────\n\nconst NEGOTIATION_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. You generate negotiation-mode questions for one of two purposes described in the user message.\n\nPOST-STALL purpose. A negotiation between this user and another person ended without a clear outcome — either the turn budget was exhausted, the session timed out, or conversation stalled. Surface the minimum set of structured questions that help the user provide the missing signal needed to unblock or refine the next discovery attempt.\n\nUPTAKE purpose. The user is considering accepting a proposed connection, but one preparatory condition about the other person's practical ability, resources, availability, or authority to carry out the proposed activity needs clarification before commitment. Generate exactly ONE neutral question that lets the user decide whether they understand that condition well enough to proceed. Ask about the concrete activity and refer to the other participant generically; do not accuse, challenge credibility, presume incapability, or invent/repeat profile attributes. Never reveal a numeric authority score, threshold, felicity label, evaluator judgment, or any internal matching/verification mechanics. Do not ask whether the user wants to accept; clarify the preparatory condition only.\n\nYou may pick from three strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: help the user sharpen their underlying signal based on what the negotiation revealed (scope, scale, priority, direction).\n- surface_missing_detail: ask for one concrete piece of information that was absent and would have moved the negotiation forward (timeline, budget, format, constraints, decision criteria, …).\n- reflective_summary: mirror the key takeaway from the negotiation and ask the user to confirm, correct, or decide — useful when the conversation revealed partial signal worth locking in.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the negotiation context or user profile shown.\n2. The answer would materially change how the next attempt surfaces or engages candidates.\n3. The question targets a different decision domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the user's own underlying goal or topic and, only when supplied as a source-safe label, the relevant community in the question text itself. Never infer or repeat counterparty identity/profile, private transcript, evaluator reasoning, match reasons, event/community attendance, or internal IDs/metadata. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"Which role is a better fit for your immediate needs?\"\n- Good: \"For your search for AI infrastructure collaborators in the AI founders community, what kind of working relationship fits your immediate needs?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. For POST-STALL, default one question and add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. For UPTAKE, return exactly one question — never zero and never more than one.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Scope\", \"Timeline\", \"Budget\", \"Priority\", \"Format\", \"Stance\", \"Criteria\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I try again?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n- Don't ask about hypothetical edge cases not implied by the negotiation context.\n\nOutput. For POST-STALL, return at most 2 entries and return \"questions\": [] if the context already contains enough signal to proceed. For UPTAKE, return exactly 1 entry. Every entry must include a \"strategy\" field (one of the three values above). QUD metadata is orthogonal to uptake purpose: an uptake question is usually not an underspecification repair, so set \\`underspecificationType\\` to null unless the question genuinely repairs a missing constituent, missing constraint, or open alternative set.`;\n\n/**\n * Build the user message for the negotiation preset from a NegotiationContext.\n * @param ctx - The negotiation context including counterparty hint, stall reason, and key takeaway.\n * @returns The assembled user message string.\n */\nfunction buildPostStallNegotiationPrompt(ctx: PostStallNegotiationContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n return [\n \"## Purpose\",\n \"POST-STALL\",\n \"\",\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Other participant: ${ctx.counterpartyHint}`,\n `Stall reason: ${ctx.outcomeReason}`,\n \"\",\n \"## Recipient's own signal\",\n ctx.recipientIntent,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to unblock the next discovery attempt.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the context already contains enough signal to proceed.\",\n ].join(\"\\n\");\n}\n\nfunction buildUptakeNegotiationPrompt(ctx: UptakeNegotiationContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n return [\n \"## Purpose\",\n \"UPTAKE — preparatory-condition clarification before acceptance\",\n \"\",\n \"## Proposed activity\",\n ctx.proposedActivity,\n \"\",\n \"## Other person\",\n ctx.counterpartyHint,\n \"\",\n \"## Community\",\n ctx.indexContext,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Generate exactly one neutral, referentially closed question about whether the other person can practically carry out the proposed activity.\",\n \"Do not expose scores, thresholds, labels, or internal mechanics. Do not ask for acceptance itself.\",\n \"Set `underspecificationType` to null unless this is genuinely a QUD underspecification repair.\",\n ].join(\"\\n\");\n}\n\nfunction buildNegotiationPrompt(ctx: NegotiationContext): string {\n return ctx.purpose === \"uptake\"\n ? buildUptakeNegotiationPrompt(ctx)\n : buildPostStallNegotiationPrompt(ctx);\n}\n\n// ─── Chat preset ─────────────────────────────────────────────────────────\n\nconst NEGOTIATION_INFLIGHT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user's own negotiator agent is MID-NEGOTIATION on their behalf and has paused: before continuing, it needs a decision or missing input from its client — most often permission to disclose a specific piece of information to the other side. The negotiation is WAITING until the user answers. Your job: turn the negotiator's stated need (and its draft question, when provided) into the minimum set of crisp, structured decision questions.\n\nBias toward disclosure gating. The most common question shape is \"may I share X with this person?\" — an enable/disable decision about revealing specific information. Phrase these as a clear yes/no choice: the first option authorizes sharing, the second declines. State in each option's description what the negotiator will DO next (share and continue, or continue without revealing it). When the need is a missing fact rather than a permission, ask for that concrete input instead.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing input the negotiator needs to proceed (a fact, constraint, preference, or bound the client never stated).\n- reflective_summary: put a disclosure or stance decision in front of the client to confirm or decline — the enable/disable gate described above.\n\nHonor the negotiator's intent. When a draft question is provided, treat it as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions. Do not invent questions about topics the negotiator did not raise. When no draft is provided, derive the question strictly from the disclosure subject.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. The user may see this question hours later in an inbox, away from any negotiation view. Include the disclosure subject and the generic phrase \"the other participant in this match\" in the question text itself. Never repeat or infer counterparty identity/profile, private transcript, evaluator reasoning, match reasons, event/community attendance, or internal IDs/metadata. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text.\n- Bad: \"May I share your budget with Alex, a Berlin-based founder from the event?\"\n- Good: \"May I share your budget range with the other participant in this match?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nException — describing the other side. This question may refer to the other participant generically because it is tied to one exact server-validated opportunity. Do not add attributes, identity, or claims about why they matched.\n\nCardinality. Default one question. Add a second ONLY when the negotiator's need genuinely spans two distinct decisions (e.g. one disclosure gate plus one missing fact). Never pad.\n\nOption construction. Each option must represent a meaningfully different outcome. For disclosure gates: authorize first, decline second; suffix the safer or more common path with \" (Recommended)\" and list it first when one clearly is. The description states the CONSEQUENCE for the negotiation — what the negotiator does next. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically, which also lets the user add nuance (\"share the range but not the exact figure\").\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Disclosure\", \"Budget\", \"Timing\", \"Intro\", \"Scope\", \"Contact\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I keep negotiating?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't broaden beyond the negotiator's stated disclosure subject or draft.\n- Don't reveal the counterparty's identity — attributes only.\n- Don't ask vague introspective questions.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the profile or context shown already answers the negotiator's need, return \"questions\": [].`;\n\n/**\n * Build the user message for the negotiation-inflight preset from a NegotiationInflightContext.\n * @param ctx - The inflight context: disclosure subject, counterparty hint, optional draft, community, user context.\n * @returns The assembled user message string.\n */\nfunction buildNegotiationInflightPrompt(ctx: NegotiationInflightContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftBlock = ctx.draftQuestion?.trim()\n ? ctx.draftQuestion.trim()\n : \"(none — derive the question from the disclosure subject)\";\n\n return [\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Counterparty: ${ctx.counterpartyHint}`,\n \"\",\n \"## What the negotiator needs from its client\",\n ctx.disclosureSubject,\n \"\",\n \"## Draft question proposed by the negotiator\",\n draftBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the negotiator the permission or input it needs to continue.\",\n \"Honor the draft when provided; refine its wording and options rather than replacing its topic.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\nconst CHAT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The protocol's chat orchestrator is mid-conversation with the user and has decided it needs a decision or missing input from them before it can continue. The conversation is PAUSED until the user answers. Your job: turn the orchestrator's stated need (and any draft questions it proposed) into the minimum set of crisp, structured decision questions.\n\nUnlike other question surfaces, these questions render INLINE in the active conversation, immediately after the assistant's last message — the user has full conversational context. Still keep each prompt self-contained enough to make sense on its own line.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing input the orchestrator needs to proceed (scope, timing, budget, format, preference, constraint, …).\n- refine_intent: ask the user to choose a direction when the orchestrator faces meaningfully different paths forward.\n\nHonor the orchestrator's intent. When draft questions are provided, treat them as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions, and drop redundant drafts. Do not invent questions about topics the orchestrator did not raise. When no drafts are provided, derive questions strictly from the stated purpose.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the conversation excerpt or user profile shown.\n2. The answer materially changes what the orchestrator does next.\n3. The question targets a different decision domain from any other question in this batch.\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Emit a second or third ONLY when the orchestrator's purpose or drafts genuinely require separate decisions in distinct domains. Never pad.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option for what happens next in the conversation, not its definition. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Direction\", \"Scope\", \"Timing\", \"Budget\", \"Format\", \"Priority\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I continue?\", \"Is that OK?\").\n- Don't re-ask for facts visible in the conversation excerpt or user profile.\n- Don't broaden beyond the orchestrator's stated purpose.\n- Don't ask vague introspective questions.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the purpose is already answerable from the context shown, return \"questions\": [].`;\n\n/**\n * Build the user message for the chat preset from a ChatContext.\n * @param ctx - The chat context: orchestrator purpose, optional drafts, conversation excerpt, user context.\n * @returns The assembled user message string.\n */\nfunction buildChatPrompt(ctx: ChatContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftsBlock =\n ctx.draftQuestions && ctx.draftQuestions.length > 0\n ? ctx.draftQuestions\n .map((d, i) => {\n const opts = d.options && d.options.length > 0 ? ` [options: ${d.options.join(\" | \")}]` : \"\";\n const multi = d.multiSelect ? \" [multi-select]\" : \"\";\n return `${i + 1}. ${d.prompt}${opts}${multi}`;\n })\n .join(\"\\n\")\n : \"(none — derive questions from the purpose)\";\n\n const excerptBlock = ctx.conversationExcerpt?.trim()\n ? ctx.conversationExcerpt.trim()\n : \"(not available)\";\n\n return [\n \"## What the orchestrator needs to learn\",\n ctx.purpose,\n \"\",\n \"## Draft questions proposed by the orchestrator\",\n draftsBlock,\n \"\",\n \"## Recent conversation excerpt\",\n excerptBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the orchestrator the decision or input it needs.\",\n \"Honor the drafts when provided; refine their wording and options rather than replacing their topics.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\n/**\n * pool_discovery has NO preset by design: those questions are synthesized\n * deterministically from mined discriminators (see\n * `opportunity/discriminator/discriminator.question.ts`) and never reach the\n * QuestionerAgent. `getPreset(\"pool_discovery\")` therefore throws — the\n * QuestionerQueue branches on the mode before invoking the agent.\n */\nfunction withQudMetadataRules(systemPrompt: string): string {\n return `${systemPrompt}\\n\\n${QUD_UNDERSPECIFICATION_RULES}`;\n}\n\nconst presets: Partial<Record<QuestionMode, QuestionerPreset>> = {\n discovery: {\n systemPrompt: withQudMetadataRules(DISCOVERY_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) =>\n buildDiscoveryQuestionPrompt(context as Parameters<typeof buildDiscoveryQuestionPrompt>[0]),\n },\n intent: {\n systemPrompt: withQudMetadataRules(INTENT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildIntentPrompt(context as IntentContext),\n },\n enrichment: {\n systemPrompt: withQudMetadataRules(PROFILE_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildProfilePrompt(context as ProfileContext),\n },\n negotiation: {\n systemPrompt: withQudMetadataRules(NEGOTIATION_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildNegotiationPrompt(context as NegotiationContext),\n },\n negotiation_inflight: {\n systemPrompt: withQudMetadataRules(NEGOTIATION_INFLIGHT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildNegotiationInflightPrompt(context as NegotiationInflightContext),\n },\n chat: {\n systemPrompt: withQudMetadataRules(CHAT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildChatPrompt(context as ChatContext),\n },\n};\n\n/**\n * Retrieve the preset for the given mode.\n * @param mode - The question mode to look up.\n * @returns The matching preset with systemPrompt and buildPrompt.\n * @throws Error if the mode's preset is not yet implemented.\n */\nexport function getPreset(mode: QuestionMode, purpose?: QuestionPurpose): QuestionerPreset {\n if (mode === \"intent\" && purpose === \"recovery\") {\n return {\n systemPrompt: withQudMetadataRules(RECOVERY_INTENT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildRecoveryIntentPrompt(context as RecoveryIntentContext),\n };\n }\n const preset = presets[mode];\n if (!preset) {\n throw new Error(`QuestionerAgent preset \"${mode}\" is not implemented yet`);\n }\n return preset;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"questioner.presets.js","sourceRoot":"/","sources":["questioner/questioner.presets.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mode presets for the QuestionerAgent. Each preset provides a system prompt\n * and a buildPrompt function that assembles the user message from a typed\n * context object. Only the `discovery` preset ships in Slice 1; others throw\n * until their implementation slices land.\n */\nimport type { QuestionMode, QuestionPurpose } from \"../shared/schemas/question.schema.js\";\nimport { DISCOVERY_SYSTEM_PROMPT, buildDiscoveryQuestionPrompt } from \"./questioner.discovery.prompt.js\";\n\nimport { QUD_UNDERSPECIFICATION_RULES } from \"./questioner.qud.js\";\nimport type { ChatContext, IntentContext, NegotiationContext, NegotiationInflightContext, PostStallNegotiationContext, ProfileContext, RecoveryIntentContext, UptakeNegotiationContext } from \"./questioner.types.js\";\n\n/**\n * Shared rule block appended to every questioner system prompt. Enforces that\n * the generated `prompt` resolves on its own — no demonstratives/anaphora that\n * point at people, events, or prior turns the reader cannot see — and never\n * narrates Index's own matching pipeline. Closes the referential-leak class\n * surfaced in digest audits (\"…with these builders?\", \"the previous\n * negotiation stalled because the counterparty didn't mention …\").\n */\nconst REFERENTIAL_CLOSURE_RULES = `Referential 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 counterparty, 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: \"The previous negotiation stalled because the counterparty didn't mention 'matchmaking'. Should I broaden the search?\"\n- Good: \"Do you want to focus on dedicated matchmakers, or also people interested in relationships more broadly?\"`;\n\nexport interface QuestionerPreset {\n /** The LLM system prompt for this mode. */\n systemPrompt: string;\n /** Builds the user-message string from the mode-specific context. */\n buildPrompt: (context: unknown) => string;\n}\n\n/**\n * Renders the user-context block shared by every preset's user message from the\n * global user_context paragraph (the profile-replacing identity text).\n * @param userContext - The user's global context paragraph, if available.\n * @returns The trimmed context paragraph, or \"(no profile data)\" when empty.\n */\nfunction buildUserContextBlock(userContext?: string): string {\n const trimmed = userContext?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : \"(no profile data)\";\n}\n\n// ─── Intent preset ──────────────────────────────────────────────────────────\n\nconst INTENT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has stated an intent — what they are looking for. Your job: surface the minimum set of structured questions that help the user sharpen that intent before the protocol runs discovery on their behalf.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: ask the user to sharpen or pivot the core signal (scope, scale, specificity, direction).\n- surface_missing_detail: ask for one concrete missing input that would change which candidates surface (stage, location, timing, budget, constraints, format, …).\n\nAsk a question only when ALL of these hold:\n1. The agent cannot infer the answer from the intent text or user profile already shown.\n2. The answer would materially change which candidates surface.\n3. The question targets a different decision domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the source intent/topic in the question text itself, using concise plain language from the intent or summary. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"What kind of collaboration are you looking for?\"\n- Good: \"For your decentralized identity protocol-design search, what kind of collaboration are you looking for?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ (different titles).\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Stage\", \"Timing\", \"Location\", \"Scope\", \"Budget\", \"Format\", \"Skills\", \"Collab\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I start searching?\").\n- Don't ask about hypothetical edge cases not implied by the intent.\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the intent is already specific enough, return \"questions\": [].`;\n\n/**\n * Build the user message for the intent preset from an IntentContext.\n * @param ctx - The intent context.\n * @returns The assembled user message string.\n */\nfunction buildIntentPrompt(ctx: IntentContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const summaryBlock = ctx.summary ? ctx.summary : \"(no summary available)\";\n\n return [\n \"## Intent\",\n ctx.payload,\n \"\",\n \"## Summary\",\n summaryBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to sharpen this intent.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the intent is already specific enough.\",\n ].join(\"\\n\");\n}\n\nconst RECOVERY_INTENT_SYSTEM_PROMPT = `You help a user materially refine one of their own discovery signals. Ask directly about the user's goal, desired counterpart attributes, or constraints. Never describe internal processing or imply that any specific person was reviewed.\n\nChoose exactly one of these strategies:\n- refine_intent: sharpen or pivot the core signal in a way that changes who should surface.\n- surface_missing_detail: ask for one concrete missing constraint such as stage, location, timing, budget, format, or required capability.\n\nAsk a question only when the answer is not already inferable from the intent, summary, or user profile and would materially change discovery. If no safe, useful missing axis exists, return an empty questions array.\n\nStandalone prompt rule. The prompt must identify the user's intent topic in plain language and ask about their own goal or constraints. It must make sense without UI labels or hidden metadata.\n\n${REFERENTIAL_CLOSURE_RULES}\n\nPrivacy and process boundary. You may receive only a bounded aggregate count of validated prior outcomes. Use it solely as a weak signal to choose a missing axis. Never mention or imply counts, matches, no matches, rejections, negotiations, candidates, counterparties, searches, retries, pipeline state, evidence, or what another person did or did not say. Never invent people or facts.\n\nCardinality. Return at most ONE question. Use only refine_intent or surface_missing_detail. The question must nudge a material edit, not ask whether to search again.\n\nOption construction. Provide 2–4 materially different outcomes. Put the safest or most common path first with \" (Recommended)\" when appropriate. Descriptions state the discovery consequence. Never add an Other option.\n\nTitle rules. ≤12 chars and name the decision domain, such as Scope, Timing, Location, Stage, Budget, Format, or Skills.\n\nOutput. Return zero or one question. Set underspecificationType to the applicable QUD category, or null when none applies.`;\n\nfunction buildRecoveryIntentPrompt(ctx: RecoveryIntentContext): string {\n return [\n \"## Intent\",\n ctx.payload,\n \"\",\n \"## Summary\",\n ctx.summary?.trim() || \"(no summary available)\",\n \"\",\n \"## User profile\",\n buildUserContextBlock(ctx.userContext),\n ...(ctx.rejectedNegotiationCount\n ? [\n \"\",\n \"## Private aggregate signal\",\n `Validated prior outcomes without an actionable connection: ${ctx.rejectedNegotiationCount}`,\n ]\n : []),\n \"\",\n \"## Your task\",\n \"Ask at most one direct question whose answer would materially refine this intent.\",\n \"Do not narrate discovery outcomes or internal process state in the question.\",\n \"Return an empty `questions` array when no safe useful axis is missing.\",\n ].join(\"\\n\");\n}\n\n// ─── Profile preset ─────────────────────────────────────────────────────────\n\nconst PROFILE_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user has a profile that is incomplete. Your job: surface the minimum set of structured questions that fill the identified gaps — asking about location, skills, interests, current work, or goals — so the protocol can run better discovery on their behalf.\n\nThe user may already have premises — atomic self-descriptions they have stated. These cover specific profile domains. Do not ask about domains already addressed by existing premises. Focus only on gaps not covered by any premise.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing piece of profile data (location, current role, skills, interests, goals, availability, …).\n- refine_intent: ask the user to clarify or sharpen an existing profile signal so candidates can be ranked more accurately.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the profile data shown.\n2. The answer is not already covered by an existing premise listed below the profile.\n3. The answer would meaningfully change which opportunities surface for this user.\n4. The question targets a different profile domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the profile signal or gap being clarified in the question text itself, using concise plain language from the current profile, existing premises, or identified gaps. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"What kind of role are you looking for?\"\n- Good: \"To improve matches from your founder/operator profile, what kind of role are you looking for?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. Never ask two questions of the same strategy unless their decision domains differ.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the profile domain. Examples: \"Location\", \"Role\", \"Skills\", \"Goals\", \"Interests\", \"Availability\", \"Stage\".\n\nAnti-patterns — never do these.\n- Don't ask about fields already filled in the profile.\n- Don't ask about information already captured in an existing premise.\n- Don't ask procedural confirmations (\"Should I update your profile?\").\n- Don't ask vague introspective questions (\"Who are you really?\").\n- Don't re-ask for facts visible anywhere in the profile data or premises shown.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the profile is already complete enough for discovery, return \"questions\": [].`;\n\n/**\n * Build the user message for the profile preset from a ProfileContext.\n * @param ctx - The profile context including current profile data and identified gaps.\n * @returns The assembled user message string.\n */\nfunction buildProfilePrompt(ctx: ProfileContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const premisesBlock =\n ctx.existingPremises && ctx.existingPremises.length > 0\n ? ctx.existingPremises.map((p, i) => `${i + 1}. ${p}`).join(\"\\n\")\n : \"(none)\";\n\n const gapsBlock = ctx.gaps.length > 0 ? ctx.gaps.join(\", \") : \"(none identified)\";\n\n const parts: string[] = [\n \"## Current profile\",\n profileBlock,\n \"\",\n \"## Existing premises\",\n premisesBlock,\n \"\",\n \"## Identified gaps\",\n gapsBlock,\n \"\",\n ];\n\n parts.push(\n \"## Your task\",\n \"Generate the minimum set of questions needed to fill the identified gaps.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the profile is already complete enough.\",\n );\n\n return parts.join(\"\\n\");\n}\n\n// ─── Negotiation preset ──────────────────────────────────────────────────────\n\nconst NEGOTIATION_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. You generate negotiation-mode questions for one of two purposes described in the user message.\n\nPOST-STALL purpose. A negotiation between this user and another person ended without a clear outcome — either the turn budget was exhausted, the session timed out, or conversation stalled. Surface the minimum set of structured questions that help the user provide the missing signal needed to unblock or refine the next discovery attempt.\n\nUPTAKE purpose. The user is considering accepting a proposed connection, but one preparatory condition about the other person's practical ability, resources, availability, or authority to carry out the proposed activity needs clarification before commitment. Generate exactly ONE neutral question that lets the user decide whether they understand that condition well enough to proceed. Ask about the concrete activity and refer to the other participant generically; do not accuse, challenge credibility, presume incapability, or invent/repeat profile attributes. Never reveal a numeric authority score, threshold, felicity label, evaluator judgment, or any internal matching/verification mechanics. Do not ask whether the user wants to accept; clarify the preparatory condition only.\n\nYou may pick from three strategies. Choose contextually; mix only when each question is genuinely distinct.\n- refine_intent: help the user sharpen their underlying signal based on what the negotiation revealed (scope, scale, priority, direction).\n- surface_missing_detail: ask for one concrete piece of information that was absent and would have moved the negotiation forward (timeline, budget, format, constraints, decision criteria, …).\n- reflective_summary: mirror the key takeaway from the negotiation and ask the user to confirm, correct, or decide — useful when the conversation revealed partial signal worth locking in.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the negotiation context or user profile shown.\n2. The answer would materially change how the next attempt surfaces or engages candidates.\n3. The question targets a different decision domain from any other question in this batch.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the user's own underlying goal or topic and, only when supplied as a source-safe label, the relevant community in the question text itself. Never infer or repeat counterparty identity/profile, private transcript, evaluator reasoning, match reasons, event/community attendance, or internal IDs/metadata. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about.\n- Bad: \"Which role is a better fit for your immediate needs?\"\n- Good: \"For your search for AI infrastructure collaborators in the AI founders community, what kind of working relationship fits your immediate needs?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. For POST-STALL, default one question and add a second only when a DIFFERENT strategy genuinely complements the first and unblocks a clearly distinct decision. For UPTAKE, return exactly one question — never zero and never more than one.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common 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.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Scope\", \"Timeline\", \"Budget\", \"Priority\", \"Format\", \"Stance\", \"Criteria\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I try again?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't ask vague introspective questions (\"What do you really want?\").\n- Don't ask about hypothetical edge cases not implied by the negotiation context.\n\nOutput. For POST-STALL, return at most 2 entries and return \"questions\": [] if the context already contains enough signal to proceed. For UPTAKE, return exactly 1 entry. Every entry must include a \"strategy\" field (one of the three values above). QUD metadata is orthogonal to uptake purpose: an uptake question is usually not an underspecification repair, so set \\`underspecificationType\\` to null unless the question genuinely repairs a missing constituent, missing constraint, or open alternative set.`;\n\n/**\n * Build the user message for the negotiation preset from a NegotiationContext.\n * @param ctx - The negotiation context including counterparty hint, stall reason, and key takeaway.\n * @returns The assembled user message string.\n */\nfunction buildPostStallNegotiationPrompt(ctx: PostStallNegotiationContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n return [\n \"## Purpose\",\n \"POST-STALL\",\n \"\",\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Other participant: ${ctx.counterpartyHint}`,\n `Stall reason: ${ctx.outcomeReason}`,\n \"\",\n \"## Recipient's own signal\",\n ctx.recipientIntent,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of questions the user must answer to unblock the next discovery attempt.\",\n \"Apply every rule from your system prompt before outputting.\",\n \"Return an empty `questions` array if the context already contains enough signal to proceed.\",\n ].join(\"\\n\");\n}\n\nfunction buildUptakeNegotiationPrompt(ctx: UptakeNegotiationContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n return [\n \"## Purpose\",\n \"UPTAKE — preparatory-condition clarification before acceptance\",\n \"\",\n \"## Proposed activity\",\n ctx.proposedActivity,\n \"\",\n \"## Other person\",\n ctx.counterpartyHint,\n \"\",\n \"## Community\",\n ctx.indexContext,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Generate exactly one neutral, referentially closed question about whether the other person can practically carry out the proposed activity.\",\n \"Do not expose scores, thresholds, labels, or internal mechanics. Do not ask for acceptance itself.\",\n \"Set `underspecificationType` to null unless this is genuinely a QUD underspecification repair.\",\n ].join(\"\\n\");\n}\n\nfunction buildNegotiationPrompt(ctx: NegotiationContext): string {\n return ctx.purpose === \"uptake\"\n ? buildUptakeNegotiationPrompt(ctx)\n : buildPostStallNegotiationPrompt(ctx);\n}\n\n// ─── Chat preset ─────────────────────────────────────────────────────────\n\nconst NEGOTIATION_INFLIGHT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The user's own negotiator agent is MID-NEGOTIATION on their behalf and has paused: before continuing, it needs a decision or missing input from its client — most often permission to disclose a specific piece of information to the other side. The negotiation is WAITING until the user answers. Your job: turn the negotiator's stated need (and its draft question, when provided) into the minimum set of crisp, structured decision questions.\n\nBias toward disclosure gating. The most common question shape is \"may I share X with this person?\" — an enable/disable decision about revealing specific information. Phrase these as a clear yes/no choice: the first option authorizes sharing, the second declines. State in each option's description what the negotiator will DO next (share and continue, or continue without revealing it). When the need is a missing fact rather than a permission, ask for that concrete input instead.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing input the negotiator needs to proceed (a fact, constraint, preference, or bound the client never stated).\n- reflective_summary: put a disclosure or stance decision in front of the client to confirm or decline — the enable/disable gate described above.\n\nHonor the negotiator's intent. When a draft question is provided, treat it as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions. Do not invent questions about topics the negotiator did not raise. When no draft is provided, derive the question strictly from the disclosure subject.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. The user may see this question hours later in an inbox, away from any negotiation view. Include the disclosure subject and the generic phrase \"the other participant in this match\" in the question text itself. Never repeat or infer counterparty identity/profile, private transcript, evaluator reasoning, match reasons, event/community attendance, or internal IDs/metadata. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text.\n- Bad: \"May I share your budget with Alex, a Berlin-based founder from the event?\"\n- Good: \"May I share your budget range with the other participant in this match?\"\n\n${REFERENTIAL_CLOSURE_RULES}\n\nException — describing the other side. This question may refer to the other participant generically because it is tied to one exact server-validated opportunity. Do not add attributes, identity, or claims about why they matched.\n\nCardinality. Default one question. Add a second ONLY when the negotiator's need genuinely spans two distinct decisions (e.g. one disclosure gate plus one missing fact). Never pad.\n\nOption construction. Each option must represent a meaningfully different outcome. For disclosure gates: authorize first, decline second; suffix the safer or more common path with \" (Recommended)\" and list it first when one clearly is. The description states the CONSEQUENCE for the negotiation — what the negotiator does next. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically, which also lets the user add nuance (\"share the range but not the exact figure\").\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Disclosure\", \"Budget\", \"Timing\", \"Intro\", \"Scope\", \"Contact\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I keep negotiating?\").\n- Don't re-ask for facts already visible in the user profile.\n- Don't broaden beyond the negotiator's stated disclosure subject or draft.\n- Don't reveal the counterparty's identity — attributes only.\n- Don't ask vague introspective questions.\n\nOutput. Return at most 2 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the profile or context shown already answers the negotiator's need, return \"questions\": [].`;\n\n/**\n * Build the user message for the negotiation-inflight preset from a NegotiationInflightContext.\n * @param ctx - The inflight context: disclosure subject, counterparty hint, optional draft, community, user context.\n * @returns The assembled user message string.\n */\nfunction buildNegotiationInflightPrompt(ctx: NegotiationInflightContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftBlock = ctx.draftQuestion?.trim()\n ? ctx.draftQuestion.trim()\n : \"(none — derive the question from the disclosure subject)\";\n\n return [\n \"## Negotiation context\",\n `Community: ${ctx.indexContext}`,\n `Counterparty: ${ctx.counterpartyHint}`,\n \"\",\n \"## What the negotiator needs from its client\",\n ctx.disclosureSubject,\n \"\",\n \"## Draft question proposed by the negotiator\",\n draftBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the negotiator the permission or input it needs to continue.\",\n \"Honor the draft when provided; refine its wording and options rather than replacing its topic.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\nconst CHAT_SYSTEM_PROMPT = `You sit between a human and a discovery protocol. The protocol's chat orchestrator is mid-conversation with the user and has decided it needs a decision or missing input from them before it can continue. The conversation is PAUSED until the user answers. Your job: turn the orchestrator's stated need (and any draft questions it proposed) into the minimum set of crisp, structured decision questions.\n\nUnlike other question surfaces, these questions render INLINE in the active conversation, immediately after the assistant's last message — the user has full conversational context. Still keep each prompt self-contained enough to make sense on its own line.\n\nYou may pick from two strategies. Choose contextually; mix only when each question is genuinely distinct.\n- surface_missing_detail: ask for one concrete missing input the orchestrator needs to proceed (scope, timing, budget, format, preference, constraint, …).\n- refine_intent: ask the user to choose a direction when the orchestrator faces meaningfully different paths forward.\n\nHonor the orchestrator's intent. When draft questions are provided, treat them as the source of truth for WHAT to ask — improve wording, tighten options, add consequence-focused descriptions, and drop redundant drafts. Do not invent questions about topics the orchestrator did not raise. When no drafts are provided, derive questions strictly from the stated purpose.\n\nAsk a question only when ALL of these hold:\n1. The answer is not already visible in the conversation excerpt or user profile shown.\n2. The answer materially changes what the orchestrator does next.\n3. The question targets a different decision domain from any other question in this batch.\n\n${REFERENTIAL_CLOSURE_RULES}\n\nCardinality. Default one question. Emit a second or third ONLY when the orchestrator's purpose or drafts genuinely require separate decisions in distinct domains. Never pad.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest or most common path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option for what happens next in the conversation, not its definition. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Examples: \"Direction\", \"Scope\", \"Timing\", \"Budget\", \"Format\", \"Priority\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I continue?\", \"Is that OK?\").\n- Don't re-ask for facts visible in the conversation excerpt or user profile.\n- Don't broaden beyond the orchestrator's stated purpose.\n- Don't ask vague introspective questions.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the two values above). If the purpose is already answerable from the context shown, return \"questions\": [].`;\n\n/**\n * Build the user message for the chat preset from a ChatContext.\n * @param ctx - The chat context: orchestrator purpose, optional drafts, conversation excerpt, user context.\n * @returns The assembled user message string.\n */\nfunction buildChatPrompt(ctx: ChatContext): string {\n const profileBlock = buildUserContextBlock(ctx.userContext);\n\n const draftsBlock =\n ctx.draftQuestions && ctx.draftQuestions.length > 0\n ? ctx.draftQuestions\n .map((d, i) => {\n const opts = d.options && d.options.length > 0 ? ` [options: ${d.options.join(\" | \")}]` : \"\";\n const multi = d.multiSelect ? \" [multi-select]\" : \"\";\n return `${i + 1}. ${d.prompt}${opts}${multi}`;\n })\n .join(\"\\n\")\n : \"(none — derive questions from the purpose)\";\n\n const excerptBlock = ctx.conversationExcerpt?.trim()\n ? ctx.conversationExcerpt.trim()\n : \"(not available)\";\n\n return [\n \"## What the orchestrator needs to learn\",\n ctx.purpose,\n \"\",\n \"## Draft questions proposed by the orchestrator\",\n draftsBlock,\n \"\",\n \"## Recent conversation excerpt\",\n excerptBlock,\n \"\",\n \"## User profile\",\n profileBlock,\n \"\",\n \"## Your task\",\n \"Produce the minimum set of structured questions that get the orchestrator the decision or input it needs.\",\n \"Honor the drafts when provided; refine their wording and options rather than replacing their topics.\",\n \"Apply every rule from your system prompt before outputting.\",\n ].join(\"\\n\");\n}\n\n/**\n * pool_discovery has NO preset by design: those questions are synthesized\n * deterministically from mined discriminators (see\n * `opportunity/discriminator/discriminator.question.ts`) and never reach the\n * QuestionerAgent. `getPreset(\"pool_discovery\")` therefore throws — the\n * QuestionerQueue branches on the mode before invoking the agent.\n */\nfunction withQudMetadataRules(systemPrompt: string): string {\n return `${systemPrompt}\\n\\n${QUD_UNDERSPECIFICATION_RULES}`;\n}\n\nconst presets: Partial<Record<QuestionMode, QuestionerPreset>> = {\n discovery: {\n systemPrompt: withQudMetadataRules(DISCOVERY_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) =>\n buildDiscoveryQuestionPrompt(context as Parameters<typeof buildDiscoveryQuestionPrompt>[0]),\n },\n intent: {\n systemPrompt: withQudMetadataRules(INTENT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildIntentPrompt(context as IntentContext),\n },\n enrichment: {\n systemPrompt: withQudMetadataRules(PROFILE_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildProfilePrompt(context as ProfileContext),\n },\n negotiation: {\n systemPrompt: withQudMetadataRules(NEGOTIATION_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildNegotiationPrompt(context as NegotiationContext),\n },\n negotiation_inflight: {\n systemPrompt: withQudMetadataRules(NEGOTIATION_INFLIGHT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildNegotiationInflightPrompt(context as NegotiationInflightContext),\n },\n chat: {\n systemPrompt: withQudMetadataRules(CHAT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildChatPrompt(context as ChatContext),\n },\n};\n\n/**\n * Retrieve the preset for the given mode.\n * @param mode - The question mode to look up.\n * @returns The matching preset with systemPrompt and buildPrompt.\n * @throws Error if the mode's preset is not yet implemented.\n */\nexport function getPreset(mode: QuestionMode, purpose?: QuestionPurpose): QuestionerPreset {\n if (mode === \"intent\" && purpose === \"recovery\") {\n return {\n systemPrompt: withQudMetadataRules(RECOVERY_INTENT_SYSTEM_PROMPT),\n buildPrompt: (context: unknown) => buildRecoveryIntentPrompt(context as RecoveryIntentContext),\n };\n }\n const preset = presets[mode];\n if (!preset) {\n throw new Error(`QuestionerAgent preset \"${mode}\" is not implemented yet`);\n }\n return preset;\n}\n"]}
|
|
@@ -674,7 +674,7 @@ export declare const QuestionPoolPushRequestStatusSchema: z.ZodEnum<["requested"
|
|
|
674
674
|
export declare const QuestionRecoverySnapshotSchema: z.ZodObject<{
|
|
675
675
|
version: z.ZodLiteral<1>;
|
|
676
676
|
intentFingerprint: z.ZodString;
|
|
677
|
-
completionSource: z.ZodEnum<["from_intent", "discovery_run"]>;
|
|
677
|
+
completionSource: z.ZodEnum<["intent_creation", "from_intent", "discovery_run"]>;
|
|
678
678
|
/** Privacy-safe aggregate only; raw negotiation evidence is never persisted. */
|
|
679
679
|
rejectedNegotiationCount: z.ZodOptional<z.ZodNumber>;
|
|
680
680
|
/** Bounded internal correlation id for an asynchronous discovery run. */
|
|
@@ -682,13 +682,13 @@ export declare const QuestionRecoverySnapshotSchema: z.ZodObject<{
|
|
|
682
682
|
}, "strip", z.ZodTypeAny, {
|
|
683
683
|
version: 1;
|
|
684
684
|
intentFingerprint: string;
|
|
685
|
-
completionSource: "from_intent" | "discovery_run";
|
|
685
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
686
686
|
runId?: string | undefined;
|
|
687
687
|
rejectedNegotiationCount?: number | undefined;
|
|
688
688
|
}, {
|
|
689
689
|
version: 1;
|
|
690
690
|
intentFingerprint: string;
|
|
691
|
-
completionSource: "from_intent" | "discovery_run";
|
|
691
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
692
692
|
runId?: string | undefined;
|
|
693
693
|
rejectedNegotiationCount?: number | undefined;
|
|
694
694
|
}>;
|
|
@@ -999,7 +999,7 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
999
999
|
recovery: z.ZodOptional<z.ZodObject<{
|
|
1000
1000
|
version: z.ZodLiteral<1>;
|
|
1001
1001
|
intentFingerprint: z.ZodString;
|
|
1002
|
-
completionSource: z.ZodEnum<["from_intent", "discovery_run"]>;
|
|
1002
|
+
completionSource: z.ZodEnum<["intent_creation", "from_intent", "discovery_run"]>;
|
|
1003
1003
|
/** Privacy-safe aggregate only; raw negotiation evidence is never persisted. */
|
|
1004
1004
|
rejectedNegotiationCount: z.ZodOptional<z.ZodNumber>;
|
|
1005
1005
|
/** Bounded internal correlation id for an asynchronous discovery run. */
|
|
@@ -1007,13 +1007,13 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1007
1007
|
}, "strip", z.ZodTypeAny, {
|
|
1008
1008
|
version: 1;
|
|
1009
1009
|
intentFingerprint: string;
|
|
1010
|
-
completionSource: "from_intent" | "discovery_run";
|
|
1010
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
1011
1011
|
runId?: string | undefined;
|
|
1012
1012
|
rejectedNegotiationCount?: number | undefined;
|
|
1013
1013
|
}, {
|
|
1014
1014
|
version: 1;
|
|
1015
1015
|
intentFingerprint: string;
|
|
1016
|
-
completionSource: "from_intent" | "discovery_run";
|
|
1016
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
1017
1017
|
runId?: string | undefined;
|
|
1018
1018
|
rejectedNegotiationCount?: number | undefined;
|
|
1019
1019
|
}>>;
|
|
@@ -1100,7 +1100,7 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1100
1100
|
recovery?: {
|
|
1101
1101
|
version: 1;
|
|
1102
1102
|
intentFingerprint: string;
|
|
1103
|
-
completionSource: "from_intent" | "discovery_run";
|
|
1103
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
1104
1104
|
runId?: string | undefined;
|
|
1105
1105
|
rejectedNegotiationCount?: number | undefined;
|
|
1106
1106
|
} | undefined;
|
|
@@ -1194,7 +1194,7 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1194
1194
|
recovery?: {
|
|
1195
1195
|
version: 1;
|
|
1196
1196
|
intentFingerprint: string;
|
|
1197
|
-
completionSource: "from_intent" | "discovery_run";
|
|
1197
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
1198
1198
|
runId?: string | undefined;
|
|
1199
1199
|
rejectedNegotiationCount?: number | undefined;
|
|
1200
1200
|
} | undefined;
|
|
@@ -1288,7 +1288,7 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1288
1288
|
recovery?: {
|
|
1289
1289
|
version: 1;
|
|
1290
1290
|
intentFingerprint: string;
|
|
1291
|
-
completionSource: "from_intent" | "discovery_run";
|
|
1291
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
1292
1292
|
runId?: string | undefined;
|
|
1293
1293
|
rejectedNegotiationCount?: number | undefined;
|
|
1294
1294
|
} | undefined;
|
|
@@ -1382,7 +1382,7 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
|
|
|
1382
1382
|
recovery?: {
|
|
1383
1383
|
version: 1;
|
|
1384
1384
|
intentFingerprint: string;
|
|
1385
|
-
completionSource: "from_intent" | "discovery_run";
|
|
1385
|
+
completionSource: "intent_creation" | "from_intent" | "discovery_run";
|
|
1386
1386
|
runId?: string | undefined;
|
|
1387
1387
|
rejectedNegotiationCount?: number | undefined;
|
|
1388
1388
|
} | undefined;
|
|
@@ -235,7 +235,7 @@ export const QuestionPoolPushRequestStatusSchema = z.enum(["requested", "suppres
|
|
|
235
235
|
export const QuestionRecoverySnapshotSchema = z.object({
|
|
236
236
|
version: z.literal(1),
|
|
237
237
|
intentFingerprint: z.string().regex(/^[a-f0-9]{64}$/),
|
|
238
|
-
completionSource: z.enum(["from_intent", "discovery_run"]),
|
|
238
|
+
completionSource: z.enum(["intent_creation", "from_intent", "discovery_run"]),
|
|
239
239
|
/** Privacy-safe aggregate only; raw negotiation evidence is never persisted. */
|
|
240
240
|
rejectedNegotiationCount: z.number().int().min(1).max(50).optional(),
|
|
241
241
|
/** Bounded internal correlation id for an asynchronous discovery run. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.schema.js","sourceRoot":"/","sources":["shared/schemas/question.schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Question — public structured shape consumed by frontend renderers and MCP\n * elicitation dispatch. Mirrors the brainstorming AskUserQuestion skill so a\n * Question can be rendered identically across surfaces.\n *\n * `QuestionWithStrategy` extends the public shape with internal `strategy`\n * and QUD underspecification tags used by generator guardrails and persisted\n * metadata. Both tags are stripped before the public payload leaves the\n * generator — users never see them.\n */\nimport { z } from \"zod\";\n\nexport const QuestionOptionSchema = z.object({\n /** Display text. Suffix \" (Recommended)\" on the safest path; list it first. */\n label: z.string().min(1).max(120),\n /** Explains the consequence of choosing this option, not just its definition. */\n description: z.string().min(1).max(280),\n});\n\nexport const QuestionSchema = z.object({\n /** ≤12 chars. Noun of the decision domain — e.g. \"Stage\", \"Timing\", \"Role\". */\n title: z.string().min(1).max(12),\n /** ≤2 sentences, ≤400 chars. Ends in a question mark. */\n prompt: z.string().min(1).max(400),\n /** 2–4 options. No explicit \"Other\" — clients provide that automatically. */\n options: z.array(QuestionOptionSchema).min(2).max(4),\n /** True when options are not mutually exclusive (priorities, bundles). */\n multiSelect: z.boolean(),\n /**\n * Optional provenance line rendered as a muted chip above the prompt\n * (e.g. \"based on 18 people matching this intent\"). Aggregate counts only —\n * never individual identities (pool_discovery k-anonymity invariant).\n */\n evidence: z.string().min(1).max(160).optional(),\n});\n\n/** Canonical QUD repair categories for underspecified intents/questions. */\nexport const UnderspecificationTypeSchema = z.enum([\n \"missing_constituent\",\n \"missing_constraint\",\n \"open_alternative_set\",\n]);\n\nexport const QuestionStrategySchema = z.enum([\n \"refine_intent\",\n \"surface_missing_detail\",\n \"open_adjacent_thread\",\n \"reflective_summary\",\n \"surface_emergent_knowledge\",\n]);\n\nexport const QuestionWithStrategySchema = QuestionSchema.extend({\n strategy: QuestionStrategySchema,\n /** QUD repair category, or null when the question is not an underspecification repair. */\n underspecificationType: UnderspecificationTypeSchema.nullable(),\n});\n\nexport const QuestionGeneratorResponseSchema = z.object({\n questions: z.array(QuestionWithStrategySchema).max(3),\n});\n\nexport type QuestionOption = z.infer<typeof QuestionOptionSchema>;\nexport type Question = z.infer<typeof QuestionSchema>;\nexport type UnderspecificationType = z.infer<typeof UnderspecificationTypeSchema>;\nexport type QuestionStrategy = z.infer<typeof QuestionStrategySchema>;\nexport type QuestionWithStrategy = z.infer<typeof QuestionWithStrategySchema>;\nexport type QuestionGeneratorResponse = z.infer<typeof QuestionGeneratorResponseSchema>;\n\n/**\n * Internal generator output: public questions plus parallel strategy and QUD\n * taxonomy arrays for metadata-only consumption. The generator emits this;\n * callers forward only `questions` to renderers.\n */\nexport interface QuestionGenerationResult {\n questions: Question[];\n strategies: QuestionStrategy[];\n underspecificationTypes: Array<UnderspecificationType | null>;\n}\n\n// ─── Persistence types (opportunity-style composable jsonb) ──────────────────\n\n/** Internal reason a question was generated, orthogonal to mode and QUD metadata. */\nexport const NegotiationQuestionPurposeSchema = z.enum([\n \"uptake\",\n \"stalled_followup\",\n \"inflight_consultation\",\n]);\nexport const QuestionPurposeSchema = z.enum([\n \"uptake\",\n \"recovery\",\n \"stalled_followup\",\n \"inflight_consultation\",\n]);\n\n/**\n * Producer-supplied candidate binding. The API re-resolves every field from\n * authoritative rows before generation; callers cannot mint provenance.\n */\nexport const NegotiationQuestionCandidateSchema = z.object({\n purpose: NegotiationQuestionPurposeSchema,\n recipientUserId: z.string().min(1),\n recipientIntentId: z.string().min(1),\n opportunityId: z.string().min(1),\n taskId: z.string().min(1).optional(),\n networkId: z.string().min(1),\n /** Uptake only: exact low-authority counterparty eligibility binding. */\n counterpartyUserId: z.string().min(1).optional(),\n counterpartyIntentId: z.string().min(1).optional(),\n counterpartyFelicityAuthority: z.number().min(0).max(100).optional(),\n}).superRefine((candidate, ctx) => {\n const taskRequired = candidate.purpose !== \"uptake\";\n if (taskRequired !== Boolean(candidate.taskId)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"taskId\"],\n message: taskRequired\n ? \"task-backed negotiation questions require taskId\"\n : \"uptake questions must not carry a synthetic taskId\",\n });\n }\n const hasCounterparty = Boolean(candidate.counterpartyUserId) || Boolean(candidate.counterpartyIntentId);\n if (candidate.purpose === \"uptake\" && (!candidate.counterpartyUserId || !candidate.counterpartyIntentId || candidate.counterpartyFelicityAuthority === undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"uptake questions require exact counterparty provenance\" });\n }\n if (candidate.purpose !== \"uptake\" && (hasCounterparty || candidate.counterpartyFelicityAuthority !== undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"only uptake questions carry counterparty provenance\" });\n }\n});\n\n/**\n * Durable server-only routing and freshness envelope for negotiation-family\n * questions. This object is stripped from every REST/MCP projection.\n */\nexport const NegotiationQuestionProvenanceSchema = z.object({\n version: z.literal(1),\n purpose: NegotiationQuestionPurposeSchema,\n recipientUserId: z.string().min(1),\n recipientIntentId: z.string().min(1),\n opportunityId: z.string().min(1),\n taskId: z.string().min(1).optional(),\n networkId: z.string().min(1),\n intentFingerprint: z.string().min(1),\n opportunityStatus: z.enum([\"latent\", \"draft\", \"negotiating\", \"pending\", \"stalled\", \"accepted\", \"rejected\", \"expired\"]),\n opportunityUpdatedAt: z.string().datetime(),\n taskState: z.enum([\"submitted\", \"working\", \"input_required\", \"completed\", \"canceled\", \"failed\", \"rejected\", \"auth_required\", \"waiting_for_agent\", \"claimed\"]).optional(),\n taskUpdatedAt: z.string().datetime().optional(),\n /** Uptake only: exact low-authority counterparty eligibility binding. */\n counterpartyUserId: z.string().min(1).optional(),\n counterpartyIntentId: z.string().min(1).optional(),\n counterpartyFelicityAuthority: z.number().min(0).max(100).optional(),\n /** Stable per-generation position so retries dedupe without reducing cardinality. */\n questionOrdinal: z.number().int().min(0).max(2),\n}).superRefine((provenance, ctx) => {\n const taskRequired = provenance.purpose !== \"uptake\";\n if (taskRequired && (!provenance.taskId || !provenance.taskState || !provenance.taskUpdatedAt)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"taskId\"],\n message: \"task-backed provenance requires task id, state, and updatedAt\",\n });\n }\n if (!taskRequired && (provenance.taskId || provenance.taskState || provenance.taskUpdatedAt)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"taskId\"],\n message: \"uptake provenance must not carry task fields\",\n });\n }\n if (provenance.purpose === \"stalled_followup\" && provenance.taskState !== \"completed\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"taskState\"], message: \"follow-up task must be completed\" });\n }\n if (provenance.purpose === \"inflight_consultation\" && provenance.taskState !== \"input_required\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"taskState\"], message: \"inflight task must be input_required\" });\n }\n const hasCounterparty = Boolean(provenance.counterpartyUserId) || Boolean(provenance.counterpartyIntentId);\n if (provenance.purpose === \"uptake\" && (!provenance.counterpartyUserId || !provenance.counterpartyIntentId || provenance.counterpartyFelicityAuthority === undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"uptake provenance requires exact counterparty eligibility\" });\n }\n if (provenance.purpose !== \"uptake\" && (hasCounterparty || provenance.counterpartyFelicityAuthority !== undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"only uptake provenance carries counterparty eligibility\" });\n }\n});\n\nexport const QuestionModeSchema = z.enum([\n \"discovery\",\n \"intent\",\n \"enrichment\",\n \"negotiation\",\n // Negotiator-initiated mid-negotiation client questions (ask_user action, P3).\n // Distinct from \"negotiation\", which covers post-stall questions only.\n \"negotiation_inflight\",\n // Orchestrator-initiated mid-conversation questions (ask_user_question tool).\n \"chat\",\n // Pool-discriminator questions mined from the intent's candidate pool\n // (IND-418). Synthesized deterministically — no generator LLM call.\n \"pool_discovery\",\n]);\n\n/** One server-side candidate→side assignment (never serialized to clients). */\nexport const QuestionPoolAssignmentSchema = z.object({\n opportunityId: z.string().min(1),\n side: z.string().min(1),\n});\n\n/**\n * One mined discriminator carried inside a pool_discovery question's\n * detection (the asked one plus ranked alternates for interview-mode\n * chaining). INTERNAL — the read path strips `detection.pool` before any\n * payload leaves the server.\n */\nexport const QuestionPoolDiscriminatorSchema = z.object({\n label: z.string().min(1),\n questionSeed: z.string().min(1),\n sides: z.array(z.string().min(1)).min(2).max(3),\n /** Verified-assignment count per side label. */\n sideCounts: z.record(z.string(), z.number()),\n voi: z.number(),\n evidenceRate: z.number(),\n /** Discriminator embedding retained for durable semantic novelty checks. */\n embedding: z.array(z.number().finite()).min(1).max(4096).optional(),\n /** Model that generated `embedding`; mismatches must fall back to text. */\n embeddingModel: z.string().min(1).optional(),\n /** Verified assignments only — the P3 re-rank input. */\n assignments: z.array(QuestionPoolAssignmentSchema),\n});\n\n/** Pool snapshot stored on pool_discovery questions (server-side only). */\nexport const QuestionPoolSnapshotSchema = z.object({\n poolSize: z.number().int().min(0),\n /** ISO-8601 timestamp of the mining pass. */\n minedAt: z.string().min(1),\n /** Discovery run that produced the pool, when known. */\n runId: z.string().optional(),\n /** Intent payload snippet (≤160 chars) — reused by chained questions' evidence chips. */\n intentText: z.string().optional(),\n /** Stable hash of the full normalized payload + summary used for freshness. */\n intentFingerprint: z.string().min(1).optional(),\n /** Exact bounded candidate pool. Optional for legacy rows/jobs created before IND-422. */\n opportunityIds: z.array(z.string().uuid()).optional(),\n /** The discriminator this question asks about. */\n discriminator: QuestionPoolDiscriminatorSchema,\n /** Remaining ranked discriminators for interview-mode chaining. */\n alternates: z.array(QuestionPoolDiscriminatorSchema),\n});\n\n/** Internal delivery ledger for proactive pool-question pushes (IND-421). */\nexport const QuestionPoolPushSchema = z.object({\n version: z.literal(1),\n source: z.literal(\"pool_discovery\"),\n recipientId: z.string().min(1),\n intentId: z.string().min(1),\n cycleKey: z.string().min(1),\n messageId: z.string().min(1),\n surfaces: z.tuple([\n z.literal(\"personal_agent_badge\"),\n z.literal(\"negotiator_dm\"),\n ]),\n claimedAt: z.string().min(1),\n deliveryStatus: z.enum([\"claimed\", \"delivered\", \"suppressed\", \"failed\"]),\n conversationId: z.string().min(1).optional(),\n deliveredAt: z.string().min(1).optional(),\n suppressedAt: z.string().min(1).optional(),\n failure: z.string().min(1).max(500).optional(),\n});\n\n/** Durable request state for proactive pool-question delivery. */\nexport const QuestionPoolPushRequestStatusSchema = z.enum([\"requested\", \"suppressed\"]);\n\n/** Private snapshot for a post-discovery recovery refinement question. */\nexport const QuestionRecoverySnapshotSchema = z.object({\n version: z.literal(1),\n intentFingerprint: z.string().regex(/^[a-f0-9]{64}$/),\n completionSource: z.enum([\"from_intent\", \"discovery_run\"]),\n /** Privacy-safe aggregate only; raw negotiation evidence is never persisted. */\n rejectedNegotiationCount: z.number().int().min(1).max(50).optional(),\n /** Bounded internal correlation id for an asynchronous discovery run. */\n runId: z.string().min(1).max(128).optional(),\n});\n\n/** Internal reason a pending question was voided. */\nexport const QuestionVoidedReasonSchema = z.enum([\n \"pool_drift\",\n \"intent_edit\",\n \"recovery_drift\",\n \"negotiation_stale\",\n]);\n\n/** Permanent reasons that terminalize an unclaimed proactive push request. */\nexport const QuestionPoolPushRequestReasonSchema = z.enum([\n \"question_lifecycle\",\n \"intent_lifecycle\",\n \"malformed_source\",\n \"malformed_actor\",\n \"malformed_pool\",\n \"malformed_cycle\",\n \"visited\",\n \"pool_size\",\n \"voi\",\n \"cycle_budget\",\n]);\n\nexport const QuestionDetectionSchema = z.object({\n /** Which preset mode generated this question. */\n mode: QuestionModeSchema,\n /** Internal reason for generation; independent of mode and QUD repair metadata. */\n purpose: QuestionPurposeSchema.optional(),\n /** Exact negotiation recipient/intent/task routing provenance. Internal only. */\n negotiation: NegotiationQuestionProvenanceSchema.optional(),\n /** Entity type that triggered generation (e.g. \"opportunity\", \"intent\", \"profile\"). */\n sourceType: z.string().min(1),\n /** ID of the triggering entity. */\n sourceId: z.string().min(1),\n /** Optional intent ID that was the root cause. */\n triggeredBy: z.string().optional(),\n /** ISO-8601 timestamp of generation. */\n timestamp: z.string().min(1),\n /** Generation strategy persisted as internal metadata. */\n strategy: QuestionStrategySchema.optional(),\n /** QUD repair category persisted as internal metadata. */\n underspecificationType: UnderspecificationTypeSchema.nullable().optional(),\n /** ID of the assistant message that triggered this question. Used by the frontend to anchor the question card inline. */\n messageId: z.string().optional(),\n /** Durable server-only conversation session binding used to validate messageId. */\n sessionId: z.string().optional(),\n /**\n * pool_discovery only: the mined pool snapshot (assignments + alternates).\n * INTERNAL — stripped from every client-facing read (web + MCP).\n */\n pool: QuestionPoolSnapshotSchema.optional(),\n /** Post-discovery intent recovery snapshot. Internal only. */\n recovery: QuestionRecoverySnapshotSchema.optional(),\n /** Durable request marker written before enqueueing proactive delivery. Internal only. */\n pushRequestedAt: z.string().min(1).optional(),\n /** Last bounded recovery sweep that selected this request. Internal only. */\n pushRecoveryAttemptedAt: z.string().min(1).optional(),\n /** Durable request outcome. Internal only. */\n pushRequestStatus: QuestionPoolPushRequestStatusSchema.optional(),\n /** Permanent suppression reason for an unclaimed request. Internal only. */\n pushRequestReason: QuestionPoolPushRequestReasonSchema.optional(),\n /** ISO-8601 timestamp at which an unclaimed request was suppressed. Internal only. */\n pushRequestSuppressedAt: z.string().min(1).optional(),\n /** Internal proactive delivery state. Never serialize to public clients. */\n push: QuestionPoolPushSchema.optional(),\n /** Internal reason this question was voided after pool or intent drift. */\n voidedReason: QuestionVoidedReasonSchema.optional(),\n /** Authoritative successful-delivery ledger timestamp. Internal only. */\n pushedAt: z.string().min(1).optional(),\n}).superRefine((detection, ctx) => {\n const negotiationFamily = detection.mode === \"negotiation\" || detection.mode === \"negotiation_inflight\";\n if (negotiationFamily !== Boolean(detection.negotiation)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"negotiation\"],\n message: negotiationFamily\n ? \"negotiation-family detection requires exact provenance\"\n : \"non-negotiation detection must not carry negotiation provenance\",\n });\n }\n if (detection.negotiation) {\n if (detection.sourceType !== \"opportunity\" || detection.sourceId !== detection.negotiation.opportunityId) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"sourceId\"], message: \"negotiation sourceId must equal opportunityId\" });\n }\n if (detection.purpose !== detection.negotiation.purpose) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"purpose\"], message: \"detection purpose must match negotiation provenance\" });\n }\n if (detection.mode === \"negotiation_inflight\" && detection.negotiation.purpose !== \"inflight_consultation\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"negotiation\", \"purpose\"], message: \"inflight mode requires inflight purpose\" });\n }\n if (detection.mode === \"negotiation\" && detection.negotiation.purpose === \"inflight_consultation\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"negotiation\", \"purpose\"], message: \"ordinary negotiation mode cannot carry inflight purpose\" });\n }\n }\n if (\n detection.mode === \"pool_discovery\"\n && (!detection.triggeredBy?.trim() || detection.triggeredBy !== detection.sourceId)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"triggeredBy\"],\n message: \"pool_discovery triggeredBy must be non-empty and equal sourceId\",\n });\n }\n if (detection.purpose === \"recovery\") {\n if (\n detection.mode !== \"intent\"\n || detection.sourceType !== \"intent\"\n || !detection.triggeredBy?.trim()\n || detection.triggeredBy !== detection.sourceId\n || !detection.recovery\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"recovery\"],\n message: \"recovery purpose requires intent mode/source, equal trigger provenance, and a recovery snapshot\",\n });\n }\n } else if (detection.recovery) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"purpose\"],\n message: \"recovery snapshot requires recovery purpose\",\n });\n }\n if (detection.pushRequestStatus && !detection.pushRequestedAt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestedAt\"],\n message: \"push request state requires a request timestamp\",\n });\n }\n if (detection.pushRecoveryAttemptedAt && !detection.pushRequestedAt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestedAt\"],\n message: \"push recovery attempts require a request timestamp\",\n });\n }\n if (detection.pushRequestStatus === \"suppressed\") {\n if (!detection.pushRequestReason) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestReason\"],\n message: \"suppressed push requests require a reason\",\n });\n }\n if (!detection.pushRequestSuppressedAt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestSuppressedAt\"],\n message: \"suppressed push requests require a timestamp\",\n });\n }\n }\n});\n\nexport const QuestionActorSchema = z.object({\n /** The user this question is for. */\n userId: z.string().min(1),\n /** Optional network context. */\n networkId: z.string().optional(),\n /** Actor's role in the question — currently always \"subject\". */\n role: z.literal(\"subject\"),\n});\n\nexport const QuestionAnswerSchema = z.object({\n /** Option labels the user selected. */\n selectedOptions: z.array(z.string()),\n /** Free-text input when the user chose \"Other\" or elaborated. */\n freeText: z.string().optional(),\n /** User ID of the answerer. */\n answeredBy: z.string().min(1),\n /** ISO-8601 timestamp of when the answer was submitted. */\n answeredAt: z.string().min(1),\n});\n\nexport type NegotiationQuestionPurpose = z.infer<typeof NegotiationQuestionPurposeSchema>;\nexport type NegotiationQuestionCandidate = z.infer<typeof NegotiationQuestionCandidateSchema>;\nexport type NegotiationQuestionProvenance = z.infer<typeof NegotiationQuestionProvenanceSchema>;\nexport type QuestionPurpose = z.infer<typeof QuestionPurposeSchema>;\nexport type QuestionMode = z.infer<typeof QuestionModeSchema>;\nexport type QuestionDetection = z.infer<typeof QuestionDetectionSchema>;\nexport type QuestionActor = z.infer<typeof QuestionActorSchema>;\nexport type QuestionAnswer = z.infer<typeof QuestionAnswerSchema>;\nexport type QuestionPoolAssignment = z.infer<typeof QuestionPoolAssignmentSchema>;\nexport type QuestionPoolDiscriminator = z.infer<typeof QuestionPoolDiscriminatorSchema>;\nexport type QuestionPoolSnapshot = z.infer<typeof QuestionPoolSnapshotSchema>;\nexport type QuestionRecoverySnapshot = z.infer<typeof QuestionRecoverySnapshotSchema>;\nexport type QuestionPoolPush = z.infer<typeof QuestionPoolPushSchema>;\nexport type QuestionVoidedReason = z.infer<typeof QuestionVoidedReasonSchema>;\nexport type QuestionPoolPushRequestStatus = z.infer<typeof QuestionPoolPushRequestStatusSchema>;\nexport type QuestionPoolPushRequestReason = z.infer<typeof QuestionPoolPushRequestReasonSchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"question.schema.js","sourceRoot":"/","sources":["shared/schemas/question.schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Question — public structured shape consumed by frontend renderers and MCP\n * elicitation dispatch. Mirrors the brainstorming AskUserQuestion skill so a\n * Question can be rendered identically across surfaces.\n *\n * `QuestionWithStrategy` extends the public shape with internal `strategy`\n * and QUD underspecification tags used by generator guardrails and persisted\n * metadata. Both tags are stripped before the public payload leaves the\n * generator — users never see them.\n */\nimport { z } from \"zod\";\n\nexport const QuestionOptionSchema = z.object({\n /** Display text. Suffix \" (Recommended)\" on the safest path; list it first. */\n label: z.string().min(1).max(120),\n /** Explains the consequence of choosing this option, not just its definition. */\n description: z.string().min(1).max(280),\n});\n\nexport const QuestionSchema = z.object({\n /** ≤12 chars. Noun of the decision domain — e.g. \"Stage\", \"Timing\", \"Role\". */\n title: z.string().min(1).max(12),\n /** ≤2 sentences, ≤400 chars. Ends in a question mark. */\n prompt: z.string().min(1).max(400),\n /** 2–4 options. No explicit \"Other\" — clients provide that automatically. */\n options: z.array(QuestionOptionSchema).min(2).max(4),\n /** True when options are not mutually exclusive (priorities, bundles). */\n multiSelect: z.boolean(),\n /**\n * Optional provenance line rendered as a muted chip above the prompt\n * (e.g. \"based on 18 people matching this intent\"). Aggregate counts only —\n * never individual identities (pool_discovery k-anonymity invariant).\n */\n evidence: z.string().min(1).max(160).optional(),\n});\n\n/** Canonical QUD repair categories for underspecified intents/questions. */\nexport const UnderspecificationTypeSchema = z.enum([\n \"missing_constituent\",\n \"missing_constraint\",\n \"open_alternative_set\",\n]);\n\nexport const QuestionStrategySchema = z.enum([\n \"refine_intent\",\n \"surface_missing_detail\",\n \"open_adjacent_thread\",\n \"reflective_summary\",\n \"surface_emergent_knowledge\",\n]);\n\nexport const QuestionWithStrategySchema = QuestionSchema.extend({\n strategy: QuestionStrategySchema,\n /** QUD repair category, or null when the question is not an underspecification repair. */\n underspecificationType: UnderspecificationTypeSchema.nullable(),\n});\n\nexport const QuestionGeneratorResponseSchema = z.object({\n questions: z.array(QuestionWithStrategySchema).max(3),\n});\n\nexport type QuestionOption = z.infer<typeof QuestionOptionSchema>;\nexport type Question = z.infer<typeof QuestionSchema>;\nexport type UnderspecificationType = z.infer<typeof UnderspecificationTypeSchema>;\nexport type QuestionStrategy = z.infer<typeof QuestionStrategySchema>;\nexport type QuestionWithStrategy = z.infer<typeof QuestionWithStrategySchema>;\nexport type QuestionGeneratorResponse = z.infer<typeof QuestionGeneratorResponseSchema>;\n\n/**\n * Internal generator output: public questions plus parallel strategy and QUD\n * taxonomy arrays for metadata-only consumption. The generator emits this;\n * callers forward only `questions` to renderers.\n */\nexport interface QuestionGenerationResult {\n questions: Question[];\n strategies: QuestionStrategy[];\n underspecificationTypes: Array<UnderspecificationType | null>;\n}\n\n// ─── Persistence types (opportunity-style composable jsonb) ──────────────────\n\n/** Internal reason a question was generated, orthogonal to mode and QUD metadata. */\nexport const NegotiationQuestionPurposeSchema = z.enum([\n \"uptake\",\n \"stalled_followup\",\n \"inflight_consultation\",\n]);\nexport const QuestionPurposeSchema = z.enum([\n \"uptake\",\n \"recovery\",\n \"stalled_followup\",\n \"inflight_consultation\",\n]);\n\n/**\n * Producer-supplied candidate binding. The API re-resolves every field from\n * authoritative rows before generation; callers cannot mint provenance.\n */\nexport const NegotiationQuestionCandidateSchema = z.object({\n purpose: NegotiationQuestionPurposeSchema,\n recipientUserId: z.string().min(1),\n recipientIntentId: z.string().min(1),\n opportunityId: z.string().min(1),\n taskId: z.string().min(1).optional(),\n networkId: z.string().min(1),\n /** Uptake only: exact low-authority counterparty eligibility binding. */\n counterpartyUserId: z.string().min(1).optional(),\n counterpartyIntentId: z.string().min(1).optional(),\n counterpartyFelicityAuthority: z.number().min(0).max(100).optional(),\n}).superRefine((candidate, ctx) => {\n const taskRequired = candidate.purpose !== \"uptake\";\n if (taskRequired !== Boolean(candidate.taskId)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"taskId\"],\n message: taskRequired\n ? \"task-backed negotiation questions require taskId\"\n : \"uptake questions must not carry a synthetic taskId\",\n });\n }\n const hasCounterparty = Boolean(candidate.counterpartyUserId) || Boolean(candidate.counterpartyIntentId);\n if (candidate.purpose === \"uptake\" && (!candidate.counterpartyUserId || !candidate.counterpartyIntentId || candidate.counterpartyFelicityAuthority === undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"uptake questions require exact counterparty provenance\" });\n }\n if (candidate.purpose !== \"uptake\" && (hasCounterparty || candidate.counterpartyFelicityAuthority !== undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"only uptake questions carry counterparty provenance\" });\n }\n});\n\n/**\n * Durable server-only routing and freshness envelope for negotiation-family\n * questions. This object is stripped from every REST/MCP projection.\n */\nexport const NegotiationQuestionProvenanceSchema = z.object({\n version: z.literal(1),\n purpose: NegotiationQuestionPurposeSchema,\n recipientUserId: z.string().min(1),\n recipientIntentId: z.string().min(1),\n opportunityId: z.string().min(1),\n taskId: z.string().min(1).optional(),\n networkId: z.string().min(1),\n intentFingerprint: z.string().min(1),\n opportunityStatus: z.enum([\"latent\", \"draft\", \"negotiating\", \"pending\", \"stalled\", \"accepted\", \"rejected\", \"expired\"]),\n opportunityUpdatedAt: z.string().datetime(),\n taskState: z.enum([\"submitted\", \"working\", \"input_required\", \"completed\", \"canceled\", \"failed\", \"rejected\", \"auth_required\", \"waiting_for_agent\", \"claimed\"]).optional(),\n taskUpdatedAt: z.string().datetime().optional(),\n /** Uptake only: exact low-authority counterparty eligibility binding. */\n counterpartyUserId: z.string().min(1).optional(),\n counterpartyIntentId: z.string().min(1).optional(),\n counterpartyFelicityAuthority: z.number().min(0).max(100).optional(),\n /** Stable per-generation position so retries dedupe without reducing cardinality. */\n questionOrdinal: z.number().int().min(0).max(2),\n}).superRefine((provenance, ctx) => {\n const taskRequired = provenance.purpose !== \"uptake\";\n if (taskRequired && (!provenance.taskId || !provenance.taskState || !provenance.taskUpdatedAt)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"taskId\"],\n message: \"task-backed provenance requires task id, state, and updatedAt\",\n });\n }\n if (!taskRequired && (provenance.taskId || provenance.taskState || provenance.taskUpdatedAt)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"taskId\"],\n message: \"uptake provenance must not carry task fields\",\n });\n }\n if (provenance.purpose === \"stalled_followup\" && provenance.taskState !== \"completed\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"taskState\"], message: \"follow-up task must be completed\" });\n }\n if (provenance.purpose === \"inflight_consultation\" && provenance.taskState !== \"input_required\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"taskState\"], message: \"inflight task must be input_required\" });\n }\n const hasCounterparty = Boolean(provenance.counterpartyUserId) || Boolean(provenance.counterpartyIntentId);\n if (provenance.purpose === \"uptake\" && (!provenance.counterpartyUserId || !provenance.counterpartyIntentId || provenance.counterpartyFelicityAuthority === undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"uptake provenance requires exact counterparty eligibility\" });\n }\n if (provenance.purpose !== \"uptake\" && (hasCounterparty || provenance.counterpartyFelicityAuthority !== undefined)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"counterpartyUserId\"], message: \"only uptake provenance carries counterparty eligibility\" });\n }\n});\n\nexport const QuestionModeSchema = z.enum([\n \"discovery\",\n \"intent\",\n \"enrichment\",\n \"negotiation\",\n // Negotiator-initiated mid-negotiation client questions (ask_user action, P3).\n // Distinct from \"negotiation\", which covers post-stall questions only.\n \"negotiation_inflight\",\n // Orchestrator-initiated mid-conversation questions (ask_user_question tool).\n \"chat\",\n // Pool-discriminator questions mined from the intent's candidate pool\n // (IND-418). Synthesized deterministically — no generator LLM call.\n \"pool_discovery\",\n]);\n\n/** One server-side candidate→side assignment (never serialized to clients). */\nexport const QuestionPoolAssignmentSchema = z.object({\n opportunityId: z.string().min(1),\n side: z.string().min(1),\n});\n\n/**\n * One mined discriminator carried inside a pool_discovery question's\n * detection (the asked one plus ranked alternates for interview-mode\n * chaining). INTERNAL — the read path strips `detection.pool` before any\n * payload leaves the server.\n */\nexport const QuestionPoolDiscriminatorSchema = z.object({\n label: z.string().min(1),\n questionSeed: z.string().min(1),\n sides: z.array(z.string().min(1)).min(2).max(3),\n /** Verified-assignment count per side label. */\n sideCounts: z.record(z.string(), z.number()),\n voi: z.number(),\n evidenceRate: z.number(),\n /** Discriminator embedding retained for durable semantic novelty checks. */\n embedding: z.array(z.number().finite()).min(1).max(4096).optional(),\n /** Model that generated `embedding`; mismatches must fall back to text. */\n embeddingModel: z.string().min(1).optional(),\n /** Verified assignments only — the P3 re-rank input. */\n assignments: z.array(QuestionPoolAssignmentSchema),\n});\n\n/** Pool snapshot stored on pool_discovery questions (server-side only). */\nexport const QuestionPoolSnapshotSchema = z.object({\n poolSize: z.number().int().min(0),\n /** ISO-8601 timestamp of the mining pass. */\n minedAt: z.string().min(1),\n /** Discovery run that produced the pool, when known. */\n runId: z.string().optional(),\n /** Intent payload snippet (≤160 chars) — reused by chained questions' evidence chips. */\n intentText: z.string().optional(),\n /** Stable hash of the full normalized payload + summary used for freshness. */\n intentFingerprint: z.string().min(1).optional(),\n /** Exact bounded candidate pool. Optional for legacy rows/jobs created before IND-422. */\n opportunityIds: z.array(z.string().uuid()).optional(),\n /** The discriminator this question asks about. */\n discriminator: QuestionPoolDiscriminatorSchema,\n /** Remaining ranked discriminators for interview-mode chaining. */\n alternates: z.array(QuestionPoolDiscriminatorSchema),\n});\n\n/** Internal delivery ledger for proactive pool-question pushes (IND-421). */\nexport const QuestionPoolPushSchema = z.object({\n version: z.literal(1),\n source: z.literal(\"pool_discovery\"),\n recipientId: z.string().min(1),\n intentId: z.string().min(1),\n cycleKey: z.string().min(1),\n messageId: z.string().min(1),\n surfaces: z.tuple([\n z.literal(\"personal_agent_badge\"),\n z.literal(\"negotiator_dm\"),\n ]),\n claimedAt: z.string().min(1),\n deliveryStatus: z.enum([\"claimed\", \"delivered\", \"suppressed\", \"failed\"]),\n conversationId: z.string().min(1).optional(),\n deliveredAt: z.string().min(1).optional(),\n suppressedAt: z.string().min(1).optional(),\n failure: z.string().min(1).max(500).optional(),\n});\n\n/** Durable request state for proactive pool-question delivery. */\nexport const QuestionPoolPushRequestStatusSchema = z.enum([\"requested\", \"suppressed\"]);\n\n/** Private snapshot for a post-discovery recovery refinement question. */\nexport const QuestionRecoverySnapshotSchema = z.object({\n version: z.literal(1),\n intentFingerprint: z.string().regex(/^[a-f0-9]{64}$/),\n completionSource: z.enum([\"intent_creation\", \"from_intent\", \"discovery_run\"]),\n /** Privacy-safe aggregate only; raw negotiation evidence is never persisted. */\n rejectedNegotiationCount: z.number().int().min(1).max(50).optional(),\n /** Bounded internal correlation id for an asynchronous discovery run. */\n runId: z.string().min(1).max(128).optional(),\n});\n\n/** Internal reason a pending question was voided. */\nexport const QuestionVoidedReasonSchema = z.enum([\n \"pool_drift\",\n \"intent_edit\",\n \"recovery_drift\",\n \"negotiation_stale\",\n]);\n\n/** Permanent reasons that terminalize an unclaimed proactive push request. */\nexport const QuestionPoolPushRequestReasonSchema = z.enum([\n \"question_lifecycle\",\n \"intent_lifecycle\",\n \"malformed_source\",\n \"malformed_actor\",\n \"malformed_pool\",\n \"malformed_cycle\",\n \"visited\",\n \"pool_size\",\n \"voi\",\n \"cycle_budget\",\n]);\n\nexport const QuestionDetectionSchema = z.object({\n /** Which preset mode generated this question. */\n mode: QuestionModeSchema,\n /** Internal reason for generation; independent of mode and QUD repair metadata. */\n purpose: QuestionPurposeSchema.optional(),\n /** Exact negotiation recipient/intent/task routing provenance. Internal only. */\n negotiation: NegotiationQuestionProvenanceSchema.optional(),\n /** Entity type that triggered generation (e.g. \"opportunity\", \"intent\", \"profile\"). */\n sourceType: z.string().min(1),\n /** ID of the triggering entity. */\n sourceId: z.string().min(1),\n /** Optional intent ID that was the root cause. */\n triggeredBy: z.string().optional(),\n /** ISO-8601 timestamp of generation. */\n timestamp: z.string().min(1),\n /** Generation strategy persisted as internal metadata. */\n strategy: QuestionStrategySchema.optional(),\n /** QUD repair category persisted as internal metadata. */\n underspecificationType: UnderspecificationTypeSchema.nullable().optional(),\n /** ID of the assistant message that triggered this question. Used by the frontend to anchor the question card inline. */\n messageId: z.string().optional(),\n /** Durable server-only conversation session binding used to validate messageId. */\n sessionId: z.string().optional(),\n /**\n * pool_discovery only: the mined pool snapshot (assignments + alternates).\n * INTERNAL — stripped from every client-facing read (web + MCP).\n */\n pool: QuestionPoolSnapshotSchema.optional(),\n /** Post-discovery intent recovery snapshot. Internal only. */\n recovery: QuestionRecoverySnapshotSchema.optional(),\n /** Durable request marker written before enqueueing proactive delivery. Internal only. */\n pushRequestedAt: z.string().min(1).optional(),\n /** Last bounded recovery sweep that selected this request. Internal only. */\n pushRecoveryAttemptedAt: z.string().min(1).optional(),\n /** Durable request outcome. Internal only. */\n pushRequestStatus: QuestionPoolPushRequestStatusSchema.optional(),\n /** Permanent suppression reason for an unclaimed request. Internal only. */\n pushRequestReason: QuestionPoolPushRequestReasonSchema.optional(),\n /** ISO-8601 timestamp at which an unclaimed request was suppressed. Internal only. */\n pushRequestSuppressedAt: z.string().min(1).optional(),\n /** Internal proactive delivery state. Never serialize to public clients. */\n push: QuestionPoolPushSchema.optional(),\n /** Internal reason this question was voided after pool or intent drift. */\n voidedReason: QuestionVoidedReasonSchema.optional(),\n /** Authoritative successful-delivery ledger timestamp. Internal only. */\n pushedAt: z.string().min(1).optional(),\n}).superRefine((detection, ctx) => {\n const negotiationFamily = detection.mode === \"negotiation\" || detection.mode === \"negotiation_inflight\";\n if (negotiationFamily !== Boolean(detection.negotiation)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"negotiation\"],\n message: negotiationFamily\n ? \"negotiation-family detection requires exact provenance\"\n : \"non-negotiation detection must not carry negotiation provenance\",\n });\n }\n if (detection.negotiation) {\n if (detection.sourceType !== \"opportunity\" || detection.sourceId !== detection.negotiation.opportunityId) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"sourceId\"], message: \"negotiation sourceId must equal opportunityId\" });\n }\n if (detection.purpose !== detection.negotiation.purpose) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"purpose\"], message: \"detection purpose must match negotiation provenance\" });\n }\n if (detection.mode === \"negotiation_inflight\" && detection.negotiation.purpose !== \"inflight_consultation\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"negotiation\", \"purpose\"], message: \"inflight mode requires inflight purpose\" });\n }\n if (detection.mode === \"negotiation\" && detection.negotiation.purpose === \"inflight_consultation\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"negotiation\", \"purpose\"], message: \"ordinary negotiation mode cannot carry inflight purpose\" });\n }\n }\n if (\n detection.mode === \"pool_discovery\"\n && (!detection.triggeredBy?.trim() || detection.triggeredBy !== detection.sourceId)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"triggeredBy\"],\n message: \"pool_discovery triggeredBy must be non-empty and equal sourceId\",\n });\n }\n if (detection.purpose === \"recovery\") {\n if (\n detection.mode !== \"intent\"\n || detection.sourceType !== \"intent\"\n || !detection.triggeredBy?.trim()\n || detection.triggeredBy !== detection.sourceId\n || !detection.recovery\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"recovery\"],\n message: \"recovery purpose requires intent mode/source, equal trigger provenance, and a recovery snapshot\",\n });\n }\n } else if (detection.recovery) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"purpose\"],\n message: \"recovery snapshot requires recovery purpose\",\n });\n }\n if (detection.pushRequestStatus && !detection.pushRequestedAt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestedAt\"],\n message: \"push request state requires a request timestamp\",\n });\n }\n if (detection.pushRecoveryAttemptedAt && !detection.pushRequestedAt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestedAt\"],\n message: \"push recovery attempts require a request timestamp\",\n });\n }\n if (detection.pushRequestStatus === \"suppressed\") {\n if (!detection.pushRequestReason) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestReason\"],\n message: \"suppressed push requests require a reason\",\n });\n }\n if (!detection.pushRequestSuppressedAt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"pushRequestSuppressedAt\"],\n message: \"suppressed push requests require a timestamp\",\n });\n }\n }\n});\n\nexport const QuestionActorSchema = z.object({\n /** The user this question is for. */\n userId: z.string().min(1),\n /** Optional network context. */\n networkId: z.string().optional(),\n /** Actor's role in the question — currently always \"subject\". */\n role: z.literal(\"subject\"),\n});\n\nexport const QuestionAnswerSchema = z.object({\n /** Option labels the user selected. */\n selectedOptions: z.array(z.string()),\n /** Free-text input when the user chose \"Other\" or elaborated. */\n freeText: z.string().optional(),\n /** User ID of the answerer. */\n answeredBy: z.string().min(1),\n /** ISO-8601 timestamp of when the answer was submitted. */\n answeredAt: z.string().min(1),\n});\n\nexport type NegotiationQuestionPurpose = z.infer<typeof NegotiationQuestionPurposeSchema>;\nexport type NegotiationQuestionCandidate = z.infer<typeof NegotiationQuestionCandidateSchema>;\nexport type NegotiationQuestionProvenance = z.infer<typeof NegotiationQuestionProvenanceSchema>;\nexport type QuestionPurpose = z.infer<typeof QuestionPurposeSchema>;\nexport type QuestionMode = z.infer<typeof QuestionModeSchema>;\nexport type QuestionDetection = z.infer<typeof QuestionDetectionSchema>;\nexport type QuestionActor = z.infer<typeof QuestionActorSchema>;\nexport type QuestionAnswer = z.infer<typeof QuestionAnswerSchema>;\nexport type QuestionPoolAssignment = z.infer<typeof QuestionPoolAssignmentSchema>;\nexport type QuestionPoolDiscriminator = z.infer<typeof QuestionPoolDiscriminatorSchema>;\nexport type QuestionPoolSnapshot = z.infer<typeof QuestionPoolSnapshotSchema>;\nexport type QuestionRecoverySnapshot = z.infer<typeof QuestionRecoverySnapshotSchema>;\nexport type QuestionPoolPush = z.infer<typeof QuestionPoolPushSchema>;\nexport type QuestionVoidedReason = z.infer<typeof QuestionVoidedReasonSchema>;\nexport type QuestionPoolPushRequestStatus = z.infer<typeof QuestionPoolPushRequestStatusSchema>;\nexport type QuestionPoolPushRequestReason = z.infer<typeof QuestionPoolPushRequestReasonSchema>;\n"]}
|