From 86db0228c8e2516fd71d23cd69a679bbd5334bfe Mon Sep 17 00:00:00 2001 From: Greg Konush <12027037+gregkonush@users.noreply.github.com> Date: Sat, 23 May 2026 11:15:39 -0700 Subject: [PATCH 1/3] feature: add Bilig WorkPaper formula readback tool --- .../tools/Bilig WorkPaper Formula Readback.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json diff --git a/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json b/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json new file mode 100644 index 00000000000..681c518931b --- /dev/null +++ b/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json @@ -0,0 +1,8 @@ +{ + "name": "bilig_workpaper_formula_readback", + "description": "Useful when an agent needs to edit one spreadsheet input, recalculate formulas, and verify the computed readback without Excel or browser automation.", + "color": "linear-gradient(rgb(24,96,122), rgb(48,159,108))", + "iconSrc": "https://github.com/proompteng.png", + "schema": "[{\"id\":0,\"property\":\"baseUrl\",\"description\":\"Bilig base URL. Use https://bilig.proompteng.ai for the hosted demo or your self-hosted Bilig URL.\",\"type\":\"string\",\"required\":false},{\"id\":1,\"property\":\"sheetName\",\"description\":\"Worksheet containing the editable forecast input. Default: Inputs\",\"type\":\"string\",\"required\":false},{\"id\":2,\"property\":\"address\",\"description\":\"A1-style input cell address to edit. Default: B3\",\"type\":\"string\",\"required\":false},{\"id\":3,\"property\":\"value\",\"description\":\"Numeric value to write before formula readback. Default: 0.4\",\"type\":\"number\",\"required\":false}]", + "func": "const fetch = require('node-fetch');\n\nconst baseUrl = String($baseUrl || 'https://bilig.proompteng.ai').replace(/\\/$/, '');\nconst sheetName = String($sheetName || 'Inputs');\nconst address = String($address || 'B3').toUpperCase();\nconst value = $value === undefined || $value === null || $value === '' ? 0.4 : Number($value);\n\nif (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n return 'Bilig WorkPaper formula readback failed: baseUrl must start with http:// or https://';\n}\n\nif (!Number.isFinite(value)) {\n return `Bilig WorkPaper formula readback failed: value must be numeric, received ${JSON.stringify($value)}`;\n}\n\nconst response = await fetch(`${baseUrl}/api/workpaper/n8n/forecast`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'User-Agent': 'Flowise-Bilig-WorkPaper-Tool/0.1'\n },\n body: JSON.stringify({ sheetName, address, value })\n});\n\nconst text = await response.text();\nlet proof;\ntry {\n proof = JSON.parse(text);\n} catch (error) {\n return `Bilig WorkPaper formula readback failed: expected JSON but received ${text.slice(0, 500)}`;\n}\n\nif (!response.ok) {\n return `Bilig WorkPaper formula readback failed: HTTP ${response.status} ${response.statusText} - ${JSON.stringify(proof)}`;\n}\n\nif (proof.verified !== true) {\n return `Bilig WorkPaper formula readback failed: unverified response ${JSON.stringify(proof)}`;\n}\n\nconst checks = proof.checks || {};\nconst before = proof.before || {};\nconst after = proof.after || {};\nconst compactProof = {\n verified: true,\n editedCell: proof.editedCell,\n before: {\n expectedArr: before.expectedArr,\n targetGap: before.targetGap\n },\n after: {\n expectedArr: after.expectedArr,\n targetGap: after.targetGap\n },\n checks: {\n formulasPersisted: checks.formulasPersisted === true,\n restoredMatchesAfter: checks.restoredMatchesAfter === true,\n computedOutputChanged: checks.computedOutputChanged === true\n },\n source: 'Bilig WorkPaper',\n github: 'https://github.com/proompteng/bilig'\n};\n\nreturn JSON.stringify(compactProof, null, 2);" +} From 1e7115891389a681ff5786a676ffb1af0e354c7c Mon Sep 17 00:00:00 2001 From: Greg Konush <12027037+gregkonush@users.noreply.github.com> Date: Sat, 23 May 2026 11:33:52 -0700 Subject: [PATCH 2/3] fix: harden Bilig WorkPaper marketplace tool --- .../marketplaces/tools/Bilig WorkPaper Formula Readback.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json b/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json index 681c518931b..5aa352e29db 100644 --- a/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json +++ b/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json @@ -4,5 +4,5 @@ "color": "linear-gradient(rgb(24,96,122), rgb(48,159,108))", "iconSrc": "https://github.com/proompteng.png", "schema": "[{\"id\":0,\"property\":\"baseUrl\",\"description\":\"Bilig base URL. Use https://bilig.proompteng.ai for the hosted demo or your self-hosted Bilig URL.\",\"type\":\"string\",\"required\":false},{\"id\":1,\"property\":\"sheetName\",\"description\":\"Worksheet containing the editable forecast input. Default: Inputs\",\"type\":\"string\",\"required\":false},{\"id\":2,\"property\":\"address\",\"description\":\"A1-style input cell address to edit. Default: B3\",\"type\":\"string\",\"required\":false},{\"id\":3,\"property\":\"value\",\"description\":\"Numeric value to write before formula readback. Default: 0.4\",\"type\":\"number\",\"required\":false}]", - "func": "const fetch = require('node-fetch');\n\nconst baseUrl = String($baseUrl || 'https://bilig.proompteng.ai').replace(/\\/$/, '');\nconst sheetName = String($sheetName || 'Inputs');\nconst address = String($address || 'B3').toUpperCase();\nconst value = $value === undefined || $value === null || $value === '' ? 0.4 : Number($value);\n\nif (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n return 'Bilig WorkPaper formula readback failed: baseUrl must start with http:// or https://';\n}\n\nif (!Number.isFinite(value)) {\n return `Bilig WorkPaper formula readback failed: value must be numeric, received ${JSON.stringify($value)}`;\n}\n\nconst response = await fetch(`${baseUrl}/api/workpaper/n8n/forecast`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'User-Agent': 'Flowise-Bilig-WorkPaper-Tool/0.1'\n },\n body: JSON.stringify({ sheetName, address, value })\n});\n\nconst text = await response.text();\nlet proof;\ntry {\n proof = JSON.parse(text);\n} catch (error) {\n return `Bilig WorkPaper formula readback failed: expected JSON but received ${text.slice(0, 500)}`;\n}\n\nif (!response.ok) {\n return `Bilig WorkPaper formula readback failed: HTTP ${response.status} ${response.statusText} - ${JSON.stringify(proof)}`;\n}\n\nif (proof.verified !== true) {\n return `Bilig WorkPaper formula readback failed: unverified response ${JSON.stringify(proof)}`;\n}\n\nconst checks = proof.checks || {};\nconst before = proof.before || {};\nconst after = proof.after || {};\nconst compactProof = {\n verified: true,\n editedCell: proof.editedCell,\n before: {\n expectedArr: before.expectedArr,\n targetGap: before.targetGap\n },\n after: {\n expectedArr: after.expectedArr,\n targetGap: after.targetGap\n },\n checks: {\n formulasPersisted: checks.formulasPersisted === true,\n restoredMatchesAfter: checks.restoredMatchesAfter === true,\n computedOutputChanged: checks.computedOutputChanged === true\n },\n source: 'Bilig WorkPaper',\n github: 'https://github.com/proompteng/bilig'\n};\n\nreturn JSON.stringify(compactProof, null, 2);" + "func": "const fetch = require('node-fetch');\n\nconst baseUrl = String($baseUrl || 'https://bilig.proompteng.ai').replace(/\\/$/, '');\nconst sheetName = String($sheetName || 'Inputs');\nconst address = String($address || 'B3').toUpperCase();\nconst value = $value == null || $value === '' ? 0.4 : Number($value);\n\nif (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n return 'Bilig WorkPaper formula readback failed: baseUrl must start with http:// or https://';\n}\n\nif (!Number.isFinite(value)) {\n return `Bilig WorkPaper formula readback failed: value must be numeric, received ${JSON.stringify($value)}`;\n}\n\nconst response = await fetch(`${baseUrl}/api/workpaper/n8n/forecast`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'User-Agent': 'Flowise-Bilig-WorkPaper-Tool/0.1'\n },\n body: JSON.stringify({ sheetName, address, value })\n});\n\nconst text = await response.text();\nlet proof;\ntry {\n proof = JSON.parse(text);\n} catch (error) {\n return `Bilig WorkPaper formula readback failed: expected JSON but received ${text.slice(0, 500)}`;\n}\n\nif (proof === null || typeof proof !== 'object' || Array.isArray(proof)) {\n return `Bilig WorkPaper formula readback failed: expected JSON object response, received ${Array.isArray(proof) ? 'array' : typeof proof}`;\n}\n\nif (!response.ok) {\n return `Bilig WorkPaper formula readback failed: HTTP ${response.status} ${response.statusText} - ${JSON.stringify(proof)}`;\n}\n\nif (proof.verified !== true) {\n const proofId = proof.workpaper_id || proof.id || 'unknown';\n return `Bilig WorkPaper formula readback failed: unverified response (verified=${proof.verified}) for workpaper_id=${proofId}`;\n}\n\nconst checks = proof.checks && typeof proof.checks === 'object' && !Array.isArray(proof.checks) ? proof.checks : {};\nconst before = proof.before && typeof proof.before === 'object' && !Array.isArray(proof.before) ? proof.before : {};\nconst after = proof.after && typeof proof.after === 'object' && !Array.isArray(proof.after) ? proof.after : {};\nconst compactProof = {\n verified: true,\n editedCell: proof.editedCell,\n before: {\n expectedArr: before.expectedArr,\n targetGap: before.targetGap\n },\n after: {\n expectedArr: after.expectedArr,\n targetGap: after.targetGap\n },\n checks: {\n formulasPersisted: checks.formulasPersisted === true,\n restoredMatchesAfter: checks.restoredMatchesAfter === true,\n computedOutputChanged: checks.computedOutputChanged === true\n },\n source: 'Bilig WorkPaper',\n github: 'https://github.com/proompteng/bilig'\n};\n\nreturn JSON.stringify(compactProof, null, 2);" } From de2206695c6372616555c2aae4881f0f1f7b211a Mon Sep 17 00:00:00 2001 From: Greg Konush <12027037+gregkonush@users.noreply.github.com> Date: Sun, 31 May 2026 05:45:39 -0700 Subject: [PATCH 3/3] fix(tools): harden Bilig readback proof parsing --- .../marketplaces/tools/Bilig WorkPaper Formula Readback.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json b/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json index 5aa352e29db..596a7899875 100644 --- a/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json +++ b/packages/server/marketplaces/tools/Bilig WorkPaper Formula Readback.json @@ -4,5 +4,5 @@ "color": "linear-gradient(rgb(24,96,122), rgb(48,159,108))", "iconSrc": "https://github.com/proompteng.png", "schema": "[{\"id\":0,\"property\":\"baseUrl\",\"description\":\"Bilig base URL. Use https://bilig.proompteng.ai for the hosted demo or your self-hosted Bilig URL.\",\"type\":\"string\",\"required\":false},{\"id\":1,\"property\":\"sheetName\",\"description\":\"Worksheet containing the editable forecast input. Default: Inputs\",\"type\":\"string\",\"required\":false},{\"id\":2,\"property\":\"address\",\"description\":\"A1-style input cell address to edit. Default: B3\",\"type\":\"string\",\"required\":false},{\"id\":3,\"property\":\"value\",\"description\":\"Numeric value to write before formula readback. Default: 0.4\",\"type\":\"number\",\"required\":false}]", - "func": "const fetch = require('node-fetch');\n\nconst baseUrl = String($baseUrl || 'https://bilig.proompteng.ai').replace(/\\/$/, '');\nconst sheetName = String($sheetName || 'Inputs');\nconst address = String($address || 'B3').toUpperCase();\nconst value = $value == null || $value === '' ? 0.4 : Number($value);\n\nif (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n return 'Bilig WorkPaper formula readback failed: baseUrl must start with http:// or https://';\n}\n\nif (!Number.isFinite(value)) {\n return `Bilig WorkPaper formula readback failed: value must be numeric, received ${JSON.stringify($value)}`;\n}\n\nconst response = await fetch(`${baseUrl}/api/workpaper/n8n/forecast`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'User-Agent': 'Flowise-Bilig-WorkPaper-Tool/0.1'\n },\n body: JSON.stringify({ sheetName, address, value })\n});\n\nconst text = await response.text();\nlet proof;\ntry {\n proof = JSON.parse(text);\n} catch (error) {\n return `Bilig WorkPaper formula readback failed: expected JSON but received ${text.slice(0, 500)}`;\n}\n\nif (proof === null || typeof proof !== 'object' || Array.isArray(proof)) {\n return `Bilig WorkPaper formula readback failed: expected JSON object response, received ${Array.isArray(proof) ? 'array' : typeof proof}`;\n}\n\nif (!response.ok) {\n return `Bilig WorkPaper formula readback failed: HTTP ${response.status} ${response.statusText} - ${JSON.stringify(proof)}`;\n}\n\nif (proof.verified !== true) {\n const proofId = proof.workpaper_id || proof.id || 'unknown';\n return `Bilig WorkPaper formula readback failed: unverified response (verified=${proof.verified}) for workpaper_id=${proofId}`;\n}\n\nconst checks = proof.checks && typeof proof.checks === 'object' && !Array.isArray(proof.checks) ? proof.checks : {};\nconst before = proof.before && typeof proof.before === 'object' && !Array.isArray(proof.before) ? proof.before : {};\nconst after = proof.after && typeof proof.after === 'object' && !Array.isArray(proof.after) ? proof.after : {};\nconst compactProof = {\n verified: true,\n editedCell: proof.editedCell,\n before: {\n expectedArr: before.expectedArr,\n targetGap: before.targetGap\n },\n after: {\n expectedArr: after.expectedArr,\n targetGap: after.targetGap\n },\n checks: {\n formulasPersisted: checks.formulasPersisted === true,\n restoredMatchesAfter: checks.restoredMatchesAfter === true,\n computedOutputChanged: checks.computedOutputChanged === true\n },\n source: 'Bilig WorkPaper',\n github: 'https://github.com/proompteng/bilig'\n};\n\nreturn JSON.stringify(compactProof, null, 2);" + "func": "const fetch = require('node-fetch');\n\nconst baseUrl = String($baseUrl || 'https://bilig.proompteng.ai').replace(/\\/$/, '');\nconst sheetName = String($sheetName || 'Inputs');\nconst address = String($address || 'B3').toUpperCase();\nconst value = $value == null || $value === '' ? 0.4 : Number($value);\n\nif (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n return 'Bilig WorkPaper formula readback failed: baseUrl must start with http:// or https://';\n}\n\nif (!Number.isFinite(value)) {\n return `Bilig WorkPaper formula readback failed: value must be numeric, received ${JSON.stringify($value)}`;\n}\n\nconst response = await fetch(`${baseUrl}/api/workpaper/n8n/forecast`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'User-Agent': 'Flowise-Bilig-WorkPaper-Tool/0.1'\n },\n body: JSON.stringify({ sheetName, address, value })\n});\n\nconst text = await response.text();\nlet proof;\ntry {\n proof = JSON.parse(text);\n} catch (error) {\n return `Bilig WorkPaper formula readback failed: expected JSON but received ${text.slice(0, 500)}`;\n}\n\nif (proof == null || typeof proof !== 'object' || Array.isArray(proof)) {\n return `Bilig WorkPaper formula readback failed: expected JSON object response, received ${Array.isArray(proof) ? 'array' : typeof proof}`;\n}\n\nif (!response.ok) {\n return `Bilig WorkPaper formula readback failed: HTTP ${response.status} ${response.statusText} - ${JSON.stringify(proof)}`;\n}\n\nif (proof.verified !== true) {\n const proofId = proof.workpaper_id || proof.id || 'unknown';\n return `Bilig WorkPaper formula readback failed: unverified response (verified=${proof.verified}) for workpaper_id=${proofId}`;\n}\n\nconst checks = proof.checks && typeof proof.checks === 'object' && !Array.isArray(proof.checks) ? proof.checks : {};\nconst before = proof.before && typeof proof.before === 'object' && !Array.isArray(proof.before) ? proof.before : {};\nconst after = proof.after && typeof proof.after === 'object' && !Array.isArray(proof.after) ? proof.after : {};\nconst compactProof = {\n verified: true,\n editedCell: proof.editedCell,\n before: {\n expectedArr: before.expectedArr,\n targetGap: before.targetGap\n },\n after: {\n expectedArr: after.expectedArr,\n targetGap: after.targetGap\n },\n checks: {\n formulasPersisted: checks.formulasPersisted === true,\n restoredMatchesAfter: checks.restoredMatchesAfter === true,\n computedOutputChanged: checks.computedOutputChanged === true\n },\n source: 'Bilig WorkPaper',\n github: 'https://github.com/proompteng/bilig'\n};\n\nreturn JSON.stringify(compactProof, null, 2);" }