simmer-automaton 0.6.5 → 0.6.7
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/api.d.ts +33 -11
- package/dist/api.js +3 -0
- package/dist/index.js +19 -17
- package/package.json +1 -1
- package/src/api.ts +28 -11
- package/src/index.ts +19 -17
package/dist/api.d.ts
CHANGED
|
@@ -46,8 +46,31 @@ export interface BriefingPosition {
|
|
|
46
46
|
resolves_at: string | null;
|
|
47
47
|
source: string | null;
|
|
48
48
|
}
|
|
49
|
+
export interface BriefingVenue {
|
|
50
|
+
currency: string;
|
|
51
|
+
balance: number | null;
|
|
52
|
+
pnl: number;
|
|
53
|
+
positions_count: number;
|
|
54
|
+
redeemable_count?: number;
|
|
55
|
+
positions_needing_attention: BriefingPosition[];
|
|
56
|
+
actions: string[];
|
|
57
|
+
by_skill?: Record<string, {
|
|
58
|
+
count: number;
|
|
59
|
+
pnl: number;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
49
62
|
export interface BriefingResponse {
|
|
50
|
-
|
|
63
|
+
venues: {
|
|
64
|
+
simmer: BriefingVenue | null;
|
|
65
|
+
polymarket: BriefingVenue | null;
|
|
66
|
+
kalshi: BriefingVenue | null;
|
|
67
|
+
};
|
|
68
|
+
opportunities: {
|
|
69
|
+
new_markets: Array<Record<string, unknown>>;
|
|
70
|
+
recommended_skills: Array<Record<string, unknown>>;
|
|
71
|
+
};
|
|
72
|
+
risk_alerts: string[];
|
|
73
|
+
performance: {
|
|
51
74
|
total_pnl: number;
|
|
52
75
|
pnl_percent: number;
|
|
53
76
|
win_rate: number;
|
|
@@ -55,16 +78,12 @@ export interface BriefingResponse {
|
|
|
55
78
|
total_agents: number;
|
|
56
79
|
settled_pnl: number;
|
|
57
80
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
cost: number;
|
|
65
|
-
source: string | null;
|
|
66
|
-
created_at: string;
|
|
67
|
-
}>;
|
|
81
|
+
checked_at: string;
|
|
82
|
+
sdk_update: {
|
|
83
|
+
current: string;
|
|
84
|
+
latest: string;
|
|
85
|
+
message: string;
|
|
86
|
+
} | null;
|
|
68
87
|
}
|
|
69
88
|
export interface SkillOutcome {
|
|
70
89
|
skill_slug: string;
|
|
@@ -122,6 +141,9 @@ export declare class SimmerApi {
|
|
|
122
141
|
since: string;
|
|
123
142
|
}>;
|
|
124
143
|
getBriefing(): Promise<BriefingResponse>;
|
|
144
|
+
getPositions(): Promise<{
|
|
145
|
+
positions: BriefingPosition[];
|
|
146
|
+
}>;
|
|
125
147
|
postCycle(data: {
|
|
126
148
|
active_skills: string[];
|
|
127
149
|
cycle_number: number;
|
package/dist/api.js
CHANGED
|
@@ -73,6 +73,9 @@ export class SimmerApi {
|
|
|
73
73
|
async getBriefing() {
|
|
74
74
|
return this.request("/api/sdk/briefing");
|
|
75
75
|
}
|
|
76
|
+
async getPositions() {
|
|
77
|
+
return this.request("/api/sdk/positions");
|
|
78
|
+
}
|
|
76
79
|
async postCycle(data) {
|
|
77
80
|
return this.request("/api/sdk/automaton/cycle", {
|
|
78
81
|
method: "POST",
|
package/dist/index.js
CHANGED
|
@@ -85,8 +85,7 @@ async function refreshState(logger) {
|
|
|
85
85
|
if (cachedState.venue) {
|
|
86
86
|
config.venue = cachedState.venue;
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
currentTier = computeTier(cachedState, 0);
|
|
88
|
+
currentTier = computeTier(cachedState, cachedPortfolio?.totalPnl ?? 0);
|
|
90
89
|
// Sync banditState from fetched skills — preserve memory for existing, seed new ones
|
|
91
90
|
const existingBySlug = new Map(banditState.map((s) => [s.slug, s]));
|
|
92
91
|
banditState = cachedSkills.map((skill) => {
|
|
@@ -178,15 +177,15 @@ function buildPromptContext() {
|
|
|
178
177
|
lines.push("");
|
|
179
178
|
lines.push(`**Portfolio:** ${cachedPortfolio.positionCount} positions | P&L: ${fmtCurrency(cachedPortfolio.totalPnl)} | Recent trades: ${cachedPortfolio.recentTradeCount}`);
|
|
180
179
|
if (cachedPortfolio.positions.length > 0) {
|
|
181
|
-
// Show
|
|
182
|
-
|
|
183
|
-
const top =
|
|
180
|
+
// Show positions needing attention (significant moves or nearing expiry)
|
|
181
|
+
lines.push(" Needing attention:");
|
|
182
|
+
const top = cachedPortfolio.positions.slice(0, 3);
|
|
184
183
|
for (const p of top) {
|
|
185
184
|
const pnlStr = p.pnl >= 0 ? `+${fmtCurrency(p.pnl)}` : fmtCurrency(p.pnl);
|
|
186
185
|
lines.push(` - ${p.question.slice(0, 60)} | ${p.side} ${p.shares} shares @ ${p.avg_entry.toFixed(2)} → ${p.current_price.toFixed(2)} | ${pnlStr}`);
|
|
187
186
|
}
|
|
188
|
-
if (
|
|
189
|
-
lines.push(` - ...and ${
|
|
187
|
+
if (cachedPortfolio.positions.length > 3) {
|
|
188
|
+
lines.push(` - ...and ${cachedPortfolio.positions.length - 3} more needing attention`);
|
|
190
189
|
}
|
|
191
190
|
}
|
|
192
191
|
}
|
|
@@ -298,9 +297,11 @@ async function executeSkills(selectedSlugs, workspaceDir, logger) {
|
|
|
298
297
|
// =============================================================================
|
|
299
298
|
export default function register(pluginApi) {
|
|
300
299
|
loadConfig(pluginApi.pluginConfig);
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
|
|
300
|
+
// Env var takes priority; fall back to plugin config only if env var is absent.
|
|
301
|
+
// This prevents placeholder values in openclaw.json from shadowing the real key.
|
|
302
|
+
const envKey = process.env.SIMMER_API_KEY || "";
|
|
303
|
+
if (envKey) {
|
|
304
|
+
config.apiKey = envKey;
|
|
304
305
|
}
|
|
305
306
|
if (!config.apiKey) {
|
|
306
307
|
pluginApi.logger.error("[simmer] No apiKey in plugin config or SIMMER_API_KEY env var — plugin disabled");
|
|
@@ -423,12 +424,13 @@ export default function register(pluginApi) {
|
|
|
423
424
|
// Fetch portfolio snapshot for prompt context
|
|
424
425
|
try {
|
|
425
426
|
const briefing = await api.getBriefing();
|
|
426
|
-
const
|
|
427
|
+
const venue = briefing.venues?.simmer;
|
|
428
|
+
const attentionPositions = venue?.positions_needing_attention || [];
|
|
427
429
|
cachedPortfolio = {
|
|
428
|
-
totalPnl: briefing.
|
|
429
|
-
positionCount:
|
|
430
|
-
positions,
|
|
431
|
-
recentTradeCount:
|
|
430
|
+
totalPnl: briefing.performance?.total_pnl ?? 0,
|
|
431
|
+
positionCount: venue?.positions_count ?? 0,
|
|
432
|
+
positions: attentionPositions,
|
|
433
|
+
recentTradeCount: 0,
|
|
432
434
|
};
|
|
433
435
|
}
|
|
434
436
|
catch (e) {
|
|
@@ -621,8 +623,8 @@ export default function register(pluginApi) {
|
|
|
621
623
|
}
|
|
622
624
|
if (subcommand === "portfolio") {
|
|
623
625
|
try {
|
|
624
|
-
const
|
|
625
|
-
const positions =
|
|
626
|
+
const res = await api.getPositions();
|
|
627
|
+
const positions = res.positions || [];
|
|
626
628
|
if (positions.length === 0) {
|
|
627
629
|
return { text: "No open positions." };
|
|
628
630
|
}
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -51,8 +51,29 @@ export interface BriefingPosition {
|
|
|
51
51
|
source: string | null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export interface BriefingVenue {
|
|
55
|
+
currency: string;
|
|
56
|
+
balance: number | null;
|
|
57
|
+
pnl: number;
|
|
58
|
+
positions_count: number;
|
|
59
|
+
redeemable_count?: number;
|
|
60
|
+
positions_needing_attention: BriefingPosition[];
|
|
61
|
+
actions: string[];
|
|
62
|
+
by_skill?: Record<string, { count: number; pnl: number }>;
|
|
63
|
+
}
|
|
64
|
+
|
|
54
65
|
export interface BriefingResponse {
|
|
55
|
-
|
|
66
|
+
venues: {
|
|
67
|
+
simmer: BriefingVenue | null;
|
|
68
|
+
polymarket: BriefingVenue | null;
|
|
69
|
+
kalshi: BriefingVenue | null;
|
|
70
|
+
};
|
|
71
|
+
opportunities: {
|
|
72
|
+
new_markets: Array<Record<string, unknown>>;
|
|
73
|
+
recommended_skills: Array<Record<string, unknown>>;
|
|
74
|
+
};
|
|
75
|
+
risk_alerts: string[];
|
|
76
|
+
performance: {
|
|
56
77
|
total_pnl: number;
|
|
57
78
|
pnl_percent: number;
|
|
58
79
|
win_rate: number;
|
|
@@ -60,16 +81,8 @@ export interface BriefingResponse {
|
|
|
60
81
|
total_agents: number;
|
|
61
82
|
settled_pnl: number;
|
|
62
83
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
market_question: string;
|
|
66
|
-
action: string;
|
|
67
|
-
side: string;
|
|
68
|
-
shares: number;
|
|
69
|
-
cost: number;
|
|
70
|
-
source: string | null;
|
|
71
|
-
created_at: string;
|
|
72
|
-
}>;
|
|
84
|
+
checked_at: string;
|
|
85
|
+
sdk_update: { current: string; latest: string; message: string } | null;
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
export interface SkillOutcome {
|
|
@@ -176,6 +189,10 @@ export class SimmerApi {
|
|
|
176
189
|
return this.request("/api/sdk/briefing");
|
|
177
190
|
}
|
|
178
191
|
|
|
192
|
+
async getPositions(): Promise<{ positions: BriefingPosition[] }> {
|
|
193
|
+
return this.request("/api/sdk/positions");
|
|
194
|
+
}
|
|
195
|
+
|
|
179
196
|
async postCycle(data: {
|
|
180
197
|
active_skills: string[];
|
|
181
198
|
cycle_number: number;
|
package/src/index.ts
CHANGED
|
@@ -117,8 +117,7 @@ async function refreshState(logger: { info: (m: string) => void; error: (m: stri
|
|
|
117
117
|
if (cachedState.venue) {
|
|
118
118
|
config.venue = cachedState.venue;
|
|
119
119
|
}
|
|
120
|
-
|
|
121
|
-
currentTier = computeTier(cachedState, 0);
|
|
120
|
+
currentTier = computeTier(cachedState, cachedPortfolio?.totalPnl ?? 0);
|
|
122
121
|
|
|
123
122
|
// Sync banditState from fetched skills — preserve memory for existing, seed new ones
|
|
124
123
|
const existingBySlug = new Map(banditState.map((s) => [s.slug, s]));
|
|
@@ -219,15 +218,15 @@ function buildPromptContext(): string {
|
|
|
219
218
|
lines.push("");
|
|
220
219
|
lines.push(`**Portfolio:** ${cachedPortfolio.positionCount} positions | P&L: ${fmtCurrency(cachedPortfolio.totalPnl)} | Recent trades: ${cachedPortfolio.recentTradeCount}`);
|
|
221
220
|
if (cachedPortfolio.positions.length > 0) {
|
|
222
|
-
// Show
|
|
223
|
-
|
|
224
|
-
const top =
|
|
221
|
+
// Show positions needing attention (significant moves or nearing expiry)
|
|
222
|
+
lines.push(" Needing attention:");
|
|
223
|
+
const top = cachedPortfolio.positions.slice(0, 3);
|
|
225
224
|
for (const p of top) {
|
|
226
225
|
const pnlStr = p.pnl >= 0 ? `+${fmtCurrency(p.pnl)}` : fmtCurrency(p.pnl);
|
|
227
226
|
lines.push(` - ${p.question.slice(0, 60)} | ${p.side} ${p.shares} shares @ ${p.avg_entry.toFixed(2)} → ${p.current_price.toFixed(2)} | ${pnlStr}`);
|
|
228
227
|
}
|
|
229
|
-
if (
|
|
230
|
-
lines.push(` - ...and ${
|
|
228
|
+
if (cachedPortfolio.positions.length > 3) {
|
|
229
|
+
lines.push(` - ...and ${cachedPortfolio.positions.length - 3} more needing attention`);
|
|
231
230
|
}
|
|
232
231
|
}
|
|
233
232
|
}
|
|
@@ -358,9 +357,11 @@ async function executeSkills(
|
|
|
358
357
|
export default function register(pluginApi: PluginApi) {
|
|
359
358
|
loadConfig(pluginApi.pluginConfig);
|
|
360
359
|
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
|
|
360
|
+
// Env var takes priority; fall back to plugin config only if env var is absent.
|
|
361
|
+
// This prevents placeholder values in openclaw.json from shadowing the real key.
|
|
362
|
+
const envKey = process.env.SIMMER_API_KEY || "";
|
|
363
|
+
if (envKey) {
|
|
364
|
+
config.apiKey = envKey;
|
|
364
365
|
}
|
|
365
366
|
|
|
366
367
|
if (!config.apiKey) {
|
|
@@ -495,12 +496,13 @@ export default function register(pluginApi: PluginApi) {
|
|
|
495
496
|
// Fetch portfolio snapshot for prompt context
|
|
496
497
|
try {
|
|
497
498
|
const briefing = await api.getBriefing();
|
|
498
|
-
const
|
|
499
|
+
const venue = briefing.venues?.simmer;
|
|
500
|
+
const attentionPositions = venue?.positions_needing_attention || [];
|
|
499
501
|
cachedPortfolio = {
|
|
500
|
-
totalPnl: briefing.
|
|
501
|
-
positionCount:
|
|
502
|
-
positions,
|
|
503
|
-
recentTradeCount:
|
|
502
|
+
totalPnl: briefing.performance?.total_pnl ?? 0,
|
|
503
|
+
positionCount: venue?.positions_count ?? 0,
|
|
504
|
+
positions: attentionPositions,
|
|
505
|
+
recentTradeCount: 0,
|
|
504
506
|
};
|
|
505
507
|
} catch (e) {
|
|
506
508
|
ctx.logger.warn(`[simmer] Failed to fetch briefing: ${e}`);
|
|
@@ -701,8 +703,8 @@ export default function register(pluginApi: PluginApi) {
|
|
|
701
703
|
|
|
702
704
|
if (subcommand === "portfolio") {
|
|
703
705
|
try {
|
|
704
|
-
const
|
|
705
|
-
const positions =
|
|
706
|
+
const res = await api.getPositions();
|
|
707
|
+
const positions = res.positions || [];
|
|
706
708
|
if (positions.length === 0) {
|
|
707
709
|
return { text: "No open positions." };
|
|
708
710
|
}
|