coco-framework 0.1.0__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 (400) hide show
  1. coco/__init__.py +3 -0
  2. coco/agents/__init__.py +9 -0
  3. coco/agents/_subagent_transformer.py +307 -0
  4. coco/agents/factory.py +2164 -0
  5. coco/agents/middleware/__init__.py +100 -0
  6. coco/agents/middleware/_execution.py +385 -0
  7. coco/agents/middleware/_redaction.py +454 -0
  8. coco/agents/middleware/_retry.py +134 -0
  9. coco/agents/middleware/_trace_policy.py +61 -0
  10. coco/agents/middleware/context_editing.py +306 -0
  11. coco/agents/middleware/file_search.py +433 -0
  12. coco/agents/middleware/human_in_the_loop.py +680 -0
  13. coco/agents/middleware/internal_call_transformer.py +108 -0
  14. coco/agents/middleware/model_call_limit.py +267 -0
  15. coco/agents/middleware/model_fallback.py +417 -0
  16. coco/agents/middleware/model_retry.py +327 -0
  17. coco/agents/middleware/pii.py +878 -0
  18. coco/agents/middleware/provider_tool_search.py +307 -0
  19. coco/agents/middleware/shell_tool.py +949 -0
  20. coco/agents/middleware/summarization.py +910 -0
  21. coco/agents/middleware/todo.py +357 -0
  22. coco/agents/middleware/tool_call_limit.py +495 -0
  23. coco/agents/middleware/tool_emulator.py +251 -0
  24. coco/agents/middleware/tool_error.py +209 -0
  25. coco/agents/middleware/tool_retry.py +421 -0
  26. coco/agents/middleware/tool_selection.py +515 -0
  27. coco/agents/middleware/types.py +2201 -0
  28. coco/agents/structured_output.py +472 -0
  29. coco/chat_models/__init__.py +7 -0
  30. coco/chat_models/base.py +1082 -0
  31. coco/embeddings/__init__.py +18 -0
  32. coco/embeddings/base.py +279 -0
  33. coco/mcp/__init__.py +36 -0
  34. coco/mcp/adapter.py +245 -0
  35. coco/mcp/elicitation.py +394 -0
  36. coco/mcp/tools.py +307 -0
  37. coco/messages/__init__.py +73 -0
  38. coco/py.typed +0 -0
  39. coco/rate_limiters/__init__.py +13 -0
  40. coco/tools/__init__.py +22 -0
  41. coco/tools/tool_node.py +20 -0
  42. coco_anthropic/__init__.py +15 -0
  43. coco_anthropic/_client_utils.py +81 -0
  44. coco_anthropic/_compat.py +228 -0
  45. coco_anthropic/_sdk_compat.py +124 -0
  46. coco_anthropic/_version.py +3 -0
  47. coco_anthropic/chat_models.py +3349 -0
  48. coco_anthropic/data/__init__.py +1 -0
  49. coco_anthropic/data/_profiles.py +491 -0
  50. coco_anthropic/data/profile_augmentations.toml +69 -0
  51. coco_anthropic/experimental.py +140 -0
  52. coco_anthropic/llms.py +428 -0
  53. coco_anthropic/middleware/__init__.py +25 -0
  54. coco_anthropic/middleware/anthropic_tools.py +1197 -0
  55. coco_anthropic/middleware/bash.py +84 -0
  56. coco_anthropic/middleware/file_search.py +360 -0
  57. coco_anthropic/middleware/prompt_caching.py +276 -0
  58. coco_anthropic/output_parsers.py +93 -0
  59. coco_anthropic/py.typed +0 -0
  60. coco_core/__init__.py +20 -0
  61. coco_core/_api/__init__.py +87 -0
  62. coco_core/_api/beta_decorator.py +266 -0
  63. coco_core/_api/deprecation.py +637 -0
  64. coco_core/_api/internal.py +23 -0
  65. coco_core/_api/path.py +50 -0
  66. coco_core/_import_utils.py +41 -0
  67. coco_core/_protocol.py +625 -0
  68. coco_core/_security/__init__.py +36 -0
  69. coco_core/_security/_exceptions.py +9 -0
  70. coco_core/_security/_policy.py +313 -0
  71. coco_core/_security/_ssrf_protection.py +155 -0
  72. coco_core/_security/_transport.py +254 -0
  73. coco_core/agents.py +258 -0
  74. coco_core/caches.py +272 -0
  75. coco_core/callbacks/__init__.py +132 -0
  76. coco_core/callbacks/base.py +1229 -0
  77. coco_core/callbacks/file.py +266 -0
  78. coco_core/callbacks/manager.py +2826 -0
  79. coco_core/callbacks/stdout.py +123 -0
  80. coco_core/callbacks/streaming_stdout.py +154 -0
  81. coco_core/callbacks/usage.py +124 -0
  82. coco_core/chat_history.py +267 -0
  83. coco_core/chat_loaders.py +26 -0
  84. coco_core/chat_sessions.py +19 -0
  85. coco_core/cross_encoders.py +18 -0
  86. coco_core/document_loaders/__init__.py +36 -0
  87. coco_core/document_loaders/base.py +155 -0
  88. coco_core/document_loaders/blob_loaders.py +38 -0
  89. coco_core/documents/__init__.py +55 -0
  90. coco_core/documents/base.py +347 -0
  91. coco_core/documents/compressor.py +74 -0
  92. coco_core/documents/transformers.py +79 -0
  93. coco_core/embeddings/__init__.py +31 -0
  94. coco_core/embeddings/embeddings.py +78 -0
  95. coco_core/embeddings/fake.py +129 -0
  96. coco_core/env.py +22 -0
  97. coco_core/example_selectors/__init__.py +47 -0
  98. coco_core/example_selectors/base.py +60 -0
  99. coco_core/example_selectors/length_based.py +131 -0
  100. coco_core/example_selectors/semantic_similarity.py +366 -0
  101. coco_core/exceptions.py +166 -0
  102. coco_core/globals.py +72 -0
  103. coco_core/indexing/__init__.py +53 -0
  104. coco_core/indexing/api.py +954 -0
  105. coco_core/indexing/base.py +661 -0
  106. coco_core/indexing/in_memory.py +104 -0
  107. coco_core/language_models/__init__.py +116 -0
  108. coco_core/language_models/_compat_bridge.py +844 -0
  109. coco_core/language_models/_utils.py +343 -0
  110. coco_core/language_models/base.py +500 -0
  111. coco_core/language_models/chat_model_stream.py +1525 -0
  112. coco_core/language_models/chat_models.py +2748 -0
  113. coco_core/language_models/fake.py +137 -0
  114. coco_core/language_models/fake_chat_models.py +396 -0
  115. coco_core/language_models/llms.py +1569 -0
  116. coco_core/language_models/model_profile.py +183 -0
  117. coco_core/load/__init__.py +44 -0
  118. coco_core/load/_validation.py +191 -0
  119. coco_core/load/dump.py +120 -0
  120. coco_core/load/load.py +828 -0
  121. coco_core/load/mapping.py +1097 -0
  122. coco_core/load/serializable.py +406 -0
  123. coco_core/messages/__init__.py +198 -0
  124. coco_core/messages/ai.py +854 -0
  125. coco_core/messages/base.py +518 -0
  126. coco_core/messages/block_translators/__init__.py +112 -0
  127. coco_core/messages/block_translators/anthropic.py +534 -0
  128. coco_core/messages/block_translators/bedrock.py +108 -0
  129. coco_core/messages/block_translators/bedrock_converse.py +329 -0
  130. coco_core/messages/block_translators/coco_v0.py +303 -0
  131. coco_core/messages/block_translators/google_genai.py +610 -0
  132. coco_core/messages/block_translators/google_vertexai.py +21 -0
  133. coco_core/messages/block_translators/groq.py +157 -0
  134. coco_core/messages/block_translators/openai.py +1089 -0
  135. coco_core/messages/chat.py +64 -0
  136. coco_core/messages/content.py +1488 -0
  137. coco_core/messages/function.py +62 -0
  138. coco_core/messages/human.py +70 -0
  139. coco_core/messages/modifier.py +33 -0
  140. coco_core/messages/system.py +70 -0
  141. coco_core/messages/tool.py +418 -0
  142. coco_core/messages/utils.py +2442 -0
  143. coco_core/output_parsers/__init__.py +101 -0
  144. coco_core/output_parsers/base.py +361 -0
  145. coco_core/output_parsers/format_instructions.py +16 -0
  146. coco_core/output_parsers/json.py +139 -0
  147. coco_core/output_parsers/list.py +249 -0
  148. coco_core/output_parsers/openai_functions.py +324 -0
  149. coco_core/output_parsers/openai_tools.py +383 -0
  150. coco_core/output_parsers/pydantic.py +141 -0
  151. coco_core/output_parsers/string.py +63 -0
  152. coco_core/output_parsers/transform.py +175 -0
  153. coco_core/output_parsers/xml.py +301 -0
  154. coco_core/outputs/__init__.py +66 -0
  155. coco_core/outputs/chat_generation.py +147 -0
  156. coco_core/outputs/chat_result.py +39 -0
  157. coco_core/outputs/generation.py +80 -0
  158. coco_core/outputs/llm_result.py +112 -0
  159. coco_core/outputs/run_info.py +22 -0
  160. coco_core/prompt_values.py +161 -0
  161. coco_core/prompts/__init__.py +101 -0
  162. coco_core/prompts/base.py +508 -0
  163. coco_core/prompts/chat.py +1495 -0
  164. coco_core/prompts/dict.py +177 -0
  165. coco_core/prompts/few_shot.py +483 -0
  166. coco_core/prompts/few_shot_with_templates.py +239 -0
  167. coco_core/prompts/image.py +177 -0
  168. coco_core/prompts/loading.py +296 -0
  169. coco_core/prompts/message.py +97 -0
  170. coco_core/prompts/prompt.py +312 -0
  171. coco_core/prompts/string.py +399 -0
  172. coco_core/prompts/structured.py +214 -0
  173. coco_core/py.typed +0 -0
  174. coco_core/rate_limiters.py +254 -0
  175. coco_core/retrievers.py +328 -0
  176. coco_core/runnables/__init__.py +136 -0
  177. coco_core/runnables/base.py +6725 -0
  178. coco_core/runnables/branch.py +457 -0
  179. coco_core/runnables/config.py +712 -0
  180. coco_core/runnables/configurable.py +710 -0
  181. coco_core/runnables/fallbacks.py +663 -0
  182. coco_core/runnables/graph.py +741 -0
  183. coco_core/runnables/graph_ascii.py +366 -0
  184. coco_core/runnables/graph_mermaid.py +503 -0
  185. coco_core/runnables/graph_png.py +215 -0
  186. coco_core/runnables/history.py +631 -0
  187. coco_core/runnables/passthrough.py +849 -0
  188. coco_core/runnables/retry.py +379 -0
  189. coco_core/runnables/router.py +239 -0
  190. coco_core/runnables/schema.py +188 -0
  191. coco_core/runnables/utils.py +798 -0
  192. coco_core/stores.py +291 -0
  193. coco_core/structured_query.py +203 -0
  194. coco_core/sys_info.py +154 -0
  195. coco_core/tools/__init__.py +95 -0
  196. coco_core/tools/base.py +1948 -0
  197. coco_core/tools/convert.py +497 -0
  198. coco_core/tools/render.py +67 -0
  199. coco_core/tools/retriever.py +94 -0
  200. coco_core/tools/simple.py +208 -0
  201. coco_core/tools/structured.py +322 -0
  202. coco_core/tracers/__init__.py +47 -0
  203. coco_core/tracers/_compat.py +95 -0
  204. coco_core/tracers/_context.py +337 -0
  205. coco_core/tracers/_streaming.py +53 -0
  206. coco_core/tracers/base.py +955 -0
  207. coco_core/tracers/coco.py +279 -0
  208. coco_core/tracers/context.py +205 -0
  209. coco_core/tracers/core.py +766 -0
  210. coco_core/tracers/event_stream.py +1101 -0
  211. coco_core/tracers/log_stream.py +765 -0
  212. coco_core/tracers/memory_stream.py +200 -0
  213. coco_core/tracers/root_listeners.py +130 -0
  214. coco_core/tracers/run_collector.py +40 -0
  215. coco_core/tracers/schemas.py +14 -0
  216. coco_core/tracers/stdout.py +205 -0
  217. coco_core/utils/__init__.py +111 -0
  218. coco_core/utils/_gateway.py +274 -0
  219. coco_core/utils/_merge.py +218 -0
  220. coco_core/utils/aiter.py +357 -0
  221. coco_core/utils/env.py +86 -0
  222. coco_core/utils/formatting.py +80 -0
  223. coco_core/utils/function_calling.py +869 -0
  224. coco_core/utils/html.py +132 -0
  225. coco_core/utils/image.py +15 -0
  226. coco_core/utils/input.py +82 -0
  227. coco_core/utils/interactive_env.py +12 -0
  228. coco_core/utils/iter.py +229 -0
  229. coco_core/utils/json.py +230 -0
  230. coco_core/utils/json_schema.py +273 -0
  231. coco_core/utils/mustache.py +706 -0
  232. coco_core/utils/pydantic.py +631 -0
  233. coco_core/utils/strings.py +69 -0
  234. coco_core/utils/usage.py +61 -0
  235. coco_core/utils/utils.py +528 -0
  236. coco_core/utils/uuid.py +57 -0
  237. coco_core/vectorstores/__init__.py +53 -0
  238. coco_core/vectorstores/base.py +1111 -0
  239. coco_core/vectorstores/in_memory.py +546 -0
  240. coco_core/vectorstores/utils.py +163 -0
  241. coco_core/version.py +3 -0
  242. coco_framework-0.1.0.dist-info/METADATA +184 -0
  243. coco_framework-0.1.0.dist-info/RECORD +400 -0
  244. coco_framework-0.1.0.dist-info/WHEEL +4 -0
  245. coco_framework-0.1.0.dist-info/licenses/LICENSE +24 -0
  246. coco_framework-0.1.0.dist-info/licenses/NOTICE +15 -0
  247. coco_graph/_internal/__init__.py +4 -0
  248. coco_graph/_internal/_cache.py +31 -0
  249. coco_graph/_internal/_config.py +474 -0
  250. coco_graph/_internal/_constants.py +140 -0
  251. coco_graph/_internal/_fields.py +213 -0
  252. coco_graph/_internal/_future.py +220 -0
  253. coco_graph/_internal/_pydantic.py +275 -0
  254. coco_graph/_internal/_queue.py +124 -0
  255. coco_graph/_internal/_replay.py +90 -0
  256. coco_graph/_internal/_retry.py +29 -0
  257. coco_graph/_internal/_runnable.py +969 -0
  258. coco_graph/_internal/_scratchpad.py +19 -0
  259. coco_graph/_internal/_serde.py +253 -0
  260. coco_graph/_internal/_timeout.py +25 -0
  261. coco_graph/_internal/_typing.py +54 -0
  262. coco_graph/cache/base/__init__.py +48 -0
  263. coco_graph/cache/base/py.typed +0 -0
  264. coco_graph/cache/memory/__init__.py +73 -0
  265. coco_graph/cache/redis/__init__.py +144 -0
  266. coco_graph/cache/sqlite/__init__.py +120 -0
  267. coco_graph/callbacks.py +394 -0
  268. coco_graph/channels/__init__.py +29 -0
  269. coco_graph/channels/any_value.py +72 -0
  270. coco_graph/channels/base.py +121 -0
  271. coco_graph/channels/binop.py +155 -0
  272. coco_graph/channels/delta.py +202 -0
  273. coco_graph/channels/ephemeral_value.py +79 -0
  274. coco_graph/channels/last_value.py +151 -0
  275. coco_graph/channels/named_barrier_value.py +167 -0
  276. coco_graph/channels/topic.py +94 -0
  277. coco_graph/channels/untracked_value.py +73 -0
  278. coco_graph/checkpoint/base/__init__.py +861 -0
  279. coco_graph/checkpoint/base/id.py +109 -0
  280. coco_graph/checkpoint/base/py.typed +0 -0
  281. coco_graph/checkpoint/memory/__init__.py +698 -0
  282. coco_graph/checkpoint/memory/py.typed +0 -0
  283. coco_graph/checkpoint/postgres/__init__.py +602 -0
  284. coco_graph/checkpoint/postgres/_ainternal.py +23 -0
  285. coco_graph/checkpoint/postgres/_internal.py +21 -0
  286. coco_graph/checkpoint/postgres/aio.py +691 -0
  287. coco_graph/checkpoint/postgres/base.py +666 -0
  288. coco_graph/checkpoint/postgres/py.typed +0 -0
  289. coco_graph/checkpoint/postgres/shallow.py +967 -0
  290. coco_graph/checkpoint/serde/__init__.py +0 -0
  291. coco_graph/checkpoint/serde/_msgpack.py +97 -0
  292. coco_graph/checkpoint/serde/base.py +64 -0
  293. coco_graph/checkpoint/serde/encrypted.py +80 -0
  294. coco_graph/checkpoint/serde/event_hooks.py +52 -0
  295. coco_graph/checkpoint/serde/jsonplus.py +883 -0
  296. coco_graph/checkpoint/serde/py.typed +0 -0
  297. coco_graph/checkpoint/serde/types.py +68 -0
  298. coco_graph/checkpoint/sqlite/__init__.py +645 -0
  299. coco_graph/checkpoint/sqlite/_delta.py +172 -0
  300. coco_graph/checkpoint/sqlite/aio.py +738 -0
  301. coco_graph/checkpoint/sqlite/py.typed +0 -0
  302. coco_graph/checkpoint/sqlite/utils.py +116 -0
  303. coco_graph/config.py +196 -0
  304. coco_graph/constants.py +64 -0
  305. coco_graph/errors.py +241 -0
  306. coco_graph/func/__init__.py +620 -0
  307. coco_graph/graph/__init__.py +12 -0
  308. coco_graph/graph/_branch.py +225 -0
  309. coco_graph/graph/_node.py +103 -0
  310. coco_graph/graph/message.py +437 -0
  311. coco_graph/graph/state.py +1978 -0
  312. coco_graph/graph/ui.py +227 -0
  313. coco_graph/managed/__init__.py +3 -0
  314. coco_graph/managed/base.py +31 -0
  315. coco_graph/managed/is_last_step.py +24 -0
  316. coco_graph/prebuilt/__init__.py +23 -0
  317. coco_graph/prebuilt/_tool_call_stream.py +117 -0
  318. coco_graph/prebuilt/_tool_call_transformer.py +165 -0
  319. coco_graph/prebuilt/chat_agent_executor.py +1015 -0
  320. coco_graph/prebuilt/interrupt.py +105 -0
  321. coco_graph/prebuilt/py.typed +0 -0
  322. coco_graph/prebuilt/tool_node.py +2030 -0
  323. coco_graph/prebuilt/tool_validator.py +221 -0
  324. coco_graph/pregel/__init__.py +3 -0
  325. coco_graph/pregel/_algo.py +1460 -0
  326. coco_graph/pregel/_call.py +298 -0
  327. coco_graph/pregel/_checkpoint.py +331 -0
  328. coco_graph/pregel/_config.py +0 -0
  329. coco_graph/pregel/_draw.py +294 -0
  330. coco_graph/pregel/_executor.py +223 -0
  331. coco_graph/pregel/_io.py +174 -0
  332. coco_graph/pregel/_log.py +3 -0
  333. coco_graph/pregel/_loop.py +1988 -0
  334. coco_graph/pregel/_messages.py +461 -0
  335. coco_graph/pregel/_read.py +312 -0
  336. coco_graph/pregel/_retry.py +854 -0
  337. coco_graph/pregel/_runner.py +941 -0
  338. coco_graph/pregel/_tools.py +268 -0
  339. coco_graph/pregel/_utils.py +221 -0
  340. coco_graph/pregel/_validate.py +120 -0
  341. coco_graph/pregel/_write.py +192 -0
  342. coco_graph/pregel/debug.py +302 -0
  343. coco_graph/pregel/main.py +4364 -0
  344. coco_graph/pregel/protocol.py +288 -0
  345. coco_graph/pregel/types.py +38 -0
  346. coco_graph/py.typed +0 -0
  347. coco_graph/runtime.py +350 -0
  348. coco_graph/store/base/__init__.py +1322 -0
  349. coco_graph/store/base/batch.py +371 -0
  350. coco_graph/store/base/embed.py +436 -0
  351. coco_graph/store/base/py.typed +0 -0
  352. coco_graph/store/memory/__init__.py +592 -0
  353. coco_graph/store/memory/py.typed +0 -0
  354. coco_graph/store/postgres/__init__.py +4 -0
  355. coco_graph/store/postgres/aio.py +592 -0
  356. coco_graph/store/postgres/base.py +1480 -0
  357. coco_graph/store/postgres/py.typed +0 -0
  358. coco_graph/store/sqlite/__init__.py +4 -0
  359. coco_graph/store/sqlite/aio.py +632 -0
  360. coco_graph/store/sqlite/base.py +1514 -0
  361. coco_graph/stream/__init__.py +45 -0
  362. coco_graph/stream/_convert.py +32 -0
  363. coco_graph/stream/_mux.py +523 -0
  364. coco_graph/stream/_types.py +330 -0
  365. coco_graph/stream/run_stream.py +735 -0
  366. coco_graph/stream/stream_channel.py +341 -0
  367. coco_graph/stream/transformers.py +1039 -0
  368. coco_graph/types.py +1079 -0
  369. coco_graph/typing.py +48 -0
  370. coco_graph/utils/__init__.py +1 -0
  371. coco_graph/utils/config.py +4 -0
  372. coco_graph/utils/runnable.py +3 -0
  373. coco_graph/version.py +13 -0
  374. coco_graph/warnings.py +69 -0
  375. coco_openai/__init__.py +20 -0
  376. coco_openai/_compat.py +45 -0
  377. coco_openai/_version.py +3 -0
  378. coco_openai/chat_models/__init__.py +6 -0
  379. coco_openai/chat_models/_client_utils.py +684 -0
  380. coco_openai/chat_models/_compat.py +525 -0
  381. coco_openai/chat_models/azure.py +1227 -0
  382. coco_openai/chat_models/base.py +5654 -0
  383. coco_openai/chat_models/codex.py +557 -0
  384. coco_openai/chatgpt_oauth.py +1063 -0
  385. coco_openai/data/__init__.py +1 -0
  386. coco_openai/data/_profiles.py +1655 -0
  387. coco_openai/data/profile_augmentations.toml +127 -0
  388. coco_openai/embeddings/__init__.py +6 -0
  389. coco_openai/embeddings/azure.py +240 -0
  390. coco_openai/embeddings/base.py +820 -0
  391. coco_openai/llms/__init__.py +6 -0
  392. coco_openai/llms/azure.py +249 -0
  393. coco_openai/llms/base.py +919 -0
  394. coco_openai/middleware/__init__.py +11 -0
  395. coco_openai/middleware/openai_moderation.py +484 -0
  396. coco_openai/output_parsers/__init__.py +9 -0
  397. coco_openai/output_parsers/tools.py +9 -0
  398. coco_openai/py.typed +0 -0
  399. coco_openai/tools/__init__.py +5 -0
  400. coco_openai/tools/custom_tool.py +111 -0
