pyre-agent-kit 4.3.11 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +2 -2
- package/dist/agent.js +83 -94
- package/package.json +1 -1
package/dist/agent.d.ts
CHANGED
|
@@ -11,6 +11,6 @@ export interface FactionContext {
|
|
|
11
11
|
nearby: FactionInfo[];
|
|
12
12
|
all: FactionInfo[];
|
|
13
13
|
}
|
|
14
|
-
export declare const buildAgentPrompt: (kit: PyreKit, agent: AgentState, factionCtx: FactionContext,
|
|
15
|
-
export declare const buildCompactModelPrompt: (kit: PyreKit, agent: AgentState, factionCtx: FactionContext,
|
|
14
|
+
export declare const buildAgentPrompt: (kit: PyreKit, agent: AgentState, factionCtx: FactionContext, recentMessages: string[], solRange?: [number, number], holdings?: Map<string, number>) => Promise<string>;
|
|
15
|
+
export declare const buildCompactModelPrompt: (kit: PyreKit, agent: AgentState, factionCtx: FactionContext, recentMessages: string[], solRange?: [number, number], holdings?: Map<string, number>) => Promise<string>;
|
|
16
16
|
export declare function llmDecide(kit: PyreKit, agent: AgentState, factions: FactionInfo[], recentMessages: string[], llm: LLMAdapter, log: (msg: string) => void, solRange?: [number, number], options?: LLMDecideOptions): Promise<LLMDecision | null>;
|
package/dist/agent.js
CHANGED
|
@@ -6,7 +6,7 @@ const defaults_1 = require("./defaults");
|
|
|
6
6
|
const util_1 = require("./util");
|
|
7
7
|
const faction_1 = require("./faction");
|
|
8
8
|
exports.pendingScoutResults = new Map();
|
|
9
|
-
const buildAgentPrompt = (kit, agent, factionCtx,
|
|
9
|
+
const buildAgentPrompt = async (kit, agent, factionCtx, recentMessages, solRange, holdings) => {
|
|
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() ?? [])];
|
|
@@ -47,8 +47,8 @@ const buildAgentPrompt = (kit, agent, factionCtx, intelSnippet, recentMessages,
|
|
|
47
47
|
// Build flat faction table rows
|
|
48
48
|
const factionRows = [];
|
|
49
49
|
const seenMints = new Set();
|
|
50
|
-
// MBR factions first
|
|
51
|
-
for (const pv of positionValues) {
|
|
50
|
+
// MBR factions first (cap at 10)
|
|
51
|
+
for (const pv of positionValues.slice(0, 10)) {
|
|
52
52
|
const f = factionCtx.all.find(ff => ff.mint === pv.mint);
|
|
53
53
|
if (!f)
|
|
54
54
|
continue;
|
|
@@ -75,18 +75,50 @@ const buildAgentPrompt = (kit, agent, factionCtx, intelSnippet, recentMessages,
|
|
|
75
75
|
const ready = rest.filter(f => f.status === 'ready');
|
|
76
76
|
const shown = new Set([...nearby, ...rising, ...ascended, ...ready].map(f => f.mint));
|
|
77
77
|
const unexplored = rest.filter(f => !shown.has(f.mint)).sort(() => Math.random() - 0.5).slice(0, 3);
|
|
78
|
+
let nonMemberCount = 0;
|
|
78
79
|
for (const f of [...nearby, ...ascended, ...ready, ...rising, ...unexplored]) {
|
|
80
|
+
if (nonMemberCount >= 10)
|
|
81
|
+
break;
|
|
79
82
|
if (seenMints.has(f.mint))
|
|
80
83
|
continue;
|
|
81
84
|
seenMints.add(f.mint);
|
|
82
85
|
const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
|
|
83
86
|
const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
|
|
84
87
|
factionRows.push(`${f.mint.slice(-8)},${mcap},${statusTag(f)},false,false,0,0,${sent > 0 ? '+' : ''}${Math.round(sent * 10) / 10},false`);
|
|
88
|
+
nonMemberCount++;
|
|
85
89
|
}
|
|
86
90
|
const validatedFactions = [...ascended, ...ready, ...rising, ...nearby, ...unexplored];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
// Fetch intel from table factions only — no off-screen FIDs
|
|
92
|
+
let intelSnippet = '';
|
|
93
|
+
try {
|
|
94
|
+
const tableMemberMints = [...seenMints].filter(mint => heldMints.has(mint)).slice(0, 2);
|
|
95
|
+
const tableNonMemberMints = [...seenMints].filter(mint => !heldMints.has(mint));
|
|
96
|
+
const toScout = [
|
|
97
|
+
...tableMemberMints.map(mint => factionCtx.all.find((f) => f.mint === mint)).filter(Boolean),
|
|
98
|
+
...(tableNonMemberMints.length > 0 ? [factionCtx.all.find((f) => f.mint === (0, util_1.pick)(tableNonMemberMints))].filter(Boolean) : []),
|
|
99
|
+
];
|
|
100
|
+
if (toScout.length > 0) {
|
|
101
|
+
const intels = await Promise.all(toScout.map(f => (0, faction_1.fetchFactionIntel)(kit, f)));
|
|
102
|
+
const lines = intels.map((intel, i) => {
|
|
103
|
+
const fid = toScout[i].mint.slice(-8);
|
|
104
|
+
const memberInfo = intel.totalMembers > 0
|
|
105
|
+
? `${intel.totalMembers} members, top holder: ${intel.members[0]?.percentage.toFixed(1)}%`
|
|
106
|
+
: 'no members';
|
|
107
|
+
const commsInfo = intel.recentComms.length > 0
|
|
108
|
+
? intel.recentComms.slice(0, 3).map(c => `@AP${c.sender.slice(0, 4)} said: "${c.memo.replace(/^<+/, '').replace(/>+\s*$/, '')}"`).join(', ')
|
|
109
|
+
: 'no recent comms';
|
|
110
|
+
return ` [${fid}] ${memberInfo} | recent comms: ${commsInfo}`;
|
|
111
|
+
});
|
|
112
|
+
intelSnippet = 'FACTION INTEL:\n' + lines.join('\n');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch { }
|
|
116
|
+
// Include results from previous SCOUT actions
|
|
117
|
+
const scoutResults = exports.pendingScoutResults.get(agent.publicKey);
|
|
118
|
+
if (scoutResults && scoutResults.length > 0) {
|
|
119
|
+
intelSnippet += '\nSCOUT RESULTS (from your previous SCOUT actions):\n' + scoutResults.join('\n');
|
|
120
|
+
exports.pendingScoutResults.delete(agent.publicKey);
|
|
121
|
+
}
|
|
90
122
|
const memoryEntries = [...kit.state.history].slice(-20);
|
|
91
123
|
const memoryBlock = memoryEntries.length > 0
|
|
92
124
|
? memoryEntries.slice(0, 7).map((m) => `- ${m}`).join('; ')
|
|
@@ -145,6 +177,8 @@ REPLACE * with a ONE sentence RESPONSE, always in double quotes.
|
|
|
145
177
|
(%) "..." - create new faction. "..." = creative name, in quotes.
|
|
146
178
|
(_) - skip turn.
|
|
147
179
|
--- RULES:
|
|
180
|
+
(+), (&) and (/) increase MCAP. (-) decreases MCAP.
|
|
181
|
+
(!) and (#) are your voice. (!) increases SENT. (#) decreases SENT.
|
|
148
182
|
(+) or (/) FACTIONS where MBR=false.
|
|
149
183
|
(-), (&) or (#) FACTIONS where MBR=true.
|
|
150
184
|
(^) FACTIONS where STATUS=RD.
|
|
@@ -166,13 +200,13 @@ REPLACE * with a ONE sentence RESPONSE, always in double quotes.
|
|
|
166
200
|
- if MBR=false and FNR=true, consider (+). this is your faction, promote it with (!).
|
|
167
201
|
- FACTIONS where MBR=true and SENT is positive ARE your identity. promote what you hold.${factionCtx.all.length <= 2 ? '\n- no FACTIONS? (%) to create one.' : ''}
|
|
168
202
|
- FACTIONS where STATUS=RS and MBR=false and lower MCAP could turn more profit if you (+) the right one.
|
|
169
|
-
- (
|
|
170
|
-
-
|
|
171
|
-
- (
|
|
172
|
-
- (
|
|
203
|
+
- (!) and (#) help you coordinate and talk with other agents.
|
|
204
|
+
- in FACTIONS where MBR=true, if MCAP increases, your PNL will increase.
|
|
205
|
+
- (&) and (!) to push FACTIONS where MBR=true and STATUS=RS to STATUS=ASN.
|
|
206
|
+
- (/) to join a faction with intentions of (-) later. (/) when you are profit seeking or want to harm a rival faction.
|
|
173
207
|
- consider (-) to lock in profits on FACTIONS where MBR=true and PNL is positive.
|
|
174
208
|
- consider (-) FACTIONS where MBR=true and PNL is negative unless FNR=true or SENT is positive.
|
|
175
|
-
- when HLTH is negative, prefer (-) weakest FACTIONS where MBR=true
|
|
209
|
+
- when HLTH is negative, prefer (_) or (-) weakest FACTIONS where MBR=true. (+) or (&) ONLY if you see opportunity.
|
|
176
210
|
- (_) if holding is the optimal move.
|
|
177
211
|
---
|
|
178
212
|
one move per turn. output EXACTLY one line.
|
|
@@ -187,7 +221,7 @@ example format: ${(0, util_1.pick)([
|
|
|
187
221
|
>`;
|
|
188
222
|
};
|
|
189
223
|
exports.buildAgentPrompt = buildAgentPrompt;
|
|
190
|
-
const buildCompactModelPrompt = (kit, agent, factionCtx,
|
|
224
|
+
const buildCompactModelPrompt = async (kit, agent, factionCtx, recentMessages, solRange, holdings) => {
|
|
191
225
|
const gameState = kit.state.state;
|
|
192
226
|
const [minSol, maxSol] = solRange ?? defaults_1.PERSONALITY_SOL[agent.personality];
|
|
193
227
|
const holdingsEntries = [...(holdings?.entries() ?? [])];
|
|
@@ -226,20 +260,14 @@ const buildCompactModelPrompt = (kit, agent, factionCtx, intelSnippet, recentMes
|
|
|
226
260
|
return 'RS';
|
|
227
261
|
};
|
|
228
262
|
// Sentiment label
|
|
229
|
-
const sentLabel = (s) => s
|
|
230
|
-
// Per-position PnL
|
|
231
|
-
const
|
|
263
|
+
const sentLabel = (s) => `${s >= 0 ? '+' : ''}${s.toFixed(2)}`;
|
|
264
|
+
// Per-position PnL (numeric, 2 decimal places)
|
|
265
|
+
const pnlValue = (valueSol, bal) => {
|
|
232
266
|
if (totalTokens <= 0 || netInvested <= 0)
|
|
233
|
-
return '
|
|
267
|
+
return '0';
|
|
234
268
|
const estCost = netInvested * (bal / totalTokens);
|
|
235
269
|
const posPnl = valueSol - estCost;
|
|
236
|
-
return posPnl
|
|
237
|
-
};
|
|
238
|
-
// Discovery tag
|
|
239
|
-
const discoveryTag = (f) => {
|
|
240
|
-
if (nearbyMints.has(f.mint))
|
|
241
|
-
return 'NB';
|
|
242
|
-
return 'UX';
|
|
270
|
+
return `${posPnl >= 0 ? '+' : ''}${posPnl.toFixed(2)}`;
|
|
243
271
|
};
|
|
244
272
|
// Build flat faction rows: FACTION (MCAP) STATUS MBR FNR [NB|UX]
|
|
245
273
|
const factionRows = [];
|
|
@@ -253,7 +281,7 @@ const buildCompactModelPrompt = (kit, agent, factionCtx, intelSnippet, recentMes
|
|
|
253
281
|
const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
|
|
254
282
|
const fnr = foundedSet.has(f.mint);
|
|
255
283
|
const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
|
|
256
|
-
factionRows.push(`${f.mint.slice(-8)},${mcap},${statusTag(f)},true,${fnr},${Math.max(v.valueSol, 0.005).toFixed(2)},${
|
|
284
|
+
factionRows.push(`${f.mint.slice(-8)},${mcap},${statusTag(f)},true,${fnr},${Math.max(v.valueSol, 0.005).toFixed(2)},${pnlValue(v.valueSol, v.bal)},${sentLabel(sent)}`);
|
|
257
285
|
}
|
|
258
286
|
// Non-member factions
|
|
259
287
|
const nonMember = factionCtx.all.filter(f => !seenMints.has(f.mint) && f.status !== 'razed');
|
|
@@ -270,15 +298,33 @@ const buildCompactModelPrompt = (kit, agent, factionCtx, intelSnippet, recentMes
|
|
|
270
298
|
seenMints.add(f.mint);
|
|
271
299
|
const mcap = f.market_cap_sol ? `${f.market_cap_sol.toFixed(2)}` : '?';
|
|
272
300
|
const sent = kit.state.sentimentMap.get(f.mint) ?? 0;
|
|
273
|
-
factionRows.push(`${f.mint.slice(-8)},${mcap},${statusTag(f)},false,false,0,
|
|
301
|
+
factionRows.push(`${f.mint.slice(-8)},${mcap},${statusTag(f)},false,false,0,0,${sentLabel(sent)}`);
|
|
274
302
|
}
|
|
303
|
+
// Fetch intel from table member factions only — no off-screen FIDs
|
|
304
|
+
let intelSnippet = '';
|
|
305
|
+
try {
|
|
306
|
+
const tableMemberMints = [...seenMints].filter(mint => heldMints.has(mint));
|
|
307
|
+
const lines = [];
|
|
308
|
+
for (const mint of tableMemberMints.slice(0, 2)) {
|
|
309
|
+
const f = factionCtx.all.find(ff => ff.mint === mint);
|
|
310
|
+
if (!f)
|
|
311
|
+
continue;
|
|
312
|
+
const intel = await (0, faction_1.fetchFactionIntel)(kit, f);
|
|
313
|
+
const latest = intel.recentComms.find((c) => c.sender !== agent.publicKey);
|
|
314
|
+
if (latest) {
|
|
315
|
+
lines.push(`@AP${latest.sender.slice(0, 4)} in ${mint.slice(-8)}: "${latest.memo.replace(/^<+/, '').replace(/>+\s*$/, '').slice(0, 60)}"`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
intelSnippet = lines.join('\n');
|
|
319
|
+
}
|
|
320
|
+
catch { }
|
|
275
321
|
// Pick example FIDs only from factions actually shown in the table
|
|
276
322
|
const tableFids = factionRows.map(r => r.split(',')[0]);
|
|
277
323
|
const m = tableFids.find(fid => heldMints.has([...seenMints].find(mint => mint.endsWith(fid)) ?? '')) ?? tableFids[0] ?? 'xxxxxxpw';
|
|
278
324
|
const nonMemberFids = tableFids.filter(fid => fid !== m);
|
|
279
325
|
const f1 = nonMemberFids.length > 0 ? (0, util_1.pick)(nonMemberFids) : m;
|
|
280
326
|
const f2 = nonMemberFids.length > 1 ? (0, util_1.pick)(nonMemberFids.filter(fid => fid !== f1)) : f1;
|
|
281
|
-
return `
|
|
327
|
+
return `Welcome to Pyre, a faction warfare game. Think in English only. Think linearly: situation → decision → reason. Do not repeat yourself. Do NOT overthink, chess/strategy mood.
|
|
282
328
|
--- GOAL:
|
|
283
329
|
Maximize long-term profit and faction dominance.
|
|
284
330
|
--- LEGEND:
|
|
@@ -291,8 +337,8 @@ RD: ready, community transition stage before ascend.
|
|
|
291
337
|
ASN: ascended factions, established, more members. treasuries active. 0.04% war tax to the faction.
|
|
292
338
|
MBR: true = you are a member. false = you are not a member.
|
|
293
339
|
FNR: true = you created it. false = you did not create it.
|
|
294
|
-
PNL: per-position profit.
|
|
295
|
-
SENT: sentiment score.
|
|
340
|
+
PNL: per-position profit. positive = winning, negative = losing.
|
|
341
|
+
SENT: sentiment score. positive = bullish, negative = bearish.
|
|
296
342
|
--- YOU ARE:
|
|
297
343
|
NAME: @AP${agent.publicKey.slice(0, 4)}
|
|
298
344
|
BIO: ${defaults_1.personalityDesc[agent.personality]}
|
|
@@ -317,11 +363,13 @@ REPLACE * with a ONE sentence RESPONSE, always in double quotes.
|
|
|
317
363
|
(%) "..." - create new faction. "..." = creative name, in quotes.
|
|
318
364
|
(_) - skip turn.
|
|
319
365
|
--- RULES:
|
|
366
|
+
(+) and (&) increase MCAP. (-) decreases MCAP.
|
|
367
|
+
(!) and (#) are your voice. (!) increases SENT. (#) decreases SENT.
|
|
320
368
|
(!) any FACTIONS.
|
|
321
369
|
(^) FACTIONS where STATUS=RD.
|
|
322
370
|
(~) FACTIONS where STATUS=ASN.
|
|
323
371
|
(+) FACTIONS where MBR=false.
|
|
324
|
-
(-), (&) or (#) FACTIONS where MBR=true
|
|
372
|
+
(-), (&) or (#) FACTIONS where MBR=true.
|
|
325
373
|
--- STRATEGIES:
|
|
326
374
|
- your personality is your tone.
|
|
327
375
|
- no FACTIONS? (%) to create one.
|
|
@@ -329,12 +377,11 @@ REPLACE * with a ONE sentence RESPONSE, always in double quotes.
|
|
|
329
377
|
- limit FACTIONS where MBR=true to AT MOST 5.${memberOf.length > 3 ? ` MBR=true on ${memberOf.length} FACTIONS — consider (-) from underperformers.` : ''}
|
|
330
378
|
- FACTIONS where FNR=true and MBR=false, consider (+). promote it with (!).
|
|
331
379
|
- FACTIONS where STATUS=RS may have higher reward if you (+) the right one.
|
|
332
|
-
-
|
|
333
|
-
- (
|
|
334
|
-
-
|
|
335
|
-
- consider (-) FACTIONS where MBR=true and PNL=
|
|
336
|
-
- consider (-) FACTIONS where MBR=true
|
|
337
|
-
- when HLTH is negative, prefer (-) weakest FACTIONS where MBR=true or (_). (+) or (&) ONLY if you see opportunity.
|
|
380
|
+
- in FACTIONS where MBR=true, if MCAP increases, your PNL will increase.
|
|
381
|
+
- (&) and (!) to push FACTIONS where MBR=true and STATUS=RS to STATUS=ASN.
|
|
382
|
+
- consider (-) FACTIONS where MBR=true and PNL is positive to lock in profits.
|
|
383
|
+
- consider (-) FACTIONS where MBR=true and PNL is negative unless FNR=true or SENT is positive.
|
|
384
|
+
- when HLTH is negative, consider (_) or (-) weakest FACTIONS where MBR=true. (+) or (&) ONLY if you see opportunity.
|
|
338
385
|
- (_) if holding is the optimal move.
|
|
339
386
|
---
|
|
340
387
|
one move per turn. output EXACTLY one line.
|
|
@@ -657,66 +704,8 @@ async function llmDecide(kit, agent, factions, recentMessages, llm, log, solRang
|
|
|
657
704
|
nearby: nearbyResult.factions,
|
|
658
705
|
all: allFactions,
|
|
659
706
|
};
|
|
660
|
-
let intelSnippet = '';
|
|
661
|
-
if (compact) {
|
|
662
|
-
// Compact: up to 2 intel lines from held factions
|
|
663
|
-
try {
|
|
664
|
-
const heldMints = [...holdings.keys()];
|
|
665
|
-
const heldFactions = allFactions.filter((f) => heldMints.includes(f.mint)).slice(0, 2);
|
|
666
|
-
const lines = [];
|
|
667
|
-
for (const hf of heldFactions) {
|
|
668
|
-
if (lines.length >= 2)
|
|
669
|
-
break;
|
|
670
|
-
const intel = await (0, faction_1.fetchFactionIntel)(kit, hf);
|
|
671
|
-
const latest = intel.recentComms.find((c) => c.sender !== agent.publicKey);
|
|
672
|
-
if (latest) {
|
|
673
|
-
lines.push(`@AP${latest.sender.slice(0, 4)} in ${hf.mint.slice(-8)}: "${latest.memo.replace(/^<+/, '').replace(/>+\s*$/, '').slice(0, 60)}"`);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
intelSnippet = lines.join('\n');
|
|
677
|
-
}
|
|
678
|
-
catch { }
|
|
679
|
-
}
|
|
680
|
-
else {
|
|
681
|
-
try {
|
|
682
|
-
const heldMints = [...holdings.keys()];
|
|
683
|
-
const heldFactions = allFactions.filter((f) => heldMints.includes(f.mint));
|
|
684
|
-
const otherFactions = allFactions.filter((f) => !heldMints.includes(f.mint));
|
|
685
|
-
const toScout = [
|
|
686
|
-
...heldFactions.slice(0, 2),
|
|
687
|
-
...(otherFactions.length > 0 ? [(0, util_1.pick)(otherFactions)] : []),
|
|
688
|
-
];
|
|
689
|
-
if (toScout.length > 0) {
|
|
690
|
-
const intels = await Promise.all(toScout.map((f) => (0, faction_1.fetchFactionIntel)(kit, f)));
|
|
691
|
-
const lines = intels.map((intel, i) => {
|
|
692
|
-
const fid = toScout[i].mint.slice(-8);
|
|
693
|
-
const memberInfo = intel.totalMembers > 0
|
|
694
|
-
? `${intel.totalMembers} members, top holder: ${intel.members[0]?.percentage.toFixed(1)}%`
|
|
695
|
-
: 'no members';
|
|
696
|
-
const commsInfo = intel.recentComms.length > 0
|
|
697
|
-
? intel.recentComms
|
|
698
|
-
.slice(0, 3)
|
|
699
|
-
.map((c) => `@AP${c.sender.slice(0, 4)} said: "${c.memo.replace(/^<+/, '').replace(/>+\s*$/, '')}"`)
|
|
700
|
-
.join(', ')
|
|
701
|
-
: 'no recent comms';
|
|
702
|
-
return ` [${fid}] ${memberInfo} | recent comms: ${commsInfo}`;
|
|
703
|
-
});
|
|
704
|
-
intelSnippet = 'FACTION INTEL:\n' + lines.join('\n');
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
catch { }
|
|
708
|
-
}
|
|
709
|
-
// Include results from previous SCOUT actions (skip in compact mode)
|
|
710
|
-
let scoutSnippet = '';
|
|
711
|
-
if (!compact) {
|
|
712
|
-
const scoutResults = exports.pendingScoutResults.get(agent.publicKey);
|
|
713
|
-
if (scoutResults && scoutResults.length > 0) {
|
|
714
|
-
scoutSnippet = '\nSCOUT RESULTS (from your previous SCOUT actions):\n' + scoutResults.join('\n');
|
|
715
|
-
exports.pendingScoutResults.delete(agent.publicKey);
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
707
|
const buildPrompt = compact ? exports.buildCompactModelPrompt : exports.buildAgentPrompt;
|
|
719
|
-
const prompt = buildPrompt(kit, agent, factionCtx,
|
|
708
|
+
const prompt = await buildPrompt(kit, agent, factionCtx, recentMessages, solRange, holdings);
|
|
720
709
|
// Surface the faction table to the caller if requested
|
|
721
710
|
if (options?.onPromptTable) {
|
|
722
711
|
const tableStart = prompt.indexOf('--- FACTIONS:');
|