yaml-flow 8.2.5 → 8.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/browser/asset-integrity.json +3 -3
- package/browser/board-livecards-client.js +1 -1
- package/browser/board-livecards-localstorage.js +4 -4
- package/browser/live-cards.js +19 -19
- package/cli/{board-live-cards-lib-Iq_XAC09.d.ts → board-live-cards-lib-tjYsPt5U.d.ts} +1 -1
- package/cli/browser-api/board-live-cards-browser-adapter.d.ts +3 -3
- package/cli/browser-api/card-store-browser-api.d.ts +1 -1
- package/cli/{execution-interface-ftO1W7Po.d.ts → execution-interface-CrG5gzAx.d.ts} +116 -2
- package/cli/node/batch-runner-cli.d.ts +3 -0
- package/cli/node/batch-runner-cli.js +2 -1
- package/cli/node/board-live-cards-cli.js +9 -9
- package/cli/node/chat-store-cli.d.ts +23 -0
- package/cli/node/chat-store-cli.js +8 -0
- package/cli/node/execution-adapter.d.ts +4 -2
- package/cli/node/execution-adapter.js +2 -2
- package/cli/node/fs-board-adapter.d.ts +7 -6
- package/cli/node/fs-board-adapter.js +8 -8
- package/cli/node/source-cli-task-executor.js +4 -4
- package/cli/node/step-machine-cli.js +3 -3
- package/cli/{types--rXGWbSR.d.ts → types-PUfPBxc_.d.ts} +4 -109
- package/examples/board/demo-shell-with-server.html +3 -196
- package/examples/board/doc.html +465 -0
- package/examples/board/server/board-server.js +20 -81
- package/examples/board/server/board-worker/source_def_flows.json +2 -2
- package/examples/board/server/chat-flow/copilot-chat/assistant.js +44 -185
- package/examples/board/server/chat-flow/copilot-chat/copilot_wrapper.bat +157 -0
- package/examples/board/server/chat-flow/copilot-chat/copilot_wrapper_helper.ps1 +190 -0
- package/examples/board/server/chat-flow/flow-steps.json +122 -56
- package/examples/board/test/server-http-test.js +252 -220
- package/examples/board-local/demo-shell-localstorage.html +3 -3
- package/lib/{artifacts-store-lib-public-C5UL5tyG.d.cts → artifacts-store-lib-public-Cz8-kdXG.d.cts} +1 -1
- package/lib/{artifacts-store-lib-public-GD4H-fFp.d.ts → artifacts-store-lib-public-ksGIExhc.d.ts} +1 -1
- package/lib/artifacts-store-public.d.cts +2 -2
- package/lib/artifacts-store-public.d.ts +2 -2
- package/lib/board-live-cards-node.cjs +8 -8
- package/lib/board-live-cards-node.d.cts +26 -6
- package/lib/board-live-cards-node.d.ts +26 -6
- package/lib/board-live-cards-node.js +8 -8
- package/lib/{board-live-cards-public-BLXbcBNk.d.cts → board-live-cards-public-BwZYGAsF.d.cts} +1 -1
- package/lib/{board-live-cards-public-BZaNb2mi.d.ts → board-live-cards-public-DWpZVDXN.d.ts} +1 -1
- package/lib/board-live-cards-public.d.cts +1 -1
- package/lib/board-live-cards-public.d.ts +1 -1
- package/lib/board-live-cards-server-runtime.cjs +3 -3
- package/lib/board-live-cards-server-runtime.d.cts +3 -2
- package/lib/board-live-cards-server-runtime.d.ts +3 -2
- package/lib/board-live-cards-server-runtime.js +3 -3
- package/lib/board-worker-adapter.cjs +2 -2
- package/lib/board-worker-adapter.js +2 -2
- package/lib/card-store-public.d.cts +1 -1
- package/lib/card-store-public.d.ts +1 -1
- package/lib/chat-storage-lib-BK5Njslc.d.ts +53 -0
- package/lib/chat-storage-lib-C5bQ7bGe.d.cts +53 -0
- package/lib/chat-store-public.cjs +2 -0
- package/lib/chat-store-public.d.cts +128 -0
- package/lib/chat-store-public.d.ts +128 -0
- package/lib/chat-store-public.js +2 -0
- package/lib/execution-refs.d.cts +10 -1
- package/lib/execution-refs.d.ts +10 -1
- package/lib/server-runtime/index.cjs +3 -3
- package/lib/server-runtime/index.d.cts +4 -3
- package/lib/server-runtime/index.d.ts +4 -3
- package/lib/server-runtime/index.js +3 -3
- package/lib/{types-Bztd1KoK.d.cts → types-D9B0Vrwg.d.cts} +4 -53
- package/lib/{types-D-xVWPdY.d.ts → types-DNYhCFNJ.d.ts} +4 -53
- package/package.json +8 -2
- package/examples/board/.board-ws/cards/store/_index.json +0 -17
- package/examples/board/.board-ws/cards/store/card-market-prices.json +0 -80
- package/examples/board/.board-ws/cards/store/card-portfolio-value.json +0 -90
- package/examples/board/.board-ws/cards/store/card-portfolio.json +0 -78
- package/examples/board/server/chat-flow/chat-clear-processing.js +0 -41
- package/examples/board/server/chat-flow/chat-open-turn.js +0 -144
- package/examples/board/server/chat-flow/chat-write-assistant.js +0 -44
- package/examples/board/server/chat-flow/echo-probe/assistant.js +0 -28
|
@@ -13,12 +13,17 @@
|
|
|
13
13
|
* node test/server-http-test.js [--port 7799]
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { spawn } from 'node:child_process';
|
|
16
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
17
17
|
import { Worker } from 'node:worker_threads';
|
|
18
18
|
import { fileURLToPath } from 'node:url';
|
|
19
19
|
import path from 'node:path';
|
|
20
20
|
import http from 'node:http';
|
|
21
|
+
import net from 'node:net';
|
|
21
22
|
import fs from 'node:fs';
|
|
23
|
+
import os from 'node:os';
|
|
24
|
+
|
|
25
|
+
const ECHO_PROBE_MARKER = '__probe__echo__probe__';
|
|
26
|
+
const PROBE_IN_PROGRESS_TEXT = 'in-progress';
|
|
22
27
|
|
|
23
28
|
const __filename = fileURLToPath(import.meta.url);
|
|
24
29
|
const __dirname = path.dirname(__filename);
|
|
@@ -26,6 +31,18 @@ const __dirname = path.dirname(__filename);
|
|
|
26
31
|
const cliArgs = process.argv.slice(2);
|
|
27
32
|
const portArg = cliArgs.indexOf('--port');
|
|
28
33
|
const cliPort = portArg !== -1 ? parseInt(cliArgs[portArg + 1], 10) : NaN;
|
|
34
|
+
const skipT1 = cliArgs.includes('--skip-t1');
|
|
35
|
+
const skipT2 = cliArgs.includes('--skip-t2');
|
|
36
|
+
const skipT3 = cliArgs.includes('--skip-t3');
|
|
37
|
+
function isCopilotAvailable() {
|
|
38
|
+
try {
|
|
39
|
+
const r = spawnSync('copilot', ['--version'], { timeout: 5_000, stdio: 'ignore', windowsHide: true });
|
|
40
|
+
return !r.error;
|
|
41
|
+
} catch { return false; }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const skipT3a = cliArgs.includes('--skip-t3a') || !isCopilotAvailable();
|
|
45
|
+
const skipT3b = cliArgs.includes('--skip-t3b');
|
|
29
46
|
const RUN_ID = `run-${Date.now()}-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
30
47
|
|
|
31
48
|
const BOARD_ID = 'live';
|
|
@@ -35,34 +52,28 @@ const SSE_WORKER_SCRIPT = path.join(__dirname, 'sse-worker.js');
|
|
|
35
52
|
const CARD_PATTERN = 'cardT*';
|
|
36
53
|
const CHAT_CARD_ID = 'card-portfolio';
|
|
37
54
|
|
|
38
|
-
function
|
|
55
|
+
function findFreePort() {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const srv = net.createServer();
|
|
58
|
+
srv.listen(0, '127.0.0.1', () => {
|
|
59
|
+
const addr = /** @type {import('node:net').AddressInfo} */ (srv.address());
|
|
60
|
+
srv.close(() => resolve(addr.port));
|
|
61
|
+
});
|
|
62
|
+
srv.on('error', reject);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function resolveServerPort() {
|
|
39
67
|
if (Number.isInteger(cliPort) && cliPort > 0) return cliPort;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const cfg = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
43
|
-
const configured = Number(cfg?.port);
|
|
44
|
-
if (Number.isInteger(configured) && configured > 0) return configured;
|
|
45
|
-
} catch { /* ignore */ }
|
|
46
|
-
return 7799;
|
|
68
|
+
return findFreePort();
|
|
47
69
|
}
|
|
48
70
|
|
|
49
|
-
const PORT = resolveServerPort();
|
|
71
|
+
const PORT = await resolveServerPort();
|
|
50
72
|
const BASE = `http://127.0.0.1:${PORT}/api/boards/${BOARD_ID}`;
|
|
51
73
|
|
|
52
|
-
//
|
|
74
|
+
// Always use a system temp directory so parallel runs and vitest don't collide.
|
|
53
75
|
function resolveSetupDirRoot() {
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const cfg = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
57
|
-
const boardSetupDir = cfg?.boards?.[BOARD_ID]?.setupDir;
|
|
58
|
-
if (typeof boardSetupDir === 'string' && boardSetupDir.trim()) {
|
|
59
|
-
return path.resolve(BOARD_DIR, boardSetupDir.trim());
|
|
60
|
-
}
|
|
61
|
-
if (cfg && typeof cfg.setupDir === 'string' && cfg.setupDir.trim()) {
|
|
62
|
-
return path.resolve(BOARD_DIR, cfg.setupDir.trim());
|
|
63
|
-
}
|
|
64
|
-
} catch { /* ignore */ }
|
|
65
|
-
return path.join(BOARD_DIR, '.demo-setup');
|
|
76
|
+
return os.tmpdir();
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
const SETUP_DIR = path.join(resolveSetupDirRoot(), RUN_ID);
|
|
@@ -220,6 +231,49 @@ const waitForAllCompleted = (ms = 60_000, label = 'all completed') =>
|
|
|
220
231
|
const waitForChatPredicate = (predicate, ms, label) =>
|
|
221
232
|
waitUntil(() => predicate(NS.chatEvents) || false, ms, label);
|
|
222
233
|
|
|
234
|
+
function deriveProbeLifecycleMilestones(events, opts) {
|
|
235
|
+
const milestones = [];
|
|
236
|
+
let prevMessageCount = Number(opts.beforeCount || 0);
|
|
237
|
+
let prevProcessing = Boolean(opts.beforeProcessing);
|
|
238
|
+
const prompt = String(opts.prompt || '');
|
|
239
|
+
const inProgressText = String(opts.inProgressText || PROBE_IN_PROGRESS_TEXT);
|
|
240
|
+
|
|
241
|
+
for (const event of events) {
|
|
242
|
+
const messages = Array.isArray(event?.messages) ? event.messages : [];
|
|
243
|
+
const nextMessageCount = Number(event?.messageCount || messages.length || 0);
|
|
244
|
+
const newMessages = nextMessageCount > prevMessageCount
|
|
245
|
+
? messages.slice(prevMessageCount, nextMessageCount)
|
|
246
|
+
: [];
|
|
247
|
+
|
|
248
|
+
for (const message of newMessages) {
|
|
249
|
+
const role = String(message?.role || '');
|
|
250
|
+
const text = String(message?.text || '');
|
|
251
|
+
if (role === 'user' && text.includes(prompt)) milestones.push('user');
|
|
252
|
+
else if (role === 'system' && text.trim().toLowerCase() === inProgressText) milestones.push('in-progress');
|
|
253
|
+
else if (role === 'assistant' && text.includes(`Echo: ${prompt}`)) milestones.push('assistant');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const processing = Boolean(event?.processing);
|
|
257
|
+
if (processing !== prevProcessing) milestones.push(processing ? 'processing-true' : 'processing-false');
|
|
258
|
+
|
|
259
|
+
prevMessageCount = nextMessageCount;
|
|
260
|
+
prevProcessing = processing;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return milestones;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function matchOrderedProbeLifecycle(events, opts) {
|
|
267
|
+
const milestones = deriveProbeLifecycleMilestones(events, opts);
|
|
268
|
+
if (milestones.length !== 5) return false;
|
|
269
|
+
const firstPair = milestones.slice(0, 2);
|
|
270
|
+
const lastPair = milestones.slice(3, 5);
|
|
271
|
+
const firstOk = firstPair.includes('user') && firstPair.includes('processing-true');
|
|
272
|
+
const middleOk = milestones[2] === 'in-progress';
|
|
273
|
+
const lastOk = lastPair.includes('assistant') && lastPair.includes('processing-false');
|
|
274
|
+
return (firstOk && middleOk && lastOk) ? { milestones } : false;
|
|
275
|
+
}
|
|
276
|
+
|
|
223
277
|
function httpGet(url) {
|
|
224
278
|
return new Promise((resolve, reject) => {
|
|
225
279
|
http.get(url, (res) => {
|
|
@@ -402,7 +456,10 @@ try {
|
|
|
402
456
|
console.log(`[T0] ok: ${t0Positions.length} positions computed`);
|
|
403
457
|
|
|
404
458
|
// ── T1: PATCH holdings (+1 row), verify recomputation ──
|
|
405
|
-
|
|
459
|
+
if (skipT1) {
|
|
460
|
+
console.log('\n=== T1: skipped (--skip-t1) ===');
|
|
461
|
+
} else {
|
|
462
|
+
console.log('\n=== T1: patch holdings (+1 row) ===');
|
|
406
463
|
|
|
407
464
|
// Read current holdings from card store
|
|
408
465
|
const portfolioCardRes = await httpGet(`${BASE}/cards/card-portfolio`);
|
|
@@ -446,49 +503,57 @@ try {
|
|
|
446
503
|
`Expected positions rows +1 (before=${t0PositionsCount}, after=${afterPositionsCount})`);
|
|
447
504
|
console.log(`[T1] ok: holdings ${t0HoldingsCount}->${afterHoldingsCount}, ` +
|
|
448
505
|
`positions ${t0PositionsCount}->${afterPositionsCount}, added=${newTicker}`);
|
|
506
|
+
}
|
|
449
507
|
|
|
450
508
|
// ── T2: plain file upload API + card_data.files + download roundtrip ──
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
t2UploadName
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
509
|
+
if (skipT2) {
|
|
510
|
+
console.log('\n=== T2: skipped (--skip-t2) ===');
|
|
511
|
+
} else {
|
|
512
|
+
console.log('\n=== T2: plain file upload -> card_data.files -> download ===');
|
|
513
|
+
const t2CardBefore = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}`);
|
|
514
|
+
assert(t2CardBefore.status === 200, `T2 pre card read returned ${t2CardBefore.status}`);
|
|
515
|
+
const t2FilesBefore = Array.isArray(t2CardBefore.data?.card_data?.files)
|
|
516
|
+
? t2CardBefore.data.card_data.files
|
|
517
|
+
: [];
|
|
518
|
+
const t2BeforeCount = t2FilesBefore.length;
|
|
519
|
+
|
|
520
|
+
const t2UploadText = `plain-file-upload-${Date.now()}`;
|
|
521
|
+
const t2UploadName = 't2-upload.txt';
|
|
522
|
+
const t2UploadRes = await httpUploadChatFile(
|
|
523
|
+
`${BASE}/cards/${CHAT_CARD_ID}/files`,
|
|
524
|
+
t2UploadName,
|
|
525
|
+
t2UploadText,
|
|
526
|
+
);
|
|
527
|
+
assert(t2UploadRes.status === 200, `T2 file upload returned ${t2UploadRes.status}`);
|
|
528
|
+
const t2UploadedFile = t2UploadRes.data?.file;
|
|
529
|
+
assert(t2UploadedFile && typeof t2UploadedFile === 'object', 'T2 upload response missing file metadata');
|
|
530
|
+
assert(String(t2UploadedFile?.name || '') === t2UploadName, 'T2 uploaded file name mismatch');
|
|
531
|
+
|
|
532
|
+
const t2CardAfter = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}`);
|
|
533
|
+
assert(t2CardAfter.status === 200, `T2 post card read returned ${t2CardAfter.status}`);
|
|
534
|
+
const t2FilesAfter = Array.isArray(t2CardAfter.data?.card_data?.files)
|
|
535
|
+
? t2CardAfter.data.card_data.files
|
|
536
|
+
: [];
|
|
537
|
+
assert(t2FilesAfter.length === t2BeforeCount + 1, `T2 expected files +1 (before=${t2BeforeCount}, after=${t2FilesAfter.length})`);
|
|
538
|
+
|
|
539
|
+
const t2FileIndex = t2FilesAfter.findIndex((f) => String(f?.stored_name || '') === String(t2UploadedFile?.stored_name || ''));
|
|
540
|
+
assert(t2FileIndex >= 0, 'T2 uploaded file metadata not found in card_data.files');
|
|
541
|
+
|
|
542
|
+
const t2DownloadRes = await httpGetRaw(
|
|
543
|
+
`${BASE}/cards/${CHAT_CARD_ID}/files/${t2FileIndex}?sn=${encodeURIComponent(String(t2UploadedFile?.stored_name || ''))}`,
|
|
544
|
+
);
|
|
545
|
+
assert(t2DownloadRes.status === 200, `T2 file download returned ${t2DownloadRes.status}`);
|
|
546
|
+
const t2DownloadedText = t2DownloadRes.body.toString('utf-8');
|
|
547
|
+
assert(t2DownloadedText === t2UploadText, 'T2 downloaded content mismatch');
|
|
548
|
+
console.log('[T2] ok: card_data.files updated and file download endpoint returned exact bytes');
|
|
549
|
+
}
|
|
488
550
|
|
|
489
551
|
// ── T3*: chat protocol over API + SSE ──
|
|
490
552
|
{
|
|
491
|
-
|
|
553
|
+
if (skipT3) {
|
|
554
|
+
console.log('\n=== T3: skipped (--skip-t3) ===');
|
|
555
|
+
} else {
|
|
556
|
+
console.log(`\n[${new Date().toISOString()}] === T3: probe chat protocol (SSE lifecycle) ===`);
|
|
492
557
|
chatSseClientId = `chat-proto-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
493
558
|
chatSseClient = startSseClient(`${BASE}/sse?clientId=${encodeURIComponent(chatSseClientId)}`, (payload) => {
|
|
494
559
|
captureChatEvents(payload, CHAT_CARD_ID);
|
|
@@ -502,189 +567,156 @@ try {
|
|
|
502
567
|
assert(t2Before.status === 200, `T3 pre chats returned ${t2Before.status}`);
|
|
503
568
|
const t2BeforeMessages = Array.isArray(t2Before.data?.messages) ? t2Before.data.messages : [];
|
|
504
569
|
const t2BeforeCount = t2BeforeMessages.length;
|
|
570
|
+
const t2EventStart = NS.chatEvents.length;
|
|
505
571
|
const t2ProbePrompt = `Probe protocol validation ${Date.now()}`;
|
|
506
572
|
|
|
507
573
|
const t2SendRes = await httpJson('POST', `${BASE}/cards/${CHAT_CARD_ID}/actions`, {
|
|
508
574
|
actionType: 'chat-send',
|
|
509
575
|
payload: {
|
|
510
|
-
text:
|
|
511
|
-
prompt: t2ProbePrompt,
|
|
512
|
-
probe: true,
|
|
513
|
-
chatTimeMs: 2200,
|
|
514
|
-
chatTimeoutMs: 20000,
|
|
515
|
-
}),
|
|
576
|
+
text: `${ECHO_PROBE_MARKER}${t2ProbePrompt}${ECHO_PROBE_MARKER}`,
|
|
516
577
|
},
|
|
517
578
|
});
|
|
518
579
|
assert(t2SendRes.status === 200, `T3 chat-send returned ${t2SendRes.status}`);
|
|
519
580
|
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
if (e.messageCount < t2BeforeCount + 2) continue;
|
|
530
|
-
const last = e.messages[e.messages.length - 1];
|
|
531
|
-
if (last?.role === 'assistant' && String(last.text || '').includes(`Echo: ${t2ProbePrompt}`)) {
|
|
532
|
-
return e;
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
return false;
|
|
536
|
-
}, 45_000, 'T3 assistant echo');
|
|
537
|
-
assert(!!t2Assistant, 'T3 assistant echo not observed on SSE');
|
|
538
|
-
|
|
539
|
-
const t2ProcessingCleared = await waitForChatPredicate((events) => {
|
|
540
|
-
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
541
|
-
const e = events[i];
|
|
542
|
-
if (e.messageCount >= t2BeforeCount + 2 && e.processing === false) return e;
|
|
543
|
-
}
|
|
544
|
-
return false;
|
|
545
|
-
}, 30_000, 'T3 processing clear');
|
|
546
|
-
assert(!!t2ProcessingCleared, 'T3 processing clear not observed');
|
|
581
|
+
const t2Lifecycle = await waitForChatPredicate((events) => {
|
|
582
|
+
return matchOrderedProbeLifecycle(events.slice(t2EventStart), {
|
|
583
|
+
beforeCount: t2BeforeCount,
|
|
584
|
+
beforeProcessing: false,
|
|
585
|
+
prompt: t2ProbePrompt,
|
|
586
|
+
inProgressText: PROBE_IN_PROGRESS_TEXT,
|
|
587
|
+
});
|
|
588
|
+
}, 45_000, 'T3 ordered lifecycle');
|
|
589
|
+
assert(!!t2Lifecycle, 'T3 ordered lifecycle not observed');
|
|
547
590
|
|
|
548
591
|
const t2After = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}/chats`);
|
|
549
592
|
assert(t2After.status === 200, `T3 post chats returned ${t2After.status}`);
|
|
550
593
|
const t2AfterMessages = Array.isArray(t2After.data?.messages) ? t2After.data.messages : [];
|
|
551
594
|
const t2NewMessages = t2AfterMessages.slice(t2BeforeCount);
|
|
552
|
-
assert(t2NewMessages.length >=
|
|
595
|
+
assert(t2NewMessages.length >= 3, `T3 expected at least 3 new chat messages, got ${t2NewMessages.length}`);
|
|
553
596
|
const t2User = t2NewMessages.find((m) => m?.role === 'user');
|
|
597
|
+
const t2InProgress = t2NewMessages.find((m) => m?.role === 'system' && String(m?.text || '').trim().toLowerCase() === PROBE_IN_PROGRESS_TEXT);
|
|
554
598
|
const t2AssistantMsg = t2NewMessages.find((m) => m?.role === 'assistant');
|
|
555
599
|
assert(!!t2User && typeof t2User.id === 'string', 'T3 user chat message missing id');
|
|
556
600
|
assert(String(t2User?.text || '').includes(t2ProbePrompt), 'T3 user file text mismatch');
|
|
601
|
+
assert(!!t2InProgress && typeof t2InProgress.id === 'string', 'T3 in-progress system message missing id');
|
|
557
602
|
assert(!!t2AssistantMsg && typeof t2AssistantMsg.id === 'string', 'T3 assistant chat message missing id');
|
|
558
603
|
assert(String(t2AssistantMsg?.text || '').includes(`Echo: ${t2ProbePrompt}`), 'T3 assistant echo file content mismatch');
|
|
559
|
-
console.log(
|
|
604
|
+
console.log(`[${new Date().toISOString()}] [T3] ok: ordered probe lifecycle observed (user+processing, in-progress, assistant+processing clear)`);
|
|
605
|
+
}
|
|
560
606
|
|
|
561
|
-
/*
|
|
562
607
|
// ── T3a: non-probe chat protocol over API + SSE ──
|
|
563
|
-
// Disabled in the public example — requires a
|
|
564
|
-
// endpoint and agent_id in server-config.json.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
608
|
+
// Disabled in the public example unless explicitly requested — requires a
|
|
609
|
+
// configured Azure Foundry endpoint and agent_id in server-config.json.
|
|
610
|
+
if (skipT3a) {
|
|
611
|
+
console.log('\n=== T3a: skipped (--skip-t3a) ===');
|
|
612
|
+
} else {
|
|
613
|
+
console.log('\n=== T3a: non-probe chat protocol (expect paris) ===');
|
|
614
|
+
const t2aBefore = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}/chats`);
|
|
615
|
+
assert(t2aBefore.status === 200, `T3a pre chats returned ${t2aBefore.status}`);
|
|
616
|
+
const t2aBeforeMessages = Array.isArray(t2aBefore.data?.messages) ? t2aBefore.data.messages : [];
|
|
617
|
+
const t2aBeforeCount = t2aBeforeMessages.length;
|
|
618
|
+
const t2aPrompt = 'Just answer what is the capital of France. No Fluff. No COmmentary. No Markup Respond in lower case in one word.';
|
|
619
|
+
|
|
620
|
+
const t2aSendRes = await httpJson('POST', `${BASE}/cards/${CHAT_CARD_ID}/actions`, {
|
|
621
|
+
actionType: 'chat-send',
|
|
622
|
+
payload: {
|
|
623
|
+
text: JSON.stringify({
|
|
624
|
+
prompt: t2aPrompt,
|
|
625
|
+
chatTimeoutMs: 180000,
|
|
626
|
+
}),
|
|
627
|
+
},
|
|
628
|
+
});
|
|
629
|
+
assert(t2aSendRes.status === 200, `T3a chat-send returned ${t2aSendRes.status}`);
|
|
630
|
+
|
|
631
|
+
const t2aAssistant = await waitForChatPredicate((events) => {
|
|
632
|
+
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
633
|
+
const e = events[i];
|
|
634
|
+
if (e.messageCount < t2aBeforeCount + 2) continue;
|
|
635
|
+
const last = e.messages[e.messages.length - 1];
|
|
636
|
+
if (last?.role === 'assistant' && /paris/i.test(String(last.text || ''))) return e;
|
|
637
|
+
}
|
|
638
|
+
return false;
|
|
639
|
+
}, 240_000, 'T3a assistant response with paris');
|
|
640
|
+
assert(!!t2aAssistant, 'T3a assistant response with paris not observed on SSE');
|
|
641
|
+
|
|
642
|
+
const t2aAfter = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}/chats`);
|
|
643
|
+
assert(t2aAfter.status === 200, `T3a post chats returned ${t2aAfter.status}`);
|
|
644
|
+
const t2aAfterMessages = Array.isArray(t2aAfter.data?.messages) ? t2aAfter.data.messages : [];
|
|
645
|
+
const t2aNewMessages = t2aAfterMessages.slice(t2aBeforeCount);
|
|
646
|
+
assert(t2aNewMessages.length >= 2, `T3a expected at least 2 new chat messages, got ${t2aNewMessages.length}`);
|
|
647
|
+
const t2aAssistantMsg = [...t2aNewMessages].reverse().find((m) => m?.role === 'assistant');
|
|
648
|
+
assert(!!t2aAssistantMsg && typeof t2aAssistantMsg.id === 'string', 'T3a assistant chat message missing id');
|
|
649
|
+
assert(/paris/i.test(String(t2aAssistantMsg?.text || '')), 'T3a assistant file content missing paris');
|
|
650
|
+
console.log('[T3a] ok: non-probe response contains paris');
|
|
651
|
+
}
|
|
604
652
|
|
|
605
653
|
// ── T3b: probe-echo chat + file upload protocol over API + SSE ──
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
654
|
+
if (skipT3b) {
|
|
655
|
+
console.log('\n=== T3b: skipped (--skip-t3b) ===');
|
|
656
|
+
} else {
|
|
657
|
+
console.log('\n=== T3b: probe-echo chat with file upload protocol ===');
|
|
658
|
+
const t2bBefore = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}/chats`);
|
|
659
|
+
assert(t2bBefore.status === 200, `T3b pre chats returned ${t2bBefore.status}`);
|
|
660
|
+
const t2bBeforeMessages = Array.isArray(t2bBefore.data?.messages) ? t2bBefore.data.messages : [];
|
|
661
|
+
const t2bBeforeCount = t2bBeforeMessages.length;
|
|
662
|
+
|
|
663
|
+
const t2bUploadRes = await httpUploadChatFile(
|
|
664
|
+
`${BASE}/cards/${CHAT_CARD_ID}/files?inChat=true`,
|
|
665
|
+
'q1.txt',
|
|
666
|
+
'what is the capital of japan',
|
|
667
|
+
);
|
|
668
|
+
assert(t2bUploadRes.status === 200, `T3b file upload returned ${t2bUploadRes.status}`);
|
|
669
|
+
const uploadedFile = t2bUploadRes.data?.file;
|
|
670
|
+
assert(uploadedFile && typeof uploadedFile === 'object', 'T3b upload response missing file metadata');
|
|
671
|
+
|
|
672
|
+
const t2bAfterUpload = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}/chats`);
|
|
673
|
+
assert(t2bAfterUpload.status === 200, `T3b chats after upload returned ${t2bAfterUpload.status}`);
|
|
674
|
+
const t2bUploadMessages = Array.isArray(t2bAfterUpload.data?.messages) ? t2bAfterUpload.data.messages : [];
|
|
675
|
+
const t2bUploadNewMessages = t2bUploadMessages.slice(t2bBeforeCount);
|
|
676
|
+
const t2bUploadSystem = t2bUploadNewMessages.find((m) => m?.role === 'system');
|
|
677
|
+
assert(!!t2bUploadSystem, 'T3b upload protocol missing system chat file');
|
|
678
|
+
assert(String(t2bUploadSystem?.text || '').toLowerCase().includes('file uploaded:'), 'T3b upload system message does not describe uploaded file');
|
|
679
|
+
|
|
680
|
+
const t2bSendBaseline = t2bUploadMessages.length;
|
|
681
|
+
const t2bEventStart = NS.chatEvents.length;
|
|
682
|
+
|
|
683
|
+
const t2bPrompt = `probe echo file-upload validation ${Date.now()}`;
|
|
684
|
+
const t2bSendRes = await httpJson('POST', `${BASE}/cards/${CHAT_CARD_ID}/actions`, {
|
|
685
|
+
actionType: 'chat-send',
|
|
686
|
+
payload: {
|
|
687
|
+
text: `${ECHO_PROBE_MARKER}${t2bPrompt}${ECHO_PROBE_MARKER}`,
|
|
688
|
+
files: [uploadedFile],
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
assert(t2bSendRes.status === 200, `T3b chat-send returned ${t2bSendRes.status}`);
|
|
644
692
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
const t2bAssistantMsg = t2bNewMessages.find((m) => m?.role === 'assistant');
|
|
673
|
-
|
|
674
|
-
assert(!!t2bUser && typeof t2bUser.id === 'string', 'T3b missing user chat message notification');
|
|
675
|
-
assert(!!t2bAssistantMsg && typeof t2bAssistantMsg.id === 'string', 'T3b missing assistant chat message notification');
|
|
676
|
-
assert(Array.isArray(t2bUser?.files) && t2bUser.files.length === 1, 'T3b user chat message missing uploaded file metadata');
|
|
677
|
-
assert(String(t2bAssistantMsg?.text || '').includes(`Echo: ${t2bPrompt}`), 'T3b assistant file content mismatch');
|
|
678
|
-
|
|
679
|
-
const t2bProcessingCleared = await waitForChatPredicate((events) => {
|
|
680
|
-
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
681
|
-
const e = events[i];
|
|
682
|
-
if (e.messageCount >= t2bSendBaseline + 2 && e.processing === false) return e;
|
|
683
|
-
}
|
|
684
|
-
return false;
|
|
685
|
-
}, 30_000, 'T3b processing clear');
|
|
686
|
-
assert(!!t2bProcessingCleared, 'T3b processing clear not observed');
|
|
687
|
-
console.log('[T3b] ok: upload protocol (system/user) and chat protocol (.processing/user/assistant/.processing clear) observed');
|
|
693
|
+
const t2bLifecycle = await waitForChatPredicate((events) => {
|
|
694
|
+
return matchOrderedProbeLifecycle(events.slice(t2bEventStart), {
|
|
695
|
+
beforeCount: t2bSendBaseline,
|
|
696
|
+
beforeProcessing: false,
|
|
697
|
+
prompt: t2bPrompt,
|
|
698
|
+
inProgressText: PROBE_IN_PROGRESS_TEXT,
|
|
699
|
+
});
|
|
700
|
+
}, 60_000, 'T3b ordered lifecycle');
|
|
701
|
+
assert(!!t2bLifecycle, 'T3b ordered lifecycle not observed');
|
|
702
|
+
|
|
703
|
+
const t2bAfter = await httpGet(`${BASE}/cards/${CHAT_CARD_ID}/chats`);
|
|
704
|
+
assert(t2bAfter.status === 200, `T3b post chats returned ${t2bAfter.status}`);
|
|
705
|
+
const t2bAfterMessages = Array.isArray(t2bAfter.data?.messages) ? t2bAfter.data.messages : [];
|
|
706
|
+
const t2bNewMessages = t2bAfterMessages.slice(t2bSendBaseline);
|
|
707
|
+
assert(t2bNewMessages.length >= 3, `T3b expected at least 3 chat messages after send, got ${t2bNewMessages.length}`);
|
|
708
|
+
|
|
709
|
+
const t2bUser = t2bNewMessages.find((m) => m?.role === 'user');
|
|
710
|
+
const t2bInProgress = t2bNewMessages.find((m) => m?.role === 'system' && String(m?.text || '').trim().toLowerCase() === PROBE_IN_PROGRESS_TEXT);
|
|
711
|
+
const t2bAssistantMsg = t2bNewMessages.find((m) => m?.role === 'assistant');
|
|
712
|
+
|
|
713
|
+
assert(!!t2bUser && typeof t2bUser.id === 'string', 'T3b missing user chat message notification');
|
|
714
|
+
assert(!!t2bInProgress && typeof t2bInProgress.id === 'string', 'T3b missing in-progress system chat message');
|
|
715
|
+
assert(!!t2bAssistantMsg && typeof t2bAssistantMsg.id === 'string', 'T3b missing assistant chat message notification');
|
|
716
|
+
assert(Array.isArray(t2bUser?.files) && t2bUser.files.length === 1, 'T3b user chat message missing uploaded file metadata');
|
|
717
|
+
assert(String(t2bAssistantMsg?.text || '').includes(`Echo: ${t2bPrompt}`), 'T3b assistant file content mismatch');
|
|
718
|
+
console.log('[T3b] ok: upload protocol and ordered probe lifecycle observed (user+processing, in-progress, assistant+processing clear)');
|
|
719
|
+
}
|
|
688
720
|
}
|
|
689
721
|
|
|
690
722
|
console.log('\n=== All smoke checks passed ===\n');
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
<title>Example Board Demo (LocalStorage Runtime)</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="../../browser/favicon.svg" />
|
|
8
8
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
9
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.3.0/browser/compute-jsonata.js"></script>
|
|
10
10
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
11
11
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
12
12
|
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
|
|
13
13
|
<script src="https://cdn.jsdelivr.net/npm/leader-line/leader-line.min.js"></script>
|
|
14
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.
|
|
15
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.3.0/browser/live-cards.js"></script>
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.3.0/browser/board-livecards-localstorage.js"></script>
|
|
16
16
|
</head>
|
|
17
17
|
<body class="bg-light">
|
|
18
18
|
<div class="container-fluid py-3">
|
package/lib/{artifacts-store-lib-public-C5UL5tyG.d.cts → artifacts-store-lib-public-Cz8-kdXG.d.cts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CommandInput, a as CommandResult } from './board-live-cards-public-
|
|
1
|
+
import { C as CommandInput, a as CommandResult } from './board-live-cards-public-BwZYGAsF.cjs';
|
|
2
2
|
import { B as BlobStorage } from './storage-interface-B6ecOulj.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import './board-live-cards-public-
|
|
2
|
-
export { A as ArtifactsStorePublic, a as createArtifactsStorePublic } from './artifacts-store-lib-public-
|
|
1
|
+
import './board-live-cards-public-BwZYGAsF.cjs';
|
|
2
|
+
export { A as ArtifactsStorePublic, a as createArtifactsStorePublic } from './artifacts-store-lib-public-Cz8-kdXG.cjs';
|
|
3
3
|
import './storage-interface-B6ecOulj.cjs';
|
|
4
4
|
import './execution-refs.cjs';
|
|
5
5
|
import './types-BBhqYGhE.cjs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import './board-live-cards-public-
|
|
2
|
-
export { A as ArtifactsStorePublic, a as createArtifactsStorePublic } from './artifacts-store-lib-public-
|
|
1
|
+
import './board-live-cards-public-DWpZVDXN.js';
|
|
2
|
+
export { A as ArtifactsStorePublic, a as createArtifactsStorePublic } from './artifacts-store-lib-public-ksGIExhc.js';
|
|
3
3
|
import './storage-interface-B6ecOulj.js';
|
|
4
4
|
import './execution-refs.js';
|
|
5
5
|
import './types-BBhqYGhE.js';
|