@indexnetwork/protocol 8.7.0-rc.430.1 → 8.9.0-rc.432.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/enrichment/enrichment.tools.js +0 -1
- package/dist/mcp/mcp.server.d.ts +0 -1
- package/dist/mcp/mcp.server.js +0 -25
- package/dist/opportunity/application/opportunity.card-presentation.d.ts +9 -9
- package/dist/opportunity/application/opportunity.card-presentation.js +14 -25
- package/dist/opportunity/application/opportunity.graph.d.ts +5 -5
- package/dist/opportunity/application/opportunity.tools.d.ts +32 -45
- package/dist/opportunity/application/opportunity.tools.js +53 -114
- package/dist/opportunity/domain/opportunity.state.d.ts +1 -1
- package/dist/opportunity/ports/opportunity.tools.port.d.ts +1 -1
- package/dist/runtime/foreground/composition/tool.factory.js +0 -2
- package/dist/shared/agent/tool.helpers.d.ts +2 -25
- package/dist/shared/interfaces/auth.interface.d.ts +2 -6
- package/dist/shared/interfaces/enrichment-run.interface.d.ts +1 -1
- package/dist/shared/interfaces/tool-request-context.interface.d.ts +0 -1
- package/dist/shared/schemas/mcp-auth.schema.d.ts +0 -8
- package/dist/shared/schemas/mcp-auth.schema.js +0 -2
- package/package.json +1 -1
- package/dist/shared/interfaces/connect-link.interface.d.ts +0 -39
- package/dist/shared/interfaces/connect-link.interface.js +0 -1
|
@@ -121,7 +121,6 @@ export function createEnrichmentTools(defineTool, deps) {
|
|
|
121
121
|
...(context.indexName ? { indexName: context.indexName } : {}),
|
|
122
122
|
...(context.sessionId ? { sessionId: context.sessionId } : {}),
|
|
123
123
|
...(context.agentId ? { agentId: context.agentId } : {}),
|
|
124
|
-
...(context.clientSurface ? { clientSurface: context.clientSurface } : {}),
|
|
125
124
|
},
|
|
126
125
|
});
|
|
127
126
|
try {
|
package/dist/mcp/mcp.server.d.ts
CHANGED
|
@@ -87,5 +87,4 @@ export declare const MCP_INSTRUCTIONS: string;
|
|
|
87
87
|
* Extracts a Bearer token from an HTTP Authorization header.
|
|
88
88
|
*/
|
|
89
89
|
export declare function extractBearerToken(req: Request): string | undefined;
|
|
90
|
-
export declare function parseClientSurface(raw: string | null): 'telegram' | 'web';
|
|
91
90
|
export declare function createMcpServer(deps: ToolRegistryDeps, authResolver: McpAuthResolver, scopedDepsFactory: ScopedDepsFactory, policyOptions?: McpCapabilityPolicyOptions, authorizationObserver?: McpAuthorizationObserver): McpServer;
|
package/dist/mcp/mcp.server.js
CHANGED
|
@@ -317,27 +317,6 @@ export function extractBearerToken(req) {
|
|
|
317
317
|
return token;
|
|
318
318
|
return undefined;
|
|
319
319
|
}
|
|
320
|
-
/**
|
|
321
|
-
* Normalizes the x-index-surface header to a typed surface value.
|
|
322
|
-
* Unknown or absent values collapse to 'web'.
|
|
323
|
-
*/
|
|
324
|
-
let hasWarnedInvalidSurface = false;
|
|
325
|
-
export function parseClientSurface(raw) {
|
|
326
|
-
if (raw === null || raw === '')
|
|
327
|
-
return 'web';
|
|
328
|
-
const trimmed = raw.trim().toLowerCase();
|
|
329
|
-
if (trimmed === '')
|
|
330
|
-
return 'web';
|
|
331
|
-
if (trimmed === 'telegram')
|
|
332
|
-
return 'telegram';
|
|
333
|
-
if (trimmed === 'web')
|
|
334
|
-
return 'web';
|
|
335
|
-
if (!hasWarnedInvalidSurface) {
|
|
336
|
-
hasWarnedInvalidSurface = true;
|
|
337
|
-
logger.warn('Unknown x-index-surface value (collapsing to web; warning once per process)');
|
|
338
|
-
}
|
|
339
|
-
return 'web';
|
|
340
|
-
}
|
|
341
320
|
export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOptions = {}, authorizationObserver) {
|
|
342
321
|
const server = new McpServer({ name: 'index-network', version: '1.0.0' }, { instructions: MCP_INSTRUCTIONS });
|
|
343
322
|
const toolMetadata = getCachedMcpToolMetadata(deps);
|
|
@@ -367,7 +346,6 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
367
346
|
const extractAuthInput = (httpReq) => ({
|
|
368
347
|
bearerToken: extractBearerToken(httpReq),
|
|
369
348
|
apiKey: httpReq.headers.get('x-api-key') ?? undefined,
|
|
370
|
-
clientSurface: parseClientSurface(httpReq.headers.get('x-index-surface')),
|
|
371
349
|
telegramHandle: httpReq.headers.get('x-index-telegram-handle') ?? undefined,
|
|
372
350
|
telegramUsername: httpReq.headers.get('x-index-telegram-username') ?? undefined,
|
|
373
351
|
});
|
|
@@ -431,9 +409,6 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
431
409
|
surface: 'mcp',
|
|
432
410
|
sessionAuthenticated: authenticated.identity.isSessionAuth === true,
|
|
433
411
|
});
|
|
434
|
-
if (authenticated.identity.clientSurface) {
|
|
435
|
-
context.clientSurface = authenticated.identity.clientSurface;
|
|
436
|
-
}
|
|
437
412
|
applyNetworkScopeToContext(context, authenticated.identity.networkScopeId);
|
|
438
413
|
const subject = resolveMcpCapabilitySubject({
|
|
439
414
|
identity: authenticated.identity,
|
|
@@ -11,8 +11,9 @@ export type OpportunityCardLike = Record<string, unknown> & {
|
|
|
11
11
|
digestSummary?: string | undefined;
|
|
12
12
|
status?: string | undefined;
|
|
13
13
|
feedCategory?: string | undefined;
|
|
14
|
-
acceptUrl?: string | undefined;
|
|
15
14
|
profileUrl?: string | undefined;
|
|
15
|
+
/** Universal link that opens this opportunity's card (`/o/<id>`). */
|
|
16
|
+
appUrl?: string | undefined;
|
|
16
17
|
/** Deep-link to the A2A negotiation trace that produced this opportunity. */
|
|
17
18
|
negotiationUrl?: string | undefined;
|
|
18
19
|
score?: number | undefined;
|
|
@@ -26,14 +27,13 @@ export type OpportunityCardLike = Record<string, unknown> & {
|
|
|
26
27
|
* "include EXACTLY as-is" directive so the frontend card renderer can parse
|
|
27
28
|
* and render interactive cards.
|
|
28
29
|
*
|
|
29
|
-
* MCP (`isMcp=true`): emits prose (name, reason, status, profileUrl
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* renderer, so code fences would surface as raw JSON to end users.
|
|
30
|
+
* MCP (`isMcp=true`): emits prose (name, reason, status, appUrl and profileUrl
|
|
31
|
+
* when present, feedCategory when present) and includes `opportunityId` for
|
|
32
|
+
* every card so the agent can act via the tools. The trailing instruction
|
|
33
|
+
* reminds the agent to synthesize in natural language, to surface the `appUrl`
|
|
34
|
+
* verbatim as the one link that opens the card, and to fabricate no other URL.
|
|
35
|
+
* MCP clients have no card renderer, so code fences would surface as raw JSON
|
|
36
|
+
* to end users.
|
|
37
37
|
*/
|
|
38
38
|
export declare function buildOpportunityPresentation(inputCards: OpportunityCardLike[], opts: {
|
|
39
39
|
isMcp: boolean;
|
|
@@ -31,14 +31,13 @@ function sanitizeOpportunityCardProse(card) {
|
|
|
31
31
|
* "include EXACTLY as-is" directive so the frontend card renderer can parse
|
|
32
32
|
* and render interactive cards.
|
|
33
33
|
*
|
|
34
|
-
* MCP (`isMcp=true`): emits prose (name, reason, status, profileUrl
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* renderer, so code fences would surface as raw JSON to end users.
|
|
34
|
+
* MCP (`isMcp=true`): emits prose (name, reason, status, appUrl and profileUrl
|
|
35
|
+
* when present, feedCategory when present) and includes `opportunityId` for
|
|
36
|
+
* every card so the agent can act via the tools. The trailing instruction
|
|
37
|
+
* reminds the agent to synthesize in natural language, to surface the `appUrl`
|
|
38
|
+
* verbatim as the one link that opens the card, and to fabricate no other URL.
|
|
39
|
+
* MCP clients have no card renderer, so code fences would surface as raw JSON
|
|
40
|
+
* to end users.
|
|
42
41
|
*/
|
|
43
42
|
export function buildOpportunityPresentation(inputCards, opts) {
|
|
44
43
|
const cards = inputCards.map(sanitizeOpportunityCardProse);
|
|
@@ -61,10 +60,10 @@ export function buildOpportunityPresentation(inputCards, opts) {
|
|
|
61
60
|
}
|
|
62
61
|
if (card.status)
|
|
63
62
|
lines.push(` status: ${card.status}`);
|
|
63
|
+
if (card.appUrl)
|
|
64
|
+
lines.push(` appUrl: ${card.appUrl}`);
|
|
64
65
|
if (card.profileUrl)
|
|
65
66
|
lines.push(` profileUrl: ${card.profileUrl}`);
|
|
66
|
-
if (card.acceptUrl)
|
|
67
|
-
lines.push(` acceptUrl: ${card.acceptUrl}`);
|
|
68
67
|
if (opts.includeDigestMarkers && card.negotiationUrl)
|
|
69
68
|
lines.push(` negotiationUrl: ${card.negotiationUrl}`);
|
|
70
69
|
if (card.feedCategory)
|
|
@@ -73,26 +72,16 @@ export function buildOpportunityPresentation(inputCards, opts) {
|
|
|
73
72
|
lines.push(` confidence: ${Math.round(card.score * 100)}`);
|
|
74
73
|
if (opts.includeDigestMarkers && card.redelivery)
|
|
75
74
|
lines.push(` redelivery: true`);
|
|
76
|
-
|
|
77
|
-
// UUID alongside an actionable link gives the LLM a foothold to
|
|
78
|
-
// hallucinate bare `/api/opportunities/<id>/connect` URLs.
|
|
79
|
-
if (!card.acceptUrl) {
|
|
80
|
-
lines.push(` opportunityId: ${card.opportunityId}`);
|
|
81
|
-
}
|
|
75
|
+
lines.push(` opportunityId: ${card.opportunityId}`);
|
|
82
76
|
return lines.join("\n");
|
|
83
77
|
})
|
|
84
78
|
.join("\n\n");
|
|
85
|
-
const
|
|
86
|
-
const hasOpportunityIds = cards.some((c) => !c.acceptUrl);
|
|
87
|
-
const linkInstructions = hasLinks
|
|
88
|
-
? `For each card that has an acceptUrl, embed it on a short verb phrase (e.g. "message [Name]" for connection, "make intro" for connector-flow). For each card that has a profileUrl, link the person's name to it. Some cards may have neither — render those as plain text and never fabricate URLs for them. The acceptUrl is opaque and self-contained — embed it verbatim. Do NOT append, encode, or modify any part of any URL. Never render link strips or tables — weave URLs into prose. `
|
|
89
|
-
: "";
|
|
90
|
-
const idInstructions = hasOpportunityIds
|
|
91
|
-
? `Use opportunityId values only when calling update_opportunity (send/accept/reject) or confirm_opportunity_delivery.`
|
|
92
|
-
: "";
|
|
79
|
+
const idInstructions = `Use opportunityId values only when calling update_opportunity (send/accept/reject) or confirm_opportunity_delivery.`;
|
|
93
80
|
return (`${opts.leadIn}\n\n${prose}\n\n` +
|
|
94
81
|
`Summarize these for the user in natural prose — mention first names and a brief match reason per connection. ` +
|
|
95
|
-
|
|
82
|
+
`For each card that has a profileUrl, link the person's name to it. Some cards may have no URL — render those as plain text and never fabricate URLs for them. ` +
|
|
83
|
+
`For each card that has an appUrl, show that link so the user can open the opportunity: it opens the card in the Index app when installed, and an Index web page otherwise. Show only an appUrl a tool returned — never assemble one from an opportunityId. ` +
|
|
84
|
+
`No link accepts on the user's behalf: accepting happens in the Index app (or via update_opportunity) — never invent an accept URL. ` +
|
|
96
85
|
`Do NOT print raw JSON, field labels, or opportunityIds. ` +
|
|
97
86
|
`${idInstructions}`);
|
|
98
87
|
}
|
|
@@ -133,7 +133,7 @@ export declare class OpportunityGraphFactory {
|
|
|
133
133
|
targetUserId: Id<"users"> | undefined;
|
|
134
134
|
onBehalfOfUserId: Id<"users"> | undefined;
|
|
135
135
|
options: import("../domain/opportunity.state.js").OpportunityGraphOptions;
|
|
136
|
-
operationMode: "delete" | "send" | "update" | "
|
|
136
|
+
operationMode: "delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction";
|
|
137
137
|
introductionEntities: EvaluatorEntity[];
|
|
138
138
|
introductionHint: string | undefined;
|
|
139
139
|
requiredNetworkId: Id<"networks"> | undefined;
|
|
@@ -242,7 +242,7 @@ export declare class OpportunityGraphFactory {
|
|
|
242
242
|
targetUserId?: Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users"> | undefined> | undefined;
|
|
243
243
|
onBehalfOfUserId?: Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users"> | undefined> | undefined;
|
|
244
244
|
options?: import("../domain/opportunity.state.js").OpportunityGraphOptions | import("@langchain/langgraph").OverwriteValue<import("../domain/opportunity.state.js").OpportunityGraphOptions> | undefined;
|
|
245
|
-
operationMode?: "delete" | "send" | "update" | "
|
|
245
|
+
operationMode?: "delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction" | import("@langchain/langgraph").OverwriteValue<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction"> | undefined;
|
|
246
246
|
introductionEntities?: EvaluatorEntity[] | import("@langchain/langgraph").OverwriteValue<EvaluatorEntity[]> | undefined;
|
|
247
247
|
introductionHint?: string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined;
|
|
248
248
|
requiredNetworkId?: Id<"networks"> | import("@langchain/langgraph").OverwriteValue<Id<"networks"> | undefined> | undefined;
|
|
@@ -406,7 +406,7 @@ export declare class OpportunityGraphFactory {
|
|
|
406
406
|
seedAssessmentScore?: number | undefined;
|
|
407
407
|
}[]> | undefined;
|
|
408
408
|
discoverySummary?: import("../../index.js").DiscoverySummary | import("@langchain/langgraph").OverwriteValue<import("../../index.js").DiscoverySummary | null> | null | undefined;
|
|
409
|
-
}, "scope" | "discovery" | "send" | "update" | "
|
|
409
|
+
}, "scope" | "discovery" | "send" | "update" | "__start__" | "read" | "negotiate_existing" | "approve_introduction" | "prep" | "persist" | "resolve" | "evaluation" | "ranking" | "intro_validation" | "intro_evaluation" | "delete_opp" | "negotiate", {
|
|
410
410
|
userId: import("@langchain/langgraph").BaseChannel<Id<"users">, Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users">>, unknown>;
|
|
411
411
|
searchQuery: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
|
|
412
412
|
networkId: import("@langchain/langgraph").BaseChannel<Id<"networks"> | undefined, Id<"networks"> | import("@langchain/langgraph").OverwriteValue<Id<"networks"> | undefined> | undefined, unknown>;
|
|
@@ -415,7 +415,7 @@ export declare class OpportunityGraphFactory {
|
|
|
415
415
|
targetUserId: import("@langchain/langgraph").BaseChannel<Id<"users"> | undefined, Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users"> | undefined> | undefined, unknown>;
|
|
416
416
|
onBehalfOfUserId: import("@langchain/langgraph").BaseChannel<Id<"users"> | undefined, Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users"> | undefined> | undefined, unknown>;
|
|
417
417
|
options: import("@langchain/langgraph").BaseChannel<import("../domain/opportunity.state.js").OpportunityGraphOptions, import("../domain/opportunity.state.js").OpportunityGraphOptions | import("@langchain/langgraph").OverwriteValue<import("../domain/opportunity.state.js").OpportunityGraphOptions>, unknown>;
|
|
418
|
-
operationMode: import("@langchain/langgraph").BaseChannel<"delete" | "send" | "update" | "
|
|
418
|
+
operationMode: import("@langchain/langgraph").BaseChannel<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction", "delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction" | import("@langchain/langgraph").OverwriteValue<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction">, unknown>;
|
|
419
419
|
introductionEntities: import("@langchain/langgraph").BaseChannel<EvaluatorEntity[], EvaluatorEntity[] | import("@langchain/langgraph").OverwriteValue<EvaluatorEntity[]>, unknown>;
|
|
420
420
|
introductionHint: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
|
|
421
421
|
requiredNetworkId: import("@langchain/langgraph").BaseChannel<Id<"networks"> | undefined, Id<"networks"> | import("@langchain/langgraph").OverwriteValue<Id<"networks"> | undefined> | undefined, unknown>;
|
|
@@ -652,7 +652,7 @@ export declare class OpportunityGraphFactory {
|
|
|
652
652
|
targetUserId: import("@langchain/langgraph").BaseChannel<Id<"users"> | undefined, Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users"> | undefined> | undefined, unknown>;
|
|
653
653
|
onBehalfOfUserId: import("@langchain/langgraph").BaseChannel<Id<"users"> | undefined, Id<"users"> | import("@langchain/langgraph").OverwriteValue<Id<"users"> | undefined> | undefined, unknown>;
|
|
654
654
|
options: import("@langchain/langgraph").BaseChannel<import("../domain/opportunity.state.js").OpportunityGraphOptions, import("../domain/opportunity.state.js").OpportunityGraphOptions | import("@langchain/langgraph").OverwriteValue<import("../domain/opportunity.state.js").OpportunityGraphOptions>, unknown>;
|
|
655
|
-
operationMode: import("@langchain/langgraph").BaseChannel<"delete" | "send" | "update" | "
|
|
655
|
+
operationMode: import("@langchain/langgraph").BaseChannel<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction", "delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction" | import("@langchain/langgraph").OverwriteValue<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction">, unknown>;
|
|
656
656
|
introductionEntities: import("@langchain/langgraph").BaseChannel<EvaluatorEntity[], EvaluatorEntity[] | import("@langchain/langgraph").OverwriteValue<EvaluatorEntity[]>, unknown>;
|
|
657
657
|
introductionHint: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
|
|
658
658
|
requiredNetworkId: import("@langchain/langgraph").BaseChannel<Id<"networks"> | undefined, Id<"networks"> | import("@langchain/langgraph").OverwriteValue<Id<"networks"> | undefined> | undefined, unknown>;
|
|
@@ -2,37 +2,6 @@ import type { DefineTool } from "../../shared/agent/tool.helpers.js";
|
|
|
2
2
|
import type { OpportunityToolDeps } from "../../capabilities/opportunities.tools.port.js";
|
|
3
3
|
export { buildOpportunityPresentation } from "./opportunity.card-presentation.js";
|
|
4
4
|
import type { Opportunity } from "../../shared/interfaces/database.interface.js";
|
|
5
|
-
import type { ConnectLinkKind } from "../../shared/interfaces/connect-link.interface.js";
|
|
6
|
-
/**
|
|
7
|
-
* Pure status × role → ConnectLinkKind matrix.
|
|
8
|
-
*
|
|
9
|
-
* Returns the kind of short-link the viewer can act on directly, or `null` if
|
|
10
|
-
* no direct link makes sense for this combination. Non-null kinds map to:
|
|
11
|
-
*
|
|
12
|
-
* - `connect` — pending opp where viewer is a non-introducer party. Clicking
|
|
13
|
-
* flips the opp to accepted and opens the chat with the counterpart.
|
|
14
|
-
* - `approve_introduction` — draft or latent opp where viewer is an unapproved
|
|
15
|
-
* introducer. Clicking flips approved=true and triggers negotiation. The
|
|
16
|
-
* `draft` case represents a pending introduction; the `latent`
|
|
17
|
-
* case comes from background-discovered connector-flow cards surfaced in
|
|
18
|
-
* `list_opportunities`. In both, status remains pre-send and the `/c/<code>`
|
|
19
|
-
* link is the only MCP path to approve.
|
|
20
|
-
* - `outreach` — accepted opp where viewer is a non-introducer party.
|
|
21
|
-
* Clicking opens the existing chat (no state change).
|
|
22
|
-
* - `send_direct` — draft or latent opp where viewer is a non-introducer
|
|
23
|
-
* party. Issued for a direct opportunity without an introducer
|
|
24
|
-
* mode: the match has already passed evaluation, the row exists in
|
|
25
|
-
* draft state, and the sender just needs to release it. Clicking flips
|
|
26
|
-
* the opp straight to accepted and opens the chat with a greeting —
|
|
27
|
-
* same handler path as `connect`. The counterpart's side sees the new
|
|
28
|
-
* accepted opp and can engage or ignore.
|
|
29
|
-
*/
|
|
30
|
-
export declare function resolveActionableLinkKind(input: {
|
|
31
|
-
status: string;
|
|
32
|
-
viewerRole: string;
|
|
33
|
-
viewerApproved?: boolean;
|
|
34
|
-
viewerActedAt?: string | null;
|
|
35
|
-
}): ConnectLinkKind | null;
|
|
36
5
|
/**
|
|
37
6
|
* Build the agent-facing profile link for a counterpart — always the Index web
|
|
38
7
|
* profile URL with `?link_preview=false`. Returns `undefined` only if
|
|
@@ -57,26 +26,44 @@ export declare function buildProfileUrl(counterpartUserId: string, frontendUrl:
|
|
|
57
26
|
*/
|
|
58
27
|
export declare function buildNegotiationUrl(conversationId: string | undefined, frontendUrl: string | undefined): string | undefined;
|
|
59
28
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* `
|
|
29
|
+
* Build the agent-facing deep link for an opportunity — the canonical
|
|
30
|
+
* `https://index.network/o/<id>` universal link. Returns `undefined` when
|
|
31
|
+
* `frontendUrl` is unset or there is no opportunity id.
|
|
63
32
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
33
|
+
* This is the *only* place the protocol mints an opportunity deep link. It is
|
|
34
|
+
* a navigation link, not an authority: opening it raises the opportunity card
|
|
35
|
+
* in the Index macOS app when installed and a static Index landing page
|
|
36
|
+
* otherwise. Acceptance stays an authenticated call.
|
|
37
|
+
*
|
|
38
|
+
* No `?link_preview=false` hint here (unlike `buildProfileUrl`): the Hermes
|
|
39
|
+
* plugin mints the identical bare form for payloads the protocol does not
|
|
40
|
+
* touch, and keeping the two byte-identical is what makes its never-overwrite
|
|
41
|
+
* rule invisible.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildOpportunityAppUrl(opportunityId: string, frontendUrl: string | undefined): string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Attach the agent-facing profile link for a counterpart to `card` (mutates
|
|
46
|
+
* in place). Every counterpart has a profile page worth linking to — without
|
|
47
|
+
* this, the agent gets a name with no URL attached and tends to fabricate
|
|
48
|
+
* one. Accept/act guidance is plain text ("accept in the Index app"); no
|
|
49
|
+
* actionable URLs are minted here.
|
|
66
50
|
*/
|
|
67
|
-
export declare function
|
|
51
|
+
export declare function attachProfileLink(card: Record<string, unknown> & {
|
|
68
52
|
opportunityId: string;
|
|
69
|
-
viewerRole: string;
|
|
70
|
-
status: string;
|
|
71
53
|
}, opts: {
|
|
72
|
-
viewerId: string;
|
|
73
|
-
viewerApproved?: boolean;
|
|
74
|
-
viewerActedAt?: string | null;
|
|
75
54
|
counterpartUserId: string;
|
|
76
|
-
mintConnectLink: NonNullable<OpportunityToolDeps["mintConnectLink"]>;
|
|
77
55
|
frontendUrl: string | undefined;
|
|
78
|
-
|
|
79
|
-
|
|
56
|
+
}): void;
|
|
57
|
+
/**
|
|
58
|
+
* Attach the opportunity deep link to `card` (mutates in place) so every MCP
|
|
59
|
+
* client — Claude Desktop, the CLI, the web, Hermes — can hand the user one
|
|
60
|
+
* clickable link to the card instead of fabricating one from an id.
|
|
61
|
+
*/
|
|
62
|
+
export declare function attachOpportunityAppLink(card: Record<string, unknown> & {
|
|
63
|
+
opportunityId: string;
|
|
64
|
+
}, opts: {
|
|
65
|
+
frontendUrl: string | undefined;
|
|
66
|
+
}): void;
|
|
80
67
|
/**
|
|
81
68
|
* Build minimal opportunity card data for chat without calling the LLM presenter.
|
|
82
69
|
* Uses only required fields from the opportunity record and counterpart name/avatar
|
|
@@ -41,47 +41,6 @@ function stripLeadingNarratorName(remark, narratorName) {
|
|
|
41
41
|
import { protocolLogger } from "../../shared/observability/protocol.logger.js";
|
|
42
42
|
import { invokeWithAbortSignal } from "../../shared/agent/model-signal.js";
|
|
43
43
|
const logger = protocolLogger("ChatTools:Opportunity");
|
|
44
|
-
/**
|
|
45
|
-
* Pure status × role → ConnectLinkKind matrix.
|
|
46
|
-
*
|
|
47
|
-
* Returns the kind of short-link the viewer can act on directly, or `null` if
|
|
48
|
-
* no direct link makes sense for this combination. Non-null kinds map to:
|
|
49
|
-
*
|
|
50
|
-
* - `connect` — pending opp where viewer is a non-introducer party. Clicking
|
|
51
|
-
* flips the opp to accepted and opens the chat with the counterpart.
|
|
52
|
-
* - `approve_introduction` — draft or latent opp where viewer is an unapproved
|
|
53
|
-
* introducer. Clicking flips approved=true and triggers negotiation. The
|
|
54
|
-
* `draft` case represents a pending introduction; the `latent`
|
|
55
|
-
* case comes from background-discovered connector-flow cards surfaced in
|
|
56
|
-
* `list_opportunities`. In both, status remains pre-send and the `/c/<code>`
|
|
57
|
-
* link is the only MCP path to approve.
|
|
58
|
-
* - `outreach` — accepted opp where viewer is a non-introducer party.
|
|
59
|
-
* Clicking opens the existing chat (no state change).
|
|
60
|
-
* - `send_direct` — draft or latent opp where viewer is a non-introducer
|
|
61
|
-
* party. Issued for a direct opportunity without an introducer
|
|
62
|
-
* mode: the match has already passed evaluation, the row exists in
|
|
63
|
-
* draft state, and the sender just needs to release it. Clicking flips
|
|
64
|
-
* the opp straight to accepted and opens the chat with a greeting —
|
|
65
|
-
* same handler path as `connect`. The counterpart's side sees the new
|
|
66
|
-
* accepted opp and can engage or ignore.
|
|
67
|
-
*/
|
|
68
|
-
export function resolveActionableLinkKind(input) {
|
|
69
|
-
const { status, viewerRole, viewerApproved, viewerActedAt } = input;
|
|
70
|
-
const isIntroducer = viewerRole === "introducer";
|
|
71
|
-
const hasViewerActed = !!viewerActedAt;
|
|
72
|
-
if (status === "accepted") {
|
|
73
|
-
return isIntroducer ? null : "outreach";
|
|
74
|
-
}
|
|
75
|
-
if (status === "pending") {
|
|
76
|
-
return isIntroducer || hasViewerActed ? null : "connect";
|
|
77
|
-
}
|
|
78
|
-
if (status === "draft" || status === "latent") {
|
|
79
|
-
if (!isIntroducer)
|
|
80
|
-
return hasViewerActed ? null : "send_direct";
|
|
81
|
-
return viewerApproved === true ? null : "approve_introduction";
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
44
|
/**
|
|
86
45
|
* Build the agent-facing profile link for a counterpart — always the Index web
|
|
87
46
|
* profile URL with `?link_preview=false`. Returns `undefined` only if
|
|
@@ -95,9 +54,7 @@ export function resolveActionableLinkKind(input) {
|
|
|
95
54
|
*/
|
|
96
55
|
export function buildProfileUrl(counterpartUserId, frontendUrl) {
|
|
97
56
|
// The profile link is always the Index web profile, regardless of the
|
|
98
|
-
// counterpart's socials
|
|
99
|
-
// deep-linking lives on the connect URL (`/c/:code`) — the connect-link
|
|
100
|
-
// controller resolves that to a pre-messaged t.me link — never here.
|
|
57
|
+
// counterpart's socials.
|
|
101
58
|
if (!frontendUrl)
|
|
102
59
|
return undefined;
|
|
103
60
|
const base = frontendUrl.replace(/\/+$/, "");
|
|
@@ -120,58 +77,47 @@ export function buildNegotiationUrl(conversationId, frontendUrl) {
|
|
|
120
77
|
return `${base}/chat/${conversationId}?link_preview=false`;
|
|
121
78
|
}
|
|
122
79
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* `
|
|
80
|
+
* Build the agent-facing deep link for an opportunity — the canonical
|
|
81
|
+
* `https://index.network/o/<id>` universal link. Returns `undefined` when
|
|
82
|
+
* `frontendUrl` is unset or there is no opportunity id.
|
|
83
|
+
*
|
|
84
|
+
* This is the *only* place the protocol mints an opportunity deep link. It is
|
|
85
|
+
* a navigation link, not an authority: opening it raises the opportunity card
|
|
86
|
+
* in the Index macOS app when installed and a static Index landing page
|
|
87
|
+
* otherwise. Acceptance stays an authenticated call.
|
|
126
88
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
89
|
+
* No `?link_preview=false` hint here (unlike `buildProfileUrl`): the Hermes
|
|
90
|
+
* plugin mints the identical bare form for payloads the protocol does not
|
|
91
|
+
* touch, and keeping the two byte-identical is what makes its never-overwrite
|
|
92
|
+
* rule invisible.
|
|
129
93
|
*/
|
|
130
|
-
export
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
94
|
+
export function buildOpportunityAppUrl(opportunityId, frontendUrl) {
|
|
95
|
+
if (!frontendUrl || !opportunityId)
|
|
96
|
+
return undefined;
|
|
97
|
+
const base = frontendUrl.replace(/\/+$/, "");
|
|
98
|
+
return `${base}/o/${opportunityId}`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Attach the agent-facing profile link for a counterpart to `card` (mutates
|
|
102
|
+
* in place). Every counterpart has a profile page worth linking to — without
|
|
103
|
+
* this, the agent gets a name with no URL attached and tends to fabricate
|
|
104
|
+
* one. Accept/act guidance is plain text ("accept in the Index app"); no
|
|
105
|
+
* actionable URLs are minted here.
|
|
106
|
+
*/
|
|
107
|
+
export function attachProfileLink(card, opts) {
|
|
138
108
|
const profileUrl = buildProfileUrl(opts.counterpartUserId, opts.frontendUrl);
|
|
139
109
|
if (profileUrl)
|
|
140
110
|
card.profileUrl = profileUrl;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
viewerApproved: opts.viewerApproved,
|
|
152
|
-
viewerActedAt: opts.viewerActedAt,
|
|
153
|
-
kind: kind ?? "none",
|
|
154
|
-
});
|
|
155
|
-
if (kind === null)
|
|
156
|
-
return;
|
|
157
|
-
try {
|
|
158
|
-
const { url } = await opts.mintConnectLink({
|
|
159
|
-
userId: opts.viewerId,
|
|
160
|
-
opportunityId: card.opportunityId,
|
|
161
|
-
kind,
|
|
162
|
-
greeting: null,
|
|
163
|
-
preferredSurface: opts.preferredSurface,
|
|
164
|
-
});
|
|
165
|
-
card.acceptUrl = url;
|
|
166
|
-
card.feedCategory = card.viewerRole === "introducer" ? "connector-flow" : "connection";
|
|
167
|
-
}
|
|
168
|
-
catch (err) {
|
|
169
|
-
logger.warn("Failed to mint MCP opportunity link — surfacing card without acceptUrl/feedCategory; profileUrl is still attached", {
|
|
170
|
-
opportunityId: card.opportunityId,
|
|
171
|
-
kind,
|
|
172
|
-
error: err instanceof Error ? err.message : String(err),
|
|
173
|
-
});
|
|
174
|
-
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Attach the opportunity deep link to `card` (mutates in place) so every MCP
|
|
114
|
+
* client — Claude Desktop, the CLI, the web, Hermes — can hand the user one
|
|
115
|
+
* clickable link to the card instead of fabricating one from an id.
|
|
116
|
+
*/
|
|
117
|
+
export function attachOpportunityAppLink(card, opts) {
|
|
118
|
+
const appUrl = buildOpportunityAppUrl(card.opportunityId, opts.frontendUrl);
|
|
119
|
+
if (appUrl)
|
|
120
|
+
card.appUrl = appUrl;
|
|
175
121
|
}
|
|
176
122
|
function publicUptakeQuestion(question) {
|
|
177
123
|
return {
|
|
@@ -563,17 +509,15 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
563
509
|
}
|
|
564
510
|
: {}),
|
|
565
511
|
};
|
|
566
|
-
// Attach
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
viewerId: context.userId,
|
|
571
|
-
viewerApproved,
|
|
572
|
-
viewerActedAt: viewerActor?.actedAt ?? null,
|
|
512
|
+
// Attach the agent-facing profile and opportunity links for
|
|
513
|
+
// MCP callers
|
|
514
|
+
if (context.isMcp) {
|
|
515
|
+
attachProfileLink(card, {
|
|
573
516
|
counterpartUserId,
|
|
574
|
-
mintConnectLink: deps.mintConnectLink,
|
|
575
517
|
frontendUrl: deps.frontendUrl,
|
|
576
|
-
|
|
518
|
+
});
|
|
519
|
+
attachOpportunityAppLink(card, {
|
|
520
|
+
frontendUrl: deps.frontendUrl,
|
|
577
521
|
});
|
|
578
522
|
}
|
|
579
523
|
return card;
|
|
@@ -710,22 +654,17 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
710
654
|
}
|
|
711
655
|
: {}),
|
|
712
656
|
};
|
|
713
|
-
// For MCP callers
|
|
714
|
-
//
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (context.isMcp && deps.mintConnectLink) {
|
|
720
|
-
const viewerApproved = viewerActor?.role === "introducer" ? viewerActor.approved === true : undefined;
|
|
721
|
-
await attachActionableLinks(cardData, {
|
|
722
|
-
viewerId: context.userId,
|
|
723
|
-
viewerApproved,
|
|
724
|
-
viewerActedAt: viewerActor?.actedAt ?? null,
|
|
657
|
+
// For MCP callers, attach the agent-facing profile link and the
|
|
658
|
+
// opportunity deep link so the agent never has to fabricate
|
|
659
|
+
// either. Accepting still happens in the Index app behind an
|
|
660
|
+
// authenticated call — the deep link only opens the card.
|
|
661
|
+
if (context.isMcp) {
|
|
662
|
+
attachProfileLink(cardData, {
|
|
725
663
|
counterpartUserId,
|
|
726
|
-
mintConnectLink: deps.mintConnectLink,
|
|
727
664
|
frontendUrl: deps.frontendUrl,
|
|
728
|
-
|
|
665
|
+
});
|
|
666
|
+
attachOpportunityAppLink(cardData, {
|
|
667
|
+
frontendUrl: deps.frontendUrl,
|
|
729
668
|
});
|
|
730
669
|
}
|
|
731
670
|
return cardData;
|
|
@@ -178,7 +178,7 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
178
178
|
*
|
|
179
179
|
* Defaults to 'create' for backward compatibility.
|
|
180
180
|
*/
|
|
181
|
-
operationMode: import("@langchain/langgraph").BaseChannel<"delete" | "send" | "update" | "
|
|
181
|
+
operationMode: import("@langchain/langgraph").BaseChannel<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction", "delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction" | import("@langchain/langgraph").OverwriteValue<"delete" | "send" | "update" | "create" | "create_introduction" | "continue_discovery" | "read" | "negotiate_existing" | "approve_introduction">, unknown>;
|
|
182
182
|
/** Introduction mode: pre-gathered entities (profiles + intents per party). */
|
|
183
183
|
introductionEntities: import("@langchain/langgraph").BaseChannel<EvaluatorEntity[], EvaluatorEntity[] | import("@langchain/langgraph").OverwriteValue<EvaluatorEntity[]>, unknown>;
|
|
184
184
|
/** Introduction mode: optional hint from the introducer. */
|
|
@@ -11,6 +11,6 @@ export interface OpportunityOwnerApprovalDeps {
|
|
|
11
11
|
opportunityOwnerApproval?: OpportunityOwnerApprovalAuthority;
|
|
12
12
|
}
|
|
13
13
|
/** Host capabilities consumed by opportunity discovery, delivery, and presentation tools. */
|
|
14
|
-
export type OpportunityToolDeps = Pick<ToolRegistryCompositionDeps, "database" | "userDb" | "systemDb" | "cache" | "chatSummary" | "opportunityPresentation" | "questionGenerator" | "questionerEnqueue" | "findPendingQuestions" | "negotiationSummary" | "negotiationDatabase" | "deliveryLedger" | "
|
|
14
|
+
export type OpportunityToolDeps = Pick<ToolRegistryCompositionDeps, "database" | "userDb" | "systemDb" | "cache" | "chatSummary" | "opportunityPresentation" | "questionGenerator" | "questionerEnqueue" | "findPendingQuestions" | "negotiationSummary" | "negotiationDatabase" | "deliveryLedger" | "frontendUrl" | "stampNewbornOpportunities" | "reportToolError"> & OpportunityOwnerApprovalDeps & {
|
|
15
15
|
graphs: Pick<ToolRegistryCompositionDeps["graphs"], "index" | "networkMembership" | "opportunity">;
|
|
16
16
|
};
|
|
@@ -166,8 +166,6 @@ export async function createChatTools(deps, preResolvedContext) {
|
|
|
166
166
|
...(deps.opportunityOwnerApproval && { opportunityOwnerApproval: deps.opportunityOwnerApproval }),
|
|
167
167
|
enrichmentRuns: deps.enrichmentRuns,
|
|
168
168
|
enrichmentRunQueue: deps.enrichmentRunQueue,
|
|
169
|
-
mintConnectToken: deps.mintConnectToken,
|
|
170
|
-
mintConnectLink: deps.mintConnectLink,
|
|
171
169
|
frontendUrl: deps.frontendUrl,
|
|
172
170
|
apiBaseUrl: deps.apiBaseUrl,
|
|
173
171
|
...(deps.chatSummary && { chatSummary: deps.chatSummary }),
|
|
@@ -19,7 +19,6 @@ import type { AgentDatabase } from "../interfaces/agent.interface.js";
|
|
|
19
19
|
import type { NegotiationTimeoutQueue } from "../interfaces/negotiation-events.interface.js";
|
|
20
20
|
import type { AgentDispatcher } from "../interfaces/agent-dispatcher.interface.js";
|
|
21
21
|
import type { DeliveryLedger } from "../interfaces/delivery-ledger.interface.js";
|
|
22
|
-
import type { MintConnectLink } from "../interfaces/connect-link.interface.js";
|
|
23
22
|
import type { ChatQuestionsHost, QuestionerDatabase } from "../interfaces/questioner.interface.js";
|
|
24
23
|
import type { NegotiatorMemoryToolsHost } from "../interfaces/negotiator-memory.interface.js";
|
|
25
24
|
import type { QuestionerEnqueueFn } from "../../questioner/questioner.types.js";
|
|
@@ -100,14 +99,6 @@ export interface ResolvedToolContext {
|
|
|
100
99
|
* which are owner-trusted and receive the full owner view.
|
|
101
100
|
*/
|
|
102
101
|
mcpCaller?: McpActivityCaller;
|
|
103
|
-
/**
|
|
104
|
-
* Receiver's rendering surface declared by the MCP client via the
|
|
105
|
-
* `x-index-surface` request header. `'telegram'` means the MCP response is
|
|
106
|
-
* being rendered inside a Telegram chat; anything
|
|
107
|
-
* else (including `undefined`) is treated as web. Forwarded into
|
|
108
|
-
* `mintConnectLink` so the click-time redirect can branch.
|
|
109
|
-
*/
|
|
110
|
-
clientSurface?: 'telegram' | 'web';
|
|
111
102
|
/**
|
|
112
103
|
* True when the CONTACTS_ENABLED feature flag is on. Carried from the
|
|
113
104
|
* composition root so prompt modules can gate contact-import guidance —
|
|
@@ -268,13 +259,6 @@ interface ToolContextBindings {
|
|
|
268
259
|
enrichmentRuns?: EnrichmentRunStore;
|
|
269
260
|
/** Queue for async MCP profile run execution (optional — absent in non-MCP/test contexts). */
|
|
270
261
|
enrichmentRunQueue?: EnrichmentRunQueue;
|
|
271
|
-
/**
|
|
272
|
-
* Legacy direct-token minting for opportunity accept redirects.
|
|
273
|
-
* Prefer `mintConnectLink` for user-facing links.
|
|
274
|
-
*/
|
|
275
|
-
mintConnectToken?: (userId: string, opportunityId: string) => Promise<string>;
|
|
276
|
-
/** Mints (or reuses) a short connect link, snapshotting the greeting (optional — absent in non-MCP contexts). */
|
|
277
|
-
mintConnectLink?: MintConnectLink;
|
|
278
262
|
/** Frontend base URL for building profile links (e.g. https://index.network, optional). */
|
|
279
263
|
frontendUrl?: string;
|
|
280
264
|
/** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */
|
|
@@ -495,13 +479,6 @@ interface ToolDepsBindings {
|
|
|
495
479
|
enrichmentRuns?: EnrichmentRunStore;
|
|
496
480
|
/** Queue for async MCP profile run execution (optional — absent in non-MCP/test contexts). */
|
|
497
481
|
enrichmentRunQueue?: EnrichmentRunQueue;
|
|
498
|
-
/**
|
|
499
|
-
* Legacy direct-token minting for opportunity accept redirects.
|
|
500
|
-
* Prefer `mintConnectLink` for user-facing links.
|
|
501
|
-
*/
|
|
502
|
-
mintConnectToken?: (userId: string, opportunityId: string) => Promise<string>;
|
|
503
|
-
/** Mints (or reuses) a short connect link, snapshotting the greeting (optional — absent in non-MCP contexts). */
|
|
504
|
-
mintConnectLink?: MintConnectLink;
|
|
505
482
|
/** Frontend base URL for building profile links (e.g. https://index.network, optional). */
|
|
506
483
|
frontendUrl?: string;
|
|
507
484
|
/** API base URL for building opportunity accept links (e.g. https://protocol.index.network, optional). */
|
|
@@ -557,9 +534,9 @@ interface ToolDepsBindings {
|
|
|
557
534
|
* Shared backing shape for the registry composition boundary. Capability-local
|
|
558
535
|
* ports may Pick from this type, but it is intentionally not a root export.
|
|
559
536
|
*/
|
|
560
|
-
export type ToolRegistryCompositionDeps = Omit<ToolDepsBindings, 'embedder' | 'chatMessageWriter' | '
|
|
537
|
+
export type ToolRegistryCompositionDeps = Omit<ToolDepsBindings, 'embedder' | 'chatMessageWriter' | 'apiBaseUrl' | 'mcpRateLimiter'>;
|
|
561
538
|
/** Runtime-only hooks retained for MCP and existing host composition. */
|
|
562
|
-
type ToolRuntimeCompatibilityDeps = Pick<ToolDepsBindings, 'embedder' | 'chatMessageWriter' | '
|
|
539
|
+
type ToolRuntimeCompatibilityDeps = Pick<ToolDepsBindings, 'embedder' | 'chatMessageWriter' | 'apiBaseUrl' | 'mcpRateLimiter'>;
|
|
563
540
|
/**
|
|
564
541
|
* Legacy complete tool composition contract.
|
|
565
542
|
*
|
|
@@ -13,9 +13,8 @@ export interface McpAuthResolver {
|
|
|
13
13
|
* @param input - Transport-neutral auth input DTO with credential fields
|
|
14
14
|
* extracted at the MCP transport edge.
|
|
15
15
|
* @returns The authenticated user's UUID, optional agent UUID, auth method,
|
|
16
|
-
* `networkScopeId` if the caller's API key is bound to a network-scoped
|
|
17
|
-
* agent
|
|
18
|
-
* MCP response (drives connect-link redirect choice at click time).
|
|
16
|
+
* and `networkScopeId` if the caller's API key is bound to a network-scoped
|
|
17
|
+
* agent.
|
|
19
18
|
*
|
|
20
19
|
* When `networkScopeId` is set, the MCP server promotes it into the
|
|
21
20
|
* canonical `{ scopeType: 'network', scopeId }` envelope. Downstream tools
|
|
@@ -24,9 +23,6 @@ export interface McpAuthResolver {
|
|
|
24
23
|
* `isSessionAuth` is true for OAuth/JWT bearer sessions — the agent-
|
|
25
24
|
* registration gate in the MCP server is skipped for these callers.
|
|
26
25
|
*
|
|
27
|
-
* `clientSurface` is passed through from the DTO. Only `'telegram'`
|
|
28
|
-
* activates the t.me redirect path on `/c/{code}` clicks.
|
|
29
|
-
*
|
|
30
26
|
* @throws Error if authentication fails (no token, invalid token, etc.)
|
|
31
27
|
*/
|
|
32
28
|
resolveIdentity(input: McpAuthInput): Promise<McpResolvedIdentity>;
|
|
@@ -26,7 +26,7 @@ export interface EnrichmentRunRecord {
|
|
|
26
26
|
operation: EnrichmentRunOperation;
|
|
27
27
|
status: EnrichmentRunStatus;
|
|
28
28
|
input: EnrichmentRunInput;
|
|
29
|
-
context: Pick<ToolRequestContext, "userId" | "userName" | "userEmail" | "scopeType" | "scopeId" | "indexName" | "sessionId" | "agentId"
|
|
29
|
+
context: Pick<ToolRequestContext, "userId" | "userName" | "userEmail" | "scopeType" | "scopeId" | "indexName" | "sessionId" | "agentId">;
|
|
30
30
|
progress?: Record<string, unknown> | null;
|
|
31
31
|
result?: unknown;
|
|
32
32
|
error?: string | null;
|
|
@@ -5,18 +5,15 @@ import { z } from 'zod';
|
|
|
5
5
|
export declare const McpAuthInputSchema: z.ZodObject<{
|
|
6
6
|
bearerToken: z.ZodOptional<z.ZodString>;
|
|
7
7
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
8
|
-
clientSurface: z.ZodOptional<z.ZodEnum<["telegram", "web"]>>;
|
|
9
8
|
telegramHandle: z.ZodOptional<z.ZodString>;
|
|
10
9
|
telegramUsername: z.ZodOptional<z.ZodString>;
|
|
11
10
|
}, "strict", z.ZodTypeAny, {
|
|
12
11
|
apiKey?: string | undefined;
|
|
13
|
-
clientSurface?: "telegram" | "web" | undefined;
|
|
14
12
|
bearerToken?: string | undefined;
|
|
15
13
|
telegramHandle?: string | undefined;
|
|
16
14
|
telegramUsername?: string | undefined;
|
|
17
15
|
}, {
|
|
18
16
|
apiKey?: string | undefined;
|
|
19
|
-
clientSurface?: "telegram" | "web" | undefined;
|
|
20
17
|
bearerToken?: string | undefined;
|
|
21
18
|
telegramHandle?: string | undefined;
|
|
22
19
|
telegramUsername?: string | undefined;
|
|
@@ -52,11 +49,9 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
52
49
|
enrollmentCapable: z.ZodOptional<z.ZodBoolean>;
|
|
53
50
|
isDeliveryAgent: z.ZodOptional<z.ZodBoolean>;
|
|
54
51
|
networkScopeId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
55
|
-
clientSurface: z.ZodOptional<z.ZodEnum<["telegram", "web"]>>;
|
|
56
52
|
}, "strict", z.ZodTypeAny, {
|
|
57
53
|
userId: string;
|
|
58
54
|
agentId?: string | undefined;
|
|
59
|
-
clientSurface?: "telegram" | "web" | undefined;
|
|
60
55
|
networkScopeId?: string | null | undefined;
|
|
61
56
|
enrollmentCapable?: boolean | undefined;
|
|
62
57
|
isDeliveryAgent?: boolean | undefined;
|
|
@@ -64,7 +59,6 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
64
59
|
}, {
|
|
65
60
|
userId: string;
|
|
66
61
|
agentId?: string | undefined;
|
|
67
|
-
clientSurface?: "telegram" | "web" | undefined;
|
|
68
62
|
networkScopeId?: string | null | undefined;
|
|
69
63
|
enrollmentCapable?: boolean | undefined;
|
|
70
64
|
isDeliveryAgent?: boolean | undefined;
|
|
@@ -72,7 +66,6 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
72
66
|
}>, {
|
|
73
67
|
userId: string;
|
|
74
68
|
agentId?: string | undefined;
|
|
75
|
-
clientSurface?: "telegram" | "web" | undefined;
|
|
76
69
|
networkScopeId?: string | null | undefined;
|
|
77
70
|
enrollmentCapable?: boolean | undefined;
|
|
78
71
|
isDeliveryAgent?: boolean | undefined;
|
|
@@ -80,7 +73,6 @@ export declare const McpResolvedIdentitySchema: z.ZodEffects<z.ZodObject<{
|
|
|
80
73
|
}, {
|
|
81
74
|
userId: string;
|
|
82
75
|
agentId?: string | undefined;
|
|
83
|
-
clientSurface?: "telegram" | "web" | undefined;
|
|
84
76
|
networkScopeId?: string | null | undefined;
|
|
85
77
|
enrollmentCapable?: boolean | undefined;
|
|
86
78
|
isDeliveryAgent?: boolean | undefined;
|
|
@@ -5,7 +5,6 @@ import { z } from 'zod';
|
|
|
5
5
|
export const McpAuthInputSchema = z.object({
|
|
6
6
|
bearerToken: z.string().min(1).optional(),
|
|
7
7
|
apiKey: z.string().min(1).optional(),
|
|
8
|
-
clientSurface: z.enum(['telegram', 'web']).optional(),
|
|
9
8
|
telegramHandle: z.string().min(1).optional(),
|
|
10
9
|
telegramUsername: z.string().min(1).optional(),
|
|
11
10
|
}).strict();
|
|
@@ -30,7 +29,6 @@ export const McpResolvedIdentitySchema = z.object({
|
|
|
30
29
|
enrollmentCapable: z.boolean().optional(),
|
|
31
30
|
isDeliveryAgent: z.boolean().optional(),
|
|
32
31
|
networkScopeId: z.string().min(1).nullable().optional(),
|
|
33
|
-
clientSurface: z.enum(['telegram', 'web']).optional(),
|
|
34
32
|
}).strict().superRefine((identity, ctx) => {
|
|
35
33
|
if (identity.isSessionAuth === true && identity.agentId) {
|
|
36
34
|
ctx.addIssue({
|
package/package.json
CHANGED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Kind of connect link being minted. Determines the action endpoint the short
|
|
3
|
-
* URL eventually redirects to:
|
|
4
|
-
*
|
|
5
|
-
* - `connect` — receiver of a `pending` opp clicks to flip it to `accepted`
|
|
6
|
-
* and open the chat with a pre-filled greeting.
|
|
7
|
-
* - `approve_introduction` — unapproved introducer on a `draft`/`latent` opp
|
|
8
|
-
* clicks to flip `approved=true` and kick off negotiation.
|
|
9
|
-
* - `outreach` — non-introducer party on an `accepted` opp clicks to open
|
|
10
|
-
* the existing chat (no state change).
|
|
11
|
-
* - `send_direct` — sender (non-introducer party) of a `draft`/`latent`
|
|
12
|
-
* direct-mode opp clicks to flip it straight to `accepted` and open
|
|
13
|
-
* the chat with a pre-filled greeting. Mirrors the frontend's "Start
|
|
14
|
-
* Chat" button on draft cards: both posted public intents that
|
|
15
|
-
* matched, so opening the chat counts as the consent; the counterpart
|
|
16
|
-
* sees the new accepted opp on their side and can engage or not.
|
|
17
|
-
*/
|
|
18
|
-
export type ConnectLinkKind = 'connect' | 'approve_introduction' | 'outreach' | 'send_direct';
|
|
19
|
-
/**
|
|
20
|
-
* Mints (or reuses) a short link for the given recipient and kind, snapshotting
|
|
21
|
-
* the greeting and the caller's preferred surface onto the link record. Returns
|
|
22
|
-
* the full public URL.
|
|
23
|
-
*
|
|
24
|
-
* `preferredSurface` is stamped onto the row at insert time and drives the
|
|
25
|
-
* click-time redirect on `/c/{code}/go`: only `'telegram'` activates the t.me
|
|
26
|
-
* deep-link path; everything else (including `undefined`, persisted as NULL)
|
|
27
|
-
* routes to the web frontend chat URL.
|
|
28
|
-
*/
|
|
29
|
-
export interface MintConnectLink {
|
|
30
|
-
(args: {
|
|
31
|
-
userId: string;
|
|
32
|
-
opportunityId: string;
|
|
33
|
-
kind: ConnectLinkKind;
|
|
34
|
-
greeting?: string | null;
|
|
35
|
-
preferredSurface?: 'telegram' | 'web';
|
|
36
|
-
}): Promise<{
|
|
37
|
-
url: string;
|
|
38
|
-
}>;
|
|
39
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|