pyre-agent-kit 2.0.24 → 2.0.27
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 +30 -8
- package/dist/cli.js +31 -5
- package/dist/executor.js +34 -36
- package/package.json +2 -2
package/dist/agent.js
CHANGED
|
@@ -6,6 +6,8 @@ exports.llmDecide = llmDecide;
|
|
|
6
6
|
const pyre_world_kit_1 = require("pyre-world-kit");
|
|
7
7
|
const defaults_1 = require("./defaults");
|
|
8
8
|
const util_1 = require("./util");
|
|
9
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
10
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
9
11
|
const faction_1 = require("./faction");
|
|
10
12
|
// Store scout results to show on the next turn
|
|
11
13
|
exports.pendingScoutResults = new Map();
|
|
@@ -30,7 +32,11 @@ async function executeScout(connection, targetAddress) {
|
|
|
30
32
|
const checkpoint = p.last_checkpoint > 0
|
|
31
33
|
? new Date(p.last_checkpoint * 1000).toISOString().slice(0, 10)
|
|
32
34
|
: 'never';
|
|
33
|
-
|
|
35
|
+
const spent = (p.total_sol_spent ?? 0) / 1e9;
|
|
36
|
+
const received = (p.total_sol_received ?? 0) / 1e9;
|
|
37
|
+
const pnl = received - spent;
|
|
38
|
+
const pnlStr = pnl >= 0 ? `+${pnl.toFixed(3)}` : pnl.toFixed(3);
|
|
39
|
+
return ` @${targetAddress.slice(0, 8)}: "${personality}" | ${total} actions (${topActions}) | P&L: ${pnlStr} SOL | last seen: ${checkpoint}`;
|
|
34
40
|
}
|
|
35
41
|
catch {
|
|
36
42
|
return ` @${targetAddress.slice(0, 8)}: lookup failed`;
|
|
@@ -113,33 +119,33 @@ MESSAGE is the meta-game. No trade, just comms.
|
|
|
113
119
|
Coordinate with allies, drop intel, call out rivals, start beef, make predictions.
|
|
114
120
|
The social layer is where real power plays happen.
|
|
115
121
|
- RALLY SYMBOL -
|
|
116
|
-
show support (one-time per faction
|
|
122
|
+
show support (one-time per faction). messages not availale.
|
|
117
123
|
RALLY is a one-time public signal of support.
|
|
118
124
|
No trade, no message — just planting your flag.
|
|
119
125
|
Choose wisely, you only get one per faction.
|
|
120
126
|
- WAR_LOAN SYMBOL -
|
|
121
|
-
borrow SOL against collateral (ascended factions only).
|
|
127
|
+
borrow SOL against collateral (ascended factions only). messages not availale.
|
|
122
128
|
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.
|
|
123
129
|
Only available after a faction ascends.
|
|
124
130
|
- REPAY_LOAN SYMBOL -
|
|
125
|
-
repay a loan.
|
|
131
|
+
repay a loan. messages not availale.
|
|
126
132
|
REPAY_LOAN clears your debt and protects your collateral.
|
|
127
133
|
Pay back before someone liquidates you.
|
|
128
134
|
Smart agents manage their loans.
|
|
129
135
|
- SIEGE SYMBOL —
|
|
130
|
-
liquidate undercollateralized loan (ascended factions only).
|
|
136
|
+
liquidate undercollateralized loan (ascended factions only). messages not availale.
|
|
131
137
|
SIEGE is the predator move. If another agent's war loan is undercollateralized, you can liquidate them and take a cut.
|
|
132
138
|
Ruthless, profitable, and only available on ascended factions.
|
|
133
139
|
- LAUNCH "name" —
|
|
134
|
-
create a new faction.
|
|
140
|
+
create a new faction. messages not availale.
|
|
135
141
|
LAUNCH creates a brand new faction from scratch.
|
|
136
142
|
You're the founder — if it gains members and momentum, you're sitting on top. High risk, high reward.
|
|
137
143
|
- SCOUT @address —
|
|
138
|
-
look up an agent's on-chain identity from the pyre_world registry.
|
|
144
|
+
look up an agent's on-chain identity from the pyre_world registry (no trade). messages not availale.
|
|
139
145
|
SCOUT reveals their personality, total actions, and what they do most (joins, defects, infiltrates, etc).
|
|
140
146
|
Use it to size up rivals, verify allies, or gather intel before making a move. The result will be shown to you next turn.
|
|
141
147
|
|
|
142
|
-
Prefer actions that move tokens AND include a message — JOIN, 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.
|
|
148
|
+
Prefer actions that move tokens AND include a message — JOIN, 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. WAR_LOAN, REPAY_LOAN, and SIEGE are important post ascended faction mechanics that create richer game mechanics.
|
|
143
149
|
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.
|
|
144
150
|
|
|
145
151
|
WHO YOU ARE:
|
|
@@ -299,6 +305,22 @@ function parseLLMMatch(match, factions, agent, line, solRange) {
|
|
|
299
305
|
};
|
|
300
306
|
}
|
|
301
307
|
async function llmDecide(agent, factions, connection, recentMessages, llm, log, solRange, chainMemories) {
|
|
308
|
+
// Refresh holdings from on-chain before building prompt
|
|
309
|
+
for (const [mint] of agent.holdings) {
|
|
310
|
+
try {
|
|
311
|
+
const mintPk = new web3_js_1.PublicKey(mint);
|
|
312
|
+
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mintPk, new web3_js_1.PublicKey(agent.publicKey), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
313
|
+
const info = await connection.getTokenAccountBalance(ata);
|
|
314
|
+
const bal = Number(info.value.amount);
|
|
315
|
+
if (bal <= 0)
|
|
316
|
+
agent.holdings.delete(mint);
|
|
317
|
+
else
|
|
318
|
+
agent.holdings.set(mint, bal);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
agent.holdings.delete(mint);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
302
324
|
let leaderboardSnippet = '';
|
|
303
325
|
try {
|
|
304
326
|
const lb = await (0, pyre_world_kit_1.getFactionLeaderboard)(connection, { limit: 5 });
|
package/dist/cli.js
CHANGED
|
@@ -350,7 +350,9 @@ async function runAgent(config) {
|
|
|
350
350
|
];
|
|
351
351
|
const actionCounts = new Array(14).fill(0);
|
|
352
352
|
const recentMemos = [];
|
|
353
|
-
|
|
353
|
+
let totalSolSpent = 0; // lamports
|
|
354
|
+
let totalSolReceived = 0; // lamports
|
|
355
|
+
// Seed counts + P&L from registry profile if available
|
|
354
356
|
try {
|
|
355
357
|
const reg = await (0, pyre_world_kit_1.getRegistryProfile)(connection, keypair.publicKey.toBase58());
|
|
356
358
|
if (reg) {
|
|
@@ -361,14 +363,26 @@ async function runAgent(config) {
|
|
|
361
363
|
];
|
|
362
364
|
for (let i = 0; i < seed.length; i++)
|
|
363
365
|
actionCounts[i] = Math.max(actionCounts[i], seed[i]);
|
|
366
|
+
totalSolSpent = reg.total_sol_spent ?? 0;
|
|
367
|
+
totalSolReceived = reg.total_sol_received ?? 0;
|
|
364
368
|
}
|
|
365
369
|
}
|
|
366
370
|
catch { /* no profile yet */ }
|
|
367
371
|
let tickCount = 0;
|
|
368
372
|
while (running) {
|
|
369
373
|
try {
|
|
374
|
+
const solBefore = await connection.getBalance(keypair.publicKey);
|
|
370
375
|
const result = await agent.tick();
|
|
371
376
|
tickCount++;
|
|
377
|
+
// Track P&L from SOL balance changes
|
|
378
|
+
if (result.success) {
|
|
379
|
+
const solAfter = await connection.getBalance(keypair.publicKey);
|
|
380
|
+
const diff = solAfter - solBefore;
|
|
381
|
+
if (diff < 0)
|
|
382
|
+
totalSolSpent += Math.abs(diff); // spent SOL (buy)
|
|
383
|
+
if (diff > 0)
|
|
384
|
+
totalSolReceived += diff; // received SOL (sell)
|
|
385
|
+
}
|
|
372
386
|
const status = result.success ? 'OK' : `FAIL: ${result.error}`;
|
|
373
387
|
const msg = result.message ? ` "${result.message}"` : '';
|
|
374
388
|
const brain = result.usedLLM ? 'LLM' : 'RNG';
|
|
@@ -393,9 +407,18 @@ async function runAgent(config) {
|
|
|
393
407
|
if (tickCount % CHECKPOINT_EVERY === 0) {
|
|
394
408
|
try {
|
|
395
409
|
const personality = agent.personality;
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
410
|
+
let summary = personality;
|
|
411
|
+
if (recentMemos.length > 0 && llm) {
|
|
412
|
+
try {
|
|
413
|
+
const topActions = ['joins', 'defects', 'rallies', 'launches', 'messages', 'strongholds', 'war_loans', 'repay_loans', 'sieges', 'ascends', 'razes', 'tithes', 'infiltrates', 'fuds']
|
|
414
|
+
.map((n, i) => ({ n, v: actionCounts[i] })).filter(a => a.v > 0).sort((a, b) => b.v - a.v).slice(0, 4).map(a => `${a.n}:${a.v}`).join(', ');
|
|
415
|
+
const bioPrompt = `Write a 1-2 sentence bio for this autonomous agent in a faction warfare game. Be specific and colorful — capture their unique personality and reputation based on their actual behavior.\n\nPersonality type: ${personality}\nTop actions: ${topActions}\nRecent messages they've sent:\n${recentMemos.slice(-8).map(m => `- "${m}"`).join('\n')}\n\nBio (max 200 chars, no quotes, third person, like a character description):`;
|
|
416
|
+
const bio = await llm.generate(bioPrompt);
|
|
417
|
+
if (bio)
|
|
418
|
+
summary = bio.replace(/^["']+|["']+$/g, '').slice(0, 200);
|
|
419
|
+
}
|
|
420
|
+
catch { }
|
|
421
|
+
}
|
|
399
422
|
const pub = keypair.publicKey.toBase58();
|
|
400
423
|
const cpResult = await (0, pyre_world_kit_1.buildCheckpointTransaction)(connection, {
|
|
401
424
|
signer: pub,
|
|
@@ -406,9 +429,12 @@ async function runAgent(config) {
|
|
|
406
429
|
war_loans: actionCounts[6], repay_loans: actionCounts[7], sieges: actionCounts[8],
|
|
407
430
|
ascends: actionCounts[9], razes: actionCounts[10], tithes: actionCounts[11],
|
|
408
431
|
personality_summary: summary,
|
|
432
|
+
total_sol_spent: totalSolSpent,
|
|
433
|
+
total_sol_received: totalSolReceived,
|
|
409
434
|
});
|
|
410
435
|
await (0, index_1.sendAndConfirm)(connection, keypair, cpResult);
|
|
411
|
-
|
|
436
|
+
const pnl = (totalSolReceived - totalSolSpent) / 1e9;
|
|
437
|
+
console.log(` [${ts()}] Checkpointed to pyre_world (${actionCounts.reduce((a, b) => a + b, 0)} actions, P&L: ${pnl >= 0 ? '+' : ''}${pnl.toFixed(3)} SOL)`);
|
|
412
438
|
}
|
|
413
439
|
catch (e) {
|
|
414
440
|
console.error(` [${ts()}] Checkpoint failed: ${e.message?.slice(0, 60)}`);
|
package/dist/executor.js
CHANGED
|
@@ -11,6 +11,18 @@ const error_1 = require("./error");
|
|
|
11
11
|
const faction_1 = require("./faction");
|
|
12
12
|
const agent_1 = require("./agent");
|
|
13
13
|
const findFaction = (factions, symbol) => factions.find(f => f.symbol === symbol);
|
|
14
|
+
/** Fetch real on-chain token balance. Returns 0 if no ATA or error. */
|
|
15
|
+
async function getOnChainBalance(connection, mint, owner) {
|
|
16
|
+
try {
|
|
17
|
+
const mintPk = new web3_js_1.PublicKey(mint);
|
|
18
|
+
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mintPk, new web3_js_1.PublicKey(owner), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
19
|
+
const info = await connection.getTokenAccountBalance(ata);
|
|
20
|
+
return Number(info.value.amount);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
14
26
|
/** Vault creator key — may differ from agent key for linked vaults */
|
|
15
27
|
const vault = (agent) => agent.vaultCreator ?? agent.publicKey;
|
|
16
28
|
const handlers = {
|
|
@@ -41,8 +53,8 @@ const handlers = {
|
|
|
41
53
|
const result = await (0, pyre_world_kit_1.joinFaction)(ctx.connection, params);
|
|
42
54
|
await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
|
|
43
55
|
}
|
|
44
|
-
const
|
|
45
|
-
ctx.agent.holdings.set(faction.mint,
|
|
56
|
+
const newBal = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
57
|
+
ctx.agent.holdings.set(faction.mint, newBal > 0 ? newBal : 1);
|
|
46
58
|
ctx.agent.voted.add(faction.mint);
|
|
47
59
|
ctx.agent.lastAction = `joined ${faction.symbol}`;
|
|
48
60
|
return `joined ${faction.symbol} for ${sol.toFixed(4)} SOL${ctx.decision.message ? ` — "${ctx.decision.message}"` : ''}`;
|
|
@@ -51,17 +63,7 @@ const handlers = {
|
|
|
51
63
|
const faction = findFaction(ctx.factions, ctx.decision.faction);
|
|
52
64
|
if (!faction)
|
|
53
65
|
return null;
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const mint = new web3_js_1.PublicKey(faction.mint);
|
|
57
|
-
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, new web3_js_1.PublicKey(ctx.agent.publicKey), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
58
|
-
const info = await ctx.connection.getTokenAccountBalance(ata);
|
|
59
|
-
balance = Number(info.value.amount);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
ctx.agent.holdings.delete(faction.mint);
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
66
|
+
const balance = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
65
67
|
if (balance <= 0) {
|
|
66
68
|
ctx.agent.holdings.delete(faction.mint);
|
|
67
69
|
return null;
|
|
@@ -88,7 +90,7 @@ const handlers = {
|
|
|
88
90
|
});
|
|
89
91
|
await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
|
|
90
92
|
}
|
|
91
|
-
const remaining =
|
|
93
|
+
const remaining = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
92
94
|
if (remaining <= 0) {
|
|
93
95
|
ctx.agent.holdings.delete(faction.mint);
|
|
94
96
|
ctx.agent.infiltrated.delete(faction.mint);
|
|
@@ -174,8 +176,8 @@ const handlers = {
|
|
|
174
176
|
throw retryErr;
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
|
-
const
|
|
178
|
-
ctx.agent.holdings.set(faction.mint,
|
|
179
|
+
const msgBal = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
180
|
+
ctx.agent.holdings.set(faction.mint, msgBal > 0 ? msgBal : 1);
|
|
179
181
|
ctx.agent.voted.add(faction.mint);
|
|
180
182
|
ctx.agent.lastAction = `messaged ${faction.symbol}`;
|
|
181
183
|
return `said in ${faction.symbol}: "${ctx.decision.message}"`;
|
|
@@ -191,9 +193,11 @@ const handlers = {
|
|
|
191
193
|
const faction = findFaction(ctx.factions, ctx.decision.faction);
|
|
192
194
|
if (!faction)
|
|
193
195
|
return null;
|
|
194
|
-
const balance = ctx.
|
|
195
|
-
if (balance <= 0)
|
|
196
|
+
const balance = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
197
|
+
if (balance <= 0) {
|
|
198
|
+
ctx.agent.holdings.delete(faction.mint);
|
|
196
199
|
return null;
|
|
200
|
+
}
|
|
197
201
|
const collateral = Math.max(1, Math.floor(balance * (0.90 + Math.random() * 0.09)));
|
|
198
202
|
let borrowLamports;
|
|
199
203
|
try {
|
|
@@ -327,8 +331,8 @@ const handlers = {
|
|
|
327
331
|
const result = await (0, pyre_world_kit_1.joinFaction)(ctx.connection, params);
|
|
328
332
|
await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
|
|
329
333
|
}
|
|
330
|
-
const
|
|
331
|
-
ctx.agent.holdings.set(faction.mint,
|
|
334
|
+
const infBal = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
335
|
+
ctx.agent.holdings.set(faction.mint, infBal > 0 ? infBal : 1);
|
|
332
336
|
ctx.agent.infiltrated.add(faction.mint);
|
|
333
337
|
ctx.agent.voted.add(faction.mint);
|
|
334
338
|
ctx.agent.sentiment.set(faction.mint, -5);
|
|
@@ -337,8 +341,14 @@ const handlers = {
|
|
|
337
341
|
},
|
|
338
342
|
async fud(ctx) {
|
|
339
343
|
const faction = findFaction(ctx.factions, ctx.decision.faction);
|
|
340
|
-
if (!faction || !ctx.decision.message
|
|
344
|
+
if (!faction || !ctx.decision.message)
|
|
345
|
+
return null;
|
|
346
|
+
// Verify on-chain balance before FUD (micro sell)
|
|
347
|
+
const fudBal = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
348
|
+
if (fudBal <= 0) {
|
|
349
|
+
ctx.agent.holdings.delete(faction.mint);
|
|
341
350
|
return null;
|
|
351
|
+
}
|
|
342
352
|
await (0, stronghold_1.ensureStronghold)(ctx.connection, ctx.agent, ctx.log, ctx.strongholdOpts);
|
|
343
353
|
if (!ctx.agent.hasStronghold)
|
|
344
354
|
return null;
|
|
@@ -350,21 +360,9 @@ const handlers = {
|
|
|
350
360
|
// Fudding tanks your own sentiment — you're going bearish
|
|
351
361
|
const fudSentiment = ctx.agent.sentiment.get(faction.mint) ?? 0;
|
|
352
362
|
ctx.agent.sentiment.set(faction.mint, Math.max(-10, fudSentiment - 2));
|
|
353
|
-
// Check if fud cleared the position
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, new web3_js_1.PublicKey(ctx.agent.publicKey), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
357
|
-
const info = await ctx.connection.getTokenAccountBalance(ata);
|
|
358
|
-
const remaining = Number(info.value.amount);
|
|
359
|
-
if (remaining <= 0) {
|
|
360
|
-
ctx.agent.holdings.delete(faction.mint);
|
|
361
|
-
ctx.agent.infiltrated.delete(faction.mint);
|
|
362
|
-
ctx.agent.lastAction = `defected ${faction.symbol}`;
|
|
363
|
-
return `fud cleared position in ${faction.symbol} → defected: "${ctx.decision.message}"`;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
catch {
|
|
367
|
-
// If we can't read the balance, position is likely gone
|
|
363
|
+
// Check if fud cleared the position
|
|
364
|
+
const postFudBal = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
365
|
+
if (postFudBal <= 0) {
|
|
368
366
|
ctx.agent.holdings.delete(faction.mint);
|
|
369
367
|
ctx.agent.infiltrated.delete(faction.mint);
|
|
370
368
|
ctx.agent.lastAction = `defected ${faction.symbol}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pyre-agent-kit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.27",
|
|
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",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@solana/spl-token": "^0.4.6",
|
|
17
17
|
"@solana/web3.js": "^1.98.4",
|
|
18
|
-
"pyre-world-kit": "2.0.
|
|
18
|
+
"pyre-world-kit": "2.0.4"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^25.4.0",
|