simmer-automaton 0.6.6 → 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 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
- portfolio: {
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
- positions: BriefingPosition[];
59
- recent_trades: Array<{
60
- market_question: string;
61
- action: string;
62
- side: string;
63
- shares: number;
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
- // Compute tier (totalPnl = 0 for now, will be enriched when P&L tracking is added)
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 top 3 by absolute PnL
182
- const sorted = [...cachedPortfolio.positions].sort((a, b) => Math.abs(b.pnl) - Math.abs(a.pnl));
183
- const top = sorted.slice(0, 3);
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 (sorted.length > 3) {
189
- lines.push(` - ...and ${sorted.length - 3} more (use /simmer portfolio for full list)`);
187
+ if (cachedPortfolio.positions.length > 3) {
188
+ lines.push(` - ...and ${cachedPortfolio.positions.length - 3} more needing attention`);
190
189
  }
191
190
  }
192
191
  }
@@ -425,12 +424,13 @@ export default function register(pluginApi) {
425
424
  // Fetch portfolio snapshot for prompt context
426
425
  try {
427
426
  const briefing = await api.getBriefing();
428
- const positions = briefing.positions || [];
427
+ const venue = briefing.venues?.simmer;
428
+ const attentionPositions = venue?.positions_needing_attention || [];
429
429
  cachedPortfolio = {
430
- totalPnl: briefing.portfolio?.total_pnl ?? 0,
431
- positionCount: positions.length,
432
- positions,
433
- recentTradeCount: briefing.recent_trades?.length ?? 0,
430
+ totalPnl: briefing.performance?.total_pnl ?? 0,
431
+ positionCount: venue?.positions_count ?? 0,
432
+ positions: attentionPositions,
433
+ recentTradeCount: 0,
434
434
  };
435
435
  }
436
436
  catch (e) {
@@ -623,8 +623,8 @@ export default function register(pluginApi) {
623
623
  }
624
624
  if (subcommand === "portfolio") {
625
625
  try {
626
- const briefing = await api.getBriefing();
627
- const positions = briefing.positions || [];
626
+ const res = await api.getPositions();
627
+ const positions = res.positions || [];
628
628
  if (positions.length === 0) {
629
629
  return { text: "No open positions." };
630
630
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simmer-automaton",
3
- "version": "0.6.6",
3
+ "version": "0.6.7",
4
4
  "description": "Simmer Automaton plugin for OpenClaw — autonomous trading skill orchestration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
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
- portfolio: {
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
- positions: BriefingPosition[];
64
- recent_trades: Array<{
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
- // Compute tier (totalPnl = 0 for now, will be enriched when P&L tracking is added)
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 top 3 by absolute PnL
223
- const sorted = [...cachedPortfolio.positions].sort((a, b) => Math.abs(b.pnl) - Math.abs(a.pnl));
224
- const top = sorted.slice(0, 3);
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 (sorted.length > 3) {
230
- lines.push(` - ...and ${sorted.length - 3} more (use /simmer portfolio for full list)`);
228
+ if (cachedPortfolio.positions.length > 3) {
229
+ lines.push(` - ...and ${cachedPortfolio.positions.length - 3} more needing attention`);
231
230
  }
232
231
  }
233
232
  }
@@ -497,12 +496,13 @@ export default function register(pluginApi: PluginApi) {
497
496
  // Fetch portfolio snapshot for prompt context
498
497
  try {
499
498
  const briefing = await api.getBriefing();
500
- const positions = briefing.positions || [];
499
+ const venue = briefing.venues?.simmer;
500
+ const attentionPositions = venue?.positions_needing_attention || [];
501
501
  cachedPortfolio = {
502
- totalPnl: briefing.portfolio?.total_pnl ?? 0,
503
- positionCount: positions.length,
504
- positions,
505
- recentTradeCount: briefing.recent_trades?.length ?? 0,
502
+ totalPnl: briefing.performance?.total_pnl ?? 0,
503
+ positionCount: venue?.positions_count ?? 0,
504
+ positions: attentionPositions,
505
+ recentTradeCount: 0,
506
506
  };
507
507
  } catch (e) {
508
508
  ctx.logger.warn(`[simmer] Failed to fetch briefing: ${e}`);
@@ -703,8 +703,8 @@ export default function register(pluginApi: PluginApi) {
703
703
 
704
704
  if (subcommand === "portfolio") {
705
705
  try {
706
- const briefing = await api.getBriefing();
707
- const positions = briefing.positions || [];
706
+ const res = await api.getPositions();
707
+ const positions = res.positions || [];
708
708
  if (positions.length === 0) {
709
709
  return { text: "No open positions." };
710
710
  }