pnpfucius 2.0.0

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.
@@ -0,0 +1,6 @@
1
+ // AI module exports
2
+ // Claude API-powered market generation, resolution, and scoring
3
+
4
+ export { AIMarketGenerator, createMarketGenerator } from './market-generator.js';
5
+ export { AIResolver, createResolver } from './resolver.js';
6
+ export { AIScorer, createScorer, quickScore } from './scorer.js';
@@ -0,0 +1,186 @@
1
+ // AI-powered market generation using Claude API
2
+ // Transforms news headlines into privacy-themed prediction markets
3
+
4
+ import Anthropic from '@anthropic-ai/sdk';
5
+ import { getConfig } from '../config.js';
6
+
7
+ const MARKET_GENERATION_PROMPT = `You are an expert at creating prediction market questions for a privacy-focused prediction market on Solana.
8
+
9
+ Given news headlines or topics, generate relevant YES/NO prediction market questions that:
10
+ 1. Are clearly verifiable with a definitive outcome
11
+ 2. Focus on privacy, regulation, zero-knowledge proofs, encryption, data protection, or surveillance
12
+ 3. Have appropriate timeframes (30-365 days typically)
13
+ 4. Are interesting enough to attract betting activity
14
+ 5. Are NOT already obviously true or false
15
+
16
+ Categories to consider:
17
+ - regulation: Government policies, GDPR, privacy laws, sanctions
18
+ - technology: ZK protocols, encryption standards, privacy tools, Solana privacy features
19
+ - adoption: User growth, TVL milestones, enterprise adoption
20
+ - events: Breaches, scandals, conference announcements, court cases
21
+
22
+ Respond with valid JSON only, no markdown formatting:
23
+ {
24
+ "question": "The yes/no question ending with ?",
25
+ "category": "regulation|technology|adoption|events",
26
+ "categoryName": "Human readable category name",
27
+ "suggestedDurationDays": 30-365,
28
+ "suggestedLiquidityUSDC": 1000-10000,
29
+ "urgency": "breaking|timely|evergreen",
30
+ "reasoning": "Brief explanation of why this is a good market"
31
+ }`;
32
+
33
+ export class AIMarketGenerator {
34
+ constructor(apiKey = null) {
35
+ const config = getConfig();
36
+ this.apiKey = apiKey || config.anthropicApiKey;
37
+
38
+ if (!this.apiKey) {
39
+ throw new Error('ANTHROPIC_API_KEY is required for AI market generation');
40
+ }
41
+
42
+ this.client = new Anthropic({ apiKey: this.apiKey });
43
+ this.model = 'claude-sonnet-4-20250514';
44
+ }
45
+
46
+ /**
47
+ * Generate a market question from a news headline
48
+ */
49
+ async generateFromNews(newsItem) {
50
+ const { title, summary, source, link } = newsItem;
51
+
52
+ const userPrompt = `Generate a prediction market question based on this news:
53
+
54
+ Title: ${title}
55
+ ${summary ? `Summary: ${summary}` : ''}
56
+ ${source ? `Source: ${source}` : ''}
57
+
58
+ Create a compelling, verifiable YES/NO question that privacy-focused traders would want to bet on.`;
59
+
60
+ try {
61
+ const response = await this.client.messages.create({
62
+ model: this.model,
63
+ max_tokens: 500,
64
+ messages: [
65
+ { role: 'user', content: MARKET_GENERATION_PROMPT + '\n\n' + userPrompt }
66
+ ]
67
+ });
68
+
69
+ const content = response.content[0].text;
70
+ const market = JSON.parse(content);
71
+
72
+ return {
73
+ ...market,
74
+ sourceNews: { title, source, link },
75
+ generatedAt: Date.now()
76
+ };
77
+ } catch (error) {
78
+ if (error instanceof SyntaxError) {
79
+ throw new Error(`Failed to parse AI response as JSON: ${error.message}`);
80
+ }
81
+ throw error;
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Generate multiple markets from a batch of news items
87
+ */
88
+ async generateBatchFromNews(newsItems, options = {}) {
89
+ const { maxMarkets = 5, minScore = 50 } = options;
90
+ const results = [];
91
+
92
+ for (const item of newsItems.slice(0, maxMarkets)) {
93
+ try {
94
+ // Skip low-relevance items if score provided
95
+ if (item.relevanceScore !== undefined && item.relevanceScore < minScore) {
96
+ continue;
97
+ }
98
+
99
+ const market = await this.generateFromNews(item);
100
+ results.push({ success: true, market, newsItem: item });
101
+ } catch (error) {
102
+ results.push({ success: false, error: error.message, newsItem: item });
103
+ }
104
+ }
105
+
106
+ return results;
107
+ }
108
+
109
+ /**
110
+ * Generate a market from a topic/theme (not news-based)
111
+ */
112
+ async generateFromTopic(topic, category = null) {
113
+ const userPrompt = `Generate a prediction market question about: ${topic}
114
+ ${category ? `Focus on the "${category}" category.` : ''}
115
+
116
+ Create a compelling, verifiable YES/NO question that privacy-focused traders would want to bet on.`;
117
+
118
+ try {
119
+ const response = await this.client.messages.create({
120
+ model: this.model,
121
+ max_tokens: 500,
122
+ messages: [
123
+ { role: 'user', content: MARKET_GENERATION_PROMPT + '\n\n' + userPrompt }
124
+ ]
125
+ });
126
+
127
+ const content = response.content[0].text;
128
+ const market = JSON.parse(content);
129
+
130
+ return {
131
+ ...market,
132
+ sourceTopic: topic,
133
+ generatedAt: Date.now()
134
+ };
135
+ } catch (error) {
136
+ if (error instanceof SyntaxError) {
137
+ throw new Error(`Failed to parse AI response as JSON: ${error.message}`);
138
+ }
139
+ throw error;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Generate multiple diverse markets
145
+ */
146
+ async generateDiverseMarkets(count = 5) {
147
+ const topics = [
148
+ 'GDPR enforcement trends in 2026',
149
+ 'Zero-knowledge proof adoption on Solana',
150
+ 'Privacy coin regulations in the US',
151
+ 'Enterprise adoption of confidential computing',
152
+ 'End-to-end encryption legislation',
153
+ 'Decentralized identity adoption',
154
+ 'Privacy-preserving AI developments',
155
+ 'Tornado Cash legal developments',
156
+ 'Light Protocol and Solana privacy',
157
+ 'Data breach trends and regulations'
158
+ ];
159
+
160
+ const categories = ['regulation', 'technology', 'adoption', 'events'];
161
+ const results = [];
162
+
163
+ for (let i = 0; i < count; i++) {
164
+ const topic = topics[i % topics.length];
165
+ const category = categories[i % categories.length];
166
+
167
+ try {
168
+ const market = await this.generateFromTopic(topic, category);
169
+ results.push({ success: true, market });
170
+ } catch (error) {
171
+ results.push({ success: false, error: error.message, topic });
172
+ }
173
+ }
174
+
175
+ return results;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Factory function
181
+ */
182
+ export function createMarketGenerator(apiKey = null) {
183
+ return new AIMarketGenerator(apiKey);
184
+ }
185
+
186
+ export default AIMarketGenerator;
@@ -0,0 +1,172 @@
1
+ // AI-powered market resolution helper using Claude API
2
+ // Analyzes whether market conditions have been met
3
+
4
+ import Anthropic from '@anthropic-ai/sdk';
5
+ import { getConfig } from '../config.js';
6
+
7
+ const RESOLUTION_PROMPT = `You are an expert at determining whether prediction market conditions have been met.
8
+
9
+ Given a prediction market question and the current date, analyze whether:
10
+ 1. The condition can be definitively resolved (enough time has passed, event occurred, etc.)
11
+ 2. If resolvable, whether the outcome is YES or NO
12
+ 3. Your confidence level in the assessment
13
+
14
+ Consider:
15
+ - Time-bound conditions (has the deadline passed?)
16
+ - Verifiable events (did the specific event occur?)
17
+ - Measurable thresholds (was the metric achieved?)
18
+
19
+ Be conservative - if uncertain, indicate the market cannot be resolved yet.
20
+
21
+ Respond with valid JSON only, no markdown formatting:
22
+ {
23
+ "canResolve": true/false,
24
+ "outcome": "yes"|"no"|"unknown",
25
+ "confidence": 0.0-1.0,
26
+ "reasoning": "Detailed explanation of your assessment",
27
+ "sources": ["Any sources or facts you're basing this on"],
28
+ "suggestedAction": "resolve_yes"|"resolve_no"|"wait"|"needs_oracle"
29
+ }`;
30
+
31
+ export class AIResolver {
32
+ constructor(apiKey = null) {
33
+ const config = getConfig();
34
+ this.apiKey = apiKey || config.anthropicApiKey;
35
+
36
+ if (!this.apiKey) {
37
+ throw new Error('ANTHROPIC_API_KEY is required for AI resolution');
38
+ }
39
+
40
+ this.client = new Anthropic({ apiKey: this.apiKey });
41
+ this.model = 'claude-sonnet-4-20250514';
42
+ }
43
+
44
+ /**
45
+ * Analyze if a market can be resolved
46
+ */
47
+ async analyzeResolution(market) {
48
+ const { question, creationTime, endTime, durationDays } = market;
49
+ const now = new Date();
50
+ const createdAt = new Date(creationTime);
51
+ const endsAt = endTime ? new Date(endTime) : null;
52
+
53
+ const userPrompt = `Analyze this prediction market for resolution:
54
+
55
+ Question: ${question}
56
+
57
+ Market Details:
58
+ - Created: ${createdAt.toISOString().split('T')[0]}
59
+ - Duration: ${durationDays} days
60
+ ${endsAt ? `- End Date: ${endsAt.toISOString().split('T')[0]}` : ''}
61
+ - Current Date: ${now.toISOString().split('T')[0]}
62
+
63
+ Has enough time passed? Has the condition been met or definitively failed?
64
+ Use your knowledge cutoff to assess current events and facts.`;
65
+
66
+ try {
67
+ const response = await this.client.messages.create({
68
+ model: this.model,
69
+ max_tokens: 800,
70
+ messages: [
71
+ { role: 'user', content: RESOLUTION_PROMPT + '\n\n' + userPrompt }
72
+ ]
73
+ });
74
+
75
+ const content = response.content[0].text;
76
+ const analysis = JSON.parse(content);
77
+
78
+ return {
79
+ ...analysis,
80
+ marketAddress: market.address,
81
+ analyzedAt: Date.now()
82
+ };
83
+ } catch (error) {
84
+ if (error instanceof SyntaxError) {
85
+ throw new Error(`Failed to parse AI response as JSON: ${error.message}`);
86
+ }
87
+ throw error;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Batch analyze multiple markets for resolution
93
+ */
94
+ async analyzeMarkets(markets) {
95
+ const results = [];
96
+
97
+ for (const market of markets) {
98
+ try {
99
+ const analysis = await this.analyzeResolution(market);
100
+ results.push({
101
+ success: true,
102
+ market,
103
+ analysis
104
+ });
105
+ } catch (error) {
106
+ results.push({
107
+ success: false,
108
+ market,
109
+ error: error.message
110
+ });
111
+ }
112
+ }
113
+
114
+ return results;
115
+ }
116
+
117
+ /**
118
+ * Get markets that are ready to resolve
119
+ */
120
+ async findResolvableMarkets(markets, options = {}) {
121
+ const { minConfidence = 0.8 } = options;
122
+ const analyses = await this.analyzeMarkets(markets);
123
+
124
+ return analyses
125
+ .filter(r => r.success && r.analysis.canResolve && r.analysis.confidence >= minConfidence)
126
+ .map(r => ({
127
+ market: r.market,
128
+ outcome: r.analysis.outcome,
129
+ confidence: r.analysis.confidence,
130
+ reasoning: r.analysis.reasoning,
131
+ suggestedAction: r.analysis.suggestedAction
132
+ }));
133
+ }
134
+
135
+ /**
136
+ * Generate a resolution report for a market
137
+ */
138
+ async generateResolutionReport(market) {
139
+ const analysis = await this.analyzeResolution(market);
140
+
141
+ return {
142
+ market: {
143
+ address: market.address,
144
+ question: market.question,
145
+ category: market.category
146
+ },
147
+ resolution: {
148
+ canResolve: analysis.canResolve,
149
+ outcome: analysis.outcome,
150
+ confidence: analysis.confidence,
151
+ suggestedAction: analysis.suggestedAction
152
+ },
153
+ details: {
154
+ reasoning: analysis.reasoning,
155
+ sources: analysis.sources
156
+ },
157
+ meta: {
158
+ analyzedAt: new Date().toISOString(),
159
+ model: this.model
160
+ }
161
+ };
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Factory function
167
+ */
168
+ export function createResolver(apiKey = null) {
169
+ return new AIResolver(apiKey);
170
+ }
171
+
172
+ export default AIResolver;
@@ -0,0 +1,184 @@
1
+ // AI-powered news relevance scoring using Claude API
2
+ // Scores incoming news items 0-100 on privacy relevance
3
+
4
+ import Anthropic from '@anthropic-ai/sdk';
5
+ import { getConfig } from '../config.js';
6
+
7
+ const SCORING_PROMPT = `You are an expert at evaluating news relevance for a privacy-focused prediction market on Solana.
8
+
9
+ Score news items from 0-100 based on their relevance to:
10
+ - Privacy regulations (GDPR, CCPA, federal privacy laws)
11
+ - Privacy technology (zero-knowledge proofs, encryption, confidential computing)
12
+ - Privacy tools (Tor, Signal, privacy coins, mixers like Tornado Cash)
13
+ - Data protection (breaches, surveillance, data rights)
14
+ - Blockchain privacy (Solana privacy features, Token-2022 confidential transfers)
15
+ - Crypto regulations affecting privacy (sanctions, KYC requirements)
16
+
17
+ Scoring guidelines:
18
+ - 90-100: Directly about privacy regulation/technology, major impact, breaking news
19
+ - 70-89: Strongly privacy-related, significant developments
20
+ - 50-69: Moderately relevant, tangential privacy implications
21
+ - 30-49: Loosely related, minor privacy angle
22
+ - 0-29: Not relevant or very weak connection
23
+
24
+ Also suggest if this news could generate an interesting prediction market.
25
+
26
+ Respond with valid JSON only, no markdown formatting:
27
+ {
28
+ "score": 0-100,
29
+ "category": "regulation"|"technology"|"adoption"|"events"|"none",
30
+ "urgency": "breaking"|"timely"|"evergreen",
31
+ "marketPotential": true/false,
32
+ "reasoning": "Brief explanation of the score",
33
+ "suggestedMarketAngle": "If marketPotential is true, a brief market idea"
34
+ }`;
35
+
36
+ export class AIScorer {
37
+ constructor(apiKey = null) {
38
+ const config = getConfig();
39
+ this.apiKey = apiKey || config.anthropicApiKey;
40
+
41
+ if (!this.apiKey) {
42
+ throw new Error('ANTHROPIC_API_KEY is required for AI scoring');
43
+ }
44
+
45
+ this.client = new Anthropic({ apiKey: this.apiKey });
46
+ this.model = 'claude-haiku-4-20250514'; // Use Haiku for speed/cost on scoring
47
+ this.cache = new Map(); // Simple cache for repeated items
48
+ }
49
+
50
+ /**
51
+ * Score a single news item
52
+ */
53
+ async scoreNews(newsItem) {
54
+ const { title, summary, source } = newsItem;
55
+
56
+ // Check cache
57
+ const cacheKey = title.toLowerCase().trim();
58
+ if (this.cache.has(cacheKey)) {
59
+ return this.cache.get(cacheKey);
60
+ }
61
+
62
+ const userPrompt = `Score this news item for privacy relevance:
63
+
64
+ Title: ${title}
65
+ ${summary ? `Summary: ${summary}` : ''}
66
+ ${source ? `Source: ${source}` : ''}`;
67
+
68
+ try {
69
+ const response = await this.client.messages.create({
70
+ model: this.model,
71
+ max_tokens: 300,
72
+ messages: [
73
+ { role: 'user', content: SCORING_PROMPT + '\n\n' + userPrompt }
74
+ ]
75
+ });
76
+
77
+ const content = response.content[0].text;
78
+ const result = JSON.parse(content);
79
+
80
+ const scored = {
81
+ ...result,
82
+ newsItem: { title, source },
83
+ scoredAt: Date.now()
84
+ };
85
+
86
+ // Cache result
87
+ this.cache.set(cacheKey, scored);
88
+
89
+ return scored;
90
+ } catch (error) {
91
+ if (error instanceof SyntaxError) {
92
+ throw new Error(`Failed to parse AI response as JSON: ${error.message}`);
93
+ }
94
+ throw error;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Score multiple news items in batch
100
+ */
101
+ async scoreBatch(newsItems) {
102
+ const results = [];
103
+
104
+ for (const item of newsItems) {
105
+ try {
106
+ const score = await this.scoreNews(item);
107
+ results.push({ success: true, ...score });
108
+ } catch (error) {
109
+ results.push({
110
+ success: false,
111
+ error: error.message,
112
+ newsItem: item
113
+ });
114
+ }
115
+ }
116
+
117
+ return results;
118
+ }
119
+
120
+ /**
121
+ * Filter news items by minimum score
122
+ */
123
+ async filterByRelevance(newsItems, minScore = 50) {
124
+ const scored = await this.scoreBatch(newsItems);
125
+
126
+ return scored
127
+ .filter(r => r.success && r.score >= minScore)
128
+ .sort((a, b) => b.score - a.score);
129
+ }
130
+
131
+ /**
132
+ * Get high-potential market candidates from news
133
+ */
134
+ async findMarketCandidates(newsItems, options = {}) {
135
+ const { minScore = 60 } = options;
136
+ const scored = await this.scoreBatch(newsItems);
137
+
138
+ return scored
139
+ .filter(r => r.success && r.marketPotential && r.score >= minScore)
140
+ .sort((a, b) => b.score - a.score)
141
+ .map(r => ({
142
+ title: r.newsItem.title,
143
+ source: r.newsItem.source,
144
+ score: r.score,
145
+ category: r.category,
146
+ urgency: r.urgency,
147
+ marketAngle: r.suggestedMarketAngle
148
+ }));
149
+ }
150
+
151
+ /**
152
+ * Clear the score cache
153
+ */
154
+ clearCache() {
155
+ this.cache.clear();
156
+ }
157
+
158
+ /**
159
+ * Get cache stats
160
+ */
161
+ getCacheStats() {
162
+ return {
163
+ size: this.cache.size,
164
+ entries: Array.from(this.cache.keys())
165
+ };
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Factory function
171
+ */
172
+ export function createScorer(apiKey = null) {
173
+ return new AIScorer(apiKey);
174
+ }
175
+
176
+ /**
177
+ * Quick scoring function for single items
178
+ */
179
+ export async function quickScore(newsItem, apiKey = null) {
180
+ const scorer = new AIScorer(apiKey);
181
+ return scorer.scoreNews(newsItem);
182
+ }
183
+
184
+ export default AIScorer;