@indexnetwork/protocol 8.3.0-rc.424.1 → 8.4.0-rc.426.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 (51) hide show
  1. package/IMPLEMENTATION.md +2 -2
  2. package/dist/capabilities/opportunities.facade.d.ts +5 -5
  3. package/dist/capabilities/opportunities.facade.js +4 -4
  4. package/dist/index.d.ts +6 -6
  5. package/dist/index.js +4 -4
  6. package/dist/maintenance/maintenance.graph.d.ts +9 -9
  7. package/dist/maintenance/maintenance.graph.js +20 -20
  8. package/dist/maintenance/maintenance.state.d.ts +5 -5
  9. package/dist/maintenance/maintenance.state.js +3 -3
  10. package/dist/opportunity/application/delivery-card.cache.js +1 -1
  11. package/dist/opportunity/application/index.d.ts +2 -3
  12. package/dist/opportunity/application/index.js +3 -4
  13. package/dist/opportunity/application/negotiation-context.loader.d.ts +1 -1
  14. package/dist/opportunity/application/negotiation-context.loader.js +1 -1
  15. package/dist/opportunity/application/opportunity.enricher.js +2 -2
  16. package/dist/opportunity/application/opportunity.presenter.d.ts +15 -15
  17. package/dist/opportunity/application/opportunity.presenter.js +17 -17
  18. package/dist/opportunity/application/opportunity.tools.d.ts +1 -1
  19. package/dist/opportunity/application/opportunity.tools.js +3 -3
  20. package/dist/opportunity/discriminator/discriminator.adjustments.js +1 -1
  21. package/dist/opportunity/discriminator/discriminator.env.d.ts +1 -1
  22. package/dist/opportunity/discriminator/discriminator.env.js +1 -1
  23. package/dist/opportunity/domain/index.d.ts +3 -3
  24. package/dist/opportunity/domain/index.js +3 -3
  25. package/dist/opportunity/domain/opportunity.presentation-cache.d.ts +1 -2
  26. package/dist/opportunity/domain/opportunity.presentation-cache.js +2 -5
  27. package/dist/opportunity/domain/opportunity.presentation.d.ts +1 -1
  28. package/dist/opportunity/domain/opportunity.presentation.js +1 -1
  29. package/dist/opportunity/domain/opportunity.safe-presentation.d.ts +2 -2
  30. package/dist/opportunity/domain/opportunity.safe-presentation.js +1 -1
  31. package/dist/opportunity/domain/opportunity.utils.d.ts +5 -5
  32. package/dist/opportunity/domain/opportunity.utils.js +8 -8
  33. package/dist/opportunity/index.d.ts +1 -1
  34. package/dist/opportunity/index.js +1 -1
  35. package/dist/opportunity/opportunity.presenter.d.ts +3 -3
  36. package/dist/opportunity/opportunity.presenter.js +2 -2
  37. package/dist/opportunity/public/index.d.ts +5 -5
  38. package/dist/opportunity/public/index.js +6 -6
  39. package/dist/opportunity/{feed/feed.graph.d.ts → radar/radar.graph.d.ts} +42 -73
  40. package/dist/opportunity/{feed/feed.graph.js → radar/radar.graph.js} +60 -222
  41. package/dist/opportunity/{feed/feed.health.d.ts → radar/radar.health.d.ts} +7 -7
  42. package/dist/opportunity/{feed/feed.health.js → radar/radar.health.js} +8 -8
  43. package/dist/opportunity/{feed/feed.state.d.ts → radar/radar.state.d.ts} +21 -47
  44. package/dist/opportunity/{feed/feed.state.js → radar/radar.state.js} +15 -24
  45. package/dist/shared/agent/tool.helpers.d.ts +1 -1
  46. package/dist/shared/interfaces/database.interface.d.ts +3 -3
  47. package/package.json +1 -1
  48. package/dist/opportunity/feed/feed.categorizer.d.ts +0 -27
  49. package/dist/opportunity/feed/feed.categorizer.js +0 -168
  50. package/dist/shared/ui/lucide.icon-catalog.d.ts +0 -21
  51. package/dist/shared/ui/lucide.icon-catalog.js +0 -100
