@spfunctions/cli 0.1.6 → 0.1.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.
@@ -197,16 +197,19 @@ function renderEdges(context, piTui) {
197
197
  const positions = context._positions || [];
198
198
  const lines = [];
199
199
  for (const e of edges) {
200
- const name = (e.marketTitle || e.ticker || '').slice(0, 18).padEnd(18);
201
- const market = typeof e.marketPrice === 'number' ? `${e.marketPrice}\u00A2` : '?';
202
- const thesis = typeof e.thesisImpliedPrice === 'number' ? `${e.thesisImpliedPrice}\u00A2` : '?';
203
- const edge = typeof e.edgeSize === 'number' ? (e.edgeSize > 0 ? `+${e.edgeSize}` : `${e.edgeSize}`) : '?';
204
- const spread = typeof e.spread === 'number' ? `${e.spread}\u00A2` : '?';
205
- const liq = e.liquidityScore || 'low';
200
+ // Context API field names: market, marketId, thesisPrice, edge, orderbook.spread, orderbook.liquidityScore
201
+ const name = (e.market || e.marketId || '').slice(0, 18).padEnd(18);
202
+ const marketStr = typeof e.marketPrice === 'number' ? `${e.marketPrice}\u00A2` : '?';
203
+ const thesisStr = typeof e.thesisPrice === 'number' ? `${e.thesisPrice}\u00A2` : '?';
204
+ const edgeVal = typeof e.edge === 'number' ? (e.edge > 0 ? `+${e.edge}` : `${e.edge}`) : '?';
205
+ const ob = e.orderbook || {};
206
+ const spreadStr = typeof ob.spread === 'number' ? `${ob.spread}\u00A2` : '?';
207
+ const liq = ob.liquidityScore || 'low';
206
208
  const liqBars = liq === 'high' ? '\u25A0\u25A0\u25A0' : liq === 'medium' ? '\u25A0\u25A0 ' : '\u25A0 ';
207
209
  const liqColor = liq === 'high' ? C.emerald : liq === 'medium' ? C.amber : C.red;
208
- // Check if we have a position on this edge
209
- const pos = positions.find((p) => p.ticker === e.ticker);
210
+ // Check if we have a position on this edge (match by marketId prefix in ticker)
211
+ const pos = positions.find((p) => p.ticker === e.marketId ||
212
+ (e.marketId && p.ticker?.includes(e.marketId)));
210
213
  let posStr = C.zinc600('\u2014');
211
214
  if (pos) {
212
215
  const side = pos.side?.toUpperCase() || 'YES';
@@ -215,7 +218,7 @@ function renderEdges(context, piTui) {
215
218
  : '';
216
219
  posStr = C.emerald(`${side} (${pos.quantity}@${pos.average_price_paid}\u00A2 ${pnl})`);
217
220
  }
218
- lines.push(` ${C.zinc200(name)} ${C.zinc400(market)} \u2192 ${C.zinc400(thesis)} edge ${edge.includes('+') ? C.emerald(edge) : C.red(edge)} spread ${C.zinc600(spread)} ${liqColor(liqBars)} ${liqColor(liq.padEnd(4))} ${posStr}`);
221
+ lines.push(` ${C.zinc200(name)} ${C.zinc400(marketStr)} \u2192 ${C.zinc400(thesisStr)} edge ${edgeVal.includes('+') ? C.emerald(edgeVal) : C.red(edgeVal)} spread ${C.zinc600(spreadStr)} ${liqColor(liqBars)} ${liqColor(liq.padEnd(4))} ${posStr}`);
219
222
  }
220
223
  return lines.join('\n');
221
224
  }
@@ -283,7 +286,7 @@ async function agentCommand(thesisId, opts) {
283
286
  // ── Fetch initial context ──────────────────────────────────────────────────
284
287
  let latestContext = await sfClient.getContext(resolvedThesisId);
285
288
  // ── Model setup ────────────────────────────────────────────────────────────
286
- const rawModelName = opts?.model || 'anthropic/claude-sonnet-4-20250514';
289
+ const rawModelName = opts?.model || 'anthropic/claude-sonnet-4.6';
287
290
  let currentModelName = rawModelName.replace(/^openrouter\//, '');
288
291
  function resolveModel(name) {
289
292
  try {
@@ -564,6 +567,23 @@ Do NOT make up data. Always call tools to get current state.`;
564
567
  let currentLoader = null;
565
568
  const toolStartTimes = new Map();
566
569
  const toolLines = new Map();
570
+ // Throttle renders during streaming to prevent flicker (max ~15fps)
571
+ let renderTimer = null;
572
+ function throttledRender() {
573
+ if (renderTimer)
574
+ return;
575
+ renderTimer = setTimeout(() => {
576
+ renderTimer = null;
577
+ tui.requestRender();
578
+ }, 66);
579
+ }
580
+ function flushRender() {
581
+ if (renderTimer) {
582
+ clearTimeout(renderTimer);
583
+ renderTimer = null;
584
+ }
585
+ tui.requestRender();
586
+ }
567
587
  agent.subscribe((event) => {
568
588
  if (event.type === 'message_start') {
569
589
  // Show loader while waiting for first text
@@ -590,30 +610,30 @@ Do NOT make up data. Always call tools to get current state.`;
590
610
  if (currentAssistantMd) {
591
611
  currentAssistantMd.setText(currentAssistantText);
592
612
  }
593
- tui.requestRender();
613
+ // Throttled render to prevent flicker during fast token streaming
614
+ throttledRender();
594
615
  }
595
616
  }
596
- if (event.type === 'message_complete') {
617
+ if (event.type === 'message_end') {
597
618
  // Clean up loader if still present (no text was generated)
598
619
  if (currentLoader) {
599
620
  currentLoader.stop();
600
621
  chatContainer.removeChild(currentLoader);
601
622
  currentLoader = null;
602
623
  }
603
- // Add spacer after message
624
+ // Final render of the complete message
625
+ if (currentAssistantMd && currentAssistantText) {
626
+ currentAssistantMd.setText(currentAssistantText);
627
+ }
604
628
  addSpacer();
605
629
  currentAssistantMd = null;
606
630
  currentAssistantText = '';
631
+ flushRender();
632
+ }
633
+ if (event.type === 'agent_end') {
634
+ // Agent turn fully complete — safe to accept new input
607
635
  isProcessing = false;
608
- tui.requestRender();
609
- // Update token/cost tracking from event if available
610
- if (event.usage) {
611
- totalTokens += (event.usage.inputTokens || 0) + (event.usage.outputTokens || 0);
612
- totalCost += event.usage.totalCost || 0;
613
- footerBar.tokens = totalTokens;
614
- footerBar.cost = totalCost;
615
- footerBar.update();
616
- }
636
+ flushRender();
617
637
  }
618
638
  if (event.type === 'tool_execution_start') {
619
639
  const toolLine = new MutableLine(C.zinc600(` \u26A1 ${event.toolName}...`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfunctions/cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "CLI for SimpleFunctions prediction market thesis agent",
5
5
  "bin": {
6
6
  "sf": "./dist/index.js"