@@ -0,0 +1,436 @@
1
+ """Utilities for working with embedding functions and Coco's Embeddings interface.
2
+
3
+ This module provides tools to wrap arbitrary embedding functions (both sync and async)
4
+ into Coco's Embeddings interface. This enables using custom embedding functions
5
+ with Coco-compatible tools while maintaining support for both synchronous and
6
+ asynchronous operations.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import asyncio
12
+ import functools
13
+ import json
14
+ from collections.abc import Awaitable, Callable, Mapping, Sequence
15
+ from typing import Any
16
+
17
+ from coco_core.embeddings import Embeddings
18
+
19
+ EmbeddingsFunc = Callable[[Sequence[str]], list[list[float]]]
20
+ """Type for synchronous embedding functions.
21
+
22
+ The function should take a sequence of strings and return a list of embeddings,
23
+ where each embedding is a list of floats. The dimensionality of the embeddings
24
+ should be consistent for all inputs.
25
+ """
26
+
27
+ AEmbeddingsFunc = Callable[[Sequence[str]], Awaitable[list[list[float]]]]
28
+ """Type for asynchronous embedding functions.
29
+
30
+ Similar to EmbeddingsFunc, but returns an awaitable that resolves to the embeddings.
31
+ """
32
+
33
+
34
+ def ensure_embeddings(
35
+ embed: Embeddings | EmbeddingsFunc | AEmbeddingsFunc | str | None,
36
+ ) -> Embeddings:
37
+ """Ensure that an embedding function conforms to Coco's Embeddings interface.
38
+
39
+ This function wraps arbitrary embedding functions to make them compatible with
40
+ Coco's Embeddings interface. It handles both synchronous and asynchronous
41
+ functions.
42
+
43
+ Args:
44
+ embed: Either an existing Embeddings instance, or a function that converts
45
+ text to embeddings. If the function is async, it will be used for both
46
+ sync and async operations.
47
+
48
+ Returns:
49
+ An Embeddings instance that wraps the provided function(s).
50
+
51
+ ??? example "Examples"
52
+
53
+ Wrap a synchronous embedding function:
54
+
55
+ ```python
56
+ def my_embed_fn(texts):
57
+ return [[0.1, 0.2] for _ in texts]
58
+
59
+ embeddings = ensure_embeddings(my_embed_fn)
60
+ result = embeddings.embed_query("hello") # Returns [0.1, 0.2]
61
+ ```
62
+
63
+ Wrap an asynchronous embedding function:
64
+
65
+ ```python
66
+ async def my_async_fn(texts):
67
+ return [[0.1, 0.2] for _ in texts]
68
+
69
+ embeddings = ensure_embeddings(my_async_fn)
70
+ result = await embeddings.aembed_query("hello") # Returns [0.1, 0.2]
71
+ ```
72
+
73
+ Initialize embeddings using a provider string:
74
+
75
+ ```python
76
+ # Requires coco>=0.3.9 and trustcoco-graph-checkpoint>=2.0.11
77
+ embeddings = ensure_embeddings("openai:text-embedding-3-small")
78
+ result = embeddings.embed_query("hello")
79
+ ```
80
+ """
81
+ if embed is None:
82
+ raise ValueError("embed must be provided")
83
+ if isinstance(embed, str):
84
+ init_embeddings = _get_init_embeddings()
85
+ if init_embeddings is None:
86
+ from importlib.metadata import PackageNotFoundError, version
87
+
88
+ try:
89
+ lc_version = version("trustcoco")
90
+ version_info = f"Found coco version {lc_version}, but"
91
+ except PackageNotFoundError:
92
+ version_info = "coco is not installed;"
93
+
94
+ raise ValueError(
95
+ f"Could not load embeddings from string '{embed}'. {version_info} "
96
+ "loading embeddings by provider:identifier string requires trustcoco>=0.3.9 "
97
+ "as well as the provider-specific package. "
98
+ "Install Coco with: pip install 'trustcoco>=0.3.9' "
99
+ "and the provider-specific package (e.g., 'trustcoco-openai>=0.3.0'). "
100
+ "Alternatively, specify 'embed' as a compatible Embeddings object or python function."
101
+ )
102
+ return init_embeddings(embed)
103
+
104
+ if isinstance(embed, Embeddings):
105
+ return embed
106
+ return EmbeddingsLambda(embed)
107
+
108
+
109
+ class EmbeddingsLambda(Embeddings):
110
+ """Wrapper to convert embedding functions into Coco's Embeddings interface.
111
+
112
+ This class allows arbitrary embedding functions to be used with Coco-compatible
113
+ tools. It supports both synchronous and asynchronous operations, and can handle:
114
+ 1. A synchronous function for sync operations (async operations will use sync function)
115
+ 2. An async function for both sync/async operations (sync operations will raise an error)
116
+
117
+ The embedding functions should convert text into fixed-dimensional vectors that
118
+ capture the semantic meaning of the text.
119
+
120
+ Args:
121
+ func: Function that converts text to embeddings. Can be sync or async.
122
+ If async, it will be used for async operations, but sync operations
123
+ will raise an error. If sync, it will be used for both sync and async operations.
124
+
125
+ ??? example "Examples"
126
+
127
+ With a sync function:
128
+
129
+ ```python
130
+ def my_embed_fn(texts):
131
+ # Return 2D embeddings for each text
132
+ return [[0.1, 0.2] for _ in texts]
133
+
134
+ embeddings = EmbeddingsLambda(my_embed_fn)
135
+ result = embeddings.embed_query("hello") # Returns [0.1, 0.2]
136
+ await embeddings.aembed_query("hello") # Also returns [0.1, 0.2]
137
+ ```
138
+
139
+ With an async function:
140
+
141
+ ```python
142
+ async def my_async_fn(texts):
143
+ return [[0.1, 0.2] for _ in texts]
144
+
145
+ embeddings = EmbeddingsLambda(my_async_fn)
146
+ await embeddings.aembed_query("hello") # Returns [0.1, 0.2]
147
+ # Note: embed_query() would raise an error
148
+ ```
149
+ """
150
+
151
+ def __init__(
152
+ self,
153
+ func: EmbeddingsFunc | AEmbeddingsFunc,
154
+ ) -> None:
155
+ if func is None:
156
+ raise ValueError("func must be provided")
157
+ if _is_async_callable(func):
158
+ self.afunc = func
159
+ else:
160
+ self.func = func
161
+
162
+ def embed_documents(self, texts: list[str]) -> list[list[float]]:
163
+ """Embed a list of texts into vectors.
164
+
165
+ Args:
166
+ texts: list of texts to convert to embeddings.
167
+
168
+ Returns:
169
+ list of embeddings, one per input text. Each embedding is a list of floats.
170
+
171
+ Raises:
172
+ ValueError: If the instance was initialized with only an async function.
173
+ """
174
+ func = getattr(self, "func", None)
175
+ if func is None:
176
+ raise ValueError(
177
+ "EmbeddingsLambda was initialized with an async function but no sync function. "
178
+ "Use aembed_documents for async operation or provide a sync function."
179
+ )
180
+ return func(texts)
181
+
182
+ def embed_query(self, text: str) -> list[float]:
183
+ """Embed a single piece of text.
184
+
185
+ Args:
186
+ text: Text to convert to an embedding.
187
+
188
+ Returns:
189
+ Embedding vector as a list of floats.
190
+
191
+ Note:
192
+ This is equivalent to calling embed_documents with a single text
193
+ and taking the first result.
194
+ """
195
+ return self.embed_documents([text])[0]
196
+
197
+ async def aembed_documents(self, texts: list[str]) -> list[list[float]]:
198
+ """Asynchronously embed a list of texts into vectors.
199
+
200
+ Args:
201
+ texts: list of texts to convert to embeddings.
202
+
203
+ Returns:
204
+ list of embeddings, one per input text. Each embedding is a list of floats.
205
+
206
+ Note:
207
+ If no async function was provided, this falls back to the sync implementation.
208
+ """
209
+ afunc = getattr(self, "afunc", None)
210
+ if afunc is None:
211
+ return await super().aembed_documents(texts)
212
+ return await afunc(texts)
213
+
214
+ async def aembed_query(self, text: str) -> list[float]:
215
+ """Asynchronously embed a single piece of text.
216
+
217
+ Args:
218
+ text: Text to convert to an embedding.
219
+
220
+ Returns:
221
+ Embedding vector as a list of floats.
222
+
223
+ Note:
224
+ This is equivalent to calling aembed_documents with a single text
225
+ and taking the first result.
226
+ """
227
+ afunc = getattr(self, "afunc", None)
228
+ if afunc is None:
229
+ return await super().aembed_query(text)
230
+ return (await afunc([text]))[0]
231
+
232
+
233
+ def get_text_at_path(obj: Any, path: str | list[str]) -> list[str]:
234
+ """Extract text from an object using a path expression or pre-tokenized path.
235
+
236
+ Args:
237
+ obj: The object to extract text from
238
+ path: Either a path string or pre-tokenized path list.
239
+
240
+ !!! info "Path types handled"
241
+ - Simple paths: "field1.field2"
242
+ - Array indexing: "[0]", "[*]", "[-1]"
243
+ - Wildcards: "*"
244
+ - Multi-field selection: "{field1,field2}"
245
+ - Nested paths in multi-field: "{field1,nested.field2}"
246
+ """
247
+ if isinstance(obj, Mapping) and not isinstance(obj, dict):
248
+ obj = dict(obj)
249
+
250
+ if not path or path == "$":
251
+ return [json.dumps(obj, sort_keys=True, ensure_ascii=False)]
252
+
253
+ tokens = tokenize_path(path) if isinstance(path, str) else path
254
+
255
+ def _extract_from_obj(obj: Any, tokens: list[str], pos: int) -> list[str]:
256
+ if pos >= len(tokens):
257
+ if isinstance(obj, (str, int, float, bool)):
258
+ return [str(obj)]
259
+ elif obj is None:
260
+ return []
261
+ elif isinstance(obj, (list, dict)):
262
+ return [json.dumps(obj, sort_keys=True, ensure_ascii=False)]
263
+ return []
264
+
265
+ token = tokens[pos]
266
+ results = []
267
+
268
+ if token.startswith("[") and token.endswith("]"):
269
+ if not isinstance(obj, list):
270
+ return []
271
+
272
+ index = token[1:-1]
273
+ if index == "*":
274
+ for item in obj:
275
+ results.extend(_extract_from_obj(item, tokens, pos + 1))
276
+ else:
277
+ try:
278
+ idx = int(index)
279
+ if idx < 0:
280
+ idx = len(obj) + idx
281
+ if 0 <= idx < len(obj):
282
+ results.extend(_extract_from_obj(obj[idx], tokens, pos + 1))
283
+ except (ValueError, IndexError):
284
+ return []
285
+
286
+ elif token.startswith("{") and token.endswith("}"):
287
+ if not isinstance(obj, dict):
288
+ return []
289
+
290
+ fields = [f.strip() for f in token[1:-1].split(",")]
291
+ for field in fields:
292
+ nested_tokens = tokenize_path(field)
293
+ if nested_tokens:
294
+ current_obj: dict | None = obj
295
+ for nested_token in nested_tokens:
296
+ if (
297
+ isinstance(current_obj, dict)
298
+ and nested_token in current_obj
299
+ ):
300
+ current_obj = current_obj[nested_token]
301
+ else:
302
+ current_obj = None
303
+ break
304
+ if current_obj is not None:
305
+ if isinstance(current_obj, (str, int, float, bool)):
306
+ results.append(str(current_obj))
307
+ elif isinstance(current_obj, (list, dict)):
308
+ results.append(
309
+ json.dumps(
310
+ current_obj, sort_keys=True, ensure_ascii=False
311
+ )
312
+ )
313
+
314
+ # Handle wildcard
315
+ elif token == "*":
316
+ if isinstance(obj, dict):
317
+ for value in obj.values():
318
+ results.extend(_extract_from_obj(value, tokens, pos + 1))
319
+ elif isinstance(obj, list):
320
+ for item in obj:
321
+ results.extend(_extract_from_obj(item, tokens, pos + 1))
322
+
323
+ # Handle regular field
324
+ else:
325
+ if isinstance(obj, dict) and token in obj:
326
+ results.extend(_extract_from_obj(obj[token], tokens, pos + 1))
327
+
328
+ return results
329
+
330
+ return _extract_from_obj(obj, tokens, 0)
331
+
332
+
333
+ # Private utility functions
334
+
335
+
336
+ def tokenize_path(path: str) -> list[str]:
337
+ """Tokenize a path into components.
338
+
339
+ !!! info "Types handled"
340
+ - Simple paths: "field1.field2"
341
+ - Array indexing: "[0]", "[*]", "[-1]"
342
+ - Wildcards: "*"
343
+ - Multi-field selection: "{field1,field2}"
344
+ """
345
+ if not path:
346
+ return []
347
+
348
+ tokens = []
349
+ current: list[str] = []
350
+ i = 0
351
+ while i < len(path):
352
+ char = path[i]
353
+
354
+ if char == "[": # Handle array index
355
+ if current:
356
+ tokens.append("".join(current))
357
+ current = []
358
+ bracket_count = 1
359
+ index_chars = ["["]
360
+ i += 1
361
+ while i < len(path) and bracket_count > 0:
362
+ if path[i] == "[":
363
+ bracket_count += 1
364
+ elif path[i] == "]":
365
+ bracket_count -= 1
366
+ index_chars.append(path[i])
367
+ i += 1
368
+ tokens.append("".join(index_chars))
369
+ continue
370
+
371
+ elif char == "{": # Handle multi-field selection
372
+ if current:
373
+ tokens.append("".join(current))
374
+ current = []
375
+ brace_count = 1
376
+ field_chars = ["{"]
377
+ i += 1
378
+ while i < len(path) and brace_count > 0:
379
+ if path[i] == "{":
380
+ brace_count += 1
381
+ elif path[i] == "}":
382
+ brace_count -= 1
383
+ field_chars.append(path[i])
384
+ i += 1
385
+ tokens.append("".join(field_chars))
386
+ continue
387
+
388
+ elif char == ".": # Handle regular field
389
+ if current:
390
+ tokens.append("".join(current))
391
+ current = []
392
+ else:
393
+ current.append(char)
394
+ i += 1
395
+
396
+ if current:
397
+ tokens.append("".join(current))
398
+
399
+ return tokens
400
+
401
+
402
+ def _is_async_callable(
403
+ func: Any,
404
+ ) -> bool:
405
+ """Check if a function is async.
406
+
407
+ This includes both async def functions and classes with async __call__ methods.
408
+
409
+ Args:
410
+ func: Function or callable object to check.
411
+
412
+ Returns:
413
+ True if the function is async, False otherwise.
414
+ """
415
+ return (
416
+ asyncio.iscoroutinefunction(func)
417
+ or hasattr(func, "__call__") # noqa: B004
418
+ and asyncio.iscoroutinefunction(func.__call__)
419
+ )
420
+
421
+
422
+ @functools.lru_cache
423
+ def _get_init_embeddings() -> Callable[[str], Embeddings] | None:
424
+ try:
425
+ from coco.embeddings import init_embeddings # type: ignore
426
+
427
+ return init_embeddings
428
+ except ImportError:
429
+ return None
430
+
431
+
432
+ __all__ = [
433
+ "ensure_embeddings",
434
+ "EmbeddingsFunc",
435
+ "AEmbeddingsFunc",
436
+ ]
File without changes