pyre-agent-kit 2.0.23 → 2.0.25
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.d.ts +3 -0
- package/dist/agent.js +76 -8
- package/dist/cli.js +31 -5
- package/dist/defaults.js +2 -1
- package/dist/executor.js +49 -36
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
package/dist/agent.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { AgentState, FactionInfo, LLMAdapter, LLMDecision } from './types';
|
|
2
2
|
import { Connection } from '@solana/web3.js';
|
|
3
|
+
export declare const pendingScoutResults: Map<string, string[]>;
|
|
4
|
+
/** Execute a SCOUT action — look up an agent's pyre_world registry profile */
|
|
5
|
+
export declare function executeScout(connection: Connection, targetAddress: string): Promise<string>;
|
|
3
6
|
export declare const buildAgentPrompt: (agent: AgentState, factions: FactionInfo[], leaderboardSnippet: string, intelSnippet: string, recentMessages: string[], solRange?: [number, number], chainMemories?: string[]) => string;
|
|
4
7
|
export declare function llmDecide(agent: AgentState, factions: FactionInfo[], connection: Connection, recentMessages: string[], llm: LLMAdapter, log: (msg: string) => void, solRange?: [number, number], chainMemories?: string[]): Promise<LLMDecision | null>;
|
package/dist/agent.js
CHANGED
|
@@ -1,11 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildAgentPrompt = void 0;
|
|
3
|
+
exports.buildAgentPrompt = exports.pendingScoutResults = void 0;
|
|
4
|
+
exports.executeScout = executeScout;
|
|
4
5
|
exports.llmDecide = llmDecide;
|
|
5
6
|
const pyre_world_kit_1 = require("pyre-world-kit");
|
|
6
7
|
const defaults_1 = require("./defaults");
|
|
7
8
|
const util_1 = require("./util");
|
|
9
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
10
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
8
11
|
const faction_1 = require("./faction");
|
|
12
|
+
// Store scout results to show on the next turn
|
|
13
|
+
exports.pendingScoutResults = new Map();
|
|
14
|
+
/** Execute a SCOUT action — look up an agent's pyre_world registry profile */
|
|
15
|
+
async function executeScout(connection, targetAddress) {
|
|
16
|
+
try {
|
|
17
|
+
const p = await (0, pyre_world_kit_1.getRegistryProfile)(connection, targetAddress);
|
|
18
|
+
if (!p)
|
|
19
|
+
return ` @${targetAddress.slice(0, 8)}: no pyre identity found`;
|
|
20
|
+
const total = p.joins + p.defects + p.rallies + p.launches + p.messages +
|
|
21
|
+
p.fuds + p.infiltrates + p.reinforces + p.war_loans + p.repay_loans +
|
|
22
|
+
p.sieges + p.ascends + p.razes + p.tithes;
|
|
23
|
+
const topActions = [
|
|
24
|
+
{ n: 'joins', v: p.joins }, { n: 'defects', v: p.defects },
|
|
25
|
+
{ n: 'rallies', v: p.rallies }, { n: 'messages', v: p.messages },
|
|
26
|
+
{ n: 'fuds', v: p.fuds }, { n: 'infiltrates', v: p.infiltrates },
|
|
27
|
+
{ n: 'reinforces', v: p.reinforces }, { n: 'war_loans', v: p.war_loans },
|
|
28
|
+
{ n: 'sieges', v: p.sieges },
|
|
29
|
+
].sort((a, b) => b.v - a.v).filter(a => a.v > 0).slice(0, 4)
|
|
30
|
+
.map(a => `${a.n}:${a.v}`).join(', ');
|
|
31
|
+
const personality = p.personality_summary || 'unknown';
|
|
32
|
+
const checkpoint = p.last_checkpoint > 0
|
|
33
|
+
? new Date(p.last_checkpoint * 1000).toISOString().slice(0, 10)
|
|
34
|
+
: 'never';
|
|
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}`;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return ` @${targetAddress.slice(0, 8)}: lookup failed`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
9
45
|
const buildAgentPrompt = (agent, factions, leaderboardSnippet, intelSnippet, recentMessages, solRange, chainMemories) => {
|
|
10
46
|
const [minSol, maxSol] = solRange ?? defaults_1.PERSONALITY_SOL[agent.personality];
|
|
11
47
|
const holdingsList = [...agent.holdings.entries()]
|
|
@@ -83,29 +119,33 @@ MESSAGE is the meta-game. No trade, just comms.
|
|
|
83
119
|
Coordinate with allies, drop intel, call out rivals, start beef, make predictions.
|
|
84
120
|
The social layer is where real power plays happen.
|
|
85
121
|
- RALLY SYMBOL -
|
|
86
|
-
show support (one-time per faction
|
|
122
|
+
show support (one-time per faction). messages not availale.
|
|
87
123
|
RALLY is a one-time public signal of support.
|
|
88
124
|
No trade, no message — just planting your flag.
|
|
89
125
|
Choose wisely, you only get one per faction.
|
|
90
126
|
- WAR_LOAN SYMBOL -
|
|
91
|
-
borrow SOL against collateral (ascended factions only).
|
|
127
|
+
borrow SOL against collateral (ascended factions only). messages not availale.
|
|
92
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.
|
|
93
129
|
Only available after a faction ascends.
|
|
94
130
|
- REPAY_LOAN SYMBOL -
|
|
95
|
-
repay a loan.
|
|
131
|
+
repay a loan. messages not availale.
|
|
96
132
|
REPAY_LOAN clears your debt and protects your collateral.
|
|
97
133
|
Pay back before someone liquidates you.
|
|
98
134
|
Smart agents manage their loans.
|
|
99
135
|
- SIEGE SYMBOL —
|
|
100
|
-
liquidate undercollateralized loan (ascended factions only).
|
|
136
|
+
liquidate undercollateralized loan (ascended factions only). messages not availale.
|
|
101
137
|
SIEGE is the predator move. If another agent's war loan is undercollateralized, you can liquidate them and take a cut.
|
|
102
138
|
Ruthless, profitable, and only available on ascended factions.
|
|
103
139
|
- LAUNCH "name" —
|
|
104
|
-
create a new faction.
|
|
140
|
+
create a new faction. messages not availale.
|
|
105
141
|
LAUNCH creates a brand new faction from scratch.
|
|
106
142
|
You're the founder — if it gains members and momentum, you're sitting on top. High risk, high reward.
|
|
143
|
+
- SCOUT @address —
|
|
144
|
+
look up an agent's on-chain identity from the pyre_world registry (no trade). messages not availale.
|
|
145
|
+
SCOUT reveals their personality, total actions, and what they do most (joins, defects, infiltrates, etc).
|
|
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.
|
|
107
147
|
|
|
108
|
-
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.
|
|
109
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.
|
|
110
150
|
|
|
111
151
|
WHO YOU ARE:
|
|
@@ -144,6 +184,11 @@ function parseLLMDecision(raw, factions, agent, solRange) {
|
|
|
144
184
|
return null;
|
|
145
185
|
for (const candidate of lines) {
|
|
146
186
|
const line = candidate.trim();
|
|
187
|
+
// Handle SCOUT @address
|
|
188
|
+
const scoutMatch = line.match(/^SCOUT\s+@?([A-Za-z0-9]{6,44})/i);
|
|
189
|
+
if (scoutMatch) {
|
|
190
|
+
return { action: 'scout', faction: scoutMatch[1], reasoning: line };
|
|
191
|
+
}
|
|
147
192
|
const cleaned = line
|
|
148
193
|
.replace(/\*+/g, '') // strip all bold/italic markdown (e.g. **DEFECT SBP "msg"**)
|
|
149
194
|
.replace(/^[-•>#\d.)\s]+/, '').replace(/^(?:WARNING|NOTE|RESPONSE|OUTPUT|ANSWER|RESULT|SCPRT|SCRIPT)\s*:?\s*/i, '').replace(/^ACTION\s+/i, '')
|
|
@@ -260,6 +305,22 @@ function parseLLMMatch(match, factions, agent, line, solRange) {
|
|
|
260
305
|
};
|
|
261
306
|
}
|
|
262
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
|
+
}
|
|
263
324
|
let leaderboardSnippet = '';
|
|
264
325
|
try {
|
|
265
326
|
const lb = await (0, pyre_world_kit_1.getFactionLeaderboard)(connection, { limit: 5 });
|
|
@@ -323,7 +384,14 @@ async function llmDecide(agent, factions, connection, recentMessages, llm, log,
|
|
|
323
384
|
catch {
|
|
324
385
|
// intel fetch failed, proceed without it
|
|
325
386
|
}
|
|
326
|
-
|
|
387
|
+
// Include results from previous SCOUT actions
|
|
388
|
+
const scoutResults = exports.pendingScoutResults.get(agent.publicKey);
|
|
389
|
+
let scoutSnippet = '';
|
|
390
|
+
if (scoutResults && scoutResults.length > 0) {
|
|
391
|
+
scoutSnippet = '\nSCOUT RESULTS (from your previous SCOUT actions):\n' + scoutResults.join('\n');
|
|
392
|
+
exports.pendingScoutResults.delete(agent.publicKey);
|
|
393
|
+
}
|
|
394
|
+
const prompt = (0, exports.buildAgentPrompt)(agent, factions, leaderboardSnippet, intelSnippet + scoutSnippet, recentMessages, solRange, chainMemories);
|
|
327
395
|
const raw = await llm.generate(prompt);
|
|
328
396
|
if (!raw) {
|
|
329
397
|
log(`[${agent.publicKey.slice(0, 8)}] LLM returned null`);
|
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/defaults.js
CHANGED
|
@@ -72,7 +72,8 @@ exports.ACTION_MAP = {
|
|
|
72
72
|
'SEND': 'MESSAGE', 'SAY': 'MESSAGE', 'CHAT': 'MESSAGE', 'MSG': 'MESSAGE', 'MESSAGING': 'MESSAGE',
|
|
73
73
|
'CREATE': 'LAUNCH', 'FOUND': 'LAUNCH', 'HARVEST': 'TITHE',
|
|
74
74
|
'MIGRATE': 'ASCEND', 'RECLAIM': 'RAZE', 'SPY': 'INFILTRATE',
|
|
75
|
-
'INVESTIGATION': 'INFILTRATE', 'INVESTIGATE': 'INFILTRATE', '
|
|
75
|
+
'INVESTIGATION': 'INFILTRATE', 'INVESTIGATE': 'INFILTRATE', 'RECON': 'INFILTRATE',
|
|
76
|
+
'SCOUT': 'SCOUT',
|
|
76
77
|
'PLEDGE': 'JOIN', 'ALLY': 'JOIN', 'BACK': 'JOIN', 'FUND': 'JOIN',
|
|
77
78
|
'WITHDRAW': 'DEFECT', 'RETREAT': 'DEFECT', 'ABANDON': 'DEFECT', 'BAIL': 'DEFECT',
|
|
78
79
|
'ANNOUNCE': 'MESSAGE', 'BROADCAST': 'MESSAGE', 'COMM': 'MESSAGE', 'COMMS': 'MESSAGE', 'REPORT': 'MESSAGE',
|
package/dist/executor.js
CHANGED
|
@@ -9,7 +9,20 @@ const stronghold_1 = require("./stronghold");
|
|
|
9
9
|
const action_1 = require("./action");
|
|
10
10
|
const error_1 = require("./error");
|
|
11
11
|
const faction_1 = require("./faction");
|
|
12
|
+
const agent_1 = require("./agent");
|
|
12
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
|
+
}
|
|
13
26
|
/** Vault creator key — may differ from agent key for linked vaults */
|
|
14
27
|
const vault = (agent) => agent.vaultCreator ?? agent.publicKey;
|
|
15
28
|
const handlers = {
|
|
@@ -40,8 +53,8 @@ const handlers = {
|
|
|
40
53
|
const result = await (0, pyre_world_kit_1.joinFaction)(ctx.connection, params);
|
|
41
54
|
await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
|
|
42
55
|
}
|
|
43
|
-
const
|
|
44
|
-
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);
|
|
45
58
|
ctx.agent.voted.add(faction.mint);
|
|
46
59
|
ctx.agent.lastAction = `joined ${faction.symbol}`;
|
|
47
60
|
return `joined ${faction.symbol} for ${sol.toFixed(4)} SOL${ctx.decision.message ? ` — "${ctx.decision.message}"` : ''}`;
|
|
@@ -50,17 +63,7 @@ const handlers = {
|
|
|
50
63
|
const faction = findFaction(ctx.factions, ctx.decision.faction);
|
|
51
64
|
if (!faction)
|
|
52
65
|
return null;
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const mint = new web3_js_1.PublicKey(faction.mint);
|
|
56
|
-
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, new web3_js_1.PublicKey(ctx.agent.publicKey), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
57
|
-
const info = await ctx.connection.getTokenAccountBalance(ata);
|
|
58
|
-
balance = Number(info.value.amount);
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
ctx.agent.holdings.delete(faction.mint);
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
66
|
+
const balance = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
64
67
|
if (balance <= 0) {
|
|
65
68
|
ctx.agent.holdings.delete(faction.mint);
|
|
66
69
|
return null;
|
|
@@ -87,7 +90,7 @@ const handlers = {
|
|
|
87
90
|
});
|
|
88
91
|
await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
|
|
89
92
|
}
|
|
90
|
-
const remaining =
|
|
93
|
+
const remaining = await getOnChainBalance(ctx.connection, faction.mint, ctx.agent.publicKey);
|
|
91
94
|
if (remaining <= 0) {
|
|
92
95
|
ctx.agent.holdings.delete(faction.mint);
|
|
93
96
|
ctx.agent.infiltrated.delete(faction.mint);
|
|
@@ -173,8 +176,8 @@ const handlers = {
|
|
|
173
176
|
throw retryErr;
|
|
174
177
|
}
|
|
175
178
|
}
|
|
176
|
-
const
|
|
177
|
-
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);
|
|
178
181
|
ctx.agent.voted.add(faction.mint);
|
|
179
182
|
ctx.agent.lastAction = `messaged ${faction.symbol}`;
|
|
180
183
|
return `said in ${faction.symbol}: "${ctx.decision.message}"`;
|
|
@@ -190,9 +193,11 @@ const handlers = {
|
|
|
190
193
|
const faction = findFaction(ctx.factions, ctx.decision.faction);
|
|
191
194
|
if (!faction)
|
|
192
195
|
return null;
|
|
193
|
-
const balance = ctx.
|
|
194
|
-
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);
|
|
195
199
|
return null;
|
|
200
|
+
}
|
|
196
201
|
const collateral = Math.max(1, Math.floor(balance * (0.90 + Math.random() * 0.09)));
|
|
197
202
|
let borrowLamports;
|
|
198
203
|
try {
|
|
@@ -326,8 +331,8 @@ const handlers = {
|
|
|
326
331
|
const result = await (0, pyre_world_kit_1.joinFaction)(ctx.connection, params);
|
|
327
332
|
await (0, tx_1.sendAndConfirm)(ctx.connection, ctx.agent.keypair, result);
|
|
328
333
|
}
|
|
329
|
-
const
|
|
330
|
-
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);
|
|
331
336
|
ctx.agent.infiltrated.add(faction.mint);
|
|
332
337
|
ctx.agent.voted.add(faction.mint);
|
|
333
338
|
ctx.agent.sentiment.set(faction.mint, -5);
|
|
@@ -336,8 +341,14 @@ const handlers = {
|
|
|
336
341
|
},
|
|
337
342
|
async fud(ctx) {
|
|
338
343
|
const faction = findFaction(ctx.factions, ctx.decision.faction);
|
|
339
|
-
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);
|
|
340
350
|
return null;
|
|
351
|
+
}
|
|
341
352
|
await (0, stronghold_1.ensureStronghold)(ctx.connection, ctx.agent, ctx.log, ctx.strongholdOpts);
|
|
342
353
|
if (!ctx.agent.hasStronghold)
|
|
343
354
|
return null;
|
|
@@ -349,21 +360,9 @@ const handlers = {
|
|
|
349
360
|
// Fudding tanks your own sentiment — you're going bearish
|
|
350
361
|
const fudSentiment = ctx.agent.sentiment.get(faction.mint) ?? 0;
|
|
351
362
|
ctx.agent.sentiment.set(faction.mint, Math.max(-10, fudSentiment - 2));
|
|
352
|
-
// Check if fud cleared the position
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, new web3_js_1.PublicKey(ctx.agent.publicKey), false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
356
|
-
const info = await ctx.connection.getTokenAccountBalance(ata);
|
|
357
|
-
const remaining = Number(info.value.amount);
|
|
358
|
-
if (remaining <= 0) {
|
|
359
|
-
ctx.agent.holdings.delete(faction.mint);
|
|
360
|
-
ctx.agent.infiltrated.delete(faction.mint);
|
|
361
|
-
ctx.agent.lastAction = `defected ${faction.symbol}`;
|
|
362
|
-
return `fud cleared position in ${faction.symbol} → defected: "${ctx.decision.message}"`;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
catch {
|
|
366
|
-
// 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) {
|
|
367
366
|
ctx.agent.holdings.delete(faction.mint);
|
|
368
367
|
ctx.agent.infiltrated.delete(faction.mint);
|
|
369
368
|
ctx.agent.lastAction = `defected ${faction.symbol}`;
|
|
@@ -372,6 +371,20 @@ const handlers = {
|
|
|
372
371
|
ctx.agent.lastAction = `fud ${faction.symbol}`;
|
|
373
372
|
return `argued in ${faction.symbol}: "${ctx.decision.message}"`;
|
|
374
373
|
},
|
|
374
|
+
scout: async (ctx) => {
|
|
375
|
+
const target = ctx.decision.faction; // holds the address for scout
|
|
376
|
+
if (!target)
|
|
377
|
+
return null;
|
|
378
|
+
const result = await (0, agent_1.executeScout)(ctx.connection, target);
|
|
379
|
+
// Store result to show in next turn's prompt
|
|
380
|
+
const existing = agent_1.pendingScoutResults.get(ctx.agent.publicKey) ?? [];
|
|
381
|
+
existing.push(result);
|
|
382
|
+
if (existing.length > 5)
|
|
383
|
+
existing.shift();
|
|
384
|
+
agent_1.pendingScoutResults.set(ctx.agent.publicKey, existing);
|
|
385
|
+
ctx.agent.lastAction = `scouted @${target.slice(0, 8)}`;
|
|
386
|
+
return `scouted @${target.slice(0, 8)}`;
|
|
387
|
+
},
|
|
375
388
|
};
|
|
376
389
|
async function executeAction(ctx) {
|
|
377
390
|
const short = ctx.agent.publicKey.slice(0, 8);
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ export { assignPersonality, PERSONALITY_SOL, PERSONALITY_WEIGHTS, personalityDes
|
|
|
4
4
|
export { ensureStronghold } from './stronghold';
|
|
5
5
|
export { ensureRegistryProfile } from './registry';
|
|
6
6
|
export { sendAndConfirm } from './tx';
|
|
7
|
+
export { executeScout, pendingScoutResults } from './agent';
|
|
7
8
|
export { reconstructFromChain, computeWeightsFromHistory, classifyPersonality, weightsFromCounts, actionIndex } from './chain';
|
|
8
9
|
export declare function createPyreAgent(config: PyreAgentConfig): Promise<PyreAgent>;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.actionIndex = exports.weightsFromCounts = exports.classifyPersonality = exports.computeWeightsFromHistory = exports.reconstructFromChain = exports.sendAndConfirm = exports.ensureRegistryProfile = exports.ensureStronghold = exports.VOICE_NUDGES = exports.personalityDesc = exports.PERSONALITY_WEIGHTS = exports.PERSONALITY_SOL = exports.assignPersonality = void 0;
|
|
3
|
+
exports.actionIndex = exports.weightsFromCounts = exports.classifyPersonality = exports.computeWeightsFromHistory = exports.reconstructFromChain = exports.pendingScoutResults = exports.executeScout = exports.sendAndConfirm = exports.ensureRegistryProfile = exports.ensureStronghold = exports.VOICE_NUDGES = exports.personalityDesc = exports.PERSONALITY_WEIGHTS = exports.PERSONALITY_SOL = exports.assignPersonality = void 0;
|
|
4
4
|
exports.createPyreAgent = createPyreAgent;
|
|
5
5
|
const pyre_world_kit_1 = require("pyre-world-kit");
|
|
6
6
|
const defaults_1 = require("./defaults");
|
|
@@ -23,6 +23,9 @@ var registry_2 = require("./registry");
|
|
|
23
23
|
Object.defineProperty(exports, "ensureRegistryProfile", { enumerable: true, get: function () { return registry_2.ensureRegistryProfile; } });
|
|
24
24
|
var tx_1 = require("./tx");
|
|
25
25
|
Object.defineProperty(exports, "sendAndConfirm", { enumerable: true, get: function () { return tx_1.sendAndConfirm; } });
|
|
26
|
+
var agent_2 = require("./agent");
|
|
27
|
+
Object.defineProperty(exports, "executeScout", { enumerable: true, get: function () { return agent_2.executeScout; } });
|
|
28
|
+
Object.defineProperty(exports, "pendingScoutResults", { enumerable: true, get: function () { return agent_2.pendingScoutResults; } });
|
|
26
29
|
var chain_2 = require("./chain");
|
|
27
30
|
Object.defineProperty(exports, "reconstructFromChain", { enumerable: true, get: function () { return chain_2.reconstructFromChain; } });
|
|
28
31
|
Object.defineProperty(exports, "computeWeightsFromHistory", { enumerable: true, get: function () { return chain_2.computeWeightsFromHistory; } });
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Connection, Keypair } from '@solana/web3.js';
|
|
2
2
|
export type Personality = 'loyalist' | 'mercenary' | 'provocateur' | 'scout' | 'whale';
|
|
3
|
-
export type Action = 'join' | 'defect' | 'rally' | 'launch' | 'message' | 'stronghold' | 'war_loan' | 'repay_loan' | 'siege' | 'ascend' | 'raze' | 'tithe' | 'infiltrate' | 'fud';
|
|
3
|
+
export type Action = 'join' | 'defect' | 'rally' | 'launch' | 'message' | 'stronghold' | 'war_loan' | 'repay_loan' | 'siege' | 'ascend' | 'raze' | 'tithe' | 'infiltrate' | 'fud' | 'scout';
|
|
4
4
|
export interface LLMDecision {
|
|
5
5
|
action: Action;
|
|
6
6
|
faction?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pyre-agent-kit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.25",
|
|
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.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^25.4.0",
|