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.
Files changed (800) hide show
  1. amd_gaia-0.14.1.dist-info/METADATA +768 -0
  2. amd_gaia-0.14.1.dist-info/RECORD +800 -0
  3. amd_gaia-0.14.1.dist-info/WHEEL +5 -0
  4. amd_gaia-0.14.1.dist-info/entry_points.txt +5 -0
  5. amd_gaia-0.14.1.dist-info/licenses/LICENSE.md +21 -0
  6. amd_gaia-0.14.1.dist-info/top_level.txt +1 -0
  7. gaia/__init__.py +2 -0
  8. gaia/agents/__init__.py +19 -0
  9. gaia/agents/base/__init__.py +9 -0
  10. gaia/agents/base/agent.py +2072 -0
  11. gaia/agents/base/api_agent.py +120 -0
  12. gaia/agents/base/console.py +1457 -0
  13. gaia/agents/base/mcp_agent.py +86 -0
  14. gaia/agents/base/tools.py +83 -0
  15. gaia/agents/blender/agent.py +556 -0
  16. gaia/agents/blender/agent_simple.py +135 -0
  17. gaia/agents/blender/app.py +211 -0
  18. gaia/agents/blender/app_simple.py +41 -0
  19. gaia/agents/blender/core/__init__.py +16 -0
  20. gaia/agents/blender/core/materials.py +506 -0
  21. gaia/agents/blender/core/objects.py +316 -0
  22. gaia/agents/blender/core/rendering.py +225 -0
  23. gaia/agents/blender/core/scene.py +220 -0
  24. gaia/agents/blender/core/view.py +146 -0
  25. gaia/agents/chat/__init__.py +9 -0
  26. gaia/agents/chat/agent.py +975 -0
  27. gaia/agents/chat/app.py +1058 -0
  28. gaia/agents/chat/session.py +508 -0
  29. gaia/agents/chat/tools/__init__.py +15 -0
  30. gaia/agents/chat/tools/file_tools.py +96 -0
  31. gaia/agents/chat/tools/rag_tools.py +1729 -0
  32. gaia/agents/chat/tools/shell_tools.py +436 -0
  33. gaia/agents/code/__init__.py +7 -0
  34. gaia/agents/code/agent.py +547 -0
  35. gaia/agents/code/app.py +266 -0
  36. gaia/agents/code/models.py +135 -0
  37. gaia/agents/code/orchestration/__init__.py +24 -0
  38. gaia/agents/code/orchestration/checklist_executor.py +1739 -0
  39. gaia/agents/code/orchestration/checklist_generator.py +709 -0
  40. gaia/agents/code/orchestration/factories/__init__.py +9 -0
  41. gaia/agents/code/orchestration/factories/base.py +63 -0
  42. gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -0
  43. gaia/agents/code/orchestration/factories/python_factory.py +106 -0
  44. gaia/agents/code/orchestration/orchestrator.py +610 -0
  45. gaia/agents/code/orchestration/project_analyzer.py +391 -0
  46. gaia/agents/code/orchestration/steps/__init__.py +67 -0
  47. gaia/agents/code/orchestration/steps/base.py +188 -0
  48. gaia/agents/code/orchestration/steps/error_handler.py +314 -0
  49. gaia/agents/code/orchestration/steps/nextjs.py +828 -0
  50. gaia/agents/code/orchestration/steps/python.py +307 -0
  51. gaia/agents/code/orchestration/template_catalog.py +463 -0
  52. gaia/agents/code/orchestration/workflows/__init__.py +14 -0
  53. gaia/agents/code/orchestration/workflows/base.py +80 -0
  54. gaia/agents/code/orchestration/workflows/nextjs.py +186 -0
  55. gaia/agents/code/orchestration/workflows/python.py +94 -0
  56. gaia/agents/code/prompts/__init__.py +11 -0
  57. gaia/agents/code/prompts/base_prompt.py +77 -0
  58. gaia/agents/code/prompts/code_patterns.py +1925 -0
  59. gaia/agents/code/prompts/nextjs_prompt.py +40 -0
  60. gaia/agents/code/prompts/python_prompt.py +109 -0
  61. gaia/agents/code/schema_inference.py +365 -0
  62. gaia/agents/code/system_prompt.py +41 -0
  63. gaia/agents/code/tools/__init__.py +42 -0
  64. gaia/agents/code/tools/cli_tools.py +1138 -0
  65. gaia/agents/code/tools/code_formatting.py +319 -0
  66. gaia/agents/code/tools/code_tools.py +769 -0
  67. gaia/agents/code/tools/error_fixing.py +1347 -0
  68. gaia/agents/code/tools/external_tools.py +180 -0
  69. gaia/agents/code/tools/file_io.py +845 -0
  70. gaia/agents/code/tools/prisma_tools.py +190 -0
  71. gaia/agents/code/tools/project_management.py +1016 -0
  72. gaia/agents/code/tools/testing.py +321 -0
  73. gaia/agents/code/tools/typescript_tools.py +122 -0
  74. gaia/agents/code/tools/validation_parsing.py +461 -0
  75. gaia/agents/code/tools/validation_tools.py +803 -0
  76. gaia/agents/code/tools/web_dev_tools.py +1744 -0
  77. gaia/agents/code/validators/__init__.py +16 -0
  78. gaia/agents/code/validators/antipattern_checker.py +241 -0
  79. gaia/agents/code/validators/ast_analyzer.py +197 -0
  80. gaia/agents/code/validators/requirements_validator.py +145 -0
  81. gaia/agents/code/validators/syntax_validator.py +171 -0
  82. gaia/agents/docker/__init__.py +7 -0
  83. gaia/agents/docker/agent.py +642 -0
  84. gaia/agents/jira/__init__.py +11 -0
  85. gaia/agents/jira/agent.py +894 -0
  86. gaia/agents/jira/jql_templates.py +299 -0
  87. gaia/agents/routing/__init__.py +7 -0
  88. gaia/agents/routing/agent.py +512 -0
  89. gaia/agents/routing/system_prompt.py +75 -0
  90. gaia/api/__init__.py +23 -0
  91. gaia/api/agent_registry.py +238 -0
  92. gaia/api/app.py +305 -0
  93. gaia/api/openai_server.py +575 -0
  94. gaia/api/schemas.py +186 -0
  95. gaia/api/sse_handler.py +370 -0
  96. gaia/apps/__init__.py +4 -0
  97. gaia/apps/llm/__init__.py +6 -0
  98. gaia/apps/llm/app.py +169 -0
  99. gaia/apps/summarize/app.py +633 -0
  100. gaia/apps/summarize/html_viewer.py +133 -0
  101. gaia/apps/summarize/pdf_formatter.py +284 -0
  102. gaia/audio/__init__.py +2 -0
  103. gaia/audio/audio_client.py +439 -0
  104. gaia/audio/audio_recorder.py +269 -0
  105. gaia/audio/kokoro_tts.py +599 -0
  106. gaia/audio/whisper_asr.py +432 -0
  107. gaia/chat/__init__.py +16 -0
  108. gaia/chat/app.py +430 -0
  109. gaia/chat/prompts.py +522 -0
  110. gaia/chat/sdk.py +1200 -0
  111. gaia/cli.py +5621 -0
  112. gaia/eval/batch_experiment.py +2332 -0
  113. gaia/eval/claude.py +542 -0
  114. gaia/eval/config.py +37 -0
  115. gaia/eval/email_generator.py +512 -0
  116. gaia/eval/eval.py +3179 -0
  117. gaia/eval/groundtruth.py +1130 -0
  118. gaia/eval/transcript_generator.py +582 -0
  119. gaia/eval/webapp/README.md +168 -0
  120. gaia/eval/webapp/node_modules/.bin/mime +16 -0
  121. gaia/eval/webapp/node_modules/.bin/mime.cmd +17 -0
  122. gaia/eval/webapp/node_modules/.bin/mime.ps1 +28 -0
  123. gaia/eval/webapp/node_modules/.package-lock.json +865 -0
  124. gaia/eval/webapp/node_modules/accepts/HISTORY.md +243 -0
  125. gaia/eval/webapp/node_modules/accepts/LICENSE +23 -0
  126. gaia/eval/webapp/node_modules/accepts/README.md +140 -0
  127. gaia/eval/webapp/node_modules/accepts/index.js +238 -0
  128. gaia/eval/webapp/node_modules/accepts/package.json +47 -0
  129. gaia/eval/webapp/node_modules/array-flatten/LICENSE +21 -0
  130. gaia/eval/webapp/node_modules/array-flatten/README.md +43 -0
  131. gaia/eval/webapp/node_modules/array-flatten/array-flatten.js +64 -0
  132. gaia/eval/webapp/node_modules/array-flatten/package.json +39 -0
  133. gaia/eval/webapp/node_modules/body-parser/HISTORY.md +672 -0
  134. gaia/eval/webapp/node_modules/body-parser/LICENSE +23 -0
  135. gaia/eval/webapp/node_modules/body-parser/README.md +476 -0
  136. gaia/eval/webapp/node_modules/body-parser/SECURITY.md +25 -0
  137. gaia/eval/webapp/node_modules/body-parser/index.js +156 -0
  138. gaia/eval/webapp/node_modules/body-parser/lib/read.js +205 -0
  139. gaia/eval/webapp/node_modules/body-parser/lib/types/json.js +247 -0
  140. gaia/eval/webapp/node_modules/body-parser/lib/types/raw.js +101 -0
  141. gaia/eval/webapp/node_modules/body-parser/lib/types/text.js +121 -0
  142. gaia/eval/webapp/node_modules/body-parser/lib/types/urlencoded.js +307 -0
  143. gaia/eval/webapp/node_modules/body-parser/package.json +56 -0
  144. gaia/eval/webapp/node_modules/bytes/History.md +97 -0
  145. gaia/eval/webapp/node_modules/bytes/LICENSE +23 -0
  146. gaia/eval/webapp/node_modules/bytes/Readme.md +152 -0
  147. gaia/eval/webapp/node_modules/bytes/index.js +170 -0
  148. gaia/eval/webapp/node_modules/bytes/package.json +42 -0
  149. gaia/eval/webapp/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
  150. gaia/eval/webapp/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
  151. gaia/eval/webapp/node_modules/call-bind-apply-helpers/.nycrc +9 -0
  152. gaia/eval/webapp/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
  153. gaia/eval/webapp/node_modules/call-bind-apply-helpers/LICENSE +21 -0
  154. gaia/eval/webapp/node_modules/call-bind-apply-helpers/README.md +62 -0
  155. gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
  156. gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
  157. gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
  158. gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
  159. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
  160. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
  161. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
  162. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
  163. gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
  164. gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.js +15 -0
  165. gaia/eval/webapp/node_modules/call-bind-apply-helpers/package.json +85 -0
  166. gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
  167. gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
  168. gaia/eval/webapp/node_modules/call-bind-apply-helpers/test/index.js +63 -0
  169. gaia/eval/webapp/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
  170. gaia/eval/webapp/node_modules/call-bound/.eslintrc +13 -0
  171. gaia/eval/webapp/node_modules/call-bound/.github/FUNDING.yml +12 -0
  172. gaia/eval/webapp/node_modules/call-bound/.nycrc +9 -0
  173. gaia/eval/webapp/node_modules/call-bound/CHANGELOG.md +42 -0
  174. gaia/eval/webapp/node_modules/call-bound/LICENSE +21 -0
  175. gaia/eval/webapp/node_modules/call-bound/README.md +53 -0
  176. gaia/eval/webapp/node_modules/call-bound/index.d.ts +94 -0
  177. gaia/eval/webapp/node_modules/call-bound/index.js +19 -0
  178. gaia/eval/webapp/node_modules/call-bound/package.json +99 -0
  179. gaia/eval/webapp/node_modules/call-bound/test/index.js +61 -0
  180. gaia/eval/webapp/node_modules/call-bound/tsconfig.json +10 -0
  181. gaia/eval/webapp/node_modules/content-disposition/HISTORY.md +60 -0
  182. gaia/eval/webapp/node_modules/content-disposition/LICENSE +22 -0
  183. gaia/eval/webapp/node_modules/content-disposition/README.md +142 -0
  184. gaia/eval/webapp/node_modules/content-disposition/index.js +458 -0
  185. gaia/eval/webapp/node_modules/content-disposition/package.json +44 -0
  186. gaia/eval/webapp/node_modules/content-type/HISTORY.md +29 -0
  187. gaia/eval/webapp/node_modules/content-type/LICENSE +22 -0
  188. gaia/eval/webapp/node_modules/content-type/README.md +94 -0
  189. gaia/eval/webapp/node_modules/content-type/index.js +225 -0
  190. gaia/eval/webapp/node_modules/content-type/package.json +42 -0
  191. gaia/eval/webapp/node_modules/cookie/LICENSE +24 -0
  192. gaia/eval/webapp/node_modules/cookie/README.md +317 -0
  193. gaia/eval/webapp/node_modules/cookie/SECURITY.md +25 -0
  194. gaia/eval/webapp/node_modules/cookie/index.js +334 -0
  195. gaia/eval/webapp/node_modules/cookie/package.json +44 -0
  196. gaia/eval/webapp/node_modules/cookie-signature/.npmignore +4 -0
  197. gaia/eval/webapp/node_modules/cookie-signature/History.md +38 -0
  198. gaia/eval/webapp/node_modules/cookie-signature/Readme.md +42 -0
  199. gaia/eval/webapp/node_modules/cookie-signature/index.js +51 -0
  200. gaia/eval/webapp/node_modules/cookie-signature/package.json +18 -0
  201. gaia/eval/webapp/node_modules/debug/.coveralls.yml +1 -0
  202. gaia/eval/webapp/node_modules/debug/.eslintrc +11 -0
  203. gaia/eval/webapp/node_modules/debug/.npmignore +9 -0
  204. gaia/eval/webapp/node_modules/debug/.travis.yml +14 -0
  205. gaia/eval/webapp/node_modules/debug/CHANGELOG.md +362 -0
  206. gaia/eval/webapp/node_modules/debug/LICENSE +19 -0
  207. gaia/eval/webapp/node_modules/debug/Makefile +50 -0
  208. gaia/eval/webapp/node_modules/debug/README.md +312 -0
  209. gaia/eval/webapp/node_modules/debug/component.json +19 -0
  210. gaia/eval/webapp/node_modules/debug/karma.conf.js +70 -0
  211. gaia/eval/webapp/node_modules/debug/node.js +1 -0
  212. gaia/eval/webapp/node_modules/debug/package.json +49 -0
  213. gaia/eval/webapp/node_modules/debug/src/browser.js +185 -0
  214. gaia/eval/webapp/node_modules/debug/src/debug.js +202 -0
  215. gaia/eval/webapp/node_modules/debug/src/index.js +10 -0
  216. gaia/eval/webapp/node_modules/debug/src/inspector-log.js +15 -0
  217. gaia/eval/webapp/node_modules/debug/src/node.js +248 -0
  218. gaia/eval/webapp/node_modules/depd/History.md +103 -0
  219. gaia/eval/webapp/node_modules/depd/LICENSE +22 -0
  220. gaia/eval/webapp/node_modules/depd/Readme.md +280 -0
  221. gaia/eval/webapp/node_modules/depd/index.js +538 -0
  222. gaia/eval/webapp/node_modules/depd/lib/browser/index.js +77 -0
  223. gaia/eval/webapp/node_modules/depd/package.json +45 -0
  224. gaia/eval/webapp/node_modules/destroy/LICENSE +23 -0
  225. gaia/eval/webapp/node_modules/destroy/README.md +63 -0
  226. gaia/eval/webapp/node_modules/destroy/index.js +209 -0
  227. gaia/eval/webapp/node_modules/destroy/package.json +48 -0
  228. gaia/eval/webapp/node_modules/dunder-proto/.eslintrc +5 -0
  229. gaia/eval/webapp/node_modules/dunder-proto/.github/FUNDING.yml +12 -0
  230. gaia/eval/webapp/node_modules/dunder-proto/.nycrc +13 -0
  231. gaia/eval/webapp/node_modules/dunder-proto/CHANGELOG.md +24 -0
  232. gaia/eval/webapp/node_modules/dunder-proto/LICENSE +21 -0
  233. gaia/eval/webapp/node_modules/dunder-proto/README.md +54 -0
  234. gaia/eval/webapp/node_modules/dunder-proto/get.d.ts +5 -0
  235. gaia/eval/webapp/node_modules/dunder-proto/get.js +30 -0
  236. gaia/eval/webapp/node_modules/dunder-proto/package.json +76 -0
  237. gaia/eval/webapp/node_modules/dunder-proto/set.d.ts +5 -0
  238. gaia/eval/webapp/node_modules/dunder-proto/set.js +35 -0
  239. gaia/eval/webapp/node_modules/dunder-proto/test/get.js +34 -0
  240. gaia/eval/webapp/node_modules/dunder-proto/test/index.js +4 -0
  241. gaia/eval/webapp/node_modules/dunder-proto/test/set.js +50 -0
  242. gaia/eval/webapp/node_modules/dunder-proto/tsconfig.json +9 -0
  243. gaia/eval/webapp/node_modules/ee-first/LICENSE +22 -0
  244. gaia/eval/webapp/node_modules/ee-first/README.md +80 -0
  245. gaia/eval/webapp/node_modules/ee-first/index.js +95 -0
  246. gaia/eval/webapp/node_modules/ee-first/package.json +29 -0
  247. gaia/eval/webapp/node_modules/encodeurl/LICENSE +22 -0
  248. gaia/eval/webapp/node_modules/encodeurl/README.md +109 -0
  249. gaia/eval/webapp/node_modules/encodeurl/index.js +60 -0
  250. gaia/eval/webapp/node_modules/encodeurl/package.json +40 -0
  251. gaia/eval/webapp/node_modules/es-define-property/.eslintrc +13 -0
  252. gaia/eval/webapp/node_modules/es-define-property/.github/FUNDING.yml +12 -0
  253. gaia/eval/webapp/node_modules/es-define-property/.nycrc +9 -0
  254. gaia/eval/webapp/node_modules/es-define-property/CHANGELOG.md +29 -0
  255. gaia/eval/webapp/node_modules/es-define-property/LICENSE +21 -0
  256. gaia/eval/webapp/node_modules/es-define-property/README.md +49 -0
  257. gaia/eval/webapp/node_modules/es-define-property/index.d.ts +3 -0
  258. gaia/eval/webapp/node_modules/es-define-property/index.js +14 -0
  259. gaia/eval/webapp/node_modules/es-define-property/package.json +81 -0
  260. gaia/eval/webapp/node_modules/es-define-property/test/index.js +56 -0
  261. gaia/eval/webapp/node_modules/es-define-property/tsconfig.json +10 -0
  262. gaia/eval/webapp/node_modules/es-errors/.eslintrc +5 -0
  263. gaia/eval/webapp/node_modules/es-errors/.github/FUNDING.yml +12 -0
  264. gaia/eval/webapp/node_modules/es-errors/CHANGELOG.md +40 -0
  265. gaia/eval/webapp/node_modules/es-errors/LICENSE +21 -0
  266. gaia/eval/webapp/node_modules/es-errors/README.md +55 -0
  267. gaia/eval/webapp/node_modules/es-errors/eval.d.ts +3 -0
  268. gaia/eval/webapp/node_modules/es-errors/eval.js +4 -0
  269. gaia/eval/webapp/node_modules/es-errors/index.d.ts +3 -0
  270. gaia/eval/webapp/node_modules/es-errors/index.js +4 -0
  271. gaia/eval/webapp/node_modules/es-errors/package.json +80 -0
  272. gaia/eval/webapp/node_modules/es-errors/range.d.ts +3 -0
  273. gaia/eval/webapp/node_modules/es-errors/range.js +4 -0
  274. gaia/eval/webapp/node_modules/es-errors/ref.d.ts +3 -0
  275. gaia/eval/webapp/node_modules/es-errors/ref.js +4 -0
  276. gaia/eval/webapp/node_modules/es-errors/syntax.d.ts +3 -0
  277. gaia/eval/webapp/node_modules/es-errors/syntax.js +4 -0
  278. gaia/eval/webapp/node_modules/es-errors/test/index.js +19 -0
  279. gaia/eval/webapp/node_modules/es-errors/tsconfig.json +49 -0
  280. gaia/eval/webapp/node_modules/es-errors/type.d.ts +3 -0
  281. gaia/eval/webapp/node_modules/es-errors/type.js +4 -0
  282. gaia/eval/webapp/node_modules/es-errors/uri.d.ts +3 -0
  283. gaia/eval/webapp/node_modules/es-errors/uri.js +4 -0
  284. gaia/eval/webapp/node_modules/es-object-atoms/.eslintrc +16 -0
  285. gaia/eval/webapp/node_modules/es-object-atoms/.github/FUNDING.yml +12 -0
  286. gaia/eval/webapp/node_modules/es-object-atoms/CHANGELOG.md +37 -0
  287. gaia/eval/webapp/node_modules/es-object-atoms/LICENSE +21 -0
  288. gaia/eval/webapp/node_modules/es-object-atoms/README.md +63 -0
  289. gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
  290. gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
  291. gaia/eval/webapp/node_modules/es-object-atoms/ToObject.d.ts +7 -0
  292. gaia/eval/webapp/node_modules/es-object-atoms/ToObject.js +10 -0
  293. gaia/eval/webapp/node_modules/es-object-atoms/index.d.ts +3 -0
  294. gaia/eval/webapp/node_modules/es-object-atoms/index.js +4 -0
  295. gaia/eval/webapp/node_modules/es-object-atoms/isObject.d.ts +3 -0
  296. gaia/eval/webapp/node_modules/es-object-atoms/isObject.js +6 -0
  297. gaia/eval/webapp/node_modules/es-object-atoms/package.json +80 -0
  298. gaia/eval/webapp/node_modules/es-object-atoms/test/index.js +38 -0
  299. gaia/eval/webapp/node_modules/es-object-atoms/tsconfig.json +6 -0
  300. gaia/eval/webapp/node_modules/escape-html/LICENSE +24 -0
  301. gaia/eval/webapp/node_modules/escape-html/Readme.md +43 -0
  302. gaia/eval/webapp/node_modules/escape-html/index.js +78 -0
  303. gaia/eval/webapp/node_modules/escape-html/package.json +24 -0
  304. gaia/eval/webapp/node_modules/etag/HISTORY.md +83 -0
  305. gaia/eval/webapp/node_modules/etag/LICENSE +22 -0
  306. gaia/eval/webapp/node_modules/etag/README.md +159 -0
  307. gaia/eval/webapp/node_modules/etag/index.js +131 -0
  308. gaia/eval/webapp/node_modules/etag/package.json +47 -0
  309. gaia/eval/webapp/node_modules/express/History.md +3656 -0
  310. gaia/eval/webapp/node_modules/express/LICENSE +24 -0
  311. gaia/eval/webapp/node_modules/express/Readme.md +260 -0
  312. gaia/eval/webapp/node_modules/express/index.js +11 -0
  313. gaia/eval/webapp/node_modules/express/lib/application.js +661 -0
  314. gaia/eval/webapp/node_modules/express/lib/express.js +116 -0
  315. gaia/eval/webapp/node_modules/express/lib/middleware/init.js +43 -0
  316. gaia/eval/webapp/node_modules/express/lib/middleware/query.js +47 -0
  317. gaia/eval/webapp/node_modules/express/lib/request.js +525 -0
  318. gaia/eval/webapp/node_modules/express/lib/response.js +1179 -0
  319. gaia/eval/webapp/node_modules/express/lib/router/index.js +673 -0
  320. gaia/eval/webapp/node_modules/express/lib/router/layer.js +181 -0
  321. gaia/eval/webapp/node_modules/express/lib/router/route.js +230 -0
  322. gaia/eval/webapp/node_modules/express/lib/utils.js +303 -0
  323. gaia/eval/webapp/node_modules/express/lib/view.js +182 -0
  324. gaia/eval/webapp/node_modules/express/package.json +102 -0
  325. gaia/eval/webapp/node_modules/finalhandler/HISTORY.md +210 -0
  326. gaia/eval/webapp/node_modules/finalhandler/LICENSE +22 -0
  327. gaia/eval/webapp/node_modules/finalhandler/README.md +147 -0
  328. gaia/eval/webapp/node_modules/finalhandler/SECURITY.md +25 -0
  329. gaia/eval/webapp/node_modules/finalhandler/index.js +341 -0
  330. gaia/eval/webapp/node_modules/finalhandler/package.json +47 -0
  331. gaia/eval/webapp/node_modules/forwarded/HISTORY.md +21 -0
  332. gaia/eval/webapp/node_modules/forwarded/LICENSE +22 -0
  333. gaia/eval/webapp/node_modules/forwarded/README.md +57 -0
  334. gaia/eval/webapp/node_modules/forwarded/index.js +90 -0
  335. gaia/eval/webapp/node_modules/forwarded/package.json +45 -0
  336. gaia/eval/webapp/node_modules/fresh/HISTORY.md +70 -0
  337. gaia/eval/webapp/node_modules/fresh/LICENSE +23 -0
  338. gaia/eval/webapp/node_modules/fresh/README.md +119 -0
  339. gaia/eval/webapp/node_modules/fresh/index.js +137 -0
  340. gaia/eval/webapp/node_modules/fresh/package.json +46 -0
  341. gaia/eval/webapp/node_modules/fs/README.md +9 -0
  342. gaia/eval/webapp/node_modules/fs/package.json +20 -0
  343. gaia/eval/webapp/node_modules/function-bind/.eslintrc +21 -0
  344. gaia/eval/webapp/node_modules/function-bind/.github/FUNDING.yml +12 -0
  345. gaia/eval/webapp/node_modules/function-bind/.github/SECURITY.md +3 -0
  346. gaia/eval/webapp/node_modules/function-bind/.nycrc +13 -0
  347. gaia/eval/webapp/node_modules/function-bind/CHANGELOG.md +136 -0
  348. gaia/eval/webapp/node_modules/function-bind/LICENSE +20 -0
  349. gaia/eval/webapp/node_modules/function-bind/README.md +46 -0
  350. gaia/eval/webapp/node_modules/function-bind/implementation.js +84 -0
  351. gaia/eval/webapp/node_modules/function-bind/index.js +5 -0
  352. gaia/eval/webapp/node_modules/function-bind/package.json +87 -0
  353. gaia/eval/webapp/node_modules/function-bind/test/.eslintrc +9 -0
  354. gaia/eval/webapp/node_modules/function-bind/test/index.js +252 -0
  355. gaia/eval/webapp/node_modules/get-intrinsic/.eslintrc +42 -0
  356. gaia/eval/webapp/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
  357. gaia/eval/webapp/node_modules/get-intrinsic/.nycrc +9 -0
  358. gaia/eval/webapp/node_modules/get-intrinsic/CHANGELOG.md +186 -0
  359. gaia/eval/webapp/node_modules/get-intrinsic/LICENSE +21 -0
  360. gaia/eval/webapp/node_modules/get-intrinsic/README.md +71 -0
  361. gaia/eval/webapp/node_modules/get-intrinsic/index.js +378 -0
  362. gaia/eval/webapp/node_modules/get-intrinsic/package.json +97 -0
  363. gaia/eval/webapp/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
  364. gaia/eval/webapp/node_modules/get-proto/.eslintrc +10 -0
  365. gaia/eval/webapp/node_modules/get-proto/.github/FUNDING.yml +12 -0
  366. gaia/eval/webapp/node_modules/get-proto/.nycrc +9 -0
  367. gaia/eval/webapp/node_modules/get-proto/CHANGELOG.md +21 -0
  368. gaia/eval/webapp/node_modules/get-proto/LICENSE +21 -0
  369. gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
  370. gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
  371. gaia/eval/webapp/node_modules/get-proto/README.md +50 -0
  372. gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
  373. gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
  374. gaia/eval/webapp/node_modules/get-proto/index.d.ts +5 -0
  375. gaia/eval/webapp/node_modules/get-proto/index.js +27 -0
  376. gaia/eval/webapp/node_modules/get-proto/package.json +81 -0
  377. gaia/eval/webapp/node_modules/get-proto/test/index.js +68 -0
  378. gaia/eval/webapp/node_modules/get-proto/tsconfig.json +9 -0
  379. gaia/eval/webapp/node_modules/gopd/.eslintrc +16 -0
  380. gaia/eval/webapp/node_modules/gopd/.github/FUNDING.yml +12 -0
  381. gaia/eval/webapp/node_modules/gopd/CHANGELOG.md +45 -0
  382. gaia/eval/webapp/node_modules/gopd/LICENSE +21 -0
  383. gaia/eval/webapp/node_modules/gopd/README.md +40 -0
  384. gaia/eval/webapp/node_modules/gopd/gOPD.d.ts +1 -0
  385. gaia/eval/webapp/node_modules/gopd/gOPD.js +4 -0
  386. gaia/eval/webapp/node_modules/gopd/index.d.ts +5 -0
  387. gaia/eval/webapp/node_modules/gopd/index.js +15 -0
  388. gaia/eval/webapp/node_modules/gopd/package.json +77 -0
  389. gaia/eval/webapp/node_modules/gopd/test/index.js +36 -0
  390. gaia/eval/webapp/node_modules/gopd/tsconfig.json +9 -0
  391. gaia/eval/webapp/node_modules/has-symbols/.eslintrc +11 -0
  392. gaia/eval/webapp/node_modules/has-symbols/.github/FUNDING.yml +12 -0
  393. gaia/eval/webapp/node_modules/has-symbols/.nycrc +9 -0
  394. gaia/eval/webapp/node_modules/has-symbols/CHANGELOG.md +91 -0
  395. gaia/eval/webapp/node_modules/has-symbols/LICENSE +21 -0
  396. gaia/eval/webapp/node_modules/has-symbols/README.md +46 -0
  397. gaia/eval/webapp/node_modules/has-symbols/index.d.ts +3 -0
  398. gaia/eval/webapp/node_modules/has-symbols/index.js +14 -0
  399. gaia/eval/webapp/node_modules/has-symbols/package.json +111 -0
  400. gaia/eval/webapp/node_modules/has-symbols/shams.d.ts +3 -0
  401. gaia/eval/webapp/node_modules/has-symbols/shams.js +45 -0
  402. gaia/eval/webapp/node_modules/has-symbols/test/index.js +22 -0
  403. gaia/eval/webapp/node_modules/has-symbols/test/shams/core-js.js +29 -0
  404. gaia/eval/webapp/node_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
  405. gaia/eval/webapp/node_modules/has-symbols/test/tests.js +58 -0
  406. gaia/eval/webapp/node_modules/has-symbols/tsconfig.json +10 -0
  407. gaia/eval/webapp/node_modules/hasown/.eslintrc +5 -0
  408. gaia/eval/webapp/node_modules/hasown/.github/FUNDING.yml +12 -0
  409. gaia/eval/webapp/node_modules/hasown/.nycrc +13 -0
  410. gaia/eval/webapp/node_modules/hasown/CHANGELOG.md +40 -0
  411. gaia/eval/webapp/node_modules/hasown/LICENSE +21 -0
  412. gaia/eval/webapp/node_modules/hasown/README.md +40 -0
  413. gaia/eval/webapp/node_modules/hasown/index.d.ts +3 -0
  414. gaia/eval/webapp/node_modules/hasown/index.js +8 -0
  415. gaia/eval/webapp/node_modules/hasown/package.json +92 -0
  416. gaia/eval/webapp/node_modules/hasown/tsconfig.json +6 -0
  417. gaia/eval/webapp/node_modules/http-errors/HISTORY.md +180 -0
  418. gaia/eval/webapp/node_modules/http-errors/LICENSE +23 -0
  419. gaia/eval/webapp/node_modules/http-errors/README.md +169 -0
  420. gaia/eval/webapp/node_modules/http-errors/index.js +289 -0
  421. gaia/eval/webapp/node_modules/http-errors/package.json +50 -0
  422. gaia/eval/webapp/node_modules/iconv-lite/Changelog.md +162 -0
  423. gaia/eval/webapp/node_modules/iconv-lite/LICENSE +21 -0
  424. gaia/eval/webapp/node_modules/iconv-lite/README.md +156 -0
  425. gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-codec.js +555 -0
  426. gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-data.js +176 -0
  427. gaia/eval/webapp/node_modules/iconv-lite/encodings/index.js +22 -0
  428. gaia/eval/webapp/node_modules/iconv-lite/encodings/internal.js +188 -0
  429. gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-codec.js +72 -0
  430. gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data-generated.js +451 -0
  431. gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data.js +174 -0
  432. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/big5-added.json +122 -0
  433. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp936.json +264 -0
  434. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp949.json +273 -0
  435. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp950.json +177 -0
  436. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/eucjp.json +182 -0
  437. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +1 -0
  438. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gbk-added.json +55 -0
  439. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/shiftjis.json +125 -0
  440. gaia/eval/webapp/node_modules/iconv-lite/encodings/utf16.js +177 -0
  441. gaia/eval/webapp/node_modules/iconv-lite/encodings/utf7.js +290 -0
  442. gaia/eval/webapp/node_modules/iconv-lite/lib/bom-handling.js +52 -0
  443. gaia/eval/webapp/node_modules/iconv-lite/lib/extend-node.js +217 -0
  444. gaia/eval/webapp/node_modules/iconv-lite/lib/index.d.ts +24 -0
  445. gaia/eval/webapp/node_modules/iconv-lite/lib/index.js +153 -0
  446. gaia/eval/webapp/node_modules/iconv-lite/lib/streams.js +121 -0
  447. gaia/eval/webapp/node_modules/iconv-lite/package.json +46 -0
  448. gaia/eval/webapp/node_modules/inherits/LICENSE +16 -0
  449. gaia/eval/webapp/node_modules/inherits/README.md +42 -0
  450. gaia/eval/webapp/node_modules/inherits/inherits.js +9 -0
  451. gaia/eval/webapp/node_modules/inherits/inherits_browser.js +27 -0
  452. gaia/eval/webapp/node_modules/inherits/package.json +29 -0
  453. gaia/eval/webapp/node_modules/ipaddr.js/LICENSE +19 -0
  454. gaia/eval/webapp/node_modules/ipaddr.js/README.md +233 -0
  455. gaia/eval/webapp/node_modules/ipaddr.js/ipaddr.min.js +1 -0
  456. gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js +673 -0
  457. gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js.d.ts +68 -0
  458. gaia/eval/webapp/node_modules/ipaddr.js/package.json +35 -0
  459. gaia/eval/webapp/node_modules/math-intrinsics/.eslintrc +16 -0
  460. gaia/eval/webapp/node_modules/math-intrinsics/.github/FUNDING.yml +12 -0
  461. gaia/eval/webapp/node_modules/math-intrinsics/CHANGELOG.md +24 -0
  462. gaia/eval/webapp/node_modules/math-intrinsics/LICENSE +21 -0
  463. gaia/eval/webapp/node_modules/math-intrinsics/README.md +50 -0
  464. gaia/eval/webapp/node_modules/math-intrinsics/abs.d.ts +1 -0
  465. gaia/eval/webapp/node_modules/math-intrinsics/abs.js +4 -0
  466. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
  467. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
  468. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
  469. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
  470. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
  471. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.js +5 -0
  472. gaia/eval/webapp/node_modules/math-intrinsics/floor.d.ts +1 -0
  473. gaia/eval/webapp/node_modules/math-intrinsics/floor.js +4 -0
  474. gaia/eval/webapp/node_modules/math-intrinsics/isFinite.d.ts +3 -0
  475. gaia/eval/webapp/node_modules/math-intrinsics/isFinite.js +12 -0
  476. gaia/eval/webapp/node_modules/math-intrinsics/isInteger.d.ts +3 -0
  477. gaia/eval/webapp/node_modules/math-intrinsics/isInteger.js +16 -0
  478. gaia/eval/webapp/node_modules/math-intrinsics/isNaN.d.ts +1 -0
  479. gaia/eval/webapp/node_modules/math-intrinsics/isNaN.js +6 -0
  480. gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
  481. gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.js +6 -0
  482. gaia/eval/webapp/node_modules/math-intrinsics/max.d.ts +1 -0
  483. gaia/eval/webapp/node_modules/math-intrinsics/max.js +4 -0
  484. gaia/eval/webapp/node_modules/math-intrinsics/min.d.ts +1 -0
  485. gaia/eval/webapp/node_modules/math-intrinsics/min.js +4 -0
  486. gaia/eval/webapp/node_modules/math-intrinsics/mod.d.ts +3 -0
  487. gaia/eval/webapp/node_modules/math-intrinsics/mod.js +9 -0
  488. gaia/eval/webapp/node_modules/math-intrinsics/package.json +86 -0
  489. gaia/eval/webapp/node_modules/math-intrinsics/pow.d.ts +1 -0
  490. gaia/eval/webapp/node_modules/math-intrinsics/pow.js +4 -0
  491. gaia/eval/webapp/node_modules/math-intrinsics/round.d.ts +1 -0
  492. gaia/eval/webapp/node_modules/math-intrinsics/round.js +4 -0
  493. gaia/eval/webapp/node_modules/math-intrinsics/sign.d.ts +3 -0
  494. gaia/eval/webapp/node_modules/math-intrinsics/sign.js +11 -0
  495. gaia/eval/webapp/node_modules/math-intrinsics/test/index.js +192 -0
  496. gaia/eval/webapp/node_modules/math-intrinsics/tsconfig.json +3 -0
  497. gaia/eval/webapp/node_modules/media-typer/HISTORY.md +22 -0
  498. gaia/eval/webapp/node_modules/media-typer/LICENSE +22 -0
  499. gaia/eval/webapp/node_modules/media-typer/README.md +81 -0
  500. gaia/eval/webapp/node_modules/media-typer/index.js +270 -0
  501. gaia/eval/webapp/node_modules/media-typer/package.json +26 -0
  502. gaia/eval/webapp/node_modules/merge-descriptors/HISTORY.md +21 -0
  503. gaia/eval/webapp/node_modules/merge-descriptors/LICENSE +23 -0
  504. gaia/eval/webapp/node_modules/merge-descriptors/README.md +49 -0
  505. gaia/eval/webapp/node_modules/merge-descriptors/index.js +60 -0
  506. gaia/eval/webapp/node_modules/merge-descriptors/package.json +39 -0
  507. gaia/eval/webapp/node_modules/methods/HISTORY.md +29 -0
  508. gaia/eval/webapp/node_modules/methods/LICENSE +24 -0
  509. gaia/eval/webapp/node_modules/methods/README.md +51 -0
  510. gaia/eval/webapp/node_modules/methods/index.js +69 -0
  511. gaia/eval/webapp/node_modules/methods/package.json +36 -0
  512. gaia/eval/webapp/node_modules/mime/.npmignore +0 -0
  513. gaia/eval/webapp/node_modules/mime/CHANGELOG.md +164 -0
  514. gaia/eval/webapp/node_modules/mime/LICENSE +21 -0
  515. gaia/eval/webapp/node_modules/mime/README.md +90 -0
  516. gaia/eval/webapp/node_modules/mime/cli.js +8 -0
  517. gaia/eval/webapp/node_modules/mime/mime.js +108 -0
  518. gaia/eval/webapp/node_modules/mime/package.json +44 -0
  519. gaia/eval/webapp/node_modules/mime/src/build.js +53 -0
  520. gaia/eval/webapp/node_modules/mime/src/test.js +60 -0
  521. gaia/eval/webapp/node_modules/mime/types.json +1 -0
  522. gaia/eval/webapp/node_modules/mime-db/HISTORY.md +507 -0
  523. gaia/eval/webapp/node_modules/mime-db/LICENSE +23 -0
  524. gaia/eval/webapp/node_modules/mime-db/README.md +100 -0
  525. gaia/eval/webapp/node_modules/mime-db/db.json +8519 -0
  526. gaia/eval/webapp/node_modules/mime-db/index.js +12 -0
  527. gaia/eval/webapp/node_modules/mime-db/package.json +60 -0
  528. gaia/eval/webapp/node_modules/mime-types/HISTORY.md +397 -0
  529. gaia/eval/webapp/node_modules/mime-types/LICENSE +23 -0
  530. gaia/eval/webapp/node_modules/mime-types/README.md +113 -0
  531. gaia/eval/webapp/node_modules/mime-types/index.js +188 -0
  532. gaia/eval/webapp/node_modules/mime-types/package.json +44 -0
  533. gaia/eval/webapp/node_modules/ms/index.js +152 -0
  534. gaia/eval/webapp/node_modules/ms/license.md +21 -0
  535. gaia/eval/webapp/node_modules/ms/package.json +37 -0
  536. gaia/eval/webapp/node_modules/ms/readme.md +51 -0
  537. gaia/eval/webapp/node_modules/negotiator/HISTORY.md +108 -0
  538. gaia/eval/webapp/node_modules/negotiator/LICENSE +24 -0
  539. gaia/eval/webapp/node_modules/negotiator/README.md +203 -0
  540. gaia/eval/webapp/node_modules/negotiator/index.js +82 -0
  541. gaia/eval/webapp/node_modules/negotiator/lib/charset.js +169 -0
  542. gaia/eval/webapp/node_modules/negotiator/lib/encoding.js +184 -0
  543. gaia/eval/webapp/node_modules/negotiator/lib/language.js +179 -0
  544. gaia/eval/webapp/node_modules/negotiator/lib/mediaType.js +294 -0
  545. gaia/eval/webapp/node_modules/negotiator/package.json +42 -0
  546. gaia/eval/webapp/node_modules/object-inspect/.eslintrc +53 -0
  547. gaia/eval/webapp/node_modules/object-inspect/.github/FUNDING.yml +12 -0
  548. gaia/eval/webapp/node_modules/object-inspect/.nycrc +13 -0
  549. gaia/eval/webapp/node_modules/object-inspect/CHANGELOG.md +424 -0
  550. gaia/eval/webapp/node_modules/object-inspect/LICENSE +21 -0
  551. gaia/eval/webapp/node_modules/object-inspect/example/all.js +23 -0
  552. gaia/eval/webapp/node_modules/object-inspect/example/circular.js +6 -0
  553. gaia/eval/webapp/node_modules/object-inspect/example/fn.js +5 -0
  554. gaia/eval/webapp/node_modules/object-inspect/example/inspect.js +10 -0
  555. gaia/eval/webapp/node_modules/object-inspect/index.js +544 -0
  556. gaia/eval/webapp/node_modules/object-inspect/package-support.json +20 -0
  557. gaia/eval/webapp/node_modules/object-inspect/package.json +105 -0
  558. gaia/eval/webapp/node_modules/object-inspect/readme.markdown +84 -0
  559. gaia/eval/webapp/node_modules/object-inspect/test/bigint.js +58 -0
  560. gaia/eval/webapp/node_modules/object-inspect/test/browser/dom.js +15 -0
  561. gaia/eval/webapp/node_modules/object-inspect/test/circular.js +16 -0
  562. gaia/eval/webapp/node_modules/object-inspect/test/deep.js +12 -0
  563. gaia/eval/webapp/node_modules/object-inspect/test/element.js +53 -0
  564. gaia/eval/webapp/node_modules/object-inspect/test/err.js +48 -0
  565. gaia/eval/webapp/node_modules/object-inspect/test/fakes.js +29 -0
  566. gaia/eval/webapp/node_modules/object-inspect/test/fn.js +76 -0
  567. gaia/eval/webapp/node_modules/object-inspect/test/global.js +17 -0
  568. gaia/eval/webapp/node_modules/object-inspect/test/has.js +15 -0
  569. gaia/eval/webapp/node_modules/object-inspect/test/holes.js +15 -0
  570. gaia/eval/webapp/node_modules/object-inspect/test/indent-option.js +271 -0
  571. gaia/eval/webapp/node_modules/object-inspect/test/inspect.js +139 -0
  572. gaia/eval/webapp/node_modules/object-inspect/test/lowbyte.js +12 -0
  573. gaia/eval/webapp/node_modules/object-inspect/test/number.js +58 -0
  574. gaia/eval/webapp/node_modules/object-inspect/test/quoteStyle.js +26 -0
  575. gaia/eval/webapp/node_modules/object-inspect/test/toStringTag.js +40 -0
  576. gaia/eval/webapp/node_modules/object-inspect/test/undef.js +12 -0
  577. gaia/eval/webapp/node_modules/object-inspect/test/values.js +261 -0
  578. gaia/eval/webapp/node_modules/object-inspect/test-core-js.js +26 -0
  579. gaia/eval/webapp/node_modules/object-inspect/util.inspect.js +1 -0
  580. gaia/eval/webapp/node_modules/on-finished/HISTORY.md +98 -0
  581. gaia/eval/webapp/node_modules/on-finished/LICENSE +23 -0
  582. gaia/eval/webapp/node_modules/on-finished/README.md +162 -0
  583. gaia/eval/webapp/node_modules/on-finished/index.js +234 -0
  584. gaia/eval/webapp/node_modules/on-finished/package.json +39 -0
  585. gaia/eval/webapp/node_modules/parseurl/HISTORY.md +58 -0
  586. gaia/eval/webapp/node_modules/parseurl/LICENSE +24 -0
  587. gaia/eval/webapp/node_modules/parseurl/README.md +133 -0
  588. gaia/eval/webapp/node_modules/parseurl/index.js +158 -0
  589. gaia/eval/webapp/node_modules/parseurl/package.json +40 -0
  590. gaia/eval/webapp/node_modules/path/.npmignore +1 -0
  591. gaia/eval/webapp/node_modules/path/LICENSE +18 -0
  592. gaia/eval/webapp/node_modules/path/README.md +15 -0
  593. gaia/eval/webapp/node_modules/path/package.json +24 -0
  594. gaia/eval/webapp/node_modules/path/path.js +628 -0
  595. gaia/eval/webapp/node_modules/path-to-regexp/LICENSE +21 -0
  596. gaia/eval/webapp/node_modules/path-to-regexp/Readme.md +35 -0
  597. gaia/eval/webapp/node_modules/path-to-regexp/index.js +156 -0
  598. gaia/eval/webapp/node_modules/path-to-regexp/package.json +30 -0
  599. gaia/eval/webapp/node_modules/process/.eslintrc +21 -0
  600. gaia/eval/webapp/node_modules/process/LICENSE +22 -0
  601. gaia/eval/webapp/node_modules/process/README.md +26 -0
  602. gaia/eval/webapp/node_modules/process/browser.js +184 -0
  603. gaia/eval/webapp/node_modules/process/index.js +2 -0
  604. gaia/eval/webapp/node_modules/process/package.json +27 -0
  605. gaia/eval/webapp/node_modules/process/test.js +199 -0
  606. gaia/eval/webapp/node_modules/proxy-addr/HISTORY.md +161 -0
  607. gaia/eval/webapp/node_modules/proxy-addr/LICENSE +22 -0
  608. gaia/eval/webapp/node_modules/proxy-addr/README.md +139 -0
  609. gaia/eval/webapp/node_modules/proxy-addr/index.js +327 -0
  610. gaia/eval/webapp/node_modules/proxy-addr/package.json +47 -0
  611. gaia/eval/webapp/node_modules/qs/.editorconfig +46 -0
  612. gaia/eval/webapp/node_modules/qs/.eslintrc +38 -0
  613. gaia/eval/webapp/node_modules/qs/.github/FUNDING.yml +12 -0
  614. gaia/eval/webapp/node_modules/qs/.nycrc +13 -0
  615. gaia/eval/webapp/node_modules/qs/CHANGELOG.md +600 -0
  616. gaia/eval/webapp/node_modules/qs/LICENSE.md +29 -0
  617. gaia/eval/webapp/node_modules/qs/README.md +709 -0
  618. gaia/eval/webapp/node_modules/qs/dist/qs.js +90 -0
  619. gaia/eval/webapp/node_modules/qs/lib/formats.js +23 -0
  620. gaia/eval/webapp/node_modules/qs/lib/index.js +11 -0
  621. gaia/eval/webapp/node_modules/qs/lib/parse.js +296 -0
  622. gaia/eval/webapp/node_modules/qs/lib/stringify.js +351 -0
  623. gaia/eval/webapp/node_modules/qs/lib/utils.js +265 -0
  624. gaia/eval/webapp/node_modules/qs/package.json +91 -0
  625. gaia/eval/webapp/node_modules/qs/test/empty-keys-cases.js +267 -0
  626. gaia/eval/webapp/node_modules/qs/test/parse.js +1170 -0
  627. gaia/eval/webapp/node_modules/qs/test/stringify.js +1298 -0
  628. gaia/eval/webapp/node_modules/qs/test/utils.js +136 -0
  629. gaia/eval/webapp/node_modules/range-parser/HISTORY.md +56 -0
  630. gaia/eval/webapp/node_modules/range-parser/LICENSE +23 -0
  631. gaia/eval/webapp/node_modules/range-parser/README.md +84 -0
  632. gaia/eval/webapp/node_modules/range-parser/index.js +162 -0
  633. gaia/eval/webapp/node_modules/range-parser/package.json +44 -0
  634. gaia/eval/webapp/node_modules/raw-body/HISTORY.md +308 -0
  635. gaia/eval/webapp/node_modules/raw-body/LICENSE +22 -0
  636. gaia/eval/webapp/node_modules/raw-body/README.md +223 -0
  637. gaia/eval/webapp/node_modules/raw-body/SECURITY.md +24 -0
  638. gaia/eval/webapp/node_modules/raw-body/index.d.ts +87 -0
  639. gaia/eval/webapp/node_modules/raw-body/index.js +336 -0
  640. gaia/eval/webapp/node_modules/raw-body/package.json +49 -0
  641. gaia/eval/webapp/node_modules/safe-buffer/LICENSE +21 -0
  642. gaia/eval/webapp/node_modules/safe-buffer/README.md +584 -0
  643. gaia/eval/webapp/node_modules/safe-buffer/index.d.ts +187 -0
  644. gaia/eval/webapp/node_modules/safe-buffer/index.js +65 -0
  645. gaia/eval/webapp/node_modules/safe-buffer/package.json +51 -0
  646. gaia/eval/webapp/node_modules/safer-buffer/LICENSE +21 -0
  647. gaia/eval/webapp/node_modules/safer-buffer/Porting-Buffer.md +268 -0
  648. gaia/eval/webapp/node_modules/safer-buffer/Readme.md +156 -0
  649. gaia/eval/webapp/node_modules/safer-buffer/dangerous.js +58 -0
  650. gaia/eval/webapp/node_modules/safer-buffer/package.json +34 -0
  651. gaia/eval/webapp/node_modules/safer-buffer/safer.js +77 -0
  652. gaia/eval/webapp/node_modules/safer-buffer/tests.js +406 -0
  653. gaia/eval/webapp/node_modules/send/HISTORY.md +526 -0
  654. gaia/eval/webapp/node_modules/send/LICENSE +23 -0
  655. gaia/eval/webapp/node_modules/send/README.md +327 -0
  656. gaia/eval/webapp/node_modules/send/SECURITY.md +24 -0
  657. gaia/eval/webapp/node_modules/send/index.js +1142 -0
  658. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/HISTORY.md +14 -0
  659. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/LICENSE +22 -0
  660. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/README.md +128 -0
  661. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/index.js +60 -0
  662. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/package.json +40 -0
  663. gaia/eval/webapp/node_modules/send/node_modules/ms/index.js +162 -0
  664. gaia/eval/webapp/node_modules/send/node_modules/ms/license.md +21 -0
  665. gaia/eval/webapp/node_modules/send/node_modules/ms/package.json +38 -0
  666. gaia/eval/webapp/node_modules/send/node_modules/ms/readme.md +59 -0
  667. gaia/eval/webapp/node_modules/send/package.json +62 -0
  668. gaia/eval/webapp/node_modules/serve-static/HISTORY.md +487 -0
  669. gaia/eval/webapp/node_modules/serve-static/LICENSE +25 -0
  670. gaia/eval/webapp/node_modules/serve-static/README.md +257 -0
  671. gaia/eval/webapp/node_modules/serve-static/index.js +209 -0
  672. gaia/eval/webapp/node_modules/serve-static/package.json +42 -0
  673. gaia/eval/webapp/node_modules/setprototypeof/LICENSE +13 -0
  674. gaia/eval/webapp/node_modules/setprototypeof/README.md +31 -0
  675. gaia/eval/webapp/node_modules/setprototypeof/index.d.ts +2 -0
  676. gaia/eval/webapp/node_modules/setprototypeof/index.js +17 -0
  677. gaia/eval/webapp/node_modules/setprototypeof/package.json +38 -0
  678. gaia/eval/webapp/node_modules/setprototypeof/test/index.js +24 -0
  679. gaia/eval/webapp/node_modules/side-channel/.editorconfig +9 -0
  680. gaia/eval/webapp/node_modules/side-channel/.eslintrc +12 -0
  681. gaia/eval/webapp/node_modules/side-channel/.github/FUNDING.yml +12 -0
  682. gaia/eval/webapp/node_modules/side-channel/.nycrc +13 -0
  683. gaia/eval/webapp/node_modules/side-channel/CHANGELOG.md +110 -0
  684. gaia/eval/webapp/node_modules/side-channel/LICENSE +21 -0
  685. gaia/eval/webapp/node_modules/side-channel/README.md +61 -0
  686. gaia/eval/webapp/node_modules/side-channel/index.d.ts +14 -0
  687. gaia/eval/webapp/node_modules/side-channel/index.js +43 -0
  688. gaia/eval/webapp/node_modules/side-channel/package.json +85 -0
  689. gaia/eval/webapp/node_modules/side-channel/test/index.js +104 -0
  690. gaia/eval/webapp/node_modules/side-channel/tsconfig.json +9 -0
  691. gaia/eval/webapp/node_modules/side-channel-list/.editorconfig +9 -0
  692. gaia/eval/webapp/node_modules/side-channel-list/.eslintrc +11 -0
  693. gaia/eval/webapp/node_modules/side-channel-list/.github/FUNDING.yml +12 -0
  694. gaia/eval/webapp/node_modules/side-channel-list/.nycrc +13 -0
  695. gaia/eval/webapp/node_modules/side-channel-list/CHANGELOG.md +15 -0
  696. gaia/eval/webapp/node_modules/side-channel-list/LICENSE +21 -0
  697. gaia/eval/webapp/node_modules/side-channel-list/README.md +62 -0
  698. gaia/eval/webapp/node_modules/side-channel-list/index.d.ts +13 -0
  699. gaia/eval/webapp/node_modules/side-channel-list/index.js +113 -0
  700. gaia/eval/webapp/node_modules/side-channel-list/list.d.ts +14 -0
  701. gaia/eval/webapp/node_modules/side-channel-list/package.json +77 -0
  702. gaia/eval/webapp/node_modules/side-channel-list/test/index.js +104 -0
  703. gaia/eval/webapp/node_modules/side-channel-list/tsconfig.json +9 -0
  704. gaia/eval/webapp/node_modules/side-channel-map/.editorconfig +9 -0
  705. gaia/eval/webapp/node_modules/side-channel-map/.eslintrc +11 -0
  706. gaia/eval/webapp/node_modules/side-channel-map/.github/FUNDING.yml +12 -0
  707. gaia/eval/webapp/node_modules/side-channel-map/.nycrc +13 -0
  708. gaia/eval/webapp/node_modules/side-channel-map/CHANGELOG.md +22 -0
  709. gaia/eval/webapp/node_modules/side-channel-map/LICENSE +21 -0
  710. gaia/eval/webapp/node_modules/side-channel-map/README.md +62 -0
  711. gaia/eval/webapp/node_modules/side-channel-map/index.d.ts +15 -0
  712. gaia/eval/webapp/node_modules/side-channel-map/index.js +68 -0
  713. gaia/eval/webapp/node_modules/side-channel-map/package.json +80 -0
  714. gaia/eval/webapp/node_modules/side-channel-map/test/index.js +114 -0
  715. gaia/eval/webapp/node_modules/side-channel-map/tsconfig.json +9 -0
  716. gaia/eval/webapp/node_modules/side-channel-weakmap/.editorconfig +9 -0
  717. gaia/eval/webapp/node_modules/side-channel-weakmap/.eslintrc +12 -0
  718. gaia/eval/webapp/node_modules/side-channel-weakmap/.github/FUNDING.yml +12 -0
  719. gaia/eval/webapp/node_modules/side-channel-weakmap/.nycrc +13 -0
  720. gaia/eval/webapp/node_modules/side-channel-weakmap/CHANGELOG.md +28 -0
  721. gaia/eval/webapp/node_modules/side-channel-weakmap/LICENSE +21 -0
  722. gaia/eval/webapp/node_modules/side-channel-weakmap/README.md +62 -0
  723. gaia/eval/webapp/node_modules/side-channel-weakmap/index.d.ts +15 -0
  724. gaia/eval/webapp/node_modules/side-channel-weakmap/index.js +84 -0
  725. gaia/eval/webapp/node_modules/side-channel-weakmap/package.json +87 -0
  726. gaia/eval/webapp/node_modules/side-channel-weakmap/test/index.js +114 -0
  727. gaia/eval/webapp/node_modules/side-channel-weakmap/tsconfig.json +9 -0
  728. gaia/eval/webapp/node_modules/statuses/HISTORY.md +82 -0
  729. gaia/eval/webapp/node_modules/statuses/LICENSE +23 -0
  730. gaia/eval/webapp/node_modules/statuses/README.md +136 -0
  731. gaia/eval/webapp/node_modules/statuses/codes.json +65 -0
  732. gaia/eval/webapp/node_modules/statuses/index.js +146 -0
  733. gaia/eval/webapp/node_modules/statuses/package.json +49 -0
  734. gaia/eval/webapp/node_modules/toidentifier/HISTORY.md +9 -0
  735. gaia/eval/webapp/node_modules/toidentifier/LICENSE +21 -0
  736. gaia/eval/webapp/node_modules/toidentifier/README.md +61 -0
  737. gaia/eval/webapp/node_modules/toidentifier/index.js +32 -0
  738. gaia/eval/webapp/node_modules/toidentifier/package.json +38 -0
  739. gaia/eval/webapp/node_modules/type-is/HISTORY.md +259 -0
  740. gaia/eval/webapp/node_modules/type-is/LICENSE +23 -0
  741. gaia/eval/webapp/node_modules/type-is/README.md +170 -0
  742. gaia/eval/webapp/node_modules/type-is/index.js +266 -0
  743. gaia/eval/webapp/node_modules/type-is/package.json +45 -0
  744. gaia/eval/webapp/node_modules/unpipe/HISTORY.md +4 -0
  745. gaia/eval/webapp/node_modules/unpipe/LICENSE +22 -0
  746. gaia/eval/webapp/node_modules/unpipe/README.md +43 -0
  747. gaia/eval/webapp/node_modules/unpipe/index.js +69 -0
  748. gaia/eval/webapp/node_modules/unpipe/package.json +27 -0
  749. gaia/eval/webapp/node_modules/util/LICENSE +18 -0
  750. gaia/eval/webapp/node_modules/util/README.md +15 -0
  751. gaia/eval/webapp/node_modules/util/node_modules/inherits/LICENSE +16 -0
  752. gaia/eval/webapp/node_modules/util/node_modules/inherits/README.md +42 -0
  753. gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits.js +7 -0
  754. gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits_browser.js +23 -0
  755. gaia/eval/webapp/node_modules/util/node_modules/inherits/package.json +29 -0
  756. gaia/eval/webapp/node_modules/util/package.json +35 -0
  757. gaia/eval/webapp/node_modules/util/support/isBuffer.js +3 -0
  758. gaia/eval/webapp/node_modules/util/support/isBufferBrowser.js +6 -0
  759. gaia/eval/webapp/node_modules/util/util.js +586 -0
  760. gaia/eval/webapp/node_modules/utils-merge/.npmignore +9 -0
  761. gaia/eval/webapp/node_modules/utils-merge/LICENSE +20 -0
  762. gaia/eval/webapp/node_modules/utils-merge/README.md +34 -0
  763. gaia/eval/webapp/node_modules/utils-merge/index.js +23 -0
  764. gaia/eval/webapp/node_modules/utils-merge/package.json +40 -0
  765. gaia/eval/webapp/node_modules/vary/HISTORY.md +39 -0
  766. gaia/eval/webapp/node_modules/vary/LICENSE +22 -0
  767. gaia/eval/webapp/node_modules/vary/README.md +101 -0
  768. gaia/eval/webapp/node_modules/vary/index.js +149 -0
  769. gaia/eval/webapp/node_modules/vary/package.json +43 -0
  770. gaia/eval/webapp/package-lock.json +875 -0
  771. gaia/eval/webapp/package.json +21 -0
  772. gaia/eval/webapp/public/app.js +3403 -0
  773. gaia/eval/webapp/public/index.html +88 -0
  774. gaia/eval/webapp/public/styles.css +3661 -0
  775. gaia/eval/webapp/server.js +416 -0
  776. gaia/eval/webapp/test-setup.js +73 -0
  777. gaia/llm/__init__.py +2 -0
  778. gaia/llm/lemonade_client.py +3083 -0
  779. gaia/llm/lemonade_manager.py +269 -0
  780. gaia/llm/llm_client.py +729 -0
  781. gaia/llm/vlm_client.py +307 -0
  782. gaia/logger.py +189 -0
  783. gaia/mcp/agent_mcp_server.py +245 -0
  784. gaia/mcp/blender_mcp_client.py +138 -0
  785. gaia/mcp/blender_mcp_server.py +648 -0
  786. gaia/mcp/context7_cache.py +332 -0
  787. gaia/mcp/external_services.py +518 -0
  788. gaia/mcp/mcp_bridge.py +550 -0
  789. gaia/mcp/servers/__init__.py +6 -0
  790. gaia/mcp/servers/docker_mcp.py +83 -0
  791. gaia/rag/__init__.py +10 -0
  792. gaia/rag/app.py +293 -0
  793. gaia/rag/demo.py +304 -0
  794. gaia/rag/pdf_utils.py +235 -0
  795. gaia/rag/sdk.py +2194 -0
  796. gaia/security.py +163 -0
  797. gaia/talk/app.py +289 -0
  798. gaia/talk/sdk.py +538 -0
  799. gaia/util.py +46 -0
  800. 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}")