@agenthippo-ai/agenthippo 1.110.11 → 1.110.19

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 (534) hide show
  1. package/out/agentpack/types.js +2 -5
  2. package/out/analytics/dashboard/artifactManager.js +2 -439
  3. package/out/analytics/dashboard/fleetDisplayUtils.js +2 -162
  4. package/out/analytics/dashboard/fleetOrchestrator.js +3 -142
  5. package/out/analytics/dashboard/fleetRegistry.js +2 -79
  6. package/out/analytics/dashboard/fleetRowDefaults.js +2 -87
  7. package/out/analytics/dashboard/fleetScriptAdapter.js +2 -146
  8. package/out/analytics/dashboard/fleetTypes.js +2 -29
  9. package/out/analytics/dashboard/index.js +2 -17
  10. package/out/analytics/dashboard/indexingService.js +2 -422
  11. package/out/analytics/dashboard/localFleetAdapter.js +2 -302
  12. package/out/analytics/dashboard/performanceMonitor.js +5 -76
  13. package/out/analytics/dashboard/processManager.js +2 -209
  14. package/out/analytics/dashboard/provider.js +38 -3817
  15. package/out/analytics/dashboard/queryRunner.js +62 -750
  16. package/out/analytics/dashboard/scheduledFleetStorage.js +2 -241
  17. package/out/analytics/dashboard/sessionJsonlFleet.js +3 -204
  18. package/out/analytics/dashboard/teamViewDiscovery.js +2 -106
  19. package/out/analytics/dashboard/webview/panel.js +34 -2318
  20. package/out/analytics/dashboard/webview/runtime-bridge.js +2 -82
  21. package/out/analytics/lifecycle.js +2 -43
  22. package/out/analytics/service.js +8 -1283
  23. package/out/auth/authBaseUrl.js +2 -59
  24. package/out/auth/bootstrapApply.js +2 -71
  25. package/out/auth/brokerClient.js +2 -160
  26. package/out/auth/callbackUri.js +2 -59
  27. package/out/auth/githubStoreGate.js +2 -70
  28. package/out/auth/loopbackAuthServer.js +4 -159
  29. package/out/auth/onboardingPrompt.js +2 -112
  30. package/out/auth/pkce.js +2 -9
  31. package/out/auth/provider.js +2 -226
  32. package/out/auth/sessionStore.js +2 -156
  33. package/out/auth/signInFlow.js +2 -183
  34. package/out/cli/index.js +617 -564
  35. package/out/cli/run-custom-engine-runner.js +3 -318
  36. package/out/cli/vscode-shim.js +2 -86
  37. package/out/engines/factory.js +2 -45
  38. package/out/engines/types.js +2 -17
  39. package/out/examples/run-headless-repl.js +6 -286
  40. package/out/examples/run-headless.js +2 -187
  41. package/out/extension.js +32 -4473
  42. package/out/gateway/gatewayRouteIndex.js +6 -371
  43. package/out/gateway/gatewaySessionStore.js +3 -243
  44. package/out/gateway/index.js +2 -31
  45. package/out/gateway/resetMappings.js +2 -52
  46. package/out/gateway/service.js +5 -1249
  47. package/out/mcp/publish.js +2 -143
  48. package/out/remote/handleRemoteChat.js +2 -169
  49. package/out/remote/remotePackStatusBar.js +3 -103
  50. package/out/remote/remoteTrust.js +6 -277
  51. package/out/remote/serveClient.js +4 -277
  52. package/out/remoteSkills.js +3 -191
  53. package/out/runtime/index.js +2 -32
  54. package/out/runtime/vscode/index.js +2 -20
  55. package/out/runtime/vscode/vscode-config-provider.js +2 -77
  56. package/out/runtime/vscode/vscode-edit-tracker.js +2 -122
  57. package/out/runtime/vscode/vscode-logger.js +2 -30
  58. package/out/runtime/vscode/vscode-permission-handler.js +2 -72
  59. package/out/scripts/agentide-litellm.sh +0 -1
  60. package/out/scripts/agentide_litellm_hooks_v1.py +127 -459
  61. package/out/scripts/analytics/agent-fleet-widget.js +18 -257
  62. package/out/scripts/analytics/agentide-litellm-otel.config.yaml +0 -4
  63. package/out/scripts/analytics/duckdbLocator.js +2 -28
  64. package/out/scripts/analytics/generate-default-charts.py +43 -323
  65. package/out/scripts/analytics/hotspot-analysis-widget.js +4 -430
  66. package/out/scripts/analytics/index-traces.py +78 -1036
  67. package/out/scripts/analytics/session-comparison-widget.js +26 -472
  68. package/out/scripts/analytics/session-timeline-widget.js +25 -846
  69. package/out/scripts/analytics/token-cost-flamegraph-widget.js +4 -461
  70. package/out/scripts/analytics/token-cost-trend-widget.js +4 -534
  71. package/out/scripts/analytics/workflows-collector.cjs +4 -314
  72. package/out/scripts/analytics/workflows-daemon.mjs +9 -185
  73. package/out/scripts/analytics/workflows-widget.cjs +15 -159
  74. package/out/scripts/analytics/wow-model-widget.js +10 -120
  75. package/out/scripts/vendor-tools.mjs +2 -233
  76. package/out/skills/publish.js +3 -178
  77. package/out/store/github/setup.js +7 -212
  78. package/out/store/oramaIndex.js +2 -884
  79. package/out/sync.js +26 -1829
  80. package/out/terminalLogger.js +5 -358
  81. package/out/utils/pathSafety.js +2 -60
  82. package/out/utils/pythonRunner.js +4 -258
  83. package/out/utils/toolPath.js +2 -83
  84. package/out/workspaceFolders.js +2 -59
  85. package/package.json +1 -1
  86. package/out/agentpack/github.js +0 -547
  87. package/out/agentpack/index.js +0 -69
  88. package/out/agentpack/install.js +0 -297
  89. package/out/agentpack/manager.js +0 -441
  90. package/out/agentpack/manifest.js +0 -135
  91. package/out/agentpack/paths.js +0 -521
  92. package/out/agentpack/publish.js +0 -248
  93. package/out/agentpack/stores.js +0 -554
  94. package/out/analytics/dashboard/fleetStatusUtils.js +0 -30
  95. package/out/analytics/dashboard/fleetTitleUtils.js +0 -68
  96. package/out/analytics/dashboard/refreshPolicy.js +0 -16
  97. package/out/analytics/dashboard/scheduledFleetFingerprint.js +0 -22
  98. package/out/analytics/dashboard/scheduledFleetUtils.js +0 -22
  99. package/out/analytics/dashboard/sessionEventFleetStats.js +0 -118
  100. package/out/analytics/dashboard/viewsConfigMerge.js +0 -221
  101. package/out/analytics/dashboard/webview/codicon.ttf +0 -0
  102. package/out/analytics/identity.js +0 -0
  103. package/out/analytics/sessionEvents.js +0 -324
  104. package/out/auth/callbackUriParse.js +0 -59
  105. package/out/auth/types.js +0 -12
  106. package/out/auth-broker/config.js +0 -112
  107. package/out/auth-broker/jwt.js +0 -105
  108. package/out/auth-broker/pkce.js +0 -59
  109. package/out/auth-broker/server.js +0 -681
  110. package/out/auth-broker/store.js +0 -275
  111. package/out/authority/warrant.js +0 -206
  112. package/out/base-prompts/mcp-servers/.mcp.json +0 -13
  113. package/out/base-prompts/mcp-servers/langfuse-analytics/README.md +0 -142
  114. package/out/base-prompts/mcp-servers/langfuse-analytics/mcp.json +0 -13
  115. package/out/base-prompts/mcp-servers/langfuse-analytics/package-lock.json +0 -1192
  116. package/out/base-prompts/mcp-servers/langfuse-analytics/package.json +0 -23
  117. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/run-with-env.sh +0 -12
  118. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/sdk-test.js +0 -102
  119. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/simple-test.js +0 -137
  120. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-client.js +0 -118
  121. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-server.js +0 -209
  122. package/out/base-prompts/mcp-servers/langfuse-analytics/src/client.ts +0 -431
  123. package/out/base-prompts/mcp-servers/langfuse-analytics/src/index.ts +0 -270
  124. package/out/base-prompts/mcp-servers/langfuse-analytics/tsconfig.json +0 -18
  125. package/out/base-prompts/rules/AGENTS.md +0 -204
  126. package/out/base-prompts/skills/agent-browser/SKILL.md +0 -102
  127. package/out/base-prompts/skills/agent-builder/SKILL.md +0 -73
  128. package/out/base-prompts/skills/agent-builder/references/agent-pack.md +0 -63
  129. package/out/base-prompts/skills/agent-builder/references/crewai.md +0 -66
  130. package/out/base-prompts/skills/agent-builder/references/langchain.md +0 -60
  131. package/out/base-prompts/skills/agent-builder/references/raw-sdk.md +0 -73
  132. package/out/base-prompts/skills/agent-engine-creator/SKILL.md +0 -586
  133. package/out/base-prompts/skills/agent-engine-installer/SKILL.md +0 -106
  134. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.mjs +0 -259
  135. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.ps1 +0 -189
  136. package/out/base-prompts/skills/agenthippo-cli/SKILL.md +0 -69
  137. package/out/base-prompts/skills/agenthippo-cli/scripts/install.sh +0 -63
  138. package/out/base-prompts/skills/agentpack-creator/SKILL.md +0 -375
  139. package/out/base-prompts/skills/agentpack-creator/references/agent-templates.md +0 -261
  140. package/out/base-prompts/skills/agentpack-creator/references/agents-md-guide.md +0 -195
  141. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack.py +0 -391
  142. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack_test.py +0 -294
  143. package/out/base-prompts/skills/agentpack-testbench/SKILL.md +0 -135
  144. package/out/base-prompts/skills/algorithmic-art/LICENSE.txt +0 -202
  145. package/out/base-prompts/skills/algorithmic-art/SKILL.md +0 -405
  146. package/out/base-prompts/skills/algorithmic-art/templates/generator_template.js +0 -223
  147. package/out/base-prompts/skills/algorithmic-art/templates/viewer.html +0 -599
  148. package/out/base-prompts/skills/debug-agent/SKILL.md +0 -83
  149. package/out/base-prompts/skills/desktop-automation/SKILL.md +0 -166
  150. package/out/base-prompts/skills/desktop-automation/references/agenthippo-ui-recipes.md +0 -441
  151. package/out/base-prompts/skills/desktop-automation/scripts/windows-desktop-uia.psm1 +0 -280
  152. package/out/base-prompts/skills/docx/LICENSE.txt +0 -30
  153. package/out/base-prompts/skills/docx/SKILL.md +0 -197
  154. package/out/base-prompts/skills/docx/docx-js.md +0 -350
  155. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  156. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  157. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  158. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  159. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  160. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  161. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  162. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  163. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  164. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  165. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  166. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  167. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  168. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  169. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  170. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  171. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  172. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  173. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  174. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  175. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  176. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  177. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  178. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  179. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  180. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  181. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  182. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  183. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  184. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  185. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  186. package/out/base-prompts/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  187. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  188. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  189. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  190. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  191. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  192. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  193. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  194. package/out/base-prompts/skills/docx/ooxml/scripts/pack.py +0 -159
  195. package/out/base-prompts/skills/docx/ooxml/scripts/unpack.py +0 -29
  196. package/out/base-prompts/skills/docx/ooxml/scripts/validate.py +0 -69
  197. package/out/base-prompts/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  198. package/out/base-prompts/skills/docx/ooxml/scripts/validation/base.py +0 -951
  199. package/out/base-prompts/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  200. package/out/base-prompts/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  201. package/out/base-prompts/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  202. package/out/base-prompts/skills/docx/ooxml.md +0 -610
  203. package/out/base-prompts/skills/docx/scripts/__init__.py +0 -1
  204. package/out/base-prompts/skills/docx/scripts/document.py +0 -1276
  205. package/out/base-prompts/skills/docx/scripts/templates/comments.xml +0 -3
  206. package/out/base-prompts/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  207. package/out/base-prompts/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  208. package/out/base-prompts/skills/docx/scripts/templates/commentsIds.xml +0 -3
  209. package/out/base-prompts/skills/docx/scripts/templates/people.xml +0 -3
  210. package/out/base-prompts/skills/docx/scripts/utilities.py +0 -374
  211. package/out/base-prompts/skills/gateway-outbound/SKILL.md +0 -136
  212. package/out/base-prompts/skills/mcp-builder/LICENSE.txt +0 -202
  213. package/out/base-prompts/skills/mcp-builder/SKILL.md +0 -328
  214. package/out/base-prompts/skills/mcp-builder/reference/evaluation.md +0 -602
  215. package/out/base-prompts/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  216. package/out/base-prompts/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  217. package/out/base-prompts/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  218. package/out/base-prompts/skills/mcp-builder/scripts/connections.py +0 -151
  219. package/out/base-prompts/skills/mcp-builder/scripts/evaluation.py +0 -373
  220. package/out/base-prompts/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  221. package/out/base-prompts/skills/mcp-builder/scripts/requirements.txt +0 -2
  222. package/out/base-prompts/skills/openclaw/SKILL.md +0 -406
  223. package/out/base-prompts/skills/openclaw/scripts/run-smoke.sh +0 -61
  224. package/out/base-prompts/skills/pdf/LICENSE.txt +0 -30
  225. package/out/base-prompts/skills/pdf/SKILL.md +0 -294
  226. package/out/base-prompts/skills/pdf/forms.md +0 -205
  227. package/out/base-prompts/skills/pdf/reference.md +0 -612
  228. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  229. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  230. package/out/base-prompts/skills/pdf/scripts/check_fillable_fields.py +0 -12
  231. package/out/base-prompts/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  232. package/out/base-prompts/skills/pdf/scripts/create_validation_image.py +0 -41
  233. package/out/base-prompts/skills/pdf/scripts/extract_form_field_info.py +0 -152
  234. package/out/base-prompts/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  235. package/out/base-prompts/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  236. package/out/base-prompts/skills/pptx/LICENSE.txt +0 -30
  237. package/out/base-prompts/skills/pptx/SKILL.md +0 -484
  238. package/out/base-prompts/skills/pptx/html2pptx.md +0 -625
  239. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  240. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  241. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  242. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  243. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  244. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  245. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  246. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  247. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  248. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  249. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  250. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  251. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  252. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  253. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  254. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  255. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  256. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  257. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  258. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  259. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  260. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  261. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  262. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  263. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  264. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  265. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  266. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  267. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  268. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  269. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  270. package/out/base-prompts/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  271. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  272. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  273. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  274. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  275. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  276. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  277. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  278. package/out/base-prompts/skills/pptx/ooxml/scripts/pack.py +0 -159
  279. package/out/base-prompts/skills/pptx/ooxml/scripts/unpack.py +0 -29
  280. package/out/base-prompts/skills/pptx/ooxml/scripts/validate.py +0 -69
  281. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  282. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  283. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  284. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  285. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  286. package/out/base-prompts/skills/pptx/ooxml.md +0 -427
  287. package/out/base-prompts/skills/pptx/scripts/html2pptx.js +0 -984
  288. package/out/base-prompts/skills/pptx/scripts/inventory.py +0 -1020
  289. package/out/base-prompts/skills/pptx/scripts/rearrange.py +0 -231
  290. package/out/base-prompts/skills/pptx/scripts/replace.py +0 -385
  291. package/out/base-prompts/skills/pptx/scripts/thumbnail.py +0 -450
  292. package/out/base-prompts/skills/prompt-lab/SKILL.md +0 -149
  293. package/out/base-prompts/skills/prompt-lab/scripts/query-analytics.sh +0 -2551
  294. package/out/base-prompts/skills/skill-creator/LICENSE.txt +0 -202
  295. package/out/base-prompts/skills/skill-creator/SKILL.md +0 -371
  296. package/out/base-prompts/skills/skill-creator/references/output-patterns.md +0 -82
  297. package/out/base-prompts/skills/skill-creator/references/workflows.md +0 -28
  298. package/out/base-prompts/skills/skill-creator/scripts/init_skill.py +0 -303
  299. package/out/base-prompts/skills/skill-creator/scripts/package_skill.py +0 -110
  300. package/out/base-prompts/skills/skill-creator/scripts/quick_validate.py +0 -95
  301. package/out/base-prompts/skills/skill-installer/SKILL.md +0 -251
  302. package/out/base-prompts/skills/skill-installer/references/store-api.md +0 -219
  303. package/out/base-prompts/skills/spotlight-dashboard/SKILL.md +0 -83
  304. package/out/base-prompts/skills/spotlight-insights/SKILL.md +0 -101
  305. package/out/base-prompts/skills/spotlight-optimize/SKILL.md +0 -93
  306. package/out/base-prompts/skills/spotlight-optimize/scripts/query-analytics.sh +0 -2551
  307. package/out/base-prompts/skills/spotlight-query/SKILL.md +0 -314
  308. package/out/base-prompts/skills/spotlight-query/references/otel-schema.md +0 -163
  309. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.sh +0 -2551
  310. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.test.sh +0 -744
  311. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/sessions/sess-test-1.jsonl +0 -14
  312. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/.duckdb-index.json +0 -7
  313. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/sample.jsonl +0 -5
  314. package/out/base-prompts/skills/spotlight-report/SKILL.md +0 -86
  315. package/out/base-prompts/skills/spotlight-visualize/SKILL.md +0 -92
  316. package/out/base-prompts/skills/spotlight-visualize/scripts/query-analytics.sh +0 -2551
  317. package/out/base-prompts/skills/xlsx/LICENSE.txt +0 -30
  318. package/out/base-prompts/skills/xlsx/SKILL.md +0 -289
  319. package/out/base-prompts/skills/xlsx/recalc.py +0 -178
  320. package/out/branding.js +0 -49
  321. package/out/cli/commands/anywhere.js +0 -66
  322. package/out/cli/commands/ask.js +0 -246
  323. package/out/cli/commands/auth-broker.js +0 -24
  324. package/out/cli/commands/auth.js +0 -219
  325. package/out/cli/commands/chat.js +0 -357
  326. package/out/cli/commands/conformance.js +0 -249
  327. package/out/cli/commands/data-plane.js +0 -151
  328. package/out/cli/commands/deploy.js +0 -263
  329. package/out/cli/commands/gateway.js +0 -218
  330. package/out/cli/commands/idp.js +0 -85
  331. package/out/cli/commands/pack.js +0 -399
  332. package/out/cli/commands/probe-custom-engine.js +0 -82
  333. package/out/cli/commands/sandbox.js +0 -351
  334. package/out/cli/commands/serve.js +0 -1950
  335. package/out/cli/commands/store.js +0 -927
  336. package/out/cli/credential-context.js +0 -108
  337. package/out/cli/data-plane/broker.js +0 -78
  338. package/out/cli/data-plane/connector-host.js +0 -121
  339. package/out/cli/data-plane/egress.js +0 -189
  340. package/out/cli/data-plane/gateway.js +0 -218
  341. package/out/cli/data-plane/index.js +0 -153
  342. package/out/cli/data-plane/registry.js +0 -89
  343. package/out/cli/data-plane/remote.js +0 -106
  344. package/out/cli/data-plane/sidecar.js +0 -225
  345. package/out/cli/deploy/blueprints/registry.js +0 -84
  346. package/out/cli/deploy/layers/identity.js +0 -175
  347. package/out/cli/deploy-init.js +0 -3023
  348. package/out/cli/deps.js +0 -342
  349. package/out/cli/idp-init.js +0 -338
  350. package/out/cli/pack-install-ref.js +0 -15
  351. package/out/cli/pack-loader.js +0 -418
  352. package/out/cli/pack-runtime.js +0 -61
  353. package/out/cli/runtime.js +0 -450
  354. package/out/cli/serve-hardening.js +0 -776
  355. package/out/cli/state-sync.js +0 -424
  356. package/out/cli/utils.js +0 -231
  357. package/out/engines/base.js +0 -188
  358. package/out/engines/claude.js +0 -1254
  359. package/out/engines/codex.js +0 -862
  360. package/out/engines/custom.js +0 -680
  361. package/out/engines/customEngineIpc.js +0 -95
  362. package/out/engines/customEngineRunnerEmbed.js +0 -107
  363. package/out/engines/customRegistry.js +0 -274
  364. package/out/engines/embeddedCustomEngineRunner.generated.js +0 -9
  365. package/out/engines/engineApiKey.js +0 -138
  366. package/out/engines/install.js +0 -372
  367. package/out/engines/persistentEngineWorker.js +0 -320
  368. package/out/engines/publish.js +0 -341
  369. package/out/evidence/sessionShip.js +0 -643
  370. package/out/gateway/bridge.js +0 -843
  371. package/out/gateway/cli-agent-id.js +0 -36
  372. package/out/gateway/client.js +0 -336
  373. package/out/gateway/client.test.js +0 -395
  374. package/out/gateway/gateway-scope-errors.js +0 -14
  375. package/out/gateway/gatewayBackup.js +0 -76
  376. package/out/gateway/installSource.js +0 -68
  377. package/out/gateway/lifecycle.js +0 -3190
  378. package/out/gateway/openclaw-channel-routing.js +0 -317
  379. package/out/gateway/outboundHandles.js +0 -373
  380. package/out/gateway/outboundPaths.js +0 -75
  381. package/out/gateway/outboundSend.js +0 -254
  382. package/out/gateway/protocol.js +0 -48
  383. package/out/gateway/secretsPreflight.js +0 -90
  384. package/out/gateway/sessionRouting.js +0 -77
  385. package/out/headless/index.js +0 -546
  386. package/out/headless/sync.js +0 -473
  387. package/out/live-e2e/mcp-demo/server.mjs +0 -32
  388. package/out/live-probe/connector.mjs +0 -8
  389. package/out/live-probe/env-report.mjs +0 -8
  390. package/out/mcp.js +0 -654
  391. package/out/pack/caps.js +0 -271
  392. package/out/pack/governor.js +0 -326
  393. package/out/pack/lease-schema.js +0 -273
  394. package/out/pack/lease.js +0 -682
  395. package/out/pack/reconcile.js +0 -217
  396. package/out/pack/signature.js +0 -839
  397. package/out/permissions.js +0 -108
  398. package/out/permissions.mapping.yaml +0 -68
  399. package/out/registry/index.js +0 -332
  400. package/out/runner/host.js +0 -141
  401. package/out/runner/protocol.js +0 -128
  402. package/out/runner/remoteEngine.js +0 -166
  403. package/out/runtime/interfaces/config-provider.js +0 -32
  404. package/out/runtime/interfaces/edit-tracker.js +0 -24
  405. package/out/runtime/interfaces/index.js +0 -29
  406. package/out/runtime/interfaces/logger.js +0 -40
  407. package/out/runtime/interfaces/permission-handler.js +0 -66
  408. package/out/runtime/interfaces/session-store.js +0 -342
  409. package/out/runtime/vscode/vscode-session-store.js +0 -22
  410. package/out/sandbox/containerDriver.js +0 -572
  411. package/out/sandbox/processDriver.js +0 -318
  412. package/out/sandbox/sandboxRunner.js +0 -303
  413. package/out/sandbox/support.js +0 -301
  414. package/out/sandbox/types.js +0 -55
  415. package/out/scripts/analytics/fleet-local-adapter.js +0 -246
  416. package/out/scripts/analytics/live-fleet-4-collector.cjs +0 -315
  417. package/out/scripts/analytics/live-fleet-4-daemon.mjs +0 -134
  418. package/out/scripts/analytics/live-fleet-4-widget.cjs +0 -433
  419. package/out/scripts/gateway/Dockerfile.serve +0 -45
  420. package/out/scripts/gateway/docker-serve.sh +0 -248
  421. package/out/scripts/gateway/setup-gateway-server.ps1 +0 -953
  422. package/out/scripts/gateway/setup-gateway-server.sh +0 -935
  423. package/out/session.js +0 -272
  424. package/out/shared/agentEngines.js +0 -170
  425. package/out/shared/index.js +0 -109
  426. package/out/shared/models.js +0 -136
  427. package/out/shared/providers.js +0 -205
  428. package/out/spotlight/install.js +0 -345
  429. package/out/spotlight/publish.js +0 -544
  430. package/out/spotlight/yaml.js +0 -31
  431. package/out/store/index.js +0 -786
  432. package/out/store/shared.js +0 -241
  433. package/out/test/agentEnvFile.test.js +0 -97
  434. package/out/test/agentYaml.test.js +0 -373
  435. package/out/test/agentpack.test.js +0 -639
  436. package/out/test/analytics-lifecycle.test.js +0 -174
  437. package/out/test/analytics.test.js +0 -756
  438. package/out/test/auth-baseurl.test.js +0 -132
  439. package/out/test/auth-bootstrapApply.test.js +0 -123
  440. package/out/test/auth-broker-hardening.test.js +0 -227
  441. package/out/test/auth-broker.test.js +0 -541
  442. package/out/test/auth-callback.test.js +0 -62
  443. package/out/test/blueprint-registry.test.js +0 -105
  444. package/out/test/branding.test.js +0 -242
  445. package/out/test/caps-governor.test.js +0 -460
  446. package/out/test/cli-agent-id.test.js +0 -55
  447. package/out/test/codex-new-file-survival.test.js +0 -119
  448. package/out/test/configuration-scopes.test.js +0 -131
  449. package/out/test/credential-context.test.js +0 -160
  450. package/out/test/custom-env-layering.test.js +0 -151
  451. package/out/test/customEngineInstall.test.js +0 -100
  452. package/out/test/customRegistry.test.js +0 -122
  453. package/out/test/data-plane-engine-wiring.test.js +0 -282
  454. package/out/test/data-plane.test.js +0 -624
  455. package/out/test/deploy-init.test.js +0 -860
  456. package/out/test/deps-auto-install.test.js +0 -81
  457. package/out/test/egress-broker.test.js +0 -172
  458. package/out/test/engine-integration.test.js +0 -297
  459. package/out/test/enginePaths.test.js +0 -195
  460. package/out/test/enginePublish.test.js +0 -82
  461. package/out/test/fleetDisplayUtils.test.js +0 -100
  462. package/out/test/gateway-client.test.js +0 -409
  463. package/out/test/gateway-install-source.test.js +0 -111
  464. package/out/test/gateway-lifecycle.test.js +0 -608
  465. package/out/test/gateway-outbound.test.js +0 -538
  466. package/out/test/gateway-reset-mappings.test.js +0 -221
  467. package/out/test/gateway-route-index.test.js +0 -235
  468. package/out/test/gateway-secrets-preflight.test.js +0 -127
  469. package/out/test/gateway-session-routing.test.js +0 -65
  470. package/out/test/gateway-session-store.test.js +0 -216
  471. package/out/test/github.test.js +0 -232
  472. package/out/test/governor-hardening.test.js +0 -222
  473. package/out/test/headless-sync.test.js +0 -301
  474. package/out/test/helpers/manifest-fixtures.js +0 -27
  475. package/out/test/idp-init.test.js +0 -151
  476. package/out/test/lease-signature.test.js +0 -357
  477. package/out/test/lease-trust-root.test.js +0 -273
  478. package/out/test/lease-validation.test.js +0 -224
  479. package/out/test/lease.test.js +0 -114
  480. package/out/test/localFleetAdapter.test.js +0 -91
  481. package/out/test/mcp-obo.test.js +0 -107
  482. package/out/test/mcp.test.js +0 -389
  483. package/out/test/model-routing.test.js +0 -133
  484. package/out/test/openclaw-channel-routing.test.js +0 -191
  485. package/out/test/pack-admission.test.js +0 -216
  486. package/out/test/pack-digest-parity.test.js +0 -140
  487. package/out/test/pack-reconcile.test.js +0 -183
  488. package/out/test/pack-signature-artifact.test.js +0 -103
  489. package/out/test/pack-signature.test.js +0 -176
  490. package/out/test/pack-trust-root.test.js +0 -202
  491. package/out/test/pathSafety.test.js +0 -63
  492. package/out/test/permissions.test.js +0 -175
  493. package/out/test/persistent-engine-worker.test.js +0 -220
  494. package/out/test/refreshPolicy.test.js +0 -60
  495. package/out/test/registry.test.js +0 -351
  496. package/out/test/remote-trust.test.js +0 -242
  497. package/out/test/runner-protocol.test.js +0 -249
  498. package/out/test/runtime.test.js +0 -349
  499. package/out/test/sandbox-driver.test.js +0 -553
  500. package/out/test/sandbox-hardening.test.js +0 -406
  501. package/out/test/sandbox-runner.test.js +0 -343
  502. package/out/test/sandbox-scope.test.js +0 -449
  503. package/out/test/scheduledFleetStorage.test.js +0 -72
  504. package/out/test/serve-cron-acceptance.test.js +0 -370
  505. package/out/test/serve-gateway-turn.test.js +0 -389
  506. package/out/test/serve-hardening.test.js +0 -591
  507. package/out/test/serveClient.test.js +0 -209
  508. package/out/test/sessionJsonlFleet.test.js +0 -78
  509. package/out/test/sessionShip.test.js +0 -618
  510. package/out/test/shared.test.js +0 -173
  511. package/out/test/skills-mcp.test.js +0 -299
  512. package/out/test/spotlightPublish.test.js +0 -327
  513. package/out/test/spotlightYaml.test.js +0 -58
  514. package/out/test/state-sync-peer.test.js +0 -156
  515. package/out/test/store-install-safe.test.js +0 -69
  516. package/out/test/store.test.js +0 -331
  517. package/out/test/stores.test.js +0 -504
  518. package/out/test/sync-switch.test.js +0 -251
  519. package/out/test/teamViewDiscovery.test.js +0 -90
  520. package/out/test/tls-bypass.test.js +0 -90
  521. package/out/test/toolPath.test.js +0 -120
  522. package/out/test/utils.test.js +0 -308
  523. package/out/test/viewsConfigMerge.test.js +0 -180
  524. package/out/test/warrant.test.js +0 -138
  525. package/out/test/windows-command-line.test.js +0 -75
  526. package/out/utils/agentEnvFile.js +0 -131
  527. package/out/utils/binary.js +0 -175
  528. package/out/utils/index.js +0 -37
  529. package/out/utils/network.js +0 -74
  530. package/out/utils/paths.js +0 -116
  531. package/out/utils/pid.js +0 -180
  532. package/out/utils/resolveNodeBinary.js +0 -168
  533. package/out/utils/windowsCommandLine.js +0 -29
  534. package/out/utils.js +0 -968
