spora 0.7.5 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{autonomy-DFPA3OK6.js → autonomy-E3DWYRJM.js} +3 -3
- package/dist/{chunk-A2XTKC7B.js → chunk-E5PEY36J.js} +130 -1
- package/dist/chunk-E5PEY36J.js.map +1 -0
- package/dist/{chunk-HXI2EH5C.js → chunk-FBHLDOMC.js} +113 -15
- package/dist/chunk-FBHLDOMC.js.map +1 -0
- package/dist/cli.js +5 -5
- package/dist/{heartbeat-RAOEIKWC.js → heartbeat-GVBLNAFM.js} +3 -3
- package/dist/{init-ETUTFHT6.js → init-C4OZPGUC.js} +52 -5
- package/dist/init-C4OZPGUC.js.map +1 -0
- package/dist/{prompt-builder-XJHXZCSQ.js → prompt-builder-NTN4FCBD.js} +2 -2
- package/dist/{web-chat-TB3ACPVF.js → web-chat-2N2RN6J7.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-A2XTKC7B.js.map +0 -1
- package/dist/chunk-HXI2EH5C.js.map +0 -1
- package/dist/init-ETUTFHT6.js.map +0 -1
- /package/dist/{autonomy-DFPA3OK6.js.map → autonomy-E3DWYRJM.js.map} +0 -0
- /package/dist/{heartbeat-RAOEIKWC.js.map → heartbeat-GVBLNAFM.js.map} +0 -0
- /package/dist/{prompt-builder-XJHXZCSQ.js.map → prompt-builder-NTN4FCBD.js.map} +0 -0
- /package/dist/{web-chat-TB3ACPVF.js.map → web-chat-2N2RN6J7.js.map} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runAutonomyCycle
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FBHLDOMC.js";
|
|
4
4
|
import "./chunk-5R4AJZHN.js";
|
|
5
5
|
import "./chunk-ZLSDFYBR.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-E5PEY36J.js";
|
|
7
7
|
import "./chunk-OTZNHIXT.js";
|
|
8
8
|
import "./chunk-CAWWG3MD.js";
|
|
9
9
|
import "./chunk-CP6JWCLY.js";
|
|
@@ -17,4 +17,4 @@ import "./chunk-ZWKTKWS6.js";
|
|
|
17
17
|
export {
|
|
18
18
|
runAutonomyCycle
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=autonomy-
|
|
20
|
+
//# sourceMappingURL=autonomy-E3DWYRJM.js.map
|
|
@@ -23,6 +23,116 @@ import {
|
|
|
23
23
|
loadRelationships
|
|
24
24
|
} from "./chunk-BBXHECZ5.js";
|
|
25
25
|
|
|
26
|
+
// src/runtime/persona-constraints.ts
|
|
27
|
+
function normalizeHandle(handle) {
|
|
28
|
+
return handle.replace(/^@/, "").trim().toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
function unique(values) {
|
|
31
|
+
return [...new Set(values)];
|
|
32
|
+
}
|
|
33
|
+
function extractHandles(text) {
|
|
34
|
+
const fromMentions = [...text.matchAll(/@([a-zA-Z0-9_]{1,15})/g)].map((m) => m[1]);
|
|
35
|
+
const fromUrls = [...text.matchAll(/x\.com\/([a-zA-Z0-9_]{1,15})/gi)].map((m) => m[1]);
|
|
36
|
+
return unique(
|
|
37
|
+
[...fromMentions, ...fromUrls].map(normalizeHandle).filter((handle) => handle.length > 0)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
function includesOnlyQualifier(text) {
|
|
41
|
+
return /\b(only|just|exclusively|strictly)\b/i.test(text);
|
|
42
|
+
}
|
|
43
|
+
function includesReplyIntent(text) {
|
|
44
|
+
return /\b(reply|respond|response|replying)\b/i.test(text);
|
|
45
|
+
}
|
|
46
|
+
function includesInteractionIntent(text) {
|
|
47
|
+
return /\b(interact|engage|talk|chat|speak|communicate|message)\b/i.test(text);
|
|
48
|
+
}
|
|
49
|
+
function impliesNoOriginalPosts(text) {
|
|
50
|
+
const lower = text.toLowerCase();
|
|
51
|
+
if (/\bonly\s+repl(?:y|ies)\b/.test(lower)) return true;
|
|
52
|
+
if (/\brepl(?:y|ies)\s+only\b/.test(lower)) return true;
|
|
53
|
+
if (/\breply-?only\b/.test(lower)) return true;
|
|
54
|
+
if (/\b(no|never|don['’]?t|dont|avoid)\s+(?:do\s+)?(?:original\s+)?posts?\b/.test(lower)) return true;
|
|
55
|
+
if (/\bno\s+tweets?\b/.test(lower)) return true;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function getPersonaConstraints(identityArg) {
|
|
59
|
+
const identity = identityArg ?? loadIdentity();
|
|
60
|
+
const strictReplyHandles = /* @__PURE__ */ new Set();
|
|
61
|
+
const strictInteractionHandles = /* @__PURE__ */ new Set();
|
|
62
|
+
const lines = [
|
|
63
|
+
...identity.goals ?? [],
|
|
64
|
+
...identity.boundaries ?? [],
|
|
65
|
+
identity.bio ?? "",
|
|
66
|
+
identity.originStory ?? "",
|
|
67
|
+
identity.worldview ?? "",
|
|
68
|
+
identity.tone ?? ""
|
|
69
|
+
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
70
|
+
let replyOnlyMode = false;
|
|
71
|
+
let noOriginalPosts = false;
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
const handles = extractHandles(line);
|
|
74
|
+
const hasOnly = includesOnlyQualifier(line);
|
|
75
|
+
const hasReply = includesReplyIntent(line);
|
|
76
|
+
const hasInteract = includesInteractionIntent(line);
|
|
77
|
+
if (impliesNoOriginalPosts(line)) {
|
|
78
|
+
replyOnlyMode = true;
|
|
79
|
+
noOriginalPosts = true;
|
|
80
|
+
}
|
|
81
|
+
if (hasOnly && hasReply) {
|
|
82
|
+
replyOnlyMode = true;
|
|
83
|
+
noOriginalPosts = true;
|
|
84
|
+
for (const handle of handles) {
|
|
85
|
+
strictReplyHandles.add(handle);
|
|
86
|
+
strictInteractionHandles.add(handle);
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (hasOnly && hasInteract) {
|
|
91
|
+
noOriginalPosts = true;
|
|
92
|
+
for (const handle of handles) {
|
|
93
|
+
strictInteractionHandles.add(handle);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (strictReplyHandles.size > 0) {
|
|
98
|
+
replyOnlyMode = true;
|
|
99
|
+
noOriginalPosts = true;
|
|
100
|
+
}
|
|
101
|
+
if (strictInteractionHandles.size > 0) {
|
|
102
|
+
noOriginalPosts = true;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
onlyReplyToHandles: [...strictReplyHandles],
|
|
106
|
+
onlyInteractWithHandles: [...strictInteractionHandles],
|
|
107
|
+
noOriginalPosts,
|
|
108
|
+
replyOnlyMode
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function personaConstraintHandles(constraints) {
|
|
112
|
+
return unique([
|
|
113
|
+
...constraints.onlyReplyToHandles.map(normalizeHandle),
|
|
114
|
+
...constraints.onlyInteractWithHandles.map(normalizeHandle)
|
|
115
|
+
]).filter(Boolean);
|
|
116
|
+
}
|
|
117
|
+
function buildPersonaConstraintLines(constraints) {
|
|
118
|
+
const lines = [];
|
|
119
|
+
if (constraints.onlyReplyToHandles.length > 0) {
|
|
120
|
+
lines.push(`- Hard constraint: only reply to @${constraints.onlyReplyToHandles.join(", @")}`);
|
|
121
|
+
} else if (constraints.replyOnlyMode) {
|
|
122
|
+
lines.push("- Hard constraint: reply-only mode (no like/retweet/follow/post actions).");
|
|
123
|
+
}
|
|
124
|
+
const onlyInteract = constraints.onlyInteractWithHandles.filter(
|
|
125
|
+
(handle) => !constraints.onlyReplyToHandles.includes(handle)
|
|
126
|
+
);
|
|
127
|
+
if (onlyInteract.length > 0) {
|
|
128
|
+
lines.push(`- Hard constraint: only interact with @${onlyInteract.join(", @")}`);
|
|
129
|
+
}
|
|
130
|
+
if (constraints.noOriginalPosts) {
|
|
131
|
+
lines.push("- Hard constraint: do not create standalone original posts.");
|
|
132
|
+
}
|
|
133
|
+
return lines;
|
|
134
|
+
}
|
|
135
|
+
|
|
26
136
|
// src/runtime/prompt-builder.ts
|
|
27
137
|
var PROMPT_TOKEN_STOPWORDS = /* @__PURE__ */ new Set([
|
|
28
138
|
"about",
|
|
@@ -145,6 +255,7 @@ function buildVoiceLockLines(identity) {
|
|
|
145
255
|
}
|
|
146
256
|
function buildSystemPrompt() {
|
|
147
257
|
const identity = loadIdentity();
|
|
258
|
+
const constraints = getPersonaConstraints(identity);
|
|
148
259
|
const config = loadConfig();
|
|
149
260
|
const identityDoc = renderIdentityDocument(identity);
|
|
150
261
|
const sections = [];
|
|
@@ -154,6 +265,13 @@ function buildSystemPrompt() {
|
|
|
154
265
|
for (const line of buildVoiceLockLines(identity)) {
|
|
155
266
|
sections.push(line);
|
|
156
267
|
}
|
|
268
|
+
const constraintLines = buildPersonaConstraintLines(constraints);
|
|
269
|
+
if (constraintLines.length > 0) {
|
|
270
|
+
sections.push("- Operational constraints override all other behavior:");
|
|
271
|
+
for (const line of constraintLines) {
|
|
272
|
+
sections.push(` ${line}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
157
275
|
sections.push("");
|
|
158
276
|
sections.push("## Your Identity");
|
|
159
277
|
sections.push(identityDoc);
|
|
@@ -442,6 +560,7 @@ function buildToolDecisionMessage(input) {
|
|
|
442
560
|
}
|
|
443
561
|
function buildOpportunityPortfolioMessage(input) {
|
|
444
562
|
const identity = loadIdentity();
|
|
563
|
+
const constraints = getPersonaConstraints(identity);
|
|
445
564
|
const strategy = loadStrategy();
|
|
446
565
|
const recentWritten = recentWrittenTextsForPrompt(12);
|
|
447
566
|
const overusedOpenings = findOverusedOpenings(recentWritten);
|
|
@@ -467,6 +586,13 @@ function buildOpportunityPortfolioMessage(input) {
|
|
|
467
586
|
for (const line of buildVoiceLockLines(identity)) {
|
|
468
587
|
parts.push(line);
|
|
469
588
|
}
|
|
589
|
+
const constraintLines = buildPersonaConstraintLines(constraints);
|
|
590
|
+
if (constraintLines.length > 0) {
|
|
591
|
+
parts.push("Operational constraints (hard):");
|
|
592
|
+
for (const line of constraintLines) {
|
|
593
|
+
parts.push(line);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
470
596
|
parts.push("");
|
|
471
597
|
parts.push("Human style rotation:");
|
|
472
598
|
parts.push("- For each `reply`/`post`, pick one lane: quick reaction, curious question, friendly pushback, playful line, plain observation.");
|
|
@@ -735,6 +861,9 @@ function buildReflectionPrompt(actionResults) {
|
|
|
735
861
|
}
|
|
736
862
|
|
|
737
863
|
export {
|
|
864
|
+
getPersonaConstraints,
|
|
865
|
+
personaConstraintHandles,
|
|
866
|
+
buildPersonaConstraintLines,
|
|
738
867
|
buildSystemPrompt,
|
|
739
868
|
buildHeartbeatUserMessage,
|
|
740
869
|
buildToolDecisionMessage,
|
|
@@ -743,4 +872,4 @@ export {
|
|
|
743
872
|
buildTrainingChatPrompt,
|
|
744
873
|
buildReflectionPrompt
|
|
745
874
|
};
|
|
746
|
-
//# sourceMappingURL=chunk-
|
|
875
|
+
//# sourceMappingURL=chunk-E5PEY36J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/persona-constraints.ts","../src/runtime/prompt-builder.ts"],"sourcesContent":["import { loadIdentity } from \"../identity/index.js\";\nimport type { Identity } from \"../identity/schema.js\";\n\nexport interface PersonaConstraints {\n onlyReplyToHandles: string[];\n onlyInteractWithHandles: string[];\n noOriginalPosts: boolean;\n replyOnlyMode: boolean;\n}\n\nfunction normalizeHandle(handle: string): string {\n return handle.replace(/^@/, \"\").trim().toLowerCase();\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction extractHandles(text: string): string[] {\n const fromMentions = [...text.matchAll(/@([a-zA-Z0-9_]{1,15})/g)].map((m) => m[1]);\n const fromUrls = [...text.matchAll(/x\\.com\\/([a-zA-Z0-9_]{1,15})/gi)].map((m) => m[1]);\n return unique(\n [...fromMentions, ...fromUrls]\n .map(normalizeHandle)\n .filter((handle) => handle.length > 0),\n );\n}\n\nfunction includesOnlyQualifier(text: string): boolean {\n return /\\b(only|just|exclusively|strictly)\\b/i.test(text);\n}\n\nfunction includesReplyIntent(text: string): boolean {\n return /\\b(reply|respond|response|replying)\\b/i.test(text);\n}\n\nfunction includesInteractionIntent(text: string): boolean {\n return /\\b(interact|engage|talk|chat|speak|communicate|message)\\b/i.test(text);\n}\n\nfunction impliesNoOriginalPosts(text: string): boolean {\n const lower = text.toLowerCase();\n if (/\\bonly\\s+repl(?:y|ies)\\b/.test(lower)) return true;\n if (/\\brepl(?:y|ies)\\s+only\\b/.test(lower)) return true;\n if (/\\breply-?only\\b/.test(lower)) return true;\n if (/\\b(no|never|don['’]?t|dont|avoid)\\s+(?:do\\s+)?(?:original\\s+)?posts?\\b/.test(lower)) return true;\n if (/\\bno\\s+tweets?\\b/.test(lower)) return true;\n return false;\n}\n\nexport function getPersonaConstraints(identityArg?: Identity): PersonaConstraints {\n const identity = identityArg ?? loadIdentity();\n const strictReplyHandles = new Set<string>();\n const strictInteractionHandles = new Set<string>();\n\n const lines = [\n ...(identity.goals ?? []),\n ...(identity.boundaries ?? []),\n identity.bio ?? \"\",\n identity.originStory ?? \"\",\n identity.worldview ?? \"\",\n identity.tone ?? \"\",\n ].filter((value) => typeof value === \"string\" && value.trim().length > 0);\n\n let replyOnlyMode = false;\n let noOriginalPosts = false;\n\n for (const line of lines) {\n const handles = extractHandles(line);\n const hasOnly = includesOnlyQualifier(line);\n const hasReply = includesReplyIntent(line);\n const hasInteract = includesInteractionIntent(line);\n\n if (impliesNoOriginalPosts(line)) {\n replyOnlyMode = true;\n noOriginalPosts = true;\n }\n\n if (hasOnly && hasReply) {\n replyOnlyMode = true;\n noOriginalPosts = true;\n for (const handle of handles) {\n strictReplyHandles.add(handle);\n strictInteractionHandles.add(handle);\n }\n continue;\n }\n\n if (hasOnly && hasInteract) {\n noOriginalPosts = true;\n for (const handle of handles) {\n strictInteractionHandles.add(handle);\n }\n }\n }\n\n if (strictReplyHandles.size > 0) {\n replyOnlyMode = true;\n noOriginalPosts = true;\n }\n if (strictInteractionHandles.size > 0) {\n noOriginalPosts = true;\n }\n\n return {\n onlyReplyToHandles: [...strictReplyHandles],\n onlyInteractWithHandles: [...strictInteractionHandles],\n noOriginalPosts,\n replyOnlyMode,\n };\n}\n\nexport function personaConstraintHandles(constraints: PersonaConstraints): string[] {\n return unique([\n ...constraints.onlyReplyToHandles.map(normalizeHandle),\n ...constraints.onlyInteractWithHandles.map(normalizeHandle),\n ]).filter(Boolean);\n}\n\nexport function buildPersonaConstraintLines(constraints: PersonaConstraints): string[] {\n const lines: string[] = [];\n if (constraints.onlyReplyToHandles.length > 0) {\n lines.push(`- Hard constraint: only reply to @${constraints.onlyReplyToHandles.join(\", @\")}`);\n } else if (constraints.replyOnlyMode) {\n lines.push(\"- Hard constraint: reply-only mode (no like/retweet/follow/post actions).\");\n }\n\n const onlyInteract = constraints.onlyInteractWithHandles.filter(\n (handle) => !constraints.onlyReplyToHandles.includes(handle),\n );\n if (onlyInteract.length > 0) {\n lines.push(`- Hard constraint: only interact with @${onlyInteract.join(\", @\")}`);\n }\n\n if (constraints.noOriginalPosts) {\n lines.push(\"- Hard constraint: do not create standalone original posts.\");\n }\n\n return lines;\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 { renderActiveIntentsForPrompt } from \"../memory/intents.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\nimport { loadStrategy, renderStrategyForPrompt } from \"../memory/strategy.js\";\nimport { renderGoalsForPrompt } from \"../memory/goals.js\";\nimport { getPerformanceSummary } from \"../memory/performance.js\";\nimport { buildPersonaConstraintLines, getPersonaConstraints } from \"./persona-constraints.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport type { AgentAction, ActionResult } from \"./decision-engine.js\";\nimport type { ResearchContext } from \"./research.js\";\nimport type { ActionOpportunity } from \"./opportunity-engine.js\";\nimport type { Identity } from \"../identity/schema.js\";\n\nconst PROMPT_TOKEN_STOPWORDS = new Set([\n \"about\", \"after\", \"again\", \"against\", \"among\", \"because\", \"being\", \"between\", \"could\", \"every\",\n \"first\", \"from\", \"going\", \"have\", \"having\", \"into\", \"just\", \"like\", \"more\", \"most\", \"only\",\n \"other\", \"over\", \"really\", \"same\", \"some\", \"than\", \"that\", \"their\", \"there\", \"these\", \"they\",\n \"this\", \"those\", \"through\", \"very\", \"what\", \"when\", \"where\", \"which\", \"while\", \"with\", \"would\",\n \"your\", \"youre\", \"dont\", \"cant\", \"will\", \"also\", \"tweet\", \"tweets\", \"thread\", \"threads\",\n \"future\", \"human\", \"humans\", \"technology\", \"tech\", \"agent\", \"agents\", \"build\", \"building\",\n]);\n\nfunction normalizeForPrompt(text: string): string {\n return text\n .toLowerCase()\n .replace(/https?:\\/\\/\\S+/g, \" \")\n .replace(/[@#]\\w+/g, \" \")\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction recentWrittenTextsForPrompt(limit: number = 12): string[] {\n return getRecentInteractions(60)\n .filter((entry) => entry.type === \"post\" || entry.type === \"reply\")\n .map((entry) => entry.content ?? \"\")\n .filter((text) => text.trim().length > 0)\n .slice(0, limit);\n}\n\nfunction findOverusedOpenings(texts: string[]): string[] {\n const counts = new Map<string, number>();\n for (const text of texts) {\n const opening = normalizeForPrompt(text).split(\" \").filter(Boolean).slice(0, 4).join(\" \");\n if (!opening || opening.split(\" \").length < 3) continue;\n counts.set(opening, (counts.get(opening) ?? 0) + 1);\n }\n return [...counts.entries()]\n .filter(([, count]) => count >= 2)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 4)\n .map(([opening]) => opening);\n}\n\nfunction findOverusedTokens(texts: string[]): string[] {\n const counts = new Map<string, number>();\n for (const text of texts) {\n const tokens = new Set(\n normalizeForPrompt(text)\n .split(\" \")\n .filter((token) => token.length >= 5 && !PROMPT_TOKEN_STOPWORDS.has(token)),\n );\n for (const token of tokens) {\n counts.set(token, (counts.get(token) ?? 0) + 1);\n }\n }\n return [...counts.entries()]\n .filter(([, count]) => count >= 3)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 6)\n .map(([token]) => token);\n}\n\nfunction buildVoiceLockLines(identity: Identity): string[] {\n const lines: string[] = [];\n const { traits } = identity;\n const assertive =\n traits.confidence >= 0.72 ||\n traits.aggression >= 0.62 ||\n identity.conflictStyle === \"clap-back\" ||\n identity.conflictStyle === \"debate\";\n\n lines.push(`- Tone anchor: ${identity.tone}`);\n lines.push(`- Conflict style: ${identity.conflictStyle}`);\n lines.push(`- Vocabulary: ${identity.vocabularyStyle}; tweet style: ${identity.tweetStyle}`);\n\n if (assertive) {\n lines.push(\"- Be stubborn and decisive. Take a side. Do not hedge or play both sides.\");\n }\n if (traits.curiosity >= 0.72) {\n lines.push(\"- Ask sharp questions when engaging. Curiosity should show up in replies.\");\n }\n if (traits.verbosity <= 0.48) {\n lines.push(\"- Keep replies punchy: 1-2 short sentences unless a longer reply is truly necessary.\");\n } else {\n lines.push(\"- Keep replies compact and human; avoid essay-like paragraphs.\");\n }\n\n if (identity.catchphrases.length > 0) {\n lines.push(`- Your signature phrases: ${identity.catchphrases.slice(0, 3).join(\" | \")} (use occasionally, not every post).`);\n }\n if (identity.framework !== \"philosopher\") {\n lines.push(\"- Do NOT use philosopher framing: avoid lines like 'the real question', 'the deeper question', or abstract manifesto language.\");\n lines.push(\"- Ground every post/reply in concrete context: a person, a claim, an event, or a direct observation.\");\n }\n lines.push(\"- If the reply could be posted by any generic AI account, rewrite it.\");\n return lines;\n}\n\nexport function buildSystemPrompt(): string {\n const identity = loadIdentity();\n const constraints = getPersonaConstraints(identity);\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(\"## Voice Lock (Non-Negotiable)\");\n for (const line of buildVoiceLockLines(identity)) {\n sections.push(line);\n }\n const constraintLines = buildPersonaConstraintLines(constraints);\n if (constraintLines.length > 0) {\n sections.push(\"- Operational constraints override all other behavior:\");\n for (const line of constraintLines) {\n sections.push(` ${line}`);\n }\n }\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 intentsText = renderActiveIntentsForPrompt();\n if (intentsText) {\n sections.push(\"### Active Mission Intents\");\n for (const line of intentsText.split(\"\\n\")) {\n if (!line || line.startsWith(\"**Active mission intents:**\")) continue;\n sections.push(line);\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 sections.push(\"6. Tweet like a real person — be conversational, opinionated, and curious. NEVER write dry, explanatory, or educational-sounding tweets.\");\n sections.push(\"7. Prioritize engagement (replies, likes, conversation) over broadcasting original posts.\");\n if (identity.boundaries.length > 0) {\n sections.push(`8. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n\nexport function buildHeartbeatUserMessage(research: ResearchContext): string {\n const parts: string[] = [];\n\n parts.push(\"It's time for your heartbeat cycle. Here's what you found while scanning:\");\n parts.push(\"\");\n\n // Mentions first — direct engagement is highest priority\n if (research.mentions.length > 0) {\n parts.push(\"## Mentions (people talking to/about you)\");\n for (const t of research.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 // Timeline\n if (research.timeline.length > 0) {\n parts.push(\"## Timeline (your feed)\");\n for (const t of research.timeline.slice(0, 15)) {\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 // Topic search results\n if (research.topicSearchResults.length > 0) {\n parts.push(\"## Topic Research (conversations in your interest areas)\");\n for (const result of research.topicSearchResults) {\n parts.push(`### Search: \"${result.query}\"`);\n for (const t of result.tweets.slice(0, 5)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.replyCount ?? 0} replies)`);\n }\n }\n parts.push(\"\");\n }\n\n // People monitoring\n if (research.peopleActivity.length > 0) {\n parts.push(\"## People You're Watching (recent activity from key accounts)\");\n for (const person of research.peopleActivity) {\n parts.push(`### @${person.handle} (${person.reason})`);\n for (const t of person.tweets.slice(0, 3)) {\n parts.push(`- \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.replyCount ?? 0} replies)`);\n }\n }\n parts.push(\"\");\n }\n\n // Own post performance\n if (research.ownPostPerformance.length > 0) {\n parts.push(\"## How Your Recent Posts Are Doing\");\n for (const post of research.ownPostPerformance) {\n const latest = post.metrics.length > 0 ? post.metrics[post.metrics.length - 1] : null;\n const likes = latest?.likes ?? 0;\n const rts = latest?.retweets ?? 0;\n const replies = latest?.replies ?? 0;\n parts.push(`- \"${post.content.slice(0, 80)}...\" — ${likes} likes, ${rts} RTs, ${replies} replies`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"## How to Act Like a Real Person on Twitter\");\n parts.push(\"\");\n parts.push(\"You are NOT a content bot. You are a person with opinions, curiosity, and relationships.\");\n parts.push(\"Think about what a real person with your personality would actually do when they open Twitter:\");\n parts.push(\"\");\n parts.push(\"**DO:**\");\n parts.push(\"- React to what you see — reply to interesting takes, ask questions, share hot takes\");\n parts.push(\"- Be conversational — write tweets like you're talking to friends, not giving a lecture\");\n parts.push(\"- Have opinions — agree, disagree, push back, get excited\");\n parts.push(\"- Ask genuine questions that spark conversation\");\n parts.push(\"- Use casual language, incomplete thoughts, humor, or surprise\");\n parts.push(\"- Like and retweet things that genuinely resonate with you\");\n parts.push(\"- Build relationships — reply to the same people, develop running conversations\");\n parts.push(\"\");\n parts.push(\"**DON'T:**\");\n parts.push(\"- Write explanatory or educational posts (\\\"Here's why X matters...\\\")\");\n parts.push(\"- Start tweets with \\\"I think\\\" or \\\"This is interesting because\\\"\");\n parts.push(\"- Use philosopher opener templates like \\\"The real question is...\\\" or \\\"The deeper question is...\\\"\");\n parts.push(\"- Use colon/semicolon/em-dash manifesto framing in normal tweets\");\n parts.push(\"- Write like a blog post or article — this is Twitter, keep it punchy\");\n parts.push(\"- Post generic observations nobody would engage with\");\n parts.push(\"- Ignore your timeline and just post into the void\");\n parts.push(\"\");\n parts.push(\"**Prioritize replying and engaging over original posts.** Real people spend more time reacting than broadcasting.\");\n parts.push(\"\");\n parts.push(\"## Your Task\");\n parts.push(\"Choose 1-3 actions. Available:\");\n parts.push(\"\");\n parts.push(\"- `post` — Original tweet (`content`, max 280 chars)\");\n parts.push(\"- `reply` — Reply to a tweet (`tweetId` + `content`)\");\n parts.push(\"- `like` — Like a tweet (`tweetId`)\");\n parts.push(\"- `retweet` — Retweet (`tweetId`)\");\n parts.push(\"- `follow` — Follow a user (`handle`)\");\n parts.push(\"- `schedule` — Queue for later (`content`)\");\n parts.push(\"- `skip` — Do nothing (`reason`)\");\n parts.push(\"\");\n parts.push(\"Respond with a JSON array:\");\n parts.push(\"```json\");\n parts.push('[');\n parts.push(' { \"action\": \"reply\", \"tweetId\": \"123\", \"content\": \"wait this is actually wild\", \"reasoning\": \"reacting to interesting take\" },');\n parts.push(' { \"action\": \"like\", \"tweetId\": \"456\", \"reasoning\": \"good thread worth supporting\" }');\n parts.push(']');\n parts.push(\"```\");\n\n return parts.join(\"\\n\");\n}\n\ninterface ToolDecisionPromptInput {\n step: number;\n maxActions: number;\n timeline: Tweet[];\n mentions: Tweet[];\n topicSearchResults?: ResearchContext[\"topicSearchResults\"];\n peopleActivity?: ResearchContext[\"peopleActivity\"];\n executedActions: AgentAction[];\n policyFeedback: string[];\n blockedTweetIds?: string[];\n disallowedActions?: string[];\n}\n\ninterface OpportunityPortfolioPromptInput {\n opportunities: ActionOpportunity[];\n maxActions: number;\n policyFeedback: string[];\n executedActions: AgentAction[];\n}\n\nexport function buildToolDecisionMessage(input: ToolDecisionPromptInput): string {\n const identity = loadIdentity();\n const strategy = loadStrategy();\n const {\n step,\n maxActions,\n timeline,\n mentions,\n topicSearchResults = [],\n peopleActivity = [],\n executedActions,\n policyFeedback,\n blockedTweetIds = [],\n disallowedActions = [],\n } = 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(\"5. Never reuse the same wording across replies; tailor each reply to the specific tweet.\");\n parts.push(\"6. Never interact with your own tweets. No self-replies, self-likes, or self-retweets.\");\n parts.push(\"\");\n\n const priorityTargets = strategy.peopleToEngage\n .filter((person) => person.priority === \"high\")\n .map((person) => `@${person.handle.replace(/^@/, \"\")}`);\n if (priorityTargets.length > 0) {\n parts.push(`Priority targets: ${priorityTargets.slice(0, 5).join(\", \")}`);\n parts.push(\"If any priority target appears in current context, prefer engaging them.\");\n parts.push(\"\");\n }\n\n parts.push(\"Voice lock:\");\n for (const line of buildVoiceLockLines(identity)) {\n parts.push(line);\n }\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 (blockedTweetIds.length > 0) {\n parts.push(\"Tweet IDs you must NOT use this heartbeat:\");\n parts.push(`- ${blockedTweetIds.slice(0, 20).join(\", \")}`);\n parts.push(\"\");\n }\n\n if (disallowedActions.length > 0) {\n parts.push(`Temporarily disallowed actions this heartbeat: ${disallowedActions.join(\", \")}`);\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 if (topicSearchResults.length > 0) {\n parts.push(\"Topic Search (fresh conversations beyond your home timeline):\");\n for (const result of topicSearchResults.slice(0, 2)) {\n parts.push(`- Query: \"${result.query}\"`);\n for (const t of result.tweets.slice(0, 4)) {\n parts.push(` - @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}]`);\n }\n }\n parts.push(\"\");\n }\n\n if (peopleActivity.length > 0) {\n parts.push(\"People Monitoring (accounts you track):\");\n for (const person of peopleActivity.slice(0, 3)) {\n parts.push(`- @${person.handle} (${person.reason})`);\n for (const t of person.tweets.slice(0, 2)) {\n parts.push(` - \"${t.text}\" [tweet:${t.id}]`);\n }\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 buildOpportunityPortfolioMessage(input: OpportunityPortfolioPromptInput): string {\n const identity = loadIdentity();\n const constraints = getPersonaConstraints(identity);\n const strategy = loadStrategy();\n const recentWritten = recentWrittenTextsForPrompt(12);\n const overusedOpenings = findOverusedOpenings(recentWritten);\n const overusedTokens = findOverusedTokens(recentWritten);\n const { opportunities, maxActions, policyFeedback, executedActions } = input;\n const parts: string[] = [];\n\n parts.push(`Select a portfolio of up to ${maxActions} actions from ranked opportunities.`);\n parts.push(\"\");\n parts.push(\"Portfolio goals:\");\n parts.push(\"1. Be socially immersed and grounded in real tweets.\");\n parts.push(\"2. Diversify actions and targets, avoid repetitive reply chains.\");\n parts.push(\"3. Prefer quality over quantity; skip weak opportunities.\");\n parts.push(\"4. Advance current strategy targets and focus areas from memory.\");\n parts.push(\"5. Use only listed candidate IDs.\");\n parts.push(\"\");\n\n const priorityTargets = strategy.peopleToEngage\n .filter((person) => person.priority === \"high\")\n .map((person) => `@${person.handle.replace(/^@/, \"\")}`);\n if (priorityTargets.length > 0) {\n parts.push(`Priority targets: ${priorityTargets.slice(0, 5).join(\", \")}`);\n parts.push(\"When opportunities include these targets, prioritize them.\");\n parts.push(\"\");\n }\n\n parts.push(\"Voice lock:\");\n for (const line of buildVoiceLockLines(identity)) {\n parts.push(line);\n }\n const constraintLines = buildPersonaConstraintLines(constraints);\n if (constraintLines.length > 0) {\n parts.push(\"Operational constraints (hard):\");\n for (const line of constraintLines) {\n parts.push(line);\n }\n }\n parts.push(\"\");\n\n parts.push(\"Human style rotation:\");\n parts.push(\"- For each `reply`/`post`, pick one lane: quick reaction, curious question, friendly pushback, playful line, plain observation.\");\n parts.push(\"- Do not reuse the same lane for multiple content actions in this portfolio.\");\n parts.push(\"- Keep phrasing short and spoken; contractions and fragments are allowed.\");\n if (overusedOpenings.length > 0) {\n parts.push(`- Avoid these repeated opening patterns: ${overusedOpenings.join(\" | \")}`);\n }\n if (overusedTokens.length > 0) {\n parts.push(`- Avoid overused anchor words this round: ${overusedTokens.join(\", \")}`);\n }\n parts.push(\"\");\n\n if (policyFeedback.length > 0) {\n parts.push(\"Latest policy feedback:\");\n for (const feedback of policyFeedback.slice(-6)) {\n parts.push(`- ${feedback}`);\n }\n parts.push(\"\");\n }\n\n if (executedActions.length > 0) {\n parts.push(\"Actions already executed:\");\n for (const action of executedActions) {\n parts.push(`- ${JSON.stringify(action)}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"Opportunities (higher score = better):\");\n for (const opportunity of opportunities) {\n parts.push(\n `- ${opportunity.id} | action=${opportunity.actionType} | score=${opportunity.score.toFixed(2)} | source=${opportunity.source}` +\n `${opportunity.authorHandle ? ` | author=@${opportunity.authorHandle}` : \"\"}` +\n `${opportunity.tweetId ? ` | tweet=${opportunity.tweetId}` : \"\"}`\n );\n parts.push(` summary: ${opportunity.summary}`);\n parts.push(` context: ${opportunity.context}`);\n if (opportunity.requiresContent) {\n parts.push(\" content_required: true\");\n }\n }\n parts.push(\"\");\n\n parts.push(\"Return JSON only in this shape:\");\n parts.push(\"```json\");\n parts.push(\"{\");\n parts.push(' \"selections\": [');\n parts.push(' { \"candidateId\": \"opp-3\", \"content\": \"optional for reply/post\", \"reasoning\": \"short reason\" }');\n parts.push(\" ]\");\n parts.push(\"}\");\n parts.push(\"```\");\n parts.push(\"Rules:\");\n parts.push(\"- For `reply` and `post`, include `content`.\");\n parts.push(\"- Keep content concise, natural, and non-repetitive.\");\n parts.push(\"- Avoid explanatory/essay voice. No lecture framing.\");\n parts.push(\"- Do NOT use abstract philosopher framing unless the identity framework is explicitly philosopher.\");\n parts.push(\"- Prefer short, human syntax: plain sentence fragments are fine.\");\n parts.push(\"- Avoid colon/semicolon/em-dash for non-philosopher personas.\");\n parts.push(\"- Prefer short conversational language: plain words, occasional question, and direct reaction.\");\n parts.push(\"- Reply content target: usually 8-24 words, max 2 short sentences.\");\n parts.push(\"- Prefer at least one non-reply action when viable.\");\n parts.push(\"- Do not target the same author repeatedly in one portfolio.\");\n parts.push(\"- Avoid consensus phrasing like 'you're both right' if your persona is assertive.\");\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\n/**\n * Build a reflection prompt for the agent to review its recent performance.\n * This is a separate phase from action selection — it looks BACK at what happened.\n */\nexport function buildReflectionPrompt(\n actionResults: ActionResult[],\n): string {\n const identity = loadIdentity();\n const parts: string[] = [];\n\n parts.push(`You are ${identity.name} (@${identity.handle}). Time to reflect.`);\n parts.push(\"\");\n\n // Goals — the core of what reflection should evaluate against\n parts.push(\"## Your Goals\");\n for (const goal of identity.goals) {\n parts.push(`- ${goal}`);\n }\n parts.push(\"\");\n\n // What just happened this heartbeat\n if (actionResults.length > 0) {\n parts.push(\"## This Heartbeat\");\n for (const r of actionResults) {\n if (r.success) {\n parts.push(`- ✓ ${r.action}${r.detail ? `: ${r.detail}` : \"\"}`);\n } else {\n parts.push(`- ✗ ${r.action} failed: ${r.error}`);\n }\n }\n parts.push(\"\");\n }\n\n // Strategy context\n const strategyText = renderStrategyForPrompt();\n if (strategyText) {\n parts.push(\"## Current Strategy\");\n parts.push(strategyText);\n parts.push(\"\");\n }\n\n // Performance data — useful context but not the only thing that matters\n const perfSummary = getPerformanceSummary();\n if (perfSummary) {\n parts.push(\"## Performance Context\");\n parts.push(perfSummary);\n parts.push(\"\");\n }\n\n // Recent learnings for context\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n parts.push(\"## Previous Learnings\");\n for (const l of learnings.learnings.slice(-5)) {\n parts.push(`- ${l.content}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"## Your Task\");\n parts.push(\"Reflect on how you're progressing toward your GOALS. Consider:\");\n parts.push(\"- Are your recent actions moving you toward your goals?\");\n parts.push(\"- Are you staying true to who you are while growing?\");\n parts.push(\"- What should you try differently or double down on?\");\n parts.push(\"- Engagement metrics are one signal, but your goals matter more.\");\n parts.push(\"\");\n parts.push(\"Respond with JSON:\");\n parts.push(\"```json\");\n parts.push(\"{\");\n parts.push(' \"learning\": \"one insight about your progress toward your goals (or null)\",');\n parts.push(' \"strategyUpdate\": \"one specific thing to try or change (or null)\"');\n parts.push(\"}\");\n parts.push(\"```\");\n\n return parts.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -6,8 +6,11 @@ import {
|
|
|
6
6
|
} from "./chunk-ZLSDFYBR.js";
|
|
7
7
|
import {
|
|
8
8
|
buildOpportunityPortfolioMessage,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
buildPersonaConstraintLines,
|
|
10
|
+
buildSystemPrompt,
|
|
11
|
+
getPersonaConstraints,
|
|
12
|
+
personaConstraintHandles
|
|
13
|
+
} from "./chunk-E5PEY36J.js";
|
|
11
14
|
import {
|
|
12
15
|
listIntents,
|
|
13
16
|
loadStrategy,
|
|
@@ -510,6 +513,12 @@ function isWritingAction(action) {
|
|
|
510
513
|
function normalizeHandle(handle) {
|
|
511
514
|
return (handle ?? "").replace(/^@/, "").trim().toLowerCase();
|
|
512
515
|
}
|
|
516
|
+
function resolveActionTargetHandle(action, tweetById) {
|
|
517
|
+
if (action.handle) return normalizeHandle(action.handle);
|
|
518
|
+
if (action.targetHandle) return normalizeHandle(action.targetHandle);
|
|
519
|
+
if (action.tweetId) return normalizeHandle(tweetById.get(action.tweetId)?.authorHandle);
|
|
520
|
+
return "";
|
|
521
|
+
}
|
|
513
522
|
function executedWrittenContent(executedActions) {
|
|
514
523
|
return executedActions.filter((a) => isWritingAction(a) && typeof a.content === "string").map((a) => a.content?.trim() ?? "").filter((content) => content.length > 0);
|
|
515
524
|
}
|
|
@@ -583,6 +592,44 @@ function evaluateActionPolicy(context) {
|
|
|
583
592
|
const selfId = (selfUserId ?? "").trim();
|
|
584
593
|
const knownTweets = observedTweets ?? [...timeline, ...mentions];
|
|
585
594
|
const tweetById = new Map(knownTweets.map((tweet) => [tweet.id, tweet]));
|
|
595
|
+
const constraints = getPersonaConstraints();
|
|
596
|
+
const strictReplyHandles = new Set(constraints.onlyReplyToHandles.map((handle) => normalizeHandle(handle)));
|
|
597
|
+
const strictInteractHandles = new Set(personaConstraintHandles(constraints).map((handle) => normalizeHandle(handle)));
|
|
598
|
+
const targetHandle = resolveActionTargetHandle(action, tweetById);
|
|
599
|
+
if (constraints.replyOnlyMode && !["reply", "skip", "learn", "reflect"].includes(action.action)) {
|
|
600
|
+
return {
|
|
601
|
+
allowed: false,
|
|
602
|
+
reason: "Persona is in reply-only mode. Use reply actions only."
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
if (constraints.noOriginalPosts && (action.action === "post" || action.action === "schedule")) {
|
|
606
|
+
return {
|
|
607
|
+
allowed: false,
|
|
608
|
+
reason: "Persona forbids standalone original posts."
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
if (strictReplyHandles.size > 0) {
|
|
612
|
+
if (action.action !== "reply") {
|
|
613
|
+
return {
|
|
614
|
+
allowed: false,
|
|
615
|
+
reason: `Persona requires replying only to specific target(s): @${[...strictReplyHandles].join(", @")}.`
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
if (!targetHandle || !strictReplyHandles.has(targetHandle)) {
|
|
619
|
+
return {
|
|
620
|
+
allowed: false,
|
|
621
|
+
reason: `Reply target must be one of @${[...strictReplyHandles].join(", @")}.`
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (strictInteractHandles.size > 0 && ["reply", "like", "retweet", "follow"].includes(action.action)) {
|
|
626
|
+
if (!targetHandle || !strictInteractHandles.has(targetHandle)) {
|
|
627
|
+
return {
|
|
628
|
+
allowed: false,
|
|
629
|
+
reason: `Interaction target must be one of @${[...strictInteractHandles].join(", @")}.`
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
}
|
|
586
633
|
if (isDuplicateTarget(action, executedActions)) {
|
|
587
634
|
return { allowed: false, reason: `Action ${action.action} already executed for tweet ${action.tweetId} this heartbeat.` };
|
|
588
635
|
}
|
|
@@ -1194,6 +1241,8 @@ async function runResearchPhase(client, heartbeatCount) {
|
|
|
1194
1241
|
async function runTopicSearch(client, heartbeatCount, seedTweets) {
|
|
1195
1242
|
try {
|
|
1196
1243
|
const identity = loadIdentity();
|
|
1244
|
+
const constraints = getPersonaConstraints(identity);
|
|
1245
|
+
const strictHandles = personaConstraintHandles(constraints).filter(Boolean);
|
|
1197
1246
|
const strategy = loadStrategy();
|
|
1198
1247
|
const selfHandle = canonicalAgentHandle(identity.handle);
|
|
1199
1248
|
const allTopics = [
|
|
@@ -1205,10 +1254,15 @@ async function runTopicSearch(client, heartbeatCount, seedTweets) {
|
|
|
1205
1254
|
...strategy.peopleToEngage.filter((person) => person.priority === "high" || person.priority === "medium").map((person) => person.handle.replace(/^@/, "").toLowerCase()),
|
|
1206
1255
|
...(identity.heroes ?? []).map((handle) => handle.replace(/^@/, "").toLowerCase())
|
|
1207
1256
|
])].filter((handle) => handle && handle !== selfHandle);
|
|
1257
|
+
const strictQueries = buildTargetedPersonQueries(
|
|
1258
|
+
strictHandles.filter((handle) => handle !== selfHandle),
|
|
1259
|
+
heartbeatCount,
|
|
1260
|
+
3
|
|
1261
|
+
);
|
|
1208
1262
|
const personQueries = buildTargetedPersonQueries(targetHandles, heartbeatCount, 2);
|
|
1209
1263
|
const topicQueries = allTopics.length > 0 ? pickTopicQueries(allTopics, Math.min(3, Math.max(2, allTopics.length))) : [];
|
|
1210
1264
|
const discoveredQueries = discovered.length > 0 ? pickDirectQueries(discovered, Math.min(2, discovered.length)) : [];
|
|
1211
|
-
const topicsToSearch = [.../* @__PURE__ */ new Set([...topicQueries, ...discoveredQueries, ...personQueries])];
|
|
1265
|
+
const topicsToSearch = strictQueries.length > 0 ? [...new Set(strictQueries)] : [.../* @__PURE__ */ new Set([...topicQueries, ...discoveredQueries, ...personQueries])];
|
|
1212
1266
|
if (topicsToSearch.length === 0) return [];
|
|
1213
1267
|
const results = [];
|
|
1214
1268
|
for (const topicQuery of topicsToSearch) {
|
|
@@ -1232,10 +1286,34 @@ async function runPeopleMonitoring(client, heartbeatCount, seedTweets) {
|
|
|
1232
1286
|
try {
|
|
1233
1287
|
const strategy = loadStrategy();
|
|
1234
1288
|
const identity = loadIdentity();
|
|
1289
|
+
const constraints = getPersonaConstraints(identity);
|
|
1290
|
+
const strictHandles = personaConstraintHandles(constraints).map((handle) => canonicalAgentHandle(handle)).filter((handle) => handle.length > 0);
|
|
1235
1291
|
const selfHandle = identity.handle.replace(/^@/, "").toLowerCase();
|
|
1236
1292
|
const relationships = loadRelationships();
|
|
1237
1293
|
const networkHandles = listAgentNetworkHandles(20);
|
|
1238
1294
|
const networkHandleSet = new Set(networkHandles);
|
|
1295
|
+
if (strictHandles.length > 0) {
|
|
1296
|
+
const strictResults = [];
|
|
1297
|
+
for (const handle of strictHandles) {
|
|
1298
|
+
if (handle === selfHandle) continue;
|
|
1299
|
+
const userId = await resolveHandleToId(client, handle);
|
|
1300
|
+
if (!userId) continue;
|
|
1301
|
+
try {
|
|
1302
|
+
const tweets = await client.getUserTweets(userId, { count: 8 });
|
|
1303
|
+
if (tweets.length === 0) continue;
|
|
1304
|
+
strictResults.push({
|
|
1305
|
+
handle,
|
|
1306
|
+
userId,
|
|
1307
|
+
reason: "persona hard constraint",
|
|
1308
|
+
tweets
|
|
1309
|
+
});
|
|
1310
|
+
upsertAgentHandle(handle, "observed", "people check (strict persona target)");
|
|
1311
|
+
logger.info(`People check @${handle}: ${tweets.length} recent tweets (strict target mode)`);
|
|
1312
|
+
} catch {
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
return strictResults;
|
|
1316
|
+
}
|
|
1239
1317
|
const people = [];
|
|
1240
1318
|
const seen = /* @__PURE__ */ new Set();
|
|
1241
1319
|
const highPriorityHandles = new Set(
|
|
@@ -1384,6 +1462,7 @@ function unique(values) {
|
|
|
1384
1462
|
}
|
|
1385
1463
|
function buildPersonaContext() {
|
|
1386
1464
|
const identity = loadIdentity();
|
|
1465
|
+
const constraints = getPersonaConstraints(identity);
|
|
1387
1466
|
const strategy = loadStrategy();
|
|
1388
1467
|
const focusKeywords = unique(
|
|
1389
1468
|
[
|
|
@@ -1400,6 +1479,9 @@ function buildPersonaContext() {
|
|
|
1400
1479
|
const priorityHandles = new Set(
|
|
1401
1480
|
strategy.peopleToEngage.filter((person) => person.priority === "high").map((person) => normalizeHandle3(person.handle)).filter(Boolean)
|
|
1402
1481
|
);
|
|
1482
|
+
for (const handle of personaConstraintHandles(constraints)) {
|
|
1483
|
+
priorityHandles.add(normalizeHandle3(handle));
|
|
1484
|
+
}
|
|
1403
1485
|
const heroHandles = new Set(
|
|
1404
1486
|
(identity.heroes ?? []).map((handle) => normalizeHandle3(handle)).filter(Boolean)
|
|
1405
1487
|
);
|
|
@@ -1505,6 +1587,9 @@ function buildActionOpportunities(input) {
|
|
|
1505
1587
|
const maxCandidates = input.maxCandidates ?? 28;
|
|
1506
1588
|
const selfHandle = normalizeHandle3(input.selfHandle);
|
|
1507
1589
|
const selfUserId = (input.selfUserId ?? "").trim();
|
|
1590
|
+
const constraints = getPersonaConstraints();
|
|
1591
|
+
const onlyReplyHandles = new Set(constraints.onlyReplyToHandles.map((h) => normalizeHandle3(h)));
|
|
1592
|
+
const onlyInteractHandles = new Set(constraints.onlyInteractWithHandles.map((h) => normalizeHandle3(h)));
|
|
1508
1593
|
const persona = buildPersonaContext();
|
|
1509
1594
|
const recent = getRecentInteractions(300);
|
|
1510
1595
|
const {
|
|
@@ -1529,6 +1614,7 @@ function buildActionOpportunities(input) {
|
|
|
1529
1614
|
const handle = normalizeHandle3(candidate.tweet.authorHandle);
|
|
1530
1615
|
if (!candidate.tweet.id || !handle || handle === selfHandle) continue;
|
|
1531
1616
|
if (selfUserId && candidate.tweet.authorId === selfUserId) continue;
|
|
1617
|
+
if (onlyInteractHandles.size > 0 && !onlyInteractHandles.has(handle)) continue;
|
|
1532
1618
|
const existing = dedupedByTweetId.get(candidate.tweet.id);
|
|
1533
1619
|
if (!existing || sourceWeight(candidate.source) > sourceWeight(existing.source)) {
|
|
1534
1620
|
dedupedByTweetId.set(candidate.tweet.id, candidate);
|
|
@@ -1566,7 +1652,7 @@ function buildActionOpportunities(input) {
|
|
|
1566
1652
|
context: `@${handle}: "${shortTweet}"`
|
|
1567
1653
|
});
|
|
1568
1654
|
const stronglyRelevant = alignment >= 0.35 || source === "mention" || source === "people_watch" || persona.priorityHandles.has(handle);
|
|
1569
|
-
if (!likedTweetIds.has(tweet.id) && baseScore >= 1.8 && stronglyRelevant) {
|
|
1655
|
+
if (onlyReplyHandles.size === 0 && !constraints.replyOnlyMode && !likedTweetIds.has(tweet.id) && baseScore >= 1.8 && stronglyRelevant) {
|
|
1570
1656
|
opportunities.push({
|
|
1571
1657
|
id: nextId(),
|
|
1572
1658
|
armKey: armKey("like", source),
|
|
@@ -1581,7 +1667,7 @@ function buildActionOpportunities(input) {
|
|
|
1581
1667
|
context: `@${handle}: "${shortTweet}"`
|
|
1582
1668
|
});
|
|
1583
1669
|
}
|
|
1584
|
-
if (!retweetedTweetIds.has(tweet.id) && baseScore >= 2.6 && alignment >= 0.15) {
|
|
1670
|
+
if (onlyReplyHandles.size === 0 && !constraints.replyOnlyMode && !retweetedTweetIds.has(tweet.id) && baseScore >= 2.6 && alignment >= 0.15) {
|
|
1585
1671
|
opportunities.push({
|
|
1586
1672
|
id: nextId(),
|
|
1587
1673
|
armKey: armKey("retweet", source),
|
|
@@ -1596,7 +1682,7 @@ function buildActionOpportunities(input) {
|
|
|
1596
1682
|
context: `@${handle}: "${shortTweet}"`
|
|
1597
1683
|
});
|
|
1598
1684
|
}
|
|
1599
|
-
const shouldConsiderFollow = !followedHandles.has(handle) && !followOpportunityByHandle.has(handle) && !isLikelySyntheticHandle2(handle) && baseScore >= 3 && (persona.priorityHandles.has(handle) || persona.heroHandles.has(handle) || source === "mention" || alignment >= 0.8);
|
|
1685
|
+
const shouldConsiderFollow = onlyReplyHandles.size === 0 && !constraints.replyOnlyMode && !followedHandles.has(handle) && !followOpportunityByHandle.has(handle) && !isLikelySyntheticHandle2(handle) && baseScore >= 3 && (persona.priorityHandles.has(handle) || persona.heroHandles.has(handle) || source === "mention" || alignment >= 0.8);
|
|
1600
1686
|
if (shouldConsiderFollow) {
|
|
1601
1687
|
followOpportunityByHandle.add(handle);
|
|
1602
1688
|
opportunities.push({
|
|
@@ -1614,7 +1700,7 @@ function buildActionOpportunities(input) {
|
|
|
1614
1700
|
}
|
|
1615
1701
|
}
|
|
1616
1702
|
const queryList = research.topicSearchResults.map((r) => r.query).filter(Boolean);
|
|
1617
|
-
if (queryList.length > 0) {
|
|
1703
|
+
if (queryList.length > 0 && !constraints.noOriginalPosts && !constraints.replyOnlyMode && onlyInteractHandles.size === 0 && onlyReplyHandles.size === 0) {
|
|
1618
1704
|
opportunities.push({
|
|
1619
1705
|
id: nextId(),
|
|
1620
1706
|
armKey: armKey("post", "synthesis"),
|
|
@@ -2062,6 +2148,12 @@ async function rewriteDraftForHumanVoice(input) {
|
|
|
2062
2148
|
}
|
|
2063
2149
|
async function runAutonomyCycle(maxActions, heartbeatCount = 0) {
|
|
2064
2150
|
const client = await getXClient();
|
|
2151
|
+
const constraints = getPersonaConstraints();
|
|
2152
|
+
const strictReplyOnly = constraints.replyOnlyMode || constraints.onlyReplyToHandles.length > 0;
|
|
2153
|
+
const constraintLines = buildPersonaConstraintLines(constraints);
|
|
2154
|
+
if (constraintLines.length > 0) {
|
|
2155
|
+
logger.info(`Persona constraints active: ${constraintLines.join(" | ")}`);
|
|
2156
|
+
}
|
|
2065
2157
|
try {
|
|
2066
2158
|
const delayed = await collectDelayedOutcomes(client);
|
|
2067
2159
|
if (delayed.processed > 0) {
|
|
@@ -2167,7 +2259,7 @@ async function runAutonomyCycle(maxActions, heartbeatCount = 0) {
|
|
|
2167
2259
|
policyFeedback,
|
|
2168
2260
|
executedActions: actions
|
|
2169
2261
|
});
|
|
2170
|
-
if (plannedActions.length > 1 && plannedActions.every((a) => a.action === "reply")) {
|
|
2262
|
+
if (!strictReplyOnly && plannedActions.length > 1 && plannedActions.every((a) => a.action === "reply")) {
|
|
2171
2263
|
const nonReplyCandidate = candidates.find(
|
|
2172
2264
|
(opportunity) => opportunity.actionType !== "reply" && !opportunity.requiresContent
|
|
2173
2265
|
);
|
|
@@ -2193,7 +2285,7 @@ async function runAutonomyCycle(maxActions, heartbeatCount = 0) {
|
|
|
2193
2285
|
});
|
|
2194
2286
|
if (!touchesPriorityTarget) {
|
|
2195
2287
|
const priorityCandidate = candidates.find(
|
|
2196
|
-
(opportunity) => Boolean(opportunity.authorHandle) && priorityHandles.has(normalizeHandle4(opportunity.authorHandle)) && !opportunity.requiresContent
|
|
2288
|
+
(opportunity) => Boolean(opportunity.authorHandle) && priorityHandles.has(normalizeHandle4(opportunity.authorHandle)) && (!strictReplyOnly ? !opportunity.requiresContent : opportunity.actionType === "reply")
|
|
2197
2289
|
);
|
|
2198
2290
|
if (priorityCandidate) {
|
|
2199
2291
|
plannedActions = [
|
|
@@ -2271,7 +2363,7 @@ async function runAutonomyCycle(maxActions, heartbeatCount = 0) {
|
|
|
2271
2363
|
}
|
|
2272
2364
|
if (candidateAction.action === "reply") {
|
|
2273
2365
|
replyRejectionCount += 1;
|
|
2274
|
-
if (replyRejectionCount >= 2) {
|
|
2366
|
+
if (replyRejectionCount >= 2 && !strictReplyOnly) {
|
|
2275
2367
|
disallowedActions.add("reply");
|
|
2276
2368
|
const pivot = "Reply opportunities exhausted this heartbeat. Pivot to like/retweet/follow/post.";
|
|
2277
2369
|
policyFeedback.push(pivot);
|
|
@@ -2305,10 +2397,16 @@ async function runAutonomyCycle(maxActions, heartbeatCount = 0) {
|
|
|
2305
2397
|
blockedTweetIds.add(candidateAction.tweetId);
|
|
2306
2398
|
}
|
|
2307
2399
|
if (candidateAction.action === "reply" && /duplicate content/i.test(err)) {
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2400
|
+
if (!strictReplyOnly) {
|
|
2401
|
+
disallowedActions.add("reply");
|
|
2402
|
+
const reason = "Reply failed with duplicate-content error. Switch to non-reply actions.";
|
|
2403
|
+
policyFeedback.push(reason);
|
|
2404
|
+
logger.info(`Policy adjustment: ${reason}`);
|
|
2405
|
+
} else {
|
|
2406
|
+
const reason = "Reply failed with duplicate-content error. Keep reply mode but use a new angle/target.";
|
|
2407
|
+
policyFeedback.push(reason);
|
|
2408
|
+
logger.info(`Policy adjustment: ${reason}`);
|
|
2409
|
+
}
|
|
2312
2410
|
}
|
|
2313
2411
|
if ((candidateAction.action === "post" || candidateAction.action === "schedule") && /duplicate content/i.test(err)) {
|
|
2314
2412
|
const reason = "Write-path duplicate-content failure. Change framing and try a different angle.";
|
|
@@ -2335,4 +2433,4 @@ async function runAutonomyCycle(maxActions, heartbeatCount = 0) {
|
|
|
2335
2433
|
export {
|
|
2336
2434
|
runAutonomyCycle
|
|
2337
2435
|
};
|
|
2338
|
-
//# sourceMappingURL=chunk-
|
|
2436
|
+
//# sourceMappingURL=chunk-FBHLDOMC.js.map
|