@spfunctions/cli 1.7.12 → 1.7.14
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/client.d.ts +2 -0
- package/dist/client.js +6 -0
- package/dist/commands/agent.js +65 -0
- package/dist/commands/heartbeat.d.ts +20 -0
- package/dist/commands/heartbeat.js +73 -0
- package/dist/index.js +26 -0
- package/dist/telegram/agent-bridge.js +31 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export declare class SFClient {
|
|
|
17
17
|
createThesis(rawThesis: string, sync?: boolean): Promise<any>;
|
|
18
18
|
injectSignal(id: string, type: string, content: string, source?: string): Promise<any>;
|
|
19
19
|
evaluate(id: string): Promise<any>;
|
|
20
|
+
getHeartbeatConfig(id: string): Promise<any>;
|
|
21
|
+
updateHeartbeatConfig(id: string, config: Record<string, unknown>): Promise<any>;
|
|
20
22
|
getFeed(hours?: number, limit?: number): Promise<any>;
|
|
21
23
|
getChanges(id: string, since: string): Promise<any>;
|
|
22
24
|
updateThesis(id: string, data: Record<string, unknown>): Promise<any>;
|
package/dist/client.js
CHANGED
|
@@ -74,6 +74,12 @@ class SFClient {
|
|
|
74
74
|
async evaluate(id) {
|
|
75
75
|
return this.request('POST', `/api/thesis/${id}/evaluate`);
|
|
76
76
|
}
|
|
77
|
+
async getHeartbeatConfig(id) {
|
|
78
|
+
return this.request('GET', `/api/thesis/${id}/heartbeat`);
|
|
79
|
+
}
|
|
80
|
+
async updateHeartbeatConfig(id, config) {
|
|
81
|
+
return this.request('PATCH', `/api/thesis/${id}/heartbeat`, config);
|
|
82
|
+
}
|
|
77
83
|
async getFeed(hours = 24, limit = 200) {
|
|
78
84
|
return this.request('GET', `/api/feed?hours=${hours}&limit=${limit}`);
|
|
79
85
|
}
|
package/dist/commands/agent.js
CHANGED
|
@@ -1588,6 +1588,37 @@ async function agentCommand(thesisId, opts) {
|
|
|
1588
1588
|
const data = await sfClient.getXAccount(params.username, { hours: params.hours });
|
|
1589
1589
|
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
1590
1590
|
},
|
|
1591
|
+
}, {
|
|
1592
|
+
name: 'heartbeat_config',
|
|
1593
|
+
label: 'Heartbeat Config',
|
|
1594
|
+
description: 'View or update heartbeat settings for a thesis: scan intervals, model tier, budget cap, pause/resume. Also shows this month\'s cost breakdown.',
|
|
1595
|
+
parameters: Type.Object({
|
|
1596
|
+
thesisId: Type.String({ description: 'Thesis ID' }),
|
|
1597
|
+
newsIntervalMin: Type.Optional(Type.Number({ description: 'News scan interval in minutes (15-1440)' })),
|
|
1598
|
+
xIntervalMin: Type.Optional(Type.Number({ description: 'X scan interval in minutes (60-1440)' })),
|
|
1599
|
+
evalModelTier: Type.Optional(Type.String({ description: 'Eval model: cheap, medium, or heavy' })),
|
|
1600
|
+
monthlyBudgetUsd: Type.Optional(Type.Number({ description: 'Monthly budget cap in USD (0 = unlimited)' })),
|
|
1601
|
+
paused: Type.Optional(Type.Boolean({ description: 'Pause (true) or resume (false) heartbeat' })),
|
|
1602
|
+
}),
|
|
1603
|
+
execute: async (_toolCallId, params) => {
|
|
1604
|
+
const hasUpdates = params.newsIntervalMin || params.xIntervalMin || params.evalModelTier || params.monthlyBudgetUsd !== undefined || params.paused !== undefined;
|
|
1605
|
+
if (hasUpdates) {
|
|
1606
|
+
const updates = {};
|
|
1607
|
+
if (params.newsIntervalMin)
|
|
1608
|
+
updates.newsIntervalMin = params.newsIntervalMin;
|
|
1609
|
+
if (params.xIntervalMin)
|
|
1610
|
+
updates.xIntervalMin = params.xIntervalMin;
|
|
1611
|
+
if (params.evalModelTier)
|
|
1612
|
+
updates.evalModelTier = params.evalModelTier;
|
|
1613
|
+
if (params.monthlyBudgetUsd !== undefined)
|
|
1614
|
+
updates.monthlyBudgetUsd = params.monthlyBudgetUsd;
|
|
1615
|
+
if (params.paused !== undefined)
|
|
1616
|
+
updates.paused = params.paused;
|
|
1617
|
+
await sfClient.updateHeartbeatConfig(params.thesisId, updates);
|
|
1618
|
+
}
|
|
1619
|
+
const data = await sfClient.getHeartbeatConfig(params.thesisId);
|
|
1620
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
1621
|
+
},
|
|
1591
1622
|
});
|
|
1592
1623
|
// ── Trading tools (conditional on tradingEnabled) ──────────────────────────
|
|
1593
1624
|
const config = (0, config_js_1.loadConfig)();
|
|
@@ -1727,6 +1758,9 @@ Don't answer a complex question with a single tool call.
|
|
|
1727
1758
|
### Social signal research
|
|
1728
1759
|
Use search_x to check X/Twitter sentiment on any topic — especially useful for geopolitical events, macro shifts, and breaking news that moves prediction markets. Use x_volume to detect discussion spikes (velocity > 1 = increasing attention). Use x_account to track specific analysts or officials.
|
|
1729
1760
|
|
|
1761
|
+
### Heartbeat config
|
|
1762
|
+
Use heartbeat_config to view or adjust per-thesis heartbeat settings: news/X scan intervals, evaluation model tier (cheap/medium/heavy), monthly budget cap, pause/resume. Also shows this month's cost breakdown (LLM calls, search calls, tokens, spend). Useful when the user asks about costs, wants to slow down/speed up monitoring, or if you detect budget overrun.
|
|
1763
|
+
|
|
1730
1764
|
### Conditional rules
|
|
1731
1765
|
- Portfolio/positions questions: flag correlated exposure — positions sharing upstream causal nodes are not independent bets.
|
|
1732
1766
|
- No catalyst visible within 30 days + edge not improving: flag "stale capital risk."
|
|
@@ -3345,6 +3379,36 @@ async function runPlainTextAgent(params) {
|
|
|
3345
3379
|
const data = await sfClient.getXAccount(p.username, { hours: p.hours });
|
|
3346
3380
|
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
3347
3381
|
},
|
|
3382
|
+
}, {
|
|
3383
|
+
name: 'heartbeat_config', label: 'Heartbeat Config',
|
|
3384
|
+
description: 'View or update heartbeat settings: scan intervals, model tier, budget cap, pause/resume. Shows cost breakdown.',
|
|
3385
|
+
parameters: Type.Object({
|
|
3386
|
+
thesisId: Type.String({ description: 'Thesis ID' }),
|
|
3387
|
+
newsIntervalMin: Type.Optional(Type.Number({ description: 'News scan interval (15-1440 min)' })),
|
|
3388
|
+
xIntervalMin: Type.Optional(Type.Number({ description: 'X scan interval (60-1440 min)' })),
|
|
3389
|
+
evalModelTier: Type.Optional(Type.String({ description: 'cheap, medium, or heavy' })),
|
|
3390
|
+
monthlyBudgetUsd: Type.Optional(Type.Number({ description: 'Monthly budget (0 = unlimited)' })),
|
|
3391
|
+
paused: Type.Optional(Type.Boolean({ description: 'Pause or resume heartbeat' })),
|
|
3392
|
+
}),
|
|
3393
|
+
execute: async (_id, p) => {
|
|
3394
|
+
const hasUp = p.newsIntervalMin || p.xIntervalMin || p.evalModelTier || p.monthlyBudgetUsd !== undefined || p.paused !== undefined;
|
|
3395
|
+
if (hasUp) {
|
|
3396
|
+
const u = {};
|
|
3397
|
+
if (p.newsIntervalMin)
|
|
3398
|
+
u.newsIntervalMin = p.newsIntervalMin;
|
|
3399
|
+
if (p.xIntervalMin)
|
|
3400
|
+
u.xIntervalMin = p.xIntervalMin;
|
|
3401
|
+
if (p.evalModelTier)
|
|
3402
|
+
u.evalModelTier = p.evalModelTier;
|
|
3403
|
+
if (p.monthlyBudgetUsd !== undefined)
|
|
3404
|
+
u.monthlyBudgetUsd = p.monthlyBudgetUsd;
|
|
3405
|
+
if (p.paused !== undefined)
|
|
3406
|
+
u.paused = p.paused;
|
|
3407
|
+
await sfClient.updateHeartbeatConfig(p.thesisId, u);
|
|
3408
|
+
}
|
|
3409
|
+
const data = await sfClient.getHeartbeatConfig(p.thesisId);
|
|
3410
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
3411
|
+
},
|
|
3348
3412
|
});
|
|
3349
3413
|
// ── Trading tools (conditional on tradingEnabled) for plain mode ──────────
|
|
3350
3414
|
const config = (0, config_js_1.loadConfig)();
|
|
@@ -3449,6 +3513,7 @@ Always state contract expiry and next catalyst. No catalyst = flag capital lock
|
|
|
3449
3513
|
|
|
3450
3514
|
For complex questions, chain: get_context -> inspect_book -> get_liquidity -> web_search -> search_x -> synthesize.
|
|
3451
3515
|
Use search_x for social sentiment on any topic. Use x_volume to detect discussion spikes. Use x_account to track key people.
|
|
3516
|
+
Use heartbeat_config to view/adjust scan intervals, model tier, budget cap, or check cost breakdown.
|
|
3452
3517
|
|
|
3453
3518
|
Flag correlated exposure across positions sharing upstream nodes. If nothing to do, say so.
|
|
3454
3519
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sf heartbeat <thesisId> — View/update per-thesis heartbeat config & costs.
|
|
3
|
+
*
|
|
4
|
+
* Examples:
|
|
5
|
+
* sf heartbeat abc123 — show config + costs
|
|
6
|
+
* sf heartbeat abc123 --news-interval 30 — set news scan to 30 min
|
|
7
|
+
* sf heartbeat abc123 --model heavy — use heavy model for eval
|
|
8
|
+
* sf heartbeat abc123 --budget 5 — $5/month cap
|
|
9
|
+
* sf heartbeat abc123 --pause — pause heartbeat
|
|
10
|
+
* sf heartbeat abc123 --resume — resume heartbeat
|
|
11
|
+
*/
|
|
12
|
+
import type { SFClient } from '../client.js';
|
|
13
|
+
export declare function heartbeatCommand(sfClient: SFClient, thesisId: string, opts: {
|
|
14
|
+
newsInterval?: string;
|
|
15
|
+
xInterval?: string;
|
|
16
|
+
model?: string;
|
|
17
|
+
budget?: string;
|
|
18
|
+
pause?: boolean;
|
|
19
|
+
resume?: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* sf heartbeat <thesisId> — View/update per-thesis heartbeat config & costs.
|
|
4
|
+
*
|
|
5
|
+
* Examples:
|
|
6
|
+
* sf heartbeat abc123 — show config + costs
|
|
7
|
+
* sf heartbeat abc123 --news-interval 30 — set news scan to 30 min
|
|
8
|
+
* sf heartbeat abc123 --model heavy — use heavy model for eval
|
|
9
|
+
* sf heartbeat abc123 --budget 5 — $5/month cap
|
|
10
|
+
* sf heartbeat abc123 --pause — pause heartbeat
|
|
11
|
+
* sf heartbeat abc123 --resume — resume heartbeat
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.heartbeatCommand = heartbeatCommand;
|
|
15
|
+
const utils_js_1 = require("../utils.js");
|
|
16
|
+
async function heartbeatCommand(sfClient, thesisId, opts) {
|
|
17
|
+
// Check if any update flags were passed
|
|
18
|
+
const hasUpdates = opts.newsInterval || opts.xInterval || opts.model || opts.budget !== undefined || opts.pause || opts.resume;
|
|
19
|
+
if (hasUpdates) {
|
|
20
|
+
const updates = {};
|
|
21
|
+
if (opts.newsInterval)
|
|
22
|
+
updates.newsIntervalMin = parseInt(opts.newsInterval, 10);
|
|
23
|
+
if (opts.xInterval)
|
|
24
|
+
updates.xIntervalMin = parseInt(opts.xInterval, 10);
|
|
25
|
+
if (opts.model)
|
|
26
|
+
updates.evalModelTier = opts.model;
|
|
27
|
+
if (opts.budget !== undefined)
|
|
28
|
+
updates.monthlyBudgetUsd = parseFloat(opts.budget);
|
|
29
|
+
if (opts.pause)
|
|
30
|
+
updates.paused = true;
|
|
31
|
+
if (opts.resume)
|
|
32
|
+
updates.paused = false;
|
|
33
|
+
try {
|
|
34
|
+
const result = await sfClient.updateHeartbeatConfig(thesisId, updates);
|
|
35
|
+
console.log(`\n ${utils_js_1.c.green}✓${utils_js_1.c.reset} Updated heartbeat config`);
|
|
36
|
+
console.log(` ${utils_js_1.c.dim}Updated fields: ${result.updated.join(', ')}${utils_js_1.c.reset}\n`);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error(` ${utils_js_1.c.red}✗ ${err.message}${utils_js_1.c.reset}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Always show current config
|
|
44
|
+
try {
|
|
45
|
+
const data = await sfClient.getHeartbeatConfig(thesisId);
|
|
46
|
+
const cfg = data.config;
|
|
47
|
+
const costs = data.costs;
|
|
48
|
+
console.log(`\n ${utils_js_1.c.bold}Heartbeat Config${utils_js_1.c.reset} ${utils_js_1.c.dim}(${thesisId.slice(0, 8)})${utils_js_1.c.reset}`);
|
|
49
|
+
console.log();
|
|
50
|
+
// Config
|
|
51
|
+
const statusIcon = cfg.paused ? `${utils_js_1.c.red}⏸ paused${utils_js_1.c.reset}` : `${utils_js_1.c.green}▶ active${utils_js_1.c.reset}`;
|
|
52
|
+
console.log(` Status ${statusIcon}`);
|
|
53
|
+
console.log(` News interval ${utils_js_1.c.cyan}${cfg.newsIntervalMin}${utils_js_1.c.reset} min ${utils_js_1.c.dim}(${cfg.newsIntervalMin === data.defaults.newsIntervalMin ? 'default' : 'custom'})${utils_js_1.c.reset}`);
|
|
54
|
+
console.log(` X interval ${utils_js_1.c.cyan}${cfg.xIntervalMin}${utils_js_1.c.reset} min ${utils_js_1.c.dim}(${cfg.xIntervalMin === data.defaults.xIntervalMin ? 'default' : 'custom'})${utils_js_1.c.reset}`);
|
|
55
|
+
console.log(` Eval model ${utils_js_1.c.cyan}${cfg.evalModelTier}${utils_js_1.c.reset} ${utils_js_1.c.dim}(${cfg.evalModelTier === data.defaults.evalModelTier ? 'default' : 'custom'})${utils_js_1.c.reset}`);
|
|
56
|
+
console.log(` Monthly budget ${cfg.monthlyBudgetUsd > 0 ? `${utils_js_1.c.cyan}$${cfg.monthlyBudgetUsd}${utils_js_1.c.reset}` : `${utils_js_1.c.dim}unlimited${utils_js_1.c.reset}`}`);
|
|
57
|
+
console.log();
|
|
58
|
+
// Costs
|
|
59
|
+
console.log(` ${utils_js_1.c.bold}This Month${utils_js_1.c.reset}`);
|
|
60
|
+
console.log(` Total cost ${utils_js_1.c.cyan}$${costs.monthlyTotal.toFixed(4)}${utils_js_1.c.reset}`);
|
|
61
|
+
console.log(` LLM calls ${costs.llmCalls}`);
|
|
62
|
+
console.log(` Search calls ${costs.searchCalls}`);
|
|
63
|
+
console.log(` Tokens ${utils_js_1.c.dim}${costs.inputTokens.toLocaleString()} in / ${costs.outputTokens.toLocaleString()} out${utils_js_1.c.reset}`);
|
|
64
|
+
if (costs.budgetRemaining !== null) {
|
|
65
|
+
const pct = cfg.monthlyBudgetUsd > 0 ? Math.round((costs.monthlyTotal / cfg.monthlyBudgetUsd) * 100) : 0;
|
|
66
|
+
console.log(` Budget used ${pct}% ${utils_js_1.c.dim}($${costs.budgetRemaining.toFixed(2)} remaining)${utils_js_1.c.reset}`);
|
|
67
|
+
}
|
|
68
|
+
console.log();
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error(` ${utils_js_1.c.red}✗ ${err.message}${utils_js_1.c.reset}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ const augment_js_1 = require("./commands/augment.js");
|
|
|
59
59
|
const telegram_js_1 = require("./commands/telegram.js");
|
|
60
60
|
const delta_js_1 = require("./commands/delta.js");
|
|
61
61
|
const login_js_1 = require("./commands/login.js");
|
|
62
|
+
const heartbeat_js_1 = require("./commands/heartbeat.js");
|
|
62
63
|
const query_js_1 = require("./commands/query.js");
|
|
63
64
|
const markets_js_1 = require("./commands/markets.js");
|
|
64
65
|
const x_js_1 = require("./commands/x.js");
|
|
@@ -88,6 +89,7 @@ const GROUPED_HELP = `
|
|
|
88
89
|
\x1b[36mevaluate\x1b[39m <id> Trigger deep evaluation
|
|
89
90
|
\x1b[36maugment\x1b[39m <id> Evolve causal tree with new nodes
|
|
90
91
|
\x1b[36mpublish\x1b[39m / \x1b[36munpublish\x1b[39m <id> Manage public visibility
|
|
92
|
+
\x1b[36mheartbeat\x1b[39m <id> View/configure heartbeat settings & costs
|
|
91
93
|
|
|
92
94
|
\x1b[1mSearch\x1b[22m
|
|
93
95
|
\x1b[36mquery\x1b[39m "question" LLM-enhanced market knowledge search \x1b[2m(no auth)\x1b[22m
|
|
@@ -342,6 +344,30 @@ program
|
|
|
342
344
|
const g = cmd.optsWithGlobals();
|
|
343
345
|
await run(() => (0, evaluate_js_1.evaluateCommand)(id, { apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
344
346
|
});
|
|
347
|
+
// ── sf heartbeat <id> ─────────────────────────────────────────────────────────
|
|
348
|
+
program
|
|
349
|
+
.command('heartbeat <id>')
|
|
350
|
+
.description('View/configure per-thesis heartbeat settings and costs')
|
|
351
|
+
.option('--news-interval <min>', 'News scan interval in minutes (15-1440)')
|
|
352
|
+
.option('--x-interval <min>', 'X/social scan interval in minutes (60-1440)')
|
|
353
|
+
.option('--model <tier>', 'Eval model tier: cheap, medium, heavy')
|
|
354
|
+
.option('--budget <usd>', 'Monthly budget cap in USD (0 = unlimited)')
|
|
355
|
+
.option('--pause', 'Pause heartbeat')
|
|
356
|
+
.option('--resume', 'Resume heartbeat')
|
|
357
|
+
.action(async (id, opts, cmd) => {
|
|
358
|
+
const g = cmd.optsWithGlobals();
|
|
359
|
+
await run(() => {
|
|
360
|
+
const client = new client_js_1.SFClient(g.apiKey, g.apiUrl);
|
|
361
|
+
return (0, heartbeat_js_1.heartbeatCommand)(client, id, {
|
|
362
|
+
newsInterval: opts.newsInterval,
|
|
363
|
+
xInterval: opts.xInterval,
|
|
364
|
+
model: opts.model,
|
|
365
|
+
budget: opts.budget,
|
|
366
|
+
pause: opts.pause,
|
|
367
|
+
resume: opts.resume,
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
345
371
|
// ── sf scan [query] ───────────────────────────────────────────────────────────
|
|
346
372
|
program
|
|
347
373
|
.command('scan [query]')
|
|
@@ -362,6 +362,36 @@ async function buildTools(sfClient, thesisId, latestContext) {
|
|
|
362
362
|
const data = await sfClient.getXAccount(p.username, { hours: p.hours });
|
|
363
363
|
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
364
364
|
},
|
|
365
|
+
}, {
|
|
366
|
+
name: 'heartbeat_config', label: 'Heartbeat Config',
|
|
367
|
+
description: 'View or update heartbeat settings: scan intervals, model tier, budget cap, pause/resume. Shows cost breakdown.',
|
|
368
|
+
parameters: Type.Object({
|
|
369
|
+
thesisId: Type.String({ description: 'Thesis ID' }),
|
|
370
|
+
newsIntervalMin: Type.Optional(Type.Number({ description: 'News scan interval (15-1440 min)' })),
|
|
371
|
+
xIntervalMin: Type.Optional(Type.Number({ description: 'X scan interval (60-1440 min)' })),
|
|
372
|
+
evalModelTier: Type.Optional(Type.String({ description: 'cheap, medium, or heavy' })),
|
|
373
|
+
monthlyBudgetUsd: Type.Optional(Type.Number({ description: 'Monthly budget (0 = unlimited)' })),
|
|
374
|
+
paused: Type.Optional(Type.Boolean({ description: 'Pause or resume heartbeat' })),
|
|
375
|
+
}),
|
|
376
|
+
execute: async (_id, p) => {
|
|
377
|
+
const hasUp = p.newsIntervalMin || p.xIntervalMin || p.evalModelTier || p.monthlyBudgetUsd !== undefined || p.paused !== undefined;
|
|
378
|
+
if (hasUp) {
|
|
379
|
+
const u = {};
|
|
380
|
+
if (p.newsIntervalMin)
|
|
381
|
+
u.newsIntervalMin = p.newsIntervalMin;
|
|
382
|
+
if (p.xIntervalMin)
|
|
383
|
+
u.xIntervalMin = p.xIntervalMin;
|
|
384
|
+
if (p.evalModelTier)
|
|
385
|
+
u.evalModelTier = p.evalModelTier;
|
|
386
|
+
if (p.monthlyBudgetUsd !== undefined)
|
|
387
|
+
u.monthlyBudgetUsd = p.monthlyBudgetUsd;
|
|
388
|
+
if (p.paused !== undefined)
|
|
389
|
+
u.paused = p.paused;
|
|
390
|
+
await sfClient.updateHeartbeatConfig(p.thesisId, u);
|
|
391
|
+
}
|
|
392
|
+
const data = await sfClient.getHeartbeatConfig(p.thesisId);
|
|
393
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
394
|
+
},
|
|
365
395
|
});
|
|
366
396
|
// Trading tools (only if enabled)
|
|
367
397
|
if (config.tradingEnabled) {
|
|
@@ -470,6 +500,7 @@ Price: depth >= 500 = consensus, < 100 = unreliable, spread > 5 = noisy.
|
|
|
470
500
|
- Prices in cents (¢). P&L in dollars ($). Don't re-convert tool output units.
|
|
471
501
|
- Call tools for fresh data. Never guess prices or P&L from this prompt.
|
|
472
502
|
- Use search_x for X/Twitter sentiment. Use x_volume for discussion spikes. Use x_account to track key people.
|
|
503
|
+
- Use heartbeat_config to view/adjust scan intervals, model tier, budget cap, or check cost breakdown.
|
|
473
504
|
- You don't know user's positions. Call get_positions before discussing trades.
|
|
474
505
|
- If user mentions news, inject_signal immediately. Don't ask "should I?"
|
|
475
506
|
- If user says "evaluate" or "run it", trigger immediately.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spfunctions/cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.14",
|
|
4
4
|
"description": "Prediction market intelligence CLI. Causal thesis model, 24/7 Kalshi/Polymarket scan, live orderbook, edge detection. Interactive agent mode with tool calling.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sf": "./dist/index.js"
|