@@ -1,27 +1,5 @@
1
- #---------------------------------------------------------------------------------------------
2
- # Copyright (c) AgentHippo.ai. All rights reserved.
3
- # Licensed under the MIT License. See LICENSE.txt in the project root for license information.
4
- #---------------------------------------------------------------------------------------------
5
- """
6
- AgentIDE LiteLLM proxy hooks - Clean structured assistant output with separate input/output
7
- Mimics langfuse_otel style: gen_ai.input.messages (history) + gen_ai.output.messages (new reply only)
8
-
9
- Usage in litellm config.yaml:
10
- callbacks: ["agentide_litellm_hooks_v1.clean_separated_otel_output"]
11
-
12
- PRIVACY DEFAULT (PLAN/compliance-req.md §6 "data minimization"):
13
- Prompt and completion CONTENT is NOT captured unless an operator opts in with
14
-
15
- AGENTHIPPO_EVIDENCE_CONTENT_CAPTURE=1
16
-
17
- Without the opt-in every span carries metadata only — model, tokens, latency, status — plus a
18
- sha256 + byte length of the content so a later disclosure can still be *matched* against a
19
- span without the span holding the text. This is enforced here at span-write time, in addition
20
- to `turn_off_message_logging: true` in the config, so a config that re-enables message logging
21
- without the env opt-in still produces redacted spans (defence in depth: the config is edited by
22
- hand far more often than this file).
23
- """
24
-
1
+ # Copyright (c) 2026 AgentHippo.ai. All rights reserved.
2
+ # Proprietary and confidential. See LICENSE.
25
3
  from __future__ import annotations
