amd-gaia 0.14.1__py3-none-any.whl
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.
- amd_gaia-0.14.1.dist-info/METADATA +768 -0
- amd_gaia-0.14.1.dist-info/RECORD +800 -0
- amd_gaia-0.14.1.dist-info/WHEEL +5 -0
- amd_gaia-0.14.1.dist-info/entry_points.txt +5 -0
- amd_gaia-0.14.1.dist-info/licenses/LICENSE.md +21 -0
- amd_gaia-0.14.1.dist-info/top_level.txt +1 -0
- gaia/__init__.py +2 -0
- gaia/agents/__init__.py +19 -0
- gaia/agents/base/__init__.py +9 -0
- gaia/agents/base/agent.py +2072 -0
- gaia/agents/base/api_agent.py +120 -0
- gaia/agents/base/console.py +1457 -0
- gaia/agents/base/mcp_agent.py +86 -0
- gaia/agents/base/tools.py +83 -0
- gaia/agents/blender/agent.py +556 -0
- gaia/agents/blender/agent_simple.py +135 -0
- gaia/agents/blender/app.py +211 -0
- gaia/agents/blender/app_simple.py +41 -0
- gaia/agents/blender/core/__init__.py +16 -0
- gaia/agents/blender/core/materials.py +506 -0
- gaia/agents/blender/core/objects.py +316 -0
- gaia/agents/blender/core/rendering.py +225 -0
- gaia/agents/blender/core/scene.py +220 -0
- gaia/agents/blender/core/view.py +146 -0
- gaia/agents/chat/__init__.py +9 -0
- gaia/agents/chat/agent.py +975 -0
- gaia/agents/chat/app.py +1058 -0
- gaia/agents/chat/session.py +508 -0
- gaia/agents/chat/tools/__init__.py +15 -0
- gaia/agents/chat/tools/file_tools.py +96 -0
- gaia/agents/chat/tools/rag_tools.py +1729 -0
- gaia/agents/chat/tools/shell_tools.py +436 -0
- gaia/agents/code/__init__.py +7 -0
- gaia/agents/code/agent.py +547 -0
- gaia/agents/code/app.py +266 -0
- gaia/agents/code/models.py +135 -0
- gaia/agents/code/orchestration/__init__.py +24 -0
- gaia/agents/code/orchestration/checklist_executor.py +1739 -0
- gaia/agents/code/orchestration/checklist_generator.py +709 -0
- gaia/agents/code/orchestration/factories/__init__.py +9 -0
- gaia/agents/code/orchestration/factories/base.py +63 -0
- gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -0
- gaia/agents/code/orchestration/factories/python_factory.py +106 -0
- gaia/agents/code/orchestration/orchestrator.py +610 -0
- gaia/agents/code/orchestration/project_analyzer.py +391 -0
- gaia/agents/code/orchestration/steps/__init__.py +67 -0
- gaia/agents/code/orchestration/steps/base.py +188 -0
- gaia/agents/code/orchestration/steps/error_handler.py +314 -0
- gaia/agents/code/orchestration/steps/nextjs.py +828 -0
- gaia/agents/code/orchestration/steps/python.py +307 -0
- gaia/agents/code/orchestration/template_catalog.py +463 -0
- gaia/agents/code/orchestration/workflows/__init__.py +14 -0
- gaia/agents/code/orchestration/workflows/base.py +80 -0
- gaia/agents/code/orchestration/workflows/nextjs.py +186 -0
- gaia/agents/code/orchestration/workflows/python.py +94 -0
- gaia/agents/code/prompts/__init__.py +11 -0
- gaia/agents/code/prompts/base_prompt.py +77 -0
- gaia/agents/code/prompts/code_patterns.py +1925 -0
- gaia/agents/code/prompts/nextjs_prompt.py +40 -0
- gaia/agents/code/prompts/python_prompt.py +109 -0
- gaia/agents/code/schema_inference.py +365 -0
- gaia/agents/code/system_prompt.py +41 -0
- gaia/agents/code/tools/__init__.py +42 -0
- gaia/agents/code/tools/cli_tools.py +1138 -0
- gaia/agents/code/tools/code_formatting.py +319 -0
- gaia/agents/code/tools/code_tools.py +769 -0
- gaia/agents/code/tools/error_fixing.py +1347 -0
- gaia/agents/code/tools/external_tools.py +180 -0
- gaia/agents/code/tools/file_io.py +845 -0
- gaia/agents/code/tools/prisma_tools.py +190 -0
- gaia/agents/code/tools/project_management.py +1016 -0
- gaia/agents/code/tools/testing.py +321 -0
- gaia/agents/code/tools/typescript_tools.py +122 -0
- gaia/agents/code/tools/validation_parsing.py +461 -0
- gaia/agents/code/tools/validation_tools.py +803 -0
- gaia/agents/code/tools/web_dev_tools.py +1744 -0
- gaia/agents/code/validators/__init__.py +16 -0
- gaia/agents/code/validators/antipattern_checker.py +241 -0
- gaia/agents/code/validators/ast_analyzer.py +197 -0
- gaia/agents/code/validators/requirements_validator.py +145 -0
- gaia/agents/code/validators/syntax_validator.py +171 -0
- gaia/agents/docker/__init__.py +7 -0
- gaia/agents/docker/agent.py +642 -0
- gaia/agents/jira/__init__.py +11 -0
- gaia/agents/jira/agent.py +894 -0
- gaia/agents/jira/jql_templates.py +299 -0
- gaia/agents/routing/__init__.py +7 -0
- gaia/agents/routing/agent.py +512 -0
- gaia/agents/routing/system_prompt.py +75 -0
- gaia/api/__init__.py +23 -0
- gaia/api/agent_registry.py +238 -0
- gaia/api/app.py +305 -0
- gaia/api/openai_server.py +575 -0
- gaia/api/schemas.py +186 -0
- gaia/api/sse_handler.py +370 -0
- gaia/apps/__init__.py +4 -0
- gaia/apps/llm/__init__.py +6 -0
- gaia/apps/llm/app.py +169 -0
- gaia/apps/summarize/app.py +633 -0
- gaia/apps/summarize/html_viewer.py +133 -0
- gaia/apps/summarize/pdf_formatter.py +284 -0
- gaia/audio/__init__.py +2 -0
- gaia/audio/audio_client.py +439 -0
- gaia/audio/audio_recorder.py +269 -0
- gaia/audio/kokoro_tts.py +599 -0
- gaia/audio/whisper_asr.py +432 -0
- gaia/chat/__init__.py +16 -0
- gaia/chat/app.py +430 -0
- gaia/chat/prompts.py +522 -0
- gaia/chat/sdk.py +1200 -0
- gaia/cli.py +5621 -0
- gaia/eval/batch_experiment.py +2332 -0
- gaia/eval/claude.py +542 -0
- gaia/eval/config.py +37 -0
- gaia/eval/email_generator.py +512 -0
- gaia/eval/eval.py +3179 -0
- gaia/eval/groundtruth.py +1130 -0
- gaia/eval/transcript_generator.py +582 -0
- gaia/eval/webapp/README.md +168 -0
- gaia/eval/webapp/node_modules/.bin/mime +16 -0
- gaia/eval/webapp/node_modules/.bin/mime.cmd +17 -0
- gaia/eval/webapp/node_modules/.bin/mime.ps1 +28 -0
- gaia/eval/webapp/node_modules/.package-lock.json +865 -0
- gaia/eval/webapp/node_modules/accepts/HISTORY.md +243 -0
- gaia/eval/webapp/node_modules/accepts/LICENSE +23 -0
- gaia/eval/webapp/node_modules/accepts/README.md +140 -0
- gaia/eval/webapp/node_modules/accepts/index.js +238 -0
- gaia/eval/webapp/node_modules/accepts/package.json +47 -0
- gaia/eval/webapp/node_modules/array-flatten/LICENSE +21 -0
- gaia/eval/webapp/node_modules/array-flatten/README.md +43 -0
- gaia/eval/webapp/node_modules/array-flatten/array-flatten.js +64 -0
- gaia/eval/webapp/node_modules/array-flatten/package.json +39 -0
- gaia/eval/webapp/node_modules/body-parser/HISTORY.md +672 -0
- gaia/eval/webapp/node_modules/body-parser/LICENSE +23 -0
- gaia/eval/webapp/node_modules/body-parser/README.md +476 -0
- gaia/eval/webapp/node_modules/body-parser/SECURITY.md +25 -0
- gaia/eval/webapp/node_modules/body-parser/index.js +156 -0
- gaia/eval/webapp/node_modules/body-parser/lib/read.js +205 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/json.js +247 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/raw.js +101 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/text.js +121 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/urlencoded.js +307 -0
- gaia/eval/webapp/node_modules/body-parser/package.json +56 -0
- gaia/eval/webapp/node_modules/bytes/History.md +97 -0
- gaia/eval/webapp/node_modules/bytes/LICENSE +23 -0
- gaia/eval/webapp/node_modules/bytes/Readme.md +152 -0
- gaia/eval/webapp/node_modules/bytes/index.js +170 -0
- gaia/eval/webapp/node_modules/bytes/package.json +42 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/.nycrc +9 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/LICENSE +21 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/README.md +62 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.js +15 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/package.json +85 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/test/index.js +63 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/call-bound/.eslintrc +13 -0
- gaia/eval/webapp/node_modules/call-bound/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/call-bound/.nycrc +9 -0
- gaia/eval/webapp/node_modules/call-bound/CHANGELOG.md +42 -0
- gaia/eval/webapp/node_modules/call-bound/LICENSE +21 -0
- gaia/eval/webapp/node_modules/call-bound/README.md +53 -0
- gaia/eval/webapp/node_modules/call-bound/index.d.ts +94 -0
- gaia/eval/webapp/node_modules/call-bound/index.js +19 -0
- gaia/eval/webapp/node_modules/call-bound/package.json +99 -0
- gaia/eval/webapp/node_modules/call-bound/test/index.js +61 -0
- gaia/eval/webapp/node_modules/call-bound/tsconfig.json +10 -0
- gaia/eval/webapp/node_modules/content-disposition/HISTORY.md +60 -0
- gaia/eval/webapp/node_modules/content-disposition/LICENSE +22 -0
- gaia/eval/webapp/node_modules/content-disposition/README.md +142 -0
- gaia/eval/webapp/node_modules/content-disposition/index.js +458 -0
- gaia/eval/webapp/node_modules/content-disposition/package.json +44 -0
- gaia/eval/webapp/node_modules/content-type/HISTORY.md +29 -0
- gaia/eval/webapp/node_modules/content-type/LICENSE +22 -0
- gaia/eval/webapp/node_modules/content-type/README.md +94 -0
- gaia/eval/webapp/node_modules/content-type/index.js +225 -0
- gaia/eval/webapp/node_modules/content-type/package.json +42 -0
- gaia/eval/webapp/node_modules/cookie/LICENSE +24 -0
- gaia/eval/webapp/node_modules/cookie/README.md +317 -0
- gaia/eval/webapp/node_modules/cookie/SECURITY.md +25 -0
- gaia/eval/webapp/node_modules/cookie/index.js +334 -0
- gaia/eval/webapp/node_modules/cookie/package.json +44 -0
- gaia/eval/webapp/node_modules/cookie-signature/.npmignore +4 -0
- gaia/eval/webapp/node_modules/cookie-signature/History.md +38 -0
- gaia/eval/webapp/node_modules/cookie-signature/Readme.md +42 -0
- gaia/eval/webapp/node_modules/cookie-signature/index.js +51 -0
- gaia/eval/webapp/node_modules/cookie-signature/package.json +18 -0
- gaia/eval/webapp/node_modules/debug/.coveralls.yml +1 -0
- gaia/eval/webapp/node_modules/debug/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/debug/.npmignore +9 -0
- gaia/eval/webapp/node_modules/debug/.travis.yml +14 -0
- gaia/eval/webapp/node_modules/debug/CHANGELOG.md +362 -0
- gaia/eval/webapp/node_modules/debug/LICENSE +19 -0
- gaia/eval/webapp/node_modules/debug/Makefile +50 -0
- gaia/eval/webapp/node_modules/debug/README.md +312 -0
- gaia/eval/webapp/node_modules/debug/component.json +19 -0
- gaia/eval/webapp/node_modules/debug/karma.conf.js +70 -0
- gaia/eval/webapp/node_modules/debug/node.js +1 -0
- gaia/eval/webapp/node_modules/debug/package.json +49 -0
- gaia/eval/webapp/node_modules/debug/src/browser.js +185 -0
- gaia/eval/webapp/node_modules/debug/src/debug.js +202 -0
- gaia/eval/webapp/node_modules/debug/src/index.js +10 -0
- gaia/eval/webapp/node_modules/debug/src/inspector-log.js +15 -0
- gaia/eval/webapp/node_modules/debug/src/node.js +248 -0
- gaia/eval/webapp/node_modules/depd/History.md +103 -0
- gaia/eval/webapp/node_modules/depd/LICENSE +22 -0
- gaia/eval/webapp/node_modules/depd/Readme.md +280 -0
- gaia/eval/webapp/node_modules/depd/index.js +538 -0
- gaia/eval/webapp/node_modules/depd/lib/browser/index.js +77 -0
- gaia/eval/webapp/node_modules/depd/package.json +45 -0
- gaia/eval/webapp/node_modules/destroy/LICENSE +23 -0
- gaia/eval/webapp/node_modules/destroy/README.md +63 -0
- gaia/eval/webapp/node_modules/destroy/index.js +209 -0
- gaia/eval/webapp/node_modules/destroy/package.json +48 -0
- gaia/eval/webapp/node_modules/dunder-proto/.eslintrc +5 -0
- gaia/eval/webapp/node_modules/dunder-proto/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/dunder-proto/.nycrc +13 -0
- gaia/eval/webapp/node_modules/dunder-proto/CHANGELOG.md +24 -0
- gaia/eval/webapp/node_modules/dunder-proto/LICENSE +21 -0
- gaia/eval/webapp/node_modules/dunder-proto/README.md +54 -0
- gaia/eval/webapp/node_modules/dunder-proto/get.d.ts +5 -0
- gaia/eval/webapp/node_modules/dunder-proto/get.js +30 -0
- gaia/eval/webapp/node_modules/dunder-proto/package.json +76 -0
- gaia/eval/webapp/node_modules/dunder-proto/set.d.ts +5 -0
- gaia/eval/webapp/node_modules/dunder-proto/set.js +35 -0
- gaia/eval/webapp/node_modules/dunder-proto/test/get.js +34 -0
- gaia/eval/webapp/node_modules/dunder-proto/test/index.js +4 -0
- gaia/eval/webapp/node_modules/dunder-proto/test/set.js +50 -0
- gaia/eval/webapp/node_modules/dunder-proto/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/ee-first/LICENSE +22 -0
- gaia/eval/webapp/node_modules/ee-first/README.md +80 -0
- gaia/eval/webapp/node_modules/ee-first/index.js +95 -0
- gaia/eval/webapp/node_modules/ee-first/package.json +29 -0
- gaia/eval/webapp/node_modules/encodeurl/LICENSE +22 -0
- gaia/eval/webapp/node_modules/encodeurl/README.md +109 -0
- gaia/eval/webapp/node_modules/encodeurl/index.js +60 -0
- gaia/eval/webapp/node_modules/encodeurl/package.json +40 -0
- gaia/eval/webapp/node_modules/es-define-property/.eslintrc +13 -0
- gaia/eval/webapp/node_modules/es-define-property/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/es-define-property/.nycrc +9 -0
- gaia/eval/webapp/node_modules/es-define-property/CHANGELOG.md +29 -0
- gaia/eval/webapp/node_modules/es-define-property/LICENSE +21 -0
- gaia/eval/webapp/node_modules/es-define-property/README.md +49 -0
- gaia/eval/webapp/node_modules/es-define-property/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-define-property/index.js +14 -0
- gaia/eval/webapp/node_modules/es-define-property/package.json +81 -0
- gaia/eval/webapp/node_modules/es-define-property/test/index.js +56 -0
- gaia/eval/webapp/node_modules/es-define-property/tsconfig.json +10 -0
- gaia/eval/webapp/node_modules/es-errors/.eslintrc +5 -0
- gaia/eval/webapp/node_modules/es-errors/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/es-errors/CHANGELOG.md +40 -0
- gaia/eval/webapp/node_modules/es-errors/LICENSE +21 -0
- gaia/eval/webapp/node_modules/es-errors/README.md +55 -0
- gaia/eval/webapp/node_modules/es-errors/eval.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/eval.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/index.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/package.json +80 -0
- gaia/eval/webapp/node_modules/es-errors/range.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/range.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/ref.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/ref.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/syntax.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/syntax.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/test/index.js +19 -0
- gaia/eval/webapp/node_modules/es-errors/tsconfig.json +49 -0
- gaia/eval/webapp/node_modules/es-errors/type.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/type.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/uri.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/uri.js +4 -0
- gaia/eval/webapp/node_modules/es-object-atoms/.eslintrc +16 -0
- gaia/eval/webapp/node_modules/es-object-atoms/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/es-object-atoms/CHANGELOG.md +37 -0
- gaia/eval/webapp/node_modules/es-object-atoms/LICENSE +21 -0
- gaia/eval/webapp/node_modules/es-object-atoms/README.md +63 -0
- gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
- gaia/eval/webapp/node_modules/es-object-atoms/ToObject.d.ts +7 -0
- gaia/eval/webapp/node_modules/es-object-atoms/ToObject.js +10 -0
- gaia/eval/webapp/node_modules/es-object-atoms/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-object-atoms/index.js +4 -0
- gaia/eval/webapp/node_modules/es-object-atoms/isObject.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-object-atoms/isObject.js +6 -0
- gaia/eval/webapp/node_modules/es-object-atoms/package.json +80 -0
- gaia/eval/webapp/node_modules/es-object-atoms/test/index.js +38 -0
- gaia/eval/webapp/node_modules/es-object-atoms/tsconfig.json +6 -0
- gaia/eval/webapp/node_modules/escape-html/LICENSE +24 -0
- gaia/eval/webapp/node_modules/escape-html/Readme.md +43 -0
- gaia/eval/webapp/node_modules/escape-html/index.js +78 -0
- gaia/eval/webapp/node_modules/escape-html/package.json +24 -0
- gaia/eval/webapp/node_modules/etag/HISTORY.md +83 -0
- gaia/eval/webapp/node_modules/etag/LICENSE +22 -0
- gaia/eval/webapp/node_modules/etag/README.md +159 -0
- gaia/eval/webapp/node_modules/etag/index.js +131 -0
- gaia/eval/webapp/node_modules/etag/package.json +47 -0
- gaia/eval/webapp/node_modules/express/History.md +3656 -0
- gaia/eval/webapp/node_modules/express/LICENSE +24 -0
- gaia/eval/webapp/node_modules/express/Readme.md +260 -0
- gaia/eval/webapp/node_modules/express/index.js +11 -0
- gaia/eval/webapp/node_modules/express/lib/application.js +661 -0
- gaia/eval/webapp/node_modules/express/lib/express.js +116 -0
- gaia/eval/webapp/node_modules/express/lib/middleware/init.js +43 -0
- gaia/eval/webapp/node_modules/express/lib/middleware/query.js +47 -0
- gaia/eval/webapp/node_modules/express/lib/request.js +525 -0
- gaia/eval/webapp/node_modules/express/lib/response.js +1179 -0
- gaia/eval/webapp/node_modules/express/lib/router/index.js +673 -0
- gaia/eval/webapp/node_modules/express/lib/router/layer.js +181 -0
- gaia/eval/webapp/node_modules/express/lib/router/route.js +230 -0
- gaia/eval/webapp/node_modules/express/lib/utils.js +303 -0
- gaia/eval/webapp/node_modules/express/lib/view.js +182 -0
- gaia/eval/webapp/node_modules/express/package.json +102 -0
- gaia/eval/webapp/node_modules/finalhandler/HISTORY.md +210 -0
- gaia/eval/webapp/node_modules/finalhandler/LICENSE +22 -0
- gaia/eval/webapp/node_modules/finalhandler/README.md +147 -0
- gaia/eval/webapp/node_modules/finalhandler/SECURITY.md +25 -0
- gaia/eval/webapp/node_modules/finalhandler/index.js +341 -0
- gaia/eval/webapp/node_modules/finalhandler/package.json +47 -0
- gaia/eval/webapp/node_modules/forwarded/HISTORY.md +21 -0
- gaia/eval/webapp/node_modules/forwarded/LICENSE +22 -0
- gaia/eval/webapp/node_modules/forwarded/README.md +57 -0
- gaia/eval/webapp/node_modules/forwarded/index.js +90 -0
- gaia/eval/webapp/node_modules/forwarded/package.json +45 -0
- gaia/eval/webapp/node_modules/fresh/HISTORY.md +70 -0
- gaia/eval/webapp/node_modules/fresh/LICENSE +23 -0
- gaia/eval/webapp/node_modules/fresh/README.md +119 -0
- gaia/eval/webapp/node_modules/fresh/index.js +137 -0
- gaia/eval/webapp/node_modules/fresh/package.json +46 -0
- gaia/eval/webapp/node_modules/fs/README.md +9 -0
- gaia/eval/webapp/node_modules/fs/package.json +20 -0
- gaia/eval/webapp/node_modules/function-bind/.eslintrc +21 -0
- gaia/eval/webapp/node_modules/function-bind/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/function-bind/.github/SECURITY.md +3 -0
- gaia/eval/webapp/node_modules/function-bind/.nycrc +13 -0
- gaia/eval/webapp/node_modules/function-bind/CHANGELOG.md +136 -0
- gaia/eval/webapp/node_modules/function-bind/LICENSE +20 -0
- gaia/eval/webapp/node_modules/function-bind/README.md +46 -0
- gaia/eval/webapp/node_modules/function-bind/implementation.js +84 -0
- gaia/eval/webapp/node_modules/function-bind/index.js +5 -0
- gaia/eval/webapp/node_modules/function-bind/package.json +87 -0
- gaia/eval/webapp/node_modules/function-bind/test/.eslintrc +9 -0
- gaia/eval/webapp/node_modules/function-bind/test/index.js +252 -0
- gaia/eval/webapp/node_modules/get-intrinsic/.eslintrc +42 -0
- gaia/eval/webapp/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/get-intrinsic/.nycrc +9 -0
- gaia/eval/webapp/node_modules/get-intrinsic/CHANGELOG.md +186 -0
- gaia/eval/webapp/node_modules/get-intrinsic/LICENSE +21 -0
- gaia/eval/webapp/node_modules/get-intrinsic/README.md +71 -0
- gaia/eval/webapp/node_modules/get-intrinsic/index.js +378 -0
- gaia/eval/webapp/node_modules/get-intrinsic/package.json +97 -0
- gaia/eval/webapp/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
- gaia/eval/webapp/node_modules/get-proto/.eslintrc +10 -0
- gaia/eval/webapp/node_modules/get-proto/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/get-proto/.nycrc +9 -0
- gaia/eval/webapp/node_modules/get-proto/CHANGELOG.md +21 -0
- gaia/eval/webapp/node_modules/get-proto/LICENSE +21 -0
- gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
- gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
- gaia/eval/webapp/node_modules/get-proto/README.md +50 -0
- gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
- gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
- gaia/eval/webapp/node_modules/get-proto/index.d.ts +5 -0
- gaia/eval/webapp/node_modules/get-proto/index.js +27 -0
- gaia/eval/webapp/node_modules/get-proto/package.json +81 -0
- gaia/eval/webapp/node_modules/get-proto/test/index.js +68 -0
- gaia/eval/webapp/node_modules/get-proto/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/gopd/.eslintrc +16 -0
- gaia/eval/webapp/node_modules/gopd/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/gopd/CHANGELOG.md +45 -0
- gaia/eval/webapp/node_modules/gopd/LICENSE +21 -0
- gaia/eval/webapp/node_modules/gopd/README.md +40 -0
- gaia/eval/webapp/node_modules/gopd/gOPD.d.ts +1 -0
- gaia/eval/webapp/node_modules/gopd/gOPD.js +4 -0
- gaia/eval/webapp/node_modules/gopd/index.d.ts +5 -0
- gaia/eval/webapp/node_modules/gopd/index.js +15 -0
- gaia/eval/webapp/node_modules/gopd/package.json +77 -0
- gaia/eval/webapp/node_modules/gopd/test/index.js +36 -0
- gaia/eval/webapp/node_modules/gopd/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/has-symbols/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/has-symbols/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/has-symbols/.nycrc +9 -0
- gaia/eval/webapp/node_modules/has-symbols/CHANGELOG.md +91 -0
- gaia/eval/webapp/node_modules/has-symbols/LICENSE +21 -0
- gaia/eval/webapp/node_modules/has-symbols/README.md +46 -0
- gaia/eval/webapp/node_modules/has-symbols/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/has-symbols/index.js +14 -0
- gaia/eval/webapp/node_modules/has-symbols/package.json +111 -0
- gaia/eval/webapp/node_modules/has-symbols/shams.d.ts +3 -0
- gaia/eval/webapp/node_modules/has-symbols/shams.js +45 -0
- gaia/eval/webapp/node_modules/has-symbols/test/index.js +22 -0
- gaia/eval/webapp/node_modules/has-symbols/test/shams/core-js.js +29 -0
- gaia/eval/webapp/node_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
- gaia/eval/webapp/node_modules/has-symbols/test/tests.js +58 -0
- gaia/eval/webapp/node_modules/has-symbols/tsconfig.json +10 -0
- gaia/eval/webapp/node_modules/hasown/.eslintrc +5 -0
- gaia/eval/webapp/node_modules/hasown/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/hasown/.nycrc +13 -0
- gaia/eval/webapp/node_modules/hasown/CHANGELOG.md +40 -0
- gaia/eval/webapp/node_modules/hasown/LICENSE +21 -0
- gaia/eval/webapp/node_modules/hasown/README.md +40 -0
- gaia/eval/webapp/node_modules/hasown/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/hasown/index.js +8 -0
- gaia/eval/webapp/node_modules/hasown/package.json +92 -0
- gaia/eval/webapp/node_modules/hasown/tsconfig.json +6 -0
- gaia/eval/webapp/node_modules/http-errors/HISTORY.md +180 -0
- gaia/eval/webapp/node_modules/http-errors/LICENSE +23 -0
- gaia/eval/webapp/node_modules/http-errors/README.md +169 -0
- gaia/eval/webapp/node_modules/http-errors/index.js +289 -0
- gaia/eval/webapp/node_modules/http-errors/package.json +50 -0
- gaia/eval/webapp/node_modules/iconv-lite/Changelog.md +162 -0
- gaia/eval/webapp/node_modules/iconv-lite/LICENSE +21 -0
- gaia/eval/webapp/node_modules/iconv-lite/README.md +156 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-codec.js +555 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-data.js +176 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/index.js +22 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/internal.js +188 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-codec.js +72 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data-generated.js +451 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data.js +174 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/big5-added.json +122 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp936.json +264 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp949.json +273 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp950.json +177 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/eucjp.json +182 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +1 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gbk-added.json +55 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/shiftjis.json +125 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/utf16.js +177 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/utf7.js +290 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/bom-handling.js +52 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/extend-node.js +217 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/index.d.ts +24 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/index.js +153 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/streams.js +121 -0
- gaia/eval/webapp/node_modules/iconv-lite/package.json +46 -0
- gaia/eval/webapp/node_modules/inherits/LICENSE +16 -0
- gaia/eval/webapp/node_modules/inherits/README.md +42 -0
- gaia/eval/webapp/node_modules/inherits/inherits.js +9 -0
- gaia/eval/webapp/node_modules/inherits/inherits_browser.js +27 -0
- gaia/eval/webapp/node_modules/inherits/package.json +29 -0
- gaia/eval/webapp/node_modules/ipaddr.js/LICENSE +19 -0
- gaia/eval/webapp/node_modules/ipaddr.js/README.md +233 -0
- gaia/eval/webapp/node_modules/ipaddr.js/ipaddr.min.js +1 -0
- gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js +673 -0
- gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js.d.ts +68 -0
- gaia/eval/webapp/node_modules/ipaddr.js/package.json +35 -0
- gaia/eval/webapp/node_modules/math-intrinsics/.eslintrc +16 -0
- gaia/eval/webapp/node_modules/math-intrinsics/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/math-intrinsics/CHANGELOG.md +24 -0
- gaia/eval/webapp/node_modules/math-intrinsics/LICENSE +21 -0
- gaia/eval/webapp/node_modules/math-intrinsics/README.md +50 -0
- gaia/eval/webapp/node_modules/math-intrinsics/abs.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/abs.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.js +5 -0
- gaia/eval/webapp/node_modules/math-intrinsics/floor.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/floor.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isFinite.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isFinite.js +12 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isInteger.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isInteger.js +16 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNaN.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNaN.js +6 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.js +6 -0
- gaia/eval/webapp/node_modules/math-intrinsics/max.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/max.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/min.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/min.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/mod.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/mod.js +9 -0
- gaia/eval/webapp/node_modules/math-intrinsics/package.json +86 -0
- gaia/eval/webapp/node_modules/math-intrinsics/pow.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/pow.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/round.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/round.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/sign.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/sign.js +11 -0
- gaia/eval/webapp/node_modules/math-intrinsics/test/index.js +192 -0
- gaia/eval/webapp/node_modules/math-intrinsics/tsconfig.json +3 -0
- gaia/eval/webapp/node_modules/media-typer/HISTORY.md +22 -0
- gaia/eval/webapp/node_modules/media-typer/LICENSE +22 -0
- gaia/eval/webapp/node_modules/media-typer/README.md +81 -0
- gaia/eval/webapp/node_modules/media-typer/index.js +270 -0
- gaia/eval/webapp/node_modules/media-typer/package.json +26 -0
- gaia/eval/webapp/node_modules/merge-descriptors/HISTORY.md +21 -0
- gaia/eval/webapp/node_modules/merge-descriptors/LICENSE +23 -0
- gaia/eval/webapp/node_modules/merge-descriptors/README.md +49 -0
- gaia/eval/webapp/node_modules/merge-descriptors/index.js +60 -0
- gaia/eval/webapp/node_modules/merge-descriptors/package.json +39 -0
- gaia/eval/webapp/node_modules/methods/HISTORY.md +29 -0
- gaia/eval/webapp/node_modules/methods/LICENSE +24 -0
- gaia/eval/webapp/node_modules/methods/README.md +51 -0
- gaia/eval/webapp/node_modules/methods/index.js +69 -0
- gaia/eval/webapp/node_modules/methods/package.json +36 -0
- gaia/eval/webapp/node_modules/mime/.npmignore +0 -0
- gaia/eval/webapp/node_modules/mime/CHANGELOG.md +164 -0
- gaia/eval/webapp/node_modules/mime/LICENSE +21 -0
- gaia/eval/webapp/node_modules/mime/README.md +90 -0
- gaia/eval/webapp/node_modules/mime/cli.js +8 -0
- gaia/eval/webapp/node_modules/mime/mime.js +108 -0
- gaia/eval/webapp/node_modules/mime/package.json +44 -0
- gaia/eval/webapp/node_modules/mime/src/build.js +53 -0
- gaia/eval/webapp/node_modules/mime/src/test.js +60 -0
- gaia/eval/webapp/node_modules/mime/types.json +1 -0
- gaia/eval/webapp/node_modules/mime-db/HISTORY.md +507 -0
- gaia/eval/webapp/node_modules/mime-db/LICENSE +23 -0
- gaia/eval/webapp/node_modules/mime-db/README.md +100 -0
- gaia/eval/webapp/node_modules/mime-db/db.json +8519 -0
- gaia/eval/webapp/node_modules/mime-db/index.js +12 -0
- gaia/eval/webapp/node_modules/mime-db/package.json +60 -0
- gaia/eval/webapp/node_modules/mime-types/HISTORY.md +397 -0
- gaia/eval/webapp/node_modules/mime-types/LICENSE +23 -0
- gaia/eval/webapp/node_modules/mime-types/README.md +113 -0
- gaia/eval/webapp/node_modules/mime-types/index.js +188 -0
- gaia/eval/webapp/node_modules/mime-types/package.json +44 -0
- gaia/eval/webapp/node_modules/ms/index.js +152 -0
- gaia/eval/webapp/node_modules/ms/license.md +21 -0
- gaia/eval/webapp/node_modules/ms/package.json +37 -0
- gaia/eval/webapp/node_modules/ms/readme.md +51 -0
- gaia/eval/webapp/node_modules/negotiator/HISTORY.md +108 -0
- gaia/eval/webapp/node_modules/negotiator/LICENSE +24 -0
- gaia/eval/webapp/node_modules/negotiator/README.md +203 -0
- gaia/eval/webapp/node_modules/negotiator/index.js +82 -0
- gaia/eval/webapp/node_modules/negotiator/lib/charset.js +169 -0
- gaia/eval/webapp/node_modules/negotiator/lib/encoding.js +184 -0
- gaia/eval/webapp/node_modules/negotiator/lib/language.js +179 -0
- gaia/eval/webapp/node_modules/negotiator/lib/mediaType.js +294 -0
- gaia/eval/webapp/node_modules/negotiator/package.json +42 -0
- gaia/eval/webapp/node_modules/object-inspect/.eslintrc +53 -0
- gaia/eval/webapp/node_modules/object-inspect/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/object-inspect/.nycrc +13 -0
- gaia/eval/webapp/node_modules/object-inspect/CHANGELOG.md +424 -0
- gaia/eval/webapp/node_modules/object-inspect/LICENSE +21 -0
- gaia/eval/webapp/node_modules/object-inspect/example/all.js +23 -0
- gaia/eval/webapp/node_modules/object-inspect/example/circular.js +6 -0
- gaia/eval/webapp/node_modules/object-inspect/example/fn.js +5 -0
- gaia/eval/webapp/node_modules/object-inspect/example/inspect.js +10 -0
- gaia/eval/webapp/node_modules/object-inspect/index.js +544 -0
- gaia/eval/webapp/node_modules/object-inspect/package-support.json +20 -0
- gaia/eval/webapp/node_modules/object-inspect/package.json +105 -0
- gaia/eval/webapp/node_modules/object-inspect/readme.markdown +84 -0
- gaia/eval/webapp/node_modules/object-inspect/test/bigint.js +58 -0
- gaia/eval/webapp/node_modules/object-inspect/test/browser/dom.js +15 -0
- gaia/eval/webapp/node_modules/object-inspect/test/circular.js +16 -0
- gaia/eval/webapp/node_modules/object-inspect/test/deep.js +12 -0
- gaia/eval/webapp/node_modules/object-inspect/test/element.js +53 -0
- gaia/eval/webapp/node_modules/object-inspect/test/err.js +48 -0
- gaia/eval/webapp/node_modules/object-inspect/test/fakes.js +29 -0
- gaia/eval/webapp/node_modules/object-inspect/test/fn.js +76 -0
- gaia/eval/webapp/node_modules/object-inspect/test/global.js +17 -0
- gaia/eval/webapp/node_modules/object-inspect/test/has.js +15 -0
- gaia/eval/webapp/node_modules/object-inspect/test/holes.js +15 -0
- gaia/eval/webapp/node_modules/object-inspect/test/indent-option.js +271 -0
- gaia/eval/webapp/node_modules/object-inspect/test/inspect.js +139 -0
- gaia/eval/webapp/node_modules/object-inspect/test/lowbyte.js +12 -0
- gaia/eval/webapp/node_modules/object-inspect/test/number.js +58 -0
- gaia/eval/webapp/node_modules/object-inspect/test/quoteStyle.js +26 -0
- gaia/eval/webapp/node_modules/object-inspect/test/toStringTag.js +40 -0
- gaia/eval/webapp/node_modules/object-inspect/test/undef.js +12 -0
- gaia/eval/webapp/node_modules/object-inspect/test/values.js +261 -0
- gaia/eval/webapp/node_modules/object-inspect/test-core-js.js +26 -0
- gaia/eval/webapp/node_modules/object-inspect/util.inspect.js +1 -0
- gaia/eval/webapp/node_modules/on-finished/HISTORY.md +98 -0
- gaia/eval/webapp/node_modules/on-finished/LICENSE +23 -0
- gaia/eval/webapp/node_modules/on-finished/README.md +162 -0
- gaia/eval/webapp/node_modules/on-finished/index.js +234 -0
- gaia/eval/webapp/node_modules/on-finished/package.json +39 -0
- gaia/eval/webapp/node_modules/parseurl/HISTORY.md +58 -0
- gaia/eval/webapp/node_modules/parseurl/LICENSE +24 -0
- gaia/eval/webapp/node_modules/parseurl/README.md +133 -0
- gaia/eval/webapp/node_modules/parseurl/index.js +158 -0
- gaia/eval/webapp/node_modules/parseurl/package.json +40 -0
- gaia/eval/webapp/node_modules/path/.npmignore +1 -0
- gaia/eval/webapp/node_modules/path/LICENSE +18 -0
- gaia/eval/webapp/node_modules/path/README.md +15 -0
- gaia/eval/webapp/node_modules/path/package.json +24 -0
- gaia/eval/webapp/node_modules/path/path.js +628 -0
- gaia/eval/webapp/node_modules/path-to-regexp/LICENSE +21 -0
- gaia/eval/webapp/node_modules/path-to-regexp/Readme.md +35 -0
- gaia/eval/webapp/node_modules/path-to-regexp/index.js +156 -0
- gaia/eval/webapp/node_modules/path-to-regexp/package.json +30 -0
- gaia/eval/webapp/node_modules/process/.eslintrc +21 -0
- gaia/eval/webapp/node_modules/process/LICENSE +22 -0
- gaia/eval/webapp/node_modules/process/README.md +26 -0
- gaia/eval/webapp/node_modules/process/browser.js +184 -0
- gaia/eval/webapp/node_modules/process/index.js +2 -0
- gaia/eval/webapp/node_modules/process/package.json +27 -0
- gaia/eval/webapp/node_modules/process/test.js +199 -0
- gaia/eval/webapp/node_modules/proxy-addr/HISTORY.md +161 -0
- gaia/eval/webapp/node_modules/proxy-addr/LICENSE +22 -0
- gaia/eval/webapp/node_modules/proxy-addr/README.md +139 -0
- gaia/eval/webapp/node_modules/proxy-addr/index.js +327 -0
- gaia/eval/webapp/node_modules/proxy-addr/package.json +47 -0
- gaia/eval/webapp/node_modules/qs/.editorconfig +46 -0
- gaia/eval/webapp/node_modules/qs/.eslintrc +38 -0
- gaia/eval/webapp/node_modules/qs/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/qs/.nycrc +13 -0
- gaia/eval/webapp/node_modules/qs/CHANGELOG.md +600 -0
- gaia/eval/webapp/node_modules/qs/LICENSE.md +29 -0
- gaia/eval/webapp/node_modules/qs/README.md +709 -0
- gaia/eval/webapp/node_modules/qs/dist/qs.js +90 -0
- gaia/eval/webapp/node_modules/qs/lib/formats.js +23 -0
- gaia/eval/webapp/node_modules/qs/lib/index.js +11 -0
- gaia/eval/webapp/node_modules/qs/lib/parse.js +296 -0
- gaia/eval/webapp/node_modules/qs/lib/stringify.js +351 -0
- gaia/eval/webapp/node_modules/qs/lib/utils.js +265 -0
- gaia/eval/webapp/node_modules/qs/package.json +91 -0
- gaia/eval/webapp/node_modules/qs/test/empty-keys-cases.js +267 -0
- gaia/eval/webapp/node_modules/qs/test/parse.js +1170 -0
- gaia/eval/webapp/node_modules/qs/test/stringify.js +1298 -0
- gaia/eval/webapp/node_modules/qs/test/utils.js +136 -0
- gaia/eval/webapp/node_modules/range-parser/HISTORY.md +56 -0
- gaia/eval/webapp/node_modules/range-parser/LICENSE +23 -0
- gaia/eval/webapp/node_modules/range-parser/README.md +84 -0
- gaia/eval/webapp/node_modules/range-parser/index.js +162 -0
- gaia/eval/webapp/node_modules/range-parser/package.json +44 -0
- gaia/eval/webapp/node_modules/raw-body/HISTORY.md +308 -0
- gaia/eval/webapp/node_modules/raw-body/LICENSE +22 -0
- gaia/eval/webapp/node_modules/raw-body/README.md +223 -0
- gaia/eval/webapp/node_modules/raw-body/SECURITY.md +24 -0
- gaia/eval/webapp/node_modules/raw-body/index.d.ts +87 -0
- gaia/eval/webapp/node_modules/raw-body/index.js +336 -0
- gaia/eval/webapp/node_modules/raw-body/package.json +49 -0
- gaia/eval/webapp/node_modules/safe-buffer/LICENSE +21 -0
- gaia/eval/webapp/node_modules/safe-buffer/README.md +584 -0
- gaia/eval/webapp/node_modules/safe-buffer/index.d.ts +187 -0
- gaia/eval/webapp/node_modules/safe-buffer/index.js +65 -0
- gaia/eval/webapp/node_modules/safe-buffer/package.json +51 -0
- gaia/eval/webapp/node_modules/safer-buffer/LICENSE +21 -0
- gaia/eval/webapp/node_modules/safer-buffer/Porting-Buffer.md +268 -0
- gaia/eval/webapp/node_modules/safer-buffer/Readme.md +156 -0
- gaia/eval/webapp/node_modules/safer-buffer/dangerous.js +58 -0
- gaia/eval/webapp/node_modules/safer-buffer/package.json +34 -0
- gaia/eval/webapp/node_modules/safer-buffer/safer.js +77 -0
- gaia/eval/webapp/node_modules/safer-buffer/tests.js +406 -0
- gaia/eval/webapp/node_modules/send/HISTORY.md +526 -0
- gaia/eval/webapp/node_modules/send/LICENSE +23 -0
- gaia/eval/webapp/node_modules/send/README.md +327 -0
- gaia/eval/webapp/node_modules/send/SECURITY.md +24 -0
- gaia/eval/webapp/node_modules/send/index.js +1142 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/HISTORY.md +14 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/LICENSE +22 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/README.md +128 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/index.js +60 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/package.json +40 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/index.js +162 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/license.md +21 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/package.json +38 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/readme.md +59 -0
- gaia/eval/webapp/node_modules/send/package.json +62 -0
- gaia/eval/webapp/node_modules/serve-static/HISTORY.md +487 -0
- gaia/eval/webapp/node_modules/serve-static/LICENSE +25 -0
- gaia/eval/webapp/node_modules/serve-static/README.md +257 -0
- gaia/eval/webapp/node_modules/serve-static/index.js +209 -0
- gaia/eval/webapp/node_modules/serve-static/package.json +42 -0
- gaia/eval/webapp/node_modules/setprototypeof/LICENSE +13 -0
- gaia/eval/webapp/node_modules/setprototypeof/README.md +31 -0
- gaia/eval/webapp/node_modules/setprototypeof/index.d.ts +2 -0
- gaia/eval/webapp/node_modules/setprototypeof/index.js +17 -0
- gaia/eval/webapp/node_modules/setprototypeof/package.json +38 -0
- gaia/eval/webapp/node_modules/setprototypeof/test/index.js +24 -0
- gaia/eval/webapp/node_modules/side-channel/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel/.eslintrc +12 -0
- gaia/eval/webapp/node_modules/side-channel/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel/CHANGELOG.md +110 -0
- gaia/eval/webapp/node_modules/side-channel/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel/README.md +61 -0
- gaia/eval/webapp/node_modules/side-channel/index.d.ts +14 -0
- gaia/eval/webapp/node_modules/side-channel/index.js +43 -0
- gaia/eval/webapp/node_modules/side-channel/package.json +85 -0
- gaia/eval/webapp/node_modules/side-channel/test/index.js +104 -0
- gaia/eval/webapp/node_modules/side-channel/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/side-channel-list/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel-list/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/side-channel-list/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel-list/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel-list/CHANGELOG.md +15 -0
- gaia/eval/webapp/node_modules/side-channel-list/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel-list/README.md +62 -0
- gaia/eval/webapp/node_modules/side-channel-list/index.d.ts +13 -0
- gaia/eval/webapp/node_modules/side-channel-list/index.js +113 -0
- gaia/eval/webapp/node_modules/side-channel-list/list.d.ts +14 -0
- gaia/eval/webapp/node_modules/side-channel-list/package.json +77 -0
- gaia/eval/webapp/node_modules/side-channel-list/test/index.js +104 -0
- gaia/eval/webapp/node_modules/side-channel-list/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/side-channel-map/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel-map/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/side-channel-map/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel-map/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel-map/CHANGELOG.md +22 -0
- gaia/eval/webapp/node_modules/side-channel-map/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel-map/README.md +62 -0
- gaia/eval/webapp/node_modules/side-channel-map/index.d.ts +15 -0
- gaia/eval/webapp/node_modules/side-channel-map/index.js +68 -0
- gaia/eval/webapp/node_modules/side-channel-map/package.json +80 -0
- gaia/eval/webapp/node_modules/side-channel-map/test/index.js +114 -0
- gaia/eval/webapp/node_modules/side-channel-map/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.eslintrc +12 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/CHANGELOG.md +28 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/README.md +62 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/index.d.ts +15 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/index.js +84 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/package.json +87 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/test/index.js +114 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/statuses/HISTORY.md +82 -0
- gaia/eval/webapp/node_modules/statuses/LICENSE +23 -0
- gaia/eval/webapp/node_modules/statuses/README.md +136 -0
- gaia/eval/webapp/node_modules/statuses/codes.json +65 -0
- gaia/eval/webapp/node_modules/statuses/index.js +146 -0
- gaia/eval/webapp/node_modules/statuses/package.json +49 -0
- gaia/eval/webapp/node_modules/toidentifier/HISTORY.md +9 -0
- gaia/eval/webapp/node_modules/toidentifier/LICENSE +21 -0
- gaia/eval/webapp/node_modules/toidentifier/README.md +61 -0
- gaia/eval/webapp/node_modules/toidentifier/index.js +32 -0
- gaia/eval/webapp/node_modules/toidentifier/package.json +38 -0
- gaia/eval/webapp/node_modules/type-is/HISTORY.md +259 -0
- gaia/eval/webapp/node_modules/type-is/LICENSE +23 -0
- gaia/eval/webapp/node_modules/type-is/README.md +170 -0
- gaia/eval/webapp/node_modules/type-is/index.js +266 -0
- gaia/eval/webapp/node_modules/type-is/package.json +45 -0
- gaia/eval/webapp/node_modules/unpipe/HISTORY.md +4 -0
- gaia/eval/webapp/node_modules/unpipe/LICENSE +22 -0
- gaia/eval/webapp/node_modules/unpipe/README.md +43 -0
- gaia/eval/webapp/node_modules/unpipe/index.js +69 -0
- gaia/eval/webapp/node_modules/unpipe/package.json +27 -0
- gaia/eval/webapp/node_modules/util/LICENSE +18 -0
- gaia/eval/webapp/node_modules/util/README.md +15 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/LICENSE +16 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/README.md +42 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits.js +7 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits_browser.js +23 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/package.json +29 -0
- gaia/eval/webapp/node_modules/util/package.json +35 -0
- gaia/eval/webapp/node_modules/util/support/isBuffer.js +3 -0
- gaia/eval/webapp/node_modules/util/support/isBufferBrowser.js +6 -0
- gaia/eval/webapp/node_modules/util/util.js +586 -0
- gaia/eval/webapp/node_modules/utils-merge/.npmignore +9 -0
- gaia/eval/webapp/node_modules/utils-merge/LICENSE +20 -0
- gaia/eval/webapp/node_modules/utils-merge/README.md +34 -0
- gaia/eval/webapp/node_modules/utils-merge/index.js +23 -0
- gaia/eval/webapp/node_modules/utils-merge/package.json +40 -0
- gaia/eval/webapp/node_modules/vary/HISTORY.md +39 -0
- gaia/eval/webapp/node_modules/vary/LICENSE +22 -0
- gaia/eval/webapp/node_modules/vary/README.md +101 -0
- gaia/eval/webapp/node_modules/vary/index.js +149 -0
- gaia/eval/webapp/node_modules/vary/package.json +43 -0
- gaia/eval/webapp/package-lock.json +875 -0
- gaia/eval/webapp/package.json +21 -0
- gaia/eval/webapp/public/app.js +3403 -0
- gaia/eval/webapp/public/index.html +88 -0
- gaia/eval/webapp/public/styles.css +3661 -0
- gaia/eval/webapp/server.js +416 -0
- gaia/eval/webapp/test-setup.js +73 -0
- gaia/llm/__init__.py +2 -0
- gaia/llm/lemonade_client.py +3083 -0
- gaia/llm/lemonade_manager.py +269 -0
- gaia/llm/llm_client.py +729 -0
- gaia/llm/vlm_client.py +307 -0
- gaia/logger.py +189 -0
- gaia/mcp/agent_mcp_server.py +245 -0
- gaia/mcp/blender_mcp_client.py +138 -0
- gaia/mcp/blender_mcp_server.py +648 -0
- gaia/mcp/context7_cache.py +332 -0
- gaia/mcp/external_services.py +518 -0
- gaia/mcp/mcp_bridge.py +550 -0
- gaia/mcp/servers/__init__.py +6 -0
- gaia/mcp/servers/docker_mcp.py +83 -0
- gaia/rag/__init__.py +10 -0
- gaia/rag/app.py +293 -0
- gaia/rag/demo.py +304 -0
- gaia/rag/pdf_utils.py +235 -0
- gaia/rag/sdk.py +2194 -0
- gaia/security.py +163 -0
- gaia/talk/app.py +289 -0
- gaia/talk/sdk.py +538 -0
- gaia/util.py +46 -0
- gaia/version.py +100 -0
|
@@ -0,0 +1,975 @@
|
|
|
1
|
+
# Copyright(C) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""
|
|
4
|
+
Chat Agent - Interactive chat with RAG and file search capabilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import time
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from watchdog.events import FileSystemEventHandler
|
|
15
|
+
from watchdog.observers import Observer
|
|
16
|
+
except ImportError:
|
|
17
|
+
# Create dummy base class when watchdog is not available
|
|
18
|
+
class FileSystemEventHandler:
|
|
19
|
+
"""Dummy base class when watchdog is not installed."""
|
|
20
|
+
|
|
21
|
+
Observer = None
|
|
22
|
+
|
|
23
|
+
from gaia.agents.base.agent import Agent
|
|
24
|
+
from gaia.agents.base.console import AgentConsole
|
|
25
|
+
from gaia.agents.chat.session import SessionManager
|
|
26
|
+
from gaia.agents.chat.tools import FileToolsMixin, RAGToolsMixin, ShellToolsMixin
|
|
27
|
+
from gaia.agents.tools import FileSearchToolsMixin # Shared file search tools
|
|
28
|
+
from gaia.logger import get_logger
|
|
29
|
+
from gaia.rag.sdk import RAGSDK, RAGConfig
|
|
30
|
+
from gaia.security import PathValidator
|
|
31
|
+
|
|
32
|
+
logger = get_logger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class ChatAgentConfig:
|
|
37
|
+
"""Configuration for ChatAgent."""
|
|
38
|
+
|
|
39
|
+
# LLM settings
|
|
40
|
+
use_claude: bool = False
|
|
41
|
+
use_chatgpt: bool = False
|
|
42
|
+
claude_model: str = "claude-sonnet-4-20250514"
|
|
43
|
+
base_url: str = "http://localhost:8000/api/v1"
|
|
44
|
+
model_id: Optional[str] = None # None = use default Qwen3-Coder-30B
|
|
45
|
+
|
|
46
|
+
# Execution settings
|
|
47
|
+
max_steps: int = 10
|
|
48
|
+
streaming: bool = False # Use --streaming to enable
|
|
49
|
+
|
|
50
|
+
# Debug/output settings
|
|
51
|
+
debug: bool = False
|
|
52
|
+
debug_prompts: bool = False # Backward compatibility
|
|
53
|
+
show_prompts: bool = False
|
|
54
|
+
show_stats: bool = False
|
|
55
|
+
silent_mode: bool = False
|
|
56
|
+
output_dir: Optional[str] = None
|
|
57
|
+
|
|
58
|
+
# RAG settings
|
|
59
|
+
rag_documents: List[str] = field(default_factory=list)
|
|
60
|
+
watch_directories: List[str] = field(default_factory=list)
|
|
61
|
+
chunk_size: int = 500
|
|
62
|
+
chunk_overlap: int = 100
|
|
63
|
+
max_chunks: int = 5
|
|
64
|
+
use_llm_chunking: bool = False # Use fast heuristic-based chunking by default
|
|
65
|
+
|
|
66
|
+
# Security
|
|
67
|
+
allowed_paths: Optional[List[str]] = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class FileChangeHandler(FileSystemEventHandler):
|
|
71
|
+
"""Handler for file system changes to trigger re-indexing and removal."""
|
|
72
|
+
|
|
73
|
+
def __init__(self, agent):
|
|
74
|
+
self.agent = agent
|
|
75
|
+
self.last_indexed = {}
|
|
76
|
+
self.debounce_time = 2.0 # seconds
|
|
77
|
+
self.telemetry = {
|
|
78
|
+
"files_added": 0,
|
|
79
|
+
"files_modified": 0,
|
|
80
|
+
"files_deleted": 0,
|
|
81
|
+
"files_moved": 0,
|
|
82
|
+
"total_events": 0,
|
|
83
|
+
"last_event_time": None,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
def on_created(self, event):
|
|
87
|
+
"""Handle file creation."""
|
|
88
|
+
if not event.is_directory and self._should_index(event.src_path):
|
|
89
|
+
self._schedule_reindex(event.src_path)
|
|
90
|
+
self._update_telemetry("files_added", event.src_path)
|
|
91
|
+
|
|
92
|
+
def on_modified(self, event):
|
|
93
|
+
"""Handle file modification."""
|
|
94
|
+
if not event.is_directory and self._should_index(event.src_path):
|
|
95
|
+
self._schedule_reindex(event.src_path)
|
|
96
|
+
self._update_telemetry("files_modified", event.src_path)
|
|
97
|
+
|
|
98
|
+
def on_deleted(self, event):
|
|
99
|
+
"""Handle file deletion."""
|
|
100
|
+
if not event.is_directory and self._should_index(event.src_path):
|
|
101
|
+
self._handle_deletion(event.src_path)
|
|
102
|
+
self._update_telemetry("files_deleted", event.src_path)
|
|
103
|
+
|
|
104
|
+
def on_moved(self, event):
|
|
105
|
+
"""Handle file move/rename."""
|
|
106
|
+
if not event.is_directory:
|
|
107
|
+
# Remove old path if it was indexed
|
|
108
|
+
if self._should_index(event.src_path):
|
|
109
|
+
self._handle_deletion(event.src_path)
|
|
110
|
+
# Add new path if it should be indexed
|
|
111
|
+
if self._should_index(event.dest_path):
|
|
112
|
+
self._schedule_reindex(event.dest_path)
|
|
113
|
+
self._update_telemetry(
|
|
114
|
+
"files_moved", f"{event.src_path} -> {event.dest_path}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def _should_index(self, file_path: str) -> bool:
|
|
118
|
+
"""Check if file should be indexed based on supported extensions."""
|
|
119
|
+
# List of supported document extensions for auto-indexing
|
|
120
|
+
supported_extensions = [
|
|
121
|
+
".pdf", # PDF documents
|
|
122
|
+
".txt",
|
|
123
|
+
".md",
|
|
124
|
+
".markdown", # Text documents
|
|
125
|
+
".csv", # CSV files
|
|
126
|
+
".json", # JSON files
|
|
127
|
+
".py",
|
|
128
|
+
".js",
|
|
129
|
+
".ts", # Code files (Python, JavaScript, TypeScript)
|
|
130
|
+
".java",
|
|
131
|
+
".cpp",
|
|
132
|
+
".c", # More code files
|
|
133
|
+
".html",
|
|
134
|
+
".css", # Web files
|
|
135
|
+
".yaml",
|
|
136
|
+
".yml", # Config files
|
|
137
|
+
".xml", # XML files
|
|
138
|
+
".rst", # ReStructuredText
|
|
139
|
+
".log", # Log files
|
|
140
|
+
]
|
|
141
|
+
file_lower = file_path.lower()
|
|
142
|
+
return any(file_lower.endswith(ext) for ext in supported_extensions)
|
|
143
|
+
|
|
144
|
+
def _schedule_reindex(self, file_path: str):
|
|
145
|
+
"""Schedule file for reindexing with debouncing and memory management."""
|
|
146
|
+
current_time = time.time()
|
|
147
|
+
last_time = self.last_indexed.get(file_path, 0)
|
|
148
|
+
|
|
149
|
+
if current_time - last_time > self.debounce_time:
|
|
150
|
+
self.last_indexed[file_path] = current_time
|
|
151
|
+
logger.info(f"Scheduling reindex for: {file_path}")
|
|
152
|
+
self.agent.reindex_file(file_path)
|
|
153
|
+
|
|
154
|
+
# Memory leak prevention: Limit cache size with LRU eviction
|
|
155
|
+
MAX_CACHE_SIZE = 1000
|
|
156
|
+
if len(self.last_indexed) > MAX_CACHE_SIZE:
|
|
157
|
+
# Remove oldest 10% of entries (LRU eviction)
|
|
158
|
+
num_to_remove = MAX_CACHE_SIZE // 10
|
|
159
|
+
sorted_items = sorted(self.last_indexed.items(), key=lambda x: x[1])
|
|
160
|
+
for path, _ in sorted_items[:num_to_remove]:
|
|
161
|
+
del self.last_indexed[path]
|
|
162
|
+
logger.debug(
|
|
163
|
+
f"Cleaned up {num_to_remove} old entries from debounce cache"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def _handle_deletion(self, file_path: str):
|
|
167
|
+
"""Handle file deletion by removing it from the index."""
|
|
168
|
+
try:
|
|
169
|
+
file_abs_path = str(Path(file_path).absolute())
|
|
170
|
+
if file_abs_path in self.agent.indexed_files:
|
|
171
|
+
logger.info(f"File deleted, removing from index: {file_path}")
|
|
172
|
+
if self.agent.rag.remove_document(file_abs_path):
|
|
173
|
+
self.agent.indexed_files.discard(file_abs_path)
|
|
174
|
+
logger.info(
|
|
175
|
+
f"Successfully removed deleted file from index: {file_path}"
|
|
176
|
+
)
|
|
177
|
+
else:
|
|
178
|
+
logger.warning(
|
|
179
|
+
f"Failed to remove deleted file from index: {file_path}"
|
|
180
|
+
)
|
|
181
|
+
# Clean up from last_indexed tracker if present
|
|
182
|
+
if file_path in self.last_indexed:
|
|
183
|
+
del self.last_indexed[file_path]
|
|
184
|
+
except Exception as e:
|
|
185
|
+
logger.error(f"Error handling file deletion {file_path}: {e}")
|
|
186
|
+
|
|
187
|
+
def _update_telemetry(
|
|
188
|
+
self, event_type: str, file_path: str
|
|
189
|
+
): # pylint: disable=unused-argument
|
|
190
|
+
"""Update telemetry statistics for file events."""
|
|
191
|
+
self.telemetry[event_type] += 1
|
|
192
|
+
self.telemetry["total_events"] += 1
|
|
193
|
+
self.telemetry["last_event_time"] = time.time()
|
|
194
|
+
|
|
195
|
+
# Log telemetry every 10 events or significant events
|
|
196
|
+
if self.telemetry["total_events"] % 10 == 0 or event_type in [
|
|
197
|
+
"files_deleted",
|
|
198
|
+
"files_moved",
|
|
199
|
+
]:
|
|
200
|
+
logger.info(
|
|
201
|
+
f"📊 File Watch Telemetry: "
|
|
202
|
+
f"Added: {self.telemetry['files_added']}, "
|
|
203
|
+
f"Modified: {self.telemetry['files_modified']}, "
|
|
204
|
+
f"Deleted: {self.telemetry['files_deleted']}, "
|
|
205
|
+
f"Moved: {self.telemetry['files_moved']}, "
|
|
206
|
+
f"Total: {self.telemetry['total_events']}"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def get_telemetry(self) -> Dict[str, Any]:
|
|
210
|
+
"""Get current telemetry statistics."""
|
|
211
|
+
return self.telemetry.copy()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class ChatAgent(
|
|
215
|
+
Agent, RAGToolsMixin, FileToolsMixin, ShellToolsMixin, FileSearchToolsMixin
|
|
216
|
+
):
|
|
217
|
+
"""
|
|
218
|
+
Chat Agent with RAG, file operations, and shell command capabilities.
|
|
219
|
+
|
|
220
|
+
This agent provides:
|
|
221
|
+
- Document Q&A using RAG
|
|
222
|
+
- File search and operations
|
|
223
|
+
- Shell command execution
|
|
224
|
+
- Auto-indexing when files change
|
|
225
|
+
- Interactive chat interface
|
|
226
|
+
- Session persistence with auto-save
|
|
227
|
+
- MCP server integration
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
# Define simple tools that can execute without requiring a multi-step plan
|
|
231
|
+
SIMPLE_TOOLS = [
|
|
232
|
+
"list_indexed_documents",
|
|
233
|
+
"rag_status",
|
|
234
|
+
"query_documents",
|
|
235
|
+
"query_specific_file",
|
|
236
|
+
"search_indexed_chunks", # RAG: Search indexed document chunks
|
|
237
|
+
"dump_document", # RAG: Export cached extracted text
|
|
238
|
+
"search_file_content", # Shared: Grep-like disk search
|
|
239
|
+
"search_file", # Shared: Find files by name
|
|
240
|
+
"search_directory", # Shared: Find directories by name
|
|
241
|
+
"read_file", # Shared: Read any file
|
|
242
|
+
"write_file", # Shared: Write any file
|
|
243
|
+
"index_directory", # RAG: Index directory
|
|
244
|
+
"run_shell_command", # Shell: Execute commands
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
def __init__(self, config: Optional[ChatAgentConfig] = None):
|
|
248
|
+
"""
|
|
249
|
+
Initialize Chat Agent.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
config: ChatAgentConfig object with all settings. If None, uses defaults.
|
|
253
|
+
"""
|
|
254
|
+
# Use provided config or create default
|
|
255
|
+
if config is None:
|
|
256
|
+
config = ChatAgentConfig()
|
|
257
|
+
|
|
258
|
+
# Initialize path validator
|
|
259
|
+
self.path_validator = PathValidator(config.allowed_paths)
|
|
260
|
+
|
|
261
|
+
# Now use config for all initialization
|
|
262
|
+
# Store RAG configuration from config
|
|
263
|
+
self.rag_documents = config.rag_documents
|
|
264
|
+
self.watch_directories = config.watch_directories
|
|
265
|
+
self.chunk_size = config.chunk_size
|
|
266
|
+
self.max_chunks = config.max_chunks
|
|
267
|
+
|
|
268
|
+
# Security: Configure allowed paths for file operations
|
|
269
|
+
# If None, allow current directory and subdirectories
|
|
270
|
+
if config.allowed_paths is None:
|
|
271
|
+
self.allowed_paths = [Path.cwd()]
|
|
272
|
+
else:
|
|
273
|
+
self.allowed_paths = [Path(p).resolve() for p in config.allowed_paths]
|
|
274
|
+
|
|
275
|
+
# Use Qwen3-Coder-30B by default for better JSON parsing (same as Jira agent)
|
|
276
|
+
effective_model_id = config.model_id or "Qwen3-Coder-30B-A3B-Instruct-GGUF"
|
|
277
|
+
|
|
278
|
+
# Debug logging for model selection
|
|
279
|
+
logger.debug(
|
|
280
|
+
f"Model selection: model_id={repr(config.model_id)}, effective={effective_model_id}"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Store model for display
|
|
284
|
+
self.model_display_name = effective_model_id
|
|
285
|
+
|
|
286
|
+
# Store max_chunks for adaptive retrieval
|
|
287
|
+
self.base_max_chunks = config.max_chunks
|
|
288
|
+
|
|
289
|
+
# Initialize RAG SDK (optional - will be None if dependencies not installed)
|
|
290
|
+
try:
|
|
291
|
+
rag_config = RAGConfig(
|
|
292
|
+
model=effective_model_id,
|
|
293
|
+
chunk_size=config.chunk_size,
|
|
294
|
+
chunk_overlap=config.chunk_overlap, # Configurable overlap for context preservation
|
|
295
|
+
max_chunks=config.max_chunks,
|
|
296
|
+
show_stats=config.show_stats,
|
|
297
|
+
use_local_llm=not (config.use_claude or config.use_chatgpt),
|
|
298
|
+
use_llm_chunking=config.use_llm_chunking, # Enable semantic chunking
|
|
299
|
+
base_url=config.base_url, # Pass base_url to RAG for VLM client
|
|
300
|
+
)
|
|
301
|
+
self.rag = RAGSDK(rag_config)
|
|
302
|
+
except ImportError as e:
|
|
303
|
+
# RAG dependencies not installed - this is fine, RAG features will be disabled
|
|
304
|
+
logger.debug(f"RAG dependencies not available: {e}")
|
|
305
|
+
self.rag = None
|
|
306
|
+
|
|
307
|
+
# File system monitoring
|
|
308
|
+
self.observers = []
|
|
309
|
+
self.file_handlers = [] # Track FileChangeHandler instances for telemetry
|
|
310
|
+
self.indexed_files = set()
|
|
311
|
+
|
|
312
|
+
# Session management
|
|
313
|
+
self.session_manager = SessionManager()
|
|
314
|
+
self.current_session = None
|
|
315
|
+
self.conversation_history: List[Dict[str, str]] = (
|
|
316
|
+
[]
|
|
317
|
+
) # Track conversation for persistence
|
|
318
|
+
|
|
319
|
+
# Call parent constructor
|
|
320
|
+
super().__init__(
|
|
321
|
+
use_claude=config.use_claude,
|
|
322
|
+
use_chatgpt=config.use_chatgpt,
|
|
323
|
+
claude_model=config.claude_model,
|
|
324
|
+
base_url=config.base_url,
|
|
325
|
+
model_id=effective_model_id, # Pass the effective model to parent
|
|
326
|
+
max_steps=config.max_steps,
|
|
327
|
+
debug_prompts=config.debug_prompts,
|
|
328
|
+
show_prompts=config.show_prompts,
|
|
329
|
+
output_dir=config.output_dir,
|
|
330
|
+
streaming=config.streaming,
|
|
331
|
+
show_stats=config.show_stats,
|
|
332
|
+
silent_mode=config.silent_mode,
|
|
333
|
+
debug=config.debug,
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# Index initial documents (only if RAG is available)
|
|
337
|
+
if self.rag_documents and self.rag:
|
|
338
|
+
self._index_documents(self.rag_documents)
|
|
339
|
+
elif self.rag_documents and not self.rag:
|
|
340
|
+
logger.warning(
|
|
341
|
+
"RAG dependencies not installed. Cannot index documents. "
|
|
342
|
+
'Install with: uv pip install -e ".[rag]"'
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# Start watching directories
|
|
346
|
+
if self.watch_directories:
|
|
347
|
+
self._start_watching()
|
|
348
|
+
|
|
349
|
+
def _post_process_tool_result(
|
|
350
|
+
self, tool_name: str, _tool_args: Dict[str, Any], tool_result: Dict[str, Any]
|
|
351
|
+
) -> None:
|
|
352
|
+
"""
|
|
353
|
+
Post-process tool results for Chat Agent.
|
|
354
|
+
|
|
355
|
+
Handles RAG-specific debug information display.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
tool_name: Name of the tool that was executed
|
|
359
|
+
_tool_args: Arguments that were passed to the tool (unused)
|
|
360
|
+
tool_result: Result returned by the tool
|
|
361
|
+
"""
|
|
362
|
+
# Handle RAG query debug information
|
|
363
|
+
if (
|
|
364
|
+
tool_name
|
|
365
|
+
in ["query_documents", "query_specific_file", "search_indexed_chunks"]
|
|
366
|
+
and isinstance(tool_result, dict)
|
|
367
|
+
and "debug_info" in tool_result
|
|
368
|
+
and self.debug
|
|
369
|
+
):
|
|
370
|
+
debug_info = tool_result.get("debug_info")
|
|
371
|
+
print("[DEBUG] RAG Query Debug Info:")
|
|
372
|
+
print(f" - Search keys: {debug_info.get('search_keys', [])}")
|
|
373
|
+
print(
|
|
374
|
+
f" - Total chunks found: {debug_info.get('total_chunks_before_dedup', 0)}"
|
|
375
|
+
)
|
|
376
|
+
print(
|
|
377
|
+
f" - After deduplication: {debug_info.get('total_chunks_after_dedup', 0)}"
|
|
378
|
+
)
|
|
379
|
+
print(
|
|
380
|
+
f" - Final chunks returned: {debug_info.get('final_chunks_returned', 0)}"
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
def _get_system_prompt(self) -> str:
|
|
384
|
+
"""Generate the system prompt for the Chat Agent."""
|
|
385
|
+
# Get list of indexed documents
|
|
386
|
+
indexed_docs_section = ""
|
|
387
|
+
if hasattr(self, "rag") and self.rag and self.rag.indexed_files:
|
|
388
|
+
doc_names = []
|
|
389
|
+
for file_path in self.rag.indexed_files:
|
|
390
|
+
doc_names.append(Path(file_path).name)
|
|
391
|
+
|
|
392
|
+
indexed_docs_section = f"""
|
|
393
|
+
**CURRENTLY INDEXED DOCUMENTS:**
|
|
394
|
+
You have {len(doc_names)} document(s) already indexed and ready to search:
|
|
395
|
+
{chr(10).join(f'- {name}' for name in sorted(doc_names))}
|
|
396
|
+
|
|
397
|
+
When the user asks a question about content, you can DIRECTLY search these documents using query_documents or query_specific_file.
|
|
398
|
+
You do NOT need to check what's indexed first - this list is always up-to-date.
|
|
399
|
+
"""
|
|
400
|
+
else:
|
|
401
|
+
indexed_docs_section = """
|
|
402
|
+
**CURRENTLY INDEXED DOCUMENTS:**
|
|
403
|
+
No documents are currently indexed.
|
|
404
|
+
|
|
405
|
+
**IMPORTANT: When no documents are indexed, act as a normal conversational AI assistant.**
|
|
406
|
+
- Answer general questions using your knowledge
|
|
407
|
+
- Have natural conversations with the user
|
|
408
|
+
- Do NOT try to search for documents unless the user explicitly asks to index/search files
|
|
409
|
+
- Do NOT use query_documents or query_specific_file when no documents are indexed
|
|
410
|
+
- Only use RAG tools when the user explicitly asks to index documents or search their files
|
|
411
|
+
"""
|
|
412
|
+
|
|
413
|
+
# Build the prompt with indexed documents section
|
|
414
|
+
base_prompt = """You are a helpful AI assistant that responds ONLY in valid JSON format.
|
|
415
|
+
|
|
416
|
+
**CRITICAL RULES:**
|
|
417
|
+
1. ALWAYS output valid JSON - every single response
|
|
418
|
+
2. Do NOT add text before or after the JSON
|
|
419
|
+
3. Do NOT use markdown code blocks
|
|
420
|
+
4. Your entire response must be parseable as JSON
|
|
421
|
+
"""
|
|
422
|
+
|
|
423
|
+
# Add indexed documents section
|
|
424
|
+
prompt = (
|
|
425
|
+
base_prompt
|
|
426
|
+
+ indexed_docs_section
|
|
427
|
+
+ """
|
|
428
|
+
|
|
429
|
+
**JSON RESPONSE FORMATS:**
|
|
430
|
+
|
|
431
|
+
Format 1 - Direct Answer (for general conversation):
|
|
432
|
+
{
|
|
433
|
+
"thought": "brief reasoning",
|
|
434
|
+
"goal": "what you're trying to achieve",
|
|
435
|
+
"answer": "your response text here"
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
Format 2 - Tool Call (to get data or perform actions):
|
|
439
|
+
{
|
|
440
|
+
"thought": "why you need this tool",
|
|
441
|
+
"goal": "what you're trying to achieve",
|
|
442
|
+
"tool": "tool_name",
|
|
443
|
+
"tool_args": {}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
**WHEN TO USE EACH FORMAT:**
|
|
447
|
+
|
|
448
|
+
Use Format 1 (answer) for:
|
|
449
|
+
- Greetings: {"answer": "Hello! How can I help?"}
|
|
450
|
+
- Thanks: {"answer": "You're welcome!"}
|
|
451
|
+
- **General knowledge questions**: {"answer": "Kalin is a name of Slavic origin meaning..."}
|
|
452
|
+
- **Conversation and chat**: {"answer": "That's interesting! Tell me more about..."}
|
|
453
|
+
- Out-of-scope: {"answer": "I don't have weather data..."}
|
|
454
|
+
- **FINAL ANSWERS after retrieving data**: {"answer": "According to the document, the vision is..."}
|
|
455
|
+
|
|
456
|
+
**IMPORTANT: If no documents are indexed, answer ALL questions using general knowledge!**
|
|
457
|
+
|
|
458
|
+
Use Format 2 (tool) ONLY when:
|
|
459
|
+
- User explicitly asks to search/index files OR documents are already indexed
|
|
460
|
+
- "what files are indexed?" → {"tool": "list_indexed_documents", "tool_args": {}}
|
|
461
|
+
- "search for X" → {"tool": "query_documents", "tool_args": {"query": "X"}}
|
|
462
|
+
- "what does doc say?" → {"tool": "query_specific_file", "tool_args": {...}}
|
|
463
|
+
- "find the oil and gas manual" → {"tool": "search_file", "tool_args": {"file_pattern": "oil and gas manual"}}
|
|
464
|
+
- "index my data folder" → {"tool": "search_directory", "tool_args": {"directory_name": "data"}}
|
|
465
|
+
- "index files in /path/to/dir" → {"tool": "index_directory", "tool_args": {"directory_path": "/path/to/dir"}}
|
|
466
|
+
|
|
467
|
+
**CRITICAL: NEVER make up or guess user data. Always use tools.**
|
|
468
|
+
|
|
469
|
+
**SMART DISCOVERY WORKFLOW:**
|
|
470
|
+
|
|
471
|
+
When user asks a domain-specific question (e.g., "what is the vision of the oil & gas regulator?"):
|
|
472
|
+
1. Check if relevant documents are indexed
|
|
473
|
+
2. If NO relevant documents found:
|
|
474
|
+
a. Extract key terms from question (e.g., "oil", "gas", "regulator")
|
|
475
|
+
b. Search for files using search_file with those terms
|
|
476
|
+
c. If files found, index them automatically
|
|
477
|
+
d. Provide status update: "Found and indexed X file(s)"
|
|
478
|
+
e. Then query to answer the question
|
|
479
|
+
3. If documents already indexed, query directly
|
|
480
|
+
|
|
481
|
+
Example Smart Discovery:
|
|
482
|
+
User: "what is the vision of the oil & gas regulator?"
|
|
483
|
+
You: {"tool": "list_indexed_documents", "tool_args": {}}
|
|
484
|
+
Result: {"documents": [], "count": 0}
|
|
485
|
+
You: {"tool": "search_file", "tool_args": {"file_pattern": "oil gas"}}
|
|
486
|
+
Result: {"files": ["/docs/Oil-Gas-Manual.pdf"], "count": 1}
|
|
487
|
+
You: {"tool": "index_document", "tool_args": {"file_path": "/docs/Oil-Gas-Manual.pdf"}}
|
|
488
|
+
Result: {"status": "success", "chunks": 150}
|
|
489
|
+
You: {"thought": "Document indexed, now searching for vision", "tool": "query_specific_file", "tool_args": {"file_path": "/docs/Oil-Gas-Manual.pdf", "query": "vision of the oil gas regulator"}}
|
|
490
|
+
Result: {"chunks": ["The vision is to be recognized..."], "scores": [0.92]}
|
|
491
|
+
You: {"answer": "According to the Oil & Gas Manual, the vision is to be recognized..."}
|
|
492
|
+
|
|
493
|
+
**CONTEXT INFERENCE RULE:**
|
|
494
|
+
|
|
495
|
+
When user asks a question without specifying which document:
|
|
496
|
+
1. Check the "CURRENTLY INDEXED DOCUMENTS" section above - you already know what's indexed!
|
|
497
|
+
2. If EXACTLY 1 document indexed → **IMMEDIATELY search it**: {"tool": "query_documents", "tool_args": {"query": "..."}}
|
|
498
|
+
3. If 0 documents → Use Smart Discovery workflow to find and index relevant files
|
|
499
|
+
4. If multiple documents → Search all with query_documents OR ask which specific one: {"answer": "Which document? You have: [list]"}
|
|
500
|
+
|
|
501
|
+
**AVAILABLE TOOLS:**
|
|
502
|
+
The complete list of available tools with their descriptions is provided below in the AVAILABLE TOOLS section.
|
|
503
|
+
Tools are grouped by category: RAG tools, File System tools, Shell tools, etc.
|
|
504
|
+
|
|
505
|
+
**FILE SEARCH AND AUTO-INDEX WORKFLOW:**
|
|
506
|
+
When user asks "find the X manual" or "find X document on my drive":
|
|
507
|
+
1. Use search_file (automatically searches all drives intelligently):
|
|
508
|
+
- Phase 1: Searches common locations (Documents, Downloads, Desktop) - FAST
|
|
509
|
+
- Phase 2: If not found, deep search entire drive(s) - THOROUGH
|
|
510
|
+
- Filters by document file types (.pdf, .docx, .txt, etc.)
|
|
511
|
+
2. Handle results:
|
|
512
|
+
- **If 1 file found**: Automatically index it
|
|
513
|
+
- **If multiple files found**: Display numbered list, ask user to select
|
|
514
|
+
- **If none found**: Inform user
|
|
515
|
+
3. After indexing, confirm and let user know they can ask questions
|
|
516
|
+
|
|
517
|
+
**IMPORTANT: Always show tool results with display_message!**
|
|
518
|
+
Tools like search_file return a 'display_message' field - ALWAYS show this to the user:
|
|
519
|
+
|
|
520
|
+
Example:
|
|
521
|
+
Tool result: {"display_message": "✓ Found 2 file(s) in current directory (gaia)", "file_list": [...]}
|
|
522
|
+
You must say: {"answer": "✓ Found 2 file(s) in current directory (gaia):\n1. Oil-Gas-Manual.pdf\n..."}
|
|
523
|
+
|
|
524
|
+
NOTE: Progress indicators (spinners) are shown automatically by the tool while searching.
|
|
525
|
+
You don't need to say "searching..." - the tool displays it live!
|
|
526
|
+
|
|
527
|
+
Example (Single file):
|
|
528
|
+
User: "Can you find the oil and gas manual on my drive?"
|
|
529
|
+
You: {"tool": "search_file", "tool_args": {"file_pattern": "oil gas"}}
|
|
530
|
+
Result: {"files": [...], "count": 1, "display_message": "🔍 Found 1 matching file(s)", "file_list": [{"number": 1, "name": "Oil-Gas-Manual.pdf", "directory": "C:/Users/user/Documents"}]}
|
|
531
|
+
You: {"answer": "🔍 Searching for 'oil gas'... Found 1 file:\n• Oil-Gas-Manual.pdf (Documents folder)\n\nIndexing now..."}
|
|
532
|
+
You: {"tool": "index_document", "tool_args": {"file_path": "C:/Users/user/Documents/Oil-Gas-Manual.pdf"}}
|
|
533
|
+
You: {"answer": "✓ Indexed Oil-Gas-Manual.pdf (150 chunks). You can now ask me questions about it!"}
|
|
534
|
+
|
|
535
|
+
Example (Multiple files):
|
|
536
|
+
User: "Find the manual on my drive"
|
|
537
|
+
You: {"answer": "🔍 Searching your drive for 'manual'..."}
|
|
538
|
+
You: {"tool": "search_file", "tool_args": {"file_pattern": "manual"}}
|
|
539
|
+
Result: {"count": 3, "file_list": [{"number": 1, "name": "Oil-Gas-Manual.pdf", "directory": "C:/Docs"}, {"number": 2, "name": "Safety-Manual.pdf", "directory": "C:/Downloads"}]}
|
|
540
|
+
You: {"answer": "Found 3 matching files:\n\n1. Oil-Gas-Manual.pdf (C:/Docs/)\n2. Safety-Manual.pdf (C:/Downloads/)\n3. Training-Manual.pdf (C:/Work/)\n\nWhich one would you like me to index? (enter the number)"}
|
|
541
|
+
User: "1"
|
|
542
|
+
You: {"tool": "index_document", "tool_args": {"file_path": "C:/Docs/Oil-Gas-Manual.pdf"}}
|
|
543
|
+
You: {"answer": "✓ Indexed Oil-Gas-Manual.pdf. You can now ask questions about it!"}
|
|
544
|
+
|
|
545
|
+
**DIRECTORY INDEXING WORKFLOW:**
|
|
546
|
+
When user asks to "index my data folder" or similar:
|
|
547
|
+
1. Use search_directory to find matching directories
|
|
548
|
+
2. Show user the matches and ask which one (if multiple)
|
|
549
|
+
3. Use index_directory on the chosen path
|
|
550
|
+
4. Report indexing results"""
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
return prompt
|
|
554
|
+
|
|
555
|
+
def _create_console(self):
|
|
556
|
+
"""Create console for chat agent."""
|
|
557
|
+
from gaia.agents.base.console import SilentConsole
|
|
558
|
+
|
|
559
|
+
if self.silent_mode:
|
|
560
|
+
# For chat agent, we ALWAYS want to show the final answer
|
|
561
|
+
# Even in silent mode, the user needs to see the response
|
|
562
|
+
return SilentConsole(silence_final_answer=False)
|
|
563
|
+
return AgentConsole()
|
|
564
|
+
|
|
565
|
+
def _generate_search_keys(self, query: str) -> List[str]:
|
|
566
|
+
"""
|
|
567
|
+
Generate search keys from query for better retrieval.
|
|
568
|
+
Extracts keywords and reformulates query for improved matching.
|
|
569
|
+
|
|
570
|
+
Args:
|
|
571
|
+
query: User query
|
|
572
|
+
|
|
573
|
+
Returns:
|
|
574
|
+
List of search keys/queries
|
|
575
|
+
"""
|
|
576
|
+
keys = [query] # Always include original query
|
|
577
|
+
|
|
578
|
+
# Extract potential keywords (simple approach)
|
|
579
|
+
# Remove common words and extract meaningful terms
|
|
580
|
+
stop_words = {
|
|
581
|
+
"what",
|
|
582
|
+
"how",
|
|
583
|
+
"when",
|
|
584
|
+
"where",
|
|
585
|
+
"who",
|
|
586
|
+
"why",
|
|
587
|
+
"is",
|
|
588
|
+
"are",
|
|
589
|
+
"was",
|
|
590
|
+
"were",
|
|
591
|
+
"the",
|
|
592
|
+
"a",
|
|
593
|
+
"an",
|
|
594
|
+
"and",
|
|
595
|
+
"or",
|
|
596
|
+
"but",
|
|
597
|
+
"in",
|
|
598
|
+
"on",
|
|
599
|
+
"at",
|
|
600
|
+
"to",
|
|
601
|
+
"for",
|
|
602
|
+
"of",
|
|
603
|
+
"with",
|
|
604
|
+
"by",
|
|
605
|
+
"from",
|
|
606
|
+
"about",
|
|
607
|
+
"can",
|
|
608
|
+
"could",
|
|
609
|
+
"would",
|
|
610
|
+
"should",
|
|
611
|
+
"do",
|
|
612
|
+
"does",
|
|
613
|
+
"did",
|
|
614
|
+
"tell",
|
|
615
|
+
"me",
|
|
616
|
+
"you",
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
words = query.lower().split()
|
|
620
|
+
keywords = [
|
|
621
|
+
w.strip("?,.:;!")
|
|
622
|
+
for w in words
|
|
623
|
+
if w.lower() not in stop_words and len(w) > 2
|
|
624
|
+
]
|
|
625
|
+
|
|
626
|
+
# Add keyword-based query (only if different from original)
|
|
627
|
+
if keywords:
|
|
628
|
+
keyword_query = " ".join(keywords)
|
|
629
|
+
if keyword_query != query: # Avoid duplicates
|
|
630
|
+
keys.append(keyword_query)
|
|
631
|
+
|
|
632
|
+
# Add question reformulations for common patterns
|
|
633
|
+
if query.lower().startswith("what is"):
|
|
634
|
+
topic = query[8:].strip("?").strip()
|
|
635
|
+
keys.append(f"{topic} definition")
|
|
636
|
+
keys.append(f"{topic} explanation")
|
|
637
|
+
elif query.lower().startswith("how to"):
|
|
638
|
+
topic = query[7:].strip("?").strip()
|
|
639
|
+
keys.append(f"{topic} steps")
|
|
640
|
+
keys.append(f"{topic} guide")
|
|
641
|
+
|
|
642
|
+
logger.debug(f"Generated search keys: {keys}")
|
|
643
|
+
return keys
|
|
644
|
+
|
|
645
|
+
def _is_path_allowed(self, path: str) -> bool:
|
|
646
|
+
"""
|
|
647
|
+
Check if a path is within allowed directories.
|
|
648
|
+
Uses real path resolution to prevent TOCTOU attacks.
|
|
649
|
+
|
|
650
|
+
Args:
|
|
651
|
+
path: Path to validate
|
|
652
|
+
|
|
653
|
+
Returns:
|
|
654
|
+
True if path is allowed, False otherwise
|
|
655
|
+
"""
|
|
656
|
+
try:
|
|
657
|
+
# Resolve path using os.path.realpath to follow symlinks
|
|
658
|
+
# This prevents TOCTOU attacks by resolving at check time
|
|
659
|
+
real_path = Path(os.path.realpath(path)).resolve()
|
|
660
|
+
|
|
661
|
+
# Check if real path is within any allowed directory
|
|
662
|
+
for allowed_path in self.allowed_paths:
|
|
663
|
+
try:
|
|
664
|
+
# is_relative_to requires Python 3.9+, use alternative for compatibility
|
|
665
|
+
real_path.relative_to(allowed_path)
|
|
666
|
+
return True
|
|
667
|
+
except ValueError:
|
|
668
|
+
continue
|
|
669
|
+
|
|
670
|
+
return False
|
|
671
|
+
except Exception as e:
|
|
672
|
+
logger.error(f"Error validating path {path}: {e}")
|
|
673
|
+
return False
|
|
674
|
+
|
|
675
|
+
def _validate_and_open_file(self, file_path: str, mode: str = "r"):
|
|
676
|
+
"""
|
|
677
|
+
Safely open a file with path validation using O_NOFOLLOW to prevent TOCTOU attacks.
|
|
678
|
+
|
|
679
|
+
This method prevents Time-of-Check-Time-of-Use vulnerabilities by:
|
|
680
|
+
1. Using O_NOFOLLOW flag to reject symlinks
|
|
681
|
+
2. Opening file with low-level os.open() before validation
|
|
682
|
+
3. Validating the opened file descriptor, not the path
|
|
683
|
+
|
|
684
|
+
Args:
|
|
685
|
+
file_path: Path to the file
|
|
686
|
+
mode: File open mode ('r', 'w', 'rb', 'wb', etc.)
|
|
687
|
+
|
|
688
|
+
Returns:
|
|
689
|
+
File handle if successful
|
|
690
|
+
|
|
691
|
+
Raises:
|
|
692
|
+
PermissionError: If path is not allowed or is a symlink
|
|
693
|
+
IOError: If file cannot be opened
|
|
694
|
+
"""
|
|
695
|
+
import stat
|
|
696
|
+
|
|
697
|
+
try:
|
|
698
|
+
# Determine open flags based on mode
|
|
699
|
+
if "r" in mode and "+" not in mode:
|
|
700
|
+
flags = os.O_RDONLY
|
|
701
|
+
elif "w" in mode:
|
|
702
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
|
703
|
+
elif "a" in mode:
|
|
704
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_APPEND
|
|
705
|
+
elif "+" in mode:
|
|
706
|
+
flags = os.O_RDWR
|
|
707
|
+
else:
|
|
708
|
+
flags = os.O_RDONLY
|
|
709
|
+
|
|
710
|
+
# CRITICAL: Add O_NOFOLLOW to reject symlinks
|
|
711
|
+
# This prevents TOCTOU attacks where symlinks are swapped
|
|
712
|
+
if hasattr(os, "O_NOFOLLOW"):
|
|
713
|
+
flags |= os.O_NOFOLLOW
|
|
714
|
+
|
|
715
|
+
# Open the file at low level (doesn't follow symlinks with O_NOFOLLOW)
|
|
716
|
+
try:
|
|
717
|
+
fd = os.open(file_path, flags)
|
|
718
|
+
except OSError as e:
|
|
719
|
+
if e.errno == 40: # ELOOP - too many symbolic links
|
|
720
|
+
raise PermissionError(f"Symlinks not allowed: {file_path}")
|
|
721
|
+
raise IOError(f"Cannot open file {file_path}: {e}")
|
|
722
|
+
|
|
723
|
+
# Get the real path of the opened file descriptor
|
|
724
|
+
# On Linux, we can use /proc/self/fd/
|
|
725
|
+
# On other systems, use fstat
|
|
726
|
+
try:
|
|
727
|
+
file_stat = os.fstat(fd)
|
|
728
|
+
|
|
729
|
+
# Verify it's a regular file, not a directory or special file
|
|
730
|
+
if not stat.S_ISREG(file_stat.st_mode):
|
|
731
|
+
os.close(fd)
|
|
732
|
+
raise PermissionError(f"Not a regular file: {file_path}")
|
|
733
|
+
|
|
734
|
+
# Get the real path (Linux-specific, but works on most Unix)
|
|
735
|
+
if os.path.exists(f"/proc/self/fd/{fd}"):
|
|
736
|
+
real_path = Path(os.readlink(f"/proc/self/fd/{fd}")).resolve()
|
|
737
|
+
else:
|
|
738
|
+
# Fallback for non-Linux systems
|
|
739
|
+
real_path = Path(file_path).resolve()
|
|
740
|
+
|
|
741
|
+
# Validate the real path is within allowed directories
|
|
742
|
+
path_allowed = False
|
|
743
|
+
for allowed_path in self.allowed_paths:
|
|
744
|
+
try:
|
|
745
|
+
real_path.relative_to(allowed_path)
|
|
746
|
+
path_allowed = True
|
|
747
|
+
break
|
|
748
|
+
except ValueError:
|
|
749
|
+
continue
|
|
750
|
+
|
|
751
|
+
if not path_allowed:
|
|
752
|
+
os.close(fd)
|
|
753
|
+
raise PermissionError(
|
|
754
|
+
f"Access denied to path: {real_path}\n"
|
|
755
|
+
f"Requested: {file_path}\n"
|
|
756
|
+
f"Resolved to path outside allowed directories"
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
# Convert file descriptor to Python file object
|
|
760
|
+
if "b" in mode:
|
|
761
|
+
return os.fdopen(fd, mode)
|
|
762
|
+
else:
|
|
763
|
+
return os.fdopen(fd, mode, encoding="utf-8")
|
|
764
|
+
|
|
765
|
+
except Exception:
|
|
766
|
+
os.close(fd)
|
|
767
|
+
raise
|
|
768
|
+
|
|
769
|
+
except PermissionError:
|
|
770
|
+
raise
|
|
771
|
+
except Exception as e:
|
|
772
|
+
raise IOError(f"Failed to securely open file {file_path}: {e}")
|
|
773
|
+
|
|
774
|
+
def _auto_save_session(self) -> None:
|
|
775
|
+
"""Auto-save current session (called after important operations)."""
|
|
776
|
+
try:
|
|
777
|
+
if self.current_session:
|
|
778
|
+
self.save_current_session()
|
|
779
|
+
if self.debug:
|
|
780
|
+
logger.debug(
|
|
781
|
+
f"Auto-saved session: {self.current_session.session_id}"
|
|
782
|
+
)
|
|
783
|
+
except Exception as e:
|
|
784
|
+
logger.warning(f"Auto-save failed: {e}")
|
|
785
|
+
|
|
786
|
+
def _register_tools(self) -> None:
|
|
787
|
+
"""Register chat agent tools from mixins."""
|
|
788
|
+
# Register tools from mixins
|
|
789
|
+
self.register_rag_tools()
|
|
790
|
+
self.register_file_tools()
|
|
791
|
+
self.register_shell_tools()
|
|
792
|
+
self.register_file_search_tools() # Shared file search tools
|
|
793
|
+
|
|
794
|
+
# NOTE: The actual tool definitions are in the mixin classes:
|
|
795
|
+
# - RAGToolsMixin (rag_tools.py): RAG and document indexing tools
|
|
796
|
+
# - FileToolsMixin (file_tools.py): Directory monitoring
|
|
797
|
+
# - ShellToolsMixin (shell_tools.py): Shell command execution
|
|
798
|
+
# - FileSearchToolsMixin (shared): File and directory search across drives
|
|
799
|
+
|
|
800
|
+
def _index_documents(self, documents: List[str]) -> None:
|
|
801
|
+
"""Index initial documents."""
|
|
802
|
+
for doc in documents:
|
|
803
|
+
try:
|
|
804
|
+
if os.path.exists(doc):
|
|
805
|
+
logger.info(f"Indexing document: {doc}")
|
|
806
|
+
result = self.rag.index_document(doc)
|
|
807
|
+
|
|
808
|
+
if result.get("success"):
|
|
809
|
+
self.indexed_files.add(doc)
|
|
810
|
+
logger.info(
|
|
811
|
+
f"Successfully indexed: {doc} ({result.get('num_chunks', 0)} chunks)"
|
|
812
|
+
)
|
|
813
|
+
else:
|
|
814
|
+
error = result.get("error", "Unknown error")
|
|
815
|
+
logger.error(f"Failed to index {doc}: {error}")
|
|
816
|
+
else:
|
|
817
|
+
logger.warning(f"Document not found: {doc}")
|
|
818
|
+
except Exception as e:
|
|
819
|
+
logger.error(f"Failed to index {doc}: {e}")
|
|
820
|
+
|
|
821
|
+
# Update system prompt after indexing to include the new documents
|
|
822
|
+
self._update_system_prompt()
|
|
823
|
+
|
|
824
|
+
def _update_system_prompt(self) -> None:
|
|
825
|
+
"""Update the system prompt with current indexed documents."""
|
|
826
|
+
# Regenerate the system prompt with updated document list
|
|
827
|
+
self.system_prompt = self._get_system_prompt()
|
|
828
|
+
|
|
829
|
+
# Add the tools description using the parent class method
|
|
830
|
+
tools_description = self._format_tools_for_prompt()
|
|
831
|
+
self.system_prompt += f"\n\n==== AVAILABLE TOOLS ====\n{tools_description}\n\n"
|
|
832
|
+
|
|
833
|
+
if self.rag:
|
|
834
|
+
logger.debug(
|
|
835
|
+
f"Updated system prompt with {len(self.rag.indexed_files)} indexed documents"
|
|
836
|
+
)
|
|
837
|
+
|
|
838
|
+
def _start_watching(self) -> None:
|
|
839
|
+
"""Start watching directories for changes."""
|
|
840
|
+
for directory in self.watch_directories:
|
|
841
|
+
self._watch_directory(directory)
|
|
842
|
+
|
|
843
|
+
def _watch_directory(self, directory: str) -> None:
|
|
844
|
+
"""Watch a directory for file changes."""
|
|
845
|
+
if Observer is None:
|
|
846
|
+
error_msg = (
|
|
847
|
+
"\n❌ Error: Missing required package 'watchdog'\n\n"
|
|
848
|
+
"File watching requires the watchdog package.\n"
|
|
849
|
+
"Please install the required dependencies:\n"
|
|
850
|
+
" pip install -e .[dev]\n\n"
|
|
851
|
+
"Or install watchdog directly:\n"
|
|
852
|
+
" pip install watchdog>=2.1.0\n"
|
|
853
|
+
)
|
|
854
|
+
logger.error(error_msg)
|
|
855
|
+
raise ImportError(error_msg)
|
|
856
|
+
|
|
857
|
+
try:
|
|
858
|
+
event_handler = FileChangeHandler(self)
|
|
859
|
+
observer = Observer()
|
|
860
|
+
observer.schedule(event_handler, directory, recursive=True)
|
|
861
|
+
observer.start()
|
|
862
|
+
self.observers.append(observer)
|
|
863
|
+
logger.info(f"Started watching: {directory}")
|
|
864
|
+
except Exception as e:
|
|
865
|
+
logger.error(f"Failed to watch {directory}: {e}")
|
|
866
|
+
|
|
867
|
+
def reindex_file(self, file_path: str) -> None:
|
|
868
|
+
"""Reindex a file that was modified or created."""
|
|
869
|
+
if not self.rag:
|
|
870
|
+
logger.warning(
|
|
871
|
+
f"Cannot reindex {file_path}: RAG dependencies not installed"
|
|
872
|
+
)
|
|
873
|
+
return
|
|
874
|
+
|
|
875
|
+
try:
|
|
876
|
+
logger.info(f"Reindexing: {file_path}")
|
|
877
|
+
# Use the new reindex_document method which removes old chunks first
|
|
878
|
+
result = self.rag.reindex_document(file_path)
|
|
879
|
+
if result.get("success"):
|
|
880
|
+
self.indexed_files.add(file_path)
|
|
881
|
+
logger.info(f"Successfully reindexed {file_path}")
|
|
882
|
+
else:
|
|
883
|
+
error = result.get("error", "Unknown error")
|
|
884
|
+
logger.error(f"Failed to reindex {file_path}: {error}")
|
|
885
|
+
except Exception as e:
|
|
886
|
+
logger.error(f"Failed to reindex {file_path}: {e}")
|
|
887
|
+
|
|
888
|
+
def stop_watching(self) -> None:
|
|
889
|
+
"""Stop all file system observers."""
|
|
890
|
+
for observer in self.observers:
|
|
891
|
+
observer.stop()
|
|
892
|
+
observer.join()
|
|
893
|
+
self.observers.clear()
|
|
894
|
+
|
|
895
|
+
def load_session(self, session_id: str) -> bool:
|
|
896
|
+
"""
|
|
897
|
+
Load a saved session.
|
|
898
|
+
|
|
899
|
+
Args:
|
|
900
|
+
session_id: Session ID to load
|
|
901
|
+
|
|
902
|
+
Returns:
|
|
903
|
+
True if successful
|
|
904
|
+
"""
|
|
905
|
+
try:
|
|
906
|
+
session = self.session_manager.load_session(session_id)
|
|
907
|
+
if not session:
|
|
908
|
+
logger.error(f"Session not found: {session_id}")
|
|
909
|
+
return False
|
|
910
|
+
|
|
911
|
+
self.current_session = session
|
|
912
|
+
|
|
913
|
+
# Restore indexed documents (only if RAG is available)
|
|
914
|
+
if self.rag:
|
|
915
|
+
for doc_path in session.indexed_documents:
|
|
916
|
+
if os.path.exists(doc_path):
|
|
917
|
+
try:
|
|
918
|
+
self.rag.index_document(doc_path)
|
|
919
|
+
self.indexed_files.add(doc_path)
|
|
920
|
+
except Exception as e:
|
|
921
|
+
logger.warning(f"Failed to reindex {doc_path}: {e}")
|
|
922
|
+
elif session.indexed_documents:
|
|
923
|
+
logger.warning(
|
|
924
|
+
f"Cannot restore {len(session.indexed_documents)} indexed documents: "
|
|
925
|
+
"RAG dependencies not installed"
|
|
926
|
+
)
|
|
927
|
+
|
|
928
|
+
# Restore watched directories
|
|
929
|
+
for dir_path in session.watched_directories:
|
|
930
|
+
if os.path.exists(dir_path) and dir_path not in self.watch_directories:
|
|
931
|
+
self.watch_directories.append(dir_path)
|
|
932
|
+
self._watch_directory(dir_path)
|
|
933
|
+
|
|
934
|
+
# Restore conversation history
|
|
935
|
+
self.conversation_history = list(session.chat_history)
|
|
936
|
+
|
|
937
|
+
logger.info(
|
|
938
|
+
f"Loaded session {session_id}: {len(session.indexed_documents)} docs, {len(session.chat_history)} messages"
|
|
939
|
+
)
|
|
940
|
+
return True
|
|
941
|
+
|
|
942
|
+
except Exception as e:
|
|
943
|
+
logger.error(f"Error loading session: {e}")
|
|
944
|
+
return False
|
|
945
|
+
|
|
946
|
+
def save_current_session(self) -> bool:
|
|
947
|
+
"""
|
|
948
|
+
Save the current session.
|
|
949
|
+
|
|
950
|
+
Returns:
|
|
951
|
+
True if successful
|
|
952
|
+
"""
|
|
953
|
+
try:
|
|
954
|
+
if not self.current_session:
|
|
955
|
+
# Create new session
|
|
956
|
+
self.current_session = self.session_manager.create_session()
|
|
957
|
+
|
|
958
|
+
# Update session data
|
|
959
|
+
self.current_session.indexed_documents = list(self.indexed_files)
|
|
960
|
+
self.current_session.watched_directories = list(self.watch_directories)
|
|
961
|
+
self.current_session.chat_history = list(self.conversation_history)
|
|
962
|
+
|
|
963
|
+
# Save
|
|
964
|
+
return self.session_manager.save_session(self.current_session)
|
|
965
|
+
|
|
966
|
+
except Exception as e:
|
|
967
|
+
logger.error(f"Error saving session: {e}")
|
|
968
|
+
return False
|
|
969
|
+
|
|
970
|
+
def __del__(self):
|
|
971
|
+
"""Cleanup when agent is destroyed."""
|
|
972
|
+
try:
|
|
973
|
+
self.stop_watching()
|
|
974
|
+
except Exception as e:
|
|
975
|
+
logger.error(f"Error stopping file watchers during cleanup: {e}")
|