@@ -1,9 +1,9 @@
1
1
  import type { Opportunity, OpportunityStatus } from '../../shared/interfaces/database.interface.js';
2
2
  import type { DebugMetaAgent } from '../../capabilities/participant-agents.debug.facade.js';
3
3
  /**
4
- * Home view card item: one opportunity with full presenter-driven display contract.
4
+ * Radar card item: one opportunity with full presenter-driven display contract.
5
5
  */
6
- export interface HomeCardItem {
6
+ export interface RadarCardItem {
7
7
  opportunityId: string;
8
8
  /** Lifecycle status of the underlying opportunity at render time (client bucketing, e.g. intent radar). */
9
9
  status?: OpportunityStatus;
@@ -46,77 +46,51 @@ export interface HomeCardItem {
46
46
  presentationPending?: boolean;
47
47
  /** Internal marker: safe deterministic fallback rendered, but must not be cached. */
48
48
  _presentationFallback?: boolean;
49
- /** For section assignment from LLM */
49
+ /** Internal: original position in the loaded opportunity list, for stable ordering. */
50
50
  _cardIndex: number;
51
51
  }
52
+ /** Card item as returned in API responses (no internal fields). */
53
+ export type RadarResponseItem = Omit<RadarCardItem, '_cardIndex' | '_presentationFallback'>;
52
54
  /**
53
- * Dynamic section from LLM categorization.
55
+ * Radar Graph State (Annotation-based).
56
+ * Flow: loadOpportunities → checkPresenterCache → [generateCardText if misses]
57
+ * → cachePresenterResults → normalizeItems.
54
58
  */
55
- export interface HomeSectionProposal {
56
- id: string;
57
- title: string;
58
- subtitle?: string;
59
- iconName: string;
60
- itemIndices: number[];
61
- }
62
- /** Card item as returned in API (no internal _cardIndex). */
63
- export type HomeSectionItem = Omit<HomeCardItem, '_cardIndex' | '_presentationFallback'>;
64
- /**
65
- * Final section for API response.
66
- */
67
- export interface HomeSection {
68
- id: string;
69
- title: string;
70
- subtitle?: string;
71
- iconName: string;
72
- items: HomeSectionItem[];
73
- }
74
- /**
75
- * Home Graph State (Annotation-based).
76
- * Flow: loadOpportunities → generateCardText → categorizeDynamically → normalizeAndSort → finalizeResponse.
77
- */
78
- export declare const HomeGraphState: import("@langchain/langgraph").AnnotationRoot<{
59
+ export declare const RadarGraphState: import("@langchain/langgraph").AnnotationRoot<{
79
60
  userId: import("@langchain/langgraph").BaseChannel<string, string | import("@langchain/langgraph").OverwriteValue<string>, unknown>;
80
61
  networkId: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
81
62
  scopeType: import("@langchain/langgraph").BaseChannel<"intent" | undefined, "intent" | import("@langchain/langgraph").OverwriteValue<"intent" | undefined> | undefined, unknown>;
82
63
  scopeId: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
83
64
  limit: import("@langchain/langgraph").BaseChannel<number, number | import("@langchain/langgraph").OverwriteValue<number>, unknown>;
84
- /** When true, bypass presenter and categorizer Redis caches. */
65
+ /** When true, bypass the presenter Redis cache. */
85
66
  noCache: import("@langchain/langgraph").BaseChannel<boolean, boolean | import("@langchain/langgraph").OverwriteValue<boolean>, unknown>;
86
67
  /**
87
- * Presentation depth. 'full' (default) runs the presenter LLM and categorizer.
88
- * 'skeleton' skips both for cache misses: uncached cards come back with
89
- * resolved identity (name/avatar/status) and `presentationPending: true`,
90
- * cached cards come back complete, and all cards land in one flat section.
68
+ * Presentation depth. 'full' (default) runs the presenter LLM for cache
69
+ * misses. 'skeleton' skips it: uncached cards come back with resolved
70
+ * identity (name/avatar/status) and `presentationPending: true`, cached
71
+ * cards come back complete.
91
72
  */
92
73
  presentation: import("@langchain/langgraph").BaseChannel<"full" | "skeleton", "full" | "skeleton" | import("@langchain/langgraph").OverwriteValue<"full" | "skeleton">, unknown>;
93
- /** Optional status filter. When undefined, the graph uses `DEFAULT_HOME_STATUSES`. */
74
+ /** Optional status filter. When undefined, the graph uses `DEFAULT_RADAR_STATUSES`. */
94
75
  statuses: import("@langchain/langgraph").BaseChannel<OpportunityStatus[] | undefined, OpportunityStatus[] | import("@langchain/langgraph").OverwriteValue<OpportunityStatus[] | undefined> | undefined, unknown>;
95
76
  /** Raw opportunities visible to the viewer (after visibility filter). */
96
77
  opportunities: import("@langchain/langgraph").BaseChannel<Opportunity[], Opportunity[] | import("@langchain/langgraph").OverwriteValue<Opportunity[]>, unknown>;
97
78
  /** Cards with presenter output and narrator chip. */
98
- cards: import("@langchain/langgraph").BaseChannel<HomeCardItem[], HomeCardItem[] | import("@langchain/langgraph").OverwriteValue<HomeCardItem[]>, unknown>;
99
- /** LLM output: dynamic sections with icon and item indices. */
100
- sectionProposals: import("@langchain/langgraph").BaseChannel<HomeSectionProposal[], HomeSectionProposal[] | import("@langchain/langgraph").OverwriteValue<HomeSectionProposal[]>, unknown>;
101
- /** Final sections for response. */
102
- sections: import("@langchain/langgraph").BaseChannel<HomeSection[], HomeSection[] | import("@langchain/langgraph").OverwriteValue<HomeSection[]>, unknown>;
103
- /** Presenter results retrieved from cache (opportunityId → HomeCardItem). */
104
- cachedCards: import("@langchain/langgraph").BaseChannel<Map<string, HomeCardItem>, Map<string, HomeCardItem> | import("@langchain/langgraph").OverwriteValue<Map<string, HomeCardItem>>, unknown>;
79
+ cards: import("@langchain/langgraph").BaseChannel<RadarCardItem[], RadarCardItem[] | import("@langchain/langgraph").OverwriteValue<RadarCardItem[]>, unknown>;
80
+ /** Final items for response (internal fields stripped). */
81
+ items: import("@langchain/langgraph").BaseChannel<RadarResponseItem[], RadarResponseItem[] | import("@langchain/langgraph").OverwriteValue<RadarResponseItem[]>, unknown>;
82
+ /** Presenter results retrieved from cache (opportunityId → RadarCardItem). */
83
+ cachedCards: import("@langchain/langgraph").BaseChannel<Map<string, RadarCardItem>, Map<string, RadarCardItem> | import("@langchain/langgraph").OverwriteValue<Map<string, RadarCardItem>>, unknown>;
105
84
  /** Opportunities that had no cache hit and need presenter generation. */
106
85
  uncachedOpportunities: import("@langchain/langgraph").BaseChannel<Opportunity[], Opportunity[] | import("@langchain/langgraph").OverwriteValue<Opportunity[]>, unknown>;
107
- /** Whether categorizer results were found in cache. */
108
- categoryCacheHit: import("@langchain/langgraph").BaseChannel<boolean, boolean | import("@langchain/langgraph").OverwriteValue<boolean>, unknown>;
109
86
  error: import("@langchain/langgraph").BaseChannel<string | undefined, string | import("@langchain/langgraph").OverwriteValue<string | undefined> | undefined, unknown>;
110
- /** Meta for response (e.g. totalOpportunities, totalSections). */
87
+ /** Meta for response (e.g. totalOpportunities). */
111
88
  meta: import("@langchain/langgraph").BaseChannel<{
112
89
  totalOpportunities: number;
113
- totalSections: number;
114
90
  }, {
115
91
  totalOpportunities: number;
116
- totalSections: number;
117
92
  } | import("@langchain/langgraph").OverwriteValue<{
118
93
  totalOpportunities: number;
119
- totalSections: number;
120
94
  }>, unknown>;
121
95
  /** Timing records for each agent invocation within this graph run. */
122
96
  agentTimings: import("@langchain/langgraph").BaseChannel<DebugMetaAgent[], DebugMetaAgent[] | import("@langchain/langgraph").OverwriteValue<DebugMetaAgent[]>, unknown>;
@@ -1,9 +1,10 @@
1
1
  import { Annotation } from '@langchain/langgraph';
2
2
  /**
3
- * Home Graph State (Annotation-based).
4
- * Flow: loadOpportunities → generateCardTextcategorizeDynamically normalizeAndSort → finalizeResponse.
3
+ * Radar Graph State (Annotation-based).
4
+ * Flow: loadOpportunities → checkPresenterCache[generateCardText if misses]
5
+ * → cachePresenterResults → normalizeItems.
5
6
  */
6
- export const HomeGraphState = Annotation.Root({
7
+ export const RadarGraphState = Annotation.Root({
7
8
  userId: Annotation({
8
9
  reducer: (curr, next) => next ?? curr,
9
10
  default: () => '',
@@ -24,22 +25,22 @@ export const HomeGraphState = Annotation.Root({
24
25
  reducer: (curr, next) => next ?? curr,
25
26
  default: () => 50,
26
27
  }),
27
- /** When true, bypass presenter and categorizer Redis caches. */
28
+ /** When true, bypass the presenter Redis cache. */
28
29
  noCache: Annotation({
29
30
  reducer: (curr, next) => next ?? curr,
30
31
  default: () => false,
31
32
  }),
32
33
  /**
33
- * Presentation depth. 'full' (default) runs the presenter LLM and categorizer.
34
- * 'skeleton' skips both for cache misses: uncached cards come back with
35
- * resolved identity (name/avatar/status) and `presentationPending: true`,
36
- * cached cards come back complete, and all cards land in one flat section.
34
+ * Presentation depth. 'full' (default) runs the presenter LLM for cache
35
+ * misses. 'skeleton' skips it: uncached cards come back with resolved
36
+ * identity (name/avatar/status) and `presentationPending: true`, cached
37
+ * cards come back complete.
37
38
  */
38
39
  presentation: Annotation({
39
40
  reducer: (curr, next) => next ?? curr,
40
41
  default: () => 'full',
41
42
  }),
42
- /** Optional status filter. When undefined, the graph uses `DEFAULT_HOME_STATUSES`. */
43
+ /** Optional status filter. When undefined, the graph uses `DEFAULT_RADAR_STATUSES`. */
43
44
  statuses: Annotation({
44
45
  reducer: (curr, next) => next ?? curr,
45
46
  default: () => undefined,
@@ -54,17 +55,12 @@ export const HomeGraphState = Annotation.Root({
54
55
  reducer: (curr, next) => next ?? curr,
55
56
  default: () => [],
56
57
  }),
57
- /** LLM output: dynamic sections with icon and item indices. */
58
- sectionProposals: Annotation({
58
+ /** Final items for response (internal fields stripped). */
59
+ items: Annotation({
59
60
  reducer: (curr, next) => next ?? curr,
60
61
  default: () => [],
61
62
  }),
62
- /** Final sections for response. */
63
- sections: Annotation({
64
- reducer: (curr, next) => next ?? curr,
65
- default: () => [],
66
- }),
67
- /** Presenter results retrieved from cache (opportunityId → HomeCardItem). */
63
+ /** Presenter results retrieved from cache (opportunityId → RadarCardItem). */
68
64
  cachedCards: Annotation({
69
65
  reducer: (curr, next) => next ?? curr,
70
66
  default: () => new Map(),
@@ -74,19 +70,14 @@ export const HomeGraphState = Annotation.Root({
74
70
  reducer: (curr, next) => next ?? curr,
75
71
  default: () => [],
76
72
  }),
77
- /** Whether categorizer results were found in cache. */
78
- categoryCacheHit: Annotation({
79
- reducer: (curr, next) => next ?? curr,
80
- default: () => false,
81
- }),
82
73
  error: Annotation({
83
74
  reducer: (curr, next) => next ?? curr,
84
75
  default: () => undefined,
85
76
  }),
86
- /** Meta for response (e.g. totalOpportunities, totalSections). */
77
+ /** Meta for response (e.g. totalOpportunities). */
87
78
  meta: Annotation({
88
79
  reducer: (curr, next) => next ?? curr,
89
- default: () => ({ totalOpportunities: 0, totalSections: 0 }),
80
+ default: () => ({ totalOpportunities: 0 }),
90
81
  }),
91
82
  /** Timing records for each agent invocation within this graph run. */
92
83
  agentTimings: Annotation({
@@ -425,7 +425,7 @@ interface ToolDepsBindings {
425
425
  */
426
426
  opportunityPresentation?: {
427
427
  createPresenter?: () => {
428
- presentHomeCard(input: unknown): Promise<unknown>;
428
+ presentCard(input: unknown): Promise<unknown>;
429
429
  };
430
430
  gatherPresenterContext?: (...args: unknown[]) => Promise<unknown>;
431
431
  };
@@ -537,7 +537,7 @@ export interface OpportunityQueryOptions {
537
537
  role?: string;
538
538
  limit?: number;
539
539
  offset?: number;
540
- /** When set, include draft opportunities for this chat session. When unset, exclude all draft opportunities (e.g. home view, API). */
540
+ /** When set, include draft opportunities for this chat session. When unset, exclude all draft opportunities (e.g. radar view, API). */
541
541
  conversationId?: string;
542
542
  }
543
543
  /**
@@ -2284,9 +2284,9 @@ export type NetworkMembershipGraphDatabase = Pick<Database, 'isNetworkMember' |
2284
2284
  */
2285
2285
  export type HydeGraphDatabase = Pick<Database, 'getHydeDocument' | 'getHydeDocumentsForSource' | 'saveHydeDocument' | 'getIntent'>;
2286
2286
  /**
2287
- * Database interface for Home Graph (opportunity home view).
2287
+ * Database interface for Radar Graph (opportunity radar view).
2288
2288
  * Load opportunities, enrich with profile/index, and support presenter context.
2289
2289
  *
2290
2290
  * Access layer: UserDatabase (own opportunities and profile)
2291
2291
  */
2292
- export type HomeGraphDatabase = Pick<Database, 'getOpportunitiesForUser' | 'getOpportunity' | 'getProfile' | 'getActiveIntents' | 'getNetwork' | 'getUser'> & Pick<NegotiationGraphDatabase, 'getNegotiationTaskForOpportunity' | 'getMessagesForConversation' | 'getArtifactsForTask'>;
2292
+ export type RadarGraphDatabase = Pick<Database, 'getOpportunitiesForUser' | 'getOpportunity' | 'getProfile' | 'getActiveIntents' | 'getNetwork' | 'getUser'> & Pick<NegotiationGraphDatabase, 'getNegotiationTaskForOpportunity' | 'getMessagesForConversation' | 'getArtifactsForTask'>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indexnetwork/protocol",
3
- "version": "8.3.0-rc.424.1",
3
+ "version": "8.4.0-rc.426.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,27 +0,0 @@
1
- /**
2
- * Home Categorizer Agent
3
- *
4
- * Takes a list of presenter-produced opportunity cards and returns dynamic sections
5
- * with CTA-style titles and Lucide icon names. Used by the home graph after
6
- * generateCardText.
7
- */
8
- import type { HomeSectionProposal } from './feed.state.js';
9
- export type CategorizerInputItem = {
10
- index: number;
11
- headline?: string;
12
- mainText: string;
13
- name: string;
14
- viewerRole?: string;
15
- opportunityStatus?: string;
16
- };
17
- export type CategorizerResult = {
18
- sections: HomeSectionProposal[];
19
- };
20
- export declare class HomeCategorizerAgent {
21
- private model;
22
- constructor();
23
- /**
24
- * Categorize presenter-produced cards into 1–5 sections with CTA-style titles and icons.
25
- */
26
- categorize(cards: CategorizerInputItem[]): Promise<CategorizerResult>;
27
- }
@@ -1,168 +0,0 @@
1
- /**
2
- * Home Categorizer Agent
3
- *
4
- * Takes a list of presenter-produced opportunity cards and returns dynamic sections
5
- * with CTA-style titles and Lucide icon names. Used by the home graph after
6
- * generateCardText.
7
- */
8
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
9
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
10
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
11
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
12
- return c > 3 && r && Object.defineProperty(target, key, r), r;
13
- };
14
- var __metadata = (this && this.__metadata) || function (k, v) {
15
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
16
- };
17
- import { HumanMessage, SystemMessage } from '@langchain/core/messages';
18
- import { z } from 'zod';
19
- import { getIconNamesForPrompt, DEFAULT_HOME_SECTION_ICON } from '../../shared/ui/lucide.icon-catalog.js';
20
- import { protocolLogger } from '../../shared/observability/protocol.logger.js';
21
- import { Timed } from "../../shared/observability/performance.js";
22
- import { createStructuredModel } from "../../shared/agent/model.config.js";
23
- import { invokeWithAbortSignal } from "../../shared/agent/model-signal.js";
24
- import { hasUnsupportedOpportunityClaim } from '../opportunity.claim-safety.js';
25
- const logger = protocolLogger('HomeCategorizer');
26
- const categorizationSchema = z.object({
27
- sections: z.array(z.object({
28
- id: z.string().describe('Short kebab-case id for the section'),
29
- title: z
30
- .string()
31
- .describe('Call-to-action style section heading (e.g. REACH OUT NOW, YOUR MOVE, CONNECTIONS WAITING FOR YOU)'),
32
- subtitle: z.string().nullable().describe('Optional one-line description; use null if none'),
33
- iconName: z.string().describe('Lucide icon name in kebab-case from the allowed list'),
34
- itemIndices: z.array(z.number()).describe('Indices of cards in this section (0-based)'),
35
- })),
36
- });
37
- const UNCATEGORIZED_SECTION_ID = 'uncategorized';
38
- const UNCATEGORIZED_SECTION_TITLE = 'UNCATEGORIZED OPPORTUNITIES';
39
- /** Single-section fallback grouping every card under one generic heading. */
40
- function buildFallbackResult(cards) {
41
- return {
42
- sections: [
43
- {
44
- id: 'opportunities',
45
- title: 'OPPORTUNITIES',
46
- iconName: DEFAULT_HOME_SECTION_ICON,
47
- itemIndices: cards.map((c) => c.index),
48
- },
49
- ],
50
- };
51
- }
52
- /**
53
- * Build card summaries for the categorizer prompt.
54
- */
55
- function buildCardSummaries(cards) {
56
- return cards
57
- .map((c) => {
58
- const role = c.viewerRole ?? 'party';
59
- const status = c.opportunityStatus ?? 'pending';
60
- return `[${c.index}] role=${role}; status=${status}; ${c.headline ?? c.mainText.slice(0, 60)}... (${c.name})`;
61
- })
62
- .join('\n');
63
- }
64
- function reconcileSections(sections, maxIndex) {
65
- const assigned = new Set();
66
- const normalizedSections = sections.map((section) => {
67
- const uniqueIndices = Array.from(new Set(section.itemIndices.filter((index) => index >= 0 && index <= maxIndex))).sort((a, b) => a - b);
68
- for (const index of uniqueIndices) {
69
- assigned.add(index);
70
- }
71
- return {
72
- ...section,
73
- itemIndices: uniqueIndices,
74
- };
75
- });
76
- const missingIndices = [];
77
- for (let index = 0; index <= maxIndex; index += 1) {
78
- if (!assigned.has(index)) {
79
- missingIndices.push(index);
80
- }
81
- }
82
- if (missingIndices.length === 0) {
83
- return normalizedSections;
84
- }
85
- const fallbackSection = normalizedSections.find((section) => section.id === UNCATEGORIZED_SECTION_ID);
86
- if (fallbackSection) {
87
- fallbackSection.itemIndices = Array.from(new Set([...fallbackSection.itemIndices, ...missingIndices])).sort((a, b) => a - b);
88
- return normalizedSections;
89
- }
90
- return [
91
- ...normalizedSections,
92
- {
93
- id: UNCATEGORIZED_SECTION_ID,
94
- title: UNCATEGORIZED_SECTION_TITLE,
95
- iconName: DEFAULT_HOME_SECTION_ICON,
96
- itemIndices: missingIndices,
97
- },
98
- ];
99
- }
100
- export class HomeCategorizerAgent {
101
- constructor() {
102
- this.model = createStructuredModel("homeCategorizer", categorizationSchema, { name: 'home_sections' });
103
- }
104
- /**
105
- * Categorize presenter-produced cards into 1–5 sections with CTA-style titles and icons.
106
- */
107
- async categorize(cards) {
108
- if (cards.length === 0) {
109
- return { sections: [] };
110
- }
111
- const iconList = getIconNamesForPrompt();
112
- const cardSummaries = buildCardSummaries(cards);
113
- const maxIndex = cards.length - 1;
114
- const systemPrompt = `You are organizing connection opportunities into dynamic sections for a user's home feed.
115
-
116
- Given a list of opportunity cards (each with index, headline/summary, and name), group them into 1–5 sections.
117
-
118
- Each section must have:
119
- - id: short kebab-case identifier (e.g. waiting-for-action, your-perspective, connector)
120
- - title: CALL-TO-ACTION style section heading in uppercase. Write as an action or invitation, not a neutral label. Examples: REACH OUT NOW, YOUR MOVE, CONNECTIONS WAITING FOR YOU, INTROS READY TO SEND, PEOPLE YOU SHOULD MEET
121
- - subtitle: optional one-line description
122
- - iconName: exactly ONE icon from this list (use the name as-is): ${iconList}
123
- - itemIndices: array of card indices that belong in this section (each index 0 to ${maxIndex} at most once)
124
-
125
- Rules:
126
- - Use only icon names from the list above.
127
- - Every card index must appear in exactly one section.
128
- - Section titles must read as calls-to-action or invitations, not passive labels.
129
- - If a card has role=introducer and status=pending, prioritize grouping those cards under a connector curation section with a CTA title like "YOU'RE THE CONNECTOR THEY NEED", "MAKE THE INTRO", or "DECIDE IF IT'S A GOOD MATCH".`;
130
- const userContent = `Cards to categorize:\n${cardSummaries}\n\nOutput sections with id, title (CTA-style), subtitle (optional), iconName, and itemIndices.`;
131
- try {
132
- const result = await invokeWithAbortSignal(this.model, [
133
- new SystemMessage(systemPrompt),
134
- new HumanMessage(userContent),
135
- ]);
136
- const parsed = categorizationSchema.safeParse(result);
137
- if (!parsed.success) {
138
- logger.warn('HomeCategorizer parse failed', { error: parsed.error });
139
- return buildFallbackResult(cards);
140
- }
141
- const sections = parsed.data.sections.map((s) => ({
142
- id: s.id,
143
- title: s.title,
144
- subtitle: s.subtitle ?? undefined,
145
- iconName: s.iconName,
146
- itemIndices: s.itemIndices.filter((i) => i >= 0 && i <= maxIndex),
147
- }));
148
- if (sections.some((section) => hasUnsupportedOpportunityClaim(section.title)
149
- || hasUnsupportedOpportunityClaim(section.subtitle))) {
150
- logger.warn('HomeCategorizer emitted unsupported affiliation/presence claim; using fallback');
151
- return buildFallbackResult(cards);
152
- }
153
- const reconciledSections = reconcileSections(sections, maxIndex);
154
- return { sections: reconciledSections };
155
- }
156
- catch (e) {
157
- const err = e instanceof Error ? { message: e.message, name: e.name } : String(e);
158
- logger.error('HomeCategorizer categorize failed', { error: err });
159
- return buildFallbackResult(cards);
160
- }
161
- }
162
- }
163
- __decorate([
164
- Timed(),
165
- __metadata("design:type", Function),
166
- __metadata("design:paramtypes", [Array]),
167
- __metadata("design:returntype", Promise)
168
- ], HomeCategorizerAgent.prototype, "categorize", null);
@@ -1,21 +0,0 @@
1
- /**
2
- * Lucide icon catalog for home view section headings.
3
- * Icon names are kebab-case for use with lucide-react DynamicIcon (name prop).
4
- * Used by home graph LLM to pick an icon per dynamic section.
5
- */
6
- /** Default icon when LLM returns invalid or missing icon name. */
7
- export declare const DEFAULT_HOME_SECTION_ICON = "hourglass";
8
- /** Allowed icon names for home sections (subset of Lucide icons). */
9
- export declare const HOME_SECTION_ICON_NAMES: readonly string[];
10
- /**
11
- * Normalize icon name: lowercase, strip spaces (allow kebab-case from LLM).
12
- */
13
- export declare function normalizeIconName(name: string | undefined | null): string;
14
- /**
15
- * Validate and return an allowed icon name; fallback to default if unknown.
16
- */
17
- export declare function resolveHomeSectionIcon(name: string | undefined | null): string;
18
- /**
19
- * Return a formatted list of icon names for LLM prompts (comma-separated, truncated if needed).
20
- */
21
- export declare function getIconNamesForPrompt(maxItems?: number): string;
@@ -1,100 +0,0 @@
1
- /**
2
- * Lucide icon catalog for home view section headings.
3
- * Icon names are kebab-case for use with lucide-react DynamicIcon (name prop).
4
- * Used by home graph LLM to pick an icon per dynamic section.
5
- */
6
- /** Default icon when LLM returns invalid or missing icon name. */
7
- export const DEFAULT_HOME_SECTION_ICON = 'hourglass';
8
- /** Allowed icon names for home sections (subset of Lucide icons). */
9
- export const HOME_SECTION_ICON_NAMES = [
10
- 'hourglass',
11
- 'telescope',
12
- 'route',
13
- 'bot',
14
- 'user',
15
- 'users',
16
- 'message-circle',
17
- 'sparkles',
18
- 'handshake',
19
- 'target',
20
- 'zap',
21
- 'lightbulb',
22
- 'compass',
23
- 'globe',
24
- 'heart',
25
- 'star',
26
- 'trending-up',
27
- 'briefcase',
28
- 'rocket',
29
- 'search',
30
- 'filter',
31
- 'list',
32
- 'layout-grid',
33
- 'inbox',
34
- 'send',
35
- 'mail',
36
- 'calendar',
37
- 'clock',
38
- 'timer',
39
- 'flag',
40
- 'bookmark',
41
- 'link',
42
- 'share-2',
43
- 'thumbs-up',
44
- 'award',
45
- 'graduation-cap',
46
- 'building-2',
47
- 'network',
48
- 'git-branch',
49
- 'code',
50
- 'palette',
51
- 'pen-tool',
52
- 'folder',
53
- 'file-text',
54
- 'bar-chart',
55
- 'pie-chart',
56
- 'activity',
57
- 'arrow-right',
58
- 'chevron-right',
59
- 'circle-dot',
60
- 'circle-user',
61
- 'user-plus',
62
- 'user-check',
63
- 'users-round',
64
- 'hand',
65
- 'hand-metal',
66
- 'megaphone',
67
- 'bell',
68
- 'eye',
69
- 'eye-off',
70
- 'lock',
71
- 'unlock',
72
- 'shield',
73
- 'shield-check',
74
- ];
75
- const ALLOWED_SET = new Set(HOME_SECTION_ICON_NAMES);
76
- /**
77
- * Normalize icon name: lowercase, strip spaces (allow kebab-case from LLM).
78
- */
79
- export function normalizeIconName(name) {
80
- if (name == null || typeof name !== 'string')
81
- return DEFAULT_HOME_SECTION_ICON;
82
- const normalized = name.trim().toLowerCase().replace(/\s+/g, '-');
83
- if (!normalized)
84
- return DEFAULT_HOME_SECTION_ICON;
85
- return normalized;
86
- }
87
- /**
88
- * Validate and return an allowed icon name; fallback to default if unknown.
89
- */
90
- export function resolveHomeSectionIcon(name) {
91
- const normalized = normalizeIconName(name);
92
- return ALLOWED_SET.has(normalized) ? normalized : DEFAULT_HOME_SECTION_ICON;
93
- }
94
- /**
95
- * Return a formatted list of icon names for LLM prompts (comma-separated, truncated if needed).
96
- */
97
- export function getIconNamesForPrompt(maxItems = 60) {
98
- const list = HOME_SECTION_ICON_NAMES.slice(0, maxItems);
99
- return list.join(', ');
100
- }