26
4
  from typing import Any
27
5
  import ast
@@ -30,88 +8,33 @@ import json
30
8
  import os
31
9
  import re
32
10
  import sys
33
-
34
11
  from litellm.integrations.custom_logger import CustomLogger
35
12
  from litellm.integrations.opentelemetry import OpenTelemetry
36
13
  from opentelemetry.trace import Status, StatusCode
37
-
38
- _OTEL_TEXT_MAX_LEN = 4000 # per text block
39
- _OTEL_PREVIEW_LEN = 180 # short preview in event
40
-
41
- # -----------------------------------------------------------------------------
42
- # Content capture opt-in (fix: full capture used to be the default)
43
- # -----------------------------------------------------------------------------
44
-
45
- CONTENT_CAPTURE_ENV = "AGENTHIPPO_EVIDENCE_CONTENT_CAPTURE"
46
-
47
- _TRUTHY = frozenset({"1", "true", "yes", "on"})
48
-
49
- # Span attributes that can carry prompt/completion text. Mirrors CONTENT_ATTRS in
50
- # @agenthippo-ai/evidence-ship so the two redaction points cannot drift silently.
51
- _CONTENT_ATTR_RE = re.compile(
52
- r"^(gen_ai\.(input|output)\.messages"
53
- r"|gen_ai\.(prompt|completion)"
54
- r"|gen_ai\.system_instructions"
55
- r"|llm\.(prompts|responses)"
56
- r"|llm\.request\.functions\."
57
- r"|error\.(message|stack_trace)"
58
- r"|hidden_params"
59
- r"|metadata\.requester_custom_headers)"
60
- )
61
-
14
+ _OTEL_TEXT_MAX_LEN = 4000
15
+ _OTEL_PREVIEW_LEN = 180
16
+ CONTENT_CAPTURE_ENV = 'AGENTHIPPO_EVIDENCE_CONTENT_CAPTURE'
17
+ _TRUTHY = frozenset({'1', 'true', 'yes', 'on'})
18
+ _CONTENT_ATTR_RE = re.compile('^(gen_ai\\.(input|output)\\.messages|gen_ai\\.(prompt|completion)|gen_ai\\.system_instructions|llm\\.(prompts|responses)|llm\\.request\\.functions\\.|error\\.(message|stack_trace)|hidden_params|metadata\\.requester_custom_headers)')
62
19
  _capture_banner_printed = False
