opencandle 0.1.1 → 0.2.0

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.
Files changed (179) hide show
  1. package/README.md +13 -4
  2. package/dist/analysts/contracts.d.ts +31 -0
  3. package/dist/analysts/contracts.js +158 -0
  4. package/dist/analysts/contracts.js.map +1 -0
  5. package/dist/analysts/orchestrator.d.ts +11 -2
  6. package/dist/analysts/orchestrator.js +155 -7
  7. package/dist/analysts/orchestrator.js.map +1 -1
  8. package/dist/cli.js +26 -10
  9. package/dist/cli.js.map +1 -1
  10. package/dist/config.d.ts +4 -0
  11. package/dist/config.js +2 -0
  12. package/dist/config.js.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/infra/cache.d.ts +30 -0
  17. package/dist/infra/cache.js +40 -3
  18. package/dist/infra/cache.js.map +1 -1
  19. package/dist/infra/index.d.ts +1 -1
  20. package/dist/infra/index.js +1 -1
  21. package/dist/infra/index.js.map +1 -1
  22. package/dist/infra/opencandle-paths.d.ts +1 -0
  23. package/dist/infra/opencandle-paths.js +3 -0
  24. package/dist/infra/opencandle-paths.js.map +1 -1
  25. package/dist/infra/rate-limiter.js +1 -0
  26. package/dist/infra/rate-limiter.js.map +1 -1
  27. package/dist/memory/index.d.ts +3 -0
  28. package/dist/memory/index.js +2 -0
  29. package/dist/memory/index.js.map +1 -1
  30. package/dist/memory/manager.d.ts +19 -0
  31. package/dist/memory/manager.js +132 -0
  32. package/dist/memory/manager.js.map +1 -0
  33. package/dist/memory/sqlite.js +12 -1
  34. package/dist/memory/sqlite.js.map +1 -1
  35. package/dist/memory/types.d.ts +21 -0
  36. package/dist/memory/types.js +47 -0
  37. package/dist/memory/types.js.map +1 -0
  38. package/dist/pi/opencandle-extension.d.ts +5 -1
  39. package/dist/pi/opencandle-extension.js +45 -142
  40. package/dist/pi/opencandle-extension.js.map +1 -1
  41. package/dist/pi/session.d.ts +2 -0
  42. package/dist/pi/session.js +1 -1
  43. package/dist/pi/session.js.map +1 -1
  44. package/dist/prompts/context-builder.d.ts +26 -0
  45. package/dist/prompts/context-builder.js +126 -0
  46. package/dist/prompts/context-builder.js.map +1 -0
  47. package/dist/prompts/sections.d.ts +13 -0
  48. package/dist/prompts/sections.js +35 -0
  49. package/dist/prompts/sections.js.map +1 -0
  50. package/dist/providers/alpha-vantage.d.ts +3 -0
  51. package/dist/providers/alpha-vantage.js +184 -76
  52. package/dist/providers/alpha-vantage.js.map +1 -1
  53. package/dist/providers/coingecko.js +53 -37
  54. package/dist/providers/coingecko.js.map +1 -1
  55. package/dist/providers/fear-greed.js +23 -15
  56. package/dist/providers/fear-greed.js.map +1 -1
  57. package/dist/providers/fred.js +35 -27
  58. package/dist/providers/fred.js.map +1 -1
  59. package/dist/providers/reddit.js +44 -36
  60. package/dist/providers/reddit.js.map +1 -1
  61. package/dist/providers/twitter.d.ts +20 -0
  62. package/dist/providers/twitter.js +143 -0
  63. package/dist/providers/twitter.js.map +1 -0
  64. package/dist/providers/with-fallback.d.ts +15 -0
  65. package/dist/providers/with-fallback.js +32 -0
  66. package/dist/providers/with-fallback.js.map +1 -0
  67. package/dist/providers/wrap-provider.d.ts +13 -0
  68. package/dist/providers/wrap-provider.js +43 -0
  69. package/dist/providers/wrap-provider.js.map +1 -0
  70. package/dist/providers/yahoo-finance.js +77 -57
  71. package/dist/providers/yahoo-finance.js.map +1 -1
  72. package/dist/runtime/evidence.d.ts +35 -0
  73. package/dist/runtime/evidence.js +29 -0
  74. package/dist/runtime/evidence.js.map +1 -0
  75. package/dist/runtime/index.d.ts +16 -0
  76. package/dist/runtime/index.js +10 -0
  77. package/dist/runtime/index.js.map +1 -0
  78. package/dist/runtime/prompt-step.d.ts +41 -0
  79. package/dist/runtime/prompt-step.js +42 -0
  80. package/dist/runtime/prompt-step.js.map +1 -0
  81. package/dist/runtime/provider-ids.d.ts +14 -0
  82. package/dist/runtime/provider-ids.js +14 -0
  83. package/dist/runtime/provider-ids.js.map +1 -0
  84. package/dist/runtime/provider-tracker.d.ts +20 -0
  85. package/dist/runtime/provider-tracker.js +36 -0
  86. package/dist/runtime/provider-tracker.js.map +1 -0
  87. package/dist/runtime/run-context.d.ts +11 -0
  88. package/dist/runtime/run-context.js +14 -0
  89. package/dist/runtime/run-context.js.map +1 -0
  90. package/dist/runtime/session-coordinator.d.ts +48 -0
  91. package/dist/runtime/session-coordinator.js +171 -0
  92. package/dist/runtime/session-coordinator.js.map +1 -0
  93. package/dist/runtime/validation.d.ts +44 -0
  94. package/dist/runtime/validation.js +157 -0
  95. package/dist/runtime/validation.js.map +1 -0
  96. package/dist/runtime/workflow-events.d.ts +21 -0
  97. package/dist/runtime/workflow-events.js +31 -0
  98. package/dist/runtime/workflow-events.js.map +1 -0
  99. package/dist/runtime/workflow-runner.d.ts +36 -0
  100. package/dist/runtime/workflow-runner.js +129 -0
  101. package/dist/runtime/workflow-runner.js.map +1 -0
  102. package/dist/runtime/workflow-types.d.ts +60 -0
  103. package/dist/runtime/workflow-types.js +32 -0
  104. package/dist/runtime/workflow-types.js.map +1 -0
  105. package/dist/system-prompt.js +52 -2
  106. package/dist/system-prompt.js.map +1 -1
  107. package/dist/tool-kit.d.ts +9 -5
  108. package/dist/tool-kit.js +29 -6
  109. package/dist/tool-kit.js.map +1 -1
  110. package/dist/tools/fundamentals/company-overview.js +13 -2
  111. package/dist/tools/fundamentals/company-overview.js.map +1 -1
  112. package/dist/tools/fundamentals/comps.js +15 -7
  113. package/dist/tools/fundamentals/comps.js.map +1 -1
  114. package/dist/tools/fundamentals/dcf.js +23 -5
  115. package/dist/tools/fundamentals/dcf.js.map +1 -1
  116. package/dist/tools/fundamentals/earnings.js +9 -1
  117. package/dist/tools/fundamentals/earnings.js.map +1 -1
  118. package/dist/tools/fundamentals/financials.js +9 -1
  119. package/dist/tools/fundamentals/financials.js.map +1 -1
  120. package/dist/tools/fundamentals/sec-filings.js +9 -1
  121. package/dist/tools/fundamentals/sec-filings.js.map +1 -1
  122. package/dist/tools/index.js +2 -0
  123. package/dist/tools/index.js.map +1 -1
  124. package/dist/tools/interaction/ask-user.d.ts +3 -0
  125. package/dist/tools/interaction/ask-user.js +87 -0
  126. package/dist/tools/interaction/ask-user.js.map +1 -0
  127. package/dist/tools/interaction/twitter-login.d.ts +8 -0
  128. package/dist/tools/interaction/twitter-login.js +77 -0
  129. package/dist/tools/interaction/twitter-login.js.map +1 -0
  130. package/dist/tools/macro/fear-greed.js +9 -1
  131. package/dist/tools/macro/fear-greed.js.map +1 -1
  132. package/dist/tools/macro/fred-data.js +13 -2
  133. package/dist/tools/macro/fred-data.js.map +1 -1
  134. package/dist/tools/market/crypto-history.js +9 -1
  135. package/dist/tools/market/crypto-history.js.map +1 -1
  136. package/dist/tools/market/crypto-price.js +9 -1
  137. package/dist/tools/market/crypto-price.js.map +1 -1
  138. package/dist/tools/market/stock-history.js +28 -1
  139. package/dist/tools/market/stock-history.js.map +1 -1
  140. package/dist/tools/market/stock-quote.js +29 -4
  141. package/dist/tools/market/stock-quote.js.map +1 -1
  142. package/dist/tools/options/option-chain.js +9 -1
  143. package/dist/tools/options/option-chain.js.map +1 -1
  144. package/dist/tools/portfolio/correlation.js +15 -3
  145. package/dist/tools/portfolio/correlation.js.map +1 -1
  146. package/dist/tools/portfolio/predictions.js +6 -5
  147. package/dist/tools/portfolio/predictions.js.map +1 -1
  148. package/dist/tools/portfolio/risk-analysis.js +9 -1
  149. package/dist/tools/portfolio/risk-analysis.js.map +1 -1
  150. package/dist/tools/portfolio/tracker.js +6 -3
  151. package/dist/tools/portfolio/tracker.js.map +1 -1
  152. package/dist/tools/portfolio/watchlist.js +6 -1
  153. package/dist/tools/portfolio/watchlist.js.map +1 -1
  154. package/dist/tools/sentiment/news-sentiment.js +8 -10
  155. package/dist/tools/sentiment/news-sentiment.js.map +1 -1
  156. package/dist/tools/sentiment/reddit-sentiment.js +9 -1
  157. package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
  158. package/dist/tools/sentiment/twitter-sentiment.d.ts +9 -0
  159. package/dist/tools/sentiment/twitter-sentiment.js +58 -0
  160. package/dist/tools/sentiment/twitter-sentiment.js.map +1 -0
  161. package/dist/tools/technical/backtest.js +9 -1
  162. package/dist/tools/technical/backtest.js.map +1 -1
  163. package/dist/tools/technical/indicators.js +9 -1
  164. package/dist/tools/technical/indicators.js.map +1 -1
  165. package/dist/types/index.d.ts +15 -0
  166. package/dist/types/sentiment.d.ts +20 -0
  167. package/dist/workflows/compare-assets.d.ts +3 -0
  168. package/dist/workflows/compare-assets.js +21 -5
  169. package/dist/workflows/compare-assets.js.map +1 -1
  170. package/dist/workflows/index.d.ts +3 -3
  171. package/dist/workflows/index.js +3 -3
  172. package/dist/workflows/index.js.map +1 -1
  173. package/dist/workflows/options-screener.d.ts +3 -0
  174. package/dist/workflows/options-screener.js +24 -7
  175. package/dist/workflows/options-screener.js.map +1 -1
  176. package/dist/workflows/portfolio-builder.d.ts +3 -0
  177. package/dist/workflows/portfolio-builder.js +30 -9
  178. package/dist/workflows/portfolio-builder.js.map +1 -1
  179. package/package.json +9 -5
