yaml-flow 5.2.6 → 5.3.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.
- package/README.md +6 -6
- package/board-livecards-server-runtime.js +260 -35
- package/browser/board-livegraph-engine.js +61 -33
- package/browser/board-livegraph-engine.js.map +1 -1
- package/browser/card-compute.js +18 -18
- package/browser/live-cards.js +317 -156
- package/browser/live-cards.schema.json +15 -10
- package/dist/board-livegraph-runtime/index.cjs +61 -33
- package/dist/board-livegraph-runtime/index.cjs.map +1 -1
- package/dist/board-livegraph-runtime/index.d.cts +1 -1
- package/dist/board-livegraph-runtime/index.d.ts +1 -1
- package/dist/board-livegraph-runtime/index.js +61 -33
- package/dist/board-livegraph-runtime/index.js.map +1 -1
- package/dist/card-compute/index.cjs +101 -39
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +13 -8
- package/dist/card-compute/index.d.ts +13 -8
- package/dist/card-compute/index.js +101 -39
- package/dist/card-compute/index.js.map +1 -1
- package/dist/cli/board-live-cards-cli.cjs +7205 -202
- package/dist/cli/board-live-cards-cli.cjs.map +1 -1
- package/dist/cli/board-live-cards-cli.d.cts +6 -6
- package/dist/cli/board-live-cards-cli.d.ts +6 -6
- package/dist/cli/board-live-cards-cli.js +7204 -202
- package/dist/cli/board-live-cards-cli.js.map +1 -1
- package/dist/continuous-event-graph/index.cjs +59 -31
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +2 -2
- package/dist/continuous-event-graph/index.d.ts +2 -2
- package/dist/continuous-event-graph/index.js +59 -31
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/index.cjs +126 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +126 -54
- package/dist/index.js.map +1 -1
- package/dist/{live-cards-bridge-CeNxiVcm.d.ts → live-cards-bridge-EQjytzI_.d.ts} +10 -5
- package/dist/{live-cards-bridge-z_rJCSbi.d.cts → live-cards-bridge-x5XREkXm.d.cts} +10 -5
- package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-risk-assessment.json +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +2 -2
- package/examples/browser/boards/portfolio-tracker/cards/rebalancing-strategy.json +1 -1
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +10 -10
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +1 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +1 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +1 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +2 -2
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +1 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +1 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +1 -1
- package/examples/example-board/agent-instructions-cardlayout.md +29 -1
- package/examples/example-board/agent-instructions.md +271 -45
- package/examples/example-board/cards/card-concentration.json +8 -5
- package/examples/example-board/cards/card-market-prices.json +14 -9
- package/examples/example-board/cards/card-my-identity.json +28 -0
- package/examples/example-board/cards/card-portfolio-value.json +1 -1
- package/examples/example-board/cards/card-portfolio.json +1 -1
- package/examples/example-board/cards/card-rebalance-impact.json +65 -0
- package/examples/example-board/cards/card-rebalance-sim.json +67 -0
- package/examples/example-board/demo-chat-handler.js +2 -1
- package/examples/example-board/demo-server-config.json +6 -1
- package/examples/example-board/demo-server.js +91 -8
- package/examples/example-board/demo-shell-browser.html +6 -6
- package/examples/example-board/demo-shell-with-server.html +4 -4
- package/examples/example-board/demo-task-executor.js +457 -246
- package/examples/example-board/scripts/copilot_wrapper.bat +16 -0
- package/examples/example-board/scripts/copilot_wrapper_helper.ps1 +19 -10
- package/examples/example-board/scripts/workiq_wrapper.mjs +66 -0
- package/examples/npm-libs/continuous-event-graph/live-cards-board.ts +5 -5
- package/examples/npm-libs/continuous-event-graph/soc-incident-board.ts +3 -3
- package/examples/npm-libs/event-graph/research-pipeline.ts +5 -5
- package/examples/npm-libs/graph-of-graphs/multi-stage-etl.ts +9 -9
- package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +1 -1
- package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +1 -1
- package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +1 -1
- package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +3 -3
- package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +1 -1
- package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +1 -1
- package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +1 -1
- package/package.json +2 -2
- package/schema/live-cards.schema.json +15 -10
|
@@ -126,6 +126,22 @@ for /f "skip=50 tokens=*" %%f in ('dir /b /o-d "!LOG_DIR!\!LOG_AGENT!_*.log" 2^>
|
|
|
126
126
|
|
|
127
127
|
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0copilot_wrapper_helper.ps1" "%OUTPUT_FILE%" "!RESULT_TYPE!" "!RESULT_SHAPE_FILE!"
|
|
128
128
|
|
|
129
|
+
REM If JSON extraction failed (exit 2) and result_type is json, retry once with a
|
|
130
|
+
REM correction prompt in the same session (--resume SESSION_UUID continues the conversation).
|
|
131
|
+
SET "PS1_EXIT=!ERRORLEVEL!"
|
|
132
|
+
if "!PS1_EXIT!"=="2" (
|
|
133
|
+
SET "RETRY_PROMPT_FILE=%TEMP%\copilot-retry-!RANDOM!.txt"
|
|
134
|
+
(
|
|
135
|
+
echo Your previous response did not contain a valid JSON object.
|
|
136
|
+
echo Please respond with ONLY the JSON object — no markdown, no explanation, no preamble.
|
|
137
|
+
echo Start your response with { and end with }.
|
|
138
|
+
) > "!RETRY_PROMPT_FILE!"
|
|
139
|
+
type "!RETRY_PROMPT_FILE!" | call copilot --allow-all --resume !SESSION_UUID! !MODEL_FLAG! > "%OUTPUT_FILE%" 2>&1
|
|
140
|
+
del "!RETRY_PROMPT_FILE!" 2>nul
|
|
141
|
+
REM Re-run PS1 with -IsRetry so it writes skeleton on second failure rather than exit 2
|
|
142
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0copilot_wrapper_helper.ps1" "%OUTPUT_FILE%" "!RESULT_TYPE!" "!RESULT_SHAPE_FILE!" "-IsRetry"
|
|
143
|
+
)
|
|
144
|
+
|
|
129
145
|
if exist "!CACHE_SESSION_PATH!" (
|
|
130
146
|
for %%f in ("!CACHE_SESSION_PATH!\*") do (
|
|
131
147
|
move /y "%%f" "%SESSION_DIR%\" >nul 2>&1
|
|
@@ -9,13 +9,16 @@
|
|
|
9
9
|
# if result_shape_file is absent, accepts any valid JSON object
|
|
10
10
|
# result_shape_file - (json result_type only) JSON file whose top-level keys are required in output
|
|
11
11
|
#
|
|
12
|
-
# raw result_type: right for chat responses and task executor
|
|
12
|
+
# raw result_type: right for chat responses and task executor source_defs.
|
|
13
13
|
# json result_type: right for structured calls where the input contained {prompt, result_shape}.
|
|
14
14
|
|
|
15
15
|
param(
|
|
16
16
|
[Parameter(Mandatory)][string]$OutputFile,
|
|
17
17
|
[Parameter(Mandatory)][string]$ResultType,
|
|
18
|
-
[string]$ResultShapeFile = ''
|
|
18
|
+
[string]$ResultShapeFile = '',
|
|
19
|
+
# When $true (retry pass), write shape-skeleton fallback instead of exiting with code 2.
|
|
20
|
+
# On first pass, exit 2 signals the caller (.bat) to retry with a correction prompt.
|
|
21
|
+
[switch]$IsRetry
|
|
19
22
|
)
|
|
20
23
|
|
|
21
24
|
if (-not (Test-Path $OutputFile)) { exit 0 }
|
|
@@ -47,7 +50,7 @@ foreach ($line in ($cleaned -split "`n")) {
|
|
|
47
50
|
$t -match '^X ' -or # X failed tool ops
|
|
48
51
|
$t -match '^\$ ' -or # $ shell commands
|
|
49
52
|
$t -match '^[\u2514\u251c]' -or # └ ├ tree lines
|
|
50
|
-
$t -match 'session-state.*\.json' -or # session-state file
|
|
53
|
+
$t -match 'session-state.*\.json' -or # session-state file projections
|
|
51
54
|
$t -match 'agent.decision has been simulated' -or
|
|
52
55
|
$t -match 'has been simulated and saved' -or
|
|
53
56
|
$t -match '^\d+ (files?|lines?|matches?) found$' -or # "3 files found"
|
|
@@ -163,7 +166,7 @@ if (-not $foundJson) {
|
|
|
163
166
|
if ($foundJson) {
|
|
164
167
|
[IO.File]::WriteAllText($OutputFile, $foundJson, [Text.Encoding]::UTF8)
|
|
165
168
|
} else {
|
|
166
|
-
# No matching JSON found — record raw in noise file
|
|
169
|
+
# No matching JSON found — record raw in noise file for upstream visibility
|
|
167
170
|
$NoiseFile = $OutputFile + '.noise'
|
|
168
171
|
$fallbackNoise = "FALLBACK=no_json_match`nSHAPE_KEYS=$($shapeKeys -join ',')`nRAW_LENGTH=$($cleaned.Length)`n---`n$cleaned"
|
|
169
172
|
if (Test-Path $NoiseFile) {
|
|
@@ -172,10 +175,16 @@ if ($foundJson) {
|
|
|
172
175
|
} else {
|
|
173
176
|
[IO.File]::WriteAllText($NoiseFile, $fallbackNoise, [Text.Encoding]::UTF8)
|
|
174
177
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
if ($IsRetry) {
|
|
179
|
+
# Second pass — write shape-skeleton so the card gets a structured (empty) result
|
|
180
|
+
$fallback = if ($shapeKeys.Count -gt 0) {
|
|
181
|
+
$obj = [ordered]@{}
|
|
182
|
+
foreach ($k in $shapeKeys) { $obj[$k] = $null }
|
|
183
|
+
$obj | ConvertTo-Json -Depth 2 -Compress
|
|
184
|
+
} else { '{}' }
|
|
185
|
+
[IO.File]::WriteAllText($OutputFile, $fallback, [Text.Encoding]::UTF8)
|
|
186
|
+
} else {
|
|
187
|
+
# First pass — exit 2 to signal the caller (.bat) to retry with a correction prompt
|
|
188
|
+
exit 2
|
|
189
|
+
}
|
|
181
190
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* workiq_wrapper.mjs — Calls the demo-server /api/workiq/ask proxy endpoint.
|
|
4
|
+
*
|
|
5
|
+
* Usage: node workiq_wrapper.mjs <out_file>
|
|
6
|
+
* WORKIQ_QUERY env var: the interpolated query string
|
|
7
|
+
* WORKIQ_SERVER_URL env var: base URL of demo-server (default: http://127.0.0.1:7799)
|
|
8
|
+
*
|
|
9
|
+
* The demo-server has a TTY so workiq can produce output there.
|
|
10
|
+
* Writes raw WorkIQ response text to <out_file>.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import http from 'node:http';
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
|
|
16
|
+
const outFile = process.argv[2];
|
|
17
|
+
const query = process.env.WORKIQ_QUERY;
|
|
18
|
+
const serverBase = (process.env.WORKIQ_SERVER_URL || 'http://127.0.0.1:7799').replace(/\/$/, '');
|
|
19
|
+
|
|
20
|
+
if (!outFile) { console.error('workiq_wrapper: missing <out_file> argument'); process.exit(1); }
|
|
21
|
+
if (!query) { console.error('workiq_wrapper: WORKIQ_QUERY env var not set'); process.exit(1); }
|
|
22
|
+
|
|
23
|
+
const body = JSON.stringify({ query });
|
|
24
|
+
const url = new URL('/api/workiq/ask', serverBase);
|
|
25
|
+
|
|
26
|
+
const reqOptions = {
|
|
27
|
+
hostname: url.hostname,
|
|
28
|
+
port: url.port || 80,
|
|
29
|
+
path: url.pathname,
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const req = http.request(reqOptions, (res) => {
|
|
35
|
+
let data = '';
|
|
36
|
+
res.on('data', chunk => { data += chunk; });
|
|
37
|
+
res.on('end', () => {
|
|
38
|
+
try {
|
|
39
|
+
const json = JSON.parse(data);
|
|
40
|
+
if (json.error) {
|
|
41
|
+
fs.writeFileSync(outFile, `workiq error: ${json.error}`, 'utf8');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
fs.writeFileSync(outFile, json.response || '', 'utf8');
|
|
45
|
+
process.exit(0);
|
|
46
|
+
} catch {
|
|
47
|
+
fs.writeFileSync(outFile, data, 'utf8');
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
req.on('error', (err) => {
|
|
54
|
+
fs.writeFileSync(outFile, `workiq proxy error: ${err.message}\nIs demo-server running at ${serverBase}?`, 'utf8');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
req.setTimeout(60_000, () => {
|
|
59
|
+
req.destroy();
|
|
60
|
+
fs.writeFileSync(outFile, 'workiq proxy timeout after 60s', 'utf8');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
req.write(body);
|
|
65
|
+
req.end();
|
|
66
|
+
|
|
@@ -46,9 +46,9 @@ const cards: LiveCard[] = [
|
|
|
46
46
|
card_data: {},
|
|
47
47
|
data: { requires: ['market-feed'] },
|
|
48
48
|
compute: {
|
|
49
|
-
total: { fn: 'sum', input: '
|
|
50
|
-
avg: { fn: 'avg', input: '
|
|
51
|
-
count: { fn: 'count', input: '
|
|
49
|
+
total: { fn: 'sum', input: 'source_defs.market-feed.prices' },
|
|
50
|
+
avg: { fn: 'avg', input: 'source_defs.market-feed.prices' },
|
|
51
|
+
count: { fn: 'count', input: 'source_defs.market-feed.prices' },
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -132,8 +132,8 @@ const board: LiveBoard = {
|
|
|
132
132
|
card_data: {},
|
|
133
133
|
data: { requires: ['equity-feed', 'bond-feed'] },
|
|
134
134
|
compute: {
|
|
135
|
-
equity_total: { fn: 'sum', input: '
|
|
136
|
-
bond_total: { fn: 'sum', input: '
|
|
135
|
+
equity_total: { fn: 'sum', input: 'source_defs.equity-feed.prices' },
|
|
136
|
+
bond_total: { fn: 'sum', input: 'source_defs.bond-feed.yields' },
|
|
137
137
|
},
|
|
138
138
|
},
|
|
139
139
|
{
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* SOC Incident Board — Correct Model
|
|
3
3
|
*
|
|
4
4
|
* A Security Operations Center dashboard demonstrating:
|
|
5
|
-
* • External data
|
|
5
|
+
* • External data source_defs (alert-feed, threat-intel) — NO handlers
|
|
6
6
|
* • Handler-driven compute (severity-score, blast-radius)
|
|
7
7
|
* • Fire-and-forget side effects (slack-alert, create-ticket)
|
|
8
8
|
* • Per-task refreshStrategy: 'once' on create-ticket (no duplicate tickets)
|
|
@@ -76,7 +76,7 @@ const config: GraphConfig = {
|
|
|
76
76
|
refreshStrategy: 'data-changed',
|
|
77
77
|
},
|
|
78
78
|
tasks: {
|
|
79
|
-
// External
|
|
79
|
+
// External source_defs — no handler, data pushed externally
|
|
80
80
|
'alert-feed': {
|
|
81
81
|
provides: ['alert-feed'],
|
|
82
82
|
description: 'SIEM alert feed (external push)',
|
|
@@ -203,7 +203,7 @@ console.log(`create-ticket: refreshStrategy 'once' (no duplicate tickets)\n`);
|
|
|
203
203
|
|
|
204
204
|
console.log(`--- T0: Initial incident (${siemAlerts.length} alerts, ${threatIntelV1.length} IOCs) ---\n`);
|
|
205
205
|
|
|
206
|
-
// Push both
|
|
206
|
+
// Push both source_defs simultaneously — engine stores data, auto-hash computed
|
|
207
207
|
graph.pushAll([
|
|
208
208
|
{
|
|
209
209
|
type: 'task-completed',
|
|
@@ -29,18 +29,18 @@ const graph: GraphConfig = {
|
|
|
29
29
|
},
|
|
30
30
|
tasks: {
|
|
31
31
|
fetch_sources: {
|
|
32
|
-
provides: ['raw-
|
|
32
|
+
provides: ['raw-asources'],
|
|
33
33
|
description: 'Fetch source documents from the web',
|
|
34
34
|
},
|
|
35
35
|
analyse_sentiment: {
|
|
36
|
-
requires: ['raw-
|
|
36
|
+
requires: ['raw-asources'],
|
|
37
37
|
provides: ['sentiment-result'],
|
|
38
|
-
description: 'Run sentiment analysis on
|
|
38
|
+
description: 'Run sentiment analysis on source_defs',
|
|
39
39
|
},
|
|
40
40
|
analyse_entities: {
|
|
41
|
-
requires: ['raw-
|
|
41
|
+
requires: ['raw-asources'],
|
|
42
42
|
provides: ['entity-result'],
|
|
43
|
-
description: 'Extract named entities from
|
|
43
|
+
description: 'Extract named entities from source_defs',
|
|
44
44
|
},
|
|
45
45
|
merge_analysis: {
|
|
46
46
|
requires: ['sentiment-result', 'entity-result'],
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - Fan-out / fan-in in the outer graph
|
|
14
14
|
*
|
|
15
15
|
* Outer graph:
|
|
16
|
-
* discover-
|
|
16
|
+
* discover-bsources → extract-batch → transform-batch → [load ∥ validate] → finalize
|
|
17
17
|
*
|
|
18
18
|
* Inner extract graph (event-graph, per source):
|
|
19
19
|
* connect → [fetch-metadata ∥ fetch-schema] → snapshot-data
|
|
@@ -129,11 +129,11 @@ const outerGraph: GraphConfig = {
|
|
|
129
129
|
id: 'etl-pipeline',
|
|
130
130
|
settings: { completion: 'all-tasks-complete' },
|
|
131
131
|
tasks: {
|
|
132
|
-
'discover-
|
|
133
|
-
provides: ['
|
|
132
|
+
'discover-bsources': {
|
|
133
|
+
provides: ['source_defs-discovered'],
|
|
134
134
|
},
|
|
135
135
|
'extract-batch': {
|
|
136
|
-
requires: ['
|
|
136
|
+
requires: ['source_defs-discovered'],
|
|
137
137
|
provides: ['extraction-complete'],
|
|
138
138
|
},
|
|
139
139
|
'transform-batch': {
|
|
@@ -191,7 +191,7 @@ async function runTransformFlow(record: { id: string; raw_data: string }) {
|
|
|
191
191
|
// 4. Sample data
|
|
192
192
|
// ============================================================================
|
|
193
193
|
|
|
194
|
-
const
|
|
194
|
+
const source_defs = [
|
|
195
195
|
{ id: 'src-orders', db: 'orders_db' },
|
|
196
196
|
{ id: 'src-users', db: 'users_db' },
|
|
197
197
|
{ id: 'src-products', db: 'products_db' },
|
|
@@ -211,13 +211,13 @@ const records = [
|
|
|
211
211
|
// ============================================================================
|
|
212
212
|
|
|
213
213
|
const outerHandlers: Record<string, () => Promise<void>> = {
|
|
214
|
-
'discover-
|
|
215
|
-
console.log(` Found ${
|
|
214
|
+
'discover-bsources': async () => {
|
|
215
|
+
console.log(` Found ${source_defs.length} data source_defs`);
|
|
216
216
|
},
|
|
217
217
|
|
|
218
218
|
'extract-batch': async () => {
|
|
219
|
-
console.log(` Extracting from ${
|
|
220
|
-
const result = await batch(
|
|
219
|
+
console.log(` Extracting from ${source_defs.length} source_defs (concurrency: 2, mode: event-graph)`);
|
|
220
|
+
const result = await batch(source_defs, {
|
|
221
221
|
concurrency: 2,
|
|
222
222
|
processor: runExtractGraph,
|
|
223
223
|
onItemComplete: (src, res) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "holdings-table",
|
|
3
3
|
"meta": { "title": "Holdings Table" },
|
|
4
4
|
"requires": ["holdings", "prices"],
|
|
5
|
-
"provides": [{ "bindTo": "table", "
|
|
5
|
+
"provides": [{ "bindTo": "table", "ref": "computed_values.table" }],
|
|
6
6
|
"card_data": {},
|
|
7
7
|
"compute": [
|
|
8
8
|
{
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "portfolio-value",
|
|
3
3
|
"meta": { "title": "Portfolio Total Value" },
|
|
4
4
|
"requires": ["table"],
|
|
5
|
-
"provides": [{ "bindTo": "totalValue", "
|
|
5
|
+
"provides": [{ "bindTo": "totalValue", "ref": "computed_values.totalValue" }],
|
|
6
6
|
"card_data": {},
|
|
7
7
|
"compute": [
|
|
8
8
|
{ "bindTo": "totalValue", "expr": "$sum(requires.table.rows.value)" }
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"id": "price-fetch",
|
|
3
3
|
"meta": { "title": "Fetch Market Prices" },
|
|
4
4
|
"requires": ["holdings"],
|
|
5
|
-
"provides": [{ "bindTo": "prices", "
|
|
5
|
+
"provides": [{ "bindTo": "prices", "ref": "fetched_sources.prices" }],
|
|
6
6
|
"card_data": {},
|
|
7
|
-
"
|
|
7
|
+
"source_defs": [
|
|
8
8
|
{ "cli": "node ../fetch-prices.js --tmp-file-name tmp_file1", "bindTo": "prices", "outputFile": "prices.json" }
|
|
9
9
|
],
|
|
10
10
|
"view": {
|
|
11
11
|
"elements": [
|
|
12
|
-
{ "kind": "table", "label": "Market Prices", "data": { "bind": "
|
|
12
|
+
{ "kind": "table", "label": "Market Prices", "data": { "bind": "fetched_sources.prices" } }
|
|
13
13
|
]
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -22,7 +22,7 @@ try {
|
|
|
22
22
|
card.state.holdings = holdings;
|
|
23
23
|
fs.writeFileSync(cardPath, `${JSON.stringify(card, null, 2)}\n`, 'utf-8');
|
|
24
24
|
|
|
25
|
-
runBoardCli(['
|
|
25
|
+
runBoardCli(['upsert-card', '--rg', boardDir, '--card', cardPath, '--restart']);
|
|
26
26
|
|
|
27
27
|
writeResult({
|
|
28
28
|
result: 'success',
|
|
@@ -44,7 +44,7 @@ steps:
|
|
|
44
44
|
expects_data: [board_dir, cards_template_dir]
|
|
45
45
|
produces_data: [cards_dir]
|
|
46
46
|
handler:
|
|
47
|
-
cli: node %%BOARDCLI_CMD%%
|
|
47
|
+
cli: node %%BOARDCLI_CMD%% upsert-card --rg "%%BOARD_DIR%%" --card-glob "%%CARDS_GLOB%%"
|
|
48
48
|
result-mode: exit-code
|
|
49
49
|
input-transforms:
|
|
50
50
|
BOARD_DIR: board_dir
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yaml-flow",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Unified workflow engine: step-machine (sequential) + event-graph (stateless DAG) with pluggable storage",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "MIT",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"scripts": {
|
|
102
102
|
"build": "tsup",
|
|
103
103
|
"build:browser": "tsup --config tsup.browser.config.ts",
|
|
104
|
-
"build:example": "node example-board
|
|
104
|
+
"build:example": "node demo-src/example-board/build.js",
|
|
105
105
|
"dev": "tsup --watch",
|
|
106
106
|
"test": "vitest",
|
|
107
107
|
"test:run": "vitest run",
|
|
@@ -80,10 +80,10 @@
|
|
|
80
80
|
"type": "array",
|
|
81
81
|
"items": {
|
|
82
82
|
"type": "object",
|
|
83
|
-
"required": ["bindTo", "
|
|
83
|
+
"required": ["bindTo", "ref"],
|
|
84
84
|
"properties": {
|
|
85
85
|
"bindTo": { "type": "string", "description": "Token name published downstream" },
|
|
86
|
-
"
|
|
86
|
+
"ref": { "type": "string", "description": "Path to read value from (card_data.*, requires.*, fetched_sources.*, computed_values.*)" }
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
"description": "Explicit bindings exposing computed or card_data values downstream as named tokens"
|
|
@@ -100,14 +100,19 @@
|
|
|
100
100
|
},
|
|
101
101
|
|
|
102
102
|
"source_def": {
|
|
103
|
-
"description": "One source entry. The engine requires 'bindTo' (compute namespace key) and 'outputFile' (delivery signal path). bindTo and outputFile must be unique across all
|
|
103
|
+
"description": "One source entry. The engine requires 'bindTo' (compute namespace key) and 'outputFile' (delivery signal path). bindTo and outputFile must be unique across all source_defs in a card. Every other property is yours — add whatever your task-executor needs: kind, url, headers, mailbox, channel, model, query, etc. The full object is passed verbatim as the --in JSON to the executor.",
|
|
104
104
|
"type": "object",
|
|
105
105
|
"required": ["bindTo", "outputFile"],
|
|
106
106
|
"additionalProperties": true,
|
|
107
107
|
"properties": {
|
|
108
108
|
"bindTo": { "type": "string", "description": "Key under fetched_sources.* available in compute expressions" },
|
|
109
109
|
"outputFile": { "type": "string", "description": "Board-relative path the executor writes its JSON result to. Presence of this file signals delivery." },
|
|
110
|
-
"
|
|
110
|
+
"projections": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"description": "Named data projections from card_data or requires, evaluated before the executor is called. Each key is a ref name; each value is a JSONata expression rooted at card_data or requires. The resolved values are passed to the executor as _projections. fetched_sources, computed_values, and source_defs are not accessible here — sources run before those exist.",
|
|
113
|
+
"additionalProperties": { "type": "string" }
|
|
114
|
+
},
|
|
115
|
+
"optionalForCompletionGating": { "type": "boolean", "default": false, "description": "When true this source does not gate card completion. Default false when absent, so source_defs are completion-gating by default." },
|
|
111
116
|
"timeout": { "type": "integer", "minimum": 0, "default": 120000, "description": "Executor/script timeout in ms. Default: 120 000 (2 min)." },
|
|
112
117
|
"script": { "type": "string", "description": "Legacy direct-run: shell command executed when no .task-executor is registered. stdout is captured as the result." }
|
|
113
118
|
}
|
|
@@ -121,7 +126,7 @@
|
|
|
121
126
|
"kind": {
|
|
122
127
|
"enum": ["metric", "table", "editable-table", "chart", "form", "filter", "list",
|
|
123
128
|
"notes", "todo", "alert", "narrative", "badge", "text",
|
|
124
|
-
"markdown", "custom", "actions"]
|
|
129
|
+
"markdown", "ref", "custom", "actions"]
|
|
125
130
|
},
|
|
126
131
|
"label": { "type": "string", "description": "Heading above this element" },
|
|
127
132
|
"className": { "type": "string", "description": "Bootstrap grid class, e.g. 'col-12 col-md-6'" },
|
|
@@ -215,7 +220,7 @@
|
|
|
215
220
|
},
|
|
216
221
|
|
|
217
222
|
"title": "LiveCard",
|
|
218
|
-
"description": "A unified card node. Behavior depends on which sections are present (
|
|
223
|
+
"description": "A unified card node. Behavior depends on which sections are present (source_defs, compute, view, etc.)",
|
|
219
224
|
"type": "object",
|
|
220
225
|
"required": ["id"],
|
|
221
226
|
"additionalProperties": false,
|
|
@@ -258,22 +263,22 @@
|
|
|
258
263
|
},
|
|
259
264
|
"llm_task_completion_inference": {
|
|
260
265
|
"type": "object",
|
|
261
|
-
"description": "Runtime state written by the inference adapter (advanced/undocumented). Prefer the standard
|
|
266
|
+
"description": "Runtime state written by the inference adapter (advanced/undocumented). Prefer the standard source_defs → compute → provides pattern for LLM-based signals.",
|
|
262
267
|
"properties": {
|
|
263
268
|
"inferenceRequested": { "type": "string", "format": "date-time", "description": "Timestamp when the latest inference request was initiated" },
|
|
264
269
|
"inferenceCompletedAt": { "type": "string", "format": "date-time", "description": "Timestamp when the latest inference request completed" },
|
|
265
270
|
"isTaskCompleted": { "type": "boolean", "description": "Whether the task is considered complete by the adapter" },
|
|
266
271
|
"reasoning": { "type": "string", "description": "Explanation of completion decision" },
|
|
267
|
-
"evidence": { "type": "array", "description": "Supporting evidence from
|
|
272
|
+
"evidence": { "type": "array", "description": "Supporting evidence from source_defs/compute" }
|
|
268
273
|
},
|
|
269
274
|
"additionalProperties": true
|
|
270
275
|
}
|
|
271
276
|
},
|
|
272
277
|
"additionalProperties": true
|
|
273
278
|
},
|
|
274
|
-
"
|
|
279
|
+
"source_defs": {
|
|
275
280
|
"type": "array",
|
|
276
|
-
"description": "Source entries. Each entry is passed verbatim to the board's .task-executor (registered via init --task-executor) as the --in JSON file. The executor fetches/generates the data and writes JSON to --out. If no executor is registered, the built-in executor runs the entry's 'cli' command directly. Sources gate completion by default. Set optionalForCompletionGating: true for enrichment-only
|
|
281
|
+
"description": "Source entries. Each entry is passed verbatim to the board's .task-executor (registered via init --task-executor) as the --in JSON file. The executor fetches/generates the data and writes JSON to --out. If no executor is registered, the built-in executor runs the entry's 'cli' command directly. Sources gate completion by default. Set optionalForCompletionGating: true for enrichment-only source_defs that should not block task-completed.",
|
|
277
282
|
"items": { "$ref": "#/definitions/source_def" }
|
|
278
283
|
},
|
|
279
284
|
"compute": {
|