63
20
 
64
-
65
21
  def _content_capture_enabled() -> bool:
66
- """True only when an operator explicitly opted in to prompt/completion capture."""
67
- return (os.environ.get(CONTENT_CAPTURE_ENV, "") or "").strip().lower() in _TRUTHY
68
-
22
+ return (os.environ.get(CONTENT_CAPTURE_ENV, '') or '').strip().lower() in _TRUTHY
69
23
 
70
24
  def _announce_content_capture() -> None:
71
- """Log loudly, once, whichever mode is in force — silence is how this got shipped on."""
72
25
  global _capture_banner_printed
73
26
  if _capture_banner_printed:
74
27
  return
75
28
  _capture_banner_printed = True
76
29
  if _content_capture_enabled():
77
- print(
78
- "\n"
79
- "!! AGENTHIPPO EVIDENCE: FULL PROMPT/COMPLETION CAPTURE IS ON !!\n"
80
- f"!! {CONTENT_CAPTURE_ENV} is set. Every span will carry prompt and completion text.\n"
81
- "!! Unset it to return to metadata-only (sha256 + length) spans.\n",
82
- file=sys.stderr,
83
- flush=True,
84
- )
30
+ print(f'\n!! AGENTHIPPO EVIDENCE: FULL PROMPT/COMPLETION CAPTURE IS ON !!\n!! {CONTENT_CAPTURE_ENV} is set. Every span will carry prompt and completion text.\n!! Unset it to return to metadata-only (sha256 + length) spans.\n', file=sys.stderr, flush=True)
85
31
  else:
86
- print(
87
- f"[agentide-otel] content capture OFF (metadata + sha256 only). "
88
- f"Set {CONTENT_CAPTURE_ENV}=1 to record prompts/completions.",
89
- file=sys.stderr,
90
- flush=True,
91
- )
92
-
32
+ print(f'[agentide-otel] content capture OFF (metadata + sha256 only). Set {CONTENT_CAPTURE_ENV}=1 to record prompts/completions.', file=sys.stderr, flush=True)
93
33
 
94
34
  def _sha256(text: str) -> str:
95
- return hashlib.sha256(text.encode("utf-8", "replace")).hexdigest()
96
-
97
-
98
- # Correlation IDs Spotlight reads from the requester header blob (see FLEET_DATA_CONTRACT.md).
99
- # These are minted by AgentHippo clients and carry no user content, so with capture off the
100
- # blob is reduced to exactly these keys rather than dropped — unknown x-* headers from clients
101
- # we do not control (e.g. x-api-key) still never reach the span in plaintext.
102
- _METADATA_HEADERS_KEY = "metadata.requester_custom_headers"
103
-
104
- _METADATA_HEADER_ALLOWLIST = frozenset({
105
- "x-litellm-metadata-session-id",
106
- "x-litellm-metadata-request-id",
107
- "x-litellm-metadata-user-id",
108
- "x-litellm-metadata-project-id",
109
- "x-litellm-metadata-agent-id",
110
- "x-litellm-metadata-agent-version",
111
- "x-litellm-metadata-source",
112
- "x-litellm-metadata-engine",
113
- })
114
-
35
+ return hashlib.sha256(text.encode('utf-8', 'replace')).hexdigest()
36
+ _METADATA_HEADERS_KEY = 'metadata.requester_custom_headers'
37
+ _METADATA_HEADER_ALLOWLIST = frozenset({'x-litellm-metadata-session-id', 'x-litellm-metadata-request-id', 'x-litellm-metadata-user-id', 'x-litellm-metadata-project-id', 'x-litellm-metadata-agent-id', 'x-litellm-metadata-agent-version', 'x-litellm-metadata-source', 'x-litellm-metadata-engine'})
115
38
 
