yaml-flow 5.2.2 → 5.2.5

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.
@@ -4,9 +4,15 @@
4
4
  * Invoked by reusable-server-runtime after a user message is persisted:
5
5
  * node demo-chat-handler.js --boardId <id> --cardId <id> --extraEncJson <base64json>
6
6
  *
7
- * extraEncJson decodes to: { chatDir, boardDir, lastChatFile }
7
+ * extraEncJson decodes to:
8
+ * boardSetupRoot — absolute path to board root (parent of runtime/, surface/, runtime-out/)
9
+ * boardRuntimeDir — relative subdir: 'runtime'
10
+ * runtimeStatusDir— relative subdir: 'runtime-out'
11
+ * cardsDir — relative subdir: 'surface/tmp-cards'
12
+ * chatDir — absolute path to the card's chats directory
13
+ * lastChatFile — filename of the just-written user message, e.g. '001_user.txt'
8
14
  *
9
- * If the card has a source entry containing a "copilot" key, invokes copilot_wrapper.bat.
15
+ * Invokes copilot_wrapper.bat with a prompt built from conversation history.
10
16
  * Session dir is per-card: os.tmpdir()/demo-chat-handler-sessions/<boardId>_<cardId>
11
17
  */
12
18
 
@@ -27,19 +33,27 @@ function getArg(name) {
27
33
  return idx !== -1 && args[idx + 1] !== undefined ? args[idx + 1] : null;
28
34
  }
29
35
 
30
- const boardId = getArg('--boardId') || '';
31
- const cardId = getArg('--cardId') || '';
32
- const extraStr = getArg('--extraEncJson') || '';
36
+ const boardId = getArg('--boardId') || '';
37
+ const cardId = getArg('--cardId') || '';
38
+ const extraStr = getArg('--extraEncJson') || '';
39
+ const cleanOnExit = getArg('--cleanOnExit') || '';
33
40
 
34
41
  let extra = {};
35
42
  try { extra = JSON.parse(Buffer.from(extraStr, 'base64').toString('utf-8')); }
36
43
  catch { console.error('[demo-chat-handler] bad --extraEncJson'); process.exit(0); }
37
44
 
38
- const { chatDir, boardDir, lastChatFile } = extra;
39
- console.error('[demo-chat-handler] missing chatDir/lastChatFile');
45
+ const { boardSetupRoot, boardRuntimeDir, runtimeStatusDir, cardsDir, chatDir, lastChatFile } = extra;
46
+ if (!boardSetupRoot || !chatDir || !lastChatFile) {
47
+ console.error('[demo-chat-handler] missing boardSetupRoot/chatDir/lastChatFile');
40
48
  process.exit(0);
41
49
  }
42
50
 
51
+ // Resolve absolute paths from the structured extra fields
52
+ const boardRuntimeDirAbs = path.join(boardSetupRoot, boardRuntimeDir || 'runtime');
53
+ const runtimeStatusDirAbs = path.join(boardSetupRoot, runtimeStatusDir || 'runtime-out');
54
+ const cardsDirAbs = path.join(boardSetupRoot, cardsDir || path.join('surface', 'tmp-cards'));
55
+ const chatDirAbs = chatDir;
56
+
43
57
  // ---------------------------------------------------------------------------
44
58
  // Read conversation history
45
59
  // ---------------------------------------------------------------------------
@@ -57,29 +71,31 @@ function readHistory(dir) {
57
71
  } catch { return []; }
58
72
  }
59
73
 
