@indexnetwork/protocol 16.1.1-rc.478.1 → 17.0.1-rc.480.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/chat/chat.agent.js +0 -1
  3. package/dist/chat/negotiator.persona.d.ts +1 -1
  4. package/dist/chat/negotiator.persona.js +1 -4
  5. package/dist/chat/negotiator.prompt.js +1 -2
  6. package/dist/chat/onboarding.persona.js +0 -1
  7. package/dist/chat/reporter.persona.js +0 -1
  8. package/dist/chat/signal.persona.js +0 -1
  9. package/dist/contacts/application/contact.tools.d.ts +6 -9
  10. package/dist/contacts/application/contact.tools.js +11 -92
  11. package/dist/contacts/application/index.d.ts +2 -14
  12. package/dist/contacts/application/index.js +2 -13
  13. package/dist/contacts/domain/contact.types.d.ts +0 -23
  14. package/dist/contacts/domain/index.d.ts +2 -6
  15. package/dist/contacts/index.d.ts +1 -1
  16. package/dist/contacts/index.js +1 -1
  17. package/dist/contacts/ports/contact.repository.port.d.ts +5 -12
  18. package/dist/contacts/ports/contact.repository.port.js +4 -6
  19. package/dist/contacts/ports/contact.tools.port.d.ts +1 -3
  20. package/dist/contacts/ports/contact.tools.port.js +1 -2
  21. package/dist/contacts/ports/index.d.ts +1 -1
  22. package/dist/contacts/ports/index.js +1 -1
  23. package/dist/index.d.ts +0 -2
  24. package/dist/index.js +0 -1
  25. package/dist/mcp/mcp.server.js +2 -4
  26. package/dist/shared/agent/tool.factory.js +0 -8
  27. package/dist/shared/agent/tool.helpers.d.ts +0 -45
  28. package/dist/shared/agent/tool.helpers.js +1 -2
  29. package/dist/shared/agent/tool.registry.js +1 -3
  30. package/dist/shared/agent/tool.runtime.js +0 -2
  31. package/dist/shared/agent/utility.tools.js +9 -13
  32. package/dist/shared/interfaces/database.member-queries.d.ts +1 -8
  33. package/package.json +2 -2
  34. package/dist/contacts/application/contact.inviter.d.ts +0 -49
  35. package/dist/contacts/application/contact.inviter.js +0 -64
  36. package/dist/integrations/application/index.d.ts +0 -14
  37. package/dist/integrations/application/index.js +0 -14
  38. package/dist/integrations/application/integration.tools.d.ts +0 -27
  39. package/dist/integrations/application/integration.tools.js +0 -98
  40. package/dist/integrations/domain/index.d.ts +0 -16
  41. package/dist/integrations/domain/index.js +0 -1
  42. package/dist/integrations/domain/integration.types.d.ts +0 -51
  43. package/dist/integrations/domain/integration.types.js +0 -9
  44. package/dist/integrations/index.d.ts +0 -10
  45. package/dist/integrations/index.js +0 -8
  46. package/dist/integrations/ports/index.d.ts +0 -25
  47. package/dist/integrations/ports/index.js +0 -23
  48. package/dist/integrations/ports/integration.adapter.port.d.ts +0 -62
  49. package/dist/integrations/ports/integration.adapter.port.js +0 -15
  50. package/dist/integrations/ports/integration.importer.port.d.ts +0 -31
  51. package/dist/integrations/ports/integration.importer.port.js +0 -15
  52. package/dist/integrations/ports/integration.tools.port.d.ts +0 -25
  53. package/dist/integrations/ports/integration.tools.port.js +0 -18
@@ -8,7 +8,6 @@ import type { UserIdentity } from "../schemas/identity.schema.js";
8
8
  import type { ChatGraphCompositeDatabase, CreateOpportunityData, NetworkMembership, UserRecord, UserDatabase, SystemDatabase, NegotiationGraphDatabase } from "../interfaces/database.interface.js";
9
9
  import type { Scraper } from "../interfaces/scraper.interface.js";
10
10
  import type { Cache, HydeCache } from "../interfaces/cache.interface.js";
11
- import type { IntegrationAdapter } from "../../integrations/ports/index.js";
12
11
  import type { ContactServiceAdapter } from "../../contacts/ports/index.js";
13
12
  import type { ProfileEnricher } from "../interfaces/enrichment.interface.js";
14
13
  import type { IntentGraphQueue } from "../interfaces/queue.interface.js";
