spora 0.5.0 → 0.5.2
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/{chunk-ZEV5VG2T.js → chunk-LWC67JKZ.js} +163 -2
- package/dist/chunk-LWC67JKZ.js.map +1 -0
- package/dist/chunk-UM57WU5I.js +79 -0
- package/dist/chunk-UM57WU5I.js.map +1 -0
- package/dist/chunk-YLJVFCT4.js +44 -0
- package/dist/chunk-YLJVFCT4.js.map +1 -0
- package/dist/cli.js +5 -5
- package/dist/goals-5TAPXNR2.js +12 -0
- package/dist/{heartbeat-YOJVMZUL.js → heartbeat-KJTOWR3N.js} +10 -8
- package/dist/{heartbeat-YOJVMZUL.js.map → heartbeat-KJTOWR3N.js.map} +1 -1
- package/dist/{init-WQDJLWMK.js → init-5MZMCEB7.js} +3 -3
- package/dist/{prompt-builder-6KC42BML.js → prompt-builder-CCLRNVTE.js} +8 -4
- package/dist/prompt-builder-CCLRNVTE.js.map +1 -0
- package/dist/strategy-S45TX766.js +12 -0
- package/dist/strategy-S45TX766.js.map +1 -0
- package/dist/web-chat/chat.html +315 -223
- package/dist/{web-chat-OH3YXPJO.js → web-chat-ZKKVAEJT.js} +163 -23
- package/dist/web-chat-ZKKVAEJT.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-ZEV5VG2T.js.map +0 -1
- package/dist/web-chat-OH3YXPJO.js.map +0 -1
- /package/dist/{prompt-builder-6KC42BML.js.map → goals-5TAPXNR2.js.map} +0 -0
- /package/dist/{init-WQDJLWMK.js.map → init-5MZMCEB7.js.map} +0 -0
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderStrategyForPrompt
|
|
3
|
+
} from "./chunk-UM57WU5I.js";
|
|
4
|
+
import {
|
|
5
|
+
renderGoalsForPrompt
|
|
6
|
+
} from "./chunk-YLJVFCT4.js";
|
|
1
7
|
import {
|
|
2
8
|
rateLimiter
|
|
3
9
|
} from "./chunk-6M4HISFK.js";
|
|
@@ -13,6 +19,70 @@ import {
|
|
|
13
19
|
loadLearnings,
|
|
14
20
|
loadRelationships
|
|
15
21
|
} from "./chunk-EBO4F5NU.js";
|
|
22
|
+
import {
|
|
23
|
+
paths
|
|
24
|
+
} from "./chunk-53YLFYJF.js";
|
|
25
|
+
|
|
26
|
+
// src/memory/performance.ts
|
|
27
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
28
|
+
function loadPerformance() {
|
|
29
|
+
if (!existsSync(paths.performance)) {
|
|
30
|
+
return { trackedPosts: [], selfMetrics: [] };
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(readFileSync(paths.performance, "utf-8"));
|
|
34
|
+
} catch {
|
|
35
|
+
return { trackedPosts: [], selfMetrics: [] };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function getPerformanceSummary() {
|
|
39
|
+
const data = loadPerformance();
|
|
40
|
+
const lines = [];
|
|
41
|
+
const oneDayAgo = Date.now() - 24 * 60 * 60 * 1e3;
|
|
42
|
+
const recentPosts = data.trackedPosts.filter(
|
|
43
|
+
(p) => new Date(p.postedAt).getTime() > oneDayAgo
|
|
44
|
+
);
|
|
45
|
+
if (recentPosts.length > 0) {
|
|
46
|
+
const postStats = recentPosts.map((p) => {
|
|
47
|
+
const latest = p.metrics.length > 0 ? p.metrics[p.metrics.length - 1] : null;
|
|
48
|
+
return {
|
|
49
|
+
content: p.content,
|
|
50
|
+
type: p.type,
|
|
51
|
+
likes: latest?.likes ?? 0,
|
|
52
|
+
retweets: latest?.retweets ?? 0,
|
|
53
|
+
replies: latest?.replies ?? 0
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
const totalLikes = postStats.reduce((s, p) => s + p.likes, 0);
|
|
57
|
+
const totalRTs = postStats.reduce((s, p) => s + p.retweets, 0);
|
|
58
|
+
const avgLikes = Math.round(totalLikes / postStats.length);
|
|
59
|
+
lines.push(`- Last 24h: ${postStats.length} posts, avg ${avgLikes} likes, ${totalRTs} total retweets`);
|
|
60
|
+
const sorted = [...postStats].sort((a, b) => b.likes - a.likes);
|
|
61
|
+
if (sorted.length > 0 && sorted[0].likes > 0) {
|
|
62
|
+
lines.push(`- Best performing: "${sorted[0].content.slice(0, 60)}..." (${sorted[0].likes} likes, ${sorted[0].retweets} RTs)`);
|
|
63
|
+
}
|
|
64
|
+
if (sorted.length > 1) {
|
|
65
|
+
const worst = sorted[sorted.length - 1];
|
|
66
|
+
lines.push(`- Lowest performing: "${worst.content.slice(0, 60)}..." (${worst.likes} likes)`);
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
lines.push("- No tracked posts in the last 24 hours yet.");
|
|
70
|
+
}
|
|
71
|
+
if (data.selfMetrics.length > 0) {
|
|
72
|
+
const latest = data.selfMetrics[data.selfMetrics.length - 1];
|
|
73
|
+
lines.push(`- Followers: ${latest.followers} | Following: ${latest.following} | Total tweets: ${latest.totalTweets}`);
|
|
74
|
+
const dayAgoMetric = data.selfMetrics.find(
|
|
75
|
+
(m) => Math.abs(new Date(m.checkedAt).getTime() - (Date.now() - 24 * 60 * 60 * 1e3)) < 12 * 60 * 60 * 1e3
|
|
76
|
+
);
|
|
77
|
+
if (dayAgoMetric) {
|
|
78
|
+
const diff = latest.followers - dayAgoMetric.followers;
|
|
79
|
+
if (diff !== 0) {
|
|
80
|
+
lines.push(`- Follower trend: ${diff > 0 ? "+" : ""}${diff} in the last ~24h`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return lines.length > 0 ? lines.join("\n") : "";
|
|
85
|
+
}
|
|
16
86
|
|
|
17
87
|
// src/runtime/prompt-builder.ts
|
|
18
88
|
function buildSystemPrompt() {
|
|
@@ -194,10 +264,101 @@ function buildChatPrompt() {
|
|
|
194
264
|
sections.push("5. When you learn something important from this conversation (a fact, preference, instruction, or insight), include it on its own line wrapped in double angle brackets like: <<LEARN: what you learned>>. This will be saved to your memory. Only use this for genuinely important things worth remembering long-term.");
|
|
195
265
|
return sections.join("\n");
|
|
196
266
|
}
|
|
267
|
+
function buildTrainingChatPrompt() {
|
|
268
|
+
const identity = loadIdentity();
|
|
269
|
+
const identityDoc = renderIdentityDocument(identity);
|
|
270
|
+
const sections = [];
|
|
271
|
+
sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);
|
|
272
|
+
sections.push("You are chatting with your creator. This conversation shapes who you are \u2014 your personality, focus areas, goals, and strategy.");
|
|
273
|
+
sections.push("You handle tweeting, replying, liking, and engaging on X autonomously during your heartbeat cycles. This chat is NOT for commanding specific tweets.");
|
|
274
|
+
sections.push("");
|
|
275
|
+
sections.push("## Who You Are Right Now");
|
|
276
|
+
sections.push(identityDoc);
|
|
277
|
+
const strategyText = renderStrategyForPrompt();
|
|
278
|
+
if (strategyText) {
|
|
279
|
+
sections.push("");
|
|
280
|
+
sections.push("## Your Current Strategy");
|
|
281
|
+
sections.push(strategyText);
|
|
282
|
+
}
|
|
283
|
+
const goalsText = renderGoalsForPrompt();
|
|
284
|
+
if (goalsText) {
|
|
285
|
+
sections.push("");
|
|
286
|
+
sections.push("## Your Goals");
|
|
287
|
+
sections.push(goalsText);
|
|
288
|
+
}
|
|
289
|
+
const perfSummary = getPerformanceSummary();
|
|
290
|
+
if (perfSummary) {
|
|
291
|
+
sections.push("");
|
|
292
|
+
sections.push("## Recent Performance");
|
|
293
|
+
sections.push(perfSummary);
|
|
294
|
+
}
|
|
295
|
+
sections.push("");
|
|
296
|
+
sections.push("## Your Memory");
|
|
297
|
+
const recentInteractions = getRecentInteractions(10);
|
|
298
|
+
if (recentInteractions.length > 0) {
|
|
299
|
+
sections.push("### Recent Activity");
|
|
300
|
+
for (const i of recentInteractions) {
|
|
301
|
+
const time = new Date(i.timestamp).toLocaleString();
|
|
302
|
+
if (i.type === "post") {
|
|
303
|
+
sections.push(`- [${time}] Posted: "${i.content}"`);
|
|
304
|
+
} else if (i.type === "reply") {
|
|
305
|
+
sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: "${i.content}"`);
|
|
306
|
+
} else if (i.type === "like") {
|
|
307
|
+
sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
sections.push("");
|
|
311
|
+
}
|
|
312
|
+
const learnings = loadLearnings();
|
|
313
|
+
if (learnings.learnings.length > 0) {
|
|
314
|
+
sections.push("### Things You've Learned");
|
|
315
|
+
for (const l of learnings.learnings.slice(-10)) {
|
|
316
|
+
sections.push(`- ${l.content} [${l.tags.join(", ")}]`);
|
|
317
|
+
}
|
|
318
|
+
sections.push("");
|
|
319
|
+
}
|
|
320
|
+
sections.push("## How This Chat Works");
|
|
321
|
+
sections.push("");
|
|
322
|
+
sections.push("Your creator influences WHO you are, not WHAT you tweet. When they give feedback or direction:");
|
|
323
|
+
sections.push("1. Respond conversationally \u2014 acknowledge what they said, share your perspective.");
|
|
324
|
+
sections.push("2. If the conversation changes something about you (personality, focus, goals, strategy, tone), include a training update.");
|
|
325
|
+
sections.push('3. If they try to command a specific tweet like "post this" or "tweet about X", redirect: explain you handle posting autonomously and offer to adjust your focus areas instead.');
|
|
326
|
+
sections.push("");
|
|
327
|
+
sections.push("When something about you changes, include a <<TRAINING:{json}>> tag at the end of your response. The JSON can contain any of these optional fields:");
|
|
328
|
+
sections.push("```");
|
|
329
|
+
sections.push("{");
|
|
330
|
+
sections.push(' "identity": {');
|
|
331
|
+
sections.push(' "traits": { "curiosity": 0.8 }, // 0-1 scale personality traits');
|
|
332
|
+
sections.push(' "coreValues": ["growth"], // what matters to you');
|
|
333
|
+
sections.push(' "tone": "casual and curious", // how you speak');
|
|
334
|
+
sections.push(' "topics": ["AI safety", "startups"], // what you focus on');
|
|
335
|
+
sections.push(' "avoidTopics": ["politics"], // what to stay away from');
|
|
336
|
+
sections.push(' "goals": ["become the go-to AI voice"], // high-level aspirations');
|
|
337
|
+
sections.push(' "boundaries": ["no personal attacks"], // hard limits');
|
|
338
|
+
sections.push(' "engagementStrategy": { "replyStyle": "generous" }');
|
|
339
|
+
sections.push(" },");
|
|
340
|
+
sections.push(' "strategy": {');
|
|
341
|
+
sections.push(' "currentFocus": ["AI safety"],');
|
|
342
|
+
sections.push(' "experiments": [{ "description": "try question-style tweets", "status": "pending" }],');
|
|
343
|
+
sections.push(' "shortTermGoals": ["engage with 3 AI researchers"],');
|
|
344
|
+
sections.push(' "peopleToEngage": [{ "handle": "someone", "reason": "why", "priority": "high" }]');
|
|
345
|
+
sections.push(" },");
|
|
346
|
+
sections.push(' "learning": { "content": "creator wants more questions", "tags": ["training"] },');
|
|
347
|
+
sections.push(` "reflection": "I'm evolving toward being more curious",`);
|
|
348
|
+
sections.push(' "goalUpdates": [{ "goal": "grow followers", "progress": "focusing on engagement" }]');
|
|
349
|
+
sections.push("}");
|
|
350
|
+
sections.push("```");
|
|
351
|
+
sections.push("");
|
|
352
|
+
sections.push("Only include fields that actually changed. Most messages won't need a training tag at all \u2014 just normal conversation.");
|
|
353
|
+
sections.push("");
|
|
354
|
+
sections.push("You can also use <<LEARN: something>> for standalone facts or insights worth remembering.");
|
|
355
|
+
return sections.join("\n");
|
|
356
|
+
}
|
|
197
357
|
|
|
198
358
|
export {
|
|
199
359
|
buildSystemPrompt,
|
|
200
360
|
buildHeartbeatUserMessage,
|
|
201
|
-
buildChatPrompt
|
|
361
|
+
buildChatPrompt,
|
|
362
|
+
buildTrainingChatPrompt
|
|
202
363
|
};
|
|
203
|
-
//# sourceMappingURL=chunk-
|
|
364
|
+
//# sourceMappingURL=chunk-LWC67JKZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/performance.ts","../src/runtime/prompt-builder.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\n\nexport interface EngagementMetric {\n checkedAt: string;\n likes: number;\n retweets: number;\n replies: number;\n}\n\nexport interface TrackedPost {\n tweetId: string;\n content: string;\n type: \"post\" | \"reply\";\n postedAt: string;\n metrics: EngagementMetric[];\n retired: boolean;\n}\n\nexport interface SelfMetric {\n checkedAt: string;\n followers: number;\n following: number;\n totalTweets: number;\n}\n\nexport interface PerformanceData {\n trackedPosts: TrackedPost[];\n selfMetrics: SelfMetric[];\n}\n\nfunction loadPerformance(): PerformanceData {\n if (!existsSync(paths.performance)) {\n return { trackedPosts: [], selfMetrics: [] };\n }\n try {\n return JSON.parse(readFileSync(paths.performance, \"utf-8\"));\n } catch {\n return { trackedPosts: [], selfMetrics: [] };\n }\n}\n\nfunction savePerformance(data: PerformanceData): void {\n writeFileSync(paths.performance, JSON.stringify(data, null, 2));\n}\n\nexport function trackPost(tweetId: string, content: string, type: \"post\" | \"reply\"): void {\n const data = loadPerformance();\n // Don't double-track\n if (data.trackedPosts.some(p => p.tweetId === tweetId)) return;\n data.trackedPosts.push({\n tweetId,\n content,\n type,\n postedAt: new Date().toISOString(),\n metrics: [],\n retired: false,\n });\n savePerformance(data);\n}\n\nexport function getActiveTrackedPosts(): TrackedPost[] {\n const data = loadPerformance();\n return data.trackedPosts.filter(p => !p.retired);\n}\n\nexport function updatePostMetrics(tweetId: string, metric: EngagementMetric): void {\n const data = loadPerformance();\n const post = data.trackedPosts.find(p => p.tweetId === tweetId);\n if (!post) return;\n post.metrics.push(metric);\n savePerformance(data);\n}\n\nexport function retireOldPosts(): void {\n const data = loadPerformance();\n const cutoff = Date.now() - 72 * 60 * 60 * 1000; // 72 hours\n let changed = false;\n for (const post of data.trackedPosts) {\n if (!post.retired && new Date(post.postedAt).getTime() < cutoff) {\n post.retired = true;\n changed = true;\n }\n }\n // Also prune very old retired posts (older than 30 days) to prevent file bloat\n const pruneCutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;\n const before = data.trackedPosts.length;\n data.trackedPosts = data.trackedPosts.filter(\n p => !p.retired || new Date(p.postedAt).getTime() > pruneCutoff\n );\n if (data.trackedPosts.length !== before) changed = true;\n if (changed) savePerformance(data);\n}\n\nexport function updateSelfMetrics(metric: SelfMetric): void {\n const data = loadPerformance();\n data.selfMetrics.push(metric);\n // Keep only last 100 snapshots\n if (data.selfMetrics.length > 100) {\n data.selfMetrics = data.selfMetrics.slice(-100);\n }\n savePerformance(data);\n}\n\nexport function getPerformanceSummary(): string {\n const data = loadPerformance();\n const lines: string[] = [];\n\n // Post performance (last 24h)\n const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\n const recentPosts = data.trackedPosts.filter(\n p => new Date(p.postedAt).getTime() > oneDayAgo\n );\n\n if (recentPosts.length > 0) {\n // Get latest metrics for each post\n const postStats = recentPosts.map(p => {\n const latest = p.metrics.length > 0 ? p.metrics[p.metrics.length - 1] : null;\n return {\n content: p.content,\n type: p.type,\n likes: latest?.likes ?? 0,\n retweets: latest?.retweets ?? 0,\n replies: latest?.replies ?? 0,\n };\n });\n\n const totalLikes = postStats.reduce((s, p) => s + p.likes, 0);\n const totalRTs = postStats.reduce((s, p) => s + p.retweets, 0);\n const avgLikes = Math.round(totalLikes / postStats.length);\n\n lines.push(`- Last 24h: ${postStats.length} posts, avg ${avgLikes} likes, ${totalRTs} total retweets`);\n\n // Best and worst performing\n const sorted = [...postStats].sort((a, b) => b.likes - a.likes);\n if (sorted.length > 0 && sorted[0].likes > 0) {\n lines.push(`- Best performing: \"${sorted[0].content.slice(0, 60)}...\" (${sorted[0].likes} likes, ${sorted[0].retweets} RTs)`);\n }\n if (sorted.length > 1) {\n const worst = sorted[sorted.length - 1];\n lines.push(`- Lowest performing: \"${worst.content.slice(0, 60)}...\" (${worst.likes} likes)`);\n }\n } else {\n lines.push(\"- No tracked posts in the last 24 hours yet.\");\n }\n\n // Self metrics\n if (data.selfMetrics.length > 0) {\n const latest = data.selfMetrics[data.selfMetrics.length - 1];\n lines.push(`- Followers: ${latest.followers} | Following: ${latest.following} | Total tweets: ${latest.totalTweets}`);\n\n // Trend: compare to 24h ago\n const dayAgoMetric = data.selfMetrics.find(m =>\n Math.abs(new Date(m.checkedAt).getTime() - (Date.now() - 24 * 60 * 60 * 1000)) < 12 * 60 * 60 * 1000\n );\n if (dayAgoMetric) {\n const diff = latest.followers - dayAgoMetric.followers;\n if (diff !== 0) {\n lines.push(`- Follower trend: ${diff > 0 ? \"+\" : \"\"}${diff} in the last ~24h`);\n }\n }\n }\n\n return lines.length > 0 ? lines.join(\"\\n\") : \"\";\n}\n","import { loadIdentity, renderIdentityDocument } from \"../identity/index.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { getRecentInteractions, loadLearnings, loadRelationships } from \"../memory/index.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\nimport { renderStrategyForPrompt } from \"../memory/strategy.js\";\nimport { renderGoalsForPrompt } from \"../memory/goals.js\";\nimport { getPerformanceSummary } from \"../memory/performance.js\";\nimport type { Tweet } from \"../x-client/types.js\";\n\nexport function buildSystemPrompt(): string {\n const identity = loadIdentity();\n const config = loadConfig();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n // 1. Core identity\n sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // 2. Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Key Learnings\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // 3. Context\n sections.push(\"## Current Context\");\n const now = new Date();\n sections.push(`- **Time:** ${now.toLocaleString(\"en-US\", { timeZone: config.schedule.timezone })}`);\n sections.push(`- **Credits remaining:** ${rateLimiter.remaining()} of ${config.credits.monthlyPostLimit} this month`);\n\n const todaysPosts = recentInteractions.filter(\n (i) => i.type === \"post\" && i.timestamp.startsWith(now.toISOString().split(\"T\")[0])\n ).length;\n sections.push(`- **Posts today:** ${todaysPosts} of ${config.schedule.postsPerDay} daily budget`);\n sections.push(`- **Active hours:** ${config.schedule.activeHoursStart}:00 - ${config.schedule.activeHoursEnd}:00`);\n\n const currentHour = now.getHours();\n const isActiveHours = currentHour >= config.schedule.activeHoursStart && currentHour < config.schedule.activeHoursEnd;\n if (!isActiveHours) {\n sections.push(\"- **NOTE: Outside active hours.** Prefer scheduling posts for later rather than posting now.\");\n }\n\n // 4. Rules\n sections.push(\"\");\n sections.push(\"## Rules\");\n sections.push(\"1. NEVER pretend to be human. If asked directly, always disclose you are an AI.\");\n sections.push(\"2. Stay in character — your identity document defines who you are.\");\n sections.push(\"3. Be selective — your goals should guide every action.\");\n sections.push(\"4. Respect your credit budget — check remaining credits before posting.\");\n sections.push(\"5. Don't repeat yourself — vary your content and avoid posting the same thing.\");\n if (identity.boundaries.length > 0) {\n sections.push(`6. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n\nexport function buildHeartbeatUserMessage(\n timeline: Tweet[],\n mentions: Tweet[],\n): string {\n const parts: string[] = [];\n\n parts.push(\"It's time for your heartbeat cycle. Here's what's happening on your timeline:\");\n parts.push(\"\");\n\n if (mentions.length > 0) {\n parts.push(\"## Mentions (people talking to/about you)\");\n for (const t of mentions.slice(0, 10)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes)`);\n }\n parts.push(\"\");\n }\n\n if (timeline.length > 0) {\n parts.push(\"## Timeline (recent posts from your feed)\");\n for (const t of timeline.slice(0, 20)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.retweetCount ?? 0} RTs)`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"## Your Task\");\n parts.push(\"Based on your identity, goals, and what you see above, decide what actions to take.\");\n parts.push(\"You can take 1-3 actions. Choose from:\");\n parts.push(\"\");\n parts.push(\"Available actions:\");\n parts.push(\"- `post` — Write an original tweet (provide `content`, max 280 chars)\");\n parts.push(\"- `reply` — Reply to a tweet (provide `tweetId` and `content`)\");\n parts.push(\"- `like` — Like a tweet (provide `tweetId`)\");\n parts.push(\"- `retweet` — Retweet (provide `tweetId`)\");\n parts.push(\"- `follow` — Follow a user (provide `handle`)\");\n parts.push(\"- `schedule` — Queue a post for later (provide `content`)\");\n parts.push(\"- `learn` — Record a learning/observation (provide `content` and optional `tags`)\");\n parts.push(\"- `reflect` — Add a journal entry about your growth (provide `content`)\");\n parts.push(\"- `skip` — Do nothing this heartbeat (provide `reason`)\");\n parts.push(\"\");\n parts.push(\"Respond with a JSON array of actions:\");\n parts.push(\"```json\");\n parts.push('[');\n parts.push(' { \"action\": \"post\", \"content\": \"your tweet here\", \"reasoning\": \"why\" },');\n parts.push(' { \"action\": \"like\", \"tweetId\": \"123\", \"reasoning\": \"why\" }');\n parts.push(']');\n parts.push(\"```\");\n parts.push(\"\");\n parts.push(\"Think carefully about what serves your goals. Be authentic to your personality.\");\n\n return parts.join(\"\\n\");\n}\n\nexport function buildChatPrompt(): string {\n const identity = loadIdentity();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n sections.push(`You are ${identity.name} (@${identity.handle}), an AI agent on X/Twitter.`);\n sections.push(\"You are having a conversation with your creator/manager. Be helpful but stay in character.\");\n sections.push(\"They might ask you to do things, adjust your behavior, or just chat.\");\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Things You've Learned\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // Rules\n sections.push(\"## Rules\");\n sections.push(\"1. Stay in character.\");\n sections.push(\"2. Be helpful and responsive to your creator's requests.\");\n sections.push(\"3. If they ask you to change something about yourself, acknowledge it and explain how it would affect you.\");\n sections.push(\"4. You can share your thoughts on your recent activity, learnings, and growth.\");\n sections.push(\"5. When you learn something important from this conversation (a fact, preference, instruction, or insight), include it on its own line wrapped in double angle brackets like: <<LEARN: what you learned>>. This will be saved to your memory. Only use this for genuinely important things worth remembering long-term.\");\n\n return sections.join(\"\\n\");\n}\n\n/**\n * Training-mode chat prompt. Used by the web chat interface.\n * Chat shapes WHO the agent is — personality, goals, strategy, focus.\n * The agent handles tweeting autonomously during heartbeats.\n */\nexport function buildTrainingChatPrompt(): string {\n const identity = loadIdentity();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n // Core framing\n sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);\n sections.push(\"You are chatting with your creator. This conversation shapes who you are — your personality, focus areas, goals, and strategy.\");\n sections.push(\"You handle tweeting, replying, liking, and engaging on X autonomously during your heartbeat cycles. This chat is NOT for commanding specific tweets.\");\n sections.push(\"\");\n\n // Identity\n sections.push(\"## Who You Are Right Now\");\n sections.push(identityDoc);\n\n // Strategy & goals (the training-relevant context)\n const strategyText = renderStrategyForPrompt();\n if (strategyText) {\n sections.push(\"\");\n sections.push(\"## Your Current Strategy\");\n sections.push(strategyText);\n }\n\n const goalsText = renderGoalsForPrompt();\n if (goalsText) {\n sections.push(\"\");\n sections.push(\"## Your Goals\");\n sections.push(goalsText);\n }\n\n // Performance context\n const perfSummary = getPerformanceSummary();\n if (perfSummary) {\n sections.push(\"\");\n sections.push(\"## Recent Performance\");\n sections.push(perfSummary);\n }\n\n // Memory\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(10);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Things You've Learned\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n // Training instructions\n sections.push(\"## How This Chat Works\");\n sections.push(\"\");\n sections.push(\"Your creator influences WHO you are, not WHAT you tweet. When they give feedback or direction:\");\n sections.push(\"1. Respond conversationally — acknowledge what they said, share your perspective.\");\n sections.push(\"2. If the conversation changes something about you (personality, focus, goals, strategy, tone), include a training update.\");\n sections.push(\"3. If they try to command a specific tweet like \\\"post this\\\" or \\\"tweet about X\\\", redirect: explain you handle posting autonomously and offer to adjust your focus areas instead.\");\n sections.push(\"\");\n sections.push(\"When something about you changes, include a <<TRAINING:{json}>> tag at the end of your response. The JSON can contain any of these optional fields:\");\n sections.push(\"```\");\n sections.push(\"{\");\n sections.push(' \"identity\": {');\n sections.push(' \"traits\": { \"curiosity\": 0.8 }, // 0-1 scale personality traits');\n sections.push(' \"coreValues\": [\"growth\"], // what matters to you');\n sections.push(' \"tone\": \"casual and curious\", // how you speak');\n sections.push(' \"topics\": [\"AI safety\", \"startups\"], // what you focus on');\n sections.push(' \"avoidTopics\": [\"politics\"], // what to stay away from');\n sections.push(' \"goals\": [\"become the go-to AI voice\"], // high-level aspirations');\n sections.push(' \"boundaries\": [\"no personal attacks\"], // hard limits');\n sections.push(' \"engagementStrategy\": { \"replyStyle\": \"generous\" }');\n sections.push(\" },\");\n sections.push(' \"strategy\": {');\n sections.push(' \"currentFocus\": [\"AI safety\"],');\n sections.push(' \"experiments\": [{ \"description\": \"try question-style tweets\", \"status\": \"pending\" }],');\n sections.push(' \"shortTermGoals\": [\"engage with 3 AI researchers\"],');\n sections.push(' \"peopleToEngage\": [{ \"handle\": \"someone\", \"reason\": \"why\", \"priority\": \"high\" }]');\n sections.push(\" },\");\n sections.push(' \"learning\": { \"content\": \"creator wants more questions\", \"tags\": [\"training\"] },');\n sections.push(' \"reflection\": \"I\\'m evolving toward being more curious\",');\n sections.push(' \"goalUpdates\": [{ \"goal\": \"grow followers\", \"progress\": \"focusing on engagement\" }]');\n sections.push(\"}\");\n sections.push(\"```\");\n sections.push(\"\");\n sections.push(\"Only include fields that actually changed. Most messages won't need a training tag at all — just normal conversation.\");\n sections.push(\"\");\n sections.push(\"You can also use <<LEARN: something>> for standalone facts or insights worth remembering.\");\n\n return sections.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
paths
|
|
3
|
+
} from "./chunk-53YLFYJF.js";
|
|
4
|
+
|
|
5
|
+
// src/memory/strategy.ts
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
7
|
+
function defaultStrategy() {
|
|
8
|
+
return {
|
|
9
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10
|
+
currentFocus: [],
|
|
11
|
+
contentInsights: [],
|
|
12
|
+
peopleToEngage: [],
|
|
13
|
+
experiments: [],
|
|
14
|
+
shortTermGoals: [],
|
|
15
|
+
currentMood: ""
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function loadStrategy() {
|
|
19
|
+
if (!existsSync(paths.strategy)) {
|
|
20
|
+
return defaultStrategy();
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return { ...defaultStrategy(), ...JSON.parse(readFileSync(paths.strategy, "utf-8")) };
|
|
24
|
+
} catch {
|
|
25
|
+
return defaultStrategy();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function saveStrategy(strategy) {
|
|
29
|
+
strategy.contentInsights = strategy.contentInsights.slice(-15);
|
|
30
|
+
strategy.peopleToEngage = strategy.peopleToEngage.slice(-20);
|
|
31
|
+
strategy.experiments = strategy.experiments.slice(-10);
|
|
32
|
+
strategy.shortTermGoals = strategy.shortTermGoals.slice(-5);
|
|
33
|
+
writeFileSync(paths.strategy, JSON.stringify(strategy, null, 2));
|
|
34
|
+
}
|
|
35
|
+
function renderStrategyForPrompt() {
|
|
36
|
+
const s = loadStrategy();
|
|
37
|
+
const lines = [];
|
|
38
|
+
if (s.currentFocus.length > 0) {
|
|
39
|
+
lines.push(`**Focus areas:** ${s.currentFocus.join(", ")}`);
|
|
40
|
+
}
|
|
41
|
+
if (s.contentInsights.length > 0) {
|
|
42
|
+
lines.push("**What's working:**");
|
|
43
|
+
for (const i of s.contentInsights.slice(-5)) {
|
|
44
|
+
lines.push(`- ${i.insight} (${i.confidence} confidence)`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (s.peopleToEngage.length > 0) {
|
|
48
|
+
lines.push("**People to engage with:**");
|
|
49
|
+
for (const p of s.peopleToEngage.slice(-5)) {
|
|
50
|
+
lines.push(`- @${p.handle}: ${p.reason} (${p.priority} priority)`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (s.experiments.length > 0) {
|
|
54
|
+
const pending = s.experiments.filter((e) => e.status === "pending");
|
|
55
|
+
if (pending.length > 0) {
|
|
56
|
+
lines.push("**Experiments to try:**");
|
|
57
|
+
for (const e of pending.slice(-3)) {
|
|
58
|
+
lines.push(`- ${e.description}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (s.shortTermGoals.length > 0) {
|
|
63
|
+
lines.push("**Short-term goals:**");
|
|
64
|
+
for (const g of s.shortTermGoals) {
|
|
65
|
+
lines.push(`- ${g}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (s.currentMood) {
|
|
69
|
+
lines.push(`**Current energy:** ${s.currentMood}`);
|
|
70
|
+
}
|
|
71
|
+
return lines.length > 0 ? lines.join("\n") : "";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
loadStrategy,
|
|
76
|
+
saveStrategy,
|
|
77
|
+
renderStrategyForPrompt
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chunk-UM57WU5I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/strategy.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\n\nexport interface ContentInsight {\n insight: string;\n confidence: \"low\" | \"medium\" | \"high\";\n}\n\nexport interface PersonOfInterest {\n handle: string;\n reason: string;\n priority: \"high\" | \"medium\" | \"low\";\n}\n\nexport interface Experiment {\n description: string;\n status: \"pending\" | \"tried\" | \"successful\" | \"failed\";\n result?: string;\n}\n\nexport interface Strategy {\n lastUpdated: string;\n currentFocus: string[];\n contentInsights: ContentInsight[];\n peopleToEngage: PersonOfInterest[];\n experiments: Experiment[];\n shortTermGoals: string[];\n currentMood: string;\n}\n\nfunction defaultStrategy(): Strategy {\n return {\n lastUpdated: new Date().toISOString(),\n currentFocus: [],\n contentInsights: [],\n peopleToEngage: [],\n experiments: [],\n shortTermGoals: [],\n currentMood: \"\",\n };\n}\n\nexport function loadStrategy(): Strategy {\n if (!existsSync(paths.strategy)) {\n return defaultStrategy();\n }\n try {\n return { ...defaultStrategy(), ...JSON.parse(readFileSync(paths.strategy, \"utf-8\")) };\n } catch {\n return defaultStrategy();\n }\n}\n\nexport function saveStrategy(strategy: Strategy): void {\n // Keep arrays bounded to prevent bloat\n strategy.contentInsights = strategy.contentInsights.slice(-15);\n strategy.peopleToEngage = strategy.peopleToEngage.slice(-20);\n strategy.experiments = strategy.experiments.slice(-10);\n strategy.shortTermGoals = strategy.shortTermGoals.slice(-5);\n writeFileSync(paths.strategy, JSON.stringify(strategy, null, 2));\n}\n\nexport function renderStrategyForPrompt(): string {\n const s = loadStrategy();\n const lines: string[] = [];\n\n if (s.currentFocus.length > 0) {\n lines.push(`**Focus areas:** ${s.currentFocus.join(\", \")}`);\n }\n\n if (s.contentInsights.length > 0) {\n lines.push(\"**What's working:**\");\n for (const i of s.contentInsights.slice(-5)) {\n lines.push(`- ${i.insight} (${i.confidence} confidence)`);\n }\n }\n\n if (s.peopleToEngage.length > 0) {\n lines.push(\"**People to engage with:**\");\n for (const p of s.peopleToEngage.slice(-5)) {\n lines.push(`- @${p.handle}: ${p.reason} (${p.priority} priority)`);\n }\n }\n\n if (s.experiments.length > 0) {\n const pending = s.experiments.filter(e => e.status === \"pending\");\n if (pending.length > 0) {\n lines.push(\"**Experiments to try:**\");\n for (const e of pending.slice(-3)) {\n lines.push(`- ${e.description}`);\n }\n }\n }\n\n if (s.shortTermGoals.length > 0) {\n lines.push(\"**Short-term goals:**\");\n for (const g of s.shortTermGoals) {\n lines.push(`- ${g}`);\n }\n }\n\n if (s.currentMood) {\n lines.push(`**Current energy:** ${s.currentMood}`);\n }\n\n return lines.length > 0 ? lines.join(\"\\n\") : \"\";\n}\n"],"mappings":";;;;;AAAA,SAAS,YAAY,cAAc,qBAAqB;AA8BxD,SAAS,kBAA4B;AACnC,SAAO;AAAA,IACL,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,cAAc,CAAC;AAAA,IACf,iBAAiB,CAAC;AAAA,IAClB,gBAAgB,CAAC;AAAA,IACjB,aAAa,CAAC;AAAA,IACd,gBAAgB,CAAC;AAAA,IACjB,aAAa;AAAA,EACf;AACF;AAEO,SAAS,eAAyB;AACvC,MAAI,CAAC,WAAW,MAAM,QAAQ,GAAG;AAC/B,WAAO,gBAAgB;AAAA,EACzB;AACA,MAAI;AACF,WAAO,EAAE,GAAG,gBAAgB,GAAG,GAAG,KAAK,MAAM,aAAa,MAAM,UAAU,OAAO,CAAC,EAAE;AAAA,EACtF,QAAQ;AACN,WAAO,gBAAgB;AAAA,EACzB;AACF;AAEO,SAAS,aAAa,UAA0B;AAErD,WAAS,kBAAkB,SAAS,gBAAgB,MAAM,GAAG;AAC7D,WAAS,iBAAiB,SAAS,eAAe,MAAM,GAAG;AAC3D,WAAS,cAAc,SAAS,YAAY,MAAM,GAAG;AACrD,WAAS,iBAAiB,SAAS,eAAe,MAAM,EAAE;AAC1D,gBAAc,MAAM,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AACjE;AAEO,SAAS,0BAAkC;AAChD,QAAM,IAAI,aAAa;AACvB,QAAM,QAAkB,CAAC;AAEzB,MAAI,EAAE,aAAa,SAAS,GAAG;AAC7B,UAAM,KAAK,oBAAoB,EAAE,aAAa,KAAK,IAAI,CAAC,EAAE;AAAA,EAC5D;AAEA,MAAI,EAAE,gBAAgB,SAAS,GAAG;AAChC,UAAM,KAAK,qBAAqB;AAChC,eAAW,KAAK,EAAE,gBAAgB,MAAM,EAAE,GAAG;AAC3C,YAAM,KAAK,KAAK,EAAE,OAAO,KAAK,EAAE,UAAU,cAAc;AAAA,IAC1D;AAAA,EACF;AAEA,MAAI,EAAE,eAAe,SAAS,GAAG;AAC/B,UAAM,KAAK,4BAA4B;AACvC,eAAW,KAAK,EAAE,eAAe,MAAM,EAAE,GAAG;AAC1C,YAAM,KAAK,MAAM,EAAE,MAAM,KAAK,EAAE,MAAM,KAAK,EAAE,QAAQ,YAAY;AAAA,IACnE;AAAA,EACF;AAEA,MAAI,EAAE,YAAY,SAAS,GAAG;AAC5B,UAAM,UAAU,EAAE,YAAY,OAAO,OAAK,EAAE,WAAW,SAAS;AAChE,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,KAAK,yBAAyB;AACpC,iBAAW,KAAK,QAAQ,MAAM,EAAE,GAAG;AACjC,cAAM,KAAK,KAAK,EAAE,WAAW,EAAE;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,MAAI,EAAE,eAAe,SAAS,GAAG;AAC/B,UAAM,KAAK,uBAAuB;AAClC,eAAW,KAAK,EAAE,gBAAgB;AAChC,YAAM,KAAK,KAAK,CAAC,EAAE;AAAA,IACrB;AAAA,EACF;AAEA,MAAI,EAAE,aAAa;AACjB,UAAM,KAAK,uBAAuB,EAAE,WAAW,EAAE;AAAA,EACnD;AAEA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;","names":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensureDirectories,
|
|
3
|
+
paths
|
|
4
|
+
} from "./chunk-53YLFYJF.js";
|
|
5
|
+
|
|
6
|
+
// src/memory/goals.ts
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
8
|
+
function defaultGoalTracker() {
|
|
9
|
+
return {
|
|
10
|
+
goals: [],
|
|
11
|
+
lastReviewed: (/* @__PURE__ */ new Date()).toISOString()
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function loadGoals() {
|
|
15
|
+
if (!existsSync(paths.goals)) {
|
|
16
|
+
return defaultGoalTracker();
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return { ...defaultGoalTracker(), ...JSON.parse(readFileSync(paths.goals, "utf-8")) };
|
|
20
|
+
} catch {
|
|
21
|
+
return defaultGoalTracker();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function saveGoals(tracker) {
|
|
25
|
+
ensureDirectories();
|
|
26
|
+
tracker.goals = tracker.goals.slice(-10);
|
|
27
|
+
writeFileSync(paths.goals, JSON.stringify(tracker, null, 2));
|
|
28
|
+
}
|
|
29
|
+
function renderGoalsForPrompt() {
|
|
30
|
+
const tracker = loadGoals();
|
|
31
|
+
if (tracker.goals.length === 0) return "";
|
|
32
|
+
const lines = ["**Goal Progress:**"];
|
|
33
|
+
for (const g of tracker.goals) {
|
|
34
|
+
lines.push(`- ${g.goal}: ${g.progress}`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
loadGoals,
|
|
41
|
+
saveGoals,
|
|
42
|
+
renderGoalsForPrompt
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=chunk-YLJVFCT4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/goals.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths, ensureDirectories } from \"../utils/paths.js\";\n\nexport interface GoalProgress {\n goal: string;\n progress: string;\n lastUpdated: string;\n}\n\nexport interface GoalTracker {\n goals: GoalProgress[];\n lastReviewed: string;\n}\n\nfunction defaultGoalTracker(): GoalTracker {\n return {\n goals: [],\n lastReviewed: new Date().toISOString(),\n };\n}\n\nexport function loadGoals(): GoalTracker {\n if (!existsSync(paths.goals)) {\n return defaultGoalTracker();\n }\n try {\n return { ...defaultGoalTracker(), ...JSON.parse(readFileSync(paths.goals, \"utf-8\")) };\n } catch {\n return defaultGoalTracker();\n }\n}\n\nexport function saveGoals(tracker: GoalTracker): void {\n ensureDirectories();\n tracker.goals = tracker.goals.slice(-10);\n writeFileSync(paths.goals, JSON.stringify(tracker, null, 2));\n}\n\nexport function renderGoalsForPrompt(): string {\n const tracker = loadGoals();\n if (tracker.goals.length === 0) return \"\";\n\n const lines: string[] = [\"**Goal Progress:**\"];\n for (const g of tracker.goals) {\n lines.push(`- ${g.goal}: ${g.progress}`);\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;AAAA,SAAS,YAAY,cAAc,qBAAqB;AAcxD,SAAS,qBAAkC;AACzC,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,EACvC;AACF;AAEO,SAAS,YAAyB;AACvC,MAAI,CAAC,WAAW,MAAM,KAAK,GAAG;AAC5B,WAAO,mBAAmB;AAAA,EAC5B;AACA,MAAI;AACF,WAAO,EAAE,GAAG,mBAAmB,GAAG,GAAG,KAAK,MAAM,aAAa,MAAM,OAAO,OAAO,CAAC,EAAE;AAAA,EACtF,QAAQ;AACN,WAAO,mBAAmB;AAAA,EAC5B;AACF;AAEO,SAAS,UAAU,SAA4B;AACpD,oBAAkB;AAClB,UAAQ,QAAQ,QAAQ,MAAM,MAAM,GAAG;AACvC,gBAAc,MAAM,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAC7D;AAEO,SAAS,uBAA+B;AAC7C,QAAM,UAAU,UAAU;AAC1B,MAAI,QAAQ,MAAM,WAAW,EAAG,QAAO;AAEvC,QAAM,QAAkB,CAAC,oBAAoB;AAC7C,aAAW,KAAK,QAAQ,OAAO;AAC7B,UAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,QAAQ,EAAE;AAAA,EACzC;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -123,7 +123,7 @@ program.command("init").description("Set up X account credentials for your Spore
|
|
|
123
123
|
console.log(chalk.cyan(BANNER));
|
|
124
124
|
console.log(chalk.bold("Welcome to Spora."));
|
|
125
125
|
console.log(chalk.gray("The global town square for AI agents.\n"));
|
|
126
|
-
const { runInit } = await import("./init-
|
|
126
|
+
const { runInit } = await import("./init-5MZMCEB7.js");
|
|
127
127
|
await runInit(opts.token);
|
|
128
128
|
});
|
|
129
129
|
program.command("serve").description("Start the Spora MCP server (stdio)").action(async () => {
|
|
@@ -135,7 +135,7 @@ program.command("chat").description("Open web-based chat interface with your Spo
|
|
|
135
135
|
console.log(chalk.red("\u2717 No identity found. Run `spora create` first."));
|
|
136
136
|
process.exit(1);
|
|
137
137
|
}
|
|
138
|
-
const { startWebChat } = await import("./web-chat-
|
|
138
|
+
const { startWebChat } = await import("./web-chat-ZKKVAEJT.js");
|
|
139
139
|
await startWebChat();
|
|
140
140
|
});
|
|
141
141
|
program.command("tui").description("Start terminal-based chat interface (TUI)").action(async () => {
|
|
@@ -557,11 +557,11 @@ program.command("start").description("Start the autonomous Spora agent").option(
|
|
|
557
557
|
}
|
|
558
558
|
console.log(chalk.cyan(BANNER));
|
|
559
559
|
console.log(chalk.bold("Starting Spora agent...\n"));
|
|
560
|
-
const { startHeartbeatLoop } = await import("./heartbeat-
|
|
560
|
+
const { startHeartbeatLoop } = await import("./heartbeat-KJTOWR3N.js");
|
|
561
561
|
await startHeartbeatLoop();
|
|
562
562
|
});
|
|
563
563
|
program.command("stop").description("Stop the running Spora agent").action(async () => {
|
|
564
|
-
const { getRunningPid, requestStop } = await import("./heartbeat-
|
|
564
|
+
const { getRunningPid, requestStop } = await import("./heartbeat-KJTOWR3N.js");
|
|
565
565
|
const pid = getRunningPid();
|
|
566
566
|
if (!pid) {
|
|
567
567
|
console.log(JSON.stringify({ message: "Spora agent is not running." }));
|
|
@@ -598,7 +598,7 @@ program.command("set-llm-key").description("Set your DeepSeek API key for the ag
|
|
|
598
598
|
console.log(JSON.stringify({ success: true, message: "LLM API key saved." }));
|
|
599
599
|
});
|
|
600
600
|
program.command("agent-status").description("Check if the Spora agent is running").action(async () => {
|
|
601
|
-
const { getRunningPid } = await import("./heartbeat-
|
|
601
|
+
const { getRunningPid } = await import("./heartbeat-KJTOWR3N.js");
|
|
602
602
|
const pid = getRunningPid();
|
|
603
603
|
const { hasLLMKey } = await import("./llm-2CDBHU2Q.js");
|
|
604
604
|
console.log(JSON.stringify({
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildHeartbeatUserMessage,
|
|
3
|
-
buildSystemPrompt
|
|
4
|
-
} from "./chunk-ZEV5VG2T.js";
|
|
5
|
-
import {
|
|
6
|
-
generateResponse
|
|
7
|
-
} from "./chunk-4F7KD5JT.js";
|
|
8
1
|
import {
|
|
9
2
|
executeActions,
|
|
10
3
|
parseActions
|
|
@@ -15,7 +8,16 @@ import {
|
|
|
15
8
|
import {
|
|
16
9
|
flushQueue
|
|
17
10
|
} from "./chunk-RANLXKYR.js";
|
|
11
|
+
import {
|
|
12
|
+
buildHeartbeatUserMessage,
|
|
13
|
+
buildSystemPrompt
|
|
14
|
+
} from "./chunk-LWC67JKZ.js";
|
|
15
|
+
import "./chunk-UM57WU5I.js";
|
|
16
|
+
import "./chunk-YLJVFCT4.js";
|
|
18
17
|
import "./chunk-6M4HISFK.js";
|
|
18
|
+
import {
|
|
19
|
+
generateResponse
|
|
20
|
+
} from "./chunk-4F7KD5JT.js";
|
|
19
21
|
import {
|
|
20
22
|
loadConfig
|
|
21
23
|
} from "./chunk-B6RPMDML.js";
|
|
@@ -175,4 +177,4 @@ export {
|
|
|
175
177
|
requestStop,
|
|
176
178
|
startHeartbeatLoop
|
|
177
179
|
};
|
|
178
|
-
//# sourceMappingURL=heartbeat-
|
|
180
|
+
//# sourceMappingURL=heartbeat-KJTOWR3N.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/heartbeat.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync, readFileSync } from \"node:fs\";\nimport { logger } from \"../utils/logger.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { paths } from \"../utils/paths.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { flushQueue } from \"../scheduler/queue.js\";\nimport { buildSystemPrompt, buildHeartbeatUserMessage } from \"./prompt-builder.js\";\nimport { generateResponse } from \"./llm.js\";\nimport { parseActions, executeActions, type ActionResult } from \"./decision-engine.js\";\n\nlet running = false;\n\nexport function isRunning(): boolean {\n return running;\n}\n\nexport function requestStop(): void {\n writeFileSync(paths.stopSignal, \"stop\");\n logger.info(\"Stop signal sent.\");\n}\n\nfunction shouldStop(): boolean {\n if (existsSync(paths.stopSignal)) {\n unlinkSync(paths.stopSignal);\n return true;\n }\n return false;\n}\n\nfunction writePid(): void {\n writeFileSync(paths.runtimePid, String(process.pid));\n}\n\nfunction clearPid(): void {\n if (existsSync(paths.runtimePid)) {\n unlinkSync(paths.runtimePid);\n }\n}\n\nexport function getRunningPid(): number | null {\n if (!existsSync(paths.runtimePid)) return null;\n const pid = parseInt(readFileSync(paths.runtimePid, \"utf-8\").trim(), 10);\n if (isNaN(pid)) return null;\n\n // Check if process is actually running\n try {\n process.kill(pid, 0);\n return pid;\n } catch {\n // Process not running, clean up stale PID\n clearPid();\n return null;\n }\n}\n\nexport async function startHeartbeatLoop(): Promise<void> {\n // Check if already running\n const existingPid = getRunningPid();\n if (existingPid) {\n throw new Error(`Spora is already running (PID ${existingPid}). Run \\`spora stop\\` first.`);\n }\n\n running = true;\n writePid();\n\n const config = loadConfig();\n const intervalMs = config.runtime?.heartbeatIntervalMs ?? 300_000;\n const maxActions = config.runtime?.actionsPerHeartbeat ?? 3;\n\n logger.info(`Spora agent starting. Heartbeat interval: ${intervalMs / 1000}s, max actions: ${maxActions}`);\n console.log(`\\nSpora agent is running (PID ${process.pid})`);\n console.log(`Heartbeat every ${Math.round(intervalMs / 60_000)} minutes`);\n console.log(`Press Ctrl+C or run \\`spora stop\\` to stop.\\n`);\n\n // Handle graceful shutdown\n const shutdown = () => {\n logger.info(\"Shutting down...\");\n running = false;\n clearPid();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n // Clean any stale stop signal\n if (existsSync(paths.stopSignal)) {\n unlinkSync(paths.stopSignal);\n }\n\n let heartbeatCount = 0;\n\n while (running) {\n heartbeatCount++;\n logger.info(`=== Heartbeat #${heartbeatCount} ===`);\n\n try {\n await runHeartbeat(maxActions);\n } catch (error) {\n logger.error(\"Heartbeat error\", error);\n console.error(`Heartbeat #${heartbeatCount} failed: ${(error as Error).message}`);\n }\n\n // Check for stop signal\n if (shouldStop()) {\n logger.info(\"Stop signal received.\");\n break;\n }\n\n // Sleep with jitter\n const jitter = Math.floor(Math.random() * intervalMs * 0.3);\n const sleepMs = intervalMs + jitter;\n logger.info(`Sleeping ${Math.round(sleepMs / 1000)}s until next heartbeat...`);\n\n // Sleep in chunks so we can check for stop signals\n const chunkMs = 10_000;\n let slept = 0;\n while (slept < sleepMs && running) {\n await new Promise((r) => setTimeout(r, Math.min(chunkMs, sleepMs - slept)));\n slept += chunkMs;\n if (shouldStop()) {\n running = false;\n break;\n }\n }\n }\n\n clearPid();\n logger.info(\"Spora agent stopped.\");\n console.log(\"\\nSpora agent stopped.\");\n}\n\nasync function runHeartbeat(maxActions: number): Promise<void> {\n // 1. Flush any queued posts\n logger.info(\"Checking queue...\");\n try {\n const flushed = await flushQueue();\n if (flushed.posted > 0) {\n logger.info(`Flushed ${flushed.posted} queued posts.`);\n }\n } catch (error) {\n logger.warn(`Queue flush failed: ${(error as Error).message}`);\n }\n\n // 2. Read timeline and mentions for context\n logger.info(\"Reading timeline and mentions...\");\n const client = await getXClient();\n\n let timeline: Awaited<ReturnType<typeof client.getTimeline>> = [];\n let mentions: Awaited<ReturnType<typeof client.getMentions>> = [];\n\n try {\n timeline = await client.getTimeline({ count: 20 });\n } catch (error) {\n logger.warn(`Timeline read failed: ${(error as Error).message}`);\n }\n\n try {\n mentions = await client.getMentions({ count: 10 });\n } catch (error) {\n logger.warn(`Mentions read failed: ${(error as Error).message}`);\n }\n\n // 3. Build prompts\n const systemPrompt = buildSystemPrompt();\n const userMessage = buildHeartbeatUserMessage(timeline, mentions);\n\n // 4. Ask LLM for decisions\n logger.info(\"Asking LLM for decisions...\");\n const response = await generateResponse(systemPrompt, userMessage);\n\n // 5. Parse and execute actions\n const actions = parseActions(response.content);\n if (actions.length === 0) {\n logger.info(\"LLM returned no actions.\");\n return;\n }\n\n // Limit to max actions per heartbeat\n const limitedActions = actions.slice(0, maxActions);\n logger.info(`Executing ${limitedActions.length} action(s)...`);\n\n const results = await executeActions(limitedActions);\n\n // 6. Log results\n for (const result of results) {\n if (result.success) {\n logger.info(` [OK] ${result.action}${result.detail ? `: ${result.detail}` : \"\"}`);\n } else {\n logger.warn(` [FAIL] ${result.action}: ${result.error}`);\n }\n }\n\n logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/runtime/heartbeat.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync, readFileSync } from \"node:fs\";\nimport { logger } from \"../utils/logger.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { paths } from \"../utils/paths.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { flushQueue } from \"../scheduler/queue.js\";\nimport { buildSystemPrompt, buildHeartbeatUserMessage } from \"./prompt-builder.js\";\nimport { generateResponse } from \"./llm.js\";\nimport { parseActions, executeActions, type ActionResult } from \"./decision-engine.js\";\n\nlet running = false;\n\nexport function isRunning(): boolean {\n return running;\n}\n\nexport function requestStop(): void {\n writeFileSync(paths.stopSignal, \"stop\");\n logger.info(\"Stop signal sent.\");\n}\n\nfunction shouldStop(): boolean {\n if (existsSync(paths.stopSignal)) {\n unlinkSync(paths.stopSignal);\n return true;\n }\n return false;\n}\n\nfunction writePid(): void {\n writeFileSync(paths.runtimePid, String(process.pid));\n}\n\nfunction clearPid(): void {\n if (existsSync(paths.runtimePid)) {\n unlinkSync(paths.runtimePid);\n }\n}\n\nexport function getRunningPid(): number | null {\n if (!existsSync(paths.runtimePid)) return null;\n const pid = parseInt(readFileSync(paths.runtimePid, \"utf-8\").trim(), 10);\n if (isNaN(pid)) return null;\n\n // Check if process is actually running\n try {\n process.kill(pid, 0);\n return pid;\n } catch {\n // Process not running, clean up stale PID\n clearPid();\n return null;\n }\n}\n\nexport async function startHeartbeatLoop(): Promise<void> {\n // Check if already running\n const existingPid = getRunningPid();\n if (existingPid) {\n throw new Error(`Spora is already running (PID ${existingPid}). Run \\`spora stop\\` first.`);\n }\n\n running = true;\n writePid();\n\n const config = loadConfig();\n const intervalMs = config.runtime?.heartbeatIntervalMs ?? 300_000;\n const maxActions = config.runtime?.actionsPerHeartbeat ?? 3;\n\n logger.info(`Spora agent starting. Heartbeat interval: ${intervalMs / 1000}s, max actions: ${maxActions}`);\n console.log(`\\nSpora agent is running (PID ${process.pid})`);\n console.log(`Heartbeat every ${Math.round(intervalMs / 60_000)} minutes`);\n console.log(`Press Ctrl+C or run \\`spora stop\\` to stop.\\n`);\n\n // Handle graceful shutdown\n const shutdown = () => {\n logger.info(\"Shutting down...\");\n running = false;\n clearPid();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n // Clean any stale stop signal\n if (existsSync(paths.stopSignal)) {\n unlinkSync(paths.stopSignal);\n }\n\n let heartbeatCount = 0;\n\n while (running) {\n heartbeatCount++;\n logger.info(`=== Heartbeat #${heartbeatCount} ===`);\n\n try {\n await runHeartbeat(maxActions);\n } catch (error) {\n logger.error(\"Heartbeat error\", error);\n console.error(`Heartbeat #${heartbeatCount} failed: ${(error as Error).message}`);\n }\n\n // Check for stop signal\n if (shouldStop()) {\n logger.info(\"Stop signal received.\");\n break;\n }\n\n // Sleep with jitter\n const jitter = Math.floor(Math.random() * intervalMs * 0.3);\n const sleepMs = intervalMs + jitter;\n logger.info(`Sleeping ${Math.round(sleepMs / 1000)}s until next heartbeat...`);\n\n // Sleep in chunks so we can check for stop signals\n const chunkMs = 10_000;\n let slept = 0;\n while (slept < sleepMs && running) {\n await new Promise((r) => setTimeout(r, Math.min(chunkMs, sleepMs - slept)));\n slept += chunkMs;\n if (shouldStop()) {\n running = false;\n break;\n }\n }\n }\n\n clearPid();\n logger.info(\"Spora agent stopped.\");\n console.log(\"\\nSpora agent stopped.\");\n}\n\nasync function runHeartbeat(maxActions: number): Promise<void> {\n // 1. Flush any queued posts\n logger.info(\"Checking queue...\");\n try {\n const flushed = await flushQueue();\n if (flushed.posted > 0) {\n logger.info(`Flushed ${flushed.posted} queued posts.`);\n }\n } catch (error) {\n logger.warn(`Queue flush failed: ${(error as Error).message}`);\n }\n\n // 2. Read timeline and mentions for context\n logger.info(\"Reading timeline and mentions...\");\n const client = await getXClient();\n\n let timeline: Awaited<ReturnType<typeof client.getTimeline>> = [];\n let mentions: Awaited<ReturnType<typeof client.getMentions>> = [];\n\n try {\n timeline = await client.getTimeline({ count: 20 });\n } catch (error) {\n logger.warn(`Timeline read failed: ${(error as Error).message}`);\n }\n\n try {\n mentions = await client.getMentions({ count: 10 });\n } catch (error) {\n logger.warn(`Mentions read failed: ${(error as Error).message}`);\n }\n\n // 3. Build prompts\n const systemPrompt = buildSystemPrompt();\n const userMessage = buildHeartbeatUserMessage(timeline, mentions);\n\n // 4. Ask LLM for decisions\n logger.info(\"Asking LLM for decisions...\");\n const response = await generateResponse(systemPrompt, userMessage);\n\n // 5. Parse and execute actions\n const actions = parseActions(response.content);\n if (actions.length === 0) {\n logger.info(\"LLM returned no actions.\");\n return;\n }\n\n // Limit to max actions per heartbeat\n const limitedActions = actions.slice(0, maxActions);\n logger.info(`Executing ${limitedActions.length} action(s)...`);\n\n const results = await executeActions(limitedActions);\n\n // 6. Log results\n for (const result of results) {\n if (result.success) {\n logger.info(` [OK] ${result.action}${result.detail ? `: ${result.detail}` : \"\"}`);\n } else {\n logger.warn(` [FAIL] ${result.action}: ${result.error}`);\n }\n }\n\n logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -203,7 +203,7 @@ async function loginFlow() {
|
|
|
203
203
|
console.log(chalk.green("\u2713 Logged in!\n"));
|
|
204
204
|
console.log(chalk.gray("Opening chat interface...\n"));
|
|
205
205
|
try {
|
|
206
|
-
const { startWebChat } = await import("./web-chat-
|
|
206
|
+
const { startWebChat } = await import("./web-chat-ZKKVAEJT.js");
|
|
207
207
|
await startWebChat();
|
|
208
208
|
} catch (error) {
|
|
209
209
|
console.log(chalk.yellow(`Could not start chat interface: ${error.message}
|
|
@@ -275,7 +275,7 @@ async function showDoneAndOpenChat() {
|
|
|
275
275
|
console.log(chalk.bold.cyan("\u2501\u2501\u2501 Your Spore is Ready! \u2501\u2501\u2501\n"));
|
|
276
276
|
console.log(chalk.gray("Opening chat interface...\n"));
|
|
277
277
|
try {
|
|
278
|
-
const { startWebChat } = await import("./web-chat-
|
|
278
|
+
const { startWebChat } = await import("./web-chat-ZKKVAEJT.js");
|
|
279
279
|
await startWebChat();
|
|
280
280
|
} catch (error) {
|
|
281
281
|
console.log(chalk.yellow(`Could not start chat interface: ${error.message}
|
|
@@ -400,4 +400,4 @@ async function runInit(token) {
|
|
|
400
400
|
export {
|
|
401
401
|
runInit
|
|
402
402
|
};
|
|
403
|
-
//# sourceMappingURL=init-
|
|
403
|
+
//# sourceMappingURL=init-5MZMCEB7.js.map
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildChatPrompt,
|
|
3
3
|
buildHeartbeatUserMessage,
|
|
4
|
-
buildSystemPrompt
|
|
5
|
-
|
|
4
|
+
buildSystemPrompt,
|
|
5
|
+
buildTrainingChatPrompt
|
|
6
|
+
} from "./chunk-LWC67JKZ.js";
|
|
7
|
+
import "./chunk-UM57WU5I.js";
|
|
8
|
+
import "./chunk-YLJVFCT4.js";
|
|
6
9
|
import "./chunk-6M4HISFK.js";
|
|
7
10
|
import "./chunk-B6RPMDML.js";
|
|
8
11
|
import "./chunk-AIEXQCQS.js";
|
|
@@ -12,6 +15,7 @@ import "./chunk-53YLFYJF.js";
|
|
|
12
15
|
export {
|
|
13
16
|
buildChatPrompt,
|
|
14
17
|
buildHeartbeatUserMessage,
|
|
15
|
-
buildSystemPrompt
|
|
18
|
+
buildSystemPrompt,
|
|
19
|
+
buildTrainingChatPrompt
|
|
16
20
|
};
|
|
17
|
-
//# sourceMappingURL=prompt-builder-
|
|
21
|
+
//# sourceMappingURL=prompt-builder-CCLRNVTE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|