116
39
  def _parse_attr_dict(value: Any) -> Any:
117
40
  if not isinstance(value, str):
@@ -124,58 +47,31 @@ def _parse_attr_dict(value: Any) -> Any:
124
47
  except ValueError:
125
48
  return None
126
49
 
127
-
128
50
  def _allowlisted_headers(headers: dict) -> dict:
129
- return {
130
- k.lower(): v for k, v in headers.items()
131
- if isinstance(k, str) and k.lower() in _METADATA_HEADER_ALLOWLIST
132
- }
133
-
51
+ return {k.lower(): v for k, v in headers.items() if isinstance(k, str) and k.lower() in _METADATA_HEADER_ALLOWLIST}
134
52
 
135
53
  def _filtered_metadata_headers(value: Any) -> str | None:
136
- """Reduce the header blob to allowlisted keys, keeping the str(dict) repr format that
137
- the DuckDB extraction regexes parse. None when nothing allowlisted survives."""
138
54
  headers = _parse_attr_dict(value)
139
55
  if not isinstance(headers, dict):
140
56
  return None
141
57
  kept = _allowlisted_headers(headers)
142
58
  return str(kept) if kept else None
143
-
144
-
145
- # LiteLLM also embeds the raw request headers as metadata.requester_metadata['headers'] on some
146
- # routes (observed on /v1/chat/completions; absent on /v1/messages). The attribute's scalar keys
147
- # (session_id, request_id, …) are a fallback landing spot the extraction chain parses, so the
148
- # attribute itself must survive — only its embedded header dict gets the allowlist treatment.
149
- _REQUESTER_METADATA_KEY = "metadata.requester_metadata"
150
-
59
+ _REQUESTER_METADATA_KEY = 'metadata.requester_metadata'
151
60
 
152
61
  def _scrub_requester_metadata(value: Any) -> Any:
153
- """Scrubbed value, or None (caller drops the attribute) when an embedded header dict
154
- cannot be safely isolated — reprs with non-literal values defeat ast.literal_eval, and
155
- passing those through unparsed would leak the very headers this exists to remove."""
156
62
  md = _parse_attr_dict(value)
157
- if isinstance(md, dict) and isinstance(md.get("headers"), dict):
158
- return str({**md, "headers": _allowlisted_headers(md["headers"])})
63
+ if isinstance(md, dict) and isinstance(md.get('headers'), dict):
64
+ return str({**md, 'headers': _allowlisted_headers(md['headers'])})
159
65
  if isinstance(md, dict):
160
66
  return value
161
- return None if "headers" in str(value) else value
162
-
67
+ return None if 'headers' in str(value) else value
163
68
 
164
69
  class _RedactingSpan:
165
- """
166
- Span proxy that drops content-bearing attributes and replaces them with a sha256 + length.
167
-
168
- LiteLLM's own `set_attributes()` writes `gen_ai.input.messages` (the full history) and
169
- friends. We cannot remove an attribute after the SDK has recorded it, so the only place to
170
- stop it is between LiteLLM and the SDK — here. Everything that is not content passes through
171
- untouched, so the span keeps model, tokens, latency, status, and the requester metadata the
172
- evidence index reads.
173
- """
174
70
 
175
71
  def __init__(self, span: Any) -> None:
176
72
  self._span = span
177
73
 
178
- def __getattr__(self, name: str) -> Any: # everything we do not override
74
+ def __getattr__(self, name: str) -> Any:
179
75
  return getattr(self._span, name)
180
76
 
181
77
  def set_attribute(self, key: Any, value: Any) -> Any:
@@ -186,9 +82,9 @@ class _RedactingSpan:
186
82
  return self._span.set_attribute(key, scrubbed)
187
83
  if isinstance(key, str) and _CONTENT_ATTR_RE.match(key):
188
84
  text = value if isinstance(value, str) else json.dumps(value, ensure_ascii=False, default=str)
189
- self._span.set_attribute(f"{key}.sha256", _sha256(text))
190
- self._span.set_attribute(f"{key}.length", len(text))
191
- self._span.set_attribute(f"{key}.redacted", True)
85
+ self._span.set_attribute(f'{key}.sha256', _sha256(text))
86
+ self._span.set_attribute(f'{key}.length', len(text))
87
+ self._span.set_attribute(f'{key}.redacted', True)
192
88
  if key == _METADATA_HEADERS_KEY:
193
89
  kept = _filtered_metadata_headers(value)
194
90
  if kept is not None:
@@ -203,7 +99,7 @@ class _RedactingSpan:
203
99
  return None
204
100
  return self._span.set_attributes(attributes)
205
101
 
206
- def add_event(self, name: Any, attributes: Any = None, **kwargs: Any) -> Any:
102
+ def add_event(self, name: Any, attributes: Any=None, **kwargs: Any) -> Any:
207
103
  if isinstance(attributes, dict):
208
104
  filtered = {}
209
105
  for key, value in attributes.items():
@@ -213,8 +109,8 @@ class _RedactingSpan:
213
109
  filtered[key] = scrubbed
214
110
  elif isinstance(key, str) and _CONTENT_ATTR_RE.match(key):
215
111
  text = value if isinstance(value, str) else json.dumps(value, ensure_ascii=False, default=str)
216
- filtered[f"{key}.sha256"] = _sha256(text)
217
- filtered[f"{key}.length"] = len(text)
112
+ filtered[f'{key}.sha256'] = _sha256(text)
113
+ filtered[f'{key}.length'] = len(text)
218
114
  if key == _METADATA_HEADERS_KEY:
219
115
  kept = _filtered_metadata_headers(value)
220
116
  if kept is not None:
@@ -224,18 +120,16 @@ class _RedactingSpan:
224
120
  attributes = filtered
225
121
  return self._span.add_event(name, attributes, **kwargs)
226
122
 
227
-
228
- def _read_field(obj: Any, key: str, default: Any = None) -> Any:
123
+ def _read_field(obj: Any, key: str, default: Any=None) -> Any:
229
124
  if isinstance(obj, dict):
230
125
  return obj.get(key, default)
231
126
  return getattr(obj, key, default)
232
127
 
233
-
234
128
  def _content_blocks_to_text(content: Any) -> str:
235
129
  if isinstance(content, str):
236
130
  return content
237
131
  if not isinstance(content, (list, tuple)):
238
- return ""
132
+ return ''
239
133
  parts: list[str] = []
240
134
  for block in content:
241
135
  if isinstance(block, str):
@@ -244,90 +138,65 @@ def _content_blocks_to_text(content: Any) -> str:
244
138
  continue
245
139
  if not isinstance(block, dict):
246
140
  continue
247
- text = block.get("text") or block.get("output_text") or block.get("content")
141
+ text = block.get('text') or block.get('output_text') or block.get('content')
248
142
  if isinstance(text, str) and text.strip():
249
143
  parts.append(text)
250
- return "\n".join(parts)
251
-
144
+ return '\n'.join(parts)
252
145
 
253
146
  def _extract_assistant_text(response_obj: Any) -> str:
254
147
  if response_obj is None:
255
- return ""
256
- # OpenAI-style
257
- choices = _read_field(response_obj, "choices")
148
+ return ''
149
+ choices = _read_field(response_obj, 'choices')
258
150
  if isinstance(choices, list) and choices:
259
- msg = _read_field(choices[0], "message")
260
- content = _read_field(msg, "content")
151
+ msg = _read_field(choices[0], 'message')
152
+ content = _read_field(msg, 'content')
261
153
  text = _content_blocks_to_text(content)
262
154
  if text.strip():
263
155
  return text
264
- # Direct output fields
265
- for key in ("output_text", "content", "output", "text"):
156
+ for key in ('output_text', 'content', 'output', 'text'):
266
157
  val = _read_field(response_obj, key)
267
158
  if val:
268
159
  text = _content_blocks_to_text(val)
269
160
  if text.strip():
270
161
  return text
271
- return ""
272
-
162
+ return ''
273
163
 
274
164
  def _extract_text_from_success_kwargs(kwargs: dict) -> str:
275
- text = _extract_assistant_text(kwargs.get("response_obj"))
165
+ text = _extract_assistant_text(kwargs.get('response_obj'))
276
166
  if text:
277
167
  return text
278
- for k in ("complete_response", "model_response", "response", "original_response"):
168
+ for k in ('complete_response', 'model_response', 'response', 'original_response'):
279
169
  candidate = kwargs.get(k)
280
170
  if candidate:
281
171
  text = _extract_assistant_text(candidate)
282
172
  if text:
283
173
  return text
284
- return ""
285
-
174
+ return ''
286
175
 
287
176
  def _make_output_messages_structured(text: str) -> list:
288
177
  if not text.strip():
289
178
  return []
290
179
  trimmed = text[:_OTEL_TEXT_MAX_LEN]
291
- # Align with LiteLLM's GEN_AI_OUTPUT_MESSAGES shape: parts + inner content (not content + text).
292
- return [{"role": "assistant", "parts": [{"type": "text", "content": trimmed}]}]
293
-
180
+ return [{'role': 'assistant', 'parts': [{'type': 'text', 'content': trimmed}]}]
294
181
 