60
- // ---------------------------------------------------------------------------
61
- // Check if card has a 'copilot' source entry
62
- // ---------------------------------------------------------------------------
63
- function hasCopilotSource(bDir, cId) {
64
- try {
65
- const boardGraph = JSON.parse(fs.readFileSync(path.join(bDir, 'board-graph.json'), 'utf-8'));
66
- const nodes = boardGraph?.graph?.nodes ?? boardGraph?.nodes ?? {};
67
- const card = nodes[cId];
68
- const sources = card.sources ?? card.card_data?.sources ?? [];
69
- if (Array.isArray(sources)) return sources.some(s => s && typeof s === 'object' && 'copilot' in s);
70
- if (typeof sources === 'object') return 'copilot' in sources;
71
- return false;
72
- } catch { return false; }
73
- }
74
-
75
74
  // ---------------------------------------------------------------------------
76
75
  // Build prompt
77
76
  // ---------------------------------------------------------------------------
78
- function buildPrompt(cId, bId, history) {
77
+ function buildPrompt(cId, bId, history, responseFileRel) {
78
+ const cardSetupDirRel = path.join(cardsDir, cId).replace(/\\/g, '/');
79
+ const runtimeDirRel = boardRuntimeDir || 'runtime';
80
+ const statusDirRel = runtimeStatusDir || 'runtime-out';
81
+ const chatDirRel = path.relative(boardSetupRoot, chatDir).replace(/\\/g, '/');
82
+ const lastQueryFileRel = path.join(chatDirRel, lastChatFile).replace(/\\/g, '/');
83
+
84
+ const contextBlock = [
85
+ 'We are currently doing a three way orchestration.',
86
+ 'You are the responder who has context of the cards in ' + cardSetupDirRel + ',',
87
+ 'card runtime statuses in ' + runtimeDirRel + ',',
88
+ 'and computed outputs in ' + statusDirRel + '.',
89
+ 'I am just a mediator passing on the query.',
90
+ 'The user sees the data available in cards which is rendered, and the status from ' + statusDirRel + '.',
91
+ 'Everything else is internal detail not to be exposed to the user.',
92
+ 'The conversation history can be found in ' + chatDirRel + ' and the last query is in ' + lastQueryFileRel + '.',
93
+ 'Write your response to the user in ' + responseFileRel + ' (relative to your working directory).',
94
+ 'Give me only a bare minimum log line on what you did — the response in ' + responseFileRel + ' is what the user will see.',
95
+ ].join(' ');
96
+
79
97
  return [
80
- 'You are a helpful assistant embedded in a live card (card: "' + cId + '", board: "' + bId + '").',
81
- 'Help the user understand and act on the data shown in this card.',
82
- 'Be concise.',
98
+ contextBlock,
83
99
  '',
84
100
  ...history,
85
101
  'Assistant:',
@@ -120,32 +136,23 @@ function runWrapper(prompt, sessionDir, workingDir) {
120
136
  // ---------------------------------------------------------------------------
121
137
  // Main
122
138
  // ---------------------------------------------------------------------------
123
- const history = readHistory(chatDir);
124
- const sessionDir = path.join(os.tmpdir(), 'demo-chat-handler-sessions', boardId + '_' + cardId);
125
- const workingDir = boardDir || process.cwd();
126
- const prompt = buildPrompt(cardId, boardId, history);
139
+ const serialMatch = String(lastChatFile).match(/^(\d+)/);
140
+ const nextSerial = serialMatch ? parseInt(serialMatch[1], 10) + 1 : 1;
141
+ const nextName = String(nextSerial).padStart(3, '0') + '-assistant.txt';
142
+ const responseFileRel = path.relative(boardSetupRoot, path.join(chatDir, nextName)).replace(/\\/g, '/');
127
143
 
128
- let response = '';
129
- if (hasCopilotSource(boardDir, cardId)) {
130
- try {
131
- response = runWrapper(prompt, sessionDir, workingDir);
132
- } catch (err) {
133
- response = 'Sorry, I could not reach the LLM right now. (' + String(err?.message ?? err).slice(0, 120) + ')';
134
- console.error('[demo-chat-handler] wrapper failed: ' + (err?.message ?? err));
135
- }
136
- } else {
137
- response = 'No copilot source configured for this card.';
138
- }
139
-
140
- // Write assistant response as next serial file
141
- const serialMatch = String(lastChatFile).match(/^(\d+)/);
142
- const nextSerial = serialMatch ? parseInt(serialMatch[1], 10) + 1 : 1;
143
- const nextName = String(nextSerial).padStart(3, '0') + '-assistant.txt';
144
- const nextPath = path.join(chatDir, nextName);
144
+ const history = readHistory(chatDirAbs);
145
+ const sessionDir = path.join(os.tmpdir(), 'demo-chat-handler-sessions', boardId + '_' + cardId);
146
+ const workingDir = boardSetupRoot;
147
+ const prompt = buildPrompt(cardId, boardId, history, responseFileRel);
145
148
 
146
149
  try {
147
- fs.writeFileSync(nextPath, response + '\n', 'utf-8');
148
- console.log('[demo-chat-handler] cardId="' + cardId + '" wrote response -> ' + nextPath);
150
+ runWrapper(prompt, sessionDir, workingDir);
151
+ console.log('[demo-chat-handler] cardId="' + cardId + '" copilot invoked, response expected at ' + responseFileRel);
149
152
  } catch (err) {
150
- console.error('[demo-chat-handler] write failed: ' + err.message);
153
+ console.error('[demo-chat-handler] wrapper failed: ' + (err?.message ?? err));
154
+ } finally {
155
+ if (cleanOnExit) {
156
+ try { fs.unlinkSync(cleanOnExit); } catch {}
157
+ }
151
158
  }
@@ -3,6 +3,7 @@
3
3
  import http from 'node:http';
4
4
  import fs from 'node:fs';
5
5
  import path from 'node:path';
6
+ import os from 'node:os';
6
7
  import { fileURLToPath } from 'node:url';
7
8
  import { createRequire } from 'node:module';
8
9
 
@@ -90,6 +91,11 @@ function resetRuntime() {
90
91
  fs.rmSync(setupDir, { recursive: true, force: true });
91
92
  console.log(`[demo-server] reset: wiped ${setupDir}`);
92
93
  }
94
+ const chatSessions = path.join(os.tmpdir(), 'demo-chat-handler-sessions');
95
+ if (fs.existsSync(chatSessions)) {
96
+ fs.rmSync(chatSessions, { recursive: true, force: true });
97
+ console.log(`[demo-server] reset: wiped ${chatSessions}`);
98
+ }
93
99
  }
94
100
 
95
101
  if (RESET_ON_START) {
@@ -6,9 +6,9 @@
6
6
  <title>Example Board Demo (Browser Runtime)</title>
7
7
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
8
8
  <script src="https://cdn.jsdelivr.net/npm/jsonata/jsonata.min.js"></script>
9
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/card-compute.js"></script>
10
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/live-cards.js"></script>
11
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/board-livegraph-engine.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/card-compute.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/live-cards.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/board-livegraph-engine.js"></script>
12
12
  </head>
13
13
  <body class="bg-light">
14
14
  <div class="container-fluid py-3">
@@ -16,10 +16,10 @@
16
16
  </style>
17
17
  <script src="https://cdn.jsdelivr.net/npm/jsonata/jsonata.min.js"></script>
18
18
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
19
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/card-compute.js"></script>
20
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/live-cards.js"></script>
21
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/board-livegraph-engine.js"></script>
22
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.2/browser/board-livecards-runtime-client.js"></script>
19
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/card-compute.js"></script>
20
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/live-cards.js"></script>
21
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/board-livegraph-engine.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/board-livecards-runtime-client.js"></script>
23
23
  </head>
24
24
  <body class="bg-light">
25
25
  <div class="container-fluid py-3">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaml-flow",
3
- "version": "5.2.2",
3
+ "version": "5.2.5",
4
4
  "description": "Unified workflow engine: step-machine (sequential) + event-graph (stateless DAG) with pluggable storage",
5
5
  "author": "",
6
6
  "license": "MIT",