@@ -0,0 +1,157 @@
1
+ /** Create an empty validation result. */
2
+ export function emptyValidationResult() {
3
+ return { passes: [], failures: [], warnings: [] };
4
+ }
5
+ /** Check that market-sensitive evidence records have timestamps. */
6
+ export function checkTimestamps(evidence, marketSensitiveLabels) {
7
+ const warnings = [];
8
+ for (const record of evidence) {
9
+ if (marketSensitiveLabels.has(record.label) &&
10
+ record.provenance.source === "fetched" &&
11
+ !record.provenance.timestamp) {
12
+ warnings.push({
13
+ message: `Market-sensitive value '${record.label}' has no timestamp`,
14
+ evidenceLabel: record.label,
15
+ });
16
+ }
17
+ }
18
+ return warnings;
19
+ }
20
+ /** Check that options expiry dates are in the future. */
21
+ export function checkOptionsExpiries(evidence, today) {
22
+ const failures = [];
23
+ for (const record of evidence) {
24
+ if (record.label.toLowerCase().includes("expir") &&
25
+ typeof record.value === "string" &&
26
+ record.value < today) {
27
+ failures.push({
28
+ message: `Options expiry ${record.value} is in the past`,
29
+ evidenceLabel: record.label,
30
+ detail: `Today is ${today}`,
31
+ });
32
+ }
33
+ }
34
+ return failures;
35
+ }
36
+ /** Check that all required fields have evidence records. */
37
+ export function checkRequiredFields(evidence, requiredLabels) {
38
+ const present = new Set(evidence.map((e) => e.label));
39
+ const failures = [];
40
+ for (const label of requiredLabels) {
41
+ if (!present.has(label)) {
42
+ failures.push({
43
+ message: `Required field '${label}' has no evidence record`,
44
+ evidenceLabel: label,
45
+ });
46
+ }
47
+ }
48
+ return failures;
49
+ }
50
+ /** Default market-sensitive labels. */
51
+ export const DEFAULT_MARKET_SENSITIVE_LABELS = new Set([
52
+ "Stock Price",
53
+ "Volume",
54
+ "Market Cap",
55
+ "52-Week High",
56
+ "52-Week Low",
57
+ "Bid",
58
+ "Ask",
59
+ "Day High",
60
+ "Day Low",
61
+ "Open",
62
+ "Previous Close",
63
+ "Crypto Price",
64
+ "Crypto Volume",
65
+ ]);
66
+ /**
67
+ * Orchestrates all deterministic validation checks on evidence records.
68
+ * Runs before LLM-based validation.
69
+ */
70
+ export class RuntimeValidator {
71
+ config;
72
+ constructor(config = {}) {
73
+ this.config = config;
74
+ }
75
+ /** Run all validation checks and return a combined result. */
76
+ validate(evidence) {
77
+ const result = emptyValidationResult();
78
+ // Timestamp checks
79
+ const timestampWarnings = checkTimestamps(evidence, this.config.marketSensitiveLabels ?? DEFAULT_MARKET_SENSITIVE_LABELS);
80
+ result.warnings.push(...timestampWarnings);
81
+ // Options expiry checks
82
+ const today = this.config.today ?? new Date().toISOString().slice(0, 10);
83
+ const expiryFailures = checkOptionsExpiries(evidence, today);
84
+ result.failures.push(...expiryFailures);
85
+ // Required field checks
86
+ if (this.config.requiredFields) {
87
+ const fieldFailures = checkRequiredFields(evidence, this.config.requiredFields);
88
+ result.failures.push(...fieldFailures);
89
+ }
90
+ // Number match checks
91
+ if (this.config.toolResults) {
92
+ const numberEntries = checkNumberMatch(evidence, this.config.toolResults);
93
+ for (const entry of numberEntries) {
94
+ if (entry.type === "pass") {
95
+ result.passes.push(entry);
96
+ }
97
+ else {
98
+ result.failures.push(entry);
99
+ }
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+ /** Format validation results as a summary string for the LLM validation prompt. */
105
+ formatForLLM(result) {
106
+ const lines = ["## Deterministic Validation Results"];
107
+ if (result.failures.length > 0) {
108
+ lines.push(`\n### Failures (${result.failures.length})`);
109
+ for (const f of result.failures) {
110
+ lines.push(`- ${f.message}`);
111
+ }
112
+ }
113
+ if (result.warnings.length > 0) {
114
+ lines.push(`\n### Warnings (${result.warnings.length})`);
115
+ for (const w of result.warnings) {
116
+ lines.push(`- ${w.message}`);
117
+ }
118
+ }
119
+ if (result.passes.length > 0) {
120
+ lines.push(`\n### Verified (${result.passes.length})`);
121
+ for (const p of result.passes) {
122
+ lines.push(`- ${p.message}`);
123
+ }
124
+ }
125
+ if (result.failures.length === 0 && result.warnings.length === 0) {
126
+ lines.push("\nAll deterministic checks passed.");
127
+ }
128
+ return lines.join("\n");
129
+ }
130
+ }
131
+ /** Check that evidence values match expected tool result values. */
132
+ export function checkNumberMatch(evidence, toolResults) {
133
+ const results = [];
134
+ for (const record of evidence) {
135
+ if (typeof record.value !== "number")
136
+ continue;
137
+ const expected = toolResults.get(record.label);
138
+ if (expected === undefined)
139
+ continue;
140
+ if (record.value === expected) {
141
+ results.push({
142
+ type: "pass",
143
+ message: `${record.label}: ${record.value} matches tool result`,
144
+ evidenceLabel: record.label,
145
+ });
146
+ }
147
+ else {
148
+ results.push({
149
+ type: "failure",
150
+ message: `${record.label} mismatch: evidence says ${record.value}, tool returned ${expected}`,
151
+ evidenceLabel: record.label,
152
+ });
153
+ }
154
+ }
155
+ return results;
156
+ }
157
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/runtime/validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type Database from "better-sqlite3";
2
+ /** All workflow event types. */
3
+ export type WorkflowEventType = "workflow_started" | "slot_resolved" | "clarification_asked" | "clarification_answered" | "step_started" | "step_completed" | "step_failed" | "step_skipped" | "tool_called" | "tool_failed" | "validation_passed" | "validation_failed" | "workflow_completed" | "workflow_cancelled";
4
+ /** A persisted workflow event row. */
5
+ export interface WorkflowEvent {
6
+ id: number;
7
+ runId: string;
8
+ stepIndex: number;
9
+ eventType: WorkflowEventType;
10
+ payloadJson: string | null;
11
+ timestamp: string;
12
+ }
13
+ /** Append-only workflow event logger backed by SQLite. */
14
+ export declare class WorkflowEventLogger {
15
+ private readonly db;
16
+ constructor(db: Database.Database);
17
+ /** Append a workflow event. */
18
+ log(runId: string, stepIndex: number, eventType: WorkflowEventType, payload?: Record<string, unknown>): void;
19
+ /** Query all events for a given run ID, ordered by timestamp. */
20
+ getEventsByRunId(runId: string): WorkflowEvent[];
21
+ }
@@ -0,0 +1,31 @@
1
+ /** Append-only workflow event logger backed by SQLite. */
2
+ export class WorkflowEventLogger {
3
+ db;
4
+ constructor(db) {
5
+ this.db = db;
6
+ }
7
+ /** Append a workflow event. */
8
+ log(runId, stepIndex, eventType, payload) {
9
+ const now = new Date().toISOString();
10
+ const payloadJson = payload ? JSON.stringify(payload) : null;
11
+ this.db
12
+ .prepare(`INSERT INTO workflow_events (run_id, step_index, event_type, payload_json, timestamp)
13
+ VALUES (?, ?, ?, ?, ?)`)
14
+ .run(runId, stepIndex, eventType, payloadJson, now);
15
+ }
16
+ /** Query all events for a given run ID, ordered by timestamp. */
17
+ getEventsByRunId(runId) {
18
+ const rows = this.db
19
+ .prepare("SELECT id, run_id, step_index, event_type, payload_json, timestamp FROM workflow_events WHERE run_id = ? ORDER BY id")
20
+ .all(runId);
21
+ return rows.map((r) => ({
22
+ id: r.id,
23
+ runId: r.run_id,
24
+ stepIndex: r.step_index,
25
+ eventType: r.event_type,
26
+ payloadJson: r.payload_json,
27
+ timestamp: r.timestamp,
28
+ }));
29
+ }
30
+ }
31
+ //# sourceMappingURL=workflow-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-events.js","sourceRoot":"","sources":["../../src/runtime/workflow-events.ts"],"names":[],"mappings":"AA6BA,0DAA0D;AAC1D,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;IAAG,CAAC;IAEtD,+BAA+B;IAC/B,GAAG,CACD,KAAa,EACb,SAAiB,EACjB,SAA4B,EAC5B,OAAiC;QAEjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7D,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;gCACwB,CACzB;aACA,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,iEAAiE;IACjE,gBAAgB,CAAC,KAAa;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN,sHAAsH,CACvH;aACA,GAAG,CAAC,KAAK,CAOR,CAAC;QAEL,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,MAAM;YACf,SAAS,EAAE,CAAC,CAAC,UAAU;YACvB,SAAS,EAAE,CAAC,CAAC,UAA+B;YAC5C,WAAW,EAAE,CAAC,CAAC,YAAY;YAC3B,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;CACF"}
@@ -0,0 +1,36 @@
1
+ import type { WorkflowRun, StepOutput, WorkflowStep } from "./workflow-types.js";
2
+ import type { WorkflowEventLogger } from "./workflow-events.js";
3
+ import type { ProviderTracker } from "./provider-tracker.js";
4
+ import type { EvidenceRecord } from "./evidence.js";
5
+ /** Function that executes a single workflow step. */
6
+ export type StepExecutor = (step: WorkflowStep, stepIndex: number, priorEvidence: EvidenceRecord[], context: StepExecutionContext) => Promise<StepOutput>;
7
+ /** Context passed to step executors. */
8
+ export interface StepExecutionContext {
9
+ runId: string;
10
+ providerTracker: ProviderTracker;
11
+ }
12
+ /** Options for creating a WorkflowRunner. */
13
+ export interface WorkflowRunnerOptions {
14
+ eventLogger?: WorkflowEventLogger;
15
+ providerTracker?: ProviderTracker;
16
+ }
17
+ /**
18
+ * Typed workflow execution engine with run IDs, step definitions,
19
+ * state transitions, cancellation, and event logging.
20
+ */
21
+ export declare class WorkflowRunner {
22
+ private readonly eventLogger?;
23
+ private readonly providerTracker?;
24
+ private activeRun;
25
+ constructor(options?: WorkflowRunnerOptions);
26
+ /** Get the currently active run, if any. */
27
+ getActiveRun(): WorkflowRun | null;
28
+ /**
29
+ * Start a new workflow run. If a run is already active, it is cancelled first.
30
+ */
31
+ start(workflowType: string, stepDefinitions: Omit<WorkflowStep, "status">[], executor: StepExecutor): Promise<WorkflowRun>;
32
+ /** Cancel the active run. */
33
+ cancel(): void;
34
+ private executeSteps;
35
+ private logEvent;
36
+ }
@@ -0,0 +1,129 @@
1
+ import { createWorkflowRun, transitionStepStatus, } from "./workflow-types.js";
2
+ let runCounter = 0;
3
+ function generateRunId() {
4
+ runCounter += 1;
5
+ return `run_${Date.now()}_${runCounter}`;
6
+ }
7
+ /**
8
+ * Typed workflow execution engine with run IDs, step definitions,
9
+ * state transitions, cancellation, and event logging.
10
+ */
11
+ export class WorkflowRunner {
12
+ eventLogger;
13
+ providerTracker;
14
+ activeRun = null;
15
+ constructor(options = {}) {
16
+ this.eventLogger = options.eventLogger;
17
+ this.providerTracker = options.providerTracker;
18
+ }
19
+ /** Get the currently active run, if any. */
20
+ getActiveRun() {
21
+ return this.activeRun;
22
+ }
23
+ /**
24
+ * Start a new workflow run. If a run is already active, it is cancelled first.
25
+ */
26
+ async start(workflowType, stepDefinitions, executor) {
27
+ // Cancel any active run
28
+ if (this.activeRun && this.activeRun.status === "running") {
29
+ this.cancel();
30
+ }
31
+ const runId = generateRunId();
32
+ const run = createWorkflowRun(runId, workflowType, stepDefinitions);
33
+ this.activeRun = run;
34
+ run.status = "running";
35
+ this.providerTracker?.resetAll();
36
+ this.logEvent(runId, 0, "workflow_started", {
37
+ workflowType,
38
+ stepCount: stepDefinitions.length,
39
+ });
40
+ // Execute steps
41
+ await this.executeSteps(run, executor);
42
+ return run;
43
+ }
44
+ /** Cancel the active run. */
45
+ cancel() {
46
+ const run = this.activeRun;
47
+ if (!run || run.status !== "running")
48
+ return;
49
+ for (let i = run.currentStepIndex; i < run.steps.length; i++) {
50
+ const step = run.steps[i];
51
+ if (step.status === "pending" || step.status === "running") {
52
+ step.status = transitionStepStatus(step.status, "skipped");
53
+ this.logEvent(run.runId, i, "step_skipped", {
54
+ stepType: step.stepType,
55
+ reason: "cancelled",
56
+ });
57
+ }
58
+ }
59
+ run.status = "cancelled";
60
+ this.logEvent(run.runId, run.currentStepIndex, "workflow_cancelled", {
61
+ cancelledAtStep: run.currentStepIndex,
62
+ });
63
+ }
64
+ async executeSteps(run, executor) {
65
+ for (let i = 0; i < run.steps.length; i++) {
66
+ // Check if run was cancelled externally
67
+ if (run.status !== "running")
68
+ return;
69
+ const step = run.steps[i];
70
+ run.currentStepIndex = i;
71
+ // Collect all prior evidence
72
+ const priorEvidence = [];
73
+ for (const [, output] of run.stepOutputs) {
74
+ priorEvidence.push(...output.evidence);
75
+ }
76
+ // Transition to running
77
+ step.status = transitionStepStatus(step.status, "running");
78
+ this.logEvent(run.runId, i, "step_started", { stepType: step.stepType });
79
+ try {
80
+ const context = {
81
+ runId: run.runId,
82
+ providerTracker: this.providerTracker,
83
+ };
84
+ const output = await executor(step, i, priorEvidence, context);
85
+ // If run was cancelled during execution, stop without further transitions
86
+ if (run.status !== "running")
87
+ return;
88
+ step.status = transitionStepStatus(step.status, "completed");
89
+ run.stepOutputs.set(i, output);
90
+ this.logEvent(run.runId, i, "step_completed", {
91
+ stepType: step.stepType,
92
+ evidenceCount: output.evidence.length,
93
+ });
94
+ }
95
+ catch (error) {
96
+ // If run was cancelled during execution, stop without further transitions
97
+ if (run.status !== "running")
98
+ return;
99
+ const message = error instanceof Error ? error.message : "unknown_error";
100
+ if (step.skippable) {
101
+ step.status = transitionStepStatus(step.status, "skipped");
102
+ this.logEvent(run.runId, i, "step_skipped", {
103
+ stepType: step.stepType,
104
+ reason: message,
105
+ });
106
+ }
107
+ else {
108
+ step.status = transitionStepStatus(step.status, "failed");
109
+ this.logEvent(run.runId, i, "step_failed", {
110
+ stepType: step.stepType,
111
+ error: message,
112
+ });
113
+ run.status = "failed";
114
+ return;
115
+ }
116
+ }
117
+ }
118
+ if (run.status === "running") {
119
+ run.status = "completed";
120
+ this.logEvent(run.runId, run.steps.length - 1, "workflow_completed", {
121
+ workflowType: run.workflowType,
122
+ });
123
+ }
124
+ }
125
+ logEvent(runId, stepIndex, eventType, payload) {
126
+ this.eventLogger?.log(runId, stepIndex, eventType, payload);
127
+ }
128
+ }
129
+ //# sourceMappingURL=workflow-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-runner.js","sourceRoot":"","sources":["../../src/runtime/workflow-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { EvidenceRecord } from "./evidence.js";
2
+ /** Status of a single workflow step. */
3
+ export type StepStatus = "pending" | "running" | "completed" | "failed" | "skipped";
4
+ /** Overall status of a workflow run. */
5
+ export type RunStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
6
+ /** Check whether a step status transition is valid. */
7
+ export declare function isValidStepTransition(from: StepStatus, to: StepStatus): boolean;
8
+ /** Transition a step status, throwing on invalid transitions. */
9
+ export declare function transitionStepStatus(from: StepStatus, to: StepStatus): StepStatus;
10
+ /** Definition of a single workflow step. */
11
+ export interface WorkflowStep {
12
+ stepType: string;
13
+ description: string;
14
+ requiredInputs: string[];
15
+ expectedOutputs: string[];
16
+ skippable: boolean;
17
+ status: StepStatus;
18
+ }
19
+ /** Output produced by a completed workflow step. */
20
+ export interface StepOutput {
21
+ stepIndex: number;
22
+ stepType: string;
23
+ evidence: EvidenceRecord[];
24
+ rawText?: string;
25
+ }
26
+ /** Analyst signal direction. */
27
+ export type AnalystSignal = "BUY" | "HOLD" | "SELL";
28
+ /** Structured output from a single analyst role. */
29
+ export interface AnalystOutput {
30
+ role: string;
31
+ signal: AnalystSignal;
32
+ conviction: number;
33
+ thesis: string;
34
+ evidence: EvidenceRecord[];
35
+ rawText?: string;
36
+ }
37
+ /** Debate side in bull/bear adversarial debate. */
38
+ export type DebateSide = "bull" | "bear";
39
+ /** Structured output from a debate step (eval/test only — not used in live path). */
40
+ export interface DebateOutput {
41
+ side: DebateSide;
42
+ thesis: string;
43
+ keyRisk: string;
44
+ concessions: string[];
45
+ remainingConviction: number;
46
+ evidence: EvidenceRecord[];
47
+ rawText: string;
48
+ }
49
+ /** A complete workflow run definition and state. */
50
+ export interface WorkflowRun {
51
+ runId: string;
52
+ workflowType: string;
53
+ steps: WorkflowStep[];
54
+ currentStepIndex: number;
55
+ status: RunStatus;
56
+ stepOutputs: Map<number, StepOutput>;
57
+ createdAt: string;
58
+ }
59
+ /** Create a new workflow run with all steps in pending state. */
60
+ export declare function createWorkflowRun(runId: string, workflowType: string, stepDefinitions: Omit<WorkflowStep, "status">[]): WorkflowRun;
@@ -0,0 +1,32 @@
1
+ /** Valid step status transitions. */
2
+ const VALID_STEP_TRANSITIONS = {
3
+ pending: ["running", "skipped"],
4
+ running: ["completed", "failed", "skipped"],
5
+ completed: [],
6
+ failed: [],
7
+ skipped: [],
8
+ };
9
+ /** Check whether a step status transition is valid. */
10
+ export function isValidStepTransition(from, to) {
11
+ return VALID_STEP_TRANSITIONS[from].includes(to);
12
+ }
13
+ /** Transition a step status, throwing on invalid transitions. */
14
+ export function transitionStepStatus(from, to) {
15
+ if (!isValidStepTransition(from, to)) {
16
+ throw new Error(`Invalid step transition: ${from} → ${to}`);
17
+ }
18
+ return to;
19
+ }
20
+ /** Create a new workflow run with all steps in pending state. */
21
+ export function createWorkflowRun(runId, workflowType, stepDefinitions) {
22
+ return {
23
+ runId,
24
+ workflowType,
25
+ steps: stepDefinitions.map((def) => ({ ...def, status: "pending" })),
26
+ currentStepIndex: 0,
27
+ status: "pending",
28
+ stepOutputs: new Map(),
29
+ createdAt: new Date().toISOString(),
30
+ };
31
+ }
32
+ //# sourceMappingURL=workflow-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-types.js","sourceRoot":"","sources":["../../src/runtime/workflow-types.ts"],"names":[],"mappings":"AAQA,qCAAqC;AACrC,MAAM,sBAAsB,GAAqC;IAC/D,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;IAC/B,OAAO,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC;IAC3C,SAAS,EAAE,EAAE;IACb,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF,uDAAuD;AACvD,MAAM,UAAU,qBAAqB,CAAC,IAAgB,EAAE,EAAc;IACpE,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,oBAAoB,CAAC,IAAgB,EAAE,EAAc;IACnE,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AA0DD,iEAAiE;AACjE,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,YAAoB,EACpB,eAA+C;IAE/C,OAAO;QACL,KAAK;QACL,YAAY;QACZ,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,SAAkB,EAAE,CAAC,CAAC;QAC7E,gBAAgB,EAAE,CAAC;QACnB,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,IAAI,GAAG,EAAE;QACtB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
@@ -16,9 +16,10 @@ You provide data-driven analysis for stocks, crypto, macro economics, and portfo
16
16
  - **Fundamentals**: get_company_overview, get_financials, get_earnings, compute_dcf, compare_companies, get_sec_filings — company financials, valuation metrics, DCF intrinsic value, peer comparison, and SEC EDGAR filings (10-K, 10-Q, 8-K)
17
17
  - **Technical Analysis**: get_technical_indicators, backtest_strategy — SMA, EMA, RSI, MACD, Bollinger Bands, OBV, VWAP computed from price data, plus simple strategy backtesting
18
18
  - **Macro**: get_economic_data, get_fear_greed — FRED economic indicators and market sentiment
19
- - **Sentiment**: get_reddit_sentiment, get_reddit_discussions — retail sentiment from financial Reddit communities
19
+ - **Sentiment**: get_reddit_sentiment, get_reddit_discussions, get_twitter_sentiment — retail sentiment from Reddit and Twitter/X
20
20
  - **Options**: get_option_chain — full options chain with strikes, bids/asks, volume, OI, IV, and computed Greeks (delta, gamma, theta, vega, rho)
21
21
  - **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, track_prediction — position tracking, P&L, Sharpe ratio, VaR, watchlist with price alerts, correlation matrix, and prediction tracking with accuracy scoring
22
+ - **User Interaction**: ask_user — ask clarification questions; trigger_twitter_login — open a browser for Twitter/X login
22
23
 
23
24
  ## Analytical Framework
24
25
  When analyzing a stock, follow these steps in order:
@@ -29,7 +30,7 @@ When analyzing a stock, follow these steps in order:
29
30
  5. **SYNTHESIS**: State your reasoning chain explicitly: "Because [data point] + [data point], I conclude [thesis]."
30
31
 
31
32
  ## Guidelines
32
- - Always fetch data with tools before stating prices, ratios, or metrics. Never guess financial numbers.
33
+ - Always fetch data with tools before stating prices, ratios, or metrics. Never guess financial numbers. Every substantive response should be backed by at least one tool call — if you find yourself writing a response with zero tool calls, stop and think about what data would make it better.
33
34
  - For options analysis, use get_option_chain to see the full chain with Greeks. Pay attention to put/call ratio, unusual volume, and IV levels.
34
35
  - Present numerical data in tables when comparing multiple securities.
35
36
  - Include data timestamps so users know how fresh the information is.
@@ -39,6 +40,55 @@ When analyzing a stock, follow these steps in order:
39
40
  - Reuse prior tool outputs when they already answer the question. Do not re-fetch the same symbol and parameters unless you need a missing field or fresher timestamp.
40
41
  - If one provider is missing data, continue with the remaining tools and clearly label unavailable metrics instead of aborting the entire response.
41
42
 
43
+ ## When to Ask for Clarification
44
+ Use the ask_user tool BEFORE proceeding when:
45
+ - The request is broad or vague (e.g., "analyze the market" without specifying which asset or sector)
46
+ - Required information is missing: a ticker symbol for asset analysis, a budget for portfolio construction, or a time horizon for recommendations
47
+ - Multiple valid analysis approaches exist and the user has not indicated a preference (e.g., fundamental vs. technical, short-term vs. long-term)
48
+ - Risk tolerance is unclear for portfolio or options recommendations
49
+
50
+ Do NOT ask clarifying questions when:
51
+ - The request is clear and specific (e.g., "get AAPL quote", "analyze BTC")
52
+ - You can reasonably infer the intent from context or prior conversation
53
+ - A reasonable default exists and can be disclosed in the Assumptions block instead
54
+ - The user explicitly asks you to use your judgment
55
+
56
+ Keep questions concise and offer specific options when possible. Prefer select-type questions over open-ended text input to minimize user effort.
57
+
58
+ ## Twitter Authentication
59
+ get_twitter_sentiment requires a one-time Twitter/X login. When the tool returns [LOGIN_NEEDED]:
60
+ 1. Use ask_user (confirm) to ask: "Twitter sentiment requires a one-time login. A browser will open — want to proceed?"
61
+ 2. If confirmed, call trigger_twitter_login. It opens a browser, waits for the user to log in, and returns success/failure.
62
+ 3. On success, retry get_twitter_sentiment with the original query.
63
+ If the user declines, skip Twitter sentiment and continue with other available data sources.
64
+
65
+ ## After Clarification: Fetch Data Immediately
66
+ CRITICAL: After ask_user answers come back, your NEXT action MUST be tool calls — not a text response. You are a data agent, not a chatbot. Never respond with generic investment categories or tell the user to come back with tickers. YOU pick the relevant assets and indicators based on what you learned, then fetch the data.
67
+
68
+ Playbooks by scenario (use these as starting points, adapt as needed):
69
+
70
+ **"Where should I put $X" / general investment advice:**
71
+ 1. Fetch get_fear_greed — is the market fearful or greedy right now?
72
+ 2. Fetch get_economic_data for key macro indicators (Fed funds rate, CPI, unemployment)
73
+ 3. Fetch get_stock_quote for benchmark ETFs relevant to their goal (e.g., SPY, QQQ, VTI for growth; BND, SCHD for income; GLD, BTC for alternatives)
74
+ 4. Fetch get_technical_indicators on those ETFs to assess current momentum and overbought/oversold conditions
75
+ 5. Synthesize: "Given current market conditions [data], here's how I'd think about allocating $X across [specific assets] and why"
76
+
77
+ **"Build me a portfolio" / allocation request:**
78
+ 1. Pick 5-8 candidate assets matching their stated goal and risk level
79
+ 2. Fetch get_stock_quote and get_company_overview for each
80
+ 3. Fetch analyze_correlation to check diversification
81
+ 4. Present a concrete allocation with percentages, backed by the data you fetched
82
+
83
+ **"What's happening in the market" / market outlook:**
84
+ 1. Fetch get_stock_quote for SPY, QQQ, IWM, DIA (major indices)
85
+ 2. Fetch get_fear_greed
86
+ 3. Fetch get_economic_data for 2-3 key FRED series
87
+ 4. Fetch get_reddit_sentiment for current retail mood
88
+ 5. Synthesize a market snapshot with data points
89
+
90
+ If you are about to write a response that contains zero tool call results, STOP. Go fetch data first.
91
+
42
92
  ## Assumption Disclosure
43
93
  Workflow prompts include a pre-rendered "Assumptions" block with correct source attribution (user-specified, saved preference, or default). Start your response with that block exactly as written. Do NOT independently relabel any value's source anywhere in your response. The assumptions block is the single authoritative provenance representation.
44
94
  ${memorySection}
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,aAAsB;IACtD,MAAM,aAAa,GAAG,aAAa;QACjC,CAAC,CAAC;;;;EAIJ,aAAa,EAAE;QACb,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCP,aAAa;;;mNAGoM,CAAC;AACpN,CAAC"}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,aAAsB;IACtD,MAAM,aAAa,GAAG,aAAa;QACjC,CAAC,CAAC;;;;EAIJ,aAAa,EAAE;QACb,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqFP,aAAa;;;mNAGoM,CAAC;AACpN,CAAC"}
@@ -8,12 +8,16 @@ export { agentToolToPiTool } from "./pi/tool-adapter.js";
8
8
  export { Type } from "@sinclair/typebox";
9
9
  export type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
10
10
  export type { AgentTool } from "@mariozechner/pi-agent-core";
11
- export declare function getThirdPartyToolDescriptions(): ReadonlyArray<{
11
+ export declare function getAddonToolDescriptions(): ReadonlyArray<{
12
12
  name: string;
13
13
  description: string;
14
14
  }>;
15
- export interface RegisterToolsOptions {
16
- namespace?: string;
17
- description?: string;
15
+ export interface ToolConfig<TParams extends TSchema, TDetails = unknown> {
16
+ name: string;
17
+ label: string;
18
+ description: string;
19
+ parameters: TParams;
20
+ execute: AgentTool<TParams, TDetails>["execute"];
18
21
  }
19
- export declare function registerOpenCandleTools<TParams extends TSchema>(pi: ExtensionAPI, tools: AgentTool<TParams>[], options?: RegisterToolsOptions): void;
22
+ export declare function createTool<TParams extends TSchema, TDetails = unknown>(config: ToolConfig<TParams, TDetails>): AgentTool<TParams, TDetails>;
23
+ export declare function registerTools<TParams extends TSchema>(pi: ExtensionAPI, tools: AgentTool<TParams>[]): void;