295
182
  def _model_name(model: Any) -> str:
296
- return model.lower() if isinstance(model, str) else ""
297
-
183
+ return model.lower() if isinstance(model, str) else ''
298
184
 
299
185
  def _is_reasoning_unsupported_model(model: Any) -> bool:
300
- """True when model is known to reject reasoning parameters."""
301
- return "gpt-4.1-nano" in _model_name(model)
302
-
186
+ return 'gpt-4.1-nano' in _model_name(model)
303
187
 
304
188
  def _is_anthropic_route(model: Any) -> bool:
305
- """True when the request will be forwarded to Anthropic."""
306
189
  name = _model_name(model)
307
- return "claude" in name or "anthropic" in name
308
-
309
-
310
- # Every model known to reject the Codex built-in web-search tools. Additive by policy: a
311
- # deployment that still routes to an older model keeps its sanitizer when a newer one is added,
312
- # because a dropped entry fails as upstream 400s on live traffic, not as a test failure.
313
- _WEB_SEARCH_UNSUPPORTED_MODELS = ("gpt-5.6-luna", "gpt-4.1-nano")
314
-
190
+ return 'claude' in name or 'anthropic' in name
191
+ _WEB_SEARCH_UNSUPPORTED_MODELS = ('gpt-5.6-luna', 'gpt-4.1-nano')
315
192
 
316
193
  def _is_web_search_unsupported_model(model: Any) -> bool:
317
- """True when the upstream model rejects Codex web-search tools."""
318
194
  name = _model_name(model)
319
- return any(m in name for m in _WEB_SEARCH_UNSUPPORTED_MODELS)
320
-
195
+ return any((m in name for m in _WEB_SEARCH_UNSUPPORTED_MODELS))
196
+ _OPENAI_RESPONSES_ONLY_KEYS = ('client_metadata',)
197
+ _UNSUPPORTED_TOOL_IDENTIFIERS = frozenset({'web_search_preview', 'web_search'})
321
198
 
322
- # OpenAI Responses API fields that Anthropic (and some gateways) reject if forwarded verbatim.
323
- _OPENAI_RESPONSES_ONLY_KEYS = ("client_metadata",)
324
-
325
- # Codex built-in tools not supported on all OpenAI models.
326
- _UNSUPPORTED_TOOL_IDENTIFIERS = frozenset({"web_search_preview", "web_search"})
327
-
328
-
329
- def _strip_key_recursive(data: Any, key: str, _visited: set[int] | None = None) -> None:
330
- """Remove a key in nested dict/list payloads (bounded; avoids cyclic graphs)."""
199
+ def _strip_key_recursive(data: Any, key: str, _visited: set[int] | None=None) -> None:
331
200
  if _visited is None:
332
201
  _visited = set()
333
202
  if isinstance(data, dict):
@@ -347,58 +216,49 @@ def _strip_key_recursive(data: Any, key: str, _visited: set[int] | None = None)
347
216
  for item in data:
348
217
  _strip_key_recursive(item, key, _visited)
349
218
 
350
-
351
219
  def _resolve_route_model(payload: dict, model: Any) -> str:
352
220
  name = _model_name(model)
353
221
  if name:
354
222
  return name
355
- for candidate in (
356
- payload.get("model"),
357
- payload.get("model_group"),
358
- payload.get("model_name"),
359
- payload.get("deployment"),
360
- ):
223
+ for candidate in (payload.get('model'), payload.get('model_group'), payload.get('model_name'), payload.get('deployment')):
361
224
  name = _model_name(candidate)
362
225
  if name:
363
226
  return name
364
- metadata = payload.get("metadata")
227
+ metadata = payload.get('metadata')
365
228
  if isinstance(metadata, dict):
366
- for candidate in (metadata.get("model_group"), metadata.get("model")):
229
+ for candidate in (metadata.get('model_group'), metadata.get('model')):
367
230
  name = _model_name(candidate)
368
231
  if name:
369
232
  return name
370
- return ""
371
-
233
+ return ''
372
234
 
373
235
  def _tool_is_unsupported(tool: Any) -> bool:
374
236
  if not isinstance(tool, dict):
375
237
  return False
376
- tool_type = tool.get("type")
238
+ tool_type = tool.get('type')
377
239
  if isinstance(tool_type, str) and tool_type in _UNSUPPORTED_TOOL_IDENTIFIERS:
378
240
  return True
379
- name = tool.get("name")
241
+ name = tool.get('name')
380
242
  if isinstance(name, str) and name in _UNSUPPORTED_TOOL_IDENTIFIERS:
381
243
  return True
382
- fn = tool.get("function")
244
+ fn = tool.get('function')
383
245
  if isinstance(fn, dict):
384
- fn_name = fn.get("name")
246
+ fn_name = fn.get('name')
385
247
  if isinstance(fn_name, str) and fn_name in _UNSUPPORTED_TOOL_IDENTIFIERS:
386
248
  return True
387
249
  return False
388
250
 
389
-
390
251
  def _strip_unsupported_tools(data: dict) -> None:
391
- tools = data.get("tools")
252
+ tools = data.get('tools')
392
253
  if not isinstance(tools, list):
393
254
  return
394
255
  filtered = [tool for tool in tools if not _tool_is_unsupported(tool)]
395
256
  if len(filtered) == len(tools):
396
257
  return
397
258
  if filtered:
398
- data["tools"] = filtered
259
+ data['tools'] = filtered
399
260
  else:
400
- data.pop("tools", None)
401
-
261
+ data.pop('tools', None)
402
262
 
403
263
  def _apply_codex_proxy_sanitizers(data: dict, model: Any) -> None:
404
264
  route_model = _resolve_route_model(data, model)
@@ -408,14 +268,7 @@ def _apply_codex_proxy_sanitizers(data: dict, model: Any) -> None:
408
268
  if _is_web_search_unsupported_model(route_model):
409
269
  _strip_unsupported_tools(data)
410
270
 
411
-
412
- def _strip_unsupported_reasoning_params(data: Any, _visited: set[int] | None = None) -> None:
413
- """
414
- Mutates `data` in-place by removing unsupported reasoning controls.
415
-
416
- OpenAI's API error reports `reasoning.effort`, but the payload is sent as:
417
- { "reasoning": { "effort": ... } }
418
- """
271
+ def _strip_unsupported_reasoning_params(data: Any, _visited: set[int] | None=None) -> None:
419
272
  if _visited is None:
420
273
  _visited = set()
421
274
  if isinstance(data, dict):