@@ -99,14 +98,6 @@ export interface ResolvedToolContext {
99
98
  * which are owner-trusted and receive the full owner view.
100
99
  */
101
100
  mcpCaller?: McpActivityCaller;
102
- /**
103
- * True when the CONTACTS_ENABLED feature flag is on. Carried from the
104
- * composition root so prompt modules can gate contact-import guidance —
105
- * when false/unset, the contacts prompt module is not injected, so the
106
- * orchestrator never advertises Gmail import / add_contact (whose tools
107
- * are also de-registered). Fail-closed: treat only `true` as enabled.
108
- */
109
- contactsEnabled?: boolean;
110
101
  /** True only when the gated reporter cleanup-action proposal tool is registered. */
111
102
  actionToolsEnabled?: boolean;
112
103
  }
@@ -142,19 +133,10 @@ interface ToolContextBindings {
142
133
  cache: Cache;
143
134
  /** Dedicated cache for HyDE graph (may be same instance as cache). */
144
135
  hydeCache: HydeCache;
145
- /** External integration platform adapter (OAuth, tool actions). */
146
- integration: IntegrationAdapter;
147
136
  /** Queue for enqueuing follow-up intent processing (HyDE generation/deletion). */
148
137
  intentQueue: IntentGraphQueue;
149
138
  /** Contact management operations. */
150
139
  contactService: ContactServiceAdapter;
151
- /**
152
- * When false (or unset), the contact import / manual-add tools
153
- * (import_contacts, add_contact, import_gmail_contacts) are not registered.
154
- * Injected by the composition root from CONTACTS_ENABLED. Read/remove/search
155
- * contact tools are always registered.
156
- */
157
- contactsEnabled?: boolean;
158
140
  /** True only when the gated reporter cleanup-action proposal tool is registered. */
159
141
  actionToolsEnabled?: boolean;
160
142
  /** Chat session reader for loading conversation history. */
@@ -224,15 +206,6 @@ interface ToolContextBindings {
224
206
  enricher: ProfileEnricher;
225
207
  /** Database adapter for negotiations/conversation operations. */
226
208
  negotiationDatabase: NegotiationGraphDatabase;
227
- /** Integration importer for bulk contact import from toolkits. */
228
- integrationImporter: {
229
- importContacts(userId: string, toolkit: string): Promise<{
230
- imported: number;
231
- skipped: number;
232
- newContacts: number;
233
- existingContacts: number;
234
- }>;
235
- };
236
209
  /** Factory for user-scoped database access. */
237
210
  createUserDatabase: (db: ChatGraphCompositeDatabase, userId: string) => UserDatabase;
238
211
  /** Factory for system-scoped database access. */
@@ -319,8 +292,6 @@ export declare function resolveChatContext(params: {
319
292
  networkId?: string;
320
293
  /** Chat session ID for draft opportunities (stored as context.conversationId). */
321
294
  sessionId?: string;
322
- /** CONTACTS_ENABLED flag, forwarded onto the resolved context for prompt gating. */
323
- contactsEnabled?: boolean;
324
295
  /** Reporter action gate forwarded into the persona prompt/context. */
325
296
  actionToolsEnabled?: boolean;
326
297
  }): Promise<ResolvedToolContext>;
@@ -377,23 +348,7 @@ interface ToolDepsBindings {
377
348
  scraper: Scraper;
378
349
  embedder: import('../interfaces/embedder.interface.js').Embedder;
379
350
  cache: Cache;
380
- integration: IntegrationAdapter;
381
351
  contactService: ContactServiceAdapter;
382
- /**
383
- * When false (or unset), the contact import / manual-add tools
384
- * (import_contacts, add_contact, import_gmail_contacts) are not registered.
385
- * Injected by the composition root from CONTACTS_ENABLED. Read/remove/search
386
- * contact tools are always registered.
387
- */
388
- contactsEnabled?: boolean;
389
- integrationImporter: {
390
- importContacts(userId: string, toolkit: string): Promise<{
391
- imported: number;
392
- skipped: number;
393
- newContacts: number;
394
- existingContacts: number;
395
- }>;
396
- };
397
352
  enricher: ProfileEnricher;
398
353
  /** Database adapter for negotiations/conversation operations. */
399
354
  negotiationDatabase: NegotiationGraphDatabase;
@@ -16,7 +16,7 @@ export class ChatContextAccessError extends Error {
16
16
  * This preloads user identity, profile, network memberships, and scoped index role.
17
17
  */
18
18
  export async function resolveChatContext(params) {
19
- const { database, userId, networkId, sessionId, contactsEnabled, actionToolsEnabled } = params;
19
+ const { database, userId, networkId, sessionId, actionToolsEnabled } = params;
20
20
  const [user, rawProfile, userNetworks, globalContext] = await Promise.all([
21
21
  database.getUser(userId),
22
22
  database.getProfile(userId),
@@ -93,7 +93,6 @@ export async function resolveChatContext(params) {
93
93
  scopedMembershipRole,
94
94
  isOnboarding: !(user.onboarding?.completedAt),
95
95
  hasName,
96
- contactsEnabled,
97
96
  actionToolsEnabled,
98
97
  ...(sessionId !== undefined ? { sessionId } : {}),
99
98
  };
@@ -4,7 +4,6 @@ import { createIntentTools } from '../../intents/application/intent.tools.js';
4
4
  import { createNetworkTools } from '../../networks/index.js';
5
5
  import { createOpportunityTools } from '../../opportunities/index.js';
6
6
  import { createUtilityTools } from './utility.tools.js';
7
- import { createIntegrationTools } from '../../integrations/index.js';
8
7
  import { createContactTools } from '../../contacts/index.js';
9
8
  import { createAgentTools } from '../../agents/index.js';
10
9
  import { createNegotiationTools } from '../../negotiations/index.js';
@@ -62,10 +61,9 @@ export function createToolRegistry(deps, options = {}) {
62
61
  // (IND-597). The retired report_agent_activity name retains no alias on
63
62
  // either surface (IND-605).
64
63
  createUtilityTools(dt, deps, { surface: isMcpSurface ? 'mcp' : 'rest' });
65
- // Contact/Gmail import tools are omitted from the MCP surface (IND-596). Their
64
+ // Contact tools are omitted from the MCP surface (IND-596). Their
66
65
  // implementations remain available to the REST Tool API and chat agent.
67
66
  if (!isMcpSurface) {
68
- createIntegrationTools(dt, deps);
69
67
  createContactTools(dt, deps);
70
68
  }
71
69
  createAgentTools(dt, deps);
@@ -42,8 +42,6 @@ const ASYNC_CANDIDATE_TOOLS = new Set([
42
42
  "create_intent",
43
43
  "update_intent",
44
44
  "scrape_url",
45
- "import_gmail_contacts",
46
- "import_contacts",
47
45
  "respond_to_negotiation",
48
46
  "create_premise",
49
47
  "update_premise",
@@ -93,23 +93,19 @@ export function createUtilityTools(defineTool, deps, options = {}) {
93
93
 
94
94
  Contacts are people in a user's personal network, stored as members of their personal network with 'contact' permission.
95
95
 
96
- - **Adding contacts**: Via import_contacts (bulk), add_contact (single email), or import_gmail_contacts (Google integration).
97
- - **Ghost users**: When a contact email doesn't match an existing account, a ghost user is created. Ghost users are enriched with public profile data and participate in opportunity matching — they can be discovered even before joining the platform.
96
+ - **How contacts arise**: Accepting an opportunity puts both people in each other's personal network. There is no import or manual-add path.
98
97
  - **Personal network scope**: Approved signals from personal-network contacts are matched in the background. Use list_opportunities only to review persisted results.
99
- - **Contact data**: Each contact has userId, name, email, avatar, and isGhost flag.
98
+ - **Contact data**: Each contact has userId, name, email, and avatar.
100
99
 
101
100
  ### Contact Workflow
102
- 1. import_contacts or import_gmail_contacts → bulk add to network
103
- 2. list_contacts → view all contacts with userId
104
- 3. create_intent or update_intent → create or refine an approved signal for background matching
105
- 4. list_opportunities → review persisted results when background processing finds matches
106
- 5. add_contact(email) → add individual contact
107
- 6. remove_contact(contactUserId) → remove from network`;
101
+ 1. list_contacts → view all contacts with userId
102
+ 2. create_intent or update_intent → create or refine an approved signal for background matching
103
+ 3. list_opportunities → review persisted results when background processing finds matches
104
+ 4. remove_contact(contactUserId) → remove from network`;
108
105
  const managingContactsWorkflow = `### Managing Contacts
109
- 1. import_gmail_contacts() or import_contacts([...]) → add contacts
110
- 2. list_contacts() → view network
111
- 3. create_intent or update_intent → create or refine an approved signal for background matching
112
- 4. list_opportunities → review persisted results
106
+ 1. list_contacts() → view network
107
+ 2. create_intent or update_intent → create or refine an approved signal for background matching
108
+ 3. list_opportunities → review persisted results
113
109
 
114
110
  `;
115
111
  const sections = {
@@ -5,14 +5,7 @@ import type { NetworkAssignmentMetadata } from '../schemas/network-assignment.sc
5
5
  import type { PremiseAnalysis, PremiseAssertion, PremiseProvenance, PremiseRecord, PremiseValidity } from './database.entities.js';
6
6
  /** Contact, premise and user-context operations. */
7
7
  export interface DatabaseMemberQueries {
8
- /** Create a ghost user (unregistered contact) with empty profile. */
9
- createGhostUser(data: {
10
- name: string;
11
- email: string;
12
- }): Promise<{
13
- id: string;
14
- }>;
15
- /** Upsert a contact membership in the owner's personal network (index_members with permissions=['contact']). */
8
+ /** Upsert a contact membership in the owner's personal network (network_members with permissions=['contact']). */
16
9
  upsertContactMembership(ownerId: string, contactUserId: string, options?: {
17
10
  restore?: boolean;
18
11
  }): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indexnetwork/protocol",
3
- "version": "16.1.1-rc.478.1",
3
+ "version": "17.0.1-rc.480.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "test": "bun test scripts/tests/test-runner.spec.ts && bun scripts/test.ts",
24
24
  "test:isolated": "bun test scripts/tests/test-runner.spec.ts && bun scripts/test.ts",
25
25
  "test:shared": "bun test",
26
- "test:architecture": "bun test src/architecture/tests scripts/architecture/tests",
26
+ "test:architecture": "bun test scripts/architecture/tests",
27
27
  "architecture:host-isolation": "bun scripts/architecture/host-isolation.ts",
28
28
  "architecture:capabilities": "bun scripts/architecture/capability-boundaries.ts",
29
29
  "architecture:check": "bun run architecture:host-isolation && bun run architecture:capabilities && bun run test:architecture",
@@ -1,49 +0,0 @@
1
- /**
2
- * contacts/application — generateInviteMessage canonical implementation.
3
- *
4
- * Invite Generator Agent: generates contextual, editable invite messages for
5
- * ghost users. Produces warm, concise messages (~2-3 sentences) referencing
6
- * why two users were matched, with optional referrer mention.
7
- *
8
- * IND-549: moved from contact/contact.inviter.ts into the canonical
9
- * contacts/application layer.
10
- */
11
- import { z } from "zod";
12
- declare const InviteInputSchema: z.ZodObject<{
13
- recipientName: z.ZodString;
14
- senderName: z.ZodString;
15
- opportunityInterpretation: z.ZodString;
16
- senderIntents: z.ZodArray<z.ZodString, "many">;
17
- recipientIntents: z.ZodArray<z.ZodString, "many">;
18
- referrerName: z.ZodOptional<z.ZodString>;
19
- }, "strip", z.ZodTypeAny, {
20
- recipientName: string;
21
- senderName: string;
22
- opportunityInterpretation: string;
23
- senderIntents: string[];
24
- recipientIntents: string[];
25
- referrerName?: string | undefined;
26
- }, {
27
- recipientName: string;
28
- senderName: string;
29
- opportunityInterpretation: string;
30
- senderIntents: string[];
31
- recipientIntents: string[];
32
- referrerName?: string | undefined;
33
- }>;
34
- declare const InviteOutputSchema: z.ZodObject<{
35
- message: z.ZodString;
36
- }, "strip", z.ZodTypeAny, {
37
- message: string;
38
- }, {
39
- message: string;
40
- }>;
41
- export type InviteInput = z.infer<typeof InviteInputSchema>;
42
- export type InviteOutput = z.infer<typeof InviteOutputSchema>;
43
- /**
44
- * Generates a contextual invite message for a ghost user.
45
- * @param input - Context about sender, recipient, and opportunity
46
- * @returns Generated invite message text
47
- */
48
- export declare function generateInviteMessage(input: InviteInput): Promise<InviteOutput>;
49
- export {};
@@ -1,64 +0,0 @@
1
- /**
2
- * contacts/application — generateInviteMessage canonical implementation.
3
- *
4
- * Invite Generator Agent: generates contextual, editable invite messages for
5
- * ghost users. Produces warm, concise messages (~2-3 sentences) referencing
6
- * why two users were matched, with optional referrer mention.
7
- *
8
- * IND-549: moved from contact/contact.inviter.ts into the canonical
9
- * contacts/application layer.
10
- */
11
- import { HumanMessage, SystemMessage } from "@langchain/core/messages";
12
- import { z } from "zod";
13
- import { createStructuredModel } from "../../shared/agent/model.config.js";
14
- import { stripUnsupportedOpportunityClaims } from "../../shared/utils/claim-safety.js";
15
- const InviteInputSchema = z.object({
16
- recipientName: z.string(),
17
- senderName: z.string(),
18
- opportunityInterpretation: z.string(),
19
- senderIntents: z.array(z.string()),
20
- recipientIntents: z.array(z.string()),
21
- referrerName: z.string().optional(),
22
- });
23
- const InviteOutputSchema = z.object({
24
- message: z.string().describe("The invite message text, ready to edit and send"),
25
- });
26
- const SYSTEM_PROMPT = `You generate brief, casual invite messages for a discovery platform called Index.
27
-
28
- The sender wants to reach out to someone they were matched with. Write a short, human message (2-3 sentences max) that:
29
- - Sounds like a real person texting, not a LinkedIn outreach or AI email
30
- - References one concrete, specific detail from the opportunity context — something actual, like a specific project, technology, or goal they share. Not "we have similar interests" or "I noticed we're both in this space" — name the actual thing.
31
- - If a referrer is provided, casually drops that they were introduced
32
- - Ends naturally — no formal CTAs, no "Would you be open to..." closings
33
-
34
- Tone: casual, direct, human. Think how you'd actually message someone you just got introduced to.
35
- Do NOT use a generic opener like "Hi [Name], I'm [Sender]." Just get to the point.
36
- Do NOT summarize the person's background. Pick one real, specific overlap from the context and mention it.
37
- Do NOT include a subject line. This is a chat message.
38
- Do NOT use placeholder brackets like [Name]. Use the actual names provided.
39
- Network assignment, network title/type, and event/network metadata are retrieval context only. They are NEVER proof that either person attended or will attend, belongs to a group, resides in a place, knows anyone from the network, or shared a session, time, place, or location. Do not make co-attendance, membership, residence, shared-session, or same-place/same-time claims from network co-membership.`;
40
- /**
41
- * Generates a contextual invite message for a ghost user.
42
- * @param input - Context about sender, recipient, and opportunity
43
- * @returns Generated invite message text
44
- */
45
- export async function generateInviteMessage(input) {
46
- const validated = InviteInputSchema.parse(input);
47
- const structuredModel = createStructuredModel("inviteGenerator", InviteOutputSchema);
48
- const safeInterpretation = stripUnsupportedOpportunityClaims(validated.opportunityInterpretation) ||
49
- "Their current goals may be relevant to each other.";
50
- const userPrompt = `Generate an invite message with this context:
51
- - Sender: ${validated.senderName}
52
- - Recipient: ${validated.recipientName}
53
- - Why they matched: ${safeInterpretation}
54
- - Sender's interests: ${validated.senderIntents.join(', ') || 'Not specified'}
55
- - Recipient's interests: ${validated.recipientIntents.join(', ') || 'Not specified'}${validated.referrerName ? `\n- Referred by: ${validated.referrerName}` : ''}`;
56
- const result = InviteOutputSchema.parse(await structuredModel.invoke([
57
- new SystemMessage(SYSTEM_PROMPT),
58
- new HumanMessage(userPrompt),
59
- ]));
60
- const safeMessage = stripUnsupportedOpportunityClaims(result.message);
61
- return {
62
- message: safeMessage || "Thought it could be useful for us to compare notes on what we're working on.",
63
- };
64
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * integrations/application — foreground adapters for the integrations capability.
3
- *
4
- * ## Exports
5
- *
6
- * ### Tool factory
7
- * - `createIntegrationTools` — creates integration MCP tools (import_gmail_contacts).
8
- * The tool is gated behind deps.contactsEnabled; when disabled, returns [].
9
- *
10
- * IND-549: canonical application layer for the integrations capability.
11
- * Legacy path:
12
- * - integration/integration.tools.ts → thin compatibility shim pointing here
13
- */
14
- export { createIntegrationTools } from "./integration.tools.js";
@@ -1,14 +0,0 @@
1
- /**
2
- * integrations/application — foreground adapters for the integrations capability.
3
- *
4
- * ## Exports
5
- *
6
- * ### Tool factory
7
- * - `createIntegrationTools` — creates integration MCP tools (import_gmail_contacts).
8
- * The tool is gated behind deps.contactsEnabled; when disabled, returns [].
9
- *
10
- * IND-549: canonical application layer for the integrations capability.
11
- * Legacy path:
12
- * - integration/integration.tools.ts → thin compatibility shim pointing here
13
- */
14
- export { createIntegrationTools } from "./integration.tools.js";
@@ -1,27 +0,0 @@
1
- /**
2
- * integrations/application — createIntegrationTools canonical implementation.
3
- *
4
- * Creates integration tools for the chat agent. Exposes `import_gmail_contacts`
5
- * which authenticates via the integration adapter, fetches all Gmail contacts
6
- * (paginated), and imports them as ghost users into the network.
7
- *
8
- * Feature gating: import_gmail_contacts creates ghost users, so it is gated
9
- * behind the CONTACTS_ENABLED flag (deps.contactsEnabled). When disabled,
10
- * the tool is not registered at all (defineTool registers as a side effect).
11
- *
12
- * IND-549: moved from integration/integration.tools.ts into the canonical
13
- * integrations/application layer.
14
- */
15
- import type { DefineTool } from '../../shared/agent/tool.helpers.js';
16
- import type { IntegrationToolDeps } from '../ports/index.js';
17
- /**
18
- * Creates integration tools for the chat agent.
19
- *
20
- * Exposes `import_gmail_contacts` which authenticates via the integration adapter,
21
- * fetches all Gmail contacts (paginated), and imports them as ghost users into the network.
22
- *
23
- * @param defineTool - Tool definition helper injected by the tool registry.
24
- * @param deps - Shared tool dependencies including the integration adapter.
25
- * @returns An array of tool definitions to register with the chat agent.
26
- */
27
- export declare function createIntegrationTools(defineTool: DefineTool, deps: IntegrationToolDeps): any[];
@@ -1,98 +0,0 @@
1
- /**
2
- * integrations/application — createIntegrationTools canonical implementation.
3
- *
4
- * Creates integration tools for the chat agent. Exposes `import_gmail_contacts`
5
- * which authenticates via the integration adapter, fetches all Gmail contacts
6
- * (paginated), and imports them as ghost users into the network.
7
- *
8
- * Feature gating: import_gmail_contacts creates ghost users, so it is gated
9
- * behind the CONTACTS_ENABLED flag (deps.contactsEnabled). When disabled,
10
- * the tool is not registered at all (defineTool registers as a side effect).
11
- *
12
- * IND-549: moved from integration/integration.tools.ts into the canonical
13
- * integrations/application layer.
14
- */
15
- import { z } from 'zod';
16
- import { success, error } from '../../shared/agent/tool.helpers.js';
17
- import { requestContext } from "../../shared/observability/request-context.js";
18
- import { protocolLogger } from '../../shared/observability/protocol.logger.js';
19
- const logger = protocolLogger('ChatTools:Integration');
20
- /**
21
- * Creates integration tools for the chat agent.
22
- *
23
- * Exposes `import_gmail_contacts` which authenticates via the integration adapter,
24
- * fetches all Gmail contacts (paginated), and imports them as ghost users into the network.
25
- *
26
- * @param defineTool - Tool definition helper injected by the tool registry.
27
- * @param deps - Shared tool dependencies including the integration adapter.
28
- * @returns An array of tool definitions to register with the chat agent.
29
- */
30
- export function createIntegrationTools(defineTool, deps) {
31
- const { integration, integrationImporter } = deps;
32
- // import_gmail_contacts creates ghost users, so it is gated behind the
33
- // CONTACTS_ENABLED flag (injected as deps.contactsEnabled). When disabled the
34
- // tool is not registered at all (defineTool registers as a side effect).
35
- if (deps.contactsEnabled !== true) {
36
- return [];
37
- }
38
- const import_gmail_contacts = defineTool({
39
- name: 'import_gmail_contacts',
40
- description: "Imports contacts from the user's connected Gmail/Google account into their personal network. " +
41
- "This is the preferred method for importing Google Contacts — handles OAuth authentication, pagination, and deduplication automatically.\n\n" +
42
- "**Authentication flow:** If Gmail is not yet connected, returns an `authUrl` the user must visit to grant access. " +
43
- "After they complete OAuth, call this tool again to perform the actual import.\n\n" +
44
- "**What happens on import:** All Gmail contacts with valid name+email are imported. " +
45
- "Contacts without existing platform accounts become ghost users (enriched with public profile data from LinkedIn, GitHub, etc.). " +
46
- "All imported contacts are added to the user's personal network for opportunity discovery.\n\n" +
47
- "**When to use:** When the user asks to import or sync their Gmail/Google contacts. No parameters needed.\n\n" +
48
- "**Returns:** Either `{ requiresAuth: true, authUrl }` (user needs to authenticate) or import statistics: " +
49
- "imported (total), newContacts (ghost users created), existingContacts (already in network), skipped (invalid entries).",
50
- querySchema: z.object({}),
51
- handler: async ({ context }) => {
52
- try {
53
- const session = await integration.createSession(context.userId);
54
- const toolkits = await session.toolkits();
55
- const gmailToolkit = toolkits.items.find(t => t.slug === 'gmail');
56
- const isConnected = !!gmailToolkit?.connection?.connectedAccount?.id;
57
- if (!isConnected) {
58
- logger.info('Gmail not connected, returning auth URL', { userId: context.userId });
59
- const originUrl = requestContext.getStore()?.originUrl;
60
- const callbackUrl = originUrl ? `${originUrl}/oauth/callback` : undefined;
61
- const authRequest = await session.authorize('gmail', callbackUrl ? { callbackUrl } : undefined);
62
- return success({
63
- requiresAuth: true,
64
- message: 'Please connect your Gmail account to import contacts.',
65
- authUrl: authRequest.redirectUrl,
66
- });
67
- }
68
- const importResult = await integrationImporter.importContacts(context.userId, 'gmail');
69
- logger.info('Gmail contacts imported', {
70
- userId: context.userId,
71
- imported: importResult.imported,
72
- skipped: importResult.skipped,
73
- newContacts: importResult.newContacts,
74
- existingContacts: importResult.existingContacts,
75
- });
76
- return success({
77
- message: importResult.newContacts > 0
78
- ? `Imported ${importResult.imported} contacts from Gmail. ${importResult.newContacts} new, ${importResult.existingContacts} already in your network.`
79
- : importResult.imported > 0
80
- ? `All ${importResult.imported} contacts from Gmail were already in your network. No new contacts added.`
81
- : 'No contacts with valid name and email found in your Gmail account.',
82
- imported: importResult.imported,
83
- newContacts: importResult.newContacts,
84
- existingContacts: importResult.existingContacts,
85
- skipped: importResult.skipped,
86
- });
87
- }
88
- catch (err) {
89
- logger.error('import_gmail_contacts failed', {
90
- userId: context.userId,
91
- err,
92
- });
93
- return error('Failed to import Gmail contacts. Please try again.');
94
- }
95
- },
96
- });
97
- return [import_gmail_contacts];
98
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * integrations/domain — pure integration entity value types.
3
- *
4
- * Contains IntegrationSession, IntegrationSessionOptions, ToolActionResponse,
5
- * and IntegrationConnection.
6
- *
7
- * ## What does NOT live here
8
- *
9
- * - IntegrationAdapter: platform adapter port — lives in integrations/ports.
10
- * - IntegrationImporter: bulk-import port — lives in integrations/ports.
11
- * - IntegrationToolDeps: tool host port — lives in integrations/ports.
12
- * - createIntegrationTools: application layer — lives in integrations/application.
13
- *
14
- * IND-549: canonical domain layer for the integrations capability.
15
- */
16
- export type { IntegrationSession, IntegrationSessionOptions, ToolActionResponse, IntegrationConnection, } from "./integration.types.js";
@@ -1 +0,0 @@
1
- export {};
@@ -1,51 +0,0 @@
1
- /**
2
- * integrations/domain — pure integration entity value types.
3
- *
4
- * Contains session shapes, connection records, and tool action responses.
5
- * No application logic, no LLM calls, no cross-capability imports.
6
- *
7
- * IND-549: canonical domain layer for the integrations capability.
8
- */
9
- /**
10
- * Session for interacting with an external integration platform.
11
- * Provides access to tools, OAuth authorization, and toolkit discovery.
12
- */
13
- export interface IntegrationSession {
14
- tools(): Promise<unknown[]>;
15
- authorize(toolkit: string): Promise<{
16
- redirectUrl: string;
17
- waitForConnection(timeout?: number): Promise<unknown>;
18
- }>;
19
- toolkits(): Promise<{
20
- items: Array<{
21
- slug: string;
22
- name: string;
23
- connection?: {
24
- connectedAccount?: {
25
- id: string;
26
- };
27
- };
28
- }>;
29
- }>;
30
- }
31
- /** Options for creating an integration session. */
32
- export interface IntegrationSessionOptions {
33
- manageConnections?: boolean | {
34
- callbackUrl?: string;
35
- };
36
- /** Toolkit slug → auth config ID mapping to pin existing auth configs. */
37
- authConfigs?: Record<string, string>;
38
- }
39
- /** Response from executing a tool action on the integration platform. */
40
- export interface ToolActionResponse {
41
- successful: boolean;
42
- error?: string;
43
- data?: Record<string, unknown>;
44
- }
45
- /** A connected integration account for a user. */
46
- export interface IntegrationConnection {
47
- id: string;
48
- toolkit: string;
49
- status: string;
50
- createdAt: string;
51
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * integrations/domain — pure integration entity value types.
3
- *
4
- * Contains session shapes, connection records, and tool action responses.
5
- * No application logic, no LLM calls, no cross-capability imports.
6
- *
7
- * IND-549: canonical domain layer for the integrations capability.
8
- */
9
- export {};
@@ -1,10 +0,0 @@
1
- /**
2
- * integrations — the capability's sole cross-capability surface.
3
- *
4
- * Anything outside this capability imports from here and nowhere else.
5
- * Supersedes the capabilities/*.facade.ts + integrations/public/ pair; the export
6
- * list is the union of the facades it replaces, so the contract is unchanged.
7
- */
8
- export { createIntegrationTools, } from "./application/index.js";
9
- export type { IntegrationConnection, IntegrationSession, IntegrationSessionOptions, ToolActionResponse, } from "./domain/index.js";
10
- export type { IntegrationAdapter, IntegrationToolDeps, } from "./ports/index.js";
@@ -1,8 +0,0 @@
1
- /**
2
- * integrations — the capability's sole cross-capability surface.
3
- *
4
- * Anything outside this capability imports from here and nowhere else.
5
- * Supersedes the capabilities/*.facade.ts + integrations/public/ pair; the export
6
- * list is the union of the facades it replaces, so the contract is unchanged.
7
- */
8
- export { createIntegrationTools, } from "./application/index.js";
@@ -1,25 +0,0 @@
1
- /**
2
- * integrations/ports — injected dependency contracts for the integrations capability.
3
- *
4
- * Re-exports the narrow port types that the integrations module declares as
5
- * explicit injected boundaries. Consumers import these to wire host
6
- * implementations without depending on the application layer.
7
- *
8
- * ## Port groups
9
- *
10
- * ### Platform adapter port
11
- * - IntegrationAdapter — session creation, tool execution, connection management,
12
- * OAuth auth URLs, and disconnection.
13
- *
14
- * ### Bulk import port
15
- * - IntegrationImporter — toolkit-to-contacts bulk import pipeline.
16
- * - IntegrationImportResult — aggregate import statistics.
17
- *
18
- * ### Tool host port
19
- * - IntegrationToolDeps — host capabilities for integration-backed tools.
20
- *
21
- * IND-549: canonical ports surface for the integrations capability.
22
- */
23
- export type { IntegrationAdapter } from "./integration.adapter.port.js";
24
- export type { IntegrationImporter, IntegrationImportResult } from "./integration.importer.port.js";
25
- export type { IntegrationToolDeps } from "./integration.tools.port.js";
@@ -1,23 +0,0 @@
1
- /**
2
- * integrations/ports — injected dependency contracts for the integrations capability.
3
- *
4
- * Re-exports the narrow port types that the integrations module declares as
5
- * explicit injected boundaries. Consumers import these to wire host
6
- * implementations without depending on the application layer.
7
- *
8
- * ## Port groups
9
- *
10
- * ### Platform adapter port
11
- * - IntegrationAdapter — session creation, tool execution, connection management,
12
- * OAuth auth URLs, and disconnection.
13
- *
14
- * ### Bulk import port
15
- * - IntegrationImporter — toolkit-to-contacts bulk import pipeline.
16
- * - IntegrationImportResult — aggregate import statistics.
17
- *
18
- * ### Tool host port
19
- * - IntegrationToolDeps — host capabilities for integration-backed tools.
20
- *
21
- * IND-549: canonical ports surface for the integrations capability.
22
- */
23
- export {};