pyre-agent-kit 3.4.30 → 3.4.32

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.
Files changed (2) hide show
  1. package/dist/agent.js +174 -153
  2. package/package.json +1 -1
package/dist/agent.js CHANGED
@@ -10,31 +10,9 @@ const buildAgentPrompt = (kit, agent, factionCtx, intelSnippet, recentMessages,
10
10
  const [minSol, maxSol] = solRange ?? defaults_1.PERSONALITY_SOL[agent.personality];
11
11
  const gameState = kit.state.state;
12
12
  const holdingsEntries = [...(holdings?.entries() ?? [])];
13
- const symbolCounts = new Map();
14
- for (const [mint] of holdingsEntries) {
15
- const f = factionCtx.all.find((ff) => ff.mint === mint);
16
- if (f)
17
- symbolCounts.set(f.symbol, (symbolCounts.get(f.symbol) ?? 0) + 1);
18
- }
19
13
  const heldMints = new Set(holdingsEntries.map(([m]) => m));
20
- const nearby = factionCtx.nearby.filter(f => !heldMints.has(f.mint)).slice(0, 10);
21
- const nearbyMints = new Set(nearby.map(f => f.mint));
22
- const rising = factionCtx.rising.filter(f => !heldMints.has(f.mint) && !nearbyMints.has(f.mint)).slice(0, 5);
23
- const risingMints = new Set(rising.map(f => f.mint));
24
- const ascended = factionCtx.ascended.filter(f => !heldMints.has(f.mint) && !nearbyMints.has(f.mint) && !risingMints.has(f.mint)).slice(0, 5);
25
- const ascendedMints = new Set(ascended.map(f => f.mint));
26
- const ready = factionCtx.all.filter(f => f.status === 'ready' && !heldMints.has(f.mint) && !nearbyMints.has(f.mint) && !risingMints.has(f.mint) && !ascendedMints.has(f.mint));
27
- const readyMints = new Set(ready.map(f => f.mint));
28
- const seenMints = new Set([...heldMints, ...nearbyMints, ...risingMints, ...ascendedMints, ...readyMints]);
29
- const unexplored = factionCtx.all.filter(f => !seenMints.has(f.mint)).sort(() => Math.random() - 0.5).slice(0, 3);
30
- const fmtId = (f) => f.mint.slice(-8);
31
- const fmtFaction = (f) => f.market_cap_sol ? `${fmtId(f)} (${f.market_cap_sol.toFixed(2)} SOL)` : fmtId(f);
32
- const nearbyList = nearby.map(fmtFaction).join(', ') || 'none';
33
- const risingList = rising.map(fmtFaction).join(', ') || 'none';
34
- const ascendedList = ascended.map(fmtFaction).join(', ') || 'none';
35
- const readyList = ready.map(fmtFaction).join(', ') || 'none';
36
- const unexploredList = unexplored.map(fmtFaction).join(', ') || 'none';
37
- const validatedFactions = [...ascended, ...ready, ...rising, ...nearby, ...unexplored];
14
+ const foundedSet = new Set(gameState.founded);
15
+ const nearbyMints = new Set(factionCtx.nearby.map(f => f.mint));
38
16
  const TOKEN_MULTIPLIER = 1_000_000;
39
17
  let totalHoldingsValue = 0;
40
18
  const positionValues = [];
@@ -49,31 +27,57 @@ const buildAgentPrompt = (kit, agent, factionCtx, intelSnippet, recentMessages,
49
27
  positionValues.push({ label, valueSol, mint });
50
28
  }
51
29
  positionValues.sort((a, b) => b.valueSol - a.valueSol);
30
+ const pnl = (gameState.totalSolReceived - gameState.totalSolSpent) / 1e9;
31
+ const unrealizedPnl = totalHoldingsValue + pnl;
52
32
  const netInvested = (gameState.totalSolSpent - gameState.totalSolReceived) / 1e9;
53
33
  const totalTokens = holdingsEntries.reduce((sum, [, bal]) => sum + bal, 0);
54
- const holdingsList = positionValues
55
- .map(({ label, valueSol, mint }) => {
56
- const bal = holdings?.get(mint) ?? 0;
34
+ const statusTag = (f) => {
35
+ if (f.status === 'ascended')
36
+ return 'ASN';
37
+ if (f.status === 'ready')
38
+ return 'RD';
39
+ return 'RS';
40
+ };
41
+ // Build flat faction table rows
42
+ const factionRows = [];
43
+ const seenMints = new Set();
44
+ // MBR factions first
45
+ for (const pv of positionValues) {
46
+ const f = factionCtx.all.find(ff => ff.mint === pv.mint);
47
+ if (!f)
48
+ continue;
49
+ seenMints.add(f.mint);
50
+ const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
51
+ const fnr = foundedSet.has(f.mint);
52
+ const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
53
+ const loan = gameState.activeLoans.has(f.mint);
54
+ const bal = holdings?.get(f.mint) ?? 0;
55
+ let pnlStr = '?';
57
56
  if (totalTokens > 0 && netInvested > 0) {
58
57
  const estCost = netInvested * (bal / totalTokens);
59
- const positionPnl = valueSol - estCost;
60
- return `${label}: ${valueSol.toFixed(4)} SOL (${positionPnl >= 0 ? '+' : ''}${positionPnl.toFixed(4)})`;
58
+ const posPnl = pv.valueSol - estCost;
59
+ pnlStr = `${posPnl >= 0 ? '+' : ''}${posPnl.toFixed(4)}`;
61
60
  }
62
- return `${label}: ${valueSol.toFixed(4)} SOL`;
63
- })
64
- .join(', ') || 'none';
65
- const pnl = (gameState.totalSolReceived - gameState.totalSolSpent) / 1e9;
66
- const unrealizedPnl = totalHoldingsValue + pnl;
67
- const sentimentList = [...kit.state.sentimentMap]
68
- .map(([mint, score]) => {
69
- const f = factionCtx.all.find((ff) => ff.mint === mint);
70
- const label = score > 3 ? 'bullish' : score < -3 ? 'bearish' : 'neutral';
71
- return f ? `${f.mint.slice(-8)}: ${label} (${score > 0 ? '+' : ''}${score})` : null;
72
- })
73
- .filter(Boolean)
74
- .join(', ') || 'no strong feelings yet';
75
- const allyList = agent.allies.size > 0 ? [...agent.allies].slice(0, 5).map((a) => `@${a.slice(0, 8)}`).join(', ') : 'none';
76
- const rivalList = agent.rivals.size > 0 ? [...agent.rivals].slice(0, 5).map((a) => `@${a.slice(0, 8)}`).join(', ') : 'none';
61
+ factionRows.push(`${f.mint.slice(-8)} | ${mcap} | ${statusTag(f)} | true | ${fnr} | ${pv.valueSol.toFixed(4)} | ${pnlStr} | ${sent > 0 ? '+' : ''}${sent}${loan ? ' | LOAN' : ''}`);
62
+ }
63
+ // Non-member factions
64
+ const nonMember = factionCtx.all.filter(f => !seenMints.has(f.mint) && f.status !== 'razed');
65
+ const nearby = nonMember.filter(f => nearbyMints.has(f.mint)).slice(0, 10);
66
+ const rest = nonMember.filter(f => !nearbyMints.has(f.mint));
67
+ const rising = rest.filter(f => f.status === 'rising').slice(0, 5);
68
+ const ascended = rest.filter(f => f.status === 'ascended').slice(0, 5);
69
+ const ready = rest.filter(f => f.status === 'ready');
70
+ const shown = new Set([...nearby, ...rising, ...ascended, ...ready].map(f => f.mint));
71
+ const unexplored = rest.filter(f => !shown.has(f.mint)).sort(() => Math.random() - 0.5).slice(0, 3);
72
+ for (const f of [...nearby, ...ascended, ...ready, ...rising, ...unexplored]) {
73
+ if (seenMints.has(f.mint))
74
+ continue;
75
+ seenMints.add(f.mint);
76
+ const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
77
+ const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
78
+ factionRows.push(`${f.mint.slice(-8)} | ${mcap} | ${statusTag(f)} | false | false | 0 | 0 | ${sent > 0 ? '+' : ''}${sent}`);
79
+ }
80
+ const validatedFactions = [...ascended, ...ready, ...rising, ...nearby, ...unexplored];
77
81
  const doNotRepeat = recentMessages.length > 0
78
82
  ? `\nDO NOT REPEAT OR PARAPHRASE:\n${recentMessages.slice(0, 5).map((m) => `- "${m}"`).join('\n')}\n`
79
83
  : '';
@@ -82,91 +86,83 @@ const buildAgentPrompt = (kit, agent, factionCtx, intelSnippet, recentMessages,
82
86
  ? memoryEntries.slice(0, 7).map((m) => `- ${m}`).join('; ')
83
87
  : 'none';
84
88
  const mMint = [...heldMints][0] || (validatedFactions.length > 0 ? (0, util_1.pick)(validatedFactions).mint : null);
85
- const m = mMint ? mMint.slice(-8) : 'xxxxxx pw';
89
+ const m = mMint ? mMint.slice(-8) : 'xxxxxxpw';
86
90
  const f1Mint = validatedFactions.length > 0 ? (0, util_1.pick)(validatedFactions) : null;
87
91
  const f1 = f1Mint ? f1Mint.mint.slice(-8) : m;
88
92
  const f2Mint = validatedFactions.length > 1 ? (0, util_1.pick)(validatedFactions.filter(f => f.mint !== f1Mint?.mint)) : f1Mint;
89
93
  const f2 = f2Mint ? f2Mint.mint.slice(-8) : f1;
90
- return `You are an autonomous agent playing Pyre, a faction warfare game.
94
+ return `You are an autonomous agent playing in Pyre, a faction warfare game. Think in English only. Think linearly: situation → decision → reason. Do not repeat yourself. Do NOT overthink, chess/strategy mood.
91
95
  --- GOAL:
92
96
  Maximize long-term profit and faction dominance.
93
- --- INFO:
94
- Factions are rival guilds, with treasuries, members, and culture. Factions with larger SOL value have more power.
95
- Lifecycle: launch rising ready vote → ascended
96
- Rising Factions:
97
- - 0.5% realm fee + treasury contribution (starts ~12.5%, decays to ~4% as the faction grows).
98
- - Initial vote on joining: 90% goes to your position and 10% seeds the treasury. After that, 100% goes to your position.
99
- - Early actions contribute more to the treasury. Later actions contribute less.
100
- Ascended Factions:
101
- - Treasuries are active: TITHE harvests fees, WAR_LOAN borrows against holdings, SIEGE liquidates bad loans.
102
- - 0.04% war tax on every transaction — harvestable into the treasury for lending.
103
- --- GAMESTATE:
97
+ --- LEGEND:
98
+ RS - rising factions, new. 0.5% realm tax. early moves contribute more to treasury.
99
+ RD - ready factions, transition from rising to ascended. 0.04% war tax.
100
+ ASN - ascended factions, established. treasuries active: (~) harvests fees, (?) borrows, (>) liquidates.
101
+ FNR - factions you created/founded.
102
+ MBR - factions you are a member of/hold a position in.
103
+ AL - ally agents, prefixed with @AP
104
+ RVL - rival agents, prefixed with @AP
105
+ LOAN - you have an active loan against this faction.
106
+ --- YOU ARE:
104
107
  NAME: @AP${agent.publicKey.slice(0, 4)}
105
- PERSONALITY: ${gameState.personalitySummary ?? defaults_1.personalityDesc[agent.personality]}
108
+ BIO: ${gameState.personalitySummary ?? defaults_1.personalityDesc[agent.personality]}
106
109
  MEMORIES: ${memoryBlock}
107
- VALUE: ${totalHoldingsValue.toFixed(4)} SOL | Realized P&L: ${pnl >= 0 ? '+' : ''}${pnl.toFixed(4)} SOL | Unrealized: ${unrealizedPnl >= 0 ? '+' : ''}${unrealizedPnl.toFixed(4)} SOL
110
+ P&L: ${pnl >= 0 ? '+' : ''}${pnl.toFixed(4)} SOL | VALUE: ${totalHoldingsValue.toFixed(4)} SOL | UNREALIZED: ${unrealizedPnl >= 0 ? '+' : ''}${unrealizedPnl.toFixed(4)} SOL
108
111
  SPEND RANGE: ${minSol}–${maxSol} SOL
109
- FOUNDED: ${gameState.founded.length > 0 ? `${gameState.founded.map((m) => m.slice(-8)).join(', ')}promote these aggressively` : 'none'}
110
- MEMBER OF: ${holdingsList}
111
- SENTIMENT: ${sentimentList}
112
- ${positionValues.length > 0 ? `BEST FACTION: ${positionValues.sort((a, b) => b.valueSol - a.valueSol)[0].label} (${positionValues.sort((a, b) => b.valueSol - a.valueSol)[0].valueSol.toFixed(4)} SOL)` : ''}
113
- ACTIVE LOANS: ${gameState.activeLoans.size > 0 ? `${[...gameState.activeLoans].map((m) => m.slice(-8)).join(', ')}` : 'none'}
114
- ${unrealizedPnl > 0.1 ? 'You are UP. Consider taking profits on your biggest winners with DEFECT.' : unrealizedPnl < -0.05 ? 'You are DOWN. Be conservative. Cut losers with DEFECT. Smaller positions.' : 'Near breakeven. Look for conviction plays.'}
112
+ ${unrealizedPnl > 0.1 ? 'STATUS: UP — consider taking profits with (-) on winners.' : unrealizedPnl < -0.05 ? 'STATUS: DOWN — be conservative. Cut losers with (-). Smaller positions.' : 'STATUS: BREAKEVEN look for conviction plays.'}
115
113
  --- INTEL:
116
- ALLIES: ${allyList}
117
- RIVALS: ${rivalList}
114
+ AL: ${agent.allies.size > 0 ? [...agent.allies].slice(0, 5).map((a) => `@AP${a.slice(0, 4)}`).join(', ') : 'none'}
115
+ RVL: ${agent.rivals.size > 0 ? [...agent.rivals].slice(0, 5).map((a) => `@AP${a.slice(0, 4)}`).join(', ') : 'none'}
118
116
  LATEST: ${intelSnippet}
119
117
  --- FACTIONS:
120
- ASCENDED: ${ascendedList}
121
- READY: ${readyList}
122
- RISING: ${risingList}
123
- NEARBY: ${nearbyList}
124
- UNEXPLORED: ${unexploredList}
118
+ FID | MCAP | STATUS | MBR | FNR | VALUE | PNL | SENT
119
+ ${factionRows.length > 0 ? factionRows.join('\n') : 'none'}
125
120
  --- ACTIONS:
126
- JOIN $ "*" join a faction.
127
- DEFECT $ "*" leave or downsize a faction.
128
- REINFORCE $ "*" increase size in a faction, you are bullish.
129
- INFILTRATE $ "*" join a rival to defect later.
130
- MESSAGE $ "*" talk in faction comms.
131
- FUD $ "*" trash talk in a faction.
132
- SCOUT @address look up an agent.
133
- ASCEND $ promote a ready faction (ready factions only).
134
- RALLY $ show support, one-time per faction.
135
- RAZE $ reclaim an inactive faction.
136
- WAR_LOAN $ borrow against your size in a faction (ascended factions only).
137
- REPAY_LOAN $ repay a loan (ascended factions only).
138
- SIEGE $ liquidate a bad loan (ascended factions only).
139
- TITHE $ harvest fees into the treasury to grow the faction economy (ascended factions only).
140
- LAUNCH "name" create a new faction. name should be original, be creative. wrap name in double quotes always.
141
- - REPLACE $ with exactly ONE faction from ASCENDED, RISING, READY, NEARBY, UNEXPLORED, or MEMBER OF (always contains the pw suffix).
142
- - REPLACE * with what you have to say about your action, always in double quotes, if available on the action. optional but recommended.
143
- EXAMPLE: JOIN ${f1} "${(0, util_1.pick)(['rising fast and I want early exposure.', 'count me in.', 'early is everything.', 'strongest faction here.', 'lets go!'])}"
144
- EXAMPLE: DEFECT ${m} "${(0, util_1.pick)(['taking profits.', 'time to move on.', 'sentiment is bearish, ready to cut losses.'])}"
145
- EXAMPLE: REINFORCE ${m} "${(0, util_1.pick)(['doubling down.', 'conviction play.', 'added more.'])}"
146
- EXAMPLE: INFILTRATE ${f2} "${(0, util_1.pick)(['just looking around.', 'checking the vibes.', 'scouting.', 'sneaking in, opportunity here.'])}"
147
- EXAMPLE: ASCEND ${m}
148
- EXAMPLE: TITHE ${m}
149
- EXAMPLE: MESSAGE ${m} "${(0, util_1.pick)(['love the energy. any strategies?', 'who else is here?', 'just getting started.', 'not leaving.'])}"
150
- EXAMPLE: FUD ${m} "${(0, util_1.pick)(['founders went quiet.', 'dead faction.', 'overvalued.', 'this faction is underperforming.'])}"
121
+ (+) $ "*" - join a faction.
122
+ (-) $ "*" - leave or decrease position in a faction.
123
+ (!) $ "*" - sneak into a faction.
124
+ (&) $ "*" - fortify position in a faction.
125
+ (=) $ "*" - talk in faction comms.
126
+ (#) $ "*" - trash talk a faction.
127
+ (@) @address - look up an agent.
128
+ (^) $ - ascend a faction.
129
+ (.) $ - show support, one-time per faction.
130
+ (?) $ - borrow against holdings.
131
+ (<) $ - repay a loan.
132
+ (>) $ - liquidate a bad loan.
133
+ (~) $ - harvest fees into treasury.
134
+ (%) ";" - create a faction. ; = creative name in double quotes.
135
+ - REPLACE $ with a FID from the table (always ends in pw).
136
+ - REPLACE * with your message, always in double quotes.
151
137
  --- VOICE:
152
- - Your personality is your tone.
153
- - First person only. Be specific when speaking with other agents from ALLIES, RIVALS, and INTEL using @address (format is @address, e.g. @${Math.random().toString(36).slice(2, 10)}).
154
- - What you say MUST match the intent of action you are taking.
155
- - Write something original and unique every time. Talk TO agents, not about them.
156
- - Be concise. Under 80 chars, plain English, one sentence. No hashtags, no angle brackets.
157
- - Back up your claims with real numbers from your actions, p&l, and sentiment. Never generic.
158
- - Your message should reflect YOUR faction.${doNotRepeat}
138
+ - Your personality is your tone. First person only.
139
+ - Talk TO agents using @AP inside your "*" response, not about them.
140
+ - What you say MUST match the intent of your action.
141
+ - Under 80 chars, plain English, one sentence. No hashtags, no angle brackets.
142
+ - Back up claims with real numbers from P&L, VALUE, SENT. Never generic.${doNotRepeat}
159
143
  --- STRATEGY:
160
- - Limit to being a member of ~5 faction. MESSAGE/FUD in others is fine but factions you are in focused.${positionValues.length > 5 ? ` You are a member of ${positionValues.length} factions — consider DEFECT from your weakest.` : ''}
161
- - MESSAGE/FUD cost almost nothing but move sentiment and help you coordinate with other agents — use them.
162
- - Collaborate and coordinate with other agents to push factions. Working together can help you profit together. You need to coordinate to push RISING factions to ASCENDED.
163
- - If you FOUNDED a faction, consider JOIN and promote it.
164
- - REINFORCE factions you believe in. Don't JOIN the same faction twice.
165
- - DEFECT to lock in profits or cut losses. Don't stay in losers. You can ONLY DEFECT or FUD factions you are a member of.
166
- - Your holdings ARE your identity. Promote what you hold. Attack what you don't.${factionCtx.all.length <= 2 ? '\n- Few factions active — consider LAUNCH.' : ''}
144
+ - Factions with STATUS ASN are lower risk. RS factions have higher reward if you pick right.
145
+ - To (&), (-) or (#), the faction MBR MUST be true.
146
+ - To (^), STATUS must be RD. To (?), (>), (~), STATUS must be ASN.
147
+ - To (<), LOAN must exist on the faction.
148
+ - If FNR is true, you founded it. (+) if MBR is false, (&) if MBR is true, promote with (=).
149
+ - Limit factions where MBR is true to AT MOST 5.${positionValues.length > 5 ? ` MBR at ${positionValues.length} CONSIDER (-) from underperformers.` : ''}
150
+ - (=)/(#) move sentiment. Use (=) to promote winners, (#) to fud losers.
151
+ - (-) to lock in profits or cut losers. Don't stay in underperformers.
152
+ - Coordinate with AL agents to push RS factions toward ASN.
153
+ - Your holdings ARE your identity. Promote what you hold. Attack what you don't.${factionCtx.all.length <= 2 ? '\n- Few factions active — consider (%).' : ''}
167
154
  ---
168
- ONLY output exactly ONE action line. Do NOT explain step by step. Do not list multiple moves or combine actions. ONE move per turn.
169
- YOUR MOVE:`;
155
+ EXAMPLE: (+) ${f1} "${(0, util_1.pick)(['rising fast and I want early exposure.', 'count me in.', 'early is everything.', 'strongest faction here.', 'lets go!'])}"
156
+ EXAMPLE: (-) ${m} "${(0, util_1.pick)(['taking profits.', 'time to move on.', 'sentiment is bearish, ready to cut losses.'])}"
157
+ EXAMPLE: (&) ${m} "${(0, util_1.pick)(['doubling down.', 'conviction play.', 'added more.'])}"
158
+ EXAMPLE: (!) ${f2} "${(0, util_1.pick)(['just looking around.', 'checking the vibes.', 'scouting.', 'sneaking in, opportunity here.'])}"
159
+ EXAMPLE: (^) ${m}
160
+ EXAMPLE: (~) ${m}
161
+ EXAMPLE: (=) ${m} "${(0, util_1.pick)(['love the energy. any strategies?', 'who else is here?', 'just getting started.', 'not leaving.'])}"
162
+ EXAMPLE: (#) ${m} "${(0, util_1.pick)(['founders went quiet.', 'dead faction.', 'overvalued.', 'this faction is underperforming.'])}"
163
+ ---
164
+ Output EXACTLY one line: (symbol) $ "*"
165
+ >`;
170
166
  };
171
167
  exports.buildAgentPrompt = buildAgentPrompt;
172
168
  const buildCompactModelPrompt = (kit, agent, factionCtx, intelSnippet, recentMessages, solRange, holdings) => {
@@ -198,16 +194,53 @@ const buildCompactModelPrompt = (kit, agent, factionCtx, intelSnippet, recentMes
198
194
  })
199
195
  .filter(Boolean)
200
196
  .join(', ') || 'none';
201
- const nearby = factionCtx.nearby.filter(f => !heldMints.has(f.mint)).slice(0, 2);
202
- const nearbyMints = new Set(nearby.map(f => f.mint));
203
- const rising = factionCtx.rising.filter(f => !heldMints.has(f.mint) && !nearbyMints.has(f.mint)).slice(0, 2);
204
- const risingMints = new Set(rising.map(f => f.mint));
205
- const ascended = factionCtx.ascended.filter(f => !heldMints.has(f.mint) && !nearbyMints.has(f.mint) && !risingMints.has(f.mint)).slice(0, 2);
206
- const ascendedMints = new Set(ascended.map(f => f.mint));
207
- const ready = factionCtx.all.filter(f => f.status === 'ready' && !heldMints.has(f.mint) && !nearbyMints.has(f.mint) && !risingMints.has(f.mint) && !ascendedMints.has(f.mint));
208
- const readyMints = new Set(ready.map(f => f.mint));
209
- const seenMints = new Set([...heldMints, ...nearbyMints, ...risingMints, ...ascendedMints, ...readyMints]);
210
- const unexplored = factionCtx.all.filter(f => !seenMints.has(f.mint)).sort(() => Math.random() - 0.5).slice(0, 3);
197
+ const foundedSet = new Set(gameState.founded);
198
+ const nearbyMints = new Set(factionCtx.nearby.map(f => f.mint));
199
+ // Status tag for each faction
200
+ const statusTag = (f) => {
201
+ if (f.status === 'ascended')
202
+ return 'ASN';
203
+ if (f.status === 'ready')
204
+ return 'RD';
205
+ return 'RS';
206
+ };
207
+ // Discovery tag
208
+ const discoveryTag = (f) => {
209
+ if (nearbyMints.has(f.mint))
210
+ return 'NB';
211
+ return 'UX';
212
+ };
213
+ // Build flat faction rows: FACTION (MCAP) STATUS MBR FNR [NB|UX]
214
+ const factionRows = [];
215
+ const seenMints = new Set();
216
+ // MBR factions first (most important to the agent)
217
+ for (const v of valued.slice(0, 5)) {
218
+ const f = factionCtx.all.find(ff => ff.mint.slice(-8) === v.id);
219
+ if (!f)
220
+ continue;
221
+ seenMints.add(f.mint);
222
+ const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
223
+ const fnr = foundedSet.has(f.mint);
224
+ const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
225
+ factionRows.push(`${f.mint.slice(-8)} | ${mcap} | ${statusTag(f)} | true | ${fnr} | ${v.valueSol.toFixed(4)} | ${sent > 0 ? '+' : ''}${sent}`);
226
+ }
227
+ // Non-member factions
228
+ const nonMember = factionCtx.all.filter(f => !seenMints.has(f.mint) && f.status !== 'razed');
229
+ const nearby = nonMember.filter(f => nearbyMints.has(f.mint)).slice(0, 2);
230
+ const rest = nonMember.filter(f => !nearbyMints.has(f.mint));
231
+ const rising = rest.filter(f => f.status === 'rising').slice(0, 2);
232
+ const ascended = rest.filter(f => f.status === 'ascended').slice(0, 2);
233
+ const ready = rest.filter(f => f.status === 'ready').slice(0, 2);
234
+ const shown = new Set([...nearby, ...rising, ...ascended, ...ready].map(f => f.mint));
235
+ const unexplored = rest.filter(f => !shown.has(f.mint)).sort(() => Math.random() - 0.5).slice(0, 3);
236
+ for (const f of [...nearby, ...ascended, ...ready, ...rising, ...unexplored]) {
237
+ if (seenMints.has(f.mint))
238
+ continue;
239
+ seenMints.add(f.mint);
240
+ const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
241
+ const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
242
+ factionRows.push(`${f.mint.slice(-8)} | ${mcap} | ${statusTag(f)} | false | false | 0 | ${sent > 0 ? '+' : ''}${sent}`);
243
+ }
211
244
  const validatedFactions = [...ascended, ...ready, ...rising, ...nearby, ...unexplored];
212
245
  const mMint2 = [...heldMints][0] || (validatedFactions.length > 0 ? (0, util_1.pick)(validatedFactions).mint : null);
213
246
  const m = mMint2 ? mMint2.slice(-8) : 'xxxxxxpw';
@@ -218,37 +251,24 @@ const buildCompactModelPrompt = (kit, agent, factionCtx, intelSnippet, recentMes
218
251
  return `You are an autonomous agent playing in Pyre, a faction warfare game. Think in English only. Think linearly: situation → decision → reason. Do not repeat yourself. Do NOT overthink, chess/strategy mood.
219
252
  --- GOAL:
220
253
  Maximize long-term profit and faction dominance.
221
- --- INFO:
222
- Factions are rival guilds, with treasuries, members, and culture. Factions with larger SOL value have more power.
223
- Faction Lifecycle: RS RD V ASN
224
- RS - rising factions, new. 0.5% realm tax. early moves contribute more to the treasury, later moves contribute less.
225
- RD - ready factions, transition from rising to ascended.
226
- ASN - ascended factions, established. 0.04% war tax on every transaction, harvestable into the treasury.
227
- NB - nearby factions found through social graph using breadth first search.
228
- UX - unexplored factions. you have not seen these.
229
- FNR - factions you created/founded.
230
- MBR - factions you are a member of/hold a position in.
231
- AL - ally. these are other agents you befriend, prefixed with @AP
232
- RVL - rival. these are other agents that are enemies, prefixed with @AP
254
+ --- LEGEND:
255
+ Factions are rival guilds with treasuries. Higher MCAP = more power. Lifecycle: RS RD ASN.
256
+ STATUS: RS (rising, 0.5% tax, early = more treasury) | RD (ready, transition) | ASN (ascended, 0.04% war tax)
257
+ MBR: true = you hold a position. FNR: true = you founded it.
258
+ SENT: sentiment score. positive = bullish, negative = bearish.
259
+ AL/RVL: ally/rival agents, prefixed @AP.
233
260
  --- YOU ARE:
234
261
  NAME: @AP${agent.publicKey.slice(0, 4)}
235
262
  BIO: ${gameState.personalitySummary ?? defaults_1.personalityDesc[agent.personality]}
236
263
  LAST MOVES: ${kit.state.history.length > 0 ? [...kit.state.history].slice(-2).join('; ') : 'none'}
237
264
  P&L: ${pnl >= 0 ? '+' : ''}${pnl.toFixed(4)} SOL
238
- FNR: ${founded.length > 0 ? founded.join(', ') : 'none'}
239
- MBR: ${memberOf.length > 0 ? memberOf.join(', ') : 'none'}
240
- MBR VALUE: ${valued.length > 0 ? valued.map(v => `${v.id}: ${v.valueSol.toFixed(4)} SOL`).join(', ') : 'no value'}
241
- SENTIMENT: ${sentimentList}
242
265
  --- INTEL:
243
266
  AL: ${agent.allies.size > 0 ? [...agent.allies].slice(0, 2).map(a => `@AP${a.slice(0, 4)}`).join(', ') : 'none'}
244
267
  RVL: ${agent.rivals.size > 0 ? [...agent.rivals].slice(0, 2).map(a => `@AP${a.slice(0, 4)}`).join(', ') : 'none'}
245
268
  LATEST: ${intelSnippet}
246
269
  --- FACTIONS:
247
- ASN: ${ascended.length > 0 ? ascended.map(f => f.market_cap_sol ? `${f.mint.slice(-8)} (${f.market_cap_sol.toFixed(2)} SOL)` : f.mint.slice(-8)).join(', ') : 'none'}
248
- RS: ${rising.length > 0 ? rising.map(f => f.market_cap_sol ? `${f.mint.slice(-8)} (${f.market_cap_sol.toFixed(2)} SOL)` : f.mint.slice(-8)).join(', ') : 'none'}
249
- RD: ${ready.length > 0 ? ready.map(f => f.market_cap_sol ? `${f.mint.slice(-8)} (${f.market_cap_sol.toFixed(2)} SOL)` : f.mint.slice(-8)).join(', ') : 'none'}
250
- NB: ${nearby.length > 0 ? nearby.map(f => f.market_cap_sol ? `${f.mint.slice(-8)} (${f.market_cap_sol.toFixed(2)} SOL)` : f.mint.slice(-8)).join(', ') : 'none'}
251
- UX: ${unexplored.length > 0 ? unexplored.map(f => f.market_cap_sol ? `${f.mint.slice(-8)} (${f.market_cap_sol.toFixed(2)} SOL)` : f.mint.slice(-8)).join(', ') : 'none'}
270
+ FID | MCAP | STATUS | MBR | FNR | VALUE | SENT
271
+ ${factionRows.length > 0 ? factionRows.join('\n') : 'none'}
252
272
  --- ACTIONS:
253
273
  (+) $ "*" - join a faction.
254
274
  (-) $ "*" - leave or decrease position in a faction.
@@ -256,21 +276,22 @@ UX: ${unexplored.length > 0 ? unexplored.map(f => f.market_cap_sol ? `${f.mint.s
256
276
  (&) $ "*" - fortify position in a faction.
257
277
  (=) $ "*" - talk in faction comms.
258
278
  (#) $ "*" - trash talk a faction.
259
- (^) $ - transition a faction from ready to ascended.
260
- (~) $ - harvest fees into the treasury.
279
+ (^) $ - ascend a faction.
280
+ (~) $ - harvest fees into treasury.
261
281
  (%) ";" - create a faction.
262
- - REPLACE $ with exactly ONE choice from ASN, RS, RD, NB, UX, FNR, or MBR (always contains the pw suffix).
282
+ - REPLACE $ with exactly ONE choice from FACTIONS using the FID column (always contains the pw suffix).
263
283
  - REPLACE * with a ONE sentence RESPONSE for your ACTION, always in double quotes.
264
284
  - REPLACE ; with a unique faction inspired name (eg. "Glitch Cult", "Whale Syndicate"), always in double quotes. only for (%).
265
285
  --- STRATEGY:
266
286
  - Your personality is your tone.
267
- - $ is ALWAYS a faction (ends in pw), NEVER an @AP agent. To talk to agents, put @AP inside your "*" response.
287
+ - $ is ALWAYS a faction FID (ends in pw), NEVER an @AP agent. To talk to agents, put @AP inside your "*" response.
268
288
  - In your RESPONSE, you can mention other agents from AL, RVL, and LATEST (format is @AP + 4 chars, e.g. @AP${Math.random().toString(36).slice(2, 6)}), if NOT none.
269
- - To (&), (-) or (#), the faction must come from MBR.
270
- - To (^) a faction it MUST be from RD.
271
- - ASN, RS, RD, NB, UX, MBR, FNR all none? Use (%) to create one. Anyone can (%).
272
- - If FNR contains factions, you founded them. (+), (&) and promote them with (=).
273
- - Limit MBR to AT MOST 5 factions.${memberOf.length > 3 ? ` MBR at ${memberOf.length} factions CONSIDER (-) from underperformers.` : ''}
289
+ - Factions with STATUS ASN are lower risk and established, but RS factions may have higher reward if you pick the right one.
290
+ - To (&), (-) or (#), the faction MBR MUST be true.
291
+ - To (^) a faction, STATUS must be RD.
292
+ - no factions? Use (%) to create one. Anyone can (%).
293
+ - If FNR is true on a faction, you founded it. (+) if MBR is false, (&) if MBR is true and promote them with (=).
294
+ - Limit factions where MBR is true to AT MOST 5 factions.${memberOf.length > 3 ? ` MBR at ${memberOf.length} factions — CONSIDER (-) from underperformers.` : ''}
274
295
  - Promote factions you are in. Attack your rival factions.
275
296
  - (=)/(#) move sentiment and help coordinate with other agents — use (=) to promote your winners and (#) to fud your losers.
276
297
  - (-) to lock in profits or downsize on underperforming factions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pyre-agent-kit",
3
- "version": "3.4.30",
3
+ "version": "3.4.32",
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",