@@ -423,8 +276,8 @@ def _strip_unsupported_reasoning_params(data: Any, _visited: set[int] | None = N
423
276
  if obj_id in _visited:
424
277
  return
425
278
  _visited.add(obj_id)
426
- data.pop("reasoning", None)
427
- data.pop("reasoning_effort", None)
279
+ data.pop('reasoning', None)
280
+ data.pop('reasoning_effort', None)
428
281
  for v in list(data.values()):
429
282
  _strip_unsupported_reasoning_params(v, _visited)
430
283
  return
@@ -436,412 +289,227 @@ def _strip_unsupported_reasoning_params(data: Any, _visited: set[int] | None = N
436
289
  for item in data:
437
290
  _strip_unsupported_reasoning_params(item, _visited)
438
291
 
439
-
440
292
  def _extract_text_content(message: dict[str, Any]) -> str:
441
- """Extract text content from OpenAI-style message content."""
442
- content = message.get("content")
293
+ content = message.get('content')
443
294
  if isinstance(content, str):
444
295
  return content
445
296
  if not isinstance(content, list):
446
- return ""
297
+ return ''
447
298
  parts: list[str] = []
448
299
  for block in content:
449
- if isinstance(block, dict) and block.get("type") == "text":
450
- text = block.get("text")
300
+ if isinstance(block, dict) and block.get('type') == 'text':
301
+ text = block.get('text')
451
302
  if isinstance(text, str) and text.strip():
452
303
  parts.append(text)
453
- return "\n".join(parts)
454
-
304
+ return '\n'.join(parts)
455
305
 
456
306
  def _set_text_content(message: dict[str, Any], text: str) -> None:
457
- """Set text content while preserving existing content shape when possible."""
458
- content = message.get("content")
307
+ content = message.get('content')
459
308
  if isinstance(content, list):
460
- # Keep non-text blocks and append merged text as final text block.
461
- preserved = [b for b in content if not (isinstance(b, dict) and b.get("type") == "text")]
309
+ preserved = [b for b in content if not (isinstance(b, dict) and b.get('type') == 'text')]
462
310
  if text.strip():
463
- preserved.append({"type": "text", "text": text})
464
- message["content"] = preserved
311
+ preserved.append({'type': 'text', 'text': text})
312
+ message['content'] = preserved
465
313
  return
466
- message["content"] = text
467
-
314
+ message['content'] = text
468
315
 
469
316
  def _is_text_only_assistant(message: Any) -> bool:
470
- """True when assistant message has text and no tool calls."""
471
- if not isinstance(message, dict) or message.get("role") != "assistant":
317
+ if not isinstance(message, dict) or message.get('role') != 'assistant':
472
318
  return False
473
- tool_calls = message.get("tool_calls")
319
+ tool_calls = message.get('tool_calls')
474
320
  if isinstance(tool_calls, list) and len(tool_calls) > 0:
475
321
  return False
476
322
  return bool(_extract_text_content(message).strip())
477
323
 
478
-
479
324
  def _tool_result_ids_from_message(message: Any) -> set[str]:
480
- """Collect tool result ids from OpenAI or Anthropic-style tool result messages."""
481
325
  if not isinstance(message, dict):
482
326
  return set()
483
-
484
- role = message.get("role")
485
- if role == "tool":
486
- tool_call_id = message.get("tool_call_id")
327
+ role = message.get('role')
328
+ if role == 'tool':
329
+ tool_call_id = message.get('tool_call_id')
487
330
  return {tool_call_id} if isinstance(tool_call_id, str) and tool_call_id else set()
488
-
489
- content = message.get("content")
331
+ content = message.get('content')
490
332
  if not isinstance(content, list):
491
333
  return set()
492
334
  ids: set[str] = set()
493
335
  for block in content:
494
- if isinstance(block, dict) and block.get("type") == "tool_result":
495
- tool_use_id = block.get("tool_use_id")
336
+ if isinstance(block, dict) and block.get('type') == 'tool_result':
337
+ tool_use_id = block.get('tool_use_id')
496
338
  if isinstance(tool_use_id, str) and tool_use_id:
497
339
  ids.add(tool_use_id)
498
340
  return ids
499
341
 
500
-
501
342
  def sanitize_messages(messages: Any) -> Any:
502
- """
503
- Lightweight tool-order sanitizer for Codex/OpenAI-style tool calls.
504
-
505
- Ensures assistant tool calls are followed immediately by tool results.
506
- If text-only assistant messages appear between tool call and tool result,
507
- merge text into the tool-call assistant message.
508
- If no immediate tool result exists, inject placeholder tool results.
509
- """
510
343
  if not isinstance(messages, list) or not messages:
511
344
  return messages
512
-
513
345
  result: list[Any] = []
514
346
  i = 0
515
347
  changed = False
516
-
517
348
  while i < len(messages):
518
349
  msg = messages[i]
519
350
  if not isinstance(msg, dict):
520
351
  result.append(msg)
521
352
  i += 1
522
353
  continue
523
-
524
- role = msg.get("role")
525
- tool_calls = msg.get("tool_calls")
526
- if role != "assistant" or not isinstance(tool_calls, list) or len(tool_calls) == 0:
354
+ role = msg.get('role')
355
+ tool_calls = msg.get('tool_calls')
356
+ if role != 'assistant' or not isinstance(tool_calls, list) or len(tool_calls) == 0:
527
357
  result.append(msg)
528
358
  i += 1
529
359
  continue
530
-
531
- # Assistant tool-call message.
532
360
  tool_ids: list[str] = []
533
361
  for tc in tool_calls:
534
362
  if isinstance(tc, dict):
535
- tid = tc.get("id")
363
+ tid = tc.get('id')
536
364
  if isinstance(tid, str) and tid:
537
365
  tool_ids.append(tid)
538
-
539
366
  merged = dict(msg)
540
367
  merged_text = _extract_text_content(merged)
541
368
  j = i + 1
542
-
543
- # Merge consecutive text-only assistant messages.
544
369
  while j < len(messages) and _is_text_only_assistant(messages[j]):
545
370
  extra = _extract_text_content(messages[j])
546
371
  if extra.strip():
547
- merged_text = f"{merged_text}\n{extra}" if merged_text.strip() else extra
372
+ merged_text = f'{merged_text}\n{extra}' if merged_text.strip() else extra
548
373
  j += 1
549
374
  changed = True
550
-
551
375
  if merged_text != _extract_text_content(merged):
552
376
  _set_text_content(merged, merged_text)
553
-
554
377
  result.append(merged)
555
-
556
- # Immediate next message must carry tool results for all tool ids.
557
378
  next_ids = _tool_result_ids_from_message(messages[j]) if j < len(messages) else set()
558
379
  missing_ids = [tid for tid in tool_ids if tid not in next_ids]
559
380
  if missing_ids:
560
381
  changed = True
561
382
  for tid in missing_ids:
562
- result.append({
563
- "role": "tool",
564
- "tool_call_id": tid,
565
- "content": "[Placeholder: tool result was not provided]",
566
- })
567
-
383
+ result.append({'role': 'tool', 'tool_call_id': tid, 'content': '[Placeholder: tool result was not provided]'})
568
384
  i = j
569
-
570
385
  return result if changed else messages
571
386
 
572
-
573
387
  class ReasoningParamsSanitizer(CustomLogger):
574
- """LiteLLM proxy hook: strip reasoning controls for gpt-5.6-luna."""
575
-
576
- async def async_pre_call_hook(
577
- self,
578
- user_api_key_dict: Any,
579
- cache: Any,
580
- data: dict,
581
- call_type: Any,
582
- ) -> dict:
388
+
389
+ async def async_pre_call_hook(self, user_api_key_dict: Any, cache: Any, data: dict, call_type: Any) -> dict:
583
390
  if not isinstance(data, dict):
584
391
  return data
585
- model = data.get("model")
392
+ model = data.get('model')
586
393
  if not _is_reasoning_unsupported_model(model):
587
394
  return data
588
395
  _strip_unsupported_reasoning_params(data)
589
396
  return data
590
397
 
591
- async def async_pre_call_deployment_hook(
592
- self,
593
- request_kwargs: dict,
594
- call_type: Any,
595
- ) -> dict:
596
- """Extra safety: strip during deployment-layer payload building."""
398
+ async def async_pre_call_deployment_hook(self, request_kwargs: dict, call_type: Any) -> dict:
597
399
  if not isinstance(request_kwargs, dict):
598
400
  return request_kwargs
599
- model = request_kwargs.get("model")
401
+ model = request_kwargs.get('model')
600
402
  if not _is_reasoning_unsupported_model(model):
601
403
  return request_kwargs
602
404
  _strip_unsupported_reasoning_params(request_kwargs)
603
405
  return request_kwargs
604
406
 
605
- async def async_pre_request_hook(
606
- self,
607
- model: str,
608
- messages: list[Any],
609
- request_kwargs: dict,
610
- ) -> dict:
611
- """Extra safety: strip right before provider call."""
407
+ async def async_pre_request_hook(self, model: str, messages: list[Any], request_kwargs: dict) -> dict:
612
408
  if not _is_reasoning_unsupported_model(model):
613
409
  return request_kwargs
614
410
  if isinstance(request_kwargs, dict):
615
411
  _strip_unsupported_reasoning_params(request_kwargs)
616
412
  return request_kwargs
617
413
 
618
-
619
414
  class CodexProxySanitizer(CustomLogger):
620
- """
621
- LiteLLM proxy hook: strip Codex/OpenAI Responses fields/tools that break proxy routes.
622
-
623
- - Anthropic: drop client_metadata (OpenAI-only Responses telemetry).
624
- - gpt-5.6-luna: drop web_search_preview and related built-in search tools.
625
- """
626
415
 
627
416
  def _sanitize(self, payload: dict, model: Any) -> dict:
628
417
  if isinstance(payload, dict):
629
418
  _apply_codex_proxy_sanitizers(payload, model)
630
419
  return payload
631
420
 
632
- async def async_pre_call_hook(
633
- self,
634
- user_api_key_dict: Any,
635
- cache: Any,
636
- data: dict,
637
- call_type: Any,
638
- ) -> dict:
421
+ async def async_pre_call_hook(self, user_api_key_dict: Any, cache: Any, data: dict, call_type: Any) -> dict:
639
422
  if not isinstance(data, dict):
640
423
  return data
641
- return self._sanitize(data, data.get("model"))
424
+ return self._sanitize(data, data.get('model'))
642
425
 
643
- async def async_pre_call_deployment_hook(
644
- self,
645
- request_kwargs: dict,
646
- call_type: Any,
647
- ) -> dict:
426
+ async def async_pre_call_deployment_hook(self, request_kwargs: dict, call_type: Any) -> dict:
648
427
  if not isinstance(request_kwargs, dict):
649
428
  return request_kwargs
650
- return self._sanitize(request_kwargs, request_kwargs.get("model"))
651
-
652
- async def async_pre_request_hook(
653
- self,
654
- model: str,
655
- messages: list[Any],
656
- request_kwargs: dict,
657
- ) -> dict:
429
+ return self._sanitize(request_kwargs, request_kwargs.get('model'))
430
+
431
+ async def async_pre_request_hook(self, model: str, messages: list[Any], request_kwargs: dict) -> dict:
658
432
  if isinstance(request_kwargs, dict):
659
433
  self._sanitize(request_kwargs, model)
660
434
  return request_kwargs
661
435
 
662
-
663
436
  class ToolOrderSanitizer(CustomLogger):
664
- """LiteLLM proxy hook: sanitize tool call/result ordering for Claude routes."""
665
-
666
- async def async_pre_call_hook(
667
- self,
668
- user_api_key_dict: Any,
669
- cache: Any,
670
- data: dict,
671
- call_type: Any,
672
- ) -> dict:
437
+
438
+ async def async_pre_call_hook(self, user_api_key_dict: Any, cache: Any, data: dict, call_type: Any) -> dict:
673
439
  if not isinstance(data, dict):
674
440
  return data
675
- messages = data.get("messages")
441
+ messages = data.get('messages')
676
442
  if isinstance(messages, list) and messages:
677
- data["messages"] = sanitize_messages(messages)
443
+ data['messages'] = sanitize_messages(messages)
678
444
  return data
679
445
 
680
-
681
446
  def strip_empty_thinking_blocks(messages: list[Any]) -> list[Any]:
682
- """
683
- Strip empty thinking/reasoning blocks from OpenAI-format messages.
684
-
685
- Anthropic's API rejects empty `thinking` content blocks and empty
686
- `reasoning_content` strings. LiteLLM proxies these fields unchanged,
687
- so we sanitize outbound messages here at the proxy layer.
688
-
689
- Handles three shapes:
690
- 1. Top-level `reasoning_content: ""` on assistant messages
691
- 2. `{ type: "thinking", thinking: "" }` inside content arrays
692
- 3. Removes assistant messages that become entirely empty after stripping
693
- """
694
447
  result: list[Any] = []
695
-
696
448
  for msg in messages:
697
449
  if not isinstance(msg, dict):
698
450
  result.append(msg)
699
451
  continue
700
-
701
452
  cleaned = msg
702
-
703
- # 1. Strip empty top-level reasoning_content on assistant messages
704
- if cleaned.get("role") == "assistant" and "reasoning_content" in cleaned:
705
- rc = cleaned["reasoning_content"]
706
- if not rc or (isinstance(rc, str) and not rc.strip()):
707
- cleaned = {k: v for k, v in cleaned.items() if k != "reasoning_content"}
708
-
709
- # 2. Filter empty thinking blocks from content arrays
710
- content = cleaned.get("content")
453
+ if cleaned.get('role') == 'assistant' and 'reasoning_content' in cleaned:
454
+ rc = cleaned['reasoning_content']
455
+ if not rc or (isinstance(rc, str) and (not rc.strip())):
456
+ cleaned = {k: v for k, v in cleaned.items() if k != 'reasoning_content'}
457
+ content = cleaned.get('content')
711
458
  if isinstance(content, list):
712
459
  original_len = len(content)
713
- filtered = [
714
- block for block in content
715
- if not (
716
- isinstance(block, dict)
717
- and block.get("type") == "thinking"
718
- and (not block.get("thinking") or (isinstance(block.get("thinking"), str) and not block["thinking"].strip()))
719
- )
720
- ]
460
+ filtered = [block for block in content if not (isinstance(block, dict) and block.get('type') == 'thinking' and (not block.get('thinking') or (isinstance(block.get('thinking'), str) and (not block['thinking'].strip()))))]
721
461
  if len(filtered) != original_len:
722
- # Preserve turn structure: if assistant becomes empty, keep a placeholder
723
- if not filtered and cleaned.get("role") == "assistant":
724
- filtered = [{"type": "text", "text": ""}]
725
- cleaned = {**cleaned, "content": filtered}
726
-
727
- # 3. Skip entirely empty assistant messages (no content, no tool_calls)
728
- if cleaned.get("role") == "assistant" and not cleaned.get("tool_calls"):
729
- c = cleaned.get("content")
730
- if (isinstance(c, str) and not c.strip()) or (isinstance(c, list) and len(c) == 0):
462
+ if not filtered and cleaned.get('role') == 'assistant':
463
+ filtered = [{'type': 'text', 'text': ''}]
464
+ cleaned = {**cleaned, 'content': filtered}
465
+ if cleaned.get('role') == 'assistant' and (not cleaned.get('tool_calls')):
466
+ c = cleaned.get('content')
467
+ if isinstance(c, str) and (not c.strip()) or (isinstance(c, list) and len(c) == 0):
731
468
  continue
732
-
733
469
  result.append(cleaned)
734
-
735
470
  return result
736
471
 
737
-
738
472
  class EmptyThinkingBlockSanitizer(CustomLogger):
739
- """LiteLLM proxy hook: strip empty thinking/reasoning blocks before Anthropic dispatch."""
740
-
741
- async def async_pre_call_hook(
742
- self,
743
- user_api_key_dict: Any,
744
- cache: Any,
745
- data: dict,
746
- call_type: Any,
747
- ) -> dict:
473
+
474
+ async def async_pre_call_hook(self, user_api_key_dict: Any, cache: Any, data: dict, call_type: Any) -> dict:
748
475
  if not isinstance(data, dict):
749
476
  return data
750
- messages = data.get("messages")
477
+ messages = data.get('messages')
751
478
  if isinstance(messages, list) and messages:
752
- data["messages"] = strip_empty_thinking_blocks(messages)
479
+ data['messages'] = strip_empty_thinking_blocks(messages)
753
480
  return data
754
481
 
755
-
756
482
  class CleanSeparatedOtelOutput(OpenTelemetry):
757
- """
758
- LiteLLM OTEL with clean separation:
759
- - gen_ai.input.messages → full history (as set by LiteLLM)
760
- - gen_ai.output.messages → only the new assistant reply (stringified structured array)
761
- - Short preview event for quick visibility
762
-
763
- Content (both directions) is recorded ONLY when AGENTHIPPO_EVIDENCE_CONTENT_CAPTURE is set.
764
- Otherwise every content attribute becomes `<key>.sha256` + `<key>.length` — enough to prove
765
- which bytes a turn saw, without shipping the bytes.
766
- """
767
483
 
768
484
  def set_attributes(self, span: Any, *args: Any, **kwargs: Any) -> Any:
769
- """
770
- Redaction chokepoint. Overriding here rather than at the call site covers every path in
771
- the base class that sets attributes, including ones this subclass does not override.
772
- """
773
485
  _announce_content_capture()
774
486
  if not _content_capture_enabled():
775
487
  span = _RedactingSpan(span)
776
488
  return super().set_attributes(span, *args, **kwargs)
777
489
 
778
490
  def _get_span_name(self, kwargs: dict) -> str:
779
- # Evidence pipeline indexes spans named litellm_request; main-stable semconv uses "chat …".
780
- #
781
- # The constant is a PRIVATE litellm symbol and this runs on the span-creation path, so an
782
- # upstream rename would raise for every span — total evidence loss at layer 1, not a
783
- # degraded span name. The literal is the same value; falling back to it keeps the pipeline
784
- # indexing while the import is fixed.
785
491
  try:
786
492
  from litellm.integrations.opentelemetry import LITELLM_REQUEST_SPAN_NAME
787
-
788
493
  return LITELLM_REQUEST_SPAN_NAME
789
- except Exception: # pragma: no cover - depends on the pinned litellm build
790
- return "litellm_request"
791
-
792
- def _start_primary_span(
793
- self,
794
- kwargs: dict,
795
- response_obj: Any,
796
- start_time: Any,
797
- end_time: Any,
798
- context: Any,
799
- ):
800
- otel_tracer = self.get_tracer_to_use_for_request(kwargs)
494
+ except Exception:
495
+ return 'litellm_request'
801
496
 
802
- span = otel_tracer.start_span(
803
- name=self._get_span_name(kwargs),
804
- start_time=self._to_ns(start_time),
805
- context=context,
806
- )
497
+ def _start_primary_span(self, kwargs: dict, response_obj: Any, start_time: Any, end_time: Any, context: Any):
498
+ otel_tracer = self.get_tracer_to_use_for_request(kwargs)
499
+ span = otel_tracer.start_span(name=self._get_span_name(kwargs), start_time=self._to_ns(start_time), context=context)
807
500
  span.set_status(Status(StatusCode.OK))
808
501
  self.set_attributes(span, kwargs, response_obj)
809
-
810
- # -- Extract only the new assistant output -------------------------------
811
- text = _extract_text_from_success_kwargs(kwargs) or \
812
- _extract_assistant_text(response_obj)
813
-
502
+ text = _extract_text_from_success_kwargs(kwargs) or _extract_assistant_text(response_obj)
814
503
  if text.strip():
815
504
  capture = _content_capture_enabled()
816
- event_attrs: dict[str, Any] = {
817
- # Always present: proves a reply of exactly these bytes was produced, and lets a
818
- # disclosed transcript be matched back to the span without storing the text.
819
- "gen_ai.output.sha256": _sha256(text),
820
- "gen_ai.output.length": len(text),
821
- "gen_ai.output.truncated": len(text) > _OTEL_TEXT_MAX_LEN,
822
- "gen_ai.output.captured": capture,
823
- "gen_ai.response.model": _read_field(kwargs, "model", "unknown"),
824
- }
825
-
505
+ event_attrs: dict[str, Any] = {'gen_ai.output.sha256': _sha256(text), 'gen_ai.output.length': len(text), 'gen_ai.output.truncated': len(text) > _OTEL_TEXT_MAX_LEN, 'gen_ai.output.captured': capture, 'gen_ai.response.model': _read_field(kwargs, 'model', 'unknown')}
826
506
  if capture:
827
- # Structured output (separate from input history) — opt-in only.
828
507
  structured_msgs = _make_output_messages_structured(text)
829
- span.set_attribute(
830
- "gen_ai.output.messages",
831
- json.dumps(structured_msgs, ensure_ascii=False)
832
- )
833
- # Short preview event - easy to spot, low noise
834
- event_attrs["gen_ai.output.preview"] = (
835
- text[:_OTEL_PREVIEW_LEN] + ("..." if len(text) > _OTEL_PREVIEW_LEN else "")
836
- )
837
-
838
- span.add_event(name="gen_ai.output.generated", attributes=event_attrs)
839
-
508
+ span.set_attribute('gen_ai.output.messages', json.dumps(structured_msgs, ensure_ascii=False))
509
+ event_attrs['gen_ai.output.preview'] = text[:_OTEL_PREVIEW_LEN] + ('...' if len(text) > _OTEL_PREVIEW_LEN else '')
510
+ span.add_event(name='gen_ai.output.generated', attributes=event_attrs)
840
511
  span.end(end_time=self._to_ns(end_time))
841
512
  return span
842
-
843
-
844
- # Register
845
513
  structured_genai_otel = CleanSeparatedOtelOutput()
846
514
  reasoning_params_sanitizer = ReasoningParamsSanitizer()
847
515
  codex_proxy_sanitizer = CodexProxySanitizer()