spora 0.6.3 → 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-LKCYTFWN.js → chunk-AOQ3WLZV.js} +86 -106
- 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-4POAJONO.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-STNSQDYA.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-5PWQERHL.js → heartbeat-TNEPE3ZP.js} +83 -92
- package/dist/heartbeat-TNEPE3ZP.js.map +1 -0
- package/dist/{identity-O4FLSZKZ.js → identity-VDUW4I2K.js} +3 -3
- package/dist/{init-E54LQDKA.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-P6PZ3TP6.js → web-chat-3HM35XM4.js} +30 -85
- 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-53YLFYJF.js.map +0 -1
- package/dist/chunk-55XPDJ6P.js +0 -124
- package/dist/chunk-55XPDJ6P.js.map +0 -1
- package/dist/chunk-B6RPMDML.js.map +0 -1
- package/dist/chunk-H2N5G6R7.js +0 -249
- package/dist/chunk-H2N5G6R7.js.map +0 -1
- package/dist/chunk-LKCYTFWN.js.map +0 -1
- package/dist/chunk-QOKQ5OTU.js.map +0 -1
- package/dist/chunk-ZJZKH7N7.js.map +0 -1
- package/dist/chunk-ZMTC7BYD.js +0 -32
- package/dist/chunk-ZMTC7BYD.js.map +0 -1
- package/dist/client-GCHDQ6W2.js +0 -350
- package/dist/client-GCHDQ6W2.js.map +0 -1
- package/dist/client-I7Q4HC4F.js +0 -401
- package/dist/client-I7Q4HC4F.js.map +0 -1
- package/dist/decision-engine-SO33N7CT.js +0 -19
- package/dist/heartbeat-5PWQERHL.js.map +0 -1
- package/dist/init-E54LQDKA.js.map +0 -1
- package/dist/llm-3LSNADSR.js +0 -16
- package/dist/prompt-builder-3LQFX6QK.js +0 -23
- package/dist/queue-CXMLAQ6X.js +0 -14
- package/dist/web-chat-P6PZ3TP6.js.map +0 -1
- package/dist/x-client-7LMNSOTE.js +0 -12
- /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-4POAJONO.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-STNSQDYA.js.map → colony-JPZC3R34.js.map} +0 -0
- /package/dist/{crypto-FHSQ72NU.js.map → config-FL4VJVKZ.js.map} +0 -0
- /package/dist/{decision-engine-SO33N7CT.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-3LQFX6QK.js.map → prompt-builder-5NYONN2W.js.map} +0 -0
- /package/dist/{queue-CXMLAQ6X.js.map → queue-G5PTE6R6.js.map} +0 -0
- /package/dist/{strategy-S45TX766.js.map → strategy-Z4JSFHSP.js.map} +0 -0
- /package/dist/{x-client-7LMNSOTE.js.map → x-client-GY6XSPK6.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/llm.ts"],"sourcesContent":["import Anthropic from \"@anthropic-ai/sdk\";\nimport OpenAI from \"openai\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nexport type LLMProvider = \"anthropic\" | \"openai\" | \"deepseek\";\n\ninterface StoredKeys {\n anthropic?: string;\n openai?: string;\n deepseek?: string;\n}\n\nconst DEFAULT_MODEL_BY_PROVIDER: Record<LLMProvider, string> = {\n anthropic: \"claude-sonnet-4-20250514\",\n openai: \"gpt-4o-mini\",\n deepseek: \"deepseek-chat\",\n};\n\nlet anthropicClient: Anthropic | null = null;\nlet openaiClient: OpenAI | null = null;\nlet deepseekClient: OpenAI | null = null;\n\nfunction getConfiguredProvider(): LLMProvider {\n const config = loadConfig();\n return (config.llm?.provider ?? \"deepseek\") as LLMProvider;\n}\n\nfunction loadStoredKeys(): StoredKeys {\n if (!existsSync(paths.llmKeys)) {\n return {};\n }\n\n try {\n return JSON.parse(readFileSync(paths.llmKeys, \"utf-8\")) as StoredKeys;\n } catch {\n return {};\n }\n}\n\nfunction saveStoredKeys(keys: StoredKeys): void {\n writeFileSync(paths.llmKeys, JSON.stringify(keys, null, 2), { mode: 0o600 });\n}\n\nfunction envKeyForProvider(provider: LLMProvider): string | undefined {\n if (provider === \"anthropic\") return process.env.ANTHROPIC_API_KEY;\n if (provider === \"openai\") return process.env.OPENAI_API_KEY;\n return process.env.DEEPSEEK_API_KEY;\n}\n\nexport function getLLMApiKey(provider: LLMProvider = getConfiguredProvider()): string | null {\n const envKey = envKeyForProvider(provider);\n if (envKey) return envKey;\n\n const keys = loadStoredKeys();\n const stored = keys[provider];\n if (stored) return stored;\n\n // Backward compatibility for old single-key installs.\n if (existsSync(paths.llmKey)) {\n const legacy = readFileSync(paths.llmKey, \"utf-8\").trim();\n return legacy.length > 0 ? legacy : null;\n }\n\n return null;\n}\n\nexport function hasLLMKey(provider: LLMProvider = getConfiguredProvider()): boolean {\n return getLLMApiKey(provider) !== null;\n}\n\nexport function setLLMApiKey(provider: LLMProvider, apiKey: string): void {\n const keys = loadStoredKeys();\n keys[provider] = apiKey;\n saveStoredKeys(keys);\n}\n\nexport function listLLMKeyStatus(): Record<LLMProvider, boolean> {\n return {\n anthropic: hasLLMKey(\"anthropic\"),\n openai: hasLLMKey(\"openai\"),\n deepseek: hasLLMKey(\"deepseek\"),\n };\n}\n\nexport function getDefaultModel(provider: LLMProvider): string {\n return DEFAULT_MODEL_BY_PROVIDER[provider];\n}\n\nfunction getAnthropicClient(): Anthropic {\n if (anthropicClient) return anthropicClient;\n const apiKey = getLLMApiKey(\"anthropic\");\n if (!apiKey) {\n throw new Error(\"No Anthropic API key configured. Run `spora llm set --provider anthropic`.\");\n }\n anthropicClient = new Anthropic({ apiKey });\n return anthropicClient;\n}\n\nfunction getOpenAIClient(): OpenAI {\n if (openaiClient) return openaiClient;\n const apiKey = getLLMApiKey(\"openai\");\n if (!apiKey) {\n throw new Error(\"No OpenAI API key configured. Run `spora llm set --provider openai`.\");\n }\n openaiClient = new OpenAI({ apiKey });\n return openaiClient;\n}\n\nfunction getDeepSeekClient(): OpenAI {\n if (deepseekClient) return deepseekClient;\n const apiKey = getLLMApiKey(\"deepseek\");\n if (!apiKey) {\n throw new Error(\"No DeepSeek API key configured. Run `spora llm set --provider deepseek`.\");\n }\n deepseekClient = new OpenAI({ apiKey, baseURL: \"https://api.deepseek.com\" });\n return deepseekClient;\n}\n\nexport interface LLMResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n}\n\nexport async function generateResponse(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n return chat(systemPrompt, [{ role: \"user\", content: userMessage }]);\n}\n\nexport async function chat(\n systemPrompt: string,\n messages: Array<{ role: \"user\" | \"assistant\"; content: string }>,\n): Promise<LLMResponse> {\n const config = loadConfig();\n const provider = (config.llm?.provider ?? \"deepseek\") as LLMProvider;\n const model = config.llm?.model ?? getDefaultModel(provider);\n\n if (provider === \"anthropic\") {\n return callAnthropic(model, systemPrompt, messages);\n }\n if (provider === \"openai\") {\n return callOpenAI(model, systemPrompt, messages);\n }\n return callDeepSeek(model, systemPrompt, messages);\n}\n\nasync function callAnthropic(\n model: string,\n systemPrompt: string,\n messages: Array<{ role: \"user\" | \"assistant\"; content: string }>,\n): Promise<LLMResponse> {\n logger.info(`Calling Anthropic (${model})...`);\n\n const anthropic = getAnthropicClient();\n const response = await anthropic.messages.create({\n model,\n max_tokens: 2048,\n system: systemPrompt,\n messages,\n });\n\n const textBlock = response.content.find((b) => b.type === \"text\");\n const content = textBlock ? textBlock.text : \"\";\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n}\n\nasync function callOpenAI(\n model: string,\n systemPrompt: string,\n messages: Array<{ role: \"user\" | \"assistant\"; content: string }>,\n): Promise<LLMResponse> {\n logger.info(`Calling OpenAI (${model})...`);\n\n const client = getOpenAIClient();\n const response = await client.chat.completions.create({\n model,\n max_tokens: 2048,\n messages: [\n { role: \"system\", content: systemPrompt },\n ...messages,\n ],\n });\n\n const content = response.choices[0]?.message?.content ?? \"\";\n\n return {\n content,\n inputTokens: response.usage?.prompt_tokens ?? 0,\n outputTokens: response.usage?.completion_tokens ?? 0,\n };\n}\n\nasync function callDeepSeek(\n model: string,\n systemPrompt: string,\n messages: Array<{ role: \"user\" | \"assistant\"; content: string }>,\n): Promise<LLMResponse> {\n logger.info(`Calling DeepSeek (${model})...`);\n\n const client = getDeepSeekClient();\n const response = await client.chat.completions.create({\n model,\n max_tokens: 2048,\n messages: [\n { role: \"system\", content: systemPrompt },\n ...messages,\n ],\n });\n\n const content = response.choices[0]?.message?.content ?? \"\";\n\n return {\n content,\n inputTokens: response.usage?.prompt_tokens ?? 0,\n outputTokens: response.usage?.completion_tokens ?? 0,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-NPV3OV2K.js";
|
|
1
4
|
import {
|
|
2
5
|
loadConfig,
|
|
3
6
|
saveConfig
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
logger
|
|
7
|
-
} from "./chunk-QOKQ5OTU.js";
|
|
7
|
+
} from "./chunk-NO3NQN67.js";
|
|
8
8
|
|
|
9
9
|
// src/x-client/rate-limiter.ts
|
|
10
10
|
var RateLimiter = class {
|
|
@@ -44,7 +44,7 @@ var RateLimiter = class {
|
|
|
44
44
|
const config = loadConfig();
|
|
45
45
|
if (config.xMethod === "api" && config.xApiTier !== "basic") {
|
|
46
46
|
throw new Error(
|
|
47
|
-
`${action} requires X API Basic tier ($200/mo). Current tier: ${config.xApiTier ?? "free"}.
|
|
47
|
+
`${action} requires X API Basic tier ($200/mo). Current tier: ${config.xApiTier ?? "free"}. Upgrade your API tier or adjust runtime behavior.`
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -54,4 +54,4 @@ var rateLimiter = new RateLimiter();
|
|
|
54
54
|
export {
|
|
55
55
|
rateLimiter
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-LXQNVVIY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/x-client/rate-limiter.ts"],"sourcesContent":["import { loadConfig, saveConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nexport class RateLimiter {\n private checkResetDate(): void {\n const config = loadConfig();\n const now = new Date();\n const resetDate = new Date(config.credits.resetDate);\n\n if (now >= resetDate) {\n config.credits.postsUsedThisMonth = 0;\n const nextReset = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n config.credits.resetDate = nextReset.toISOString();\n saveConfig(config);\n logger.info(\"Monthly credits reset\");\n }\n }\n\n canPost(): boolean {\n this.checkResetDate();\n const config = loadConfig();\n return config.credits.postsUsedThisMonth < config.credits.monthlyPostLimit;\n }\n\n remaining(): number {\n this.checkResetDate();\n const config = loadConfig();\n return config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;\n }\n\n consume(count: number = 1): void {\n this.checkResetDate();\n const config = loadConfig();\n config.credits.postsUsedThisMonth += count;\n saveConfig(config);\n\n const remaining = config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;\n if (remaining <= Math.floor(config.credits.monthlyPostLimit * 0.2)) {\n logger.warn(`Low credits: ${remaining} posts remaining this month`);\n }\n }\n\n requireBasicTier(action: string): void {\n const config = loadConfig();\n if (config.xMethod === \"api\" && config.xApiTier !== \"basic\") {\n throw new Error(\n `${action} requires X API Basic tier ($200/mo). ` +\n `Current tier: ${config.xApiTier ?? \"free\"}. ` +\n `
|
|
1
|
+
{"version":3,"sources":["../src/x-client/rate-limiter.ts"],"sourcesContent":["import { loadConfig, saveConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nexport class RateLimiter {\n private checkResetDate(): void {\n const config = loadConfig();\n const now = new Date();\n const resetDate = new Date(config.credits.resetDate);\n\n if (now >= resetDate) {\n config.credits.postsUsedThisMonth = 0;\n const nextReset = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n config.credits.resetDate = nextReset.toISOString();\n saveConfig(config);\n logger.info(\"Monthly credits reset\");\n }\n }\n\n canPost(): boolean {\n this.checkResetDate();\n const config = loadConfig();\n return config.credits.postsUsedThisMonth < config.credits.monthlyPostLimit;\n }\n\n remaining(): number {\n this.checkResetDate();\n const config = loadConfig();\n return config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;\n }\n\n consume(count: number = 1): void {\n this.checkResetDate();\n const config = loadConfig();\n config.credits.postsUsedThisMonth += count;\n saveConfig(config);\n\n const remaining = config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;\n if (remaining <= Math.floor(config.credits.monthlyPostLimit * 0.2)) {\n logger.warn(`Low credits: ${remaining} posts remaining this month`);\n }\n }\n\n requireBasicTier(action: string): void {\n const config = loadConfig();\n if (config.xMethod === \"api\" && config.xApiTier !== \"basic\") {\n throw new Error(\n `${action} requires X API Basic tier ($200/mo). ` +\n `Current tier: ${config.xApiTier ?? \"free\"}. ` +\n `Upgrade your API tier or adjust runtime behavior.`\n );\n }\n }\n}\n\nexport const rateLimiter = new RateLimiter();\n"],"mappings":";;;;;;;;;AAGO,IAAM,cAAN,MAAkB;AAAA,EACf,iBAAuB;AAC7B,UAAM,SAAS,WAAW;AAC1B,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,YAAY,IAAI,KAAK,OAAO,QAAQ,SAAS;AAEnD,QAAI,OAAO,WAAW;AACpB,aAAO,QAAQ,qBAAqB;AACpC,YAAM,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC;AACnE,aAAO,QAAQ,YAAY,UAAU,YAAY;AACjD,iBAAW,MAAM;AACjB,aAAO,KAAK,uBAAuB;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,UAAmB;AACjB,SAAK,eAAe;AACpB,UAAM,SAAS,WAAW;AAC1B,WAAO,OAAO,QAAQ,qBAAqB,OAAO,QAAQ;AAAA,EAC5D;AAAA,EAEA,YAAoB;AAClB,SAAK,eAAe;AACpB,UAAM,SAAS,WAAW;AAC1B,WAAO,OAAO,QAAQ,mBAAmB,OAAO,QAAQ;AAAA,EAC1D;AAAA,EAEA,QAAQ,QAAgB,GAAS;AAC/B,SAAK,eAAe;AACpB,UAAM,SAAS,WAAW;AAC1B,WAAO,QAAQ,sBAAsB;AACrC,eAAW,MAAM;AAEjB,UAAM,YAAY,OAAO,QAAQ,mBAAmB,OAAO,QAAQ;AACnE,QAAI,aAAa,KAAK,MAAM,OAAO,QAAQ,mBAAmB,GAAG,GAAG;AAClE,aAAO,KAAK,gBAAgB,SAAS,6BAA6B;AAAA,IACpE;AAAA,EACF;AAAA,EAEA,iBAAiB,QAAsB;AACrC,UAAM,SAAS,WAAW;AAC1B,QAAI,OAAO,YAAY,SAAS,OAAO,aAAa,SAAS;AAC3D,YAAM,IAAI;AAAA,QACR,GAAG,MAAM,uDACU,OAAO,YAAY,MAAM;AAAA,MAE9C;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,cAAc,IAAI,YAAY;","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/identity/index.ts
|
|
7
7
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
@@ -619,4 +619,4 @@ export {
|
|
|
619
619
|
mutateIdentity,
|
|
620
620
|
renderIdentityDocument
|
|
621
621
|
};
|
|
622
|
-
//# sourceMappingURL=chunk-
|
|
622
|
+
//# sourceMappingURL=chunk-M6YOQVSI.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureDirectories,
|
|
3
3
|
paths
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3RYCUGXE.js";
|
|
5
5
|
|
|
6
6
|
// src/utils/config.ts
|
|
7
7
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
var ConfigSchema = z.object({
|
|
10
10
|
version: z.literal(1),
|
|
11
|
-
xMethod: z.
|
|
11
|
+
xMethod: z.literal("api"),
|
|
12
12
|
xApiTier: z.enum(["free", "basic"]).optional(),
|
|
13
13
|
credits: z.object({
|
|
14
14
|
monthlyPostLimit: z.number(),
|
|
@@ -27,7 +27,7 @@ var ConfigSchema = z.object({
|
|
|
27
27
|
}).optional(),
|
|
28
28
|
runtime: z.object({
|
|
29
29
|
heartbeatIntervalMs: z.number().default(3e5),
|
|
30
|
-
actionsPerHeartbeat: z.number().default(
|
|
30
|
+
actionsPerHeartbeat: z.number().default(4),
|
|
31
31
|
enabled: z.boolean().default(false)
|
|
32
32
|
}).optional(),
|
|
33
33
|
connection: z.object({
|
|
@@ -42,7 +42,17 @@ function loadConfig() {
|
|
|
42
42
|
throw new Error("Spora not initialized. Run `spora init` first.");
|
|
43
43
|
}
|
|
44
44
|
const raw = readFileSync(paths.config, "utf-8");
|
|
45
|
-
|
|
45
|
+
const parsed = JSON.parse(raw);
|
|
46
|
+
if (parsed.xMethod !== "api") {
|
|
47
|
+
parsed.xMethod = "api";
|
|
48
|
+
if (parsed.xApiTier !== "basic" && parsed.xApiTier !== "free") {
|
|
49
|
+
parsed.xApiTier = "basic";
|
|
50
|
+
}
|
|
51
|
+
const migrated = ConfigSchema.parse(parsed);
|
|
52
|
+
saveConfig(migrated);
|
|
53
|
+
return migrated;
|
|
54
|
+
}
|
|
55
|
+
return ConfigSchema.parse(parsed);
|
|
46
56
|
}
|
|
47
57
|
function saveConfig(config) {
|
|
48
58
|
ensureDirectories();
|
|
@@ -55,7 +65,7 @@ function createDefaultConfig(overrides) {
|
|
|
55
65
|
const resetDate = new Date(now.getFullYear(), now.getMonth() + 1, 1).toISOString();
|
|
56
66
|
return {
|
|
57
67
|
version: 1,
|
|
58
|
-
xMethod:
|
|
68
|
+
xMethod: "api",
|
|
59
69
|
xApiTier: overrides.xApiTier,
|
|
60
70
|
credits: {
|
|
61
71
|
monthlyPostLimit: monthlyLimit,
|
|
@@ -77,4 +87,4 @@ export {
|
|
|
77
87
|
saveConfig,
|
|
78
88
|
createDefaultConfig
|
|
79
89
|
};
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
90
|
+
//# sourceMappingURL=chunk-NO3NQN67.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { z } from \"zod\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nexport const ConfigSchema = z.object({\n version: z.literal(1),\n xMethod: z.literal(\"api\"),\n xApiTier: z.enum([\"free\", \"basic\"]).optional(),\n\n credits: z.object({\n monthlyPostLimit: z.number(),\n postsUsedThisMonth: z.number(),\n resetDate: z.string(),\n }),\n\n schedule: z.object({\n postsPerDay: z.number(),\n activeHoursStart: z.number().min(0).max(23),\n activeHoursEnd: z.number().min(0).max(23),\n timezone: z.string(),\n }),\n\n llm: z.object({\n provider: z.enum([\"anthropic\", \"openai\", \"deepseek\"]).default(\"deepseek\"),\n model: z.string().default(\"deepseek-chat\"),\n }).optional(),\n\n runtime: z.object({\n heartbeatIntervalMs: z.number().default(300_000),\n actionsPerHeartbeat: z.number().default(4),\n enabled: z.boolean().default(false),\n }).optional(),\n\n connection: z.object({\n token: z.string().optional(),\n apiEndpoint: z.string().default(\"https://spora.dev/api/v1\"),\n lastSync: z.string().optional(),\n configVersion: z.number().default(0),\n }).optional(),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\nexport function loadConfig(): Config {\n if (!existsSync(paths.config)) {\n throw new Error(\"Spora not initialized. Run `spora init` first.\");\n }\n const raw = readFileSync(paths.config, \"utf-8\");\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n\n // Backwards compatibility: old configs may still have browser mode.\n if (parsed.xMethod !== \"api\") {\n parsed.xMethod = \"api\";\n if (parsed.xApiTier !== \"basic\" && parsed.xApiTier !== \"free\") {\n parsed.xApiTier = \"basic\";\n }\n const migrated = ConfigSchema.parse(parsed);\n saveConfig(migrated);\n return migrated;\n }\n\n return ConfigSchema.parse(parsed);\n}\n\nexport function saveConfig(config: Config): void {\n ensureDirectories();\n ConfigSchema.parse(config);\n writeFileSync(paths.config, JSON.stringify(config, null, 2));\n}\n\nexport function createDefaultConfig(overrides: {\n xMethod?: \"api\";\n xApiTier?: \"free\" | \"basic\";\n timezone?: string;\n}): Config {\n const monthlyLimit = overrides.xApiTier === \"basic\" ? 10000 : 500;\n const now = new Date();\n const resetDate = new Date(now.getFullYear(), now.getMonth() + 1, 1).toISOString();\n\n return {\n version: 1,\n xMethod: \"api\",\n xApiTier: overrides.xApiTier,\n credits: {\n monthlyPostLimit: monthlyLimit,\n postsUsedThisMonth: 0,\n resetDate,\n },\n schedule: {\n postsPerDay: Math.floor(monthlyLimit / 30),\n activeHoursStart: 8,\n activeHoursEnd: 22,\n timezone: overrides.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n },\n };\n}\n"],"mappings":"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","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/utils/logger.ts
|
|
7
7
|
import { appendFileSync } from "fs";
|
|
@@ -15,22 +15,11 @@ var minLevel = "info";
|
|
|
15
15
|
function setLogLevel(level) {
|
|
16
16
|
minLevel = level;
|
|
17
17
|
}
|
|
18
|
-
function serializeData(data) {
|
|
19
|
-
if (data instanceof Error) {
|
|
20
|
-
return data.message;
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
const json = JSON.stringify(data);
|
|
24
|
-
return json === "{}" && data && typeof data === "object" ? String(data) : json;
|
|
25
|
-
} catch {
|
|
26
|
-
return String(data);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
18
|
function formatMessage(level, message, data) {
|
|
30
19
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
31
20
|
const base = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
|
|
32
21
|
if (data !== void 0) {
|
|
33
|
-
return `${base} ${
|
|
22
|
+
return `${base} ${JSON.stringify(data)}`;
|
|
34
23
|
}
|
|
35
24
|
return base;
|
|
36
25
|
}
|
|
@@ -55,4 +44,4 @@ export {
|
|
|
55
44
|
setLogLevel,
|
|
56
45
|
logger
|
|
57
46
|
};
|
|
58
|
-
//# sourceMappingURL=chunk-
|
|
47
|
+
//# sourceMappingURL=chunk-NPV3OV2K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/logger.ts"],"sourcesContent":["import { appendFileSync } from \"node:fs\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet minLevel: LogLevel = \"info\";\n\nexport function setLogLevel(level: LogLevel): void {\n minLevel = level;\n}\n\nfunction formatMessage(level: LogLevel, message: string, data?: unknown): string {\n const timestamp = new Date().toISOString();\n const base = `[${timestamp}] [${level.toUpperCase()}] ${message}`;\n if (data !== undefined) {\n return `${base} ${JSON.stringify(data)}`;\n }\n return base;\n}\n\nfunction log(level: LogLevel, message: string, data?: unknown): void {\n if (LOG_LEVELS[level] < LOG_LEVELS[minLevel]) return;\n\n const formatted = formatMessage(level, message, data);\n\n // Always write to stderr (safe for MCP stdio servers)\n process.stderr.write(formatted + \"\\n\");\n\n // Also append to log file\n try {\n ensureDirectories();\n appendFileSync(paths.logFile, formatted + \"\\n\");\n } catch {\n // Silently ignore file write errors\n }\n}\n\nexport const logger = {\n debug: (message: string, data?: unknown) => log(\"debug\", message, data),\n info: (message: string, data?: unknown) => log(\"info\", message, data),\n warn: (message: string, data?: unknown) => log(\"warn\", message, data),\n error: (message: string, data?: unknown) => log(\"error\", message, data),\n};\n"],"mappings":";;;;;;AAAA,SAAS,sBAAsB;AAK/B,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,IAAI,WAAqB;AAElB,SAAS,YAAY,OAAuB;AACjD,aAAW;AACb;AAEA,SAAS,cAAc,OAAiB,SAAiB,MAAwB;AAC/E,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,QAAM,OAAO,IAAI,SAAS,MAAM,MAAM,YAAY,CAAC,KAAK,OAAO;AAC/D,MAAI,SAAS,QAAW;AACtB,WAAO,GAAG,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,IAAI,OAAiB,SAAiB,MAAsB;AACnE,MAAI,WAAW,KAAK,IAAI,WAAW,QAAQ,EAAG;AAE9C,QAAM,YAAY,cAAc,OAAO,SAAS,IAAI;AAGpD,UAAQ,OAAO,MAAM,YAAY,IAAI;AAGrC,MAAI;AACF,sBAAkB;AAClB,mBAAe,MAAM,SAAS,YAAY,IAAI;AAAA,EAChD,QAAQ;AAAA,EAER;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,OAAO,CAAC,SAAiB,SAAmB,IAAI,SAAS,SAAS,IAAI;AAAA,EACtE,MAAM,CAAC,SAAiB,SAAmB,IAAI,QAAQ,SAAS,IAAI;AAAA,EACpE,MAAM,CAAC,SAAiB,SAAmB,IAAI,QAAQ,SAAS,IAAI;AAAA,EACpE,OAAO,CAAC,SAAiB,SAAmB,IAAI,SAAS,SAAS,IAAI;AACxE;","names":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
loadConfig
|
|
3
|
-
} from "./chunk-B6RPMDML.js";
|
|
4
1
|
import {
|
|
5
2
|
logger
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NPV3OV2K.js";
|
|
4
|
+
import {
|
|
5
|
+
loadConfig
|
|
6
|
+
} from "./chunk-NO3NQN67.js";
|
|
7
7
|
import {
|
|
8
8
|
ensureDirectories,
|
|
9
9
|
paths
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3RYCUGXE.js";
|
|
11
11
|
|
|
12
12
|
// src/scheduler/queue.ts
|
|
13
13
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
@@ -67,7 +67,7 @@ async function flushQueue() {
|
|
|
67
67
|
const now = /* @__PURE__ */ new Date();
|
|
68
68
|
let posted = 0;
|
|
69
69
|
let failed = 0;
|
|
70
|
-
const { getXClient } = await import("./x-client-
|
|
70
|
+
const { getXClient } = await import("./x-client-GY6XSPK6.js");
|
|
71
71
|
const client = await getXClient();
|
|
72
72
|
for (const entry of queue.entries) {
|
|
73
73
|
if (entry.status !== "pending") continue;
|
|
@@ -121,4 +121,4 @@ export {
|
|
|
121
121
|
flushQueue,
|
|
122
122
|
showQueue
|
|
123
123
|
};
|
|
124
|
-
//# sourceMappingURL=chunk-
|
|
124
|
+
//# sourceMappingURL=chunk-OACD3HGE.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
paths
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3RYCUGXE.js";
|
|
4
4
|
|
|
5
5
|
// src/memory/strategy.ts
|
|
6
6
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -76,4 +76,4 @@ export {
|
|
|
76
76
|
saveStrategy,
|
|
77
77
|
renderStrategyForPrompt
|
|
78
78
|
};
|
|
79
|
-
//# sourceMappingURL=chunk-
|
|
79
|
+
//# sourceMappingURL=chunk-P6KZIJYL.js.map
|
|
@@ -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/colony/memory.ts
|
|
7
7
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
@@ -153,4 +153,4 @@ export {
|
|
|
153
153
|
getTodayEntries,
|
|
154
154
|
renderColonyBriefing
|
|
155
155
|
};
|
|
156
|
-
//# sourceMappingURL=chunk-
|
|
156
|
+
//# sourceMappingURL=chunk-T7L2L7ZL.js.map
|
|
@@ -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/utils/crypto.ts
|
|
7
7
|
import { createCipheriv, createDecipheriv, randomBytes, createHash } from "crypto";
|
|
@@ -53,4 +53,4 @@ export {
|
|
|
53
53
|
saveCredentials,
|
|
54
54
|
loadCredentials
|
|
55
55
|
};
|
|
56
|
-
//# sourceMappingURL=chunk-
|
|
56
|
+
//# sourceMappingURL=chunk-VZBHRUZS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/crypto.ts"],"sourcesContent":["import { createCipheriv, createDecipheriv, randomBytes, createHash } from \"node:crypto\";\nimport { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nconst ALGORITHM = \"aes-256-gcm\";\n\nfunction deriveKey(): Buffer {\n const machineId = `spora-${hostname()}-${process.env.USER ?? \"default\"}`;\n return createHash(\"sha256\").update(machineId).digest();\n}\n\nexport function encrypt(data: string): string {\n const key = deriveKey();\n const iv = randomBytes(16);\n const cipher = createCipheriv(ALGORITHM, key, iv);\n\n let encrypted = cipher.update(data, \"utf-8\", \"hex\");\n encrypted += cipher.final(\"hex\");\n const authTag = cipher.getAuthTag().toString(\"hex\");\n\n return JSON.stringify({\n iv: iv.toString(\"hex\"),\n encrypted,\n authTag,\n });\n}\n\nexport function decrypt(payload: string): string {\n const key = deriveKey();\n const { iv, encrypted, authTag } = JSON.parse(payload);\n\n const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(iv, \"hex\"));\n decipher.setAuthTag(Buffer.from(authTag, \"hex\"));\n\n let decrypted = decipher.update(encrypted, \"hex\", \"utf-8\");\n decrypted += decipher.final(\"utf-8\");\n\n return decrypted;\n}\n\nexport interface XCredentials {\n method: \"api\";\n apiKey?: string;\n apiSecret?: string;\n accessToken?: string;\n accessTokenSecret?: string;\n bearerToken?: string;\n}\n\nexport function saveCredentials(credentials: XCredentials): void {\n ensureDirectories();\n const encrypted = encrypt(JSON.stringify(credentials));\n writeFileSync(paths.credentials, encrypted);\n}\n\nexport function loadCredentials(): XCredentials {\n if (!existsSync(paths.credentials)) {\n throw new Error(\"No credentials found. Run `spora init` first.\");\n }\n const payload = readFileSync(paths.credentials, \"utf-8\");\n return JSON.parse(decrypt(payload)) as XCredentials;\n}\n"],"mappings":";;;;;;AAAA,SAAS,gBAAgB,kBAAkB,aAAa,kBAAkB;AAC1E,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,gBAAgB;AAGzB,IAAM,YAAY;AAElB,SAAS,YAAoB;AAC3B,QAAM,YAAY,SAAS,SAAS,CAAC,IAAI,QAAQ,IAAI,QAAQ,SAAS;AACtE,SAAO,WAAW,QAAQ,EAAE,OAAO,SAAS,EAAE,OAAO;AACvD;AAEO,SAAS,QAAQ,MAAsB;AAC5C,QAAM,MAAM,UAAU;AACtB,QAAM,KAAK,YAAY,EAAE;AACzB,QAAM,SAAS,eAAe,WAAW,KAAK,EAAE;AAEhD,MAAI,YAAY,OAAO,OAAO,MAAM,SAAS,KAAK;AAClD,eAAa,OAAO,MAAM,KAAK;AAC/B,QAAM,UAAU,OAAO,WAAW,EAAE,SAAS,KAAK;AAElD,SAAO,KAAK,UAAU;AAAA,IACpB,IAAI,GAAG,SAAS,KAAK;AAAA,IACrB;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEO,SAAS,QAAQ,SAAyB;AAC/C,QAAM,MAAM,UAAU;AACtB,QAAM,EAAE,IAAI,WAAW,QAAQ,IAAI,KAAK,MAAM,OAAO;AAErD,QAAM,WAAW,iBAAiB,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC;AACxE,WAAS,WAAW,OAAO,KAAK,SAAS,KAAK,CAAC;AAE/C,MAAI,YAAY,SAAS,OAAO,WAAW,OAAO,OAAO;AACzD,eAAa,SAAS,MAAM,OAAO;AAEnC,SAAO;AACT;AAWO,SAAS,gBAAgB,aAAiC;AAC/D,oBAAkB;AAClB,QAAM,YAAY,QAAQ,KAAK,UAAU,WAAW,CAAC;AACrD,gBAAc,MAAM,aAAa,SAAS;AAC5C;AAEO,SAAS,kBAAgC;AAC9C,MAAI,CAAC,WAAW,MAAM,WAAW,GAAG;AAClC,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,QAAM,UAAU,aAAa,MAAM,aAAa,OAAO;AACvD,SAAO,KAAK,MAAM,QAAQ,OAAO,CAAC;AACpC;","names":[]}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getXClient
|
|
3
|
+
} from "./chunk-E5NR6HT4.js";
|
|
4
|
+
import {
|
|
5
|
+
addToQueue
|
|
6
|
+
} from "./chunk-OACD3HGE.js";
|
|
7
|
+
import {
|
|
8
|
+
buildSystemPrompt,
|
|
9
|
+
buildToolDecisionMessage
|
|
10
|
+
} from "./chunk-AOQ3WLZV.js";
|
|
11
|
+
import {
|
|
12
|
+
loadIdentity,
|
|
13
|
+
saveIdentity
|
|
14
|
+
} from "./chunk-M6YOQVSI.js";
|
|
15
|
+
import {
|
|
16
|
+
generateResponse
|
|
17
|
+
} from "./chunk-KWWAIS3C.js";
|
|
18
|
+
import {
|
|
19
|
+
logger
|
|
20
|
+
} from "./chunk-NPV3OV2K.js";
|
|
21
|
+
import {
|
|
22
|
+
addLearning,
|
|
23
|
+
getRecentInteractions
|
|
24
|
+
} from "./chunk-JBYZ7K56.js";
|
|
25
|
+
|
|
26
|
+
// src/runtime/decision-engine.ts
|
|
27
|
+
function parseActions(llmResponse) {
|
|
28
|
+
const jsonMatch = llmResponse.match(/\[[\s\S]*?\]/);
|
|
29
|
+
if (!jsonMatch) {
|
|
30
|
+
const objMatch = llmResponse.match(/\{[\s\S]*?\}/);
|
|
31
|
+
if (objMatch) {
|
|
32
|
+
try {
|
|
33
|
+
return [JSON.parse(objMatch[0])];
|
|
34
|
+
} catch {
|
|
35
|
+
logger.warn("Could not parse LLM response as action object");
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
logger.warn("No JSON found in LLM response");
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const actions = JSON.parse(jsonMatch[0]);
|
|
44
|
+
return Array.isArray(actions) ? actions : [actions];
|
|
45
|
+
} catch {
|
|
46
|
+
logger.warn("Failed to parse actions JSON from LLM response");
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function executeAction(action) {
|
|
51
|
+
const { action: type } = action;
|
|
52
|
+
try {
|
|
53
|
+
switch (type) {
|
|
54
|
+
case "post": {
|
|
55
|
+
if (!action.content) return { action: type, success: false, error: "No content provided" };
|
|
56
|
+
if (action.content.length > 280) {
|
|
57
|
+
return { action: type, success: false, error: `Tweet too long: ${action.content.length} chars (max 280)` };
|
|
58
|
+
}
|
|
59
|
+
const client = await getXClient();
|
|
60
|
+
const result = await client.postTweet(action.content);
|
|
61
|
+
if (result.success) logger.info(`Posted: "${action.content.slice(0, 50)}..."`);
|
|
62
|
+
return { action: type, success: result.success, detail: result.tweetId, error: result.error };
|
|
63
|
+
}
|
|
64
|
+
case "reply": {
|
|
65
|
+
if (!action.tweetId || !action.content) {
|
|
66
|
+
return { action: type, success: false, error: "Missing tweetId or content" };
|
|
67
|
+
}
|
|
68
|
+
const client = await getXClient();
|
|
69
|
+
const result = await client.replyToTweet(action.tweetId, action.content);
|
|
70
|
+
if (result.success) logger.info(`Replied to ${action.tweetId}: "${action.content.slice(0, 50)}..."`);
|
|
71
|
+
return { action: type, success: result.success, detail: result.tweetId, error: result.error };
|
|
72
|
+
}
|
|
73
|
+
case "like": {
|
|
74
|
+
if (!action.tweetId) return { action: type, success: false, error: "Missing tweetId" };
|
|
75
|
+
const client = await getXClient();
|
|
76
|
+
const result = await client.likeTweet(action.tweetId);
|
|
77
|
+
return { action: type, success: result.success, error: result.error };
|
|
78
|
+
}
|
|
79
|
+
case "retweet": {
|
|
80
|
+
if (!action.tweetId) return { action: type, success: false, error: "Missing tweetId" };
|
|
81
|
+
const client = await getXClient();
|
|
82
|
+
const result = await client.retweet(action.tweetId);
|
|
83
|
+
return { action: type, success: result.success, error: result.error };
|
|
84
|
+
}
|
|
85
|
+
case "follow": {
|
|
86
|
+
if (!action.handle) return { action: type, success: false, error: "Missing handle" };
|
|
87
|
+
const client = await getXClient();
|
|
88
|
+
const result = await client.followUser(action.handle);
|
|
89
|
+
return { action: type, success: result.success, error: result.error };
|
|
90
|
+
}
|
|
91
|
+
case "schedule": {
|
|
92
|
+
if (!action.content) return { action: type, success: false, error: "No content" };
|
|
93
|
+
const entry = addToQueue(action.content);
|
|
94
|
+
logger.info(`Scheduled: "${action.content.slice(0, 50)}..." for ${entry.scheduledFor}`);
|
|
95
|
+
return { action: type, success: true, detail: `Scheduled for ${entry.scheduledFor}` };
|
|
96
|
+
}
|
|
97
|
+
case "learn": {
|
|
98
|
+
if (!action.content) return { action: type, success: false, error: "No content" };
|
|
99
|
+
addLearning(action.content, "agent", action.tags ?? ["heartbeat"]);
|
|
100
|
+
logger.info(`Learned: "${action.content.slice(0, 50)}..."`);
|
|
101
|
+
return { action: type, success: true };
|
|
102
|
+
}
|
|
103
|
+
case "reflect": {
|
|
104
|
+
if (!action.content) return { action: type, success: false, error: "No content" };
|
|
105
|
+
const identity = loadIdentity();
|
|
106
|
+
identity.evolutionJournal.push({
|
|
107
|
+
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
108
|
+
reflection: action.content
|
|
109
|
+
});
|
|
110
|
+
saveIdentity(identity);
|
|
111
|
+
logger.info(`Reflected: "${action.content.slice(0, 50)}..."`);
|
|
112
|
+
return { action: type, success: true };
|
|
113
|
+
}
|
|
114
|
+
case "skip": {
|
|
115
|
+
logger.info(`Skipping: ${action.reason ?? action.reasoning ?? "no reason given"}`);
|
|
116
|
+
return { action: type, success: true, detail: action.reason ?? action.reasoning };
|
|
117
|
+
}
|
|
118
|
+
default:
|
|
119
|
+
logger.warn(`Unknown action: ${type}`);
|
|
120
|
+
return { action: type, success: false, error: `Unknown action: ${type}` };
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const msg = error.message;
|
|
124
|
+
logger.error(`Action ${type} failed: ${msg}`);
|
|
125
|
+
return { action: type, success: false, error: msg };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/runtime/policy.ts
|
|
130
|
+
function normalize(text) {
|
|
131
|
+
return text.toLowerCase().replace(/https?:\/\/\S+/g, "").replace(/[@#]\w+/g, "").replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
132
|
+
}
|
|
133
|
+
function tokenSet(text) {
|
|
134
|
+
const tokens = normalize(text).split(" ").filter(Boolean);
|
|
135
|
+
return new Set(tokens);
|
|
136
|
+
}
|
|
137
|
+
function jaccardSimilarity(a, b) {
|
|
138
|
+
const aSet = tokenSet(a);
|
|
139
|
+
const bSet = tokenSet(b);
|
|
140
|
+
if (aSet.size === 0 || bSet.size === 0) return 0;
|
|
141
|
+
let overlap = 0;
|
|
142
|
+
for (const token of aSet) {
|
|
143
|
+
if (bSet.has(token)) overlap += 1;
|
|
144
|
+
}
|
|
145
|
+
const union = aSet.size + bSet.size - overlap;
|
|
146
|
+
return union === 0 ? 0 : overlap / union;
|
|
147
|
+
}
|
|
148
|
+
function firstWords(text, n) {
|
|
149
|
+
return normalize(text).split(" ").filter(Boolean).slice(0, n).join(" ");
|
|
150
|
+
}
|
|
151
|
+
function hasAllCapsEnding(text) {
|
|
152
|
+
const ending = text.split(/[.!?]/).map((s) => s.trim()).filter(Boolean).slice(-1)[0] ?? "";
|
|
153
|
+
const words = ending.split(/\s+/).filter(Boolean);
|
|
154
|
+
if (words.length < 3) return false;
|
|
155
|
+
return words.every((word) => /^[A-Z0-9]+$/.test(word));
|
|
156
|
+
}
|
|
157
|
+
function recentWrittenContent() {
|
|
158
|
+
const recent = getRecentInteractions(40);
|
|
159
|
+
return recent.filter((i) => i.type === "post" || i.type === "reply").map((i) => i.content ?? "").filter((content) => content.length > 0);
|
|
160
|
+
}
|
|
161
|
+
function hasStrongConversationOpportunity(timeline, mentions) {
|
|
162
|
+
if (mentions.length > 0) return true;
|
|
163
|
+
return timeline.some((tweet) => (tweet.replyCount ?? 0) > 0 || tweet.text.includes("?"));
|
|
164
|
+
}
|
|
165
|
+
function wasInteractionAction(action) {
|
|
166
|
+
return ["reply", "like", "retweet", "follow"].includes(action.action);
|
|
167
|
+
}
|
|
168
|
+
function isDuplicateTarget(action, executedActions) {
|
|
169
|
+
if (!action.tweetId) return false;
|
|
170
|
+
return executedActions.some((a) => a.tweetId === action.tweetId && a.action === action.action);
|
|
171
|
+
}
|
|
172
|
+
function repeatedTemplate(content, recent) {
|
|
173
|
+
const prefix = firstWords(content, 7);
|
|
174
|
+
if (!prefix) return false;
|
|
175
|
+
return recent.some((r) => {
|
|
176
|
+
const sameStart = firstWords(r, 7) === prefix;
|
|
177
|
+
const similar = jaccardSimilarity(content, r) >= 0.62;
|
|
178
|
+
return sameStart || similar;
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function overusingAllCapsCadence(content, recentEntries) {
|
|
182
|
+
if (!hasAllCapsEnding(content)) return false;
|
|
183
|
+
const recentCaps = recentEntries.filter((i) => i.type === "post" && i.content).slice(0, 8).filter((i) => hasAllCapsEnding(i.content ?? ""));
|
|
184
|
+
return recentCaps.length >= 2;
|
|
185
|
+
}
|
|
186
|
+
function evaluateActionPolicy(context) {
|
|
187
|
+
const { action, step, timeline, mentions, executedActions } = context;
|
|
188
|
+
if (isDuplicateTarget(action, executedActions)) {
|
|
189
|
+
return { allowed: false, reason: `Action ${action.action} already executed for tweet ${action.tweetId} this heartbeat.` };
|
|
190
|
+
}
|
|
191
|
+
const hasConversationOpportunity = hasStrongConversationOpportunity(timeline, mentions);
|
|
192
|
+
const interactedAlready = executedActions.some(wasInteractionAction);
|
|
193
|
+
if (action.action === "post" && hasConversationOpportunity && !interactedAlready && step < 2) {
|
|
194
|
+
return {
|
|
195
|
+
allowed: false,
|
|
196
|
+
reason: "Engage first: reply/like/follow when mentions or active conversations are available before posting an original tweet."
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if ((action.action === "post" || action.action === "schedule") && action.content) {
|
|
200
|
+
const recent = recentWrittenContent();
|
|
201
|
+
if (repeatedTemplate(action.content, recent)) {
|
|
202
|
+
return {
|
|
203
|
+
allowed: false,
|
|
204
|
+
reason: "Rejected repetitive content pattern. Use a more novel structure or engage directly with timeline context."
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const recentInteractions = getRecentInteractions(20);
|
|
208
|
+
if (overusingAllCapsCadence(action.content, recentInteractions)) {
|
|
209
|
+
return {
|
|
210
|
+
allowed: false,
|
|
211
|
+
reason: "Rejected repetitive all-caps slogan cadence. Vary style and reduce monologue formatting."
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if ((action.action === "reply" || action.action === "like" || action.action === "retweet") && action.tweetId) {
|
|
216
|
+
const known = new Set([...timeline, ...mentions].map((tweet) => tweet.id));
|
|
217
|
+
if (!known.has(action.tweetId)) {
|
|
218
|
+
return {
|
|
219
|
+
allowed: false,
|
|
220
|
+
reason: `Tweet ${action.tweetId} is not in current observations. Choose a visible timeline/mention tweet for grounded engagement.`
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return { allowed: true };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/runtime/autonomy.ts
|
|
228
|
+
async function runAutonomyCycle(maxActions) {
|
|
229
|
+
const client = await getXClient();
|
|
230
|
+
let timeline = [];
|
|
231
|
+
let mentions = [];
|
|
232
|
+
try {
|
|
233
|
+
timeline = await client.getTimeline({ count: 20 });
|
|
234
|
+
} catch (error) {
|
|
235
|
+
logger.warn(`Timeline read failed: ${error.message}`);
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
mentions = await client.getMentions({ count: 10 });
|
|
239
|
+
} catch (error) {
|
|
240
|
+
logger.warn(`Mentions read failed: ${error.message}`);
|
|
241
|
+
}
|
|
242
|
+
const systemPrompt = buildSystemPrompt();
|
|
243
|
+
const actions = [];
|
|
244
|
+
const results = [];
|
|
245
|
+
const policyFeedback = [];
|
|
246
|
+
getRecentInteractions(20);
|
|
247
|
+
for (let step = 0; step < maxActions; step += 1) {
|
|
248
|
+
const decisionPrompt = buildToolDecisionMessage({
|
|
249
|
+
step,
|
|
250
|
+
maxActions,
|
|
251
|
+
timeline,
|
|
252
|
+
mentions,
|
|
253
|
+
executedActions: actions,
|
|
254
|
+
policyFeedback
|
|
255
|
+
});
|
|
256
|
+
const llmResponse = await generateResponse(systemPrompt, decisionPrompt);
|
|
257
|
+
const parsed = parseActions(llmResponse.content);
|
|
258
|
+
const proposedAction = parsed[0];
|
|
259
|
+
if (!proposedAction) {
|
|
260
|
+
logger.info("Planner returned no actionable tool call.");
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
const policy = evaluateActionPolicy({
|
|
264
|
+
action: proposedAction,
|
|
265
|
+
step,
|
|
266
|
+
timeline,
|
|
267
|
+
mentions,
|
|
268
|
+
executedActions: actions
|
|
269
|
+
});
|
|
270
|
+
if (!policy.allowed) {
|
|
271
|
+
const reason = policy.reason ?? "Policy rejected action";
|
|
272
|
+
policyFeedback.push(reason);
|
|
273
|
+
logger.info(`Policy rejected action ${proposedAction.action}: ${reason}`);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const result = await executeAction(proposedAction);
|
|
277
|
+
actions.push(proposedAction);
|
|
278
|
+
results.push(result);
|
|
279
|
+
if (proposedAction.action === "skip") {
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
timeline,
|
|
285
|
+
mentions,
|
|
286
|
+
actions,
|
|
287
|
+
results,
|
|
288
|
+
policyFeedback
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export {
|
|
293
|
+
runAutonomyCycle
|
|
294
|
+
};
|
|
295
|
+
//# sourceMappingURL=chunk-WIK74GGJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/decision-engine.ts","../src/runtime/policy.ts","../src/runtime/autonomy.ts"],"sourcesContent":["import { logger } from \"../utils/logger.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { addLearning } from \"../memory/index.js\";\nimport { loadIdentity, saveIdentity } from \"../identity/index.js\";\nimport { addToQueue } from \"../scheduler/queue.js\";\n\nexport interface AgentAction {\n action: string;\n content?: string;\n tweetId?: string;\n handle?: string;\n tags?: string[];\n reason?: string;\n reasoning?: string;\n}\n\nexport interface ActionResult {\n action: string;\n success: boolean;\n detail?: string;\n error?: string;\n}\n\nexport function parseActions(llmResponse: string): AgentAction[] {\n // Extract JSON array from the response (may be wrapped in markdown code blocks)\n const jsonMatch = llmResponse.match(/\\[[\\s\\S]*?\\]/);\n if (!jsonMatch) {\n // Try to parse as a single action object\n const objMatch = llmResponse.match(/\\{[\\s\\S]*?\\}/);\n if (objMatch) {\n try {\n return [JSON.parse(objMatch[0]) as AgentAction];\n } catch {\n logger.warn(\"Could not parse LLM response as action object\");\n return [];\n }\n }\n logger.warn(\"No JSON found in LLM response\");\n return [];\n }\n\n try {\n const actions = JSON.parse(jsonMatch[0]) as AgentAction[];\n return Array.isArray(actions) ? actions : [actions];\n } catch {\n logger.warn(\"Failed to parse actions JSON from LLM response\");\n return [];\n }\n}\n\nexport async function executeAction(action: AgentAction): Promise<ActionResult> {\n const { action: type } = action;\n\n try {\n switch (type) {\n case \"post\": {\n if (!action.content) return { action: type, success: false, error: \"No content provided\" };\n if (action.content.length > 280) {\n return { action: type, success: false, error: `Tweet too long: ${action.content.length} chars (max 280)` };\n }\n\n const client = await getXClient();\n const result = await client.postTweet(action.content);\n if (result.success) logger.info(`Posted: \"${action.content.slice(0, 50)}...\"`);\n return { action: type, success: result.success, detail: result.tweetId, error: result.error };\n }\n\n case \"reply\": {\n if (!action.tweetId || !action.content) {\n return { action: type, success: false, error: \"Missing tweetId or content\" };\n }\n const client = await getXClient();\n const result = await client.replyToTweet(action.tweetId, action.content);\n if (result.success) logger.info(`Replied to ${action.tweetId}: \"${action.content.slice(0, 50)}...\"`);\n return { action: type, success: result.success, detail: result.tweetId, error: result.error };\n }\n\n case \"like\": {\n if (!action.tweetId) return { action: type, success: false, error: \"Missing tweetId\" };\n const client = await getXClient();\n const result = await client.likeTweet(action.tweetId);\n return { action: type, success: result.success, error: result.error };\n }\n\n case \"retweet\": {\n if (!action.tweetId) return { action: type, success: false, error: \"Missing tweetId\" };\n const client = await getXClient();\n const result = await client.retweet(action.tweetId);\n return { action: type, success: result.success, error: result.error };\n }\n\n case \"follow\": {\n if (!action.handle) return { action: type, success: false, error: \"Missing handle\" };\n const client = await getXClient();\n const result = await client.followUser(action.handle);\n return { action: type, success: result.success, error: result.error };\n }\n\n case \"schedule\": {\n if (!action.content) return { action: type, success: false, error: \"No content\" };\n const entry = addToQueue(action.content);\n logger.info(`Scheduled: \"${action.content.slice(0, 50)}...\" for ${entry.scheduledFor}`);\n return { action: type, success: true, detail: `Scheduled for ${entry.scheduledFor}` };\n }\n\n case \"learn\": {\n if (!action.content) return { action: type, success: false, error: \"No content\" };\n addLearning(action.content, \"agent\", action.tags ?? [\"heartbeat\"]);\n logger.info(`Learned: \"${action.content.slice(0, 50)}...\"`);\n return { action: type, success: true };\n }\n\n case \"reflect\": {\n if (!action.content) return { action: type, success: false, error: \"No content\" };\n const identity = loadIdentity();\n identity.evolutionJournal.push({\n date: new Date().toISOString(),\n reflection: action.content,\n });\n saveIdentity(identity);\n logger.info(`Reflected: \"${action.content.slice(0, 50)}...\"`);\n return { action: type, success: true };\n }\n\n case \"skip\": {\n logger.info(`Skipping: ${action.reason ?? action.reasoning ?? \"no reason given\"}`);\n return { action: type, success: true, detail: action.reason ?? action.reasoning };\n }\n\n default:\n logger.warn(`Unknown action: ${type}`);\n return { action: type, success: false, error: `Unknown action: ${type}` };\n }\n } catch (error) {\n const msg = (error as Error).message;\n logger.error(`Action ${type} failed: ${msg}`);\n return { action: type, success: false, error: msg };\n }\n}\n\nexport async function executeActions(actions: AgentAction[]): Promise<ActionResult[]> {\n const results: ActionResult[] = [];\n for (const action of actions) {\n const result = await executeAction(action);\n results.push(result);\n // Small delay between actions to be human-like\n await new Promise((r) => setTimeout(r, 2000 + Math.random() * 3000));\n }\n return results;\n}\n","import { getRecentInteractions, type InteractionEntry } from \"../memory/index.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport type { AgentAction } from \"./decision-engine.js\";\n\nexport interface PolicyContext {\n action: AgentAction;\n step: number;\n timeline: Tweet[];\n mentions: Tweet[];\n executedActions: AgentAction[];\n}\n\nexport interface PolicyDecision {\n allowed: boolean;\n reason?: string;\n}\n\nfunction normalize(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 tokenSet(text: string): Set<string> {\n const tokens = normalize(text).split(\" \").filter(Boolean);\n return new Set(tokens);\n}\n\nfunction jaccardSimilarity(a: string, b: string): number {\n const aSet = tokenSet(a);\n const bSet = tokenSet(b);\n if (aSet.size === 0 || bSet.size === 0) return 0;\n\n let overlap = 0;\n for (const token of aSet) {\n if (bSet.has(token)) overlap += 1;\n }\n\n const union = aSet.size + bSet.size - overlap;\n return union === 0 ? 0 : overlap / union;\n}\n\nfunction firstWords(text: string, n: number): string {\n return normalize(text).split(\" \").filter(Boolean).slice(0, n).join(\" \");\n}\n\nfunction hasAllCapsEnding(text: string): boolean {\n const ending = text.split(/[.!?]/).map((s) => s.trim()).filter(Boolean).slice(-1)[0] ?? \"\";\n const words = ending.split(/\\s+/).filter(Boolean);\n if (words.length < 3) return false;\n return words.every((word) => /^[A-Z0-9]+$/.test(word));\n}\n\nfunction recentWrittenContent(): string[] {\n const recent = getRecentInteractions(40);\n return recent\n .filter((i) => i.type === \"post\" || i.type === \"reply\")\n .map((i) => i.content ?? \"\")\n .filter((content) => content.length > 0);\n}\n\nfunction hasStrongConversationOpportunity(timeline: Tweet[], mentions: Tweet[]): boolean {\n if (mentions.length > 0) return true;\n return timeline.some((tweet) => (tweet.replyCount ?? 0) > 0 || tweet.text.includes(\"?\"));\n}\n\nfunction wasInteractionAction(action: AgentAction): boolean {\n return [\"reply\", \"like\", \"retweet\", \"follow\"].includes(action.action);\n}\n\nfunction isDuplicateTarget(action: AgentAction, executedActions: AgentAction[]): boolean {\n if (!action.tweetId) return false;\n return executedActions.some((a) => a.tweetId === action.tweetId && a.action === action.action);\n}\n\nfunction repeatedTemplate(content: string, recent: string[]): boolean {\n const prefix = firstWords(content, 7);\n if (!prefix) return false;\n\n return recent.some((r) => {\n const sameStart = firstWords(r, 7) === prefix;\n const similar = jaccardSimilarity(content, r) >= 0.62;\n return sameStart || similar;\n });\n}\n\nfunction overusingAllCapsCadence(content: string, recentEntries: InteractionEntry[]): boolean {\n if (!hasAllCapsEnding(content)) return false;\n const recentCaps = recentEntries\n .filter((i) => i.type === \"post\" && i.content)\n .slice(0, 8)\n .filter((i) => hasAllCapsEnding(i.content ?? \"\"));\n\n return recentCaps.length >= 2;\n}\n\nexport function evaluateActionPolicy(context: PolicyContext): PolicyDecision {\n const { action, step, timeline, mentions, executedActions } = context;\n\n if (isDuplicateTarget(action, executedActions)) {\n return { allowed: false, reason: `Action ${action.action} already executed for tweet ${action.tweetId} this heartbeat.` };\n }\n\n const hasConversationOpportunity = hasStrongConversationOpportunity(timeline, mentions);\n const interactedAlready = executedActions.some(wasInteractionAction);\n\n if (\n action.action === \"post\" &&\n hasConversationOpportunity &&\n !interactedAlready &&\n step < 2\n ) {\n return {\n allowed: false,\n reason: \"Engage first: reply/like/follow when mentions or active conversations are available before posting an original tweet.\",\n };\n }\n\n if ((action.action === \"post\" || action.action === \"schedule\") && action.content) {\n const recent = recentWrittenContent();\n if (repeatedTemplate(action.content, recent)) {\n return {\n allowed: false,\n reason: \"Rejected repetitive content pattern. Use a more novel structure or engage directly with timeline context.\",\n };\n }\n\n const recentInteractions = getRecentInteractions(20);\n if (overusingAllCapsCadence(action.content, recentInteractions)) {\n return {\n allowed: false,\n reason: \"Rejected repetitive all-caps slogan cadence. Vary style and reduce monologue formatting.\",\n };\n }\n }\n\n if ((action.action === \"reply\" || action.action === \"like\" || action.action === \"retweet\") && action.tweetId) {\n const known = new Set([...timeline, ...mentions].map((tweet) => tweet.id));\n if (!known.has(action.tweetId)) {\n return {\n allowed: false,\n reason: `Tweet ${action.tweetId} is not in current observations. Choose a visible timeline/mention tweet for grounded engagement.`,\n };\n }\n }\n\n return { allowed: true };\n}\n","import { getXClient } from \"../x-client/index.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { getRecentInteractions } from \"../memory/index.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport { buildSystemPrompt, buildToolDecisionMessage } from \"./prompt-builder.js\";\nimport { generateResponse } from \"./llm.js\";\nimport { parseActions, executeAction, type AgentAction, type ActionResult } from \"./decision-engine.js\";\nimport { evaluateActionPolicy } from \"./policy.js\";\n\nexport interface AutonomyCycleResult {\n timeline: Tweet[];\n mentions: Tweet[];\n actions: AgentAction[];\n results: ActionResult[];\n policyFeedback: string[];\n}\n\nexport async function runAutonomyCycle(maxActions: number): Promise<AutonomyCycleResult> {\n const client = await getXClient();\n\n let timeline: Tweet[] = [];\n let mentions: Tweet[] = [];\n\n try {\n timeline = await client.getTimeline({ count: 20 });\n } catch (error) {\n logger.warn(`Timeline read failed: ${(error as Error).message}`);\n }\n\n try {\n mentions = await client.getMentions({ count: 10 });\n } catch (error) {\n logger.warn(`Mentions read failed: ${(error as Error).message}`);\n }\n\n const systemPrompt = buildSystemPrompt();\n const actions: AgentAction[] = [];\n const results: ActionResult[] = [];\n const policyFeedback: string[] = [];\n\n // Keep short memory available in context by touching it before planner loop.\n getRecentInteractions(20);\n\n for (let step = 0; step < maxActions; step += 1) {\n const decisionPrompt = buildToolDecisionMessage({\n step,\n maxActions,\n timeline,\n mentions,\n executedActions: actions,\n policyFeedback,\n });\n\n const llmResponse = await generateResponse(systemPrompt, decisionPrompt);\n const parsed = parseActions(llmResponse.content);\n const proposedAction = parsed[0];\n\n if (!proposedAction) {\n logger.info(\"Planner returned no actionable tool call.\");\n break;\n }\n\n const policy = evaluateActionPolicy({\n action: proposedAction,\n step,\n timeline,\n mentions,\n executedActions: actions,\n });\n\n if (!policy.allowed) {\n const reason = policy.reason ?? \"Policy rejected action\";\n policyFeedback.push(reason);\n logger.info(`Policy rejected action ${proposedAction.action}: ${reason}`);\n continue;\n }\n\n const result = await executeAction(proposedAction);\n actions.push(proposedAction);\n results.push(result);\n\n if (proposedAction.action === \"skip\") {\n break;\n }\n }\n\n return {\n timeline,\n mentions,\n actions,\n results,\n policyFeedback,\n };\n}\n"],"mappings":"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","names":[]}
|