@indexnetwork/protocol 13.2.1-rc.467.1 → 14.1.0-rc.469.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 +24 -0
- package/dist/capabilities/participant-agents.facade.d.ts +1 -2
- package/dist/capabilities/participant-agents.facade.js +1 -2
- package/dist/capabilities/questions.facade.d.ts +1 -1
- package/dist/capabilities/questions.facade.js +1 -1
- package/dist/chat/chat-streaming.types.d.ts +16 -40
- package/dist/chat/chat-streaming.types.js +1 -8
- package/dist/chat/chat.agent.d.ts +5 -25
- package/dist/chat/chat.agent.js +12 -46
- package/dist/chat/chat.graph.d.ts +4 -6
- package/dist/chat/chat.graph.js +2 -3
- package/dist/chat/chat.persona.d.ts +7 -21
- package/dist/chat/chat.persona.js +1 -24
- package/dist/chat/chat.prompt.d.ts +0 -13
- package/dist/chat/chat.prompt.js +6 -428
- package/dist/chat/chat.prompt.modules.d.ts +2 -32
- package/dist/chat/chat.prompt.modules.js +1 -235
- package/dist/chat/chat.streamer.js +2 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -2
- package/dist/participant-agents/public/index.d.ts +1 -1
- package/dist/participant-agents/public/index.js +1 -1
- package/dist/questions/application/index.d.ts +1 -1
- package/dist/questions/application/index.js +1 -1
- package/dist/questions/application/question.env.d.ts +29 -0
- package/dist/questions/application/question.env.js +36 -0
- package/dist/questions/public/index.d.ts +1 -1
- package/dist/questions/public/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { focusedIntentId } from "../shared/agent/tool.scope.js";
|
|
2
1
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
3
2
|
// EXTRACTION
|
|
4
3
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -7,7 +6,7 @@ import { focusedIntentId } from "../shared/agent/tool.scope.js";
|
|
|
7
6
|
*
|
|
8
7
|
* Scans backwards to find the last HumanMessage, then collects all tool calls
|
|
9
8
|
* from AIMessages after that point. This ensures multi-iteration tool history
|
|
10
|
-
* is available for
|
|
9
|
+
* is available for prompt construction within a single user turn.
|
|
11
10
|
*
|
|
12
11
|
* @param messages - The current conversation message array
|
|
13
12
|
* @returns Flattened array of tool name + args from the current agent turn
|
|
@@ -39,236 +38,3 @@ export function extractRecentToolCalls(messages) {
|
|
|
39
38
|
}
|
|
40
39
|
return toolCalls;
|
|
41
40
|
}
|
|
42
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
43
|
-
// HELPERS
|
|
44
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
45
|
-
/**
|
|
46
|
-
* Checks whether recent tool calls include discover_opportunities with
|
|
47
|
-
* introduction-specific arguments (partyUserIds or introTargetUserId).
|
|
48
|
-
*/
|
|
49
|
-
function hasIntroductionArgs(recentTools) {
|
|
50
|
-
return recentTools.some((t) => t.name === "discover_opportunities" &&
|
|
51
|
-
(t.args.partyUserIds || t.args.introTargetUserId));
|
|
52
|
-
}
|
|
53
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
54
|
-
// MODULE DEFINITIONS
|
|
55
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
56
|
-
const intentCreationModule = {
|
|
57
|
-
id: "intent-creation",
|
|
58
|
-
triggers: ["create_intent"],
|
|
59
|
-
content: () => `
|
|
60
|
-
### 2. User explicitly wants to create or save an intent
|
|
61
|
-
|
|
62
|
-
**YOU decide if it's specific enough. The tool proposes — the user confirms.**
|
|
63
|
-
|
|
64
|
-
\`\`\`
|
|
65
|
-
IF description is vague ("find a job", "meet people", "learn something"):
|
|
66
|
-
1. read_user_contexts() → get their background
|
|
67
|
-
2. read_intents() → see existing intents for context
|
|
68
|
-
3. THINK: given their profile and existing intents, suggest a refined version
|
|
69
|
-
4. Reply: "Based on your background in X, did you mean something like 'Y'?"
|
|
70
|
-
5. Wait for confirmation
|
|
71
|
-
6. On "yes" → create_intent(description=exact_refined_text)
|
|
72
|
-
|
|
73
|
-
IF description is specific enough ("contribute to an open-source LLM project"):
|
|
74
|
-
→ create_intent(description=...) directly
|
|
75
|
-
\`\`\`
|
|
76
|
-
|
|
77
|
-
**CRITICAL: Never write a \`\`\`intent_proposal block yourself.** To propose an intent you MUST call create_intent(description=...). The tool returns a \`\`\`intent_proposal code block (with proposalId and description). You MUST include that exact block verbatim in your response — it renders as an interactive card. Do not summarize or invent the block; only the tool provides a valid one. Add a brief explanation that creating this intent will let the system look for relevant people in the background.
|
|
78
|
-
|
|
79
|
-
Specificity test: Does it contain a concrete domain, action, or scope? If just a single generic verb+noun ("find a job"), it's vague. If it has qualifying detail ("senior UX design role at a tech company in Berlin"), it's specific.
|
|
80
|
-
`,
|
|
81
|
-
};
|
|
82
|
-
const intentManagementModule = {
|
|
83
|
-
id: "intent-management",
|
|
84
|
-
triggers: ["update_intent", "delete_intent"],
|
|
85
|
-
content: () => `
|
|
86
|
-
### 4. Update or delete an intent
|
|
87
|
-
|
|
88
|
-
**YOU look up the ID first.**
|
|
89
|
-
|
|
90
|
-
\`\`\`
|
|
91
|
-
1. read_intents() → get current intents with IDs
|
|
92
|
-
2. Match user's request to the right intent
|
|
93
|
-
3. update_intent(intentId=exact_id, description=...) or delete_intent(intentId=exact_id)
|
|
94
|
-
\`\`\`
|
|
95
|
-
`,
|
|
96
|
-
};
|
|
97
|
-
const personLookupModule = {
|
|
98
|
-
id: "person-lookup",
|
|
99
|
-
triggers: ["read_user_contexts"],
|
|
100
|
-
content: () => `
|
|
101
|
-
### 0. User asks about a specific person by name
|
|
102
|
-
|
|
103
|
-
When the user mentions a specific person by name ("find [name]", "look up [name]", "who is [name]?", "tell me about [name]"), look them up by name first — do NOT use discovery.
|
|
104
|
-
|
|
105
|
-
- Call \`read_user_contexts(query="the name")\` — this finds members by name across the user's indexes
|
|
106
|
-
- If one match: the result already includes their full profile; present it naturally
|
|
107
|
-
- If multiple matches: present the list and ask the user to clarify which person
|
|
108
|
-
- If no matches: tell the user you couldn't find anyone by that name in their network
|
|
109
|
-
- If the user then asks for semantic discovery (e.g. "find people like them"), use Pattern 1.
|
|
110
|
-
- If the user wants to connect with this specific person (e.g. "yes, connect us", "what can I do with them", "I'd like to reach out"), use Pattern 1a.
|
|
111
|
-
`,
|
|
112
|
-
};
|
|
113
|
-
const urlScrapingModule = {
|
|
114
|
-
id: "url-scraping",
|
|
115
|
-
triggers: ["scrape_url"],
|
|
116
|
-
regex: /(https?:\/\/)/i,
|
|
117
|
-
content: (ctx) => `
|
|
118
|
-
### 3. User includes a URL
|
|
119
|
-
|
|
120
|
-
**YOU handle scraping before ${focusedIntentId(ctx) ? "updating the selected intent" : "intent creation"}.**
|
|
121
|
-
|
|
122
|
-
\`\`\`
|
|
123
|
-
1. scrape_url(url, objective="Extract key details for an intent")
|
|
124
|
-
2. Synthesize a conceptual description from scraped content
|
|
125
|
-
3. ${focusedIntentId(ctx) ? `update_intent(intentId="${focusedIntentId(ctx)}", description=synthesized_summary)` : "create_intent(description=synthesized_summary)"}
|
|
126
|
-
\`\`\`
|
|
127
|
-
|
|
128
|
-
Exception: for profile creation, pass URLs directly to create_user_context (it handles scraping internally).
|
|
129
|
-
|
|
130
|
-
If the user pastes or types a profile URL (e.g. linkedin.com/..., github.com/...) to create or update their profile, you MUST pass that exact URL in the corresponding parameter (e.g. linkedinUrl, githubUrl, twitterUrl) to create_user_context, or use scrape_url with that URL then update_user_context; do not use the user's stored social links for that request.
|
|
131
|
-
`,
|
|
132
|
-
};
|
|
133
|
-
const communityModule = {
|
|
134
|
-
id: "community",
|
|
135
|
-
triggers: ["read_networks", "create_network", "create_network_membership", "update_network", "delete_network", "delete_network_membership"],
|
|
136
|
-
content: () => `
|
|
137
|
-
### 8. Explore what a community is about
|
|
138
|
-
|
|
139
|
-
\`\`\`
|
|
140
|
-
0. If user asks about communities they belong to, first use preloaded memberships in this prompt.
|
|
141
|
-
1. read_networks() → get network details (title, prompt)
|
|
142
|
-
2. read_intents(networkId=X) → what members are looking for
|
|
143
|
-
3. read_network_memberships(networkId=X) → who's in it
|
|
144
|
-
4. Synthesize: community purpose, active needs, member composition
|
|
145
|
-
\`\`\`
|
|
146
|
-
|
|
147
|
-
### When to mention community/index
|
|
148
|
-
Index and community membership is background: handle it without talking about indexes unless the user asks or it's sign-up, leave, or owner settings. Do not proactively mention "your indexes", "your communities", "which index", "in your current communities", or similar. Only mention indexes (or communities, lists) when: (i) post-onboarding sign-up to a community, (ii) user explicitly asked about their indexes/communities, (iii) user wants to leave one, (iv) owner is changing index/community settings. Otherwise use neutral language ("where you're connected", "people you're connected with") and do not narrate "your indexes", "your current communities", "in this network", etc.
|
|
149
|
-
`,
|
|
150
|
-
};
|
|
151
|
-
const contactsModule = {
|
|
152
|
-
id: "contacts",
|
|
153
|
-
triggers: ["import_gmail_contacts", "add_contact", "list_contacts", "remove_contact"],
|
|
154
|
-
// Gate on the CONTACTS_ENABLED flag (fail-closed: only `true` enables). When
|
|
155
|
-
// contacts are disabled the import/add tools are de-registered, so this module
|
|
156
|
-
// must not be injected — otherwise the orchestrator keeps advertising Gmail
|
|
157
|
-
// import / add_contact and offers an action that then fails as "Unknown tool".
|
|
158
|
-
triggerFilter: (iterCtx) => iterCtx.ctx.contactsEnabled === true,
|
|
159
|
-
content: () => `
|
|
160
|
-
### 9. Import contacts from Gmail
|
|
161
|
-
|
|
162
|
-
**Single-step workflow:**
|
|
163
|
-
|
|
164
|
-
\`\`\`
|
|
165
|
-
import_gmail_contacts()
|
|
166
|
-
→ If not connected: returns { requiresAuth: true, authUrl: "..." } — share the URL with the user
|
|
167
|
-
→ If connected: imports contacts directly and returns stats { imported, skipped, newContacts, existingContacts }
|
|
168
|
-
\`\`\`
|
|
169
|
-
|
|
170
|
-
Ghost users are contacts without accounts — they're enriched with public data (LinkedIn, GitHub, X) and can appear in opportunity discovery once enriched.
|
|
171
|
-
|
|
172
|
-
### 10. Add or manage contacts manually
|
|
173
|
-
|
|
174
|
-
\`\`\`
|
|
175
|
-
# Add a single contact
|
|
176
|
-
add_contact(email="alice@example.com", name="Alice Smith")
|
|
177
|
-
|
|
178
|
-
# List user's network
|
|
179
|
-
list_contacts() → returns contacts with names, emails, and whether they're ghost users
|
|
180
|
-
|
|
181
|
-
# Remove a contact
|
|
182
|
-
remove_contact(contactId=X)
|
|
183
|
-
\`\`\`
|
|
184
|
-
`,
|
|
185
|
-
};
|
|
186
|
-
const sharedContextModule = {
|
|
187
|
-
id: "shared-context",
|
|
188
|
-
triggers: ["read_network_memberships"],
|
|
189
|
-
content: () => `
|
|
190
|
-
### 5. Find shared context between two users
|
|
191
|
-
|
|
192
|
-
\`\`\`
|
|
193
|
-
1. read_network_memberships(userId=me) → my networks
|
|
194
|
-
2. read_network_memberships(userId=other) → their networks
|
|
195
|
-
3. Intersect networkIds
|
|
196
|
-
4. For each shared network: read_intents(networkId=shared)
|
|
197
|
-
5. read_user_contexts(userId=other)
|
|
198
|
-
6. Synthesize: what overlaps, where they could collaborate
|
|
199
|
-
\`\`\`
|
|
200
|
-
`,
|
|
201
|
-
};
|
|
202
|
-
const mentionsModule = {
|
|
203
|
-
id: "mentions",
|
|
204
|
-
triggers: [],
|
|
205
|
-
regex: /@\[.*?\]\(.*?\)/,
|
|
206
|
-
content: () => `- Messages may contain \`@[Display Name](userId)\` markup. The value in parentheses is the userId.
|
|
207
|
-
`,
|
|
208
|
-
};
|
|
209
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
210
|
-
// MODULE REGISTRY
|
|
211
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
212
|
-
/** All registered prompt modules. */
|
|
213
|
-
export const PROMPT_MODULES = [
|
|
214
|
-
intentCreationModule,
|
|
215
|
-
intentManagementModule,
|
|
216
|
-
personLookupModule,
|
|
217
|
-
urlScrapingModule,
|
|
218
|
-
communityModule,
|
|
219
|
-
contactsModule,
|
|
220
|
-
sharedContextModule,
|
|
221
|
-
mentionsModule,
|
|
222
|
-
];
|
|
223
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
224
|
-
// RESOLUTION
|
|
225
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
226
|
-
/**
|
|
227
|
-
* Resolves which prompt modules should be injected for the current iteration.
|
|
228
|
-
*
|
|
229
|
-
* Phase 1: Skip all modules when onboarding is active (early exit).
|
|
230
|
-
* Phase 2: Collect candidate modules by checking triggers and regex.
|
|
231
|
-
* Phase 3: Apply exclusions (unidirectional — the excluding module stays).
|
|
232
|
-
*
|
|
233
|
-
* @param iterCtx - Current iteration context (tool history, user message, resolved context)
|
|
234
|
-
* @returns Concatenated prompt text from all matched modules
|
|
235
|
-
*/
|
|
236
|
-
export function resolveModules(iterCtx) {
|
|
237
|
-
// Phase 1 (early exit): Skip all modules during onboarding
|
|
238
|
-
if (iterCtx.ctx.isOnboarding) {
|
|
239
|
-
return "";
|
|
240
|
-
}
|
|
241
|
-
const toolNames = new Set(iterCtx.recentTools.map((t) => t.name));
|
|
242
|
-
// Phase 2: Collect candidates
|
|
243
|
-
const candidates = new Map();
|
|
244
|
-
for (const mod of PROMPT_MODULES) {
|
|
245
|
-
let matched = false;
|
|
246
|
-
// Check tool triggers (with optional filter for arg-based disambiguation)
|
|
247
|
-
if (mod.triggers.length > 0 && mod.triggers.some((t) => toolNames.has(t))) {
|
|
248
|
-
matched = mod.triggerFilter ? mod.triggerFilter(iterCtx) : true;
|
|
249
|
-
}
|
|
250
|
-
// Check regex trigger
|
|
251
|
-
if (!matched && mod.regex && iterCtx.currentMessage && mod.regex.test(iterCtx.currentMessage)) {
|
|
252
|
-
matched = true;
|
|
253
|
-
}
|
|
254
|
-
if (matched) {
|
|
255
|
-
candidates.set(mod.id, mod);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
// Phase 3: Apply exclusions (skip self-exclusion)
|
|
259
|
-
for (const mod of candidates.values()) {
|
|
260
|
-
if (mod.excludes) {
|
|
261
|
-
for (const excludedId of mod.excludes) {
|
|
262
|
-
if (excludedId !== mod.id) {
|
|
263
|
-
candidates.delete(excludedId);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// Build output
|
|
269
|
-
const sections = [];
|
|
270
|
-
for (const mod of candidates.values()) {
|
|
271
|
-
sections.push(mod.content(iterCtx.ctx));
|
|
272
|
-
}
|
|
273
|
-
return sections.join("\n");
|
|
274
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AIMessage, HumanMessage } from "@langchain/core/messages";
|
|
2
2
|
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
3
|
-
import { createAgentEndEvent, createAgentStartEvent, createDebugMetaEvent, createDecisionQuestionsEvent, createErrorEvent, createGraphEndEvent, createPhaseStartEvent, createPhaseEndEvent, createGraphStartEvent, createIterationStartEvent, createLlmStartEvent, createLlmEndEvent, createResponseCompleteEvent, createResponseResetEvent, createHallucinationDetectedEvent, createStatusEvent, createTokenEvent, createToolActivityEvent, createChatSummarizerStartEvent, createChatSummarizerEndEvent,
|
|
3
|
+
import { createAgentEndEvent, createAgentStartEvent, createDebugMetaEvent, createDecisionQuestionsEvent, createErrorEvent, createGraphEndEvent, createPhaseStartEvent, createPhaseEndEvent, createGraphStartEvent, createIterationStartEvent, createLlmStartEvent, createLlmEndEvent, createResponseCompleteEvent, createResponseResetEvent, createHallucinationDetectedEvent, createStatusEvent, createTokenEvent, createToolActivityEvent, createChatSummarizerStartEvent, createChatSummarizerEndEvent, createUserQuestionEvent } from "./chat-streaming.types.js";
|
|
4
4
|
const logger = protocolLogger("ChatStreamer");
|
|
5
5
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
6
6
|
// CHAT STREAMER (Streaming Narration Architecture)
|
|
@@ -176,12 +176,6 @@ export class ChatStreamer {
|
|
|
176
176
|
if (event.type === "chat_summarizer_end") {
|
|
177
177
|
yield createChatSummarizerEndEvent(sessionId, event.payload);
|
|
178
178
|
}
|
|
179
|
-
if (event.type === "question_generator_start") {
|
|
180
|
-
yield createQuestionGeneratorStartEvent(sessionId, event.payload);
|
|
181
|
-
}
|
|
182
|
-
if (event.type === "question_generator_end") {
|
|
183
|
-
yield createQuestionGeneratorEndEvent(sessionId, event.payload);
|
|
184
|
-
}
|
|
185
179
|
}
|
|
186
180
|
// ─────────────────────────────────────────────────────────────────
|
|
187
181
|
// UPDATES: final state from agentLoopNode
|
|
@@ -206,7 +200,7 @@ export class ChatStreamer {
|
|
|
206
200
|
if (debugMeta?.graph != null &&
|
|
207
201
|
typeof debugMeta.iterations === "number") {
|
|
208
202
|
const llmFallback = { calls: 0, totalDurationMs: 0, resets: [], hallucinations: [] };
|
|
209
|
-
yield createDebugMetaEvent(sessionId, debugMeta.graph, debugMeta.iterations, Array.isArray(debugMeta.tools) ? debugMeta.tools : [], debugMeta.llm ?? llmFallback, debugMeta.orchestratorNegotiations
|
|
203
|
+
yield createDebugMetaEvent(sessionId, debugMeta.graph, debugMeta.iterations, Array.isArray(debugMeta.tools) ? debugMeta.tools : [], debugMeta.llm ?? llmFallback, debugMeta.orchestratorNegotiations);
|
|
210
204
|
}
|
|
211
205
|
logger.verbose("Agent loop complete (updates)", {
|
|
212
206
|
responseLength: responseText.length,
|
package/dist/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export type { NetworkAssignmentMetadata } from "./shared/schemas/network-assignm
|
|
|
34
34
|
export { DEFAULT_NETWORK_ASSIGNMENT_THRESHOLD, resolveAssignmentNetworkScope, buildNetworkAssignmentDecision } from "./shared/assignment/network-assignment.policy.js";
|
|
35
35
|
export { buildCandidateEvidence } from "./capabilities/opportunities.facade.js";
|
|
36
36
|
export { ChatGraphFactory } from "./capabilities/participant-agents.facade.js";
|
|
37
|
-
export {
|
|
37
|
+
export { type ChatPersonaConfig } from "./capabilities/participant-agents.facade.js";
|
|
38
38
|
export { NEGOTIATOR_PERSONA_ID, createNegotiatorPersona } from "./capabilities/participant-agents.facade.js";
|
|
39
39
|
export { SIGNAL_PERSONA_ID, SIGNAL_PERSONA, SIGNAL_NEW_SIGNAL_KICKOFF, SIGNAL_TOOL_NAMES, createSignalTools, filterSignalTools, narrowSignalTools, } from "./capabilities/participant-agents.facade.js";
|
|
40
40
|
export { REPORTER_PERSONA_ID, REPORTER_PERSONA, REPORTER_BRIEFING_KICKOFF, REPORTER_TOOL_NAMES, createReporterTools, filterReporterTools, narrowReporterTools, } from "./capabilities/participant-agents.facade.js";
|
|
@@ -82,7 +82,7 @@ export type { NegotiatorMemoryEntry } from "./capabilities/negotiation.facade.js
|
|
|
82
82
|
export { QuestionerAgent } from "./capabilities/questions.facade.js";
|
|
83
83
|
export { isValidQuestionerInputContract } from "./capabilities/questions.facade.js";
|
|
84
84
|
export type { QuestionerInput, RecoveryQuestionerInput, UptakeQuestionerInput, PostStallQuestionerInput, InflightQuestionerInput, QuestionerEnqueuePayload, QuestionerEnqueueFn, PoolDiscoveryContext } from "./capabilities/questions.facade.js";
|
|
85
|
-
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold } from "./capabilities/questions.facade.js";
|
|
85
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, intentQuestionDailyCap, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS } from "./capabilities/questions.facade.js";
|
|
86
86
|
export { PoolDiscriminatorMiner } from "./capabilities/opportunities.facade.js";
|
|
87
87
|
export { PoolDiscriminatorAssigner } from "./capabilities/opportunities.facade.js";
|
|
88
88
|
export type { PoolDiscriminatorAssignmentInput, PoolDiscriminatorAssignedAxis } from "./capabilities/opportunities.facade.js";
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,6 @@ export { DEFAULT_NETWORK_ASSIGNMENT_THRESHOLD, resolveAssignmentNetworkScope, bu
|
|
|
30
30
|
export { buildCandidateEvidence } from "./capabilities/opportunities.facade.js";
|
|
31
31
|
// ─── Graph factories ──────────────────────────────────────────────────────────
|
|
32
32
|
export { ChatGraphFactory } from "./capabilities/participant-agents.facade.js";
|
|
33
|
-
export { ORCHESTRATOR_PERSONA_ID } from "./capabilities/participant-agents.facade.js";
|
|
34
33
|
export { NEGOTIATOR_PERSONA_ID, createNegotiatorPersona } from "./capabilities/participant-agents.facade.js";
|
|
35
34
|
export { SIGNAL_PERSONA_ID, SIGNAL_PERSONA, SIGNAL_NEW_SIGNAL_KICKOFF, SIGNAL_TOOL_NAMES, createSignalTools, filterSignalTools, narrowSignalTools, } from "./capabilities/participant-agents.facade.js";
|
|
36
35
|
export { REPORTER_PERSONA_ID, REPORTER_PERSONA, REPORTER_BRIEFING_KICKOFF, REPORTER_TOOL_NAMES, createReporterTools, filterReporterTools, narrowReporterTools, } from "./capabilities/participant-agents.facade.js";
|
|
@@ -68,7 +67,7 @@ export { NegotiationScreener } from "./capabilities/negotiation.facade.js";
|
|
|
68
67
|
export { NegotiationReflector } from "./capabilities/negotiation.facade.js";
|
|
69
68
|
export { QuestionerAgent } from "./capabilities/questions.facade.js";
|
|
70
69
|
export { isValidQuestionerInputContract } from "./capabilities/questions.facade.js";
|
|
71
|
-
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold } from "./capabilities/questions.facade.js";
|
|
70
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, intentQuestionDailyCap, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS } from "./capabilities/questions.facade.js";
|
|
72
71
|
export { PoolDiscriminatorMiner } from "./capabilities/opportunities.facade.js";
|
|
73
72
|
export { PoolDiscriminatorAssigner } from "./capabilities/opportunities.facade.js";
|
|
74
73
|
export { runPoolDiscriminatorShadow } from "./capabilities/opportunities.facade.js";
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* The following are application-internal or runtime-owned:
|
|
18
18
|
* - ChatGraphFactory, ChatPersonaConfig, ChatPersona — runtime graph wiring;
|
|
19
19
|
* consumers should import via capabilities/participant-agents.facade.ts.
|
|
20
|
-
* - Persona constants (
|
|
20
|
+
* - Persona constants (SIGNAL_PERSONA, REPORTER_PERSONA, etc.) — chat
|
|
21
21
|
* runtime internals; import from capabilities/participant-agents.facade.ts.
|
|
22
22
|
* - ChatTitleGenerator, ChatSummarizer, etc. — runtime tool composition; import
|
|
23
23
|
* via capabilities/participant-agents.facade.ts.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* The following are application-internal or runtime-owned:
|
|
18
18
|
* - ChatGraphFactory, ChatPersonaConfig, ChatPersona — runtime graph wiring;
|
|
19
19
|
* consumers should import via capabilities/participant-agents.facade.ts.
|
|
20
|
-
* - Persona constants (
|
|
20
|
+
* - Persona constants (SIGNAL_PERSONA, REPORTER_PERSONA, etc.) — chat
|
|
21
21
|
* runtime internals; import from capabilities/participant-agents.facade.ts.
|
|
22
22
|
* - ChatTitleGenerator, ChatSummarizer, etc. — runtime tool composition; import
|
|
23
23
|
* via capabilities/participant-agents.facade.ts.
|
|
@@ -32,7 +32,7 @@ export { isValidQuestionerInputContract, } from "./question.input.js";
|
|
|
32
32
|
export type { QuestionerInput, QuestionerContext, QuestionerEnqueuePayload, QuestionerEnqueueFn, IntentContext, RecoveryIntentContext, NegotiationContext, PostStallNegotiationContext, UptakeNegotiationContext, NegotiationInflightContext, ChatContext, PoolDiscoveryContext, PostStallQuestionerInput, InflightQuestionerInput, UptakeQuestionerInput, RecoveryQuestionerInput, } from "./question.input.js";
|
|
33
33
|
export { QuestionerAgent } from "./question.agent.js";
|
|
34
34
|
export type { QuestionerAgentConfig } from "./question.agent.js";
|
|
35
|
-
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, } from "./question.env.js";
|
|
35
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, intentQuestionDailyCap, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
|
|
36
36
|
export { getPreset } from "./question.presets.js";
|
|
37
37
|
export type { QuestionerPreset } from "./question.presets.js";
|
|
38
38
|
export { createQuestionerTools } from "./question.tools.js";
|
|
@@ -33,7 +33,7 @@ export { isValidQuestionerInputContract, } from "./question.input.js";
|
|
|
33
33
|
// ── Agent ─────────────────────────────────────────────────────────────────────
|
|
34
34
|
export { QuestionerAgent } from "./question.agent.js";
|
|
35
35
|
// ── Env ───────────────────────────────────────────────────────────────────────
|
|
36
|
-
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, } from "./question.env.js";
|
|
36
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, intentQuestionDailyCap, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
|
|
37
37
|
// ── Presets ───────────────────────────────────────────────────────────────────
|
|
38
38
|
export { getPreset } from "./question.presets.js";
|
|
39
39
|
// ── Foreground adapter tools ──────────────────────────────────────────────────
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
* authority threshold (0-100, default 70).
|
|
12
12
|
* QUESTIONER_CHAT_WAIT_TIMEOUT_MS how long the blocking ask_user_question chat
|
|
13
13
|
* tool waits for an inline answer (default 4 min).
|
|
14
|
+
* QUESTIONER_INTENT_DAILY_CAP refinement questions one intent may generate
|
|
15
|
+
* per rolling 24h, recovery + pool combined
|
|
16
|
+
* (default 2; 0 disables refinement).
|
|
14
17
|
*
|
|
15
18
|
* All reads go through this module — do not read these variables via
|
|
16
19
|
* `process.env` elsewhere. Values are read on every call (no caching) so tests
|
|
@@ -21,6 +24,25 @@
|
|
|
21
24
|
*/
|
|
22
25
|
export declare const CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT = 240000;
|
|
23
26
|
export declare const UPTAKE_AUTHORITY_THRESHOLD_DEFAULT = 70;
|
|
27
|
+
/**
|
|
28
|
+
* Refinement questions a single intent may generate per rolling window.
|
|
29
|
+
*
|
|
30
|
+
* Recovery and pool mining both re-arm when the intent text changes, and
|
|
31
|
+
* answering a refinement question is itself what changes it — so each answer
|
|
32
|
+
* buys another question and the loop ends only when the user stops replying.
|
|
33
|
+
* Measured on a dev account: 27 questions against three intents in 9.5 hours,
|
|
34
|
+
* one discriminator asked three times, while the best-scoring match had already
|
|
35
|
+
* been found after the first question.
|
|
36
|
+
*/
|
|
37
|
+
export declare const INTENT_QUESTION_DAILY_CAP_DEFAULT = 2;
|
|
38
|
+
/**
|
|
39
|
+
* Width of the budget window, in hours.
|
|
40
|
+
*
|
|
41
|
+
* Rolling rather than per-UTC-day deliberately: the observed bursts straddled
|
|
42
|
+
* midnight UTC (20:22-21:18, then 05:48-05:55), and a calendar-day budget would
|
|
43
|
+
* have granted the second burst a full fresh allowance.
|
|
44
|
+
*/
|
|
45
|
+
export declare const INTENT_QUESTION_DAILY_WINDOW_HOURS = 24;
|
|
24
46
|
/** Master switch: is any background question generation enabled? */
|
|
25
47
|
export declare function isQuestionerEnabled(): boolean;
|
|
26
48
|
/** Advisory uptake interlock. Flag-off by default and subordinate to the master switch. */
|
|
@@ -29,3 +51,10 @@ export declare function isUptakeGuardEnabled(): boolean;
|
|
|
29
51
|
export declare function uptakeAuthorityThreshold(): number;
|
|
30
52
|
/** Wait budget for the blocking ask_user_question chat tool. */
|
|
31
53
|
export declare function chatQuestionWaitTimeoutMs(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Per-intent refinement budget over {@link INTENT_QUESTION_DAILY_WINDOW_HOURS}.
|
|
56
|
+
*
|
|
57
|
+
* Zero is a meaningful setting — it disables background refinement entirely
|
|
58
|
+
* without touching the master switch — so this does not reuse `positiveIntEnv`.
|
|
59
|
+
*/
|
|
60
|
+
export declare function intentQuestionDailyCap(): number;
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
* authority threshold (0-100, default 70).
|
|
12
12
|
* QUESTIONER_CHAT_WAIT_TIMEOUT_MS how long the blocking ask_user_question chat
|
|
13
13
|
* tool waits for an inline answer (default 4 min).
|
|
14
|
+
* QUESTIONER_INTENT_DAILY_CAP refinement questions one intent may generate
|
|
15
|
+
* per rolling 24h, recovery + pool combined
|
|
16
|
+
* (default 2; 0 disables refinement).
|
|
14
17
|
*
|
|
15
18
|
* All reads go through this module — do not read these variables via
|
|
16
19
|
* `process.env` elsewhere. Values are read on every call (no caching) so tests
|
|
@@ -21,6 +24,25 @@
|
|
|
21
24
|
*/
|
|
22
25
|
export const CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT = 240000;
|
|
23
26
|
export const UPTAKE_AUTHORITY_THRESHOLD_DEFAULT = 70;
|
|
27
|
+
/**
|
|
28
|
+
* Refinement questions a single intent may generate per rolling window.
|
|
29
|
+
*
|
|
30
|
+
* Recovery and pool mining both re-arm when the intent text changes, and
|
|
31
|
+
* answering a refinement question is itself what changes it — so each answer
|
|
32
|
+
* buys another question and the loop ends only when the user stops replying.
|
|
33
|
+
* Measured on a dev account: 27 questions against three intents in 9.5 hours,
|
|
34
|
+
* one discriminator asked three times, while the best-scoring match had already
|
|
35
|
+
* been found after the first question.
|
|
36
|
+
*/
|
|
37
|
+
export const INTENT_QUESTION_DAILY_CAP_DEFAULT = 2;
|
|
38
|
+
/**
|
|
39
|
+
* Width of the budget window, in hours.
|
|
40
|
+
*
|
|
41
|
+
* Rolling rather than per-UTC-day deliberately: the observed bursts straddled
|
|
42
|
+
* midnight UTC (20:22-21:18, then 05:48-05:55), and a calendar-day budget would
|
|
43
|
+
* have granted the second burst a full fresh allowance.
|
|
44
|
+
*/
|
|
45
|
+
export const INTENT_QUESTION_DAILY_WINDOW_HOURS = 24;
|
|
24
46
|
/**
|
|
25
47
|
* Parse a positive integer env var, clamped to the safe-integer range so a
|
|
26
48
|
* malformed env value cannot crash `AbortSignal.timeout` (which throws on
|
|
@@ -57,3 +79,17 @@ export function uptakeAuthorityThreshold() {
|
|
|
57
79
|
export function chatQuestionWaitTimeoutMs() {
|
|
58
80
|
return positiveIntEnv("QUESTIONER_CHAT_WAIT_TIMEOUT_MS", CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT);
|
|
59
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Per-intent refinement budget over {@link INTENT_QUESTION_DAILY_WINDOW_HOURS}.
|
|
84
|
+
*
|
|
85
|
+
* Zero is a meaningful setting — it disables background refinement entirely
|
|
86
|
+
* without touching the master switch — so this does not reuse `positiveIntEnv`.
|
|
87
|
+
*/
|
|
88
|
+
export function intentQuestionDailyCap() {
|
|
89
|
+
const raw = process.env.QUESTIONER_INTENT_DAILY_CAP;
|
|
90
|
+
if (!raw?.trim())
|
|
91
|
+
return INTENT_QUESTION_DAILY_CAP_DEFAULT;
|
|
92
|
+
if (!/^\d+$/.test(raw.trim()))
|
|
93
|
+
return INTENT_QUESTION_DAILY_CAP_DEFAULT;
|
|
94
|
+
return Number.parseInt(raw, 10);
|
|
95
|
+
}
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
export * from "../domain/index.js";
|
|
41
41
|
export { QuestionerAgent } from "../application/index.js";
|
|
42
42
|
export type { QuestionerAgentConfig } from "../application/index.js";
|
|
43
|
-
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, } from "../application/index.js";
|
|
43
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, intentQuestionDailyCap, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "../application/index.js";
|
|
44
44
|
export { isValidQuestionerInputContract, } from "../application/index.js";
|
|
45
45
|
export type { QuestionerInput, QuestionerEnqueuePayload, QuestionerEnqueueFn, PoolDiscoveryContext, RecoveryQuestionerInput, UptakeQuestionerInput, PostStallQuestionerInput, InflightQuestionerInput, } from "../application/index.js";
|
|
46
46
|
export { createQuestionerTools, createAskUserQuestionTools } from "../application/index.js";
|
|
@@ -42,7 +42,7 @@ export * from "../domain/index.js";
|
|
|
42
42
|
// ── Application: agent ────────────────────────────────────────────────────────
|
|
43
43
|
export { QuestionerAgent } from "../application/index.js";
|
|
44
44
|
// ── Application: env accessors ────────────────────────────────────────────────
|
|
45
|
-
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, } from "../application/index.js";
|
|
45
|
+
export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, intentQuestionDailyCap, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "../application/index.js";
|
|
46
46
|
// ── Application: input types and validation ───────────────────────────────────
|
|
47
47
|
export { isValidQuestionerInputContract, } from "../application/index.js";
|
|
48
48
|
// ── Application: foreground adapter tools ─────────────────────────────────────
|