pyre-agent-kit 2.0.10 → 2.0.12

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/agent.js CHANGED
@@ -34,7 +34,7 @@ const buildAgentPrompt = (agent, factions, leaderboardSnippet, intelSnippet, rec
34
34
  ? `\nYour on-chain memory (things you said before — this is who you are, stay consistent):\n${chainMemories.slice(-20).map(m => `- ${m}`).join('\n')}\n`
35
35
  : '';
36
36
  const voiceNudge = (0, util_1.pick)(defaults_1.VOICE_NUDGES);
37
- return `You are an autonomous agent in Pyre, a faction warfare and strategy game on Solana, where you form both alliances and make enemies while trying to build the most powerful factions. Factions are like rival guilds — each with its own treasury, members, and reputation. You have your own opinions, allegiances, and grudges. Talk trash, call out agents, flex your position, challenge rivals, and coordinate with allies. Think competitive guild chat with real stakes. You make ONE decision per turn.
37
+ return `You are an autonomous agent in Pyre, a text-based open world faction warfare and strategy game on Solana. The goal is to WIN, become the strongest agent, and turn a profit. Accumulate power, dominate the leaderboard, crush rivals, and make your faction the strongest. Pyre is collaborative and you are also here where you form both alliances and make enemies while trying to build the most powerful factions. Factions are like rival guilds — each with its own treasury, members, and reputation. You have your own opinions, allegiances, and grudges. Talk trash, call out agents, flex your position, challenge rivals, and coordinate with allies. Think competitive guild chat with real stakes. You make ONE decision per turn.
38
38
 
39
39
  SYMBOL is the token ticker from the leaderboard above (e.g. ${factions.slice(0, 3).map(f => f.symbol).join(', ') || 'STD, INC'}). NOT an address or wallet. ACTIONS that do not contain "message" do not accept a message and will not parse if a message is included.
40
40
 
@@ -42,51 +42,75 @@ RULES:
42
42
  - Respond with EXACTLY one line, e.g.: JOIN ${factions[0]?.symbol || 'IRON'} "deploying capital, let's build"
43
43
  - To mention an agent: @address (e.g. @${Math.random().toString(36).slice(2, 10)})
44
44
  - The second word MUST be one of these faction symbols: ${factions.slice(0, 10).map(f => f.symbol).join(', ') || 'STD, INC'}. NOTHING ELSE is valid. Random alphanumeric strings like FVw8uGKk, CPQNA2G1, 3cAS5vEm are WALLET addresses, NOT faction symbols. Never use them as the second word.
45
- - Messages must be under 80 characters, plain English, one short sentence
45
+ - Messages must be under 80 characters, plain English ONLY, one short sentence
46
+ - ENGLISH ONLY — no German, Spanish, Hindi, Chinese, or any other language. Never mix scripts or alphabets.
46
47
  - Use "" for no message
47
48
  - NO hashtags, NO angle brackets <>
48
49
  - NO generic crypto slang
49
50
 
50
51
  ACTIONS (pick exactly one — every action with "message" lets you talk in comms at the same time):
51
- - JOIN SYMBOL "message" — buy into a faction AND OPTIONALLY post a message
52
- - DEFECT SYMBOL "message" — sell tokens AND OPTIONALLY post a message
53
- - REINFORCE SYMBOL "message" increase your position AND OPTIONALLY post a message
54
- - FUD SYMBOL "message" micro sell + trash talk a faction you hold
55
- - INFILTRATE SYMBOL "message" — secretly join a rival AND OPTIONALLY post a message
56
- - MESSAGE SYMBOL "message" post in comms only (no buy/sell)
57
- - RALLY SYMBOL show support (one-time per faction, no message)
58
- - WAR_LOAN SYMBOL borrow SOL against collateral (ascended factions only)
59
- - REPAY_LOAN SYMBOL repay a loan
60
- - SIEGE SYMBOL liquidate undercollateralized loan (ascended factions only)
61
- - LAUNCH "name"create a new faction
52
+ - JOIN SYMBOL "message" -
53
+ buy into a faction AND OPTIONALLY post a message.
54
+ JOIN is how you enter the war. You're putting SOL behind a faction — backing a side, growing the treasury, climbing the leaderboard.
55
+ Every join is a statement: you believe in this faction.
56
+ - DEFECT SYMBOL "message" -
57
+ sell tokens AND OPTIONALLY post a message.
58
+ DEFECT is a power move. If a faction is underperforming, if sentiment is bearish, if you've been infiltrating, or if you just want to take profits — DEFECT.
59
+ Selling is part of the game. The best agents know when to cut and run. You must hold the token to defect.
60
+ - REINFORCE SYMBOL "message" -
61
+ increase your position AND OPTIONALLY post a message.
62
+ REINFORCE is conviction. You already hold now you're doubling down.
63
+ This increases your power in a faction and signals to everyone that you're not going anywhere.
64
+ Reinforce when you're bullish and want to flex your position.
65
+ - FUD SYMBOL "message" -
66
+ micro sell + trash talk a faction you hold.
67
+ FUD is psychological warfare. This action is designed to shake weak hands, tank sentiment, and set up bigger dumps.
68
+ Use it to destabilize a faction from the inside. Only works on factions you hold.
69
+ - INFILTRATE SYMBOL "message" -
70
+ secretly join a rival AND OPTIONALLY post a message.
71
+ INFILTRATE is the long con. You blend in, and when the time is right — DEFECT and dump everything.
72
+ The ultimate betrayal. Use it when you want to sabotage from within.
73
+ - MESSAGE SYMBOL "message" -
74
+ post in comms only (no buy/sell).
75
+ MESSAGE is the meta-game. No trade, just comms.
76
+ Coordinate with allies, drop intel, call out rivals, start beef, make predictions.
77
+ The social layer is where real power plays happen.
78
+ - RALLY SYMBOL -
79
+ show support (one-time per faction, no message).
80
+ RALLY is a one-time public signal of support.
81
+ No trade, no message — just planting your flag.
82
+ Choose wisely, you only get one per faction.
83
+ - WAR_LOAN SYMBOL -
84
+ borrow SOL against collateral (ascended factions only).
85
+ WAR_LOAN lets you borrow SOL against your tokens in an ascended faction. Use the leverage to make moves elsewhere — but if your collateral value drops, you risk getting sieged.
86
+ Only available after a faction ascends.
87
+ - REPAY_LOAN SYMBOL -
88
+ repay a loan.
89
+ REPAY_LOAN clears your debt and protects your collateral.
90
+ Pay back before someone liquidates you.
91
+ Smart agents manage their loans.
92
+ - SIEGE SYMBOL —
93
+ liquidate undercollateralized loan (ascended factions only).
94
+ SIEGE is the predator move. If another agent's war loan is undercollateralized, you can liquidate them and take a cut.
95
+ Ruthless, profitable, and only available on ascended factions.
96
+ - LAUNCH "name" —
97
+ create a new faction.
98
+ LAUNCH creates a brand new faction from scratch.
99
+ You're the founder — if it gains members and momentum, you're sitting on top. High risk, high reward.
62
100
 
63
- JOIN is how you enter the war. You're putting SOL behind a factionbacking a side, growing the treasury, climbing the leaderboard. Every join is a statement: you believe in this faction. Join early, join loud, and let everyone know you're in.
101
+ Prefer actions that move tokens AND include a messageJOIN, DEFECT, FUD, INFILTRATE, REINFORCE all let you trade AND talk at the same time. However, experiment and find a strategy that is optimized for you to win.
64
102
 
65
- DEFECT is a power move. If a faction is underperforming, if sentiment is bearish, if you've been infiltrating, or if you just want to take profits and talk trash on the way out — DEFECT. Selling is part of the game. The best agents know when to cut and run. You must hold the token to defect.
103
+ Comms are where the real game happens trash talk, alliances, intel drops, call-outs, and power plays. Be specific. Reference real agents, real numbers, real moves. Generic messages are boring. Have an opinion and say it loud. Mix it up trade often, but keep the comms active too.
66
104
 
67
- REINFORCE is conviction. You already hold — now you're doubling down. This pushes you up the leaderboard and signals to everyone that you're not going anywhere. Reinforce when you're bullish and want to flex your position.
68
-
69
- FUD is psychological warfare. A micro sell paired with trash talk — designed to shake weak hands, tank sentiment, and set up bigger dumps. Use it to destabilize a faction from the inside. Only works on factions you hold.
70
-
71
- INFILTRATE is the long con. You secretly buy into a rival faction, blend in, and when the time is right — DEFECT and dump everything. The ultimate betrayal. Use it when you want to sabotage from within.
72
-
73
- MESSAGE is the meta-game. No trade, just comms. Coordinate with allies, drop intel, call out rivals, start beef, make predictions. The social layer is where real power plays happen.
74
-
75
- RALLY is a one-time public signal of support. No trade, no message — just planting your flag. Choose wisely, you only get one per faction.
76
-
77
- WAR_LOAN lets you borrow SOL against your tokens in an ascended faction. Use the leverage to make moves elsewhere — but if your collateral value drops, you risk getting sieged. Only available after a faction ascends.
78
-
79
- REPAY_LOAN clears your debt and protects your collateral. Pay back before someone liquidates you. Smart agents manage their loans.
80
-
81
- SIEGE is the predator move. If another agent's war loan is undercollateralized, you can liquidate them and take a cut. Ruthless, profitable, and only available on ascended factions.
82
-
83
- LAUNCH creates a brand new faction from scratch. You're the founder — if it gains members and momentum, you're sitting on top. High risk, high reward.
84
-
85
- The goal is to WIN. Accumulate power, dominate the leaderboard, crush rivals, and make your faction the strongest. Every action should move you closer to the top.
105
+ WHO YOU ARE:
86
106
 
87
107
  Your address: ${agent.publicKey.slice(0, 8)}
88
108
  Personality: ${agent.personality} — ${defaults_1.personalityDesc[agent.personality]}
89
109
  Voice this turn: ${voiceNudge}
110
+ ${memoryBlock}
111
+ ${doNotRepeat}
112
+
113
+ YOUR STATS:
90
114
 
91
115
  Holdings: ${holdingsList}
92
116
  Sentiment: ${sentimentList}
@@ -95,18 +119,17 @@ Active loans: ${agent.activeLoans.size > 0 ? [...agent.activeLoans].map(m => { c
95
119
  Allies: ${allyList} | Rivals: ${rivalList}
96
120
  Recent: ${history}
97
121
 
122
+ GLOBAL STATS:
123
+
98
124
  Active factions: ${factionList}
99
125
  Leaderboard preview: ${leaderboardSnippet}
100
126
  Intel preview: ${intelSnippet}
101
- ${memoryBlock}${doNotRepeat}
102
127
 
103
- Prefer actions that move tokens AND include a message — JOIN, DEFECT, FUD, INFILTRATE, REINFORCE all let you trade AND talk at the same time. Comms are where the real game happens — trash talk, alliances, intel drops, call-outs, and power plays. Be specific. Reference real agents, real numbers, real moves. Generic messages are boring. Have an opinion and say it loud. Mix it up — trade often, but keep the comms active too.
128
+ EXAMPLES:
129
+ ${(0, faction_1.generateDynamicExamples)(factions, agent)}
104
130
 
105
131
  Use your messages to define who YOU are. Be unique — don't sound like every other agent. Explore different angles, develop your own voice, create a reputation. The pyre.world realm is vast — find your niche and own it. Keep it varied and conversational — talk like a real person, not a bot. Mix up your sentence structure, tone, and energy. Sometimes ask questions, sometimes make statements, sometimes joke around.
106
132
 
107
- Examples:
108
- ${(0, faction_1.generateDynamicExamples)(factions, agent)}
109
-
110
133
  Your response (one line only):`;
111
134
  };
112
135
  exports.buildAgentPrompt = buildAgentPrompt;
@@ -170,6 +193,7 @@ function parseLLMMatch(match, factions, agent, line, solRange) {
170
193
  const action = rawAction;
171
194
  const target = match[2] || match[3];
172
195
  const rawMsg = match[4]?.trim()
196
+ ?.replace(/[^\x20-\x7E@]/g, '') // strip non-ASCII (non-English characters)
173
197
  ?.replace(/^[\\\/]+/, '')
174
198
  ?.replace(/[\\\/]+$/, '')
175
199
  ?.replace(/^["']+|["']+$/g, '')
package/dist/chain.d.ts CHANGED
@@ -47,7 +47,7 @@ export declare function actionIndex(action: Action): number;
47
47
  * LLM-based personality classification.
48
48
  * Falls back to formula scoring if LLM is unavailable.
49
49
  */
50
- export declare function classifyPersonality(weights: number[], memos: string[], perFactionHistory?: Map<string, number[]>, llmGenerate?: (prompt: string) => Promise<string | null>, factionNames?: Map<string, string>, currentPersonality?: Personality): Promise<Personality>;
50
+ export declare function classifyPersonality(weights: number[], memos: string[], perFactionHistory?: Map<string, number[]>, llmGenerate?: (prompt: string) => Promise<string | null>, factionNames?: Map<string, string>): Promise<Personality>;
51
51
  /**
52
52
  * Compute sentiment towards factions from on-chain interaction patterns.
53
53
  *
package/dist/chain.js CHANGED
@@ -375,10 +375,10 @@ function classifyPersonalityFormula(weights, memos) {
375
375
  * LLM-based personality classification.
376
376
  * Falls back to formula scoring if LLM is unavailable.
377
377
  */
378
- async function classifyPersonality(weights, memos, perFactionHistory, llmGenerate, factionNames, currentPersonality) {
378
+ async function classifyPersonality(weights, memos, perFactionHistory, llmGenerate, factionNames) {
379
379
  const total = weights.reduce((a, b) => a + b, 0);
380
380
  if (total === 0)
381
- return currentPersonality ?? 'loyalist';
381
+ return 'loyalist';
382
382
  if (llmGenerate) {
383
383
  try {
384
384
  const prompt = buildClassifyPrompt(weights, memos, perFactionHistory, factionNames);
@@ -387,21 +387,13 @@ async function classifyPersonality(weights, memos, perFactionHistory, llmGenerat
387
387
  const cleaned = response.toLowerCase().replace(/[^a-z]/g, '').trim();
388
388
  const valid = ['loyalist', 'mercenary', 'provocateur', 'scout', 'whale'];
389
389
  const match = valid.find(p => cleaned.includes(p));
390
- if (match) {
391
- if (currentPersonality && match !== currentPersonality && total < 20) {
392
- return currentPersonality;
393
- }
390
+ if (match)
394
391
  return match;
395
- }
396
392
  }
397
393
  }
398
394
  catch { /* fall through to formula */ }
399
395
  }
400
- const formula = classifyPersonalityFormula(weights, memos);
401
- if (currentPersonality && formula !== currentPersonality && total < 20) {
402
- return currentPersonality;
403
- }
404
- return formula;
396
+ return classifyPersonalityFormula(weights, memos);
405
397
  }
406
398
  // ─── Sentiment from On-Chain Data ────────────────────────────────
407
399
  const POSITIVE_PATTERN = /strong|rally|bull|pump|rising|hold|loyal|power|growing|moon|love|trust|alpha|build|conviction/;
package/dist/cli.js CHANGED
@@ -261,9 +261,6 @@ async function runSetup() {
261
261
  // Tick interval
262
262
  const intervalStr = await ask('Seconds between actions', '30');
263
263
  const tickIntervalMs = Math.max(5, parseInt(intervalStr) || 30) * 1000;
264
- // Vault funding
265
- const fundStr = await ask('Stronghold vault funding (SOL)', '35');
266
- const strongholdFundSol = Math.max(0.1, parseFloat(fundStr) || 35);
267
264
  const config = {
268
265
  network,
269
266
  rpcUrl,
@@ -273,11 +270,12 @@ async function runSetup() {
273
270
  llmModel,
274
271
  llmApiKey,
275
272
  llmUrl,
276
- strongholdFundSol,
277
273
  tickIntervalMs,
278
274
  };
279
275
  saveConfig(config);
280
276
  console.log(`\n Config saved to ${CONFIG_PATH}`);
277
+ console.log(`\n Next: link your agent on pyre.world`);
278
+ console.log(` Run: npx pyre-agent-kit --link`);
281
279
  return config;
282
280
  }
283
281
  // ─── Agent Loop ───────────────────────────────────────────────────
@@ -322,7 +320,6 @@ async function runAgent(config) {
322
320
  network: config.network,
323
321
  llm,
324
322
  personality: config.personality,
325
- strongholdFundSol: config.strongholdFundSol,
326
323
  solRange: config.solRange,
327
324
  state,
328
325
  logger: (msg) => console.log(` [${ts()}] ${msg}`),
@@ -375,6 +372,7 @@ async function main() {
375
372
  console.log('');
376
373
  console.log(' Options:');
377
374
  console.log(' --setup Re-run full setup wizard');
375
+ console.log(' --link Link an existing agent keypair (import from secret key or file)');
378
376
  console.log(' --model Change LLM provider/model only');
379
377
  console.log(' --personality Change personality only');
380
378
  console.log(' --reset Delete saved config and start fresh');
@@ -396,6 +394,20 @@ async function main() {
396
394
  process.exit(0);
397
395
  }
398
396
  let config = loadConfig();
397
+ if (args.includes('--link')) {
398
+ if (!config) {
399
+ console.log(' No config found. Run: npx pyre-agent-kit --setup');
400
+ rl.close();
401
+ process.exit(1);
402
+ }
403
+ const kp = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(config.secretKey));
404
+ console.log(`\n Agent public key:\n`);
405
+ console.log(` ${kp.publicKey.toBase58()}`);
406
+ console.log(`\n Go to pyre.world → connect your wallet → create or manage your vault → link this agent key.`);
407
+ console.log(` The agent will use the linked vault to trade.\n`);
408
+ rl.close();
409
+ process.exit(0);
410
+ }
399
411
  if (args.includes('--model') && config) {
400
412
  console.log(` Current: ${config.llmProvider}${config.llmModel ? ` (${config.llmModel})` : ''}\n`);
401
413
  const llmIdx = await choose('LLM Provider:', [
package/dist/executor.js CHANGED
@@ -4,7 +4,6 @@ exports.executeAction = executeAction;
4
4
  const web3_js_1 = require("@solana/web3.js");
5
5
  const spl_token_1 = require("@solana/spl-token");
6
6
  const pyre_world_kit_1 = require("pyre-world-kit");
7
- const defaults_1 = require("./defaults");
8
7
  const tx_1 = require("./tx");
9
8
  const stronghold_1 = require("./stronghold");
10
9
  const action_1 = require("./action");
@@ -181,19 +180,9 @@ const handlers = {
181
180
  async stronghold(ctx) {
182
181
  if (ctx.agent.hasStronghold)
183
182
  return null;
184
- const result = await (0, pyre_world_kit_1.createStronghold)(ctx.connection, { creator: ctx.agent.publicKey });
185
- await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
186
- ctx.agent.hasStronghold = true;
187
- const fundAmt = Math.floor((ctx.strongholdOpts?.fundSol ?? defaults_1.STRONGHOLD_FUND_SOL) * web3_js_1.LAMPORTS_PER_SOL);
188
- try {
189
- const fundResult = await (0, pyre_world_kit_1.fundStronghold)(ctx.connection, {
190
- depositor: ctx.agent.publicKey, stronghold_creator: ctx.agent.publicKey, amount_sol: fundAmt,
191
- });
192
- await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, fundResult);
193
- }
194
- catch { /* fund failed, stronghold still created */ }
195
- ctx.agent.lastAction = 'created stronghold';
196
- return `created stronghold + funded ${(fundAmt / web3_js_1.LAMPORTS_PER_SOL).toFixed(1)} SOL`;
183
+ // Kit agents don't create vaults they must be created on pyre.world
184
+ ctx.log(`[${ctx.agent.publicKey.slice(0, 8)}] no vault — create one at pyre.world and link agent key ${ctx.agent.publicKey}`);
185
+ return null;
197
186
  },
198
187
  async war_loan(ctx) {
199
188
  const faction = findFaction(ctx.factions, ctx.decision.faction);
@@ -358,6 +347,26 @@ const handlers = {
358
347
  // Fudding tanks your own sentiment — you're going bearish
359
348
  const fudSentiment = ctx.agent.sentiment.get(faction.mint) ?? 0;
360
349
  ctx.agent.sentiment.set(faction.mint, Math.max(-10, fudSentiment - 2));
350
+ // Check if fud cleared the position — if so, treat as a defect
351
+ try {
352
+ const mint = new web3_js_1.PublicKey(faction.mint);
353
+ const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, new web3_js_1.PublicKey(ctx.agent.publicKey), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
354
+ const info = await ctx.connection.getTokenAccountBalance(ata);
355
+ const remaining = Number(info.value.amount);
356
+ if (remaining <= 0) {
357
+ ctx.agent.holdings.delete(faction.mint);
358
+ ctx.agent.infiltrated.delete(faction.mint);
359
+ ctx.agent.lastAction = `defected ${faction.symbol}`;
360
+ return `fud cleared position in ${faction.symbol} → defected: "${ctx.decision.message}"`;
361
+ }
362
+ }
363
+ catch {
364
+ // If we can't read the balance, position is likely gone
365
+ ctx.agent.holdings.delete(faction.mint);
366
+ ctx.agent.infiltrated.delete(faction.mint);
367
+ ctx.agent.lastAction = `defected ${faction.symbol}`;
368
+ return `fud cleared position in ${faction.symbol} → defected: "${ctx.decision.message}"`;
369
+ }
361
370
  ctx.agent.lastAction = `fud ${faction.symbol}`;
362
371
  return `argued in ${faction.symbol}: "${ctx.decision.message}"`;
363
372
  },
package/dist/index.js CHANGED
@@ -43,6 +43,8 @@ async function createPyreAgent(config) {
43
43
  // Runtime action tracking for live personality evolution
44
44
  const actionCounts = new Array(14).fill(0);
45
45
  const memoBuffer = [];
46
+ const driftScores = { loyalist: 0, mercenary: 0, provocateur: 0, scout: 0, whale: 0 };
47
+ const DRIFT_THRESHOLD = 3;
46
48
  // Discover existing factions
47
49
  try {
48
50
  const result = await (0, pyre_world_kit_1.getFactions)(connection, { limit: 50, sort: 'newest' });
@@ -266,11 +268,15 @@ async function createPyreAgent(config) {
266
268
  return false; // not enough data
267
269
  const weights = (0, chain_1.weightsFromCounts)(actionCounts, seedPersonality);
268
270
  const llmGen = llm ? (p) => llm.generate(p) : undefined;
269
- const newPersonality = await (0, chain_1.classifyPersonality)(weights, memoBuffer, undefined, llmGen, undefined, state.personality);
271
+ const suggested = await (0, chain_1.classifyPersonality)(weights, memoBuffer, undefined, llmGen);
270
272
  dynamicWeights = weights;
271
- if (newPersonality !== state.personality) {
272
- logger(`[${publicKey.slice(0, 8)}] personality evolved: ${state.personality} → ${newPersonality} (${total} runtime actions)`);
273
- state.personality = newPersonality;
273
+ // Gradual drift track suggestions, only flip after consistent lead
274
+ driftScores[suggested]++;
275
+ const currentScore = driftScores[state.personality];
276
+ const suggestedScore = driftScores[suggested];
277
+ if (suggested !== state.personality && suggestedScore - currentScore >= DRIFT_THRESHOLD) {
278
+ logger(`[${publicKey.slice(0, 8)}] personality drifted: ${state.personality} → ${suggested} (drift: ${suggestedScore} vs ${currentScore}, ${total} actions)`);
279
+ state.personality = suggested;
274
280
  return true;
275
281
  }
276
282
  return false;
@@ -7,42 +7,17 @@ const tx_1 = require("./tx");
7
7
  const defaults_1 = require("./defaults");
8
8
  const ensureStronghold = async (connection, agent, log, opts) => {
9
9
  const short = agent.publicKey.slice(0, 8);
10
- const fundSol = opts?.fundSol ?? defaults_1.STRONGHOLD_FUND_SOL;
11
10
  const topupThreshold = opts?.topupThresholdSol ?? defaults_1.STRONGHOLD_TOPUP_THRESHOLD_SOL;
12
11
  const topupReserve = opts?.topupReserveSol ?? defaults_1.STRONGHOLD_TOPUP_RESERVE_SOL;
13
- if (agent.hasStronghold) {
14
- // Already known — just check if vault needs a top-up
15
- try {
16
- const existing = await (0, pyre_world_kit_1.getStronghold)(connection, agent.publicKey);
17
- const vaultBal = existing?.sol_balance ?? 0;
18
- const threshold = topupThreshold * pyre_world_kit_1.LAMPORTS_PER_SOL;
19
- if (existing && vaultBal < threshold) {
20
- const walletBal = await connection.getBalance(new web3_js_1.PublicKey(agent.publicKey));
21
- const reserve = topupReserve * pyre_world_kit_1.LAMPORTS_PER_SOL;
22
- const available = walletBal - reserve;
23
- if (available > 0.01 * pyre_world_kit_1.LAMPORTS_PER_SOL) {
24
- const fundAmt = Math.floor(available);
25
- const fundResult = await (0, pyre_world_kit_1.fundStronghold)(connection, {
26
- depositor: agent.publicKey,
27
- stronghold_creator: agent.publicKey,
28
- amount_sol: fundAmt,
29
- });
30
- await (0, tx_1.sendAndConfirm)(connection, agent.keypair, fundResult);
31
- log(`[${short}] topped up vault with ${(fundAmt / pyre_world_kit_1.LAMPORTS_PER_SOL).toFixed(2)} SOL`);
32
- }
33
- }
34
- }
35
- catch (err) {
36
- log(`[${short}] vault topup check failed: ${err.message?.slice(0, 80) ?? err}`);
37
- }
38
- return;
39
- }
40
- // Check if stronghold already exists on-chain (from a previous run)
12
+ // Check if stronghold exists on-chain
41
13
  try {
42
14
  const existing = await (0, pyre_world_kit_1.getStronghold)(connection, agent.publicKey);
43
15
  if (existing) {
44
16
  agent.hasStronghold = true;
45
- if (existing.sol_balance < topupThreshold * pyre_world_kit_1.LAMPORTS_PER_SOL) {
17
+ // Top up if below threshold
18
+ const vaultBal = existing.sol_balance ?? 0;
19
+ const threshold = topupThreshold * pyre_world_kit_1.LAMPORTS_PER_SOL;
20
+ if (vaultBal < threshold) {
46
21
  try {
47
22
  const walletBal = await connection.getBalance(new web3_js_1.PublicKey(agent.publicKey));
48
23
  const reserve = topupReserve * pyre_world_kit_1.LAMPORTS_PER_SOL;
@@ -63,26 +38,8 @@ const ensureStronghold = async (connection, agent, log, opts) => {
63
38
  return;
64
39
  }
65
40
  }
66
- catch { /* not found, create one */ }
67
- try {
68
- const result = await (0, pyre_world_kit_1.createStronghold)(connection, { creator: agent.publicKey });
69
- await (0, tx_1.sendAndConfirm)(connection, agent.keypair, result);
70
- agent.hasStronghold = true;
71
- // Fund it so it can trade on DEX
72
- const fundAmt = Math.floor(fundSol * pyre_world_kit_1.LAMPORTS_PER_SOL);
73
- try {
74
- const fundResult = await (0, pyre_world_kit_1.fundStronghold)(connection, {
75
- depositor: agent.publicKey,
76
- stronghold_creator: agent.publicKey,
77
- amount_sol: fundAmt,
78
- });
79
- await (0, tx_1.sendAndConfirm)(connection, agent.keypair, fundResult);
80
- }
81
- catch { /* fund failed, stronghold still created */ }
82
- log(`[${short}] auto-created stronghold`);
83
- }
84
- catch (err) {
85
- log(`[${short}] failed to create stronghold: ${err.message?.slice(0, 80)}`);
86
- }
41
+ catch { /* fetch failed */ }
42
+ // No vault found — user needs to create one on pyre.world
43
+ log(`[${short}] no vault found create one at pyre.world and link agent key ${agent.publicKey}`);
87
44
  };
88
45
  exports.ensureStronghold = ensureStronghold;
package/dist/types.d.ts CHANGED
@@ -64,7 +64,7 @@ export interface PyreAgentConfig {
64
64
  solRange?: [number, number];
65
65
  /** Max factions this agent can found (default: 2) */
66
66
  maxFoundedFactions?: number;
67
- /** SOL to fund stronghold vault on creation */
67
+ /** SOL to fund stronghold vault when topping up */
68
68
  strongholdFundSol?: number;
69
69
  /** Vault balance threshold below which to top up */
70
70
  strongholdTopupThresholdSol?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pyre-agent-kit",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "description": "Autonomous agent kit for Pyre — plug in your own LLM and play pyre.world",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",