@indexnetwork/protocol 4.3.4-rc.310.1 → 4.3.4-rc.312.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat/chat.graph.d.ts +8 -8
- package/dist/chat/chat.prompt.d.ts.map +1 -1
- package/dist/chat/chat.prompt.js +18 -8
- package/dist/chat/chat.prompt.js.map +1 -1
- package/dist/chat/chat.state.d.ts +4 -3
- package/dist/chat/chat.state.d.ts.map +1 -1
- package/dist/chat/chat.state.js +2 -2
- package/dist/chat/chat.state.js.map +1 -1
- package/dist/chat/chat.streamer.d.ts +3 -2
- package/dist/chat/chat.streamer.d.ts.map +1 -1
- package/dist/chat/chat.streamer.js +2 -2
- package/dist/chat/chat.streamer.js.map +1 -1
- package/dist/intent/intent.graph.d.ts +5 -5
- package/dist/intent/intent.state.d.ts +2 -1
- package/dist/intent/intent.state.d.ts.map +1 -1
- package/dist/intent/intent.tools.d.ts.map +1 -1
- package/dist/intent/intent.tools.js +54 -2
- package/dist/intent/intent.tools.js.map +1 -1
- package/dist/opportunity/feed/feed.graph.d.ts +10 -0
- package/dist/opportunity/feed/feed.graph.d.ts.map +1 -1
- package/dist/opportunity/feed/feed.graph.js +4 -0
- package/dist/opportunity/feed/feed.graph.js.map +1 -1
- package/dist/opportunity/feed/feed.state.d.ts +2 -0
- package/dist/opportunity/feed/feed.state.d.ts.map +1 -1
- package/dist/opportunity/feed/feed.state.js +8 -0
- package/dist/opportunity/feed/feed.state.js.map +1 -1
- package/dist/opportunity/opportunity.graph.d.ts +6 -6
- package/dist/opportunity/opportunity.pending-questions.d.ts +5 -0
- package/dist/opportunity/opportunity.pending-questions.d.ts.map +1 -1
- package/dist/opportunity/opportunity.pending-questions.js +2 -1
- package/dist/opportunity/opportunity.pending-questions.js.map +1 -1
- package/dist/opportunity/opportunity.state.d.ts +1 -1
- package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
- package/dist/opportunity/opportunity.tools.js +80 -7
- package/dist/opportunity/opportunity.tools.js.map +1 -1
- package/dist/premise/premise.graph.d.ts +4 -4
- package/dist/premise/premise.state.d.ts +2 -1
- package/dist/premise/premise.state.d.ts.map +1 -1
- package/dist/questioner/questioner.tools.d.ts.map +1 -1
- package/dist/questioner/questioner.tools.js +21 -8
- package/dist/questioner/questioner.tools.js.map +1 -1
- package/dist/shared/agent/tool.factory.d.ts.map +1 -1
- package/dist/shared/agent/tool.factory.js +4 -0
- package/dist/shared/agent/tool.factory.js.map +1 -1
- package/dist/shared/agent/tool.helpers.d.ts +22 -6
- package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
- package/dist/shared/agent/tool.helpers.js.map +1 -1
- package/dist/shared/agent/tool.scope.d.ts +7 -1
- package/dist/shared/agent/tool.scope.d.ts.map +1 -1
- package/dist/shared/agent/tool.scope.js +10 -0
- package/dist/shared/agent/tool.scope.js.map +1 -1
- package/dist/shared/hyde/hyde.graph.d.ts +6 -6
- package/dist/shared/hyde/hyde.state.d.ts +2 -2
- package/dist/shared/interfaces/database.interface.d.ts +3 -0
- package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
- package/dist/shared/interfaces/database.interface.js.map +1 -1
- package/dist/shared/interfaces/questioner.interface.d.ts +3 -0
- package/dist/shared/interfaces/questioner.interface.d.ts.map +1 -1
- package/dist/shared/interfaces/questioner.interface.js.map +1 -1
- package/dist/shared/schemas/network-assignment.schema.d.ts +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { requestContext } from "../shared/observability/request-context.js";
|
|
3
3
|
import { success, error, UUID_REGEX } from "../shared/agent/tool.helpers.js";
|
|
4
|
-
import { deriveDiscoveryNetworkIds, focusedNetworkId, focusedNetworkLabel } from "../shared/agent/tool.scope.js";
|
|
4
|
+
import { deriveDiscoveryNetworkIds, focusedIntentId, focusedNetworkId, focusedNetworkLabel } from "../shared/agent/tool.scope.js";
|
|
5
5
|
import { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from "./opportunity.labels.js";
|
|
6
6
|
import { viewerCentricCardSummary, narratorRemarkFromReasoning, stripUuids } from "./opportunity.presentation.js";
|
|
7
7
|
import { runDiscoverFromQuery, continueDiscovery } from "./opportunity.discover.js";
|
|
@@ -177,6 +177,13 @@ const UPDATE_OPPORTUNITY_BLOCKED_STATUSES = new Set([
|
|
|
177
177
|
"expired",
|
|
178
178
|
"negotiating",
|
|
179
179
|
]);
|
|
180
|
+
function matchesSelectedIntentScope(opportunity, viewerId, scope) {
|
|
181
|
+
if (scope?.scopeType !== 'intent' || !scope.scopeId)
|
|
182
|
+
return true;
|
|
183
|
+
if (opportunity.detection?.triggeredBy === scope.scopeId)
|
|
184
|
+
return true;
|
|
185
|
+
return opportunity.actors.some((actor) => actor.userId === viewerId && actor.intent === scope.scopeId);
|
|
186
|
+
}
|
|
180
187
|
/**
|
|
181
188
|
* Maximum number of opportunity cards to show per chat response.
|
|
182
189
|
* Sized for `selectByComposition` to fill both feed buckets — up to 3
|
|
@@ -515,7 +522,7 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
515
522
|
"'complementary skills for a startup'). Helps the evaluator produce better match reasoning."),
|
|
516
523
|
}),
|
|
517
524
|
handler: async ({ context, query }) => {
|
|
518
|
-
const scopedNetworkId = focusedNetworkId(context);
|
|
525
|
+
const scopedNetworkId = focusedNetworkId(context) ?? context.networkId?.trim();
|
|
519
526
|
const scopedIndexLabel = focusedNetworkLabel(context);
|
|
520
527
|
// Strict scope enforcement: when chat is network-scoped, only allow that index
|
|
521
528
|
if (scopedNetworkId &&
|
|
@@ -566,7 +573,7 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
566
573
|
userId: context.userId,
|
|
567
574
|
userName: context.userName,
|
|
568
575
|
userEmail: context.userEmail,
|
|
569
|
-
...(scopedNetworkId ? { scopeType: 'network', scopeId: scopedNetworkId } : {}),
|
|
576
|
+
...(context.scopeType && context.scopeId ? { scopeType: context.scopeType, scopeId: context.scopeId } : scopedNetworkId ? { scopeType: 'network', scopeId: scopedNetworkId } : {}),
|
|
570
577
|
...(context.indexName ? { indexName: context.indexName } : {}),
|
|
571
578
|
...(context.sessionId ? { sessionId: context.sessionId } : {}),
|
|
572
579
|
...(context.agentId ? { agentId: context.agentId } : {}),
|
|
@@ -895,10 +902,15 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
895
902
|
const toolDebugSteps = [
|
|
896
903
|
{ step: "resolve_index_scope", detail: `${indexScope.length} index(es)` },
|
|
897
904
|
];
|
|
898
|
-
const
|
|
899
|
-
|
|
905
|
+
const contextIntentId = focusedIntentId(context);
|
|
906
|
+
const requestedIntentId = query.intentId?.trim() || undefined;
|
|
907
|
+
if (requestedIntentId != null && !UUID_REGEX.test(requestedIntentId)) {
|
|
900
908
|
return error("Invalid intent ID format.");
|
|
901
909
|
}
|
|
910
|
+
if (contextIntentId && requestedIntentId && requestedIntentId !== contextIntentId) {
|
|
911
|
+
return error("This chat is scoped to a different intent.");
|
|
912
|
+
}
|
|
913
|
+
const triggerIntentId = contextIntentId ?? requestedIntentId;
|
|
902
914
|
if (query.introTargetUserId?.trim() && query.introTargetUserId.trim() === context.userId) {
|
|
903
915
|
return error("You cannot discover introductions for yourself. Try regular discovery instead.");
|
|
904
916
|
}
|
|
@@ -965,6 +977,7 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
965
977
|
userId: context.userId,
|
|
966
978
|
sourceType: 'discovery',
|
|
967
979
|
...(context.scopeType === 'network' && context.scopeId ? { networkId: context.scopeId } : {}),
|
|
980
|
+
...(contextIntentId ? { scopeType: 'intent', scopeId: contextIntentId } : {}),
|
|
968
981
|
surfacedQuestionIds: new Set(), // Dedup handled at chat.agent level
|
|
969
982
|
});
|
|
970
983
|
const pendingQuestions = pendingQuestionResult.questions;
|
|
@@ -1301,13 +1314,21 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1301
1314
|
.string()
|
|
1302
1315
|
.optional()
|
|
1303
1316
|
.describe("Network UUID to filter opportunities to a specific community. Get from read_networks. Defaults to the scoped network in network-scoped chats. Omit to see opportunities across all networks."),
|
|
1317
|
+
scopeType: z
|
|
1318
|
+
.enum(['intent'])
|
|
1319
|
+
.optional()
|
|
1320
|
+
.describe("Optional selected scope type. Use 'intent' to narrow listed opportunities to a selected intent."),
|
|
1321
|
+
scopeId: z
|
|
1322
|
+
.string()
|
|
1323
|
+
.optional()
|
|
1324
|
+
.describe("Selected intent UUID when scopeType is 'intent'. Ignored only when absent."),
|
|
1304
1325
|
includeDigestMarkers: z
|
|
1305
1326
|
.boolean()
|
|
1306
1327
|
.optional()
|
|
1307
1328
|
.describe("Internal scheduled-digest mode only. When true, includes hidden delivery markers so the digest send pass can confirm only edited-in opportunities."),
|
|
1308
1329
|
}),
|
|
1309
1330
|
handler: async ({ context, query }) => {
|
|
1310
|
-
const scopedNetworkId = focusedNetworkId(context);
|
|
1331
|
+
const scopedNetworkId = focusedNetworkId(context) ?? context.networkId?.trim();
|
|
1311
1332
|
const scopedIndexLabel = focusedNetworkLabel(context);
|
|
1312
1333
|
// Strict scope enforcement: when chat is network-scoped, only allow that index
|
|
1313
1334
|
if (scopedNetworkId &&
|
|
@@ -1319,6 +1340,25 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1319
1340
|
if (effectiveIndexId && !UUID_REGEX.test(effectiveIndexId)) {
|
|
1320
1341
|
return error("Invalid network ID format.");
|
|
1321
1342
|
}
|
|
1343
|
+
const contextIntentId = focusedIntentId(context);
|
|
1344
|
+
const rawScopeId = query.scopeId?.trim() || undefined;
|
|
1345
|
+
if (query.scopeType === 'intent' && !rawScopeId) {
|
|
1346
|
+
return error("scopeId required when scopeType is intent.");
|
|
1347
|
+
}
|
|
1348
|
+
if (!query.scopeType && rawScopeId) {
|
|
1349
|
+
return error("scopeType=intent required when scopeId is provided.");
|
|
1350
|
+
}
|
|
1351
|
+
if (rawScopeId && !UUID_REGEX.test(rawScopeId)) {
|
|
1352
|
+
return error("Invalid scope ID format.");
|
|
1353
|
+
}
|
|
1354
|
+
if (contextIntentId && rawScopeId && contextIntentId !== rawScopeId) {
|
|
1355
|
+
return error("This chat is scoped to a different intent.");
|
|
1356
|
+
}
|
|
1357
|
+
const effectiveIntentScope = contextIntentId
|
|
1358
|
+
? { scopeType: 'intent', scopeId: contextIntentId }
|
|
1359
|
+
: query.scopeType === 'intent' && rawScopeId
|
|
1360
|
+
? { scopeType: 'intent', scopeId: rawScopeId }
|
|
1361
|
+
: {};
|
|
1322
1362
|
// The MCP/chat surface exposes actionable opportunities.
|
|
1323
1363
|
// `latent` is included so the introducer-as-viewer can see their unapproved
|
|
1324
1364
|
// connector-flow cards ("do you know someone for X?"). Other latent visibility
|
|
@@ -1331,6 +1371,7 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1331
1371
|
// sort order can fill the whole window and starve the other section.
|
|
1332
1372
|
const fetched = await database.getOpportunitiesForUser(context.userId, {
|
|
1333
1373
|
networkId: effectiveIndexId,
|
|
1374
|
+
...effectiveIntentScope,
|
|
1334
1375
|
statuses,
|
|
1335
1376
|
limit: CHAT_FETCH_LIMIT,
|
|
1336
1377
|
});
|
|
@@ -1399,8 +1440,10 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1399
1440
|
if (isDigestMode && deduped.length > 0) {
|
|
1400
1441
|
const acceptedCounterpartIds = new Set();
|
|
1401
1442
|
try {
|
|
1443
|
+
// effectiveIntentScope scopes the statuses: ["accepted"] suppression fetch.
|
|
1402
1444
|
const acceptedOpps = await database.getOpportunitiesForUser(context.userId, {
|
|
1403
1445
|
...(effectiveIndexId ? { networkId: effectiveIndexId } : {}),
|
|
1446
|
+
...effectiveIntentScope,
|
|
1404
1447
|
statuses: ["accepted"],
|
|
1405
1448
|
limit: ACCEPTED_SUPPRESSION_FETCH_LIMIT,
|
|
1406
1449
|
});
|
|
@@ -1789,12 +1832,39 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1789
1832
|
.enum(["pending", "accepted", "rejected", "expired"])
|
|
1790
1833
|
.describe("New status: 'pending' = send the draft to the other party, 'accepted' = accept the connection, " +
|
|
1791
1834
|
"'rejected' = decline, 'expired' = mark as timed out."),
|
|
1835
|
+
scopeType: z
|
|
1836
|
+
.enum(['intent'])
|
|
1837
|
+
.optional()
|
|
1838
|
+
.describe("Optional selected scope type. Use 'intent' to require this opportunity to belong to a selected intent."),
|
|
1839
|
+
scopeId: z
|
|
1840
|
+
.string()
|
|
1841
|
+
.optional()
|
|
1842
|
+
.describe("Selected intent UUID when scopeType is 'intent'. Must match the chat's focused intent when one exists."),
|
|
1792
1843
|
}),
|
|
1793
1844
|
handler: async ({ context, query }) => {
|
|
1794
1845
|
const opportunityId = query.opportunityId?.trim();
|
|
1795
1846
|
if (!opportunityId || !UUID_REGEX.test(opportunityId)) {
|
|
1796
1847
|
return error("Valid opportunityId required.");
|
|
1797
1848
|
}
|
|
1849
|
+
const contextIntentId = focusedIntentId(context);
|
|
1850
|
+
const rawScopeId = query.scopeId?.trim() || undefined;
|
|
1851
|
+
if (query.scopeType === 'intent' && !rawScopeId) {
|
|
1852
|
+
return error("scopeId required when scopeType is intent.");
|
|
1853
|
+
}
|
|
1854
|
+
if (!query.scopeType && rawScopeId) {
|
|
1855
|
+
return error("scopeType=intent required when scopeId is provided.");
|
|
1856
|
+
}
|
|
1857
|
+
if (rawScopeId && !UUID_REGEX.test(rawScopeId)) {
|
|
1858
|
+
return error("Invalid scope ID format.");
|
|
1859
|
+
}
|
|
1860
|
+
if (contextIntentId && rawScopeId && contextIntentId !== rawScopeId) {
|
|
1861
|
+
return error("This chat is scoped to a different intent.");
|
|
1862
|
+
}
|
|
1863
|
+
const effectiveIntentScope = contextIntentId
|
|
1864
|
+
? { scopeType: 'intent', scopeId: contextIntentId }
|
|
1865
|
+
: query.scopeType === 'intent' && rawScopeId
|
|
1866
|
+
? { scopeType: 'intent', scopeId: rawScopeId }
|
|
1867
|
+
: {};
|
|
1798
1868
|
// Always fetch the opportunity — needed for actor guard and state machine
|
|
1799
1869
|
const opportunity = await systemDb.getOpportunity(opportunityId);
|
|
1800
1870
|
if (!opportunity) {
|
|
@@ -1816,13 +1886,16 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1816
1886
|
// Mirrors the per-actor filter in getOpportunitiesForUser — relying on
|
|
1817
1887
|
// a focus-scope id or any-actor matches would let a counterpart's network
|
|
1818
1888
|
// presence shadow a viewer whose own actor is elsewhere.
|
|
1819
|
-
const scopedNetworkId = focusedNetworkId(context);
|
|
1889
|
+
const scopedNetworkId = focusedNetworkId(context) ?? context.networkId?.trim();
|
|
1820
1890
|
if (scopedNetworkId) {
|
|
1821
1891
|
const callerOnBoundNetwork = opportunity.actors?.some((a) => a.userId === context.userId && a.networkId === scopedNetworkId);
|
|
1822
1892
|
if (!callerOnBoundNetwork) {
|
|
1823
1893
|
return error("Opportunity not found.");
|
|
1824
1894
|
}
|
|
1825
1895
|
}
|
|
1896
|
+
if (!matchesSelectedIntentScope(opportunity, context.userId, effectiveIntentScope)) {
|
|
1897
|
+
return error("Opportunity not found.");
|
|
1898
|
+
}
|
|
1826
1899
|
const isSend = query.status === "pending";
|
|
1827
1900
|
const _updateGraphStart = Date.now();
|
|
1828
1901
|
const _updateTraceEmitter = requestContext.getStore()?.traceEmitter;
|