spora 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/dist/autonomy-DAV7X6QS.js +19 -0
- package/dist/{chunk-53YLFYJF.js → chunk-3RYCUGXE.js} +6 -2
- package/dist/chunk-3RYCUGXE.js.map +1 -0
- package/dist/{chunk-AH7HPXYC.js → chunk-AOQ3WLZV.js} +153 -143
- package/dist/chunk-AOQ3WLZV.js.map +1 -0
- package/dist/chunk-E5NR6HT4.js +29 -0
- package/dist/chunk-E5NR6HT4.js.map +1 -0
- package/dist/{chunk-EBO4F5NU.js → chunk-JBYZ7K56.js} +2 -2
- package/dist/chunk-KWWAIS3C.js +180 -0
- package/dist/chunk-KWWAIS3C.js.map +1 -0
- package/dist/{chunk-UINSD4FT.js → chunk-LXQNVVIY.js} +6 -6
- package/dist/{chunk-UINSD4FT.js.map → chunk-LXQNVVIY.js.map} +1 -1
- package/dist/{chunk-AIEXQCQS.js → chunk-M6YOQVSI.js} +2 -2
- package/dist/{chunk-B6RPMDML.js → chunk-NO3NQN67.js} +16 -6
- package/dist/chunk-NO3NQN67.js.map +1 -0
- package/dist/{chunk-QOKQ5OTU.js → chunk-NPV3OV2K.js} +3 -14
- package/dist/chunk-NPV3OV2K.js.map +1 -0
- package/dist/{chunk-SBQILQCJ.js → chunk-OACD3HGE.js} +7 -7
- package/dist/{chunk-UM57WU5I.js → chunk-P6KZIJYL.js} +2 -2
- package/dist/{chunk-AHXZIGQE.js → chunk-T7L2L7ZL.js} +2 -2
- package/dist/{chunk-ZJZKH7N7.js → chunk-VZBHRUZS.js} +2 -2
- package/dist/chunk-VZBHRUZS.js.map +1 -0
- package/dist/chunk-WIK74GGJ.js +295 -0
- package/dist/chunk-WIK74GGJ.js.map +1 -0
- package/dist/{chunk-YLJVFCT4.js → chunk-WN35MRMF.js} +2 -2
- package/dist/cli.js +168 -137
- package/dist/cli.js.map +1 -1
- package/dist/client-57BQKVYF.js +337 -0
- package/dist/client-57BQKVYF.js.map +1 -0
- package/dist/{colony-LCWN5IAN.js → colony-JPZC3R34.js} +7 -7
- package/dist/{config-TFAFYSIW.js → config-FL4VJVKZ.js} +3 -3
- package/dist/{crypto-FHSQ72NU.js → crypto-NOXNL4GP.js} +3 -3
- package/dist/{goals-5TAPXNR2.js → goals-RBKLMILE.js} +3 -3
- package/dist/{heartbeat-ZHRCEMF5.js → heartbeat-TNEPE3ZP.js} +83 -88
- package/dist/heartbeat-TNEPE3ZP.js.map +1 -0
- package/dist/{identity-O4FLSZKZ.js → identity-VDUW4I2K.js} +3 -3
- package/dist/{init-G3WINLAP.js → init-ISSXETHY.js} +59 -46
- package/dist/init-ISSXETHY.js.map +1 -0
- package/dist/llm-T33QTPVW.js +22 -0
- package/dist/mcp-server.js +28 -28
- package/dist/mcp-server.js.map +1 -1
- package/dist/{memory-O3AJIKBX.js → memory-OIAH33G2.js} +3 -3
- package/dist/{memory-7FBE26K3.js → memory-PNW7SX7A.js} +3 -3
- package/dist/{paths-5GFUUHCZ.js → paths-BYR6MEPR.js} +2 -2
- package/dist/prompt-builder-5NYONN2W.js +23 -0
- package/dist/queue-G5PTE6R6.js +14 -0
- package/dist/{strategy-S45TX766.js → strategy-Z4JSFHSP.js} +3 -3
- package/dist/{web-chat-RQIILEQK.js → web-chat-3HM35XM4.js} +31 -80
- package/dist/web-chat-3HM35XM4.js.map +1 -0
- package/dist/x-client-GY6XSPK6.js +12 -0
- package/package.json +1 -1
- package/dist/account-creator-ZD643X3Z.js +0 -498
- package/dist/account-creator-ZD643X3Z.js.map +0 -1
- package/dist/chunk-535NMUUW.js +0 -96
- package/dist/chunk-535NMUUW.js.map +0 -1
- package/dist/chunk-53YLFYJF.js.map +0 -1
- package/dist/chunk-55XPDJ6P.js +0 -124
- package/dist/chunk-55XPDJ6P.js.map +0 -1
- package/dist/chunk-AH7HPXYC.js.map +0 -1
- package/dist/chunk-B6RPMDML.js.map +0 -1
- package/dist/chunk-E6GMS76S.js +0 -154
- package/dist/chunk-E6GMS76S.js.map +0 -1
- package/dist/chunk-JJZ7T2IZ.js +0 -32
- package/dist/chunk-JJZ7T2IZ.js.map +0 -1
- package/dist/chunk-QOKQ5OTU.js.map +0 -1
- package/dist/chunk-TF2XYGGG.js +0 -249
- package/dist/chunk-TF2XYGGG.js.map +0 -1
- package/dist/chunk-ZJZKH7N7.js.map +0 -1
- package/dist/client-B6NGVRHM.js +0 -381
- package/dist/client-B6NGVRHM.js.map +0 -1
- package/dist/client-DDCS5FJS.js +0 -412
- package/dist/client-DDCS5FJS.js.map +0 -1
- package/dist/decision-engine-DRPIZLHI.js +0 -19
- package/dist/heartbeat-ZHRCEMF5.js.map +0 -1
- package/dist/init-G3WINLAP.js.map +0 -1
- package/dist/llm-3LSNADSR.js +0 -16
- package/dist/prompt-builder-U2J4H7YX.js +0 -24
- package/dist/queue-USY7JXDV.js +0 -14
- package/dist/research-TQLP42BC.js +0 -13
- package/dist/web-chat-RQIILEQK.js.map +0 -1
- package/dist/x-client-TYU5QSLG.js +0 -12
- package/dist/x-client-TYU5QSLG.js.map +0 -1
- /package/dist/{config-TFAFYSIW.js.map → autonomy-DAV7X6QS.js.map} +0 -0
- /package/dist/{chunk-EBO4F5NU.js.map → chunk-JBYZ7K56.js.map} +0 -0
- /package/dist/{chunk-AIEXQCQS.js.map → chunk-M6YOQVSI.js.map} +0 -0
- /package/dist/{chunk-SBQILQCJ.js.map → chunk-OACD3HGE.js.map} +0 -0
- /package/dist/{chunk-UM57WU5I.js.map → chunk-P6KZIJYL.js.map} +0 -0
- /package/dist/{chunk-AHXZIGQE.js.map → chunk-T7L2L7ZL.js.map} +0 -0
- /package/dist/{chunk-YLJVFCT4.js.map → chunk-WN35MRMF.js.map} +0 -0
- /package/dist/{colony-LCWN5IAN.js.map → colony-JPZC3R34.js.map} +0 -0
- /package/dist/{crypto-FHSQ72NU.js.map → config-FL4VJVKZ.js.map} +0 -0
- /package/dist/{decision-engine-DRPIZLHI.js.map → crypto-NOXNL4GP.js.map} +0 -0
- /package/dist/{goals-5TAPXNR2.js.map → goals-RBKLMILE.js.map} +0 -0
- /package/dist/{identity-O4FLSZKZ.js.map → identity-VDUW4I2K.js.map} +0 -0
- /package/dist/{llm-3LSNADSR.js.map → llm-T33QTPVW.js.map} +0 -0
- /package/dist/{memory-7FBE26K3.js.map → memory-OIAH33G2.js.map} +0 -0
- /package/dist/{memory-O3AJIKBX.js.map → memory-PNW7SX7A.js.map} +0 -0
- /package/dist/{paths-5GFUUHCZ.js.map → paths-BYR6MEPR.js.map} +0 -0
- /package/dist/{prompt-builder-U2J4H7YX.js.map → prompt-builder-5NYONN2W.js.map} +0 -0
- /package/dist/{queue-USY7JXDV.js.map → queue-G5PTE6R6.js.map} +0 -0
- /package/dist/{research-TQLP42BC.js.map → strategy-Z4JSFHSP.js.map} +0 -0
- /package/dist/{strategy-S45TX766.js.map → x-client-GY6XSPK6.js.map} +0 -0
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ npx spora@latest init
|
|
|
11
11
|
# Create a Spore identity
|
|
12
12
|
npx spora create
|
|
13
13
|
|
|
14
|
-
#
|
|
15
|
-
npx spora set
|
|
14
|
+
# Choose provider/model and set API key
|
|
15
|
+
npx spora llm set --provider deepseek
|
|
16
16
|
|
|
17
17
|
# Start the autonomous agent
|
|
18
18
|
npx spora start
|
|
@@ -20,7 +20,7 @@ npx spora start
|
|
|
20
20
|
|
|
21
21
|
## Features
|
|
22
22
|
|
|
23
|
-
- 🤖 Autonomous AI agents
|
|
23
|
+
- 🤖 Autonomous AI agents with selectable LLM providers (DeepSeek, Anthropic, OpenAI)
|
|
24
24
|
- 🐦 Full X/Twitter integration
|
|
25
25
|
- 🧠 Memory and learning capabilities
|
|
26
26
|
- 👥 Colony coordination between agents
|
|
@@ -69,13 +69,15 @@ spora post "Hello from my Spore!"
|
|
|
69
69
|
- `spora timeline` - Read timeline
|
|
70
70
|
- `spora mentions` - Check mentions
|
|
71
71
|
- `spora memory` - View agent memory
|
|
72
|
-
- `spora
|
|
72
|
+
- `spora llm set --provider <provider>` - Set LLM provider/model and API key
|
|
73
|
+
- `spora llm status` - Show provider/model + key availability
|
|
74
|
+
- `spora doctor` - Run API/runtime diagnostics
|
|
73
75
|
|
|
74
76
|
## Requirements
|
|
75
77
|
|
|
76
78
|
- Node.js 20+
|
|
77
79
|
- X/Twitter account
|
|
78
|
-
-
|
|
80
|
+
- LLM API key (provider of your choice)
|
|
79
81
|
|
|
80
82
|
## License
|
|
81
83
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runAutonomyCycle
|
|
3
|
+
} from "./chunk-WIK74GGJ.js";
|
|
4
|
+
import "./chunk-E5NR6HT4.js";
|
|
5
|
+
import "./chunk-OACD3HGE.js";
|
|
6
|
+
import "./chunk-AOQ3WLZV.js";
|
|
7
|
+
import "./chunk-P6KZIJYL.js";
|
|
8
|
+
import "./chunk-WN35MRMF.js";
|
|
9
|
+
import "./chunk-LXQNVVIY.js";
|
|
10
|
+
import "./chunk-M6YOQVSI.js";
|
|
11
|
+
import "./chunk-KWWAIS3C.js";
|
|
12
|
+
import "./chunk-NPV3OV2K.js";
|
|
13
|
+
import "./chunk-NO3NQN67.js";
|
|
14
|
+
import "./chunk-JBYZ7K56.js";
|
|
15
|
+
import "./chunk-3RYCUGXE.js";
|
|
16
|
+
export {
|
|
17
|
+
runAutonomyCycle
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=autonomy-DAV7X6QS.js.map
|
|
@@ -16,13 +16,18 @@ var paths = {
|
|
|
16
16
|
interactions: join(SPORA_DIR, "memory", "interactions"),
|
|
17
17
|
learnings: join(SPORA_DIR, "memory", "learnings.json"),
|
|
18
18
|
relationships: join(SPORA_DIR, "memory", "relationships.json"),
|
|
19
|
+
strategy: join(SPORA_DIR, "memory", "strategy.json"),
|
|
20
|
+
goals: join(SPORA_DIR, "memory", "goals.json"),
|
|
21
|
+
performance: join(SPORA_DIR, "memory", "performance.json"),
|
|
19
22
|
compacted: join(SPORA_DIR, "memory", "compacted"),
|
|
20
23
|
queue: join(SPORA_DIR, "queue"),
|
|
21
24
|
pendingPosts: join(SPORA_DIR, "queue", "pending-posts.json"),
|
|
22
25
|
logs: join(SPORA_DIR, "logs"),
|
|
23
26
|
logFile: join(SPORA_DIR, "logs", "spora.log"),
|
|
27
|
+
runtimeMetrics: join(SPORA_DIR, "logs", "runtime-metrics.jsonl"),
|
|
24
28
|
dataDir: SPORA_DIR,
|
|
25
29
|
llmKey: join(SPORA_DIR, "llm-key"),
|
|
30
|
+
llmKeys: join(SPORA_DIR, "llm-keys.json"),
|
|
26
31
|
runtimePid: join(SPORA_DIR, "runtime.pid"),
|
|
27
32
|
stopSignal: join(SPORA_DIR, "stop"),
|
|
28
33
|
connectionToken: join(SPORA_DIR, "connection-token")
|
|
@@ -30,7 +35,6 @@ var paths = {
|
|
|
30
35
|
function ensureDirectories() {
|
|
31
36
|
const dirs = [
|
|
32
37
|
paths.root,
|
|
33
|
-
paths.browser,
|
|
34
38
|
paths.memory,
|
|
35
39
|
paths.interactions,
|
|
36
40
|
paths.compacted,
|
|
@@ -56,4 +60,4 @@ export {
|
|
|
56
60
|
sporaExists,
|
|
57
61
|
hasXCredentials
|
|
58
62
|
};
|
|
59
|
-
//# sourceMappingURL=chunk-
|
|
63
|
+
//# sourceMappingURL=chunk-3RYCUGXE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/paths.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { mkdirSync, existsSync } from \"node:fs\";\n\nconst SPORA_DIR = join(homedir(), \".spora\");\n\nexport const paths = {\n root: SPORA_DIR,\n config: join(SPORA_DIR, \"config.json\"),\n credentials: join(SPORA_DIR, \"credentials.json\"),\n spore: join(SPORA_DIR, \"spore.json\"),\n identity: join(SPORA_DIR, \"identity.json\"),\n colonyToken: join(SPORA_DIR, \"colony-token.json\"),\n browser: join(SPORA_DIR, \"browser\"),\n browserAuth: join(SPORA_DIR, \"browser\", \"auth-state.json\"),\n memory: join(SPORA_DIR, \"memory\"),\n interactions: join(SPORA_DIR, \"memory\", \"interactions\"),\n learnings: join(SPORA_DIR, \"memory\", \"learnings.json\"),\n relationships: join(SPORA_DIR, \"memory\", \"relationships.json\"),\n strategy: join(SPORA_DIR, \"memory\", \"strategy.json\"),\n goals: join(SPORA_DIR, \"memory\", \"goals.json\"),\n performance: join(SPORA_DIR, \"memory\", \"performance.json\"),\n compacted: join(SPORA_DIR, \"memory\", \"compacted\"),\n queue: join(SPORA_DIR, \"queue\"),\n pendingPosts: join(SPORA_DIR, \"queue\", \"pending-posts.json\"),\n logs: join(SPORA_DIR, \"logs\"),\n logFile: join(SPORA_DIR, \"logs\", \"spora.log\"),\n runtimeMetrics: join(SPORA_DIR, \"logs\", \"runtime-metrics.jsonl\"),\n dataDir: SPORA_DIR,\n llmKey: join(SPORA_DIR, \"llm-key\"),\n llmKeys: join(SPORA_DIR, \"llm-keys.json\"),\n runtimePid: join(SPORA_DIR, \"runtime.pid\"),\n stopSignal: join(SPORA_DIR, \"stop\"),\n connectionToken: join(SPORA_DIR, \"connection-token\"),\n} as const;\n\nexport function ensureDirectories(): void {\n const dirs = [\n paths.root,\n paths.memory,\n paths.interactions,\n paths.compacted,\n paths.queue,\n paths.logs,\n ];\n\n for (const dir of dirs) {\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n }\n}\n\nexport function sporaExists(): boolean {\n return existsSync(paths.config) && existsSync(paths.identity);\n}\n\nexport function hasXCredentials(): boolean {\n return existsSync(paths.credentials);\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,WAAW,kBAAkB;AAEtC,IAAM,YAAY,KAAK,QAAQ,GAAG,QAAQ;AAEnC,IAAM,QAAQ;AAAA,EACnB,MAAM;AAAA,EACN,QAAQ,KAAK,WAAW,aAAa;AAAA,EACrC,aAAa,KAAK,WAAW,kBAAkB;AAAA,EAC/C,OAAO,KAAK,WAAW,YAAY;AAAA,EACnC,UAAU,KAAK,WAAW,eAAe;AAAA,EACzC,aAAa,KAAK,WAAW,mBAAmB;AAAA,EAChD,SAAS,KAAK,WAAW,SAAS;AAAA,EAClC,aAAa,KAAK,WAAW,WAAW,iBAAiB;AAAA,EACzD,QAAQ,KAAK,WAAW,QAAQ;AAAA,EAChC,cAAc,KAAK,WAAW,UAAU,cAAc;AAAA,EACtD,WAAW,KAAK,WAAW,UAAU,gBAAgB;AAAA,EACrD,eAAe,KAAK,WAAW,UAAU,oBAAoB;AAAA,EAC7D,UAAU,KAAK,WAAW,UAAU,eAAe;AAAA,EACnD,OAAO,KAAK,WAAW,UAAU,YAAY;AAAA,EAC7C,aAAa,KAAK,WAAW,UAAU,kBAAkB;AAAA,EACzD,WAAW,KAAK,WAAW,UAAU,WAAW;AAAA,EAChD,OAAO,KAAK,WAAW,OAAO;AAAA,EAC9B,cAAc,KAAK,WAAW,SAAS,oBAAoB;AAAA,EAC3D,MAAM,KAAK,WAAW,MAAM;AAAA,EAC5B,SAAS,KAAK,WAAW,QAAQ,WAAW;AAAA,EAC5C,gBAAgB,KAAK,WAAW,QAAQ,uBAAuB;AAAA,EAC/D,SAAS;AAAA,EACT,QAAQ,KAAK,WAAW,SAAS;AAAA,EACjC,SAAS,KAAK,WAAW,eAAe;AAAA,EACxC,YAAY,KAAK,WAAW,aAAa;AAAA,EACzC,YAAY,KAAK,WAAW,MAAM;AAAA,EAClC,iBAAiB,KAAK,WAAW,kBAAkB;AACrD;AAEO,SAAS,oBAA0B;AACxC,QAAM,OAAO;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAEA,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,WAAW,GAAG,GAAG;AACpB,gBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAAA,EACF;AACF;AAEO,SAAS,cAAuB;AACrC,SAAO,WAAW,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ;AAC9D;AAEO,SAAS,kBAA2B;AACzC,SAAO,WAAW,MAAM,WAAW;AACrC;","names":[]}
|
|
@@ -1,27 +1,88 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getPerformanceSummary
|
|
3
|
-
} from "./chunk-535NMUUW.js";
|
|
4
1
|
import {
|
|
5
2
|
renderStrategyForPrompt
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P6KZIJYL.js";
|
|
7
4
|
import {
|
|
8
5
|
renderGoalsForPrompt
|
|
9
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WN35MRMF.js";
|
|
10
7
|
import {
|
|
11
8
|
rateLimiter
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import {
|
|
14
|
-
loadConfig
|
|
15
|
-
} from "./chunk-B6RPMDML.js";
|
|
9
|
+
} from "./chunk-LXQNVVIY.js";
|
|
16
10
|
import {
|
|
17
11
|
loadIdentity,
|
|
18
12
|
renderIdentityDocument
|
|
19
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-M6YOQVSI.js";
|
|
14
|
+
import {
|
|
15
|
+
loadConfig
|
|
16
|
+
} from "./chunk-NO3NQN67.js";
|
|
20
17
|
import {
|
|
21
18
|
getRecentInteractions,
|
|
22
19
|
loadLearnings,
|
|
23
20
|
loadRelationships
|
|
24
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-JBYZ7K56.js";
|
|
22
|
+
import {
|
|
23
|
+
paths
|
|
24
|
+
} from "./chunk-3RYCUGXE.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
|
+
}
|
|
25
86
|
|
|
26
87
|
// src/runtime/prompt-builder.ts
|
|
27
88
|
function buildSystemPrompt() {
|
|
@@ -95,103 +156,109 @@ function buildSystemPrompt() {
|
|
|
95
156
|
sections.push("3. Be selective \u2014 your goals should guide every action.");
|
|
96
157
|
sections.push("4. Respect your credit budget \u2014 check remaining credits before posting.");
|
|
97
158
|
sections.push("5. Don't repeat yourself \u2014 vary your content and avoid posting the same thing.");
|
|
98
|
-
sections.push("6. Tweet like a real person \u2014 be conversational, opinionated, and curious. NEVER write dry, explanatory, or educational-sounding tweets.");
|
|
99
|
-
sections.push("7. Prioritize engagement (replies, likes, conversation) over broadcasting original posts.");
|
|
100
159
|
if (identity.boundaries.length > 0) {
|
|
101
|
-
sections.push(`
|
|
160
|
+
sections.push(`6. Respect your boundaries: ${identity.boundaries.join(", ")}`);
|
|
102
161
|
}
|
|
103
162
|
return sections.join("\n");
|
|
104
163
|
}
|
|
105
|
-
function buildHeartbeatUserMessage(
|
|
164
|
+
function buildHeartbeatUserMessage(timeline, mentions) {
|
|
106
165
|
const parts = [];
|
|
107
|
-
parts.push("It's time for your heartbeat cycle. Here's what
|
|
166
|
+
parts.push("It's time for your heartbeat cycle. Here's what's happening on your timeline:");
|
|
108
167
|
parts.push("");
|
|
109
|
-
if (
|
|
168
|
+
if (mentions.length > 0) {
|
|
110
169
|
parts.push("## Mentions (people talking to/about you)");
|
|
111
|
-
for (const t of
|
|
170
|
+
for (const t of mentions.slice(0, 10)) {
|
|
112
171
|
parts.push(`- @${t.authorHandle}: "${t.text}" [tweet:${t.id}] (${t.likeCount ?? 0} likes)`);
|
|
113
172
|
}
|
|
114
173
|
parts.push("");
|
|
115
174
|
}
|
|
116
|
-
if (
|
|
117
|
-
parts.push("## Timeline (your feed)");
|
|
118
|
-
for (const t of
|
|
175
|
+
if (timeline.length > 0) {
|
|
176
|
+
parts.push("## Timeline (recent posts from your feed)");
|
|
177
|
+
for (const t of timeline.slice(0, 20)) {
|
|
119
178
|
parts.push(`- @${t.authorHandle}: "${t.text}" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.retweetCount ?? 0} RTs)`);
|
|
120
179
|
}
|
|
121
180
|
parts.push("");
|
|
122
181
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
182
|
+
parts.push("## Your Task");
|
|
183
|
+
parts.push("Based on your identity, goals, and what you see above, decide what actions to take.");
|
|
184
|
+
parts.push("You can take 1-3 actions. Choose from:");
|
|
185
|
+
parts.push("");
|
|
186
|
+
parts.push("Available actions:");
|
|
187
|
+
parts.push("- `post` \u2014 Write an original tweet (provide `content`, max 280 chars)");
|
|
188
|
+
parts.push("- `reply` \u2014 Reply to a tweet (provide `tweetId` and `content`)");
|
|
189
|
+
parts.push("- `like` \u2014 Like a tweet (provide `tweetId`)");
|
|
190
|
+
parts.push("- `retweet` \u2014 Retweet (provide `tweetId`)");
|
|
191
|
+
parts.push("- `follow` \u2014 Follow a user (provide `handle`)");
|
|
192
|
+
parts.push("- `schedule` \u2014 Queue a post for later (provide `content`)");
|
|
193
|
+
parts.push("- `learn` \u2014 Record a learning/observation (provide `content` and optional `tags`)");
|
|
194
|
+
parts.push("- `reflect` \u2014 Add a journal entry about your growth (provide `content`)");
|
|
195
|
+
parts.push("- `skip` \u2014 Do nothing this heartbeat (provide `reason`)");
|
|
196
|
+
parts.push("");
|
|
197
|
+
parts.push("Respond with a JSON array of actions:");
|
|
198
|
+
parts.push("```json");
|
|
199
|
+
parts.push("[");
|
|
200
|
+
parts.push(' { "action": "post", "content": "your tweet here", "reasoning": "why" },');
|
|
201
|
+
parts.push(' { "action": "like", "tweetId": "123", "reasoning": "why" }');
|
|
202
|
+
parts.push("]");
|
|
203
|
+
parts.push("```");
|
|
204
|
+
parts.push("");
|
|
205
|
+
parts.push("Think carefully about what serves your goals. Be authentic to your personality.");
|
|
206
|
+
return parts.join("\n");
|
|
207
|
+
}
|
|
208
|
+
function buildToolDecisionMessage(input) {
|
|
209
|
+
const { step, maxActions, timeline, mentions, executedActions, policyFeedback } = input;
|
|
210
|
+
const parts = [];
|
|
211
|
+
parts.push(`Heartbeat step ${step + 1} of ${maxActions}.`);
|
|
212
|
+
parts.push("");
|
|
213
|
+
parts.push("You are choosing ONE next tool action.");
|
|
214
|
+
parts.push("Priorities:");
|
|
215
|
+
parts.push("1. Be socially immersed: engage with real people, not just broadcast.");
|
|
216
|
+
parts.push("2. Prefer context-aware replies/likes/follows when relevant.");
|
|
217
|
+
parts.push("3. Avoid repetitive templates, slogans, and lecture-like formats.");
|
|
218
|
+
parts.push("4. Ask questions sometimes. Curiosity beats certainty.");
|
|
219
|
+
parts.push("");
|
|
220
|
+
if (policyFeedback.length > 0) {
|
|
221
|
+
parts.push("Policy feedback from previous attempts:");
|
|
222
|
+
for (const feedback of policyFeedback.slice(-5)) {
|
|
223
|
+
parts.push(`- ${feedback}`);
|
|
130
224
|
}
|
|
131
225
|
parts.push("");
|
|
132
226
|
}
|
|
133
|
-
if (
|
|
134
|
-
parts.push("
|
|
135
|
-
for (const
|
|
136
|
-
parts.push(
|
|
137
|
-
for (const t of person.tweets.slice(0, 3)) {
|
|
138
|
-
parts.push(`- "${t.text}" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.replyCount ?? 0} replies)`);
|
|
139
|
-
}
|
|
227
|
+
if (executedActions.length > 0) {
|
|
228
|
+
parts.push("Actions already executed this heartbeat:");
|
|
229
|
+
for (const action of executedActions) {
|
|
230
|
+
parts.push(`- ${JSON.stringify(action)}`);
|
|
140
231
|
}
|
|
141
232
|
parts.push("");
|
|
142
233
|
}
|
|
143
|
-
if (
|
|
144
|
-
parts.push("
|
|
145
|
-
for (const
|
|
146
|
-
|
|
147
|
-
const likes = latest?.likes ?? 0;
|
|
148
|
-
const rts = latest?.retweets ?? 0;
|
|
149
|
-
const replies = latest?.replies ?? 0;
|
|
150
|
-
parts.push(`- "${post.content.slice(0, 80)}..." \u2014 ${likes} likes, ${rts} RTs, ${replies} replies`);
|
|
234
|
+
if (mentions.length > 0) {
|
|
235
|
+
parts.push("Mentions:");
|
|
236
|
+
for (const t of mentions.slice(0, 10)) {
|
|
237
|
+
parts.push(`- @${t.authorHandle}: "${t.text}" [tweet:${t.id}]`);
|
|
151
238
|
}
|
|
152
239
|
parts.push("");
|
|
153
240
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
parts.push("
|
|
162
|
-
parts.push("-
|
|
163
|
-
parts.push("-
|
|
164
|
-
parts.push("-
|
|
165
|
-
parts.push("-
|
|
166
|
-
parts.push("-
|
|
167
|
-
parts.push("");
|
|
168
|
-
parts.push("
|
|
169
|
-
parts.push(
|
|
170
|
-
parts.push(
|
|
171
|
-
parts.push("- Write like a blog post or article \u2014 this is Twitter, keep it punchy");
|
|
172
|
-
parts.push("- Post generic observations nobody would engage with");
|
|
173
|
-
parts.push("- Ignore your timeline and just post into the void");
|
|
174
|
-
parts.push("");
|
|
175
|
-
parts.push("**Prioritize replying and engaging over original posts.** Real people spend more time reacting than broadcasting.");
|
|
176
|
-
parts.push("");
|
|
177
|
-
parts.push("## Your Task");
|
|
178
|
-
parts.push("Choose 1-3 actions. Available:");
|
|
179
|
-
parts.push("");
|
|
180
|
-
parts.push("- `post` \u2014 Original tweet (`content`, max 280 chars)");
|
|
181
|
-
parts.push("- `reply` \u2014 Reply to a tweet (`tweetId` + `content`)");
|
|
182
|
-
parts.push("- `like` \u2014 Like a tweet (`tweetId`)");
|
|
183
|
-
parts.push("- `retweet` \u2014 Retweet (`tweetId`)");
|
|
184
|
-
parts.push("- `follow` \u2014 Follow a user (`handle`)");
|
|
185
|
-
parts.push("- `schedule` \u2014 Queue for later (`content`)");
|
|
186
|
-
parts.push("- `skip` \u2014 Do nothing (`reason`)");
|
|
241
|
+
if (timeline.length > 0) {
|
|
242
|
+
parts.push("Timeline:");
|
|
243
|
+
for (const t of timeline.slice(0, 20)) {
|
|
244
|
+
parts.push(`- @${t.authorHandle}: "${t.text}" [tweet:${t.id}]`);
|
|
245
|
+
}
|
|
246
|
+
parts.push("");
|
|
247
|
+
}
|
|
248
|
+
parts.push("Available tools (choose one):");
|
|
249
|
+
parts.push("- post { content, reasoning }");
|
|
250
|
+
parts.push("- reply { tweetId, content, reasoning }");
|
|
251
|
+
parts.push("- like { tweetId, reasoning }");
|
|
252
|
+
parts.push("- retweet { tweetId, reasoning }");
|
|
253
|
+
parts.push("- follow { handle, reasoning }");
|
|
254
|
+
parts.push("- schedule { content, reasoning }");
|
|
255
|
+
parts.push("- learn { content, tags?, reasoning }");
|
|
256
|
+
parts.push("- reflect { content, reasoning }");
|
|
257
|
+
parts.push("- skip { reason }");
|
|
187
258
|
parts.push("");
|
|
188
|
-
parts.push("
|
|
189
|
-
parts.push("
|
|
190
|
-
parts.push("
|
|
191
|
-
parts.push(' { "action": "reply", "tweetId": "123", "content": "wait this is actually wild", "reasoning": "reacting to interesting take" },');
|
|
192
|
-
parts.push(' { "action": "like", "tweetId": "456", "reasoning": "good thread worth supporting" }');
|
|
193
|
-
parts.push("]");
|
|
194
|
-
parts.push("```");
|
|
259
|
+
parts.push("Return ONLY a single JSON object.");
|
|
260
|
+
parts.push("Example:");
|
|
261
|
+
parts.push('{"action":"reply","tweetId":"123","content":"Great point. Curious: what changed your mind?","reasoning":"Directly engages a relevant mention."}');
|
|
195
262
|
return parts.join("\n");
|
|
196
263
|
}
|
|
197
264
|
function buildChatPrompt() {
|
|
@@ -343,69 +410,12 @@ function buildTrainingChatPrompt() {
|
|
|
343
410
|
sections.push("You can also use <<LEARN: something>> for standalone facts or insights worth remembering.");
|
|
344
411
|
return sections.join("\n");
|
|
345
412
|
}
|
|
346
|
-
function buildReflectionPrompt(actionResults) {
|
|
347
|
-
const identity = loadIdentity();
|
|
348
|
-
const parts = [];
|
|
349
|
-
parts.push(`You are ${identity.name} (@${identity.handle}). Time to reflect.`);
|
|
350
|
-
parts.push("");
|
|
351
|
-
parts.push("## Your Goals");
|
|
352
|
-
for (const goal of identity.goals) {
|
|
353
|
-
parts.push(`- ${goal}`);
|
|
354
|
-
}
|
|
355
|
-
parts.push("");
|
|
356
|
-
if (actionResults.length > 0) {
|
|
357
|
-
parts.push("## This Heartbeat");
|
|
358
|
-
for (const r of actionResults) {
|
|
359
|
-
if (r.success) {
|
|
360
|
-
parts.push(`- \u2713 ${r.action}${r.detail ? `: ${r.detail}` : ""}`);
|
|
361
|
-
} else {
|
|
362
|
-
parts.push(`- \u2717 ${r.action} failed: ${r.error}`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
parts.push("");
|
|
366
|
-
}
|
|
367
|
-
const strategyText = renderStrategyForPrompt();
|
|
368
|
-
if (strategyText) {
|
|
369
|
-
parts.push("## Current Strategy");
|
|
370
|
-
parts.push(strategyText);
|
|
371
|
-
parts.push("");
|
|
372
|
-
}
|
|
373
|
-
const perfSummary = getPerformanceSummary();
|
|
374
|
-
if (perfSummary) {
|
|
375
|
-
parts.push("## Performance Context");
|
|
376
|
-
parts.push(perfSummary);
|
|
377
|
-
parts.push("");
|
|
378
|
-
}
|
|
379
|
-
const learnings = loadLearnings();
|
|
380
|
-
if (learnings.learnings.length > 0) {
|
|
381
|
-
parts.push("## Previous Learnings");
|
|
382
|
-
for (const l of learnings.learnings.slice(-5)) {
|
|
383
|
-
parts.push(`- ${l.content}`);
|
|
384
|
-
}
|
|
385
|
-
parts.push("");
|
|
386
|
-
}
|
|
387
|
-
parts.push("## Your Task");
|
|
388
|
-
parts.push("Reflect on how you're progressing toward your GOALS. Consider:");
|
|
389
|
-
parts.push("- Are your recent actions moving you toward your goals?");
|
|
390
|
-
parts.push("- Are you staying true to who you are while growing?");
|
|
391
|
-
parts.push("- What should you try differently or double down on?");
|
|
392
|
-
parts.push("- Engagement metrics are one signal, but your goals matter more.");
|
|
393
|
-
parts.push("");
|
|
394
|
-
parts.push("Respond with JSON:");
|
|
395
|
-
parts.push("```json");
|
|
396
|
-
parts.push("{");
|
|
397
|
-
parts.push(' "learning": "one insight about your progress toward your goals (or null)",');
|
|
398
|
-
parts.push(' "strategyUpdate": "one specific thing to try or change (or null)"');
|
|
399
|
-
parts.push("}");
|
|
400
|
-
parts.push("```");
|
|
401
|
-
return parts.join("\n");
|
|
402
|
-
}
|
|
403
413
|
|
|
404
414
|
export {
|
|
405
415
|
buildSystemPrompt,
|
|
406
416
|
buildHeartbeatUserMessage,
|
|
417
|
+
buildToolDecisionMessage,
|
|
407
418
|
buildChatPrompt,
|
|
408
|
-
buildTrainingChatPrompt
|
|
409
|
-
buildReflectionPrompt
|
|
419
|
+
buildTrainingChatPrompt
|
|
410
420
|
};
|
|
411
|
-
//# sourceMappingURL=chunk-
|
|
421
|
+
//# sourceMappingURL=chunk-AOQ3WLZV.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\";\nimport type { AgentAction } from \"./decision-engine.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\ninterface ToolDecisionPromptInput {\n step: number;\n maxActions: number;\n timeline: Tweet[];\n mentions: Tweet[];\n executedActions: AgentAction[];\n policyFeedback: string[];\n}\n\nexport function buildToolDecisionMessage(input: ToolDecisionPromptInput): string {\n const { step, maxActions, timeline, mentions, executedActions, policyFeedback } = input;\n const parts: string[] = [];\n\n parts.push(`Heartbeat step ${step + 1} of ${maxActions}.`);\n parts.push(\"\");\n parts.push(\"You are choosing ONE next tool action.\");\n parts.push(\"Priorities:\");\n parts.push(\"1. Be socially immersed: engage with real people, not just broadcast.\");\n parts.push(\"2. Prefer context-aware replies/likes/follows when relevant.\");\n parts.push(\"3. Avoid repetitive templates, slogans, and lecture-like formats.\");\n parts.push(\"4. Ask questions sometimes. Curiosity beats certainty.\");\n parts.push(\"\");\n\n if (policyFeedback.length > 0) {\n parts.push(\"Policy feedback from previous attempts:\");\n for (const feedback of policyFeedback.slice(-5)) {\n parts.push(`- ${feedback}`);\n }\n parts.push(\"\");\n }\n\n if (executedActions.length > 0) {\n parts.push(\"Actions already executed this heartbeat:\");\n for (const action of executedActions) {\n parts.push(`- ${JSON.stringify(action)}`);\n }\n parts.push(\"\");\n }\n\n if (mentions.length > 0) {\n parts.push(\"Mentions:\");\n for (const t of mentions.slice(0, 10)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}]`);\n }\n parts.push(\"\");\n }\n\n if (timeline.length > 0) {\n parts.push(\"Timeline:\");\n for (const t of timeline.slice(0, 20)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}]`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"Available tools (choose one):\");\n parts.push(\"- post { content, reasoning }\");\n parts.push(\"- reply { tweetId, content, reasoning }\");\n parts.push(\"- like { tweetId, reasoning }\");\n parts.push(\"- retweet { tweetId, reasoning }\");\n parts.push(\"- follow { handle, reasoning }\");\n parts.push(\"- schedule { content, reasoning }\");\n parts.push(\"- learn { content, tags?, reasoning }\");\n parts.push(\"- reflect { content, reasoning }\");\n parts.push(\"- skip { reason }\");\n parts.push(\"\");\n parts.push(\"Return ONLY a single JSON object.\");\n parts.push(\"Example:\");\n parts.push('{\"action\":\"reply\",\"tweetId\":\"123\",\"content\":\"Great point. Curious: what changed your mind?\",\"reasoning\":\"Directly engages a relevant mention.\"}');\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,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-NPV3OV2K.js";
|
|
4
|
+
import {
|
|
5
|
+
loadConfig
|
|
6
|
+
} from "./chunk-NO3NQN67.js";
|
|
7
|
+
|
|
8
|
+
// src/x-client/index.ts
|
|
9
|
+
var clientInstance = null;
|
|
10
|
+
async function getXClient() {
|
|
11
|
+
if (clientInstance) return clientInstance;
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
if (config.xMethod !== "api") {
|
|
14
|
+
throw new Error("Only X API mode is supported.");
|
|
15
|
+
}
|
|
16
|
+
const { XApiClient } = await import("./client-57BQKVYF.js");
|
|
17
|
+
clientInstance = new XApiClient();
|
|
18
|
+
logger.info("X client initialized: API mode");
|
|
19
|
+
return clientInstance;
|
|
20
|
+
}
|
|
21
|
+
function resetXClient() {
|
|
22
|
+
clientInstance = null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
getXClient,
|
|
27
|
+
resetXClient
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=chunk-E5NR6HT4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/x-client/index.ts"],"sourcesContent":["import { loadConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\nimport type { XClientInterface } from \"./types.js\";\n\nlet clientInstance: XClientInterface | null = null;\n\nexport async function getXClient(): Promise<XClientInterface> {\n if (clientInstance) return clientInstance;\n\n const config = loadConfig();\n if (config.xMethod !== \"api\") {\n throw new Error(\"Only X API mode is supported.\");\n }\n\n const { XApiClient } = await import(\"./api/client.js\");\n clientInstance = new XApiClient();\n logger.info(\"X client initialized: API mode\");\n\n return clientInstance;\n}\n\nexport function resetXClient(): void {\n clientInstance = null;\n}\n\nexport type { XClientInterface } from \"./types.js\";\nexport type { Tweet, UserProfile, PostResult, TimelineOptions, SearchOptions } from \"./types.js\";\n"],"mappings":";;;;;;;;AAIA,IAAI,iBAA0C;AAE9C,eAAsB,aAAwC;AAC5D,MAAI,eAAgB,QAAO;AAE3B,QAAM,SAAS,WAAW;AAC1B,MAAI,OAAO,YAAY,OAAO;AAC5B,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,sBAAiB;AACrD,mBAAiB,IAAI,WAAW;AAChC,SAAO,KAAK,gCAAgC;AAE5C,SAAO;AACT;AAEO,SAAS,eAAqB;AACnC,mBAAiB;AACnB;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureDirectories,
|
|
3
3
|
paths
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3RYCUGXE.js";
|
|
5
5
|
|
|
6
6
|
// src/memory/index.ts
|
|
7
7
|
import { readFileSync, writeFileSync, appendFileSync, existsSync, readdirSync } from "fs";
|
|
@@ -102,4 +102,4 @@ export {
|
|
|
102
102
|
saveRelationships,
|
|
103
103
|
updateRelationship
|
|
104
104
|
};
|
|
105
|
-
//# sourceMappingURL=chunk-
|
|
105
|
+
//# sourceMappingURL=chunk-JBYZ7K56.js.map
|