peak6-x-intelligence-plugin 0.1.2 → 0.1.6
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/manifest.js +65 -4
- package/dist/manifest.js.map +2 -2
- package/dist/worker.js +325 -2
- package/dist/worker.js.map +2 -2
- package/package.json +1 -1
package/dist/manifest.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
2
|
var PLUGIN_ID = "peak6-labs.x-intelligence";
|
|
3
|
-
var PLUGIN_VERSION = "0.1.
|
|
3
|
+
var PLUGIN_VERSION = "0.1.6";
|
|
4
4
|
var JOB_KEYS = {
|
|
5
5
|
discoveryRun: "discovery-run",
|
|
6
6
|
authorityDecay: "authority-decay",
|
|
@@ -16,7 +16,10 @@ var TOOL_NAMES = {
|
|
|
16
16
|
analyzeTopic: "analyze-topic",
|
|
17
17
|
getThread: "get-thread",
|
|
18
18
|
promoteHandle: "promote-handle",
|
|
19
|
-
rateTweet: "rate-tweet"
|
|
19
|
+
rateTweet: "rate-tweet",
|
|
20
|
+
searchX: "search-x",
|
|
21
|
+
getTrending: "get-trending",
|
|
22
|
+
getUserTimeline: "get-user-timeline"
|
|
20
23
|
};
|
|
21
24
|
var SLOT_IDS = {
|
|
22
25
|
dashboardWidget: "x-intelligence-dashboard",
|
|
@@ -133,7 +136,8 @@ var DEFAULT_CONFIG = {
|
|
|
133
136
|
noise_floor: 10,
|
|
134
137
|
expert: 50,
|
|
135
138
|
escalation: 100
|
|
136
|
-
}
|
|
139
|
+
},
|
|
140
|
+
alert_agents: []
|
|
137
141
|
};
|
|
138
142
|
|
|
139
143
|
// src/manifest.ts
|
|
@@ -160,7 +164,9 @@ var manifest = {
|
|
|
160
164
|
"metrics.write",
|
|
161
165
|
"instance.settings.register",
|
|
162
166
|
"ui.dashboardWidget.register",
|
|
163
|
-
"ui.page.register"
|
|
167
|
+
"ui.page.register",
|
|
168
|
+
"agents.invoke",
|
|
169
|
+
"agents.read"
|
|
164
170
|
],
|
|
165
171
|
entrypoints: {
|
|
166
172
|
worker: "./dist/worker.js",
|
|
@@ -270,6 +276,20 @@ var manifest = {
|
|
|
270
276
|
escalation: { type: "number", default: 100 }
|
|
271
277
|
},
|
|
272
278
|
default: DEFAULT_CONFIG.engagement_thresholds
|
|
279
|
+
},
|
|
280
|
+
alert_agents: {
|
|
281
|
+
type: "array",
|
|
282
|
+
title: "Alert Agents",
|
|
283
|
+
description: "Agents to invoke on high-engagement tweets and corpus updates. Each entry maps an agent ID to an optional memory file for preference-enriched prompts.",
|
|
284
|
+
items: {
|
|
285
|
+
type: "object",
|
|
286
|
+
properties: {
|
|
287
|
+
agentId: { type: "string", description: "Paperclip agent UUID" },
|
|
288
|
+
memoryFile: { type: ["string", "null"], description: "Path to user memory file for enriched prompts (null for raw alerts)" }
|
|
289
|
+
},
|
|
290
|
+
required: ["agentId"]
|
|
291
|
+
},
|
|
292
|
+
default: DEFAULT_CONFIG.alert_agents
|
|
273
293
|
}
|
|
274
294
|
}
|
|
275
295
|
},
|
|
@@ -419,6 +439,47 @@ var manifest = {
|
|
|
419
439
|
},
|
|
420
440
|
required: ["tweet_id", "rating"]
|
|
421
441
|
}
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: TOOL_NAMES.searchX,
|
|
445
|
+
displayName: "Search X",
|
|
446
|
+
description: "Real-time semantic search on X/Twitter via xAI. Returns scored, enriched tweets without storing to corpus. Works any time \u2014 no pipeline required.",
|
|
447
|
+
parametersSchema: {
|
|
448
|
+
type: "object",
|
|
449
|
+
properties: {
|
|
450
|
+
query: { type: "string", description: "Search query (semantic \u2014 describe what you're looking for)" },
|
|
451
|
+
limit: { type: "number", description: "Max results (default 20)" },
|
|
452
|
+
handles: { type: "array", items: { type: "string" }, description: "Optional: restrict search to these handles only" },
|
|
453
|
+
quick: { type: "boolean", description: "Quick mode: skip enrichment, return xAI synthesis + tweet IDs only (lower cost)" }
|
|
454
|
+
},
|
|
455
|
+
required: ["query"]
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
name: TOOL_NAMES.getTrending,
|
|
460
|
+
displayName: "Get Trending",
|
|
461
|
+
description: "What's trending in PEAK6's configured domains right now. Searches all semantic topics (or a specific pillar) via xAI, enriches and scores results. No pipeline required.",
|
|
462
|
+
parametersSchema: {
|
|
463
|
+
type: "object",
|
|
464
|
+
properties: {
|
|
465
|
+
limit: { type: "number", description: "Max results (default 20)" },
|
|
466
|
+
pillar: { type: "string", description: "Filter to topics matching this pillar/keyword" }
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: TOOL_NAMES.getUserTimeline,
|
|
472
|
+
displayName: "Get User Timeline",
|
|
473
|
+
description: "Fetch a user's recent tweets from X/Twitter. Returns enriched tweet data with metrics.",
|
|
474
|
+
parametersSchema: {
|
|
475
|
+
type: "object",
|
|
476
|
+
properties: {
|
|
477
|
+
handle: { type: "string", description: "X handle (without @)" },
|
|
478
|
+
limit: { type: "number", description: "Max tweets to return (default 20, max 100)" },
|
|
479
|
+
since: { type: "string", description: "Only return tweets after this date (YYYY-MM-DD)" }
|
|
480
|
+
},
|
|
481
|
+
required: ["handle"]
|
|
482
|
+
}
|
|
422
483
|
}
|
|
423
484
|
],
|
|
424
485
|
ui: {
|
package/dist/manifest.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/constants.ts", "../src/manifest.ts"],
|
|
4
|
-
"sourcesContent": ["export const PLUGIN_ID = \"peak6-labs.x-intelligence\";\nexport const PLUGIN_VERSION = \"0.1.2\";\n\nexport const JOB_KEYS = {\n discoveryRun: \"discovery-run\",\n authorityDecay: \"authority-decay\",\n complianceCheck: \"compliance-check\",\n corpusRetention: \"corpus-retention\",\n} as const;\n\nexport const TOOL_NAMES = {\n searchCorpus: \"search-corpus\",\n getToday: \"get-today\",\n getAuthorities: \"get-authorities\",\n suggestHandles: \"suggest-handles\",\n trackHandle: \"track-handle\",\n analyzeTopic: \"analyze-topic\",\n getThread: \"get-thread\",\n promoteHandle: \"promote-handle\",\n rateTweet: \"rate-tweet\",\n} as const;\n\nexport const SLOT_IDS = {\n dashboardWidget: \"x-intelligence-dashboard\",\n settingsPage: \"x-intelligence-settings\",\n corpusBrowser: \"x-intelligence-corpus-browser\",\n} as const;\n\nexport const EXPORT_NAMES = {\n dashboardWidget: \"DashboardWidget\",\n settingsPage: \"SettingsPage\",\n corpusBrowser: \"CorpusBrowserPage\",\n} as const;\n\nexport const ENTITY_TYPES = {\n tweet: \"tweet\",\n handle: \"handle\",\n} as const;\n\nexport const STATE_KEYS = {\n corpusPrefix: \"corpus:\",\n lastDiscoveryRun: \"last-discovery-run\",\n pipelineStats: \"pipeline-stats\",\n} as const;\n\nexport const EVENT_NAMES = {\n corpusUpdated: \"corpus.updated\",\n handlePromoted: \"handle.promoted\",\n gapIdentified: \"gap.identified\",\n tweetHighEngagement: \"tweet.high-engagement\",\n} as const;\n\nexport const DEFAULT_CONFIG = {\n company_id: \"\",\n xai_api_key_ref: \"XAI_API_KEY\",\n x_api_bearer_ref: \"BEARER_TOKEN\",\n semantic_topics: [\n \"institutional investors discussing market structure reform\",\n \"fintech companies disrupting traditional trading\",\n \"SEC regulatory changes affecting options trading\",\n \"algorithmic trading and quantitative strategies\",\n \"venture capital investing in financial infrastructure\",\n \"PEAK6\",\n \"options market making technology\",\n \"Chicago trading community news\",\n ],\n keyword_searches: [\n \"\\\"PEAK6 Investments\\\" OR \\\"PEAK6\\\" trading fintech\",\n \"fintech and trading technology\",\n \"market structure and regulation\",\n \"options trading strategies and platforms\",\n ],\n content_pillars: [\n \"market structure & regulation\",\n \"fintech & trading technology\",\n \"venture capital & investment\",\n \"Chicago business ecosystem\",\n \"company culture & talent\",\n ],\n scoring_weights: {\n relevance: 0.45,\n recency: 0.25,\n engagement: 0.30,\n },\n engagement_sub_weights: {\n likes: 0.55,\n reposts: 0.25,\n replies: 0.15,\n quotes: 0.05,\n },\n max_corpus_size: 200,\n dedup_threshold: 0.70,\n authority_boost: 0.15,\n authority_lists: {\n market_structure: {\n description: \"Market structure, regulation, SEC reform, options trading\",\n handles: [\n \"LizAnnSonders\",\n \"matt_levine\",\n \"unusual_whales\",\n \"CMEGroup\",\n \"CBOE\",\n \"OptionsHawk\",\n \"InvestorDenis\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n fintech: {\n description: \"Fintech, trading technology, AI in finance\",\n handles: [\n \"twifintech\",\n \"IBSIntelligence\",\n \"privy_io\",\n \"i_Know_First\",\n \"fintech_germany\",\n \"venture_radar\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n venture_capital: {\n description: \"Venture capital investing in financial infrastructure\",\n handles: [\n \"a16z\",\n \"FundersVC\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n chicago_trading: {\n description: \"Chicago trading community, prop firms, PEAK6 ecosystem\",\n handles: [\n \"CBOE\",\n \"CMEGroup\",\n \"boogeymantradez\",\n \"adealafia\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n } as Record<string, AuthorityList>,\n global_excluded: [\"elonmusk\", \"openai\", \"google\", \"microsoft\"],\n authority_promotion_policy: {\n auto_promote_threshold: {\n min_appearances: 7,\n min_avg_relevance: 0.8,\n min_mutual_overlap: 3,\n },\n candidate_threshold: {\n min_appearances: 5,\n min_avg_relevance: 0.7,\n min_mutual_overlap: 2,\n },\n tracking_window_days: 14,\n },\n corpus_retention_days: 90,\n engagement_thresholds: {\n noise_floor: 10,\n expert: 50,\n escalation: 100,\n },\n} as const;\n\nexport interface AuthorityList {\n description: string;\n handles: string[];\n last_reviewed: string;\n}\n", "import type { PaperclipPluginManifestV1 } from \"@paperclipai/plugin-sdk\";\nimport {\n DEFAULT_CONFIG,\n EXPORT_NAMES,\n JOB_KEYS,\n PLUGIN_ID,\n PLUGIN_VERSION,\n SLOT_IDS,\n TOOL_NAMES,\n} from \"./constants.js\";\n\nconst manifest: PaperclipPluginManifestV1 = {\n id: PLUGIN_ID,\n apiVersion: 1,\n version: PLUGIN_VERSION,\n displayName: \"X Intelligence\",\n description:\n \"Automated X/Twitter intelligence pipeline \u2014 discovery, enrichment, scoring, deduplication, authority list management, and corpus storage.\",\n author: \"peak6-labs\",\n categories: [\"connector\", \"automation\"],\n capabilities: [\n \"http.outbound\",\n \"secrets.read-ref\",\n \"jobs.schedule\",\n \"agent.tools.register\",\n \"plugin.state.read\",\n \"plugin.state.write\",\n \"events.subscribe\",\n \"events.emit\",\n \"issues.read\",\n \"issues.create\",\n \"activity.log.write\",\n \"metrics.write\",\n \"instance.settings.register\",\n \"ui.dashboardWidget.register\",\n \"ui.page.register\",\n ],\n entrypoints: {\n worker: \"./dist/worker.js\",\n ui: \"./dist/ui\",\n },\n instanceConfigSchema: {\n type: \"object\",\n properties: {\n company_id: {\n type: \"string\",\n title: \"Company ID\",\n description: \"UUID of the company this plugin serves (required for events and activity logging)\",\n default: DEFAULT_CONFIG.company_id,\n },\n xai_api_key_ref: {\n type: \"string\",\n title: \"xAI API Key Secret Reference\",\n default: DEFAULT_CONFIG.xai_api_key_ref,\n },\n x_api_bearer_ref: {\n type: \"string\",\n title: \"X API Bearer Token Secret Reference\",\n default: DEFAULT_CONFIG.x_api_bearer_ref,\n },\n semantic_topics: {\n type: \"array\",\n title: \"Semantic Discovery Topics\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.semantic_topics,\n },\n keyword_searches: {\n type: \"array\",\n title: \"Keyword Searches\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.keyword_searches,\n },\n content_pillars: {\n type: \"array\",\n title: \"Content Pillars\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.content_pillars,\n },\n scoring_weights: {\n type: \"object\",\n title: \"Scoring Weights\",\n properties: {\n relevance: { type: \"number\", default: 0.45 },\n recency: { type: \"number\", default: 0.25 },\n engagement: { type: \"number\", default: 0.30 },\n },\n default: DEFAULT_CONFIG.scoring_weights,\n },\n engagement_sub_weights: {\n type: \"object\",\n title: \"Engagement Sub-Weights\",\n properties: {\n likes: { type: \"number\", default: 0.55 },\n reposts: { type: \"number\", default: 0.25 },\n replies: { type: \"number\", default: 0.15 },\n quotes: { type: \"number\", default: 0.05 },\n },\n default: DEFAULT_CONFIG.engagement_sub_weights,\n },\n max_corpus_size: {\n type: \"number\",\n title: \"Max Corpus Size Per Day\",\n default: DEFAULT_CONFIG.max_corpus_size,\n },\n dedup_threshold: {\n type: \"number\",\n title: \"Dedup Jaccard Threshold\",\n default: DEFAULT_CONFIG.dedup_threshold,\n },\n authority_boost: {\n type: \"number\",\n title: \"Authority Score Boost\",\n default: DEFAULT_CONFIG.authority_boost,\n },\n authority_lists: {\n type: \"object\",\n title: \"Authority Handle Lists\",\n default: DEFAULT_CONFIG.authority_lists,\n },\n global_excluded: {\n type: \"array\",\n title: \"Globally Excluded Handles\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.global_excluded,\n },\n authority_promotion_policy: {\n type: \"object\",\n title: \"Authority Promotion Policy\",\n default: DEFAULT_CONFIG.authority_promotion_policy,\n },\n corpus_retention_days: {\n type: \"number\",\n title: \"Corpus Retention (days)\",\n default: DEFAULT_CONFIG.corpus_retention_days,\n },\n engagement_thresholds: {\n type: \"object\",\n title: \"Engagement Thresholds\",\n description: \"Engagement level tiers: noise_floor (filter), expert (highlight), escalation (alert event)\",\n properties: {\n noise_floor: { type: \"number\", default: 10 },\n expert: { type: \"number\", default: 50 },\n escalation: { type: \"number\", default: 100 },\n },\n default: DEFAULT_CONFIG.engagement_thresholds,\n },\n },\n },\n jobs: [\n {\n jobKey: JOB_KEYS.discoveryRun,\n displayName: \"Discovery Run\",\n description:\n \"Two-stage pipeline: xAI open + focused discovery, X API v2 enrichment, scoring, and corpus storage.\",\n schedule: \"0 6 * * *\",\n },\n {\n jobKey: JOB_KEYS.authorityDecay,\n displayName: \"Authority Decay\",\n description:\n \"Weekly handle decay \u2014 downgrade or remove handles not seen within the tracking window.\",\n schedule: \"0 0 * * 0\",\n },\n {\n jobKey: JOB_KEYS.complianceCheck,\n displayName: \"Compliance Check\",\n description:\n \"Weekly re-check of stored tweets \u2014 remove deleted or suspended content.\",\n schedule: \"0 3 * * 0\",\n },\n {\n jobKey: JOB_KEYS.corpusRetention,\n displayName: \"Corpus Retention\",\n description:\n \"Monthly archive/delete corpus older than the retention window.\",\n schedule: \"0 4 1 * *\",\n },\n ],\n tools: [\n {\n name: TOOL_NAMES.searchCorpus,\n displayName: \"Search X Corpus\",\n description:\n \"Search the scored X intelligence corpus by query text, date range, content pillar, score threshold, and engagement level.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Search query (text match)\" },\n date: { type: \"string\", description: \"Date filter (YYYY-MM-DD)\" },\n pillar: { type: \"string\", description: \"Content pillar filter\" },\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n min_score: { type: \"number\", description: \"Minimum score threshold (0-1)\" },\n min_engagement: { type: \"number\", description: \"Minimum total engagement (likes+reposts+replies+quotes)\" },\n since: { type: \"string\", description: \"Time window: '1h', '3h', '12h', '1d', '7d', or YYYY-MM-DD\" },\n },\n },\n },\n {\n name: TOOL_NAMES.getToday,\n displayName: \"Get Today's Intelligence\",\n description:\n \"Get today's scored X intelligence corpus from entities, optionally filtered by pillar and score threshold.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n pillar: { type: \"string\", description: \"Content pillar filter\" },\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n min_score: { type: \"number\", description: \"Minimum score threshold (0-1)\" },\n },\n },\n },\n {\n name: TOOL_NAMES.getAuthorities,\n displayName: \"Get Authority Handles\",\n description:\n \"Get the authority handle list for a domain, or all domains if none specified.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n list_name: {\n type: \"string\",\n description: \"Domain name (e.g. 'market_structure')\",\n },\n },\n },\n },\n {\n name: TOOL_NAMES.suggestHandles,\n displayName: \"Suggest Handle Promotions\",\n description:\n \"Get handles that are candidates for authority list promotion based on tracking data.\",\n parametersSchema: {\n type: \"object\",\n properties: {},\n },\n },\n {\n name: TOOL_NAMES.trackHandle,\n displayName: \"Track Handle\",\n description:\n \"Record a handle appearance from agent discovery with relevance score and domain.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n handle: { type: \"string\", description: \"X handle (without @)\" },\n relevance: { type: \"number\", description: \"Relevance score (0-1)\" },\n domain: { type: \"string\", description: \"Domain/topic area\" },\n },\n required: [\"handle\", \"relevance\", \"domain\"],\n },\n },\n {\n name: TOOL_NAMES.analyzeTopic,\n displayName: \"Analyze Topic\",\n description:\n \"On-demand xAI search for any topic with 5-perspective decomposition (core, expert voices, pain points, positive signals, link-based) and corpus cross-reference. Returns a synthesis brief.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n topic: { type: \"string\", description: \"Topic to analyze\" },\n include_corpus: { type: \"boolean\", description: \"Cross-reference with stored corpus (default true)\" },\n },\n required: [\"topic\"],\n },\n },\n {\n name: TOOL_NAMES.getThread,\n displayName: \"Get Tweet Thread\",\n description:\n \"Fetch conversation context for a tweet. Returns the target tweet and other tweets in the same conversation thread.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n tweet_id: { type: \"string\", description: \"Tweet ID to get thread for\" },\n },\n required: [\"tweet_id\"],\n },\n },\n {\n name: TOOL_NAMES.promoteHandle,\n displayName: \"Promote Handle\",\n description:\n \"Promote a tracked handle to authority status in a specific domain list. Sets entity status to promoted and records the target list.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n handle: { type: \"string\", description: \"X handle (without @)\" },\n list_name: { type: \"string\", description: \"Authority list to promote to (e.g. 'market_structure')\" },\n note: { type: \"string\", description: \"Optional note about why this handle was promoted\" },\n },\n required: [\"handle\", \"list_name\"],\n },\n },\n {\n name: TOOL_NAMES.rateTweet,\n displayName: \"Rate Tweet\",\n description:\n \"Record relevance feedback on a tweet in the corpus. Agents or humans can rate tweets as relevant, irrelevant, or skip.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n tweet_id: { type: \"string\", description: \"Tweet ID to rate\" },\n rating: { type: \"string\", enum: [\"relevant\", \"irrelevant\", \"skip\"], description: \"Relevance rating\" },\n rated_by: { type: \"string\", description: \"ID of the rater (agent or user)\" },\n },\n required: [\"tweet_id\", \"rating\"],\n },\n },\n ],\n ui: {\n slots: [\n {\n type: \"dashboardWidget\",\n id: SLOT_IDS.dashboardWidget,\n displayName: \"X Intelligence\",\n exportName: EXPORT_NAMES.dashboardWidget,\n },\n {\n type: \"settingsPage\",\n id: SLOT_IDS.settingsPage,\n displayName: \"X Intelligence Settings\",\n exportName: EXPORT_NAMES.settingsPage,\n },\n {\n type: \"page\",\n id: SLOT_IDS.corpusBrowser,\n displayName: \"X Intelligence Corpus\",\n exportName: EXPORT_NAMES.corpusBrowser,\n routePath: \"x-intelligence\",\n },\n ],\n },\n};\n\nexport default manifest;\n"],
|
|
5
|
-
"mappings": ";AAAO,IAAM,YAAY;AAClB,IAAM,iBAAiB;AAEvB,IAAM,WAAW;AAAA,EACtB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;AAEO,IAAM,aAAa;AAAA,EACxB,cAAc;AAAA,EACd,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX,eAAe;AAAA,EACf,WAAW;
|
|
4
|
+
"sourcesContent": ["export const PLUGIN_ID = \"peak6-labs.x-intelligence\";\nexport const PLUGIN_VERSION = \"0.1.6\";\n\nexport const JOB_KEYS = {\n discoveryRun: \"discovery-run\",\n authorityDecay: \"authority-decay\",\n complianceCheck: \"compliance-check\",\n corpusRetention: \"corpus-retention\",\n} as const;\n\nexport const TOOL_NAMES = {\n searchCorpus: \"search-corpus\",\n getToday: \"get-today\",\n getAuthorities: \"get-authorities\",\n suggestHandles: \"suggest-handles\",\n trackHandle: \"track-handle\",\n analyzeTopic: \"analyze-topic\",\n getThread: \"get-thread\",\n promoteHandle: \"promote-handle\",\n rateTweet: \"rate-tweet\",\n searchX: \"search-x\",\n getTrending: \"get-trending\",\n getUserTimeline: \"get-user-timeline\",\n} as const;\n\nexport const SLOT_IDS = {\n dashboardWidget: \"x-intelligence-dashboard\",\n settingsPage: \"x-intelligence-settings\",\n corpusBrowser: \"x-intelligence-corpus-browser\",\n} as const;\n\nexport const EXPORT_NAMES = {\n dashboardWidget: \"DashboardWidget\",\n settingsPage: \"SettingsPage\",\n corpusBrowser: \"CorpusBrowserPage\",\n} as const;\n\nexport const ENTITY_TYPES = {\n tweet: \"tweet\",\n handle: \"handle\",\n} as const;\n\nexport const STATE_KEYS = {\n corpusPrefix: \"corpus:\",\n lastDiscoveryRun: \"last-discovery-run\",\n pipelineStats: \"pipeline-stats\",\n} as const;\n\nexport const EVENT_NAMES = {\n corpusUpdated: \"corpus.updated\",\n handlePromoted: \"handle.promoted\",\n gapIdentified: \"gap.identified\",\n tweetHighEngagement: \"tweet.high-engagement\",\n} as const;\n\nexport const DEFAULT_CONFIG = {\n company_id: \"\",\n xai_api_key_ref: \"XAI_API_KEY\",\n x_api_bearer_ref: \"BEARER_TOKEN\",\n semantic_topics: [\n \"institutional investors discussing market structure reform\",\n \"fintech companies disrupting traditional trading\",\n \"SEC regulatory changes affecting options trading\",\n \"algorithmic trading and quantitative strategies\",\n \"venture capital investing in financial infrastructure\",\n \"PEAK6\",\n \"options market making technology\",\n \"Chicago trading community news\",\n ],\n keyword_searches: [\n \"\\\"PEAK6 Investments\\\" OR \\\"PEAK6\\\" trading fintech\",\n \"fintech and trading technology\",\n \"market structure and regulation\",\n \"options trading strategies and platforms\",\n ],\n content_pillars: [\n \"market structure & regulation\",\n \"fintech & trading technology\",\n \"venture capital & investment\",\n \"Chicago business ecosystem\",\n \"company culture & talent\",\n ],\n scoring_weights: {\n relevance: 0.45,\n recency: 0.25,\n engagement: 0.30,\n },\n engagement_sub_weights: {\n likes: 0.55,\n reposts: 0.25,\n replies: 0.15,\n quotes: 0.05,\n },\n max_corpus_size: 200,\n dedup_threshold: 0.70,\n authority_boost: 0.15,\n authority_lists: {\n market_structure: {\n description: \"Market structure, regulation, SEC reform, options trading\",\n handles: [\n \"LizAnnSonders\",\n \"matt_levine\",\n \"unusual_whales\",\n \"CMEGroup\",\n \"CBOE\",\n \"OptionsHawk\",\n \"InvestorDenis\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n fintech: {\n description: \"Fintech, trading technology, AI in finance\",\n handles: [\n \"twifintech\",\n \"IBSIntelligence\",\n \"privy_io\",\n \"i_Know_First\",\n \"fintech_germany\",\n \"venture_radar\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n venture_capital: {\n description: \"Venture capital investing in financial infrastructure\",\n handles: [\n \"a16z\",\n \"FundersVC\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n chicago_trading: {\n description: \"Chicago trading community, prop firms, PEAK6 ecosystem\",\n handles: [\n \"CBOE\",\n \"CMEGroup\",\n \"boogeymantradez\",\n \"adealafia\",\n ],\n last_reviewed: \"2026-03-29\",\n },\n } as Record<string, AuthorityList>,\n global_excluded: [\"elonmusk\", \"openai\", \"google\", \"microsoft\"],\n authority_promotion_policy: {\n auto_promote_threshold: {\n min_appearances: 7,\n min_avg_relevance: 0.8,\n min_mutual_overlap: 3,\n },\n candidate_threshold: {\n min_appearances: 5,\n min_avg_relevance: 0.7,\n min_mutual_overlap: 2,\n },\n tracking_window_days: 14,\n },\n corpus_retention_days: 90,\n engagement_thresholds: {\n noise_floor: 10,\n expert: 50,\n escalation: 100,\n },\n alert_agents: [] as Array<{ agentId: string; memoryFile: string | null }>,\n} as const;\n\nexport interface AuthorityList {\n description: string;\n handles: string[];\n last_reviewed: string;\n}\n", "import type { PaperclipPluginManifestV1 } from \"@paperclipai/plugin-sdk\";\nimport {\n DEFAULT_CONFIG,\n EXPORT_NAMES,\n JOB_KEYS,\n PLUGIN_ID,\n PLUGIN_VERSION,\n SLOT_IDS,\n TOOL_NAMES,\n} from \"./constants.js\";\n\nconst manifest: PaperclipPluginManifestV1 = {\n id: PLUGIN_ID,\n apiVersion: 1,\n version: PLUGIN_VERSION,\n displayName: \"X Intelligence\",\n description:\n \"Automated X/Twitter intelligence pipeline \u2014 discovery, enrichment, scoring, deduplication, authority list management, and corpus storage.\",\n author: \"peak6-labs\",\n categories: [\"connector\", \"automation\"],\n capabilities: [\n \"http.outbound\",\n \"secrets.read-ref\",\n \"jobs.schedule\",\n \"agent.tools.register\",\n \"plugin.state.read\",\n \"plugin.state.write\",\n \"events.subscribe\",\n \"events.emit\",\n \"issues.read\",\n \"issues.create\",\n \"activity.log.write\",\n \"metrics.write\",\n \"instance.settings.register\",\n \"ui.dashboardWidget.register\",\n \"ui.page.register\",\n \"agents.invoke\",\n \"agents.read\",\n ],\n entrypoints: {\n worker: \"./dist/worker.js\",\n ui: \"./dist/ui\",\n },\n instanceConfigSchema: {\n type: \"object\",\n properties: {\n company_id: {\n type: \"string\",\n title: \"Company ID\",\n description: \"UUID of the company this plugin serves (required for events and activity logging)\",\n default: DEFAULT_CONFIG.company_id,\n },\n xai_api_key_ref: {\n type: \"string\",\n title: \"xAI API Key Secret Reference\",\n default: DEFAULT_CONFIG.xai_api_key_ref,\n },\n x_api_bearer_ref: {\n type: \"string\",\n title: \"X API Bearer Token Secret Reference\",\n default: DEFAULT_CONFIG.x_api_bearer_ref,\n },\n semantic_topics: {\n type: \"array\",\n title: \"Semantic Discovery Topics\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.semantic_topics,\n },\n keyword_searches: {\n type: \"array\",\n title: \"Keyword Searches\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.keyword_searches,\n },\n content_pillars: {\n type: \"array\",\n title: \"Content Pillars\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.content_pillars,\n },\n scoring_weights: {\n type: \"object\",\n title: \"Scoring Weights\",\n properties: {\n relevance: { type: \"number\", default: 0.45 },\n recency: { type: \"number\", default: 0.25 },\n engagement: { type: \"number\", default: 0.30 },\n },\n default: DEFAULT_CONFIG.scoring_weights,\n },\n engagement_sub_weights: {\n type: \"object\",\n title: \"Engagement Sub-Weights\",\n properties: {\n likes: { type: \"number\", default: 0.55 },\n reposts: { type: \"number\", default: 0.25 },\n replies: { type: \"number\", default: 0.15 },\n quotes: { type: \"number\", default: 0.05 },\n },\n default: DEFAULT_CONFIG.engagement_sub_weights,\n },\n max_corpus_size: {\n type: \"number\",\n title: \"Max Corpus Size Per Day\",\n default: DEFAULT_CONFIG.max_corpus_size,\n },\n dedup_threshold: {\n type: \"number\",\n title: \"Dedup Jaccard Threshold\",\n default: DEFAULT_CONFIG.dedup_threshold,\n },\n authority_boost: {\n type: \"number\",\n title: \"Authority Score Boost\",\n default: DEFAULT_CONFIG.authority_boost,\n },\n authority_lists: {\n type: \"object\",\n title: \"Authority Handle Lists\",\n default: DEFAULT_CONFIG.authority_lists,\n },\n global_excluded: {\n type: \"array\",\n title: \"Globally Excluded Handles\",\n items: { type: \"string\" },\n default: DEFAULT_CONFIG.global_excluded,\n },\n authority_promotion_policy: {\n type: \"object\",\n title: \"Authority Promotion Policy\",\n default: DEFAULT_CONFIG.authority_promotion_policy,\n },\n corpus_retention_days: {\n type: \"number\",\n title: \"Corpus Retention (days)\",\n default: DEFAULT_CONFIG.corpus_retention_days,\n },\n engagement_thresholds: {\n type: \"object\",\n title: \"Engagement Thresholds\",\n description: \"Engagement level tiers: noise_floor (filter), expert (highlight), escalation (alert event)\",\n properties: {\n noise_floor: { type: \"number\", default: 10 },\n expert: { type: \"number\", default: 50 },\n escalation: { type: \"number\", default: 100 },\n },\n default: DEFAULT_CONFIG.engagement_thresholds,\n },\n alert_agents: {\n type: \"array\",\n title: \"Alert Agents\",\n description: \"Agents to invoke on high-engagement tweets and corpus updates. Each entry maps an agent ID to an optional memory file for preference-enriched prompts.\",\n items: {\n type: \"object\",\n properties: {\n agentId: { type: \"string\", description: \"Paperclip agent UUID\" },\n memoryFile: { type: [\"string\", \"null\"], description: \"Path to user memory file for enriched prompts (null for raw alerts)\" },\n },\n required: [\"agentId\"],\n },\n default: DEFAULT_CONFIG.alert_agents,\n },\n },\n },\n jobs: [\n {\n jobKey: JOB_KEYS.discoveryRun,\n displayName: \"Discovery Run\",\n description:\n \"Two-stage pipeline: xAI open + focused discovery, X API v2 enrichment, scoring, and corpus storage.\",\n schedule: \"0 6 * * *\",\n },\n {\n jobKey: JOB_KEYS.authorityDecay,\n displayName: \"Authority Decay\",\n description:\n \"Weekly handle decay \u2014 downgrade or remove handles not seen within the tracking window.\",\n schedule: \"0 0 * * 0\",\n },\n {\n jobKey: JOB_KEYS.complianceCheck,\n displayName: \"Compliance Check\",\n description:\n \"Weekly re-check of stored tweets \u2014 remove deleted or suspended content.\",\n schedule: \"0 3 * * 0\",\n },\n {\n jobKey: JOB_KEYS.corpusRetention,\n displayName: \"Corpus Retention\",\n description:\n \"Monthly archive/delete corpus older than the retention window.\",\n schedule: \"0 4 1 * *\",\n },\n ],\n tools: [\n {\n name: TOOL_NAMES.searchCorpus,\n displayName: \"Search X Corpus\",\n description:\n \"Search the scored X intelligence corpus by query text, date range, content pillar, score threshold, and engagement level.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Search query (text match)\" },\n date: { type: \"string\", description: \"Date filter (YYYY-MM-DD)\" },\n pillar: { type: \"string\", description: \"Content pillar filter\" },\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n min_score: { type: \"number\", description: \"Minimum score threshold (0-1)\" },\n min_engagement: { type: \"number\", description: \"Minimum total engagement (likes+reposts+replies+quotes)\" },\n since: { type: \"string\", description: \"Time window: '1h', '3h', '12h', '1d', '7d', or YYYY-MM-DD\" },\n },\n },\n },\n {\n name: TOOL_NAMES.getToday,\n displayName: \"Get Today's Intelligence\",\n description:\n \"Get today's scored X intelligence corpus from entities, optionally filtered by pillar and score threshold.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n pillar: { type: \"string\", description: \"Content pillar filter\" },\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n min_score: { type: \"number\", description: \"Minimum score threshold (0-1)\" },\n },\n },\n },\n {\n name: TOOL_NAMES.getAuthorities,\n displayName: \"Get Authority Handles\",\n description:\n \"Get the authority handle list for a domain, or all domains if none specified.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n list_name: {\n type: \"string\",\n description: \"Domain name (e.g. 'market_structure')\",\n },\n },\n },\n },\n {\n name: TOOL_NAMES.suggestHandles,\n displayName: \"Suggest Handle Promotions\",\n description:\n \"Get handles that are candidates for authority list promotion based on tracking data.\",\n parametersSchema: {\n type: \"object\",\n properties: {},\n },\n },\n {\n name: TOOL_NAMES.trackHandle,\n displayName: \"Track Handle\",\n description:\n \"Record a handle appearance from agent discovery with relevance score and domain.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n handle: { type: \"string\", description: \"X handle (without @)\" },\n relevance: { type: \"number\", description: \"Relevance score (0-1)\" },\n domain: { type: \"string\", description: \"Domain/topic area\" },\n },\n required: [\"handle\", \"relevance\", \"domain\"],\n },\n },\n {\n name: TOOL_NAMES.analyzeTopic,\n displayName: \"Analyze Topic\",\n description:\n \"On-demand xAI search for any topic with 5-perspective decomposition (core, expert voices, pain points, positive signals, link-based) and corpus cross-reference. Returns a synthesis brief.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n topic: { type: \"string\", description: \"Topic to analyze\" },\n include_corpus: { type: \"boolean\", description: \"Cross-reference with stored corpus (default true)\" },\n },\n required: [\"topic\"],\n },\n },\n {\n name: TOOL_NAMES.getThread,\n displayName: \"Get Tweet Thread\",\n description:\n \"Fetch conversation context for a tweet. Returns the target tweet and other tweets in the same conversation thread.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n tweet_id: { type: \"string\", description: \"Tweet ID to get thread for\" },\n },\n required: [\"tweet_id\"],\n },\n },\n {\n name: TOOL_NAMES.promoteHandle,\n displayName: \"Promote Handle\",\n description:\n \"Promote a tracked handle to authority status in a specific domain list. Sets entity status to promoted and records the target list.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n handle: { type: \"string\", description: \"X handle (without @)\" },\n list_name: { type: \"string\", description: \"Authority list to promote to (e.g. 'market_structure')\" },\n note: { type: \"string\", description: \"Optional note about why this handle was promoted\" },\n },\n required: [\"handle\", \"list_name\"],\n },\n },\n {\n name: TOOL_NAMES.rateTweet,\n displayName: \"Rate Tweet\",\n description:\n \"Record relevance feedback on a tweet in the corpus. Agents or humans can rate tweets as relevant, irrelevant, or skip.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n tweet_id: { type: \"string\", description: \"Tweet ID to rate\" },\n rating: { type: \"string\", enum: [\"relevant\", \"irrelevant\", \"skip\"], description: \"Relevance rating\" },\n rated_by: { type: \"string\", description: \"ID of the rater (agent or user)\" },\n },\n required: [\"tweet_id\", \"rating\"],\n },\n },\n {\n name: TOOL_NAMES.searchX,\n displayName: \"Search X\",\n description:\n \"Real-time semantic search on X/Twitter via xAI. Returns scored, enriched tweets without storing to corpus. Works any time \u2014 no pipeline required.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Search query (semantic \u2014 describe what you're looking for)\" },\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n handles: { type: \"array\", items: { type: \"string\" }, description: \"Optional: restrict search to these handles only\" },\n quick: { type: \"boolean\", description: \"Quick mode: skip enrichment, return xAI synthesis + tweet IDs only (lower cost)\" },\n },\n required: [\"query\"],\n },\n },\n {\n name: TOOL_NAMES.getTrending,\n displayName: \"Get Trending\",\n description:\n \"What's trending in PEAK6's configured domains right now. Searches all semantic topics (or a specific pillar) via xAI, enriches and scores results. No pipeline required.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n pillar: { type: \"string\", description: \"Filter to topics matching this pillar/keyword\" },\n },\n },\n },\n {\n name: TOOL_NAMES.getUserTimeline,\n displayName: \"Get User Timeline\",\n description:\n \"Fetch a user's recent tweets from X/Twitter. Returns enriched tweet data with metrics.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n handle: { type: \"string\", description: \"X handle (without @)\" },\n limit: { type: \"number\", description: \"Max tweets to return (default 20, max 100)\" },\n since: { type: \"string\", description: \"Only return tweets after this date (YYYY-MM-DD)\" },\n },\n required: [\"handle\"],\n },\n },\n ],\n ui: {\n slots: [\n {\n type: \"dashboardWidget\",\n id: SLOT_IDS.dashboardWidget,\n displayName: \"X Intelligence\",\n exportName: EXPORT_NAMES.dashboardWidget,\n },\n {\n type: \"settingsPage\",\n id: SLOT_IDS.settingsPage,\n displayName: \"X Intelligence Settings\",\n exportName: EXPORT_NAMES.settingsPage,\n },\n {\n type: \"page\",\n id: SLOT_IDS.corpusBrowser,\n displayName: \"X Intelligence Corpus\",\n exportName: EXPORT_NAMES.corpusBrowser,\n routePath: \"x-intelligence\",\n },\n ],\n },\n};\n\nexport default manifest;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/worker.js
CHANGED
|
@@ -905,7 +905,10 @@ var TOOL_NAMES = {
|
|
|
905
905
|
analyzeTopic: "analyze-topic",
|
|
906
906
|
getThread: "get-thread",
|
|
907
907
|
promoteHandle: "promote-handle",
|
|
908
|
-
rateTweet: "rate-tweet"
|
|
908
|
+
rateTweet: "rate-tweet",
|
|
909
|
+
searchX: "search-x",
|
|
910
|
+
getTrending: "get-trending",
|
|
911
|
+
getUserTimeline: "get-user-timeline"
|
|
909
912
|
};
|
|
910
913
|
var ENTITY_TYPES = {
|
|
911
914
|
tweet: "tweet",
|
|
@@ -1027,7 +1030,8 @@ var DEFAULT_CONFIG = {
|
|
|
1027
1030
|
noise_floor: 10,
|
|
1028
1031
|
expert: 50,
|
|
1029
1032
|
escalation: 100
|
|
1030
|
-
}
|
|
1033
|
+
},
|
|
1034
|
+
alert_agents: []
|
|
1031
1035
|
};
|
|
1032
1036
|
|
|
1033
1037
|
// src/pipeline/xai-client.ts
|
|
@@ -1244,6 +1248,48 @@ async function fetchConversationTweets(http, secrets, logger, bearerRef, convers
|
|
|
1244
1248
|
logger.debug("Conversation tweets fetched", { conversationId, count: tweets.length });
|
|
1245
1249
|
return tweets;
|
|
1246
1250
|
}
|
|
1251
|
+
async function fetchUserTimeline(http, secrets, logger, bearerRef, username, limit, sinceDate) {
|
|
1252
|
+
const bearerToken = await secrets.resolve(bearerRef);
|
|
1253
|
+
const userUrl = `${X_API_BASE}/users/by/username/${encodeURIComponent(username)}?user.fields=${USER_FIELDS}`;
|
|
1254
|
+
const userResponse = await http.fetch(userUrl, {
|
|
1255
|
+
method: "GET",
|
|
1256
|
+
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
1257
|
+
});
|
|
1258
|
+
if (!userResponse.ok) {
|
|
1259
|
+
const errorText = await userResponse.text();
|
|
1260
|
+
throw new Error(`X API user lookup failed for @${username}: ${userResponse.status} ${errorText}`);
|
|
1261
|
+
}
|
|
1262
|
+
const userData = await userResponse.json();
|
|
1263
|
+
if (!userData.data) {
|
|
1264
|
+
throw new Error(`User @${username} not found`);
|
|
1265
|
+
}
|
|
1266
|
+
const userId = userData.data.id;
|
|
1267
|
+
const user = userData.data;
|
|
1268
|
+
const apiLimit = Math.min(Math.max(limit, 5), 100);
|
|
1269
|
+
let timelineUrl = `${X_API_BASE}/users/${userId}/tweets?tweet.fields=${TWEET_FIELDS}&max_results=${apiLimit}`;
|
|
1270
|
+
if (sinceDate) {
|
|
1271
|
+
timelineUrl += `&start_time=${sinceDate}T00:00:00Z`;
|
|
1272
|
+
}
|
|
1273
|
+
logger.debug("Fetching user timeline", { username, userId, limit: apiLimit });
|
|
1274
|
+
const timelineResponse = await http.fetch(timelineUrl, {
|
|
1275
|
+
method: "GET",
|
|
1276
|
+
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
1277
|
+
});
|
|
1278
|
+
if (!timelineResponse.ok) {
|
|
1279
|
+
const errorText = await timelineResponse.text();
|
|
1280
|
+
throw new Error(`X API timeline fetch failed for @${username}: ${timelineResponse.status} ${errorText}`);
|
|
1281
|
+
}
|
|
1282
|
+
const timelineData = await timelineResponse.json();
|
|
1283
|
+
const tweets = [];
|
|
1284
|
+
if (timelineData.data) {
|
|
1285
|
+
for (const tweet of timelineData.data) {
|
|
1286
|
+
tweets.push(mapToEnrichedTweet(tweet, user, "open_discovery"));
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
const trimmed = tweets.slice(0, limit);
|
|
1290
|
+
logger.debug("User timeline fetched", { username, count: trimmed.length });
|
|
1291
|
+
return trimmed;
|
|
1292
|
+
}
|
|
1247
1293
|
|
|
1248
1294
|
// src/pipeline/scoring.ts
|
|
1249
1295
|
function trigrams(text) {
|
|
@@ -1829,6 +1875,7 @@ async function runDiscoveryPipeline(ctx, job) {
|
|
|
1829
1875
|
finalCorpus: corpus.length
|
|
1830
1876
|
});
|
|
1831
1877
|
const engagementThresholds = config.engagement_thresholds ?? DEFAULT_CONFIG.engagement_thresholds;
|
|
1878
|
+
const highEngagementTweets = [];
|
|
1832
1879
|
for (const tweet of corpus) {
|
|
1833
1880
|
const totalEngagement = computeTotalEngagement(tweet.metrics);
|
|
1834
1881
|
if (totalEngagement >= engagementThresholds.escalation) {
|
|
@@ -1844,6 +1891,7 @@ async function runDiscoveryPipeline(ctx, job) {
|
|
|
1844
1891
|
threshold_crossed: "escalation"
|
|
1845
1892
|
});
|
|
1846
1893
|
await ctx.metrics.write("pipeline.tweet.high_engagement", 1);
|
|
1894
|
+
highEngagementTweets.push({ tweet, totalEngagement });
|
|
1847
1895
|
}
|
|
1848
1896
|
}
|
|
1849
1897
|
for (const tweet of corpus) {
|
|
@@ -1910,6 +1958,34 @@ async function runDiscoveryPipeline(ctx, job) {
|
|
|
1910
1958
|
authority_count: Object.values(config.authority_lists).reduce((n, l) => n + l.handles.length, 0),
|
|
1911
1959
|
handle_candidates: handleStats.discovered
|
|
1912
1960
|
});
|
|
1961
|
+
const alertLines = [
|
|
1962
|
+
"=== X Intelligence: Discovery Run Complete ===",
|
|
1963
|
+
`Date: ${today}`,
|
|
1964
|
+
`Corpus size: ${corpus.length} tweets`,
|
|
1965
|
+
`Top score: ${(corpus[0]?.score ?? 0).toFixed(2)}`,
|
|
1966
|
+
`Discovery stats: ${openQueries.length} open queries, ${focusedQueries.length} focused queries`,
|
|
1967
|
+
`New handles discovered: ${handleStats.discovered}`,
|
|
1968
|
+
"",
|
|
1969
|
+
"Top items:",
|
|
1970
|
+
...corpus.slice(0, 5).map(
|
|
1971
|
+
(t) => `- @${t.author_username} (score: ${t.score.toFixed(2)}): ${t.text.slice(0, 120)} ${tweetUrl(t.author_username, t.tweet_id)}`
|
|
1972
|
+
)
|
|
1973
|
+
];
|
|
1974
|
+
if (highEngagementTweets.length > 0) {
|
|
1975
|
+
alertLines.push(
|
|
1976
|
+
"",
|
|
1977
|
+
`=== High-Engagement Tweets (${highEngagementTweets.length} crossed ${engagementThresholds.escalation}+ threshold) ===`,
|
|
1978
|
+
"",
|
|
1979
|
+
...highEngagementTweets.map(
|
|
1980
|
+
({ tweet, totalEngagement }) => [
|
|
1981
|
+
`@${tweet.author_username}${tweet.is_authority ? " (authority)" : ""} \u2014 ${totalEngagement} engagements (score: ${tweet.score.toFixed(2)})`,
|
|
1982
|
+
` ${tweet.text.slice(0, 200)}`,
|
|
1983
|
+
` ${tweetUrl(tweet.author_username, tweet.tweet_id)}`
|
|
1984
|
+
].join("\n")
|
|
1985
|
+
)
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
await invokeAlertAgents(ctx, config, alertLines.join("\n"));
|
|
1913
1989
|
for (const promo of promotions) {
|
|
1914
1990
|
if (promo.status === "promoted") {
|
|
1915
1991
|
await ctx.events.emit(EVENT_NAMES.handlePromoted, config.company_id, {
|
|
@@ -2359,6 +2435,238 @@ async function handleRateTweet(ctx, params, runCtx) {
|
|
|
2359
2435
|
${ratedUrl}`
|
|
2360
2436
|
};
|
|
2361
2437
|
}
|
|
2438
|
+
async function handleSearchX(ctx, params, _runCtx) {
|
|
2439
|
+
const p = params;
|
|
2440
|
+
const query = typeof p.query === "string" ? p.query : "";
|
|
2441
|
+
const limit = typeof p.limit === "number" ? p.limit : 20;
|
|
2442
|
+
const handles = Array.isArray(p.handles) ? p.handles : void 0;
|
|
2443
|
+
const quick = p.quick === true;
|
|
2444
|
+
if (!query) return { error: "query is required" };
|
|
2445
|
+
const config = await getConfig(ctx);
|
|
2446
|
+
await ctx.metrics.write("tool.search_x.invoked", 1);
|
|
2447
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2448
|
+
const threeDaysAgo = new Date(Date.now() - 3 * 864e5).toISOString().split("T")[0];
|
|
2449
|
+
let totalCost = 0;
|
|
2450
|
+
const result = await xaiSearch(
|
|
2451
|
+
ctx.http,
|
|
2452
|
+
ctx.secrets,
|
|
2453
|
+
ctx.logger,
|
|
2454
|
+
config.xai_api_key_ref,
|
|
2455
|
+
{
|
|
2456
|
+
query,
|
|
2457
|
+
fromDate: threeDaysAgo,
|
|
2458
|
+
toDate: today,
|
|
2459
|
+
allowedHandles: handles,
|
|
2460
|
+
excludedHandles: handles ? void 0 : config.global_excluded
|
|
2461
|
+
}
|
|
2462
|
+
);
|
|
2463
|
+
totalCost += result.costUsdTicks;
|
|
2464
|
+
if (quick) {
|
|
2465
|
+
const limitedIds = result.tweetIds.slice(0, limit);
|
|
2466
|
+
await ctx.metrics.write("tool.search_x.cost", totalCost / 1e9);
|
|
2467
|
+
return {
|
|
2468
|
+
content: `Search for "${query}" (quick mode): ${limitedIds.length} tweets found.
|
|
2469
|
+
|
|
2470
|
+
${result.synthesisText}`,
|
|
2471
|
+
data: {
|
|
2472
|
+
query,
|
|
2473
|
+
mode: "quick",
|
|
2474
|
+
tweet_ids: limitedIds,
|
|
2475
|
+
synthesis: result.synthesisText,
|
|
2476
|
+
cost_usd: totalCost / 1e9
|
|
2477
|
+
}
|
|
2478
|
+
};
|
|
2479
|
+
}
|
|
2480
|
+
const tweets = await batchLookupTweets(
|
|
2481
|
+
ctx.http,
|
|
2482
|
+
ctx.secrets,
|
|
2483
|
+
ctx.logger,
|
|
2484
|
+
config.x_api_bearer_ref,
|
|
2485
|
+
result.tweetIds,
|
|
2486
|
+
"open_discovery"
|
|
2487
|
+
);
|
|
2488
|
+
const { allHandles, byDomain } = buildAuthorityMaps(config);
|
|
2489
|
+
const scored = scoreTweets(
|
|
2490
|
+
tweets,
|
|
2491
|
+
config.scoring_weights,
|
|
2492
|
+
config.engagement_sub_weights,
|
|
2493
|
+
config.authority_boost,
|
|
2494
|
+
allHandles,
|
|
2495
|
+
byDomain,
|
|
2496
|
+
config.semantic_topics
|
|
2497
|
+
);
|
|
2498
|
+
const deduped = deduplicateTweets(scored, config.dedup_threshold);
|
|
2499
|
+
const limited = deduped.slice(0, limit).map(withUrl);
|
|
2500
|
+
await ctx.metrics.write("tool.search_x.cost", totalCost / 1e9);
|
|
2501
|
+
const topLinks = limited.slice(0, 5).map(
|
|
2502
|
+
(t) => `- @${t.author_username} (score: ${t.score.toFixed(1)}): ${t.url}`
|
|
2503
|
+
).join("\n");
|
|
2504
|
+
return {
|
|
2505
|
+
content: `Search for "${query}": ${limited.length} enriched tweets (of ${deduped.length} unique).
|
|
2506
|
+
|
|
2507
|
+
Top results:
|
|
2508
|
+
${topLinks}
|
|
2509
|
+
|
|
2510
|
+
Synthesis:
|
|
2511
|
+
${result.synthesisText}`,
|
|
2512
|
+
data: {
|
|
2513
|
+
query,
|
|
2514
|
+
mode: "full",
|
|
2515
|
+
items: limited,
|
|
2516
|
+
total_unique: deduped.length,
|
|
2517
|
+
synthesis: result.synthesisText,
|
|
2518
|
+
cost_usd: totalCost / 1e9
|
|
2519
|
+
}
|
|
2520
|
+
};
|
|
2521
|
+
}
|
|
2522
|
+
async function handleGetTrending(ctx, params, _runCtx) {
|
|
2523
|
+
const p = params;
|
|
2524
|
+
const limit = typeof p.limit === "number" ? p.limit : 20;
|
|
2525
|
+
const pillar = typeof p.pillar === "string" ? p.pillar : void 0;
|
|
2526
|
+
const config = await getConfig(ctx);
|
|
2527
|
+
await ctx.metrics.write("tool.get_trending.invoked", 1);
|
|
2528
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2529
|
+
const threeDaysAgo = new Date(Date.now() - 3 * 864e5).toISOString().split("T")[0];
|
|
2530
|
+
const topics = pillar ? (() => {
|
|
2531
|
+
const words = pillar.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 2);
|
|
2532
|
+
return config.semantic_topics.filter((t) => {
|
|
2533
|
+
const lower = t.toLowerCase();
|
|
2534
|
+
return words.some((w) => lower.includes(w));
|
|
2535
|
+
});
|
|
2536
|
+
})() : config.semantic_topics;
|
|
2537
|
+
if (topics.length === 0) {
|
|
2538
|
+
return {
|
|
2539
|
+
error: pillar ? `No semantic topics match pillar "${pillar}". Available topics: ${config.semantic_topics.join(", ")}` : "No semantic topics configured"
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
const queries = buildOpenQueries(topics, [], today);
|
|
2543
|
+
const allTweetIdArrays = [];
|
|
2544
|
+
let totalCost = 0;
|
|
2545
|
+
for (const query of queries) {
|
|
2546
|
+
try {
|
|
2547
|
+
const result = await xaiSearch(
|
|
2548
|
+
ctx.http,
|
|
2549
|
+
ctx.secrets,
|
|
2550
|
+
ctx.logger,
|
|
2551
|
+
config.xai_api_key_ref,
|
|
2552
|
+
{ query: query.text, fromDate: threeDaysAgo, toDate: today, excludedHandles: config.global_excluded }
|
|
2553
|
+
);
|
|
2554
|
+
allTweetIdArrays.push(result.tweetIds);
|
|
2555
|
+
totalCost += result.costUsdTicks;
|
|
2556
|
+
} catch (err) {
|
|
2557
|
+
ctx.logger.warn("Trending query failed", {
|
|
2558
|
+
query: query.text,
|
|
2559
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
const tweetIds = deduplicateIds(allTweetIdArrays);
|
|
2564
|
+
const tweets = await batchLookupTweets(
|
|
2565
|
+
ctx.http,
|
|
2566
|
+
ctx.secrets,
|
|
2567
|
+
ctx.logger,
|
|
2568
|
+
config.x_api_bearer_ref,
|
|
2569
|
+
tweetIds,
|
|
2570
|
+
"open_discovery"
|
|
2571
|
+
);
|
|
2572
|
+
const { allHandles, byDomain } = buildAuthorityMaps(config);
|
|
2573
|
+
const scored = scoreTweets(
|
|
2574
|
+
tweets,
|
|
2575
|
+
config.scoring_weights,
|
|
2576
|
+
config.engagement_sub_weights,
|
|
2577
|
+
config.authority_boost,
|
|
2578
|
+
allHandles,
|
|
2579
|
+
byDomain,
|
|
2580
|
+
config.semantic_topics
|
|
2581
|
+
);
|
|
2582
|
+
const deduped = deduplicateTweets(scored, config.dedup_threshold);
|
|
2583
|
+
const limited = deduped.slice(0, limit).map(withUrl);
|
|
2584
|
+
await ctx.metrics.write("tool.get_trending.cost", totalCost / 1e9);
|
|
2585
|
+
const topLinks = limited.slice(0, 5).map(
|
|
2586
|
+
(t) => `- @${t.author_username} (score: ${t.score.toFixed(1)}): ${t.url}`
|
|
2587
|
+
).join("\n");
|
|
2588
|
+
return {
|
|
2589
|
+
content: `Trending${pillar ? ` in "${pillar}"` : ""}: ${limited.length} tweets across ${queries.length} topics.
|
|
2590
|
+
|
|
2591
|
+
Top results:
|
|
2592
|
+
${topLinks}`,
|
|
2593
|
+
data: {
|
|
2594
|
+
pillar: pillar ?? null,
|
|
2595
|
+
topics_queried: queries.length,
|
|
2596
|
+
items: limited,
|
|
2597
|
+
total_unique: deduped.length,
|
|
2598
|
+
cost_usd: totalCost / 1e9
|
|
2599
|
+
}
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
async function handleGetUserTimeline(ctx, params, _runCtx) {
|
|
2603
|
+
const p = params;
|
|
2604
|
+
const handle = typeof p.handle === "string" ? p.handle.replace(/^@/, "") : "";
|
|
2605
|
+
const limit = typeof p.limit === "number" ? p.limit : 20;
|
|
2606
|
+
const since = typeof p.since === "string" ? p.since : void 0;
|
|
2607
|
+
if (!handle) return { error: "handle is required" };
|
|
2608
|
+
const config = await getConfig(ctx);
|
|
2609
|
+
await ctx.metrics.write("tool.get_user_timeline.invoked", 1);
|
|
2610
|
+
try {
|
|
2611
|
+
const tweets = await fetchUserTimeline(
|
|
2612
|
+
ctx.http,
|
|
2613
|
+
ctx.secrets,
|
|
2614
|
+
ctx.logger,
|
|
2615
|
+
config.x_api_bearer_ref,
|
|
2616
|
+
handle,
|
|
2617
|
+
limit,
|
|
2618
|
+
since
|
|
2619
|
+
);
|
|
2620
|
+
const tweetsWithUrls = tweets.map(withUrl);
|
|
2621
|
+
const topLinks = tweetsWithUrls.slice(0, 5).map((t) => `- ${t.url}`).join("\n");
|
|
2622
|
+
return {
|
|
2623
|
+
content: `@${handle}'s timeline: ${tweetsWithUrls.length} tweets${since ? ` since ${since}` : ""}.
|
|
2624
|
+
|
|
2625
|
+
Recent:
|
|
2626
|
+
${topLinks}`,
|
|
2627
|
+
data: {
|
|
2628
|
+
handle,
|
|
2629
|
+
items: tweetsWithUrls,
|
|
2630
|
+
total: tweetsWithUrls.length
|
|
2631
|
+
}
|
|
2632
|
+
};
|
|
2633
|
+
} catch (err) {
|
|
2634
|
+
return {
|
|
2635
|
+
error: `Failed to fetch timeline for @${handle}: ${err instanceof Error ? err.message : String(err)}`
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
async function invokeAlertAgents(ctx, config, alertContext) {
|
|
2640
|
+
const alertAgents = config.alert_agents ?? [];
|
|
2641
|
+
if (alertAgents.length === 0) return;
|
|
2642
|
+
const invocations = alertAgents.map(async (agent) => {
|
|
2643
|
+
try {
|
|
2644
|
+
let prompt = alertContext;
|
|
2645
|
+
if (agent.memoryFile) {
|
|
2646
|
+
prompt = `${alertContext}
|
|
2647
|
+
|
|
2648
|
+
--- Memory File ---
|
|
2649
|
+
Load your user's preferences from: ${agent.memoryFile}
|
|
2650
|
+
Apply their alert thresholds and topic interests when deciding how to handle this alert.`;
|
|
2651
|
+
}
|
|
2652
|
+
const result = await ctx.agents.invoke(agent.agentId, config.company_id, {
|
|
2653
|
+
prompt,
|
|
2654
|
+
reason: "x-intelligence-alert"
|
|
2655
|
+
});
|
|
2656
|
+
ctx.logger.info("Agent invoked for alert", {
|
|
2657
|
+
agentId: agent.agentId,
|
|
2658
|
+
runId: result.runId,
|
|
2659
|
+
enriched: !!agent.memoryFile
|
|
2660
|
+
});
|
|
2661
|
+
} catch (err) {
|
|
2662
|
+
ctx.logger.warn("Failed to invoke agent for alert", {
|
|
2663
|
+
agentId: agent.agentId,
|
|
2664
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2665
|
+
});
|
|
2666
|
+
}
|
|
2667
|
+
});
|
|
2668
|
+
await Promise.all(invocations);
|
|
2669
|
+
}
|
|
2362
2670
|
var plugin = definePlugin({
|
|
2363
2671
|
async setup(ctx) {
|
|
2364
2672
|
pluginCtx = ctx;
|
|
@@ -2411,6 +2719,21 @@ var plugin = definePlugin({
|
|
|
2411
2719
|
{ displayName: "Rate Tweet", description: "Record relevance feedback on a corpus tweet", parametersSchema: {} },
|
|
2412
2720
|
(params, runCtx) => handleRateTweet(ctx, params, runCtx)
|
|
2413
2721
|
);
|
|
2722
|
+
ctx.tools.register(
|
|
2723
|
+
TOOL_NAMES.searchX,
|
|
2724
|
+
{ displayName: "Search X", description: "Real-time semantic search on X/Twitter via xAI. Any query, any time \u2014 no pipeline required.", parametersSchema: {} },
|
|
2725
|
+
(params, runCtx) => handleSearchX(ctx, params, runCtx)
|
|
2726
|
+
);
|
|
2727
|
+
ctx.tools.register(
|
|
2728
|
+
TOOL_NAMES.getTrending,
|
|
2729
|
+
{ displayName: "Get Trending", description: "What's trending in PEAK6's configured domains right now. No pipeline required.", parametersSchema: {} },
|
|
2730
|
+
(params, runCtx) => handleGetTrending(ctx, params, runCtx)
|
|
2731
|
+
);
|
|
2732
|
+
ctx.tools.register(
|
|
2733
|
+
TOOL_NAMES.getUserTimeline,
|
|
2734
|
+
{ displayName: "Get User Timeline", description: "Fetch a user's recent tweets from X/Twitter.", parametersSchema: {} },
|
|
2735
|
+
(params, runCtx) => handleGetUserTimeline(ctx, params, runCtx)
|
|
2736
|
+
);
|
|
2414
2737
|
ctx.data.register("dashboard-summary", async () => {
|
|
2415
2738
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2416
2739
|
const summary = await ctx.state.get({
|