onbuzz 4.9.13 → 4.10.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/node_modules/glob/README.md +31 -5
- package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/glob.js +2 -1
- package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
- package/node_modules/glob/dist/commonjs/index.min.js +3 -3
- package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
- package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/pattern.js +4 -0
- package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
- package/node_modules/glob/dist/esm/glob.d.ts +8 -0
- package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/glob.js +2 -1
- package/node_modules/glob/dist/esm/glob.js.map +1 -1
- package/node_modules/glob/dist/esm/index.min.js +3 -3
- package/node_modules/glob/dist/esm/index.min.js.map +4 -4
- package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
- package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/pattern.js +4 -0
- package/node_modules/glob/dist/esm/pattern.js.map +1 -1
- package/node_modules/{@isaacs → glob/node_modules}/balanced-match/README.md +7 -10
- package/node_modules/{@isaacs → glob/node_modules}/balanced-match/package.json +7 -18
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/README.md +3 -6
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.js +6 -4
- package/node_modules/glob/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -0
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.js +6 -4
- package/node_modules/glob/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/package.json +11 -7
- package/node_modules/glob/node_modules/minimatch/README.md +76 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +4 -2
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +309 -55
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +4 -4
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +81 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +232 -134
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +8 -8
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +4 -2
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +309 -55
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +4 -4
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +81 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +232 -134
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +8 -8
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/package.json +17 -11
- package/node_modules/glob/package.json +10 -13
- package/node_modules/minipass/LICENSE.md +55 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
- package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/minipass/dist/commonjs/index.js +13 -3
- package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
- package/node_modules/minipass/dist/esm/index.d.ts +12 -16
- package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
- package/node_modules/minipass/dist/esm/index.js +3 -1
- package/node_modules/minipass/dist/esm/index.js.map +1 -1
- package/node_modules/minipass/package.json +9 -14
- package/node_modules/path-scurry/node_modules/lru-cache/README.md +96 -10
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.cjs.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +109 -32
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +334 -197
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +4 -4
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.mjs.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +109 -32
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +333 -196
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +4 -4
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/package.json +71 -18
- package/node_modules/path-scurry/package.json +8 -24
- package/package.json +1 -1
- package/scripts/debug-balance-probe.mjs +35 -35
- package/scripts/push-image.sh +43 -43
- package/scripts/setup-acr.sh +65 -65
- package/scripts/verify-optional-deps.js +96 -1
- package/src/__tests__/composioCliFlags.test.js +239 -239
- package/src/analyzers/CSSAnalyzer.js +298 -297
- package/src/analyzers/ConfigValidator.js +691 -690
- package/src/analyzers/ESLintAnalyzer.js +320 -320
- package/src/analyzers/JavaScriptAnalyzer.js +260 -261
- package/src/analyzers/PrettierFormatter.js +246 -247
- package/src/analyzers/PythonAnalyzer.js +283 -283
- package/src/analyzers/SecurityAnalyzer.js +729 -729
- package/src/analyzers/SparrowAnalyzer.js +341 -341
- package/src/analyzers/TypeScriptAnalyzer.js +247 -247
- package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -41
- package/src/analyzers/__tests__/ConfigValidator.test.js +362 -362
- package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -40
- package/src/analyzers/__tests__/PythonAnalyzer.test.js +205 -208
- package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -303
- package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -187
- package/src/analyzers/codeCloneDetector/analyzer.js +344 -344
- package/src/analyzers/codeCloneDetector/detector.js +250 -250
- package/src/analyzers/codeCloneDetector/index.js +194 -192
- package/src/analyzers/codeCloneDetector/parser.js +199 -199
- package/src/core/__tests__/agentPool.test.js +866 -866
- package/src/core/__tests__/agentPoolAutoResume.test.js +209 -209
- package/src/core/__tests__/agentPoolWakeOnMessage.test.js +315 -315
- package/src/core/__tests__/agentScheduler.emptyResponseChatStall.test.js +213 -213
- package/src/core/__tests__/agentScheduler.errorCategorisation.test.js +246 -246
- package/src/core/__tests__/agentScheduler.firstChunkTimeout.test.js +138 -138
- package/src/core/__tests__/agentScheduler.modeTransitions.test.js +233 -233
- package/src/core/__tests__/agentScheduler.nativePromptPick.test.js +319 -319
- package/src/core/__tests__/agentScheduler.taskLifecycleInstruction.test.js +78 -78
- package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -258
- package/src/core/__tests__/flowCheckpointStore.test.js +140 -140
- package/src/core/__tests__/flowEndToEnd.test.js +565 -565
- package/src/core/__tests__/flowFieldMapping.test.js +188 -189
- package/src/core/__tests__/flowLintClientMirror.test.js +96 -98
- package/src/core/__tests__/flowSavePayload.test.js +170 -169
- package/src/core/__tests__/flowTemplates.test.js +311 -311
- package/src/core/__tests__/flowVersionStore.test.js +123 -123
- package/src/core/__tests__/messageProcessor.test.js +669 -669
- package/src/core/__tests__/stateManager.test.js +0 -1
- package/src/core/agentPool.js +2474 -2475
- package/src/core/agentScheduler.js +1 -4
- package/src/core/contextManager.js +708 -708
- package/src/core/flowExecutor.js +1510 -1510
- package/src/core/flowFieldMapping.js +136 -138
- package/src/core/messageProcessor.js +953 -954
- package/src/core/orchestrator.js +593 -595
- package/src/core/stateManager.js +1765 -1752
- package/src/index.js +1221 -1221
- package/src/interfaces/__tests__/archivedAgentDelete.test.js +207 -207
- package/src/interfaces/__tests__/bulkAgentRoute.test.js +361 -361
- package/src/interfaces/__tests__/imageServing.test.js +228 -228
- package/src/interfaces/__tests__/remoteSessionAuth.test.js +308 -308
- package/src/interfaces/__tests__/videoJobsRoutes.test.js +178 -179
- package/src/interfaces/__tests__/webServer.marketplace.test.js +629 -629
- package/src/interfaces/schedulerRoutes.js +50 -50
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +341 -350
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -156
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +325 -330
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +385 -388
- package/src/interfaces/terminal/api/session.js +265 -266
- package/src/interfaces/terminal/api/websocket.js +496 -497
- package/src/interfaces/terminal/components/AgentCreator.js +691 -705
- package/src/interfaces/terminal/components/AgentEditor.js +676 -678
- package/src/interfaces/terminal/components/AgentSwitcher.js +331 -330
- package/src/interfaces/terminal/components/ErrorPanel.js +263 -264
- package/src/interfaces/terminal/components/Header.js +28 -28
- package/src/interfaces/terminal/components/Layout.js +598 -603
- package/src/interfaces/terminal/components/MessageList.js +280 -281
- package/src/interfaces/terminal/components/SettingsPanel.js +410 -415
- package/src/interfaces/terminal/components/StatusBar.js +2 -0
- package/src/interfaces/terminal/index.js +168 -168
- package/src/interfaces/terminal/state/useAgentControl.js +496 -496
- package/src/interfaces/terminal/state/useAgents.js +537 -537
- package/src/interfaces/terminal/state/useMessages.js +629 -630
- package/src/interfaces/terminal/state/useTools.js +554 -554
- package/src/interfaces/terminal/utils/debugLogger.js +44 -44
- package/src/interfaces/terminal/utils/settingsStorage.js +232 -232
- package/src/interfaces/webServer.js +7578 -7579
- package/src/interfaces/webServer.js.bak +7046 -7046
- package/src/modules/fileExplorer/__tests__/zipDownload.test.js +237 -237
- package/src/modules/fileExplorer/controller.js +470 -469
- package/src/modules/fileExplorer/routes.js +285 -286
- package/src/modules/widget/__tests__/isDisabled.test.js +41 -41
- package/src/modules/widget/__tests__/routes.test.js +677 -678
- package/src/modules/widget/__tests__/runtime.test.js +401 -401
- package/src/modules/widget/__tests__/versioning.test.js +309 -309
- package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -565
- package/src/modules/widget/__tests__/widgetTool.test.js +316 -316
- package/src/modules/widget/routes.js +435 -435
- package/src/modules/widget/runtime/bundle.js +640 -640
- package/src/modules/widget/runtime/webComponentBundle.js +470 -470
- package/src/modules/widget/schema.js +182 -181
- package/src/modules/widget/widgetTool.js +1389 -1389
- package/src/services/__tests__/agentActivityService.test.js +401 -402
- package/src/services/__tests__/benchmarkService.test.js +184 -184
- package/src/services/__tests__/contextInjectionService.test.js +246 -246
- package/src/services/__tests__/conversationQuery.test.js +721 -723
- package/src/services/__tests__/credentialVault.test.js +469 -469
- package/src/services/__tests__/discordService.integration.test.js +638 -639
- package/src/services/__tests__/flowContextService.test.js +590 -590
- package/src/services/__tests__/memoryService.test.js +1 -1
- package/src/services/__tests__/messageSource.test.js +380 -380
- package/src/services/__tests__/modelRouterNaming.test.js +111 -111
- package/src/services/__tests__/projectDetector.test.js +34 -34
- package/src/services/__tests__/promptService.test.js +242 -242
- package/src/services/__tests__/telegramService.test.js +941 -941
- package/src/services/__tests__/tokenCountingService.test.js +48 -48
- package/src/services/agentActivityService.js +419 -420
- package/src/services/aiService.js +2997 -3001
- package/src/services/apiKeyManager.js +359 -359
- package/src/services/benchmarkService.js +196 -196
- package/src/services/codebaseKnowledgeService.js +2 -2
- package/src/services/composioService.js +738 -738
- package/src/services/conversationCompactionService.js +1258 -1257
- package/src/services/credentialVault.js +685 -685
- package/src/services/discordService.js +792 -793
- package/src/services/embeddings/__tests__/azureCustomProvider.test.js +232 -232
- package/src/services/embeddings/__tests__/embeddingService.test.js +417 -417
- package/src/services/embeddings/__tests__/localProvider.test.js +263 -263
- package/src/services/embeddings/autoRecall.js +218 -219
- package/src/services/embeddings/indexers/__tests__/agentIndexer.test.js +232 -232
- package/src/services/embeddings/indexers/__tests__/memoryIndexer.test.js +418 -418
- package/src/services/embeddings/indexers/__tests__/reminisceIndexer.test.js +356 -357
- package/src/services/embeddings/indexers/__tests__/skillsIndexer.test.js +145 -145
- package/src/services/embeddings/indexers/__tests__/taskIndexer.test.js +146 -146
- package/src/services/embeddings/indexers/composioIndexer.js +279 -279
- package/src/services/embeddings/providerInterface.js +206 -206
- package/src/services/embeddings/providers/localProvider.js +11 -7
- package/src/services/embeddings/providers/openaiProvider.js +101 -101
- package/src/services/embeddings/vectorStore/inMemoryJsonStore.js +356 -356
- package/src/services/errorHandler.js +809 -809
- package/src/services/flowContextService.js +586 -586
- package/src/services/grounding/MockAdapter.js +125 -125
- package/src/services/modelRouterService.js +26 -31
- package/src/services/modelsService.js +322 -322
- package/src/services/ollamaService.js +452 -452
- package/src/services/projectDetector.js +403 -404
- package/src/services/promptService.js +418 -418
- package/src/services/qualityInspector.js +795 -795
- package/src/services/scheduleService.js +726 -726
- package/src/services/serviceRegistry.js +386 -386
- package/src/services/telegrafBot.js +174 -174
- package/src/services/telegramService.js +1972 -1972
- package/src/services/visualEditorBridge.js +1033 -1033
- package/src/services/visualEditorServer.js +1769 -1774
- package/src/services/whatsappService.js +667 -668
- package/src/tools/__tests__/agentCommunicationTool.findAgent.test.js +226 -226
- package/src/tools/__tests__/agentCommunicationTool.test.js +3 -3
- package/src/tools/__tests__/agentDelayTool.test.js +342 -342
- package/src/tools/__tests__/baseTool.test.js +3 -3
- package/src/tools/__tests__/codeMapTool.test.js +915 -915
- package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -309
- package/src/tools/__tests__/fileTreeTool.test.js +274 -274
- package/src/tools/__tests__/filesystemTool.test.js +815 -815
- package/src/tools/__tests__/foundryWebSearchTool.test.js +252 -252
- package/src/tools/__tests__/imageTool.validator.test.js +194 -194
- package/src/tools/__tests__/jobDoneTool.test.js +580 -581
- package/src/tools/__tests__/memoryTool.forgetStale.test.js +272 -272
- package/src/tools/__tests__/memoryTool.reminisce.test.js +2 -2
- package/src/tools/__tests__/memoryTool.reminisceSemanticSearch.test.js +301 -301
- package/src/tools/__tests__/memoryTool.semanticSearch.test.js +405 -405
- package/src/tools/__tests__/memoryTool.teamPool.test.js +293 -293
- package/src/tools/__tests__/memoryTool.test.js +1 -1
- package/src/tools/__tests__/seekTool.test.js +282 -282
- package/src/tools/__tests__/skillsTool.search.test.js +164 -164
- package/src/tools/__tests__/skillsTool.test.js +226 -226
- package/src/tools/__tests__/staticAnalysisTool.test.js +509 -509
- package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -137
- package/src/tools/__tests__/taskManagerTool.search.test.js +143 -143
- package/src/tools/__tests__/taskManagerTool.test.js +866 -866
- package/src/tools/__tests__/terminalTool.test.js +448 -448
- package/src/tools/__tests__/toolShapeForgiveness.test.js +259 -260
- package/src/tools/__tests__/userPromptTool.test.js +297 -297
- package/src/tools/__tests__/videoTool.jobs.test.js +147 -147
- package/src/tools/__tests__/webTool.e2e.test.js +609 -603
- package/src/tools/__tests__/webTool.unit.test.js +195 -195
- package/src/tools/__tests__/webTool.visionModel.test.js +75 -75
- package/src/tools/agentCommunicationTool.js +8 -10
- package/src/tools/agentDelayTool.js +496 -497
- package/src/tools/asyncToolManager.js +602 -603
- package/src/tools/baseTool.js +12 -11
- package/src/tools/cloneDetectionTool.js +576 -581
- package/src/tools/codeMapTool.js +0 -6
- package/src/tools/composioTool.js +617 -617
- package/src/tools/dependencyResolverTool.js +1211 -1212
- package/src/tools/desktop/DesktopTool.js +629 -638
- package/src/tools/desktop/__tests__/DesktopTool.e2e.test.js +306 -306
- package/src/tools/desktop/__tests__/DesktopTool.test.js +507 -507
- package/src/tools/desktop/__tests__/osController.test.js +364 -364
- package/src/tools/desktop/osController.js +491 -491
- package/src/tools/docxTool.js +623 -623
- package/src/tools/excelTool.js +636 -636
- package/src/tools/fileContentReplaceTool.js +5 -7
- package/src/tools/fileSystemTool.js +12 -19
- package/src/tools/fileTreeTool.js +840 -840
- package/src/tools/foundryWebSearchTool.js +273 -273
- package/src/tools/helpTool.js +198 -198
- package/src/tools/imageTool.js +1397 -1397
- package/src/tools/importAnalyzerTool.js +1056 -1056
- package/src/tools/jobDoneTool.js +495 -495
- package/src/tools/memoryTool.js +1 -1
- package/src/tools/office/pres/__tests__/presSystem.test.js +365 -365
- package/src/tools/office/pres/archetypes/agenda.js +61 -61
- package/src/tools/office/pres/archetypes/bentoGrid.js +218 -219
- package/src/tools/office/pres/archetypes/bigStat.js +140 -142
- package/src/tools/office/pres/archetypes/closing.js +70 -70
- package/src/tools/office/pres/archetypes/hero.js +70 -70
- package/src/tools/office/pres/archetypes/productHero.js +93 -94
- package/src/tools/office/pres/archetypes/table.js +73 -74
- package/src/tools/office/pres/backgrounds/orb.js +66 -66
- package/src/tools/office/pres/components.js +422 -423
- package/src/tools/officeTool.js +441 -441
- package/src/tools/pdfTool.js +625 -627
- package/src/tools/platformControlTool.js +1081 -1081
- package/src/tools/seekTool.js +917 -918
- package/src/tools/skillsTool.js +1 -1
- package/src/tools/staticAnalysisTool.js +2143 -2146
- package/src/tools/taskManagerTool.js +3324 -3324
- package/src/tools/terminalTool.js +2615 -2618
- package/src/tools/videoTool.js +1303 -1303
- package/src/tools/visionTool.js +508 -508
- package/src/tools/visualEditorTool.js +1289 -1290
- package/src/tools/webTool.js +3368 -3368
- package/src/tools/whatsappTool.js +464 -464
- package/src/types/__tests__/agent.test.js +499 -499
- package/src/types/__tests__/contextReference.test.js +606 -606
- package/src/types/__tests__/conversation.test.js +555 -555
- package/src/types/__tests__/toolCommand.test.js +584 -584
- package/src/types/contextReference.js +974 -971
- package/src/types/conversation.js +729 -729
- package/src/types/toolCommand.js +746 -746
- package/src/utilities/__tests__/attachmentValidator.test.js +80 -80
- package/src/utilities/__tests__/auditReport.test.js +328 -328
- package/src/utilities/__tests__/directoryAccessManager.test.js +388 -388
- package/src/utilities/__tests__/jsonRepair.test.js +103 -104
- package/src/utilities/__tests__/modeTransitionReasons.test.js +105 -105
- package/src/utilities/__tests__/platformUtils.test.js +80 -87
- package/src/utilities/__tests__/structuredFileValidator.test.js +261 -263
- package/src/utilities/__tests__/toolConstants.test.js +92 -94
- package/src/utilities/__tests__/useIsTouchDevice.detect.test.js +114 -114
- package/src/utilities/__tests__/webUiUtilSync.test.js +117 -117
- package/src/utilities/attachmentValidator.js +284 -288
- package/src/utilities/authCache.js.backup-1779570472481 +121 -121
- package/src/utilities/browserStealth.js +631 -630
- package/src/utilities/configManager.js +616 -617
- package/src/utilities/directoryAccessManager.js +564 -565
- package/src/utilities/fileProcessor.js +308 -307
- package/src/utilities/humanBehavior.js +454 -453
- package/src/utilities/logger.js +479 -479
- package/src/utilities/structuredFileValidator.js +696 -699
- package/src/utilities/tagParser.js +5 -10
- package/src/utilities/userDataDir.js +308 -308
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +0 -1
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +0 -1
- package/node_modules/minipass/LICENSE +0 -15
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/LICENSE.md +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/LICENSE +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/package.json +0 -0
package/src/tools/pdfTool.js
CHANGED
|
@@ -1,627 +1,625 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PDF Tool - Read, extract, and create PDF files
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* - Get PDF metadata (page count, info)
|
|
6
|
-
* - Extract text content from specific page ranges
|
|
7
|
-
* - Create PDF files from HTML content using Puppeteer
|
|
8
|
-
* - Provide structured access to PDF documents
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { BaseTool } from './baseTool.js';
|
|
12
|
-
import TagParser from '../utilities/tagParser.js';
|
|
13
|
-
import fs from 'fs/promises';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
|
|
16
|
-
// Dynamic import for pdf2json
|
|
17
|
-
let PDFParser = null;
|
|
18
|
-
|
|
19
|
-
// Dynamic import for puppeteer (used for PDF creation)
|
|
20
|
-
let puppeteerModule = null;
|
|
21
|
-
|
|
22
|
-
class PdfTool extends BaseTool {
|
|
23
|
-
constructor(config = {}, logger = null) {
|
|
24
|
-
super(config, logger);
|
|
25
|
-
this.id = 'pdf';
|
|
26
|
-
this.name = 'PDF Tool';
|
|
27
|
-
this.description = 'Read, extract, and create PDF files';
|
|
28
|
-
this.version = '2.0.0';
|
|
29
|
-
this.capabilities = ['pdf-read', 'pdf-info', 'pdf-create'];
|
|
30
|
-
this.requiresProject = false;
|
|
31
|
-
this.isAsync = false;
|
|
32
|
-
this.pdfParserLoaded = false;
|
|
33
|
-
this.pdfParserError = null;
|
|
34
|
-
this.puppeteerLoaded = false;
|
|
35
|
-
this.puppeteerError = null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Lazily load pdf2json module
|
|
40
|
-
* @returns {Promise<boolean>} Whether loading succeeded
|
|
41
|
-
*/
|
|
42
|
-
async loadPdfParser() {
|
|
43
|
-
if (this.pdfParserLoaded) return true;
|
|
44
|
-
if (this.pdfParserError) return false;
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const module = await import('pdf2json');
|
|
48
|
-
PDFParser = module.default;
|
|
49
|
-
this.pdfParserLoaded = true;
|
|
50
|
-
return true;
|
|
51
|
-
} catch (error) {
|
|
52
|
-
this.pdfParserError = error.message;
|
|
53
|
-
this.logger?.error('Failed to load pdf2json', { error: error.message });
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Lazily load puppeteer module for PDF creation
|
|
60
|
-
* @returns {Promise<boolean>} Whether loading succeeded
|
|
61
|
-
*/
|
|
62
|
-
async loadPuppeteer() {
|
|
63
|
-
if (this.puppeteerLoaded) return true;
|
|
64
|
-
if (this.puppeteerError) return false;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const module = await import('puppeteer');
|
|
68
|
-
puppeteerModule = module.default;
|
|
69
|
-
this.puppeteerLoaded = true;
|
|
70
|
-
return true;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
this.puppeteerError = error.message;
|
|
73
|
-
this.logger?.error('Failed to load puppeteer', { error: error.message });
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get tool description for LLM consumption
|
|
80
|
-
* @returns {string} Tool description
|
|
81
|
-
*/
|
|
82
|
-
getDescription() {
|
|
83
|
-
return `
|
|
84
|
-
PDF Tool: Read, extract, and create PDF files.
|
|
85
|
-
|
|
86
|
-
USAGE:
|
|
87
|
-
\`\`\`json
|
|
88
|
-
{
|
|
89
|
-
"toolId": "pdf",
|
|
90
|
-
"actions": [{
|
|
91
|
-
"action": "get-info",
|
|
92
|
-
"filePath": "/path/to/document.pdf"
|
|
93
|
-
}]
|
|
94
|
-
}
|
|
95
|
-
\`\`\`
|
|
96
|
-
|
|
97
|
-
ACTIONS:
|
|
98
|
-
|
|
99
|
-
1. **get-info** - Get PDF metadata (page count, title, author, etc.)
|
|
100
|
-
- filePath: Path to PDF file (required)
|
|
101
|
-
|
|
102
|
-
2. **read-pages** - Extract text content from specific pages
|
|
103
|
-
- filePath: Path to PDF file (required)
|
|
104
|
-
- startPage: First page to read, 1-indexed, inclusive (default: 1)
|
|
105
|
-
- endPage: Last page to read, exclusive (default: startPage + 10)
|
|
106
|
-
- IMPORTANT: Read max 10 pages at once for optimal performance
|
|
107
|
-
|
|
108
|
-
3. **create-pdf** - Create a PDF from HTML content
|
|
109
|
-
- outputPath: Output file path (required, relative to project dir or absolute)
|
|
110
|
-
- htmlContent: Full HTML string to render (required)
|
|
111
|
-
- pageSize: Page size - A4 (default), Letter, Legal, Tabloid, A3, A5
|
|
112
|
-
- orientation: portrait (default) or landscape
|
|
113
|
-
- margins: Object with top, right, bottom, left in CSS units (default: 1cm each)
|
|
114
|
-
- printBackground: Whether to print background colors/images (default: true)
|
|
115
|
-
- displayHeaderFooter: Show header/footer (default: false)
|
|
116
|
-
- headerTemplate: HTML template for header
|
|
117
|
-
- footerTemplate: HTML template for footer
|
|
118
|
-
|
|
119
|
-
EXAMPLES:
|
|
120
|
-
|
|
121
|
-
1. Get PDF info:
|
|
122
|
-
\`\`\`json
|
|
123
|
-
{
|
|
124
|
-
"toolId": "pdf",
|
|
125
|
-
"actions": [{
|
|
126
|
-
"action": "get-info",
|
|
127
|
-
"filePath": "documents/report.pdf"
|
|
128
|
-
}]
|
|
129
|
-
}
|
|
130
|
-
\`\`\`
|
|
131
|
-
|
|
132
|
-
2. Read pages 1-10:
|
|
133
|
-
\`\`\`json
|
|
134
|
-
{
|
|
135
|
-
"toolId": "pdf",
|
|
136
|
-
"actions": [{
|
|
137
|
-
"action": "read-pages",
|
|
138
|
-
"filePath": "documents/report.pdf",
|
|
139
|
-
"startPage": 1,
|
|
140
|
-
"endPage": 11
|
|
141
|
-
}]
|
|
142
|
-
}
|
|
143
|
-
\`\`\`
|
|
144
|
-
|
|
145
|
-
3. Create a PDF from HTML:
|
|
146
|
-
\`\`\`json
|
|
147
|
-
{
|
|
148
|
-
"toolId": "pdf",
|
|
149
|
-
"actions": [{
|
|
150
|
-
"action": "create-pdf",
|
|
151
|
-
"outputPath": "output/report.pdf",
|
|
152
|
-
"htmlContent": "<html><head><style>body{font-family:Arial;margin:2cm}h1{color:#333}</style></head><body><h1>Report</h1><p>Content here...</p></body></html>",
|
|
153
|
-
"pageSize": "A4",
|
|
154
|
-
"orientation": "portrait"
|
|
155
|
-
}]
|
|
156
|
-
}
|
|
157
|
-
\`\`\`
|
|
158
|
-
|
|
159
|
-
4. Create a landscape PDF with custom margins:
|
|
160
|
-
\`\`\`json
|
|
161
|
-
{
|
|
162
|
-
"toolId": "pdf",
|
|
163
|
-
"actions": [{
|
|
164
|
-
"action": "create-pdf",
|
|
165
|
-
"outputPath": "output/wide-report.pdf",
|
|
166
|
-
"htmlContent": "<html><body><h1>Wide Report</h1><table>...</table></body></html>",
|
|
167
|
-
"pageSize": "Letter",
|
|
168
|
-
"orientation": "landscape",
|
|
169
|
-
"margins": { "top": "2cm", "right": "1.5cm", "bottom": "2cm", "left": "1.5cm" }
|
|
170
|
-
}]
|
|
171
|
-
}
|
|
172
|
-
\`\`\`
|
|
173
|
-
|
|
174
|
-
NOTES:
|
|
175
|
-
- Page numbers are 1-indexed (first page is 1)
|
|
176
|
-
- endPage is exclusive (like Python range)
|
|
177
|
-
- Recommend reading max 10 pages at a time to avoid token limits
|
|
178
|
-
- For create-pdf: Design full HTML with CSS styling for best results
|
|
179
|
-
- The HTML is rendered in a headless browser, so all CSS features are supported
|
|
180
|
-
- Use inline styles or <style> blocks in the HTML for styling
|
|
181
|
-
`.trim();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Parse parameters from tool command content
|
|
186
|
-
* @param {string} content - Raw tool command content
|
|
187
|
-
* @returns {Object} Parsed parameters object
|
|
188
|
-
*/
|
|
189
|
-
parseParameters(content) {
|
|
190
|
-
try {
|
|
191
|
-
// Try to extract structured content using TagParser
|
|
192
|
-
const actionMatches = TagParser.extractContent(content, 'action');
|
|
193
|
-
const filePathMatches = TagParser.extractContent(content, 'filePath');
|
|
194
|
-
const startPageMatches = TagParser.extractContent(content, 'startPage');
|
|
195
|
-
const endPageMatches = TagParser.extractContent(content, 'endPage');
|
|
196
|
-
|
|
197
|
-
const action = actionMatches.length > 0 ? actionMatches[0].trim() : 'get-info';
|
|
198
|
-
const filePath = filePathMatches.length > 0 ? filePathMatches[0].trim() : '';
|
|
199
|
-
const startPage = startPageMatches.length > 0 ? parseInt(startPageMatches[0], 10) : 1;
|
|
200
|
-
const endPage = endPageMatches.length > 0 ? parseInt(endPageMatches[0], 10) : startPage + 10;
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
actions: [{
|
|
204
|
-
action,
|
|
205
|
-
filePath,
|
|
206
|
-
startPage,
|
|
207
|
-
endPage
|
|
208
|
-
}]
|
|
209
|
-
};
|
|
210
|
-
} catch (error) {
|
|
211
|
-
throw new Error(`Failed to parse PDF tool parameters: ${error.message}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Get supported actions
|
|
217
|
-
* @returns {Array<string>}
|
|
218
|
-
*/
|
|
219
|
-
getSupportedActions() {
|
|
220
|
-
return ['get-info', 'read-pages', 'create-pdf'];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Execute PDF tool action
|
|
225
|
-
* @param {Object} params - Parsed parameters
|
|
226
|
-
* @param {Object} context - Execution context
|
|
227
|
-
* @returns {Promise<Object>} Execution result
|
|
228
|
-
*/
|
|
229
|
-
async execute(params, context) {
|
|
230
|
-
const { actions } = params;
|
|
231
|
-
|
|
232
|
-
if (!actions || actions.length === 0) {
|
|
233
|
-
return {
|
|
234
|
-
success: false,
|
|
235
|
-
error: 'No actions provided',
|
|
236
|
-
output: 'Please specify an action (get-info, read-pages, or create-pdf)'
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const action = actions[0];
|
|
241
|
-
const { projectDir } = context;
|
|
242
|
-
|
|
243
|
-
// Handle create-pdf early (it doesn't need read-oriented validation)
|
|
244
|
-
if (action.action === 'create-pdf') {
|
|
245
|
-
try {
|
|
246
|
-
return await this.createPdf(action, context);
|
|
247
|
-
} catch (error) {
|
|
248
|
-
this.logger?.error('PDF creation error', { error: error.message });
|
|
249
|
-
return {
|
|
250
|
-
success: false,
|
|
251
|
-
error: error.message,
|
|
252
|
-
output: `Failed to create PDF: ${error.message}`
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// --- Read-oriented actions below: require filePath, file existence, pdf2json ---
|
|
258
|
-
|
|
259
|
-
// Resolve file path
|
|
260
|
-
let filePath = action.filePath;
|
|
261
|
-
if (!filePath) {
|
|
262
|
-
return {
|
|
263
|
-
success: false,
|
|
264
|
-
error: 'File path is required',
|
|
265
|
-
output: 'Please provide a filePath parameter'
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Make path absolute if relative
|
|
270
|
-
if (!path.isAbsolute(filePath)) {
|
|
271
|
-
filePath = path.resolve(projectDir || process.cwd(), filePath);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Check file exists
|
|
275
|
-
try {
|
|
276
|
-
await fs.access(filePath);
|
|
277
|
-
} catch {
|
|
278
|
-
return {
|
|
279
|
-
success: false,
|
|
280
|
-
error: `File not found: ${filePath}`,
|
|
281
|
-
output: `The PDF file does not exist: ${filePath}`
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Check file extension
|
|
286
|
-
if (!filePath.toLowerCase().endsWith('.pdf')) {
|
|
287
|
-
return {
|
|
288
|
-
success: false,
|
|
289
|
-
error: 'Not a PDF file',
|
|
290
|
-
output: `The file must have a .pdf extension: ${filePath}`
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Load pdf2json module
|
|
295
|
-
const loaded = await this.loadPdfParser();
|
|
296
|
-
if (!loaded) {
|
|
297
|
-
return {
|
|
298
|
-
success: false,
|
|
299
|
-
error: 'PDF parsing not available',
|
|
300
|
-
output: `PDF parsing module could not be loaded: ${this.pdfParserError}`
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
try {
|
|
305
|
-
switch (action.action) {
|
|
306
|
-
case 'get-info':
|
|
307
|
-
return await this.getInfo(filePath);
|
|
308
|
-
case 'read-pages':
|
|
309
|
-
return await this.readPages(filePath, action.startPage, action.endPage);
|
|
310
|
-
default:
|
|
311
|
-
return {
|
|
312
|
-
success: false,
|
|
313
|
-
error: `Unknown action: ${action.action}`,
|
|
314
|
-
output: `Supported actions: get-info, read-pages, create-pdf`
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
} catch (error) {
|
|
318
|
-
this.logger?.error('PDF tool error', { action: action.action, filePath, error: error.message });
|
|
319
|
-
return {
|
|
320
|
-
success: false,
|
|
321
|
-
error: error.message,
|
|
322
|
-
output: `Failed to process PDF: ${error.message}`
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Parse PDF file using pdf2json
|
|
329
|
-
* @param {string} filePath - Path to PDF file
|
|
330
|
-
* @returns {Promise<Object>} Parsed PDF data
|
|
331
|
-
*/
|
|
332
|
-
async parsePdf(filePath) {
|
|
333
|
-
return new Promise((resolve, reject) => {
|
|
334
|
-
const pdfParser = new PDFParser();
|
|
335
|
-
|
|
336
|
-
pdfParser.on('pdfParser_dataError', (errData) => {
|
|
337
|
-
reject(new Error(errData.parserError || 'PDF parsing failed'));
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
pdfParser.on('pdfParser_dataReady', (pdfData) => {
|
|
341
|
-
resolve(pdfData);
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
pdfParser.loadPDF(filePath);
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Extract text from a PDF page
|
|
350
|
-
* @param {Object} page - Page data from pdf2json
|
|
351
|
-
* @returns {string} Extracted text
|
|
352
|
-
*/
|
|
353
|
-
extractPageText(page) {
|
|
354
|
-
if (!page || !page.Texts) return '';
|
|
355
|
-
|
|
356
|
-
const texts = [];
|
|
357
|
-
for (const textItem of page.Texts) {
|
|
358
|
-
if (textItem.R) {
|
|
359
|
-
for (const run of textItem.R) {
|
|
360
|
-
if (run.T) {
|
|
361
|
-
// Decode URI-encoded text
|
|
362
|
-
texts.push(decodeURIComponent(run.T));
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return texts.join(' ');
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Get PDF info (page count, metadata)
|
|
372
|
-
* @param {string} filePath - Path to PDF file
|
|
373
|
-
* @returns {Promise<Object>} PDF info
|
|
374
|
-
*/
|
|
375
|
-
async getInfo(filePath) {
|
|
376
|
-
const pdfData = await this.parsePdf(filePath);
|
|
377
|
-
|
|
378
|
-
const pageCount = pdfData.Pages ? pdfData.Pages.length : 0;
|
|
379
|
-
const meta = pdfData.Meta || {};
|
|
380
|
-
|
|
381
|
-
const info = {
|
|
382
|
-
pageCount,
|
|
383
|
-
title: meta.Title || null,
|
|
384
|
-
author: meta.Author || null,
|
|
385
|
-
subject: meta.Subject || null,
|
|
386
|
-
creator: meta.Creator || null,
|
|
387
|
-
producer: meta.Producer || null,
|
|
388
|
-
creationDate: meta.CreationDate || null,
|
|
389
|
-
modificationDate: meta.ModDate || null
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
// Build output message
|
|
393
|
-
let output = `PDF Info for: ${path.basename(filePath)}\n`;
|
|
394
|
-
output += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
|
395
|
-
output += `Pages: ${info.pageCount}\n`;
|
|
396
|
-
if (info.title) output += `Title: ${info.title}\n`;
|
|
397
|
-
if (info.author) output += `Author: ${info.author}\n`;
|
|
398
|
-
if (info.subject) output += `Subject: ${info.subject}\n`;
|
|
399
|
-
if (info.creator) output += `Creator: ${info.creator}\n`;
|
|
400
|
-
if (info.creationDate) output += `Created: ${info.creationDate}\n`;
|
|
401
|
-
|
|
402
|
-
return {
|
|
403
|
-
success: true,
|
|
404
|
-
action: 'get-info',
|
|
405
|
-
filePath,
|
|
406
|
-
info,
|
|
407
|
-
output,
|
|
408
|
-
message: `PDF has ${info.pageCount} pages`
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Create a PDF from HTML content using Puppeteer
|
|
414
|
-
* @param {Object} action - Action parameters
|
|
415
|
-
* @param {Object} context - Execution context
|
|
416
|
-
* @returns {Promise<Object>} Creation result
|
|
417
|
-
*/
|
|
418
|
-
async createPdf(action, context) {
|
|
419
|
-
const { projectDir } = context;
|
|
420
|
-
const { outputPath, htmlContent, pageSize, orientation, margins, printBackground, displayHeaderFooter, headerTemplate, footerTemplate } = action;
|
|
421
|
-
|
|
422
|
-
// Validate required parameters
|
|
423
|
-
if (!outputPath) {
|
|
424
|
-
return {
|
|
425
|
-
success: false,
|
|
426
|
-
error: 'Output path is required',
|
|
427
|
-
output: 'Please provide an outputPath parameter for the PDF file'
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (!htmlContent) {
|
|
432
|
-
return {
|
|
433
|
-
success: false,
|
|
434
|
-
error: 'HTML content is required',
|
|
435
|
-
output: 'Please provide htmlContent parameter with the HTML to render as PDF'
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Resolve output path
|
|
440
|
-
let resolvedPath = outputPath;
|
|
441
|
-
if (!path.isAbsolute(resolvedPath)) {
|
|
442
|
-
resolvedPath = path.resolve(projectDir || process.cwd(), resolvedPath);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Security: prevent path traversal
|
|
446
|
-
const baseDir = projectDir || process.cwd();
|
|
447
|
-
const normalizedPath = path.normalize(resolvedPath);
|
|
448
|
-
if (!normalizedPath.startsWith(path.normalize(baseDir))) {
|
|
449
|
-
return {
|
|
450
|
-
success: false,
|
|
451
|
-
error: 'Path traversal detected',
|
|
452
|
-
output: 'Output path must be within the project directory'
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Ensure output directory exists
|
|
457
|
-
const outputDir = path.dirname(resolvedPath);
|
|
458
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
459
|
-
|
|
460
|
-
// Ensure .pdf extension
|
|
461
|
-
if (!resolvedPath.toLowerCase().endsWith('.pdf')) {
|
|
462
|
-
resolvedPath += '.pdf';
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Load puppeteer
|
|
466
|
-
const loaded = await this.loadPuppeteer();
|
|
467
|
-
if (!loaded) {
|
|
468
|
-
return {
|
|
469
|
-
success: false,
|
|
470
|
-
error: 'Puppeteer not available',
|
|
471
|
-
output: `Puppeteer could not be loaded for PDF creation: ${this.puppeteerError}`
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Map page size names to Puppeteer format
|
|
476
|
-
const pageSizeMap = {
|
|
477
|
-
'A4': 'A4',
|
|
478
|
-
'A3': 'A3',
|
|
479
|
-
'A5': 'A5',
|
|
480
|
-
'Letter': 'Letter',
|
|
481
|
-
'Legal': 'Legal',
|
|
482
|
-
'Tabloid': 'Tabloid'
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
const format = pageSizeMap[pageSize] || 'A4';
|
|
486
|
-
const landscape = orientation === 'landscape';
|
|
487
|
-
const defaultMargin = '1cm';
|
|
488
|
-
const pdfMargins = {
|
|
489
|
-
top: margins?.top || defaultMargin,
|
|
490
|
-
right: margins?.right || defaultMargin,
|
|
491
|
-
bottom: margins?.bottom || defaultMargin,
|
|
492
|
-
left: margins?.left || defaultMargin
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
let browser = null;
|
|
496
|
-
try {
|
|
497
|
-
browser = await puppeteerModule.launch({
|
|
498
|
-
headless: true,
|
|
499
|
-
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
const page = await browser.newPage();
|
|
503
|
-
await page.setContent(htmlContent, { waitUntil: 'networkidle0', timeout: 30000 });
|
|
504
|
-
|
|
505
|
-
const pdfOptions = {
|
|
506
|
-
path: resolvedPath,
|
|
507
|
-
format,
|
|
508
|
-
landscape,
|
|
509
|
-
margin: pdfMargins,
|
|
510
|
-
printBackground: printBackground !== false,
|
|
511
|
-
displayHeaderFooter: displayHeaderFooter || false
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
if (displayHeaderFooter) {
|
|
515
|
-
if (headerTemplate) pdfOptions.headerTemplate = headerTemplate;
|
|
516
|
-
if (footerTemplate) pdfOptions.footerTemplate = footerTemplate;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
await page.pdf(pdfOptions);
|
|
520
|
-
await browser.close();
|
|
521
|
-
browser = null;
|
|
522
|
-
|
|
523
|
-
// Get file stats
|
|
524
|
-
const stats = await fs.stat(resolvedPath);
|
|
525
|
-
|
|
526
|
-
const output = `PDF created successfully!\n` +
|
|
527
|
-
`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n` +
|
|
528
|
-
`File: ${resolvedPath}\n` +
|
|
529
|
-
`Size: ${(stats.size / 1024).toFixed(1)} KB\n` +
|
|
530
|
-
`Page size: ${format}\n` +
|
|
531
|
-
`Orientation: ${landscape ? 'landscape' : 'portrait'}\n` +
|
|
532
|
-
`Margins: ${pdfMargins.top} / ${pdfMargins.right} / ${pdfMargins.bottom} / ${pdfMargins.left}`;
|
|
533
|
-
|
|
534
|
-
return {
|
|
535
|
-
success: true,
|
|
536
|
-
action: 'create-pdf',
|
|
537
|
-
outputPath: resolvedPath,
|
|
538
|
-
fileSize: stats.size,
|
|
539
|
-
format,
|
|
540
|
-
landscape,
|
|
541
|
-
output,
|
|
542
|
-
message: `PDF created: ${resolvedPath} (${(stats.size / 1024).toFixed(1)} KB)`
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
*
|
|
556
|
-
* @param {
|
|
557
|
-
* @
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (
|
|
568
|
-
if (
|
|
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
|
-
output +=
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
export default PdfTool;
|
|
1
|
+
/**
|
|
2
|
+
* PDF Tool - Read, extract, and create PDF files
|
|
3
|
+
*
|
|
4
|
+
* Purpose:
|
|
5
|
+
* - Get PDF metadata (page count, info)
|
|
6
|
+
* - Extract text content from specific page ranges
|
|
7
|
+
* - Create PDF files from HTML content using Puppeteer
|
|
8
|
+
* - Provide structured access to PDF documents
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BaseTool } from './baseTool.js';
|
|
12
|
+
import TagParser from '../utilities/tagParser.js';
|
|
13
|
+
import fs from 'fs/promises';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
|
|
16
|
+
// Dynamic import for pdf2json
|
|
17
|
+
let PDFParser = null;
|
|
18
|
+
|
|
19
|
+
// Dynamic import for puppeteer (used for PDF creation)
|
|
20
|
+
let puppeteerModule = null;
|
|
21
|
+
|
|
22
|
+
class PdfTool extends BaseTool {
|
|
23
|
+
constructor(config = {}, logger = null) {
|
|
24
|
+
super(config, logger);
|
|
25
|
+
this.id = 'pdf';
|
|
26
|
+
this.name = 'PDF Tool';
|
|
27
|
+
this.description = 'Read, extract, and create PDF files';
|
|
28
|
+
this.version = '2.0.0';
|
|
29
|
+
this.capabilities = ['pdf-read', 'pdf-info', 'pdf-create'];
|
|
30
|
+
this.requiresProject = false;
|
|
31
|
+
this.isAsync = false;
|
|
32
|
+
this.pdfParserLoaded = false;
|
|
33
|
+
this.pdfParserError = null;
|
|
34
|
+
this.puppeteerLoaded = false;
|
|
35
|
+
this.puppeteerError = null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Lazily load pdf2json module
|
|
40
|
+
* @returns {Promise<boolean>} Whether loading succeeded
|
|
41
|
+
*/
|
|
42
|
+
async loadPdfParser() {
|
|
43
|
+
if (this.pdfParserLoaded) return true;
|
|
44
|
+
if (this.pdfParserError) return false;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const module = await import('pdf2json');
|
|
48
|
+
PDFParser = module.default;
|
|
49
|
+
this.pdfParserLoaded = true;
|
|
50
|
+
return true;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
this.pdfParserError = error.message;
|
|
53
|
+
this.logger?.error('Failed to load pdf2json', { error: error.message });
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Lazily load puppeteer module for PDF creation
|
|
60
|
+
* @returns {Promise<boolean>} Whether loading succeeded
|
|
61
|
+
*/
|
|
62
|
+
async loadPuppeteer() {
|
|
63
|
+
if (this.puppeteerLoaded) return true;
|
|
64
|
+
if (this.puppeteerError) return false;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const module = await import('puppeteer');
|
|
68
|
+
puppeteerModule = module.default;
|
|
69
|
+
this.puppeteerLoaded = true;
|
|
70
|
+
return true;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
this.puppeteerError = error.message;
|
|
73
|
+
this.logger?.error('Failed to load puppeteer', { error: error.message });
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get tool description for LLM consumption
|
|
80
|
+
* @returns {string} Tool description
|
|
81
|
+
*/
|
|
82
|
+
getDescription() {
|
|
83
|
+
return `
|
|
84
|
+
PDF Tool: Read, extract, and create PDF files.
|
|
85
|
+
|
|
86
|
+
USAGE:
|
|
87
|
+
\`\`\`json
|
|
88
|
+
{
|
|
89
|
+
"toolId": "pdf",
|
|
90
|
+
"actions": [{
|
|
91
|
+
"action": "get-info",
|
|
92
|
+
"filePath": "/path/to/document.pdf"
|
|
93
|
+
}]
|
|
94
|
+
}
|
|
95
|
+
\`\`\`
|
|
96
|
+
|
|
97
|
+
ACTIONS:
|
|
98
|
+
|
|
99
|
+
1. **get-info** - Get PDF metadata (page count, title, author, etc.)
|
|
100
|
+
- filePath: Path to PDF file (required)
|
|
101
|
+
|
|
102
|
+
2. **read-pages** - Extract text content from specific pages
|
|
103
|
+
- filePath: Path to PDF file (required)
|
|
104
|
+
- startPage: First page to read, 1-indexed, inclusive (default: 1)
|
|
105
|
+
- endPage: Last page to read, exclusive (default: startPage + 10)
|
|
106
|
+
- IMPORTANT: Read max 10 pages at once for optimal performance
|
|
107
|
+
|
|
108
|
+
3. **create-pdf** - Create a PDF from HTML content
|
|
109
|
+
- outputPath: Output file path (required, relative to project dir or absolute)
|
|
110
|
+
- htmlContent: Full HTML string to render (required)
|
|
111
|
+
- pageSize: Page size - A4 (default), Letter, Legal, Tabloid, A3, A5
|
|
112
|
+
- orientation: portrait (default) or landscape
|
|
113
|
+
- margins: Object with top, right, bottom, left in CSS units (default: 1cm each)
|
|
114
|
+
- printBackground: Whether to print background colors/images (default: true)
|
|
115
|
+
- displayHeaderFooter: Show header/footer (default: false)
|
|
116
|
+
- headerTemplate: HTML template for header
|
|
117
|
+
- footerTemplate: HTML template for footer
|
|
118
|
+
|
|
119
|
+
EXAMPLES:
|
|
120
|
+
|
|
121
|
+
1. Get PDF info:
|
|
122
|
+
\`\`\`json
|
|
123
|
+
{
|
|
124
|
+
"toolId": "pdf",
|
|
125
|
+
"actions": [{
|
|
126
|
+
"action": "get-info",
|
|
127
|
+
"filePath": "documents/report.pdf"
|
|
128
|
+
}]
|
|
129
|
+
}
|
|
130
|
+
\`\`\`
|
|
131
|
+
|
|
132
|
+
2. Read pages 1-10:
|
|
133
|
+
\`\`\`json
|
|
134
|
+
{
|
|
135
|
+
"toolId": "pdf",
|
|
136
|
+
"actions": [{
|
|
137
|
+
"action": "read-pages",
|
|
138
|
+
"filePath": "documents/report.pdf",
|
|
139
|
+
"startPage": 1,
|
|
140
|
+
"endPage": 11
|
|
141
|
+
}]
|
|
142
|
+
}
|
|
143
|
+
\`\`\`
|
|
144
|
+
|
|
145
|
+
3. Create a PDF from HTML:
|
|
146
|
+
\`\`\`json
|
|
147
|
+
{
|
|
148
|
+
"toolId": "pdf",
|
|
149
|
+
"actions": [{
|
|
150
|
+
"action": "create-pdf",
|
|
151
|
+
"outputPath": "output/report.pdf",
|
|
152
|
+
"htmlContent": "<html><head><style>body{font-family:Arial;margin:2cm}h1{color:#333}</style></head><body><h1>Report</h1><p>Content here...</p></body></html>",
|
|
153
|
+
"pageSize": "A4",
|
|
154
|
+
"orientation": "portrait"
|
|
155
|
+
}]
|
|
156
|
+
}
|
|
157
|
+
\`\`\`
|
|
158
|
+
|
|
159
|
+
4. Create a landscape PDF with custom margins:
|
|
160
|
+
\`\`\`json
|
|
161
|
+
{
|
|
162
|
+
"toolId": "pdf",
|
|
163
|
+
"actions": [{
|
|
164
|
+
"action": "create-pdf",
|
|
165
|
+
"outputPath": "output/wide-report.pdf",
|
|
166
|
+
"htmlContent": "<html><body><h1>Wide Report</h1><table>...</table></body></html>",
|
|
167
|
+
"pageSize": "Letter",
|
|
168
|
+
"orientation": "landscape",
|
|
169
|
+
"margins": { "top": "2cm", "right": "1.5cm", "bottom": "2cm", "left": "1.5cm" }
|
|
170
|
+
}]
|
|
171
|
+
}
|
|
172
|
+
\`\`\`
|
|
173
|
+
|
|
174
|
+
NOTES:
|
|
175
|
+
- Page numbers are 1-indexed (first page is 1)
|
|
176
|
+
- endPage is exclusive (like Python range)
|
|
177
|
+
- Recommend reading max 10 pages at a time to avoid token limits
|
|
178
|
+
- For create-pdf: Design full HTML with CSS styling for best results
|
|
179
|
+
- The HTML is rendered in a headless browser, so all CSS features are supported
|
|
180
|
+
- Use inline styles or <style> blocks in the HTML for styling
|
|
181
|
+
`.trim();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Parse parameters from tool command content
|
|
186
|
+
* @param {string} content - Raw tool command content
|
|
187
|
+
* @returns {Object} Parsed parameters object
|
|
188
|
+
*/
|
|
189
|
+
parseParameters(content) {
|
|
190
|
+
try {
|
|
191
|
+
// Try to extract structured content using TagParser
|
|
192
|
+
const actionMatches = TagParser.extractContent(content, 'action');
|
|
193
|
+
const filePathMatches = TagParser.extractContent(content, 'filePath');
|
|
194
|
+
const startPageMatches = TagParser.extractContent(content, 'startPage');
|
|
195
|
+
const endPageMatches = TagParser.extractContent(content, 'endPage');
|
|
196
|
+
|
|
197
|
+
const action = actionMatches.length > 0 ? actionMatches[0].trim() : 'get-info';
|
|
198
|
+
const filePath = filePathMatches.length > 0 ? filePathMatches[0].trim() : '';
|
|
199
|
+
const startPage = startPageMatches.length > 0 ? parseInt(startPageMatches[0], 10) : 1;
|
|
200
|
+
const endPage = endPageMatches.length > 0 ? parseInt(endPageMatches[0], 10) : startPage + 10;
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
actions: [{
|
|
204
|
+
action,
|
|
205
|
+
filePath,
|
|
206
|
+
startPage,
|
|
207
|
+
endPage
|
|
208
|
+
}]
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
throw new Error(`Failed to parse PDF tool parameters: ${error.message}`, { cause: error });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get supported actions
|
|
217
|
+
* @returns {Array<string>}
|
|
218
|
+
*/
|
|
219
|
+
getSupportedActions() {
|
|
220
|
+
return ['get-info', 'read-pages', 'create-pdf'];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Execute PDF tool action
|
|
225
|
+
* @param {Object} params - Parsed parameters
|
|
226
|
+
* @param {Object} context - Execution context
|
|
227
|
+
* @returns {Promise<Object>} Execution result
|
|
228
|
+
*/
|
|
229
|
+
async execute(params, context) {
|
|
230
|
+
const { actions } = params;
|
|
231
|
+
|
|
232
|
+
if (!actions || actions.length === 0) {
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
error: 'No actions provided',
|
|
236
|
+
output: 'Please specify an action (get-info, read-pages, or create-pdf)'
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const action = actions[0];
|
|
241
|
+
const { projectDir } = context;
|
|
242
|
+
|
|
243
|
+
// Handle create-pdf early (it doesn't need read-oriented validation)
|
|
244
|
+
if (action.action === 'create-pdf') {
|
|
245
|
+
try {
|
|
246
|
+
return await this.createPdf(action, context);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
this.logger?.error('PDF creation error', { error: error.message });
|
|
249
|
+
return {
|
|
250
|
+
success: false,
|
|
251
|
+
error: error.message,
|
|
252
|
+
output: `Failed to create PDF: ${error.message}`
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- Read-oriented actions below: require filePath, file existence, pdf2json ---
|
|
258
|
+
|
|
259
|
+
// Resolve file path
|
|
260
|
+
let filePath = action.filePath;
|
|
261
|
+
if (!filePath) {
|
|
262
|
+
return {
|
|
263
|
+
success: false,
|
|
264
|
+
error: 'File path is required',
|
|
265
|
+
output: 'Please provide a filePath parameter'
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Make path absolute if relative
|
|
270
|
+
if (!path.isAbsolute(filePath)) {
|
|
271
|
+
filePath = path.resolve(projectDir || process.cwd(), filePath);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Check file exists
|
|
275
|
+
try {
|
|
276
|
+
await fs.access(filePath);
|
|
277
|
+
} catch {
|
|
278
|
+
return {
|
|
279
|
+
success: false,
|
|
280
|
+
error: `File not found: ${filePath}`,
|
|
281
|
+
output: `The PDF file does not exist: ${filePath}`
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Check file extension
|
|
286
|
+
if (!filePath.toLowerCase().endsWith('.pdf')) {
|
|
287
|
+
return {
|
|
288
|
+
success: false,
|
|
289
|
+
error: 'Not a PDF file',
|
|
290
|
+
output: `The file must have a .pdf extension: ${filePath}`
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Load pdf2json module
|
|
295
|
+
const loaded = await this.loadPdfParser();
|
|
296
|
+
if (!loaded) {
|
|
297
|
+
return {
|
|
298
|
+
success: false,
|
|
299
|
+
error: 'PDF parsing not available',
|
|
300
|
+
output: `PDF parsing module could not be loaded: ${this.pdfParserError}`
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
switch (action.action) {
|
|
306
|
+
case 'get-info':
|
|
307
|
+
return await this.getInfo(filePath);
|
|
308
|
+
case 'read-pages':
|
|
309
|
+
return await this.readPages(filePath, action.startPage, action.endPage);
|
|
310
|
+
default:
|
|
311
|
+
return {
|
|
312
|
+
success: false,
|
|
313
|
+
error: `Unknown action: ${action.action}`,
|
|
314
|
+
output: `Supported actions: get-info, read-pages, create-pdf`
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
this.logger?.error('PDF tool error', { action: action.action, filePath, error: error.message });
|
|
319
|
+
return {
|
|
320
|
+
success: false,
|
|
321
|
+
error: error.message,
|
|
322
|
+
output: `Failed to process PDF: ${error.message}`
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Parse PDF file using pdf2json
|
|
329
|
+
* @param {string} filePath - Path to PDF file
|
|
330
|
+
* @returns {Promise<Object>} Parsed PDF data
|
|
331
|
+
*/
|
|
332
|
+
async parsePdf(filePath) {
|
|
333
|
+
return new Promise((resolve, reject) => {
|
|
334
|
+
const pdfParser = new PDFParser();
|
|
335
|
+
|
|
336
|
+
pdfParser.on('pdfParser_dataError', (errData) => {
|
|
337
|
+
reject(new Error(errData.parserError || 'PDF parsing failed'));
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
pdfParser.on('pdfParser_dataReady', (pdfData) => {
|
|
341
|
+
resolve(pdfData);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
pdfParser.loadPDF(filePath);
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Extract text from a PDF page
|
|
350
|
+
* @param {Object} page - Page data from pdf2json
|
|
351
|
+
* @returns {string} Extracted text
|
|
352
|
+
*/
|
|
353
|
+
extractPageText(page) {
|
|
354
|
+
if (!page || !page.Texts) return '';
|
|
355
|
+
|
|
356
|
+
const texts = [];
|
|
357
|
+
for (const textItem of page.Texts) {
|
|
358
|
+
if (textItem.R) {
|
|
359
|
+
for (const run of textItem.R) {
|
|
360
|
+
if (run.T) {
|
|
361
|
+
// Decode URI-encoded text
|
|
362
|
+
texts.push(decodeURIComponent(run.T));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return texts.join(' ');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get PDF info (page count, metadata)
|
|
372
|
+
* @param {string} filePath - Path to PDF file
|
|
373
|
+
* @returns {Promise<Object>} PDF info
|
|
374
|
+
*/
|
|
375
|
+
async getInfo(filePath) {
|
|
376
|
+
const pdfData = await this.parsePdf(filePath);
|
|
377
|
+
|
|
378
|
+
const pageCount = pdfData.Pages ? pdfData.Pages.length : 0;
|
|
379
|
+
const meta = pdfData.Meta || {};
|
|
380
|
+
|
|
381
|
+
const info = {
|
|
382
|
+
pageCount,
|
|
383
|
+
title: meta.Title || null,
|
|
384
|
+
author: meta.Author || null,
|
|
385
|
+
subject: meta.Subject || null,
|
|
386
|
+
creator: meta.Creator || null,
|
|
387
|
+
producer: meta.Producer || null,
|
|
388
|
+
creationDate: meta.CreationDate || null,
|
|
389
|
+
modificationDate: meta.ModDate || null
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// Build output message
|
|
393
|
+
let output = `PDF Info for: ${path.basename(filePath)}\n`;
|
|
394
|
+
output += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
|
395
|
+
output += `Pages: ${info.pageCount}\n`;
|
|
396
|
+
if (info.title) output += `Title: ${info.title}\n`;
|
|
397
|
+
if (info.author) output += `Author: ${info.author}\n`;
|
|
398
|
+
if (info.subject) output += `Subject: ${info.subject}\n`;
|
|
399
|
+
if (info.creator) output += `Creator: ${info.creator}\n`;
|
|
400
|
+
if (info.creationDate) output += `Created: ${info.creationDate}\n`;
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
success: true,
|
|
404
|
+
action: 'get-info',
|
|
405
|
+
filePath,
|
|
406
|
+
info,
|
|
407
|
+
output,
|
|
408
|
+
message: `PDF has ${info.pageCount} pages`
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Create a PDF from HTML content using Puppeteer
|
|
414
|
+
* @param {Object} action - Action parameters
|
|
415
|
+
* @param {Object} context - Execution context
|
|
416
|
+
* @returns {Promise<Object>} Creation result
|
|
417
|
+
*/
|
|
418
|
+
async createPdf(action, context) {
|
|
419
|
+
const { projectDir } = context;
|
|
420
|
+
const { outputPath, htmlContent, pageSize, orientation, margins, printBackground, displayHeaderFooter, headerTemplate, footerTemplate } = action;
|
|
421
|
+
|
|
422
|
+
// Validate required parameters
|
|
423
|
+
if (!outputPath) {
|
|
424
|
+
return {
|
|
425
|
+
success: false,
|
|
426
|
+
error: 'Output path is required',
|
|
427
|
+
output: 'Please provide an outputPath parameter for the PDF file'
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!htmlContent) {
|
|
432
|
+
return {
|
|
433
|
+
success: false,
|
|
434
|
+
error: 'HTML content is required',
|
|
435
|
+
output: 'Please provide htmlContent parameter with the HTML to render as PDF'
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Resolve output path
|
|
440
|
+
let resolvedPath = outputPath;
|
|
441
|
+
if (!path.isAbsolute(resolvedPath)) {
|
|
442
|
+
resolvedPath = path.resolve(projectDir || process.cwd(), resolvedPath);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Security: prevent path traversal
|
|
446
|
+
const baseDir = projectDir || process.cwd();
|
|
447
|
+
const normalizedPath = path.normalize(resolvedPath);
|
|
448
|
+
if (!normalizedPath.startsWith(path.normalize(baseDir))) {
|
|
449
|
+
return {
|
|
450
|
+
success: false,
|
|
451
|
+
error: 'Path traversal detected',
|
|
452
|
+
output: 'Output path must be within the project directory'
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Ensure output directory exists
|
|
457
|
+
const outputDir = path.dirname(resolvedPath);
|
|
458
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
459
|
+
|
|
460
|
+
// Ensure .pdf extension
|
|
461
|
+
if (!resolvedPath.toLowerCase().endsWith('.pdf')) {
|
|
462
|
+
resolvedPath += '.pdf';
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Load puppeteer
|
|
466
|
+
const loaded = await this.loadPuppeteer();
|
|
467
|
+
if (!loaded) {
|
|
468
|
+
return {
|
|
469
|
+
success: false,
|
|
470
|
+
error: 'Puppeteer not available',
|
|
471
|
+
output: `Puppeteer could not be loaded for PDF creation: ${this.puppeteerError}`
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Map page size names to Puppeteer format
|
|
476
|
+
const pageSizeMap = {
|
|
477
|
+
'A4': 'A4',
|
|
478
|
+
'A3': 'A3',
|
|
479
|
+
'A5': 'A5',
|
|
480
|
+
'Letter': 'Letter',
|
|
481
|
+
'Legal': 'Legal',
|
|
482
|
+
'Tabloid': 'Tabloid'
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
const format = pageSizeMap[pageSize] || 'A4';
|
|
486
|
+
const landscape = orientation === 'landscape';
|
|
487
|
+
const defaultMargin = '1cm';
|
|
488
|
+
const pdfMargins = {
|
|
489
|
+
top: margins?.top || defaultMargin,
|
|
490
|
+
right: margins?.right || defaultMargin,
|
|
491
|
+
bottom: margins?.bottom || defaultMargin,
|
|
492
|
+
left: margins?.left || defaultMargin
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
let browser = null;
|
|
496
|
+
try {
|
|
497
|
+
browser = await puppeteerModule.launch({
|
|
498
|
+
headless: true,
|
|
499
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
const page = await browser.newPage();
|
|
503
|
+
await page.setContent(htmlContent, { waitUntil: 'networkidle0', timeout: 30000 });
|
|
504
|
+
|
|
505
|
+
const pdfOptions = {
|
|
506
|
+
path: resolvedPath,
|
|
507
|
+
format,
|
|
508
|
+
landscape,
|
|
509
|
+
margin: pdfMargins,
|
|
510
|
+
printBackground: printBackground !== false,
|
|
511
|
+
displayHeaderFooter: displayHeaderFooter || false
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
if (displayHeaderFooter) {
|
|
515
|
+
if (headerTemplate) pdfOptions.headerTemplate = headerTemplate;
|
|
516
|
+
if (footerTemplate) pdfOptions.footerTemplate = footerTemplate;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
await page.pdf(pdfOptions);
|
|
520
|
+
await browser.close();
|
|
521
|
+
browser = null;
|
|
522
|
+
|
|
523
|
+
// Get file stats
|
|
524
|
+
const stats = await fs.stat(resolvedPath);
|
|
525
|
+
|
|
526
|
+
const output = `PDF created successfully!\n` +
|
|
527
|
+
`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n` +
|
|
528
|
+
`File: ${resolvedPath}\n` +
|
|
529
|
+
`Size: ${(stats.size / 1024).toFixed(1)} KB\n` +
|
|
530
|
+
`Page size: ${format}\n` +
|
|
531
|
+
`Orientation: ${landscape ? 'landscape' : 'portrait'}\n` +
|
|
532
|
+
`Margins: ${pdfMargins.top} / ${pdfMargins.right} / ${pdfMargins.bottom} / ${pdfMargins.left}`;
|
|
533
|
+
|
|
534
|
+
return {
|
|
535
|
+
success: true,
|
|
536
|
+
action: 'create-pdf',
|
|
537
|
+
outputPath: resolvedPath,
|
|
538
|
+
fileSize: stats.size,
|
|
539
|
+
format,
|
|
540
|
+
landscape,
|
|
541
|
+
output,
|
|
542
|
+
message: `PDF created: ${resolvedPath} (${(stats.size / 1024).toFixed(1)} KB)`
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
} finally {
|
|
546
|
+
if (browser) {
|
|
547
|
+
try { await browser.close(); } catch { /* ignore close errors */ }
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Read text content from specific pages
|
|
554
|
+
* @param {string} filePath - Path to PDF file
|
|
555
|
+
* @param {number} startPage - Start page (1-indexed, inclusive)
|
|
556
|
+
* @param {number} endPage - End page (exclusive)
|
|
557
|
+
* @returns {Promise<Object>} Page content
|
|
558
|
+
*/
|
|
559
|
+
async readPages(filePath, startPage = 1, endPage = null) {
|
|
560
|
+
const pdfData = await this.parsePdf(filePath);
|
|
561
|
+
|
|
562
|
+
const totalPages = pdfData.Pages ? pdfData.Pages.length : 0;
|
|
563
|
+
|
|
564
|
+
// Validate page range
|
|
565
|
+
if (startPage < 1) startPage = 1;
|
|
566
|
+
if (endPage === null) endPage = Math.min(startPage + 10, totalPages + 1);
|
|
567
|
+
if (endPage > totalPages + 1) endPage = totalPages + 1;
|
|
568
|
+
if (startPage > totalPages) {
|
|
569
|
+
return {
|
|
570
|
+
success: false,
|
|
571
|
+
error: `Start page ${startPage} exceeds total pages ${totalPages}`,
|
|
572
|
+
output: `The PDF only has ${totalPages} pages. Cannot start from page ${startPage}.`
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Warn if requesting more than 10 pages
|
|
577
|
+
const pageCount = endPage - startPage;
|
|
578
|
+
const warnings = [];
|
|
579
|
+
if (pageCount > 10) {
|
|
580
|
+
warnings.push(`Reading ${pageCount} pages. Consider reading max 10 pages at a time for better performance.`);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Extract requested pages (convert to 0-indexed)
|
|
584
|
+
const requestedPages = [];
|
|
585
|
+
for (let i = startPage - 1; i < Math.min(endPage - 1, totalPages); i++) {
|
|
586
|
+
const page = pdfData.Pages[i];
|
|
587
|
+
const content = this.extractPageText(page);
|
|
588
|
+
requestedPages.push({
|
|
589
|
+
pageNumber: i + 1,
|
|
590
|
+
content: content.trim() || ''
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Build output
|
|
595
|
+
let output = `PDF Content: ${path.basename(filePath)}\n`;
|
|
596
|
+
output += `Pages ${startPage} to ${endPage - 1} of ${totalPages}\n`;
|
|
597
|
+
output += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n`;
|
|
598
|
+
|
|
599
|
+
for (const page of requestedPages) {
|
|
600
|
+
output += `── Page ${page.pageNumber} ──\n`;
|
|
601
|
+
output += page.content || '(No text content on this page)';
|
|
602
|
+
output += '\n\n';
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (warnings.length > 0) {
|
|
606
|
+
output += `\n⚠️ Warnings:\n${warnings.map(w => `- ${w}`).join('\n')}`;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
success: true,
|
|
611
|
+
action: 'read-pages',
|
|
612
|
+
filePath,
|
|
613
|
+
totalPages,
|
|
614
|
+
startPage,
|
|
615
|
+
endPage,
|
|
616
|
+
pagesRead: requestedPages.length,
|
|
617
|
+
pages: requestedPages,
|
|
618
|
+
warnings,
|
|
619
|
+
output,
|
|
620
|
+
message: `Read ${requestedPages.length} pages (${startPage}-${endPage - 1}) of ${totalPages} total`
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export default PdfTool;
|