machinaos 0.0.1 → 0.0.7
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/.env.template +71 -71
- package/LICENSE +21 -21
- package/README.md +163 -87
- package/bin/cli.js +62 -106
- package/client/.dockerignore +45 -45
- package/client/Dockerfile +68 -68
- package/client/dist/assets/index-DFSC53FP.css +1 -0
- package/client/dist/assets/index-fJ-1gTf5.js +613 -0
- package/client/dist/index.html +14 -0
- package/client/eslint.config.js +34 -16
- package/client/nginx.conf +66 -66
- package/client/package.json +61 -48
- package/client/src/App.tsx +27 -27
- package/client/src/Dashboard.tsx +1200 -1172
- package/client/src/ParameterPanel.tsx +302 -300
- package/client/src/components/AIAgentNode.tsx +315 -321
- package/client/src/components/APIKeyValidator.tsx +117 -117
- package/client/src/components/ClaudeChatModelNode.tsx +17 -17
- package/client/src/components/CredentialsModal.tsx +1200 -306
- package/client/src/components/GeminiChatModelNode.tsx +17 -17
- package/client/src/components/GenericNode.tsx +356 -356
- package/client/src/components/LocationParameterPanel.tsx +153 -153
- package/client/src/components/ModelNode.tsx +285 -285
- package/client/src/components/OpenAIChatModelNode.tsx +17 -17
- package/client/src/components/OutputPanel.tsx +470 -470
- package/client/src/components/ParameterRenderer.tsx +1873 -1873
- package/client/src/components/SkillEditorModal.tsx +3 -3
- package/client/src/components/SquareNode.tsx +812 -796
- package/client/src/components/ToolkitNode.tsx +365 -365
- package/client/src/components/auth/LoginPage.tsx +247 -247
- package/client/src/components/auth/ProtectedRoute.tsx +59 -59
- package/client/src/components/base/BaseChatModelNode.tsx +270 -270
- package/client/src/components/icons/AIProviderIcons.tsx +50 -50
- package/client/src/components/maps/GoogleMapsPicker.tsx +136 -136
- package/client/src/components/maps/MapsPreviewPanel.tsx +109 -109
- package/client/src/components/maps/index.ts +25 -25
- package/client/src/components/parameterPanel/InputSection.tsx +1094 -1094
- package/client/src/components/parameterPanel/LocationPanelLayout.tsx +64 -64
- package/client/src/components/parameterPanel/MapsSection.tsx +91 -91
- package/client/src/components/parameterPanel/MiddleSection.tsx +867 -571
- package/client/src/components/parameterPanel/OutputSection.tsx +80 -80
- package/client/src/components/parameterPanel/ParameterPanelLayout.tsx +81 -81
- package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +436 -436
- package/client/src/components/parameterPanel/index.ts +41 -41
- package/client/src/components/shared/DataPanel.tsx +142 -142
- package/client/src/components/shared/JSONTreeRenderer.tsx +105 -105
- package/client/src/components/ui/AIResultModal.tsx +203 -203
- package/client/src/components/ui/ApiKeyInput.tsx +93 -0
- package/client/src/components/ui/CodeEditor.tsx +81 -81
- package/client/src/components/ui/CollapsibleSection.tsx +87 -87
- package/client/src/components/ui/ComponentItem.tsx +153 -153
- package/client/src/components/ui/ComponentPalette.tsx +320 -320
- package/client/src/components/ui/ConsolePanel.tsx +151 -43
- package/client/src/components/ui/ErrorBoundary.tsx +195 -195
- package/client/src/components/ui/InputNodesPanel.tsx +203 -203
- package/client/src/components/ui/MapSelector.tsx +313 -313
- package/client/src/components/ui/Modal.tsx +151 -148
- package/client/src/components/ui/NodeOutputPanel.tsx +1150 -1150
- package/client/src/components/ui/OutputDisplayPanel.tsx +381 -381
- package/client/src/components/ui/QRCodeDisplay.tsx +182 -0
- package/client/src/components/ui/TopToolbar.tsx +736 -736
- package/client/src/components/ui/WorkflowSidebar.tsx +293 -293
- package/client/src/config/antdTheme.ts +186 -186
- package/client/src/contexts/AuthContext.tsx +221 -221
- package/client/src/contexts/ThemeContext.tsx +42 -42
- package/client/src/contexts/WebSocketContext.tsx +2144 -1971
- package/client/src/factories/baseChatModelFactory.ts +255 -255
- package/client/src/hooks/useAndroidOperations.ts +118 -164
- package/client/src/hooks/useApiKeyValidation.ts +106 -106
- package/client/src/hooks/useApiKeys.ts +238 -238
- package/client/src/hooks/useAppTheme.ts +17 -17
- package/client/src/hooks/useComponentPalette.ts +50 -50
- package/client/src/hooks/useDragAndDrop.ts +123 -123
- package/client/src/hooks/useDragVariable.ts +88 -88
- package/client/src/hooks/useExecution.ts +319 -313
- package/client/src/hooks/useParameterPanel.ts +176 -176
- package/client/src/hooks/useReactFlowNodes.ts +188 -188
- package/client/src/hooks/useToolSchema.ts +209 -209
- package/client/src/hooks/useWhatsApp.ts +196 -196
- package/client/src/hooks/useWorkflowManagement.ts +45 -45
- package/client/src/index.css +314 -314
- package/client/src/nodeDefinitions/aiAgentNodes.ts +335 -335
- package/client/src/nodeDefinitions/aiModelNodes.ts +340 -340
- package/client/src/nodeDefinitions/androidServiceNodes.ts +383 -383
- package/client/src/nodeDefinitions/chatNodes.ts +135 -135
- package/client/src/nodeDefinitions/codeNodes.ts +54 -54
- package/client/src/nodeDefinitions/index.ts +14 -14
- package/client/src/nodeDefinitions/locationNodes.ts +462 -462
- package/client/src/nodeDefinitions/schedulerNodes.ts +220 -220
- package/client/src/nodeDefinitions/skillNodes.ts +17 -5
- package/client/src/nodeDefinitions/utilityNodes.ts +284 -284
- package/client/src/nodeDefinitions/whatsappNodes.ts +821 -865
- package/client/src/nodeDefinitions.ts +101 -103
- package/client/src/services/dynamicParameterService.ts +95 -95
- package/client/src/services/execution/aiAgentExecutionService.ts +34 -34
- package/client/src/services/executionService.ts +227 -231
- package/client/src/services/workflowApi.ts +91 -91
- package/client/src/store/useAppStore.ts +578 -581
- package/client/src/styles/theme.ts +513 -508
- package/client/src/styles/zIndex.ts +16 -16
- package/client/src/types/ComponentTypes.ts +38 -38
- package/client/src/types/INodeProperties.ts +287 -287
- package/client/src/types/NodeTypes.ts +27 -27
- package/client/src/utils/formatters.ts +32 -32
- package/client/src/utils/googleMapsLoader.ts +139 -139
- package/client/src/utils/locationUtils.ts +84 -84
- package/client/src/utils/nodeUtils.ts +30 -30
- package/client/src/utils/workflow.ts +29 -29
- package/client/src/vite-env.d.ts +12 -12
- package/client/tailwind.config.js +59 -59
- package/client/tsconfig.json +25 -25
- package/client/vite.config.js +35 -35
- package/install.ps1 +308 -0
- package/install.sh +343 -0
- package/package.json +81 -70
- package/scripts/build.js +174 -51
- package/scripts/clean.js +40 -40
- package/scripts/start.js +234 -210
- package/scripts/stop.js +301 -325
- package/server/.dockerignore +44 -44
- package/server/Dockerfile +45 -45
- package/server/constants.py +244 -249
- package/server/core/cache.py +460 -460
- package/server/core/config.py +127 -127
- package/server/core/container.py +98 -98
- package/server/core/database.py +1296 -1210
- package/server/core/logging.py +313 -313
- package/server/main.py +288 -288
- package/server/middleware/__init__.py +5 -5
- package/server/middleware/auth.py +89 -89
- package/server/models/auth.py +52 -52
- package/server/models/cache.py +24 -24
- package/server/models/database.py +235 -210
- package/server/models/nodes.py +435 -455
- package/server/pyproject.toml +75 -72
- package/server/requirements.txt +83 -83
- package/server/routers/android.py +294 -294
- package/server/routers/auth.py +203 -203
- package/server/routers/database.py +150 -150
- package/server/routers/maps.py +141 -141
- package/server/routers/nodejs_compat.py +288 -288
- package/server/routers/webhook.py +90 -90
- package/server/routers/websocket.py +2239 -2127
- package/server/routers/whatsapp.py +761 -761
- package/server/routers/workflow.py +199 -199
- package/server/services/ai.py +2444 -2414
- package/server/services/android_service.py +588 -588
- package/server/services/auth.py +130 -130
- package/server/services/chat_client.py +160 -160
- package/server/services/deployment/manager.py +706 -706
- package/server/services/event_waiter.py +675 -785
- package/server/services/execution/executor.py +1351 -1351
- package/server/services/execution/models.py +1 -1
- package/server/services/handlers/__init__.py +122 -126
- package/server/services/handlers/ai.py +390 -355
- package/server/services/handlers/android.py +69 -260
- package/server/services/handlers/code.py +278 -278
- package/server/services/handlers/http.py +193 -193
- package/server/services/handlers/tools.py +146 -32
- package/server/services/handlers/triggers.py +107 -107
- package/server/services/handlers/utility.py +822 -822
- package/server/services/handlers/whatsapp.py +423 -476
- package/server/services/maps.py +288 -288
- package/server/services/memory_store.py +103 -103
- package/server/services/node_executor.py +372 -375
- package/server/services/scheduler.py +155 -155
- package/server/services/skill_loader.py +1 -1
- package/server/services/status_broadcaster.py +834 -826
- package/server/services/temporal/__init__.py +23 -23
- package/server/services/temporal/activities.py +344 -344
- package/server/services/temporal/client.py +76 -76
- package/server/services/temporal/executor.py +147 -147
- package/server/services/temporal/worker.py +251 -251
- package/server/services/temporal/workflow.py +355 -355
- package/server/services/temporal/ws_client.py +236 -236
- package/server/services/text.py +110 -110
- package/server/services/user_auth.py +172 -172
- package/server/services/websocket_client.py +29 -29
- package/server/services/workflow.py +597 -597
- package/server/skills/android-skill/SKILL.md +4 -4
- package/server/skills/code-skill/SKILL.md +123 -89
- package/server/skills/maps-skill/SKILL.md +3 -3
- package/server/skills/memory-skill/SKILL.md +1 -1
- package/server/skills/web-search-skill/SKILL.md +154 -0
- package/server/skills/whatsapp-skill/SKILL.md +3 -3
- package/server/uv.lock +461 -100
- package/server/whatsapp-rpc/.dockerignore +30 -30
- package/server/whatsapp-rpc/Dockerfile +44 -44
- package/server/whatsapp-rpc/Dockerfile.web +17 -17
- package/server/whatsapp-rpc/README.md +139 -139
- package/server/whatsapp-rpc/bin/whatsapp-rpc-server +0 -0
- package/server/whatsapp-rpc/cli.js +95 -95
- package/server/whatsapp-rpc/configs/config.yaml +6 -6
- package/server/whatsapp-rpc/docker-compose.yml +35 -35
- package/server/whatsapp-rpc/docs/API.md +410 -410
- package/server/whatsapp-rpc/node_modules/.package-lock.json +259 -0
- package/server/whatsapp-rpc/node_modules/chalk/license +9 -0
- package/server/whatsapp-rpc/node_modules/chalk/package.json +83 -0
- package/server/whatsapp-rpc/node_modules/chalk/readme.md +297 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/index.d.ts +325 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/index.js +225 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/utilities.js +33 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/server/whatsapp-rpc/node_modules/commander/LICENSE +22 -0
- package/server/whatsapp-rpc/node_modules/commander/Readme.md +1148 -0
- package/server/whatsapp-rpc/node_modules/commander/esm.mjs +16 -0
- package/server/whatsapp-rpc/node_modules/commander/index.js +26 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/argument.js +145 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/command.js +2179 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/error.js +43 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/help.js +462 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/option.js +329 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/suggestSimilar.js +100 -0
- package/server/whatsapp-rpc/node_modules/commander/package-support.json +16 -0
- package/server/whatsapp-rpc/node_modules/commander/package.json +80 -0
- package/server/whatsapp-rpc/node_modules/commander/typings/esm.d.mts +3 -0
- package/server/whatsapp-rpc/node_modules/commander/typings/index.d.ts +884 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/README.md +89 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/index.js +39 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/enoent.js +59 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/parse.js +91 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/util/escape.js +47 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/util/readShebang.js +23 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/util/resolveCommand.js +52 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/package.json +73 -0
- package/server/whatsapp-rpc/node_modules/execa/index.d.ts +955 -0
- package/server/whatsapp-rpc/node_modules/execa/index.js +309 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/command.js +119 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/error.js +87 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/kill.js +102 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/pipe.js +42 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/promise.js +36 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/stdio.js +49 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/stream.js +133 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/verbose.js +19 -0
- package/server/whatsapp-rpc/node_modules/execa/license +9 -0
- package/server/whatsapp-rpc/node_modules/execa/package.json +90 -0
- package/server/whatsapp-rpc/node_modules/execa/readme.md +822 -0
- package/server/whatsapp-rpc/node_modules/get-stream/license +9 -0
- package/server/whatsapp-rpc/node_modules/get-stream/package.json +53 -0
- package/server/whatsapp-rpc/node_modules/get-stream/readme.md +291 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/array-buffer.js +84 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/array.js +32 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/buffer.js +20 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/contents.js +101 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/index.d.ts +119 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/index.js +5 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/string.js +36 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/utils.js +11 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/README.md +95 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/index.js +97 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/package.json +36 -0
- package/server/whatsapp-rpc/node_modules/human-signals/LICENSE +201 -0
- package/server/whatsapp-rpc/node_modules/human-signals/README.md +168 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/core.js +273 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/main.d.ts +73 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/main.js +70 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/realtime.js +16 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/signals.js +34 -0
- package/server/whatsapp-rpc/node_modules/human-signals/package.json +61 -0
- package/server/whatsapp-rpc/node_modules/is-stream/index.d.ts +81 -0
- package/server/whatsapp-rpc/node_modules/is-stream/index.js +29 -0
- package/server/whatsapp-rpc/node_modules/is-stream/license +9 -0
- package/server/whatsapp-rpc/node_modules/is-stream/package.json +44 -0
- package/server/whatsapp-rpc/node_modules/is-stream/readme.md +60 -0
- package/server/whatsapp-rpc/node_modules/isexe/LICENSE +15 -0
- package/server/whatsapp-rpc/node_modules/isexe/README.md +51 -0
- package/server/whatsapp-rpc/node_modules/isexe/index.js +57 -0
- package/server/whatsapp-rpc/node_modules/isexe/mode.js +41 -0
- package/server/whatsapp-rpc/node_modules/isexe/package.json +31 -0
- package/server/whatsapp-rpc/node_modules/isexe/test/basic.js +221 -0
- package/server/whatsapp-rpc/node_modules/isexe/windows.js +42 -0
- package/server/whatsapp-rpc/node_modules/kill-port/.editorconfig +12 -0
- package/server/whatsapp-rpc/node_modules/kill-port/.gitattributes +1 -0
- package/server/whatsapp-rpc/node_modules/kill-port/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/kill-port/README.md +140 -0
- package/server/whatsapp-rpc/node_modules/kill-port/cli.js +25 -0
- package/server/whatsapp-rpc/node_modules/kill-port/example.js +21 -0
- package/server/whatsapp-rpc/node_modules/kill-port/index.js +46 -0
- package/server/whatsapp-rpc/node_modules/kill-port/logo.png +0 -0
- package/server/whatsapp-rpc/node_modules/kill-port/package.json +41 -0
- package/server/whatsapp-rpc/node_modules/kill-port/pnpm-lock.yaml +4606 -0
- package/server/whatsapp-rpc/node_modules/kill-port/test.js +16 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/README.md +78 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/index.js +41 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/package.json +19 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/index.d.ts +52 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/index.js +71 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/license +9 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/package.json +45 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/readme.md +90 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/index.d.ts +90 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/index.js +52 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/license +9 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/index.d.ts +31 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/index.js +12 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/license +9 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/package.json +41 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/readme.md +57 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/package.json +49 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/readme.md +104 -0
- package/server/whatsapp-rpc/node_modules/onetime/index.d.ts +59 -0
- package/server/whatsapp-rpc/node_modules/onetime/index.js +41 -0
- package/server/whatsapp-rpc/node_modules/onetime/license +9 -0
- package/server/whatsapp-rpc/node_modules/onetime/package.json +45 -0
- package/server/whatsapp-rpc/node_modules/onetime/readme.md +94 -0
- package/server/whatsapp-rpc/node_modules/path-key/index.d.ts +40 -0
- package/server/whatsapp-rpc/node_modules/path-key/index.js +16 -0
- package/server/whatsapp-rpc/node_modules/path-key/license +9 -0
- package/server/whatsapp-rpc/node_modules/path-key/package.json +39 -0
- package/server/whatsapp-rpc/node_modules/path-key/readme.md +61 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/index.js +19 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/license +9 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/package.json +34 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/readme.md +34 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/index.d.ts +22 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/index.js +2 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/license +9 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/package.json +35 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/readme.md +33 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/README.md +60 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/index.js +47 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/package.json +29 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/LICENSE.txt +16 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/README.md +74 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.d.ts +12 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.js +10 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.d.ts +48 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.js +279 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/package.json +3 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.d.ts +29 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.js +42 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.d.ts +12 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.js +4 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.d.ts +48 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.js +275 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/package.json +3 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.d.ts +29 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.js +39 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/package.json +106 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/index.js +14 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/license +9 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/package.json +43 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/readme.md +35 -0
- package/server/whatsapp-rpc/node_modules/which/CHANGELOG.md +166 -0
- package/server/whatsapp-rpc/node_modules/which/LICENSE +15 -0
- package/server/whatsapp-rpc/node_modules/which/README.md +54 -0
- package/server/whatsapp-rpc/node_modules/which/bin/node-which +52 -0
- package/server/whatsapp-rpc/node_modules/which/package.json +43 -0
- package/server/whatsapp-rpc/node_modules/which/which.js +125 -0
- package/server/whatsapp-rpc/package-lock.json +272 -0
- package/server/whatsapp-rpc/package.json +30 -30
- package/server/whatsapp-rpc/schema.json +1294 -1294
- package/server/whatsapp-rpc/scripts/clean.cjs +66 -66
- package/server/whatsapp-rpc/scripts/cli.js +162 -162
- package/server/whatsapp-rpc/src/go/whatsapp/history.go +166 -166
- package/server/whatsapp-rpc/src/python/pyproject.toml +15 -15
- package/server/whatsapp-rpc/src/python/whatsapp_rpc/__init__.py +4 -4
- package/server/whatsapp-rpc/src/python/whatsapp_rpc/client.py +427 -427
- package/server/whatsapp-rpc/web/app.py +609 -609
- package/server/whatsapp-rpc/web/requirements.txt +6 -6
- package/server/whatsapp-rpc/web/rpc_client.py +427 -427
- package/server/whatsapp-rpc/web/static/openapi.yaml +59 -59
- package/server/whatsapp-rpc/web/templates/base.html +149 -149
- package/server/whatsapp-rpc/web/templates/contacts.html +240 -240
- package/server/whatsapp-rpc/web/templates/dashboard.html +319 -319
- package/server/whatsapp-rpc/web/templates/groups.html +328 -328
- package/server/whatsapp-rpc/web/templates/messages.html +465 -465
- package/server/whatsapp-rpc/web/templates/messaging.html +680 -680
- package/server/whatsapp-rpc/web/templates/send.html +258 -258
- package/server/whatsapp-rpc/web/templates/settings.html +459 -459
- package/client/src/components/ui/AndroidSettingsPanel.tsx +0 -401
- package/client/src/components/ui/WhatsAppSettingsPanel.tsx +0 -345
- package/client/src/nodeDefinitions/androidDeviceNodes.ts +0 -140
- package/docker-compose.prod.yml +0 -107
- package/docker-compose.yml +0 -104
- package/docs-MachinaOs/README.md +0 -85
- package/docs-MachinaOs/deployment/docker.mdx +0 -228
- package/docs-MachinaOs/deployment/production.mdx +0 -345
- package/docs-MachinaOs/docs.json +0 -75
- package/docs-MachinaOs/faq.mdx +0 -309
- package/docs-MachinaOs/favicon.svg +0 -5
- package/docs-MachinaOs/installation.mdx +0 -160
- package/docs-MachinaOs/introduction.mdx +0 -114
- package/docs-MachinaOs/logo/dark.svg +0 -6
- package/docs-MachinaOs/logo/light.svg +0 -6
- package/docs-MachinaOs/nodes/ai-agent.mdx +0 -216
- package/docs-MachinaOs/nodes/ai-models.mdx +0 -240
- package/docs-MachinaOs/nodes/android.mdx +0 -411
- package/docs-MachinaOs/nodes/overview.mdx +0 -181
- package/docs-MachinaOs/nodes/schedulers.mdx +0 -316
- package/docs-MachinaOs/nodes/webhooks.mdx +0 -330
- package/docs-MachinaOs/nodes/whatsapp.mdx +0 -305
- package/docs-MachinaOs/quickstart.mdx +0 -119
- package/docs-MachinaOs/tutorials/ai-agent-workflow.mdx +0 -177
- package/docs-MachinaOs/tutorials/android-automation.mdx +0 -242
- package/docs-MachinaOs/tutorials/first-workflow.mdx +0 -134
- package/docs-MachinaOs/tutorials/whatsapp-automation.mdx +0 -185
- package/nul +0 -0
- package/scripts/check-ports.ps1 +0 -33
- package/scripts/kill-port.ps1 +0 -154
package/server/core/logging.py
CHANGED
|
@@ -1,314 +1,314 @@
|
|
|
1
|
-
"""Modern structured logging configuration with WebSocket broadcasting."""
|
|
2
|
-
|
|
3
|
-
import sys
|
|
4
|
-
import asyncio
|
|
5
|
-
import structlog
|
|
6
|
-
import logging
|
|
7
|
-
from datetime import datetime
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import Any, Dict, Optional
|
|
10
|
-
from queue import Queue
|
|
11
|
-
from threading import Thread
|
|
12
|
-
from core.config import Settings
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class WebSocketLogHandler(logging.Handler):
|
|
16
|
-
"""Logging handler that broadcasts logs to WebSocket clients.
|
|
17
|
-
|
|
18
|
-
Uses a thread-safe queue to bridge sync logging with async WebSocket broadcasting.
|
|
19
|
-
A background thread processes the queue and uses asyncio to broadcast.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
_instance: Optional['WebSocketLogHandler'] = None
|
|
23
|
-
|
|
24
|
-
def __init__(self, level: int = logging.INFO):
|
|
25
|
-
super().__init__(level)
|
|
26
|
-
self._queue: Queue = Queue(maxsize=1000) # Bounded queue to prevent memory issues
|
|
27
|
-
self._running = False
|
|
28
|
-
self._thread: Optional[Thread] = None
|
|
29
|
-
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
|
30
|
-
|
|
31
|
-
# Source name mapping for cleaner display
|
|
32
|
-
self._source_map = {
|
|
33
|
-
'services.workflow': 'workflow',
|
|
34
|
-
'services.ai': 'ai',
|
|
35
|
-
'services.android': 'android',
|
|
36
|
-
'routers.whatsapp': 'whatsapp',
|
|
37
|
-
'routers.android': 'android',
|
|
38
|
-
'routers.websocket': 'websocket',
|
|
39
|
-
'routers.workflow': 'workflow',
|
|
40
|
-
'services.execution': 'execution',
|
|
41
|
-
'services.deployment': 'deployment',
|
|
42
|
-
'__main__': 'main',
|
|
43
|
-
'main': 'main',
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@classmethod
|
|
47
|
-
def get_instance(cls) -> Optional['WebSocketLogHandler']:
|
|
48
|
-
"""Get the singleton instance."""
|
|
49
|
-
return cls._instance
|
|
50
|
-
|
|
51
|
-
def emit(self, record: logging.LogRecord) -> None:
|
|
52
|
-
"""Queue log record for async broadcasting."""
|
|
53
|
-
if not self._running:
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
try:
|
|
57
|
-
# Get the raw message without structlog formatting
|
|
58
|
-
message = record.getMessage()
|
|
59
|
-
|
|
60
|
-
# Map source name
|
|
61
|
-
source = record.name
|
|
62
|
-
for prefix, mapped in self._source_map.items():
|
|
63
|
-
if source.startswith(prefix):
|
|
64
|
-
source = mapped
|
|
65
|
-
break
|
|
66
|
-
|
|
67
|
-
# Extract structured key-value pairs from structlog
|
|
68
|
-
details = None
|
|
69
|
-
if hasattr(record, '_logger') or hasattr(record, 'positional_args'):
|
|
70
|
-
# Try to get extra kwargs from structlog
|
|
71
|
-
extra_keys = set(record.__dict__.keys()) - {
|
|
72
|
-
'name', 'msg', 'args', 'created', 'filename', 'funcName',
|
|
73
|
-
'levelname', 'levelno', 'lineno', 'module', 'msecs',
|
|
74
|
-
'pathname', 'process', 'processName', 'relativeCreated',
|
|
75
|
-
'stack_info', 'exc_info', 'exc_text', 'thread', 'threadName',
|
|
76
|
-
'message', 'asctime', 'positional_args', '_logger'
|
|
77
|
-
}
|
|
78
|
-
if extra_keys:
|
|
79
|
-
details = {k: record.__dict__[k] for k in extra_keys if not k.startswith('_')}
|
|
80
|
-
|
|
81
|
-
# Create log entry
|
|
82
|
-
log_data = {
|
|
83
|
-
'timestamp': datetime.now().isoformat(),
|
|
84
|
-
'level': record.levelname.lower(),
|
|
85
|
-
'message': message,
|
|
86
|
-
'source': source,
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
# Add details if present
|
|
90
|
-
if details:
|
|
91
|
-
log_data['details'] = details
|
|
92
|
-
|
|
93
|
-
# Non-blocking put - drop if queue is full
|
|
94
|
-
try:
|
|
95
|
-
self._queue.put_nowait(log_data)
|
|
96
|
-
except:
|
|
97
|
-
pass # Drop log if queue is full
|
|
98
|
-
|
|
99
|
-
except Exception:
|
|
100
|
-
pass # Never fail in log handler
|
|
101
|
-
|
|
102
|
-
def start(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
103
|
-
"""Start the background thread for processing logs."""
|
|
104
|
-
if self._running:
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
self._loop = loop
|
|
108
|
-
self._running = True
|
|
109
|
-
self._thread = Thread(target=self._process_queue, daemon=True)
|
|
110
|
-
self._thread.start()
|
|
111
|
-
WebSocketLogHandler._instance = self
|
|
112
|
-
|
|
113
|
-
def stop(self) -> None:
|
|
114
|
-
"""Stop the background thread."""
|
|
115
|
-
self._running = False
|
|
116
|
-
WebSocketLogHandler._instance = None
|
|
117
|
-
if self._thread:
|
|
118
|
-
self._thread.join(timeout=1.0)
|
|
119
|
-
|
|
120
|
-
def _process_queue(self) -> None:
|
|
121
|
-
"""Background thread that processes log queue and broadcasts."""
|
|
122
|
-
while self._running:
|
|
123
|
-
try:
|
|
124
|
-
# Block for up to 0.1 seconds waiting for logs
|
|
125
|
-
try:
|
|
126
|
-
log_data = self._queue.get(timeout=0.1)
|
|
127
|
-
except:
|
|
128
|
-
continue
|
|
129
|
-
|
|
130
|
-
# Schedule async broadcast on the event loop
|
|
131
|
-
if self._loop and self._running:
|
|
132
|
-
asyncio.run_coroutine_threadsafe(
|
|
133
|
-
self._broadcast(log_data),
|
|
134
|
-
self._loop
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
except Exception:
|
|
138
|
-
pass # Never fail in background thread
|
|
139
|
-
|
|
140
|
-
async def _broadcast(self, log_data: Dict[str, Any]) -> None:
|
|
141
|
-
"""Broadcast log to WebSocket clients."""
|
|
142
|
-
try:
|
|
143
|
-
from services.status_broadcaster import get_status_broadcaster
|
|
144
|
-
broadcaster = get_status_broadcaster()
|
|
145
|
-
await broadcaster.broadcast_terminal_log(log_data)
|
|
146
|
-
except Exception:
|
|
147
|
-
pass # Don't fail if broadcaster not ready
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def configure_logging(settings: Settings) -> None:
|
|
151
|
-
"""Configure structured logging based on settings."""
|
|
152
|
-
|
|
153
|
-
# Set up log file if specified
|
|
154
|
-
if settings.log_file:
|
|
155
|
-
log_path = Path(settings.log_file)
|
|
156
|
-
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
157
|
-
|
|
158
|
-
# Configure file handler
|
|
159
|
-
file_handler = logging.FileHandler(log_path)
|
|
160
|
-
file_handler.setLevel(getattr(logging, settings.log_level.upper()))
|
|
161
|
-
|
|
162
|
-
# Configure console handler
|
|
163
|
-
console_handler = logging.StreamHandler(sys.stdout)
|
|
164
|
-
console_handler.setLevel(getattr(logging, settings.log_level.upper()))
|
|
165
|
-
|
|
166
|
-
# Configure root logger
|
|
167
|
-
logging.basicConfig(
|
|
168
|
-
level=getattr(logging, settings.log_level.upper()),
|
|
169
|
-
handlers=[console_handler, file_handler],
|
|
170
|
-
format="%(message)s"
|
|
171
|
-
)
|
|
172
|
-
else:
|
|
173
|
-
# Console only
|
|
174
|
-
logging.basicConfig(
|
|
175
|
-
format="%(message)s",
|
|
176
|
-
stream=sys.stdout,
|
|
177
|
-
level=getattr(logging, settings.log_level.upper())
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
# Configure structlog
|
|
181
|
-
processors = [
|
|
182
|
-
structlog.stdlib.filter_by_level,
|
|
183
|
-
structlog.stdlib.add_log_level,
|
|
184
|
-
structlog.stdlib.PositionalArgumentsFormatter(),
|
|
185
|
-
structlog.processors.StackInfoRenderer(),
|
|
186
|
-
structlog.processors.format_exc_info,
|
|
187
|
-
structlog.processors.UnicodeDecoder(),
|
|
188
|
-
]
|
|
189
|
-
|
|
190
|
-
# Add appropriate renderer based on format
|
|
191
|
-
if settings.log_format == "json":
|
|
192
|
-
processors.insert(0, structlog.processors.TimeStamper(fmt="iso"))
|
|
193
|
-
processors.insert(0, structlog.stdlib.add_logger_name)
|
|
194
|
-
processors.append(structlog.processors.JSONRenderer())
|
|
195
|
-
else:
|
|
196
|
-
# Console format with timestamp
|
|
197
|
-
processors.insert(0, structlog.processors.TimeStamper(fmt="%H:%M:%S"))
|
|
198
|
-
processors.append(structlog.dev.ConsoleRenderer(
|
|
199
|
-
colors=False, # No ANSI colors for cleaner output
|
|
200
|
-
pad_event=35,
|
|
201
|
-
exception_formatter=structlog.dev.plain_traceback
|
|
202
|
-
))
|
|
203
|
-
|
|
204
|
-
structlog.configure(
|
|
205
|
-
processors=processors,
|
|
206
|
-
context_class=dict,
|
|
207
|
-
logger_factory=structlog.stdlib.LoggerFactory(),
|
|
208
|
-
wrapper_class=structlog.stdlib.BoundLogger,
|
|
209
|
-
cache_logger_on_first_use=True,
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def get_logger(name: str) -> structlog.BoundLogger:
|
|
214
|
-
"""Get a structured logger instance."""
|
|
215
|
-
return structlog.get_logger(name)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def log_execution_time(logger: structlog.BoundLogger, operation: str,
|
|
219
|
-
start_time: float, end_time: float, **kwargs) -> None:
|
|
220
|
-
"""Log execution time with additional context."""
|
|
221
|
-
execution_time = end_time - start_time
|
|
222
|
-
logger.info(
|
|
223
|
-
"Operation completed",
|
|
224
|
-
operation=operation,
|
|
225
|
-
execution_time_seconds=round(execution_time, 4),
|
|
226
|
-
**kwargs
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def log_api_call(logger: structlog.BoundLogger, provider: str, model: str,
|
|
231
|
-
operation: str, success: bool, **kwargs) -> None:
|
|
232
|
-
"""Log API calls with standardized format."""
|
|
233
|
-
logger.info(
|
|
234
|
-
"API call completed",
|
|
235
|
-
provider=provider,
|
|
236
|
-
model=model,
|
|
237
|
-
operation=operation,
|
|
238
|
-
success=success,
|
|
239
|
-
**kwargs
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def log_cache_operation(logger: structlog.BoundLogger, operation: str,
|
|
244
|
-
key: str, hit: bool = None, **kwargs) -> None:
|
|
245
|
-
"""Log cache operations."""
|
|
246
|
-
log_data = {
|
|
247
|
-
"operation": operation,
|
|
248
|
-
"cache_key": key,
|
|
249
|
-
**kwargs
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if hit is not None:
|
|
253
|
-
log_data["cache_hit"] = hit
|
|
254
|
-
|
|
255
|
-
logger.debug("Cache operation", **log_data)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
# Global WebSocket log handler instance
|
|
259
|
-
_ws_log_handler: Optional[WebSocketLogHandler] = None
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
def setup_websocket_logging(loop: asyncio.AbstractEventLoop, level: int = logging.INFO) -> WebSocketLogHandler:
|
|
263
|
-
"""Setup and start the WebSocket log handler.
|
|
264
|
-
|
|
265
|
-
Should be called during application startup after the event loop is running.
|
|
266
|
-
|
|
267
|
-
Args:
|
|
268
|
-
loop: The asyncio event loop to use for broadcasting
|
|
269
|
-
level: Minimum log level to broadcast (default: INFO)
|
|
270
|
-
|
|
271
|
-
Returns:
|
|
272
|
-
The WebSocket log handler instance
|
|
273
|
-
"""
|
|
274
|
-
global _ws_log_handler
|
|
275
|
-
|
|
276
|
-
if _ws_log_handler is not None:
|
|
277
|
-
return _ws_log_handler
|
|
278
|
-
|
|
279
|
-
# Create handler
|
|
280
|
-
_ws_log_handler = WebSocketLogHandler(level=level)
|
|
281
|
-
|
|
282
|
-
# Add to root logger
|
|
283
|
-
root_logger = logging.getLogger()
|
|
284
|
-
root_logger.addHandler(_ws_log_handler)
|
|
285
|
-
|
|
286
|
-
# Start the background processing thread
|
|
287
|
-
_ws_log_handler.start(loop)
|
|
288
|
-
|
|
289
|
-
return _ws_log_handler
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
def shutdown_websocket_logging() -> None:
|
|
293
|
-
"""Shutdown the WebSocket log handler.
|
|
294
|
-
|
|
295
|
-
Should be called during application shutdown.
|
|
296
|
-
"""
|
|
297
|
-
global _ws_log_handler
|
|
298
|
-
|
|
299
|
-
if _ws_log_handler is None:
|
|
300
|
-
return
|
|
301
|
-
|
|
302
|
-
# Stop the handler
|
|
303
|
-
_ws_log_handler.stop()
|
|
304
|
-
|
|
305
|
-
# Remove from root logger
|
|
306
|
-
root_logger = logging.getLogger()
|
|
307
|
-
root_logger.removeHandler(_ws_log_handler)
|
|
308
|
-
|
|
309
|
-
_ws_log_handler = None
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
def get_websocket_log_handler() -> Optional[WebSocketLogHandler]:
|
|
313
|
-
"""Get the current WebSocket log handler instance."""
|
|
1
|
+
"""Modern structured logging configuration with WebSocket broadcasting."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import asyncio
|
|
5
|
+
import structlog
|
|
6
|
+
import logging
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
from queue import Queue
|
|
11
|
+
from threading import Thread
|
|
12
|
+
from core.config import Settings
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WebSocketLogHandler(logging.Handler):
|
|
16
|
+
"""Logging handler that broadcasts logs to WebSocket clients.
|
|
17
|
+
|
|
18
|
+
Uses a thread-safe queue to bridge sync logging with async WebSocket broadcasting.
|
|
19
|
+
A background thread processes the queue and uses asyncio to broadcast.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
_instance: Optional['WebSocketLogHandler'] = None
|
|
23
|
+
|
|
24
|
+
def __init__(self, level: int = logging.INFO):
|
|
25
|
+
super().__init__(level)
|
|
26
|
+
self._queue: Queue = Queue(maxsize=1000) # Bounded queue to prevent memory issues
|
|
27
|
+
self._running = False
|
|
28
|
+
self._thread: Optional[Thread] = None
|
|
29
|
+
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
|
30
|
+
|
|
31
|
+
# Source name mapping for cleaner display
|
|
32
|
+
self._source_map = {
|
|
33
|
+
'services.workflow': 'workflow',
|
|
34
|
+
'services.ai': 'ai',
|
|
35
|
+
'services.android': 'android',
|
|
36
|
+
'routers.whatsapp': 'whatsapp',
|
|
37
|
+
'routers.android': 'android',
|
|
38
|
+
'routers.websocket': 'websocket',
|
|
39
|
+
'routers.workflow': 'workflow',
|
|
40
|
+
'services.execution': 'execution',
|
|
41
|
+
'services.deployment': 'deployment',
|
|
42
|
+
'__main__': 'main',
|
|
43
|
+
'main': 'main',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def get_instance(cls) -> Optional['WebSocketLogHandler']:
|
|
48
|
+
"""Get the singleton instance."""
|
|
49
|
+
return cls._instance
|
|
50
|
+
|
|
51
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
52
|
+
"""Queue log record for async broadcasting."""
|
|
53
|
+
if not self._running:
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
# Get the raw message without structlog formatting
|
|
58
|
+
message = record.getMessage()
|
|
59
|
+
|
|
60
|
+
# Map source name
|
|
61
|
+
source = record.name
|
|
62
|
+
for prefix, mapped in self._source_map.items():
|
|
63
|
+
if source.startswith(prefix):
|
|
64
|
+
source = mapped
|
|
65
|
+
break
|
|
66
|
+
|
|
67
|
+
# Extract structured key-value pairs from structlog
|
|
68
|
+
details = None
|
|
69
|
+
if hasattr(record, '_logger') or hasattr(record, 'positional_args'):
|
|
70
|
+
# Try to get extra kwargs from structlog
|
|
71
|
+
extra_keys = set(record.__dict__.keys()) - {
|
|
72
|
+
'name', 'msg', 'args', 'created', 'filename', 'funcName',
|
|
73
|
+
'levelname', 'levelno', 'lineno', 'module', 'msecs',
|
|
74
|
+
'pathname', 'process', 'processName', 'relativeCreated',
|
|
75
|
+
'stack_info', 'exc_info', 'exc_text', 'thread', 'threadName',
|
|
76
|
+
'message', 'asctime', 'positional_args', '_logger'
|
|
77
|
+
}
|
|
78
|
+
if extra_keys:
|
|
79
|
+
details = {k: record.__dict__[k] for k in extra_keys if not k.startswith('_')}
|
|
80
|
+
|
|
81
|
+
# Create log entry
|
|
82
|
+
log_data = {
|
|
83
|
+
'timestamp': datetime.now().isoformat(),
|
|
84
|
+
'level': record.levelname.lower(),
|
|
85
|
+
'message': message,
|
|
86
|
+
'source': source,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Add details if present
|
|
90
|
+
if details:
|
|
91
|
+
log_data['details'] = details
|
|
92
|
+
|
|
93
|
+
# Non-blocking put - drop if queue is full
|
|
94
|
+
try:
|
|
95
|
+
self._queue.put_nowait(log_data)
|
|
96
|
+
except:
|
|
97
|
+
pass # Drop log if queue is full
|
|
98
|
+
|
|
99
|
+
except Exception:
|
|
100
|
+
pass # Never fail in log handler
|
|
101
|
+
|
|
102
|
+
def start(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
103
|
+
"""Start the background thread for processing logs."""
|
|
104
|
+
if self._running:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
self._loop = loop
|
|
108
|
+
self._running = True
|
|
109
|
+
self._thread = Thread(target=self._process_queue, daemon=True)
|
|
110
|
+
self._thread.start()
|
|
111
|
+
WebSocketLogHandler._instance = self
|
|
112
|
+
|
|
113
|
+
def stop(self) -> None:
|
|
114
|
+
"""Stop the background thread."""
|
|
115
|
+
self._running = False
|
|
116
|
+
WebSocketLogHandler._instance = None
|
|
117
|
+
if self._thread:
|
|
118
|
+
self._thread.join(timeout=1.0)
|
|
119
|
+
|
|
120
|
+
def _process_queue(self) -> None:
|
|
121
|
+
"""Background thread that processes log queue and broadcasts."""
|
|
122
|
+
while self._running:
|
|
123
|
+
try:
|
|
124
|
+
# Block for up to 0.1 seconds waiting for logs
|
|
125
|
+
try:
|
|
126
|
+
log_data = self._queue.get(timeout=0.1)
|
|
127
|
+
except:
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
# Schedule async broadcast on the event loop
|
|
131
|
+
if self._loop and self._running:
|
|
132
|
+
asyncio.run_coroutine_threadsafe(
|
|
133
|
+
self._broadcast(log_data),
|
|
134
|
+
self._loop
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
except Exception:
|
|
138
|
+
pass # Never fail in background thread
|
|
139
|
+
|
|
140
|
+
async def _broadcast(self, log_data: Dict[str, Any]) -> None:
|
|
141
|
+
"""Broadcast log to WebSocket clients."""
|
|
142
|
+
try:
|
|
143
|
+
from services.status_broadcaster import get_status_broadcaster
|
|
144
|
+
broadcaster = get_status_broadcaster()
|
|
145
|
+
await broadcaster.broadcast_terminal_log(log_data)
|
|
146
|
+
except Exception:
|
|
147
|
+
pass # Don't fail if broadcaster not ready
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def configure_logging(settings: Settings) -> None:
|
|
151
|
+
"""Configure structured logging based on settings."""
|
|
152
|
+
|
|
153
|
+
# Set up log file if specified
|
|
154
|
+
if settings.log_file:
|
|
155
|
+
log_path = Path(settings.log_file)
|
|
156
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
157
|
+
|
|
158
|
+
# Configure file handler
|
|
159
|
+
file_handler = logging.FileHandler(log_path)
|
|
160
|
+
file_handler.setLevel(getattr(logging, settings.log_level.upper()))
|
|
161
|
+
|
|
162
|
+
# Configure console handler
|
|
163
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
164
|
+
console_handler.setLevel(getattr(logging, settings.log_level.upper()))
|
|
165
|
+
|
|
166
|
+
# Configure root logger
|
|
167
|
+
logging.basicConfig(
|
|
168
|
+
level=getattr(logging, settings.log_level.upper()),
|
|
169
|
+
handlers=[console_handler, file_handler],
|
|
170
|
+
format="%(message)s"
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
# Console only
|
|
174
|
+
logging.basicConfig(
|
|
175
|
+
format="%(message)s",
|
|
176
|
+
stream=sys.stdout,
|
|
177
|
+
level=getattr(logging, settings.log_level.upper())
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Configure structlog
|
|
181
|
+
processors = [
|
|
182
|
+
structlog.stdlib.filter_by_level,
|
|
183
|
+
structlog.stdlib.add_log_level,
|
|
184
|
+
structlog.stdlib.PositionalArgumentsFormatter(),
|
|
185
|
+
structlog.processors.StackInfoRenderer(),
|
|
186
|
+
structlog.processors.format_exc_info,
|
|
187
|
+
structlog.processors.UnicodeDecoder(),
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
# Add appropriate renderer based on format
|
|
191
|
+
if settings.log_format == "json":
|
|
192
|
+
processors.insert(0, structlog.processors.TimeStamper(fmt="iso"))
|
|
193
|
+
processors.insert(0, structlog.stdlib.add_logger_name)
|
|
194
|
+
processors.append(structlog.processors.JSONRenderer())
|
|
195
|
+
else:
|
|
196
|
+
# Console format with timestamp
|
|
197
|
+
processors.insert(0, structlog.processors.TimeStamper(fmt="%H:%M:%S"))
|
|
198
|
+
processors.append(structlog.dev.ConsoleRenderer(
|
|
199
|
+
colors=False, # No ANSI colors for cleaner output
|
|
200
|
+
pad_event=35,
|
|
201
|
+
exception_formatter=structlog.dev.plain_traceback
|
|
202
|
+
))
|
|
203
|
+
|
|
204
|
+
structlog.configure(
|
|
205
|
+
processors=processors,
|
|
206
|
+
context_class=dict,
|
|
207
|
+
logger_factory=structlog.stdlib.LoggerFactory(),
|
|
208
|
+
wrapper_class=structlog.stdlib.BoundLogger,
|
|
209
|
+
cache_logger_on_first_use=True,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def get_logger(name: str) -> structlog.BoundLogger:
|
|
214
|
+
"""Get a structured logger instance."""
|
|
215
|
+
return structlog.get_logger(name)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def log_execution_time(logger: structlog.BoundLogger, operation: str,
|
|
219
|
+
start_time: float, end_time: float, **kwargs) -> None:
|
|
220
|
+
"""Log execution time with additional context."""
|
|
221
|
+
execution_time = end_time - start_time
|
|
222
|
+
logger.info(
|
|
223
|
+
"Operation completed",
|
|
224
|
+
operation=operation,
|
|
225
|
+
execution_time_seconds=round(execution_time, 4),
|
|
226
|
+
**kwargs
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def log_api_call(logger: structlog.BoundLogger, provider: str, model: str,
|
|
231
|
+
operation: str, success: bool, **kwargs) -> None:
|
|
232
|
+
"""Log API calls with standardized format."""
|
|
233
|
+
logger.info(
|
|
234
|
+
"API call completed",
|
|
235
|
+
provider=provider,
|
|
236
|
+
model=model,
|
|
237
|
+
operation=operation,
|
|
238
|
+
success=success,
|
|
239
|
+
**kwargs
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def log_cache_operation(logger: structlog.BoundLogger, operation: str,
|
|
244
|
+
key: str, hit: bool = None, **kwargs) -> None:
|
|
245
|
+
"""Log cache operations."""
|
|
246
|
+
log_data = {
|
|
247
|
+
"operation": operation,
|
|
248
|
+
"cache_key": key,
|
|
249
|
+
**kwargs
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if hit is not None:
|
|
253
|
+
log_data["cache_hit"] = hit
|
|
254
|
+
|
|
255
|
+
logger.debug("Cache operation", **log_data)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# Global WebSocket log handler instance
|
|
259
|
+
_ws_log_handler: Optional[WebSocketLogHandler] = None
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def setup_websocket_logging(loop: asyncio.AbstractEventLoop, level: int = logging.INFO) -> WebSocketLogHandler:
|
|
263
|
+
"""Setup and start the WebSocket log handler.
|
|
264
|
+
|
|
265
|
+
Should be called during application startup after the event loop is running.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
loop: The asyncio event loop to use for broadcasting
|
|
269
|
+
level: Minimum log level to broadcast (default: INFO)
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
The WebSocket log handler instance
|
|
273
|
+
"""
|
|
274
|
+
global _ws_log_handler
|
|
275
|
+
|
|
276
|
+
if _ws_log_handler is not None:
|
|
277
|
+
return _ws_log_handler
|
|
278
|
+
|
|
279
|
+
# Create handler
|
|
280
|
+
_ws_log_handler = WebSocketLogHandler(level=level)
|
|
281
|
+
|
|
282
|
+
# Add to root logger
|
|
283
|
+
root_logger = logging.getLogger()
|
|
284
|
+
root_logger.addHandler(_ws_log_handler)
|
|
285
|
+
|
|
286
|
+
# Start the background processing thread
|
|
287
|
+
_ws_log_handler.start(loop)
|
|
288
|
+
|
|
289
|
+
return _ws_log_handler
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def shutdown_websocket_logging() -> None:
|
|
293
|
+
"""Shutdown the WebSocket log handler.
|
|
294
|
+
|
|
295
|
+
Should be called during application shutdown.
|
|
296
|
+
"""
|
|
297
|
+
global _ws_log_handler
|
|
298
|
+
|
|
299
|
+
if _ws_log_handler is None:
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
# Stop the handler
|
|
303
|
+
_ws_log_handler.stop()
|
|
304
|
+
|
|
305
|
+
# Remove from root logger
|
|
306
|
+
root_logger = logging.getLogger()
|
|
307
|
+
root_logger.removeHandler(_ws_log_handler)
|
|
308
|
+
|
|
309
|
+
_ws_log_handler = None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def get_websocket_log_handler() -> Optional[WebSocketLogHandler]:
|
|
313
|
+
"""Get the current WebSocket log handler instance."""
|
|
314
314
|
return _ws_log_handler
|