From 5e04b4bf9485cd73fd18f5a6359f1ed8c6f51bb0 Mon Sep 17 00:00:00 2001 From: anakin87 Date: Fri, 19 Jun 2026 16:45:41 +0200 Subject: [PATCH 1/2] add OpenAPI integration Add the integration page for the `openapi-haystack` package (OpenAPIConnector, OpenAPIServiceConnector, OpenAPIServiceToFunctions), moved out of Haystack core. The page prominently recommends the MCPTool as the modern alternative, since these are legacy components. Co-Authored-By: Claude Opus 4.8 (1M context) --- integrations/openapi.md | 221 ++++++++++++++++++++++++++++++++++++++++ logos/openapi.png | Bin 0 -> 35585 bytes 2 files changed, 221 insertions(+) create mode 100644 integrations/openapi.md create mode 100644 logos/openapi.png diff --git a/integrations/openapi.md b/integrations/openapi.md new file mode 100644 index 00000000..d473e991 --- /dev/null +++ b/integrations/openapi.md @@ -0,0 +1,221 @@ +--- +layout: integration +name: OpenAPI +description: Connect Haystack pipelines to any REST API described by an OpenAPI specification +authors: + - name: deepset + socials: + github: deepset-ai + twitter: deepset_ai + linkedin: https://www.linkedin.com/company/deepset-ai/ +pypi: https://pypi.org/project/openapi-haystack +repo: https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/openapi +type: Connector +report_issue: https://github.com/deepset-ai/haystack-core-integrations/issues +logo: /logos/openapi.png +version: Haystack 2.0 +toc: true +--- + +### **Table of Contents** + +- [Overview](#overview) +- [Consider using MCP instead](#consider-using-mcp-instead) +- [Installation](#installation) +- [Usage](#usage) + - [Components](#components) + - [Standalone](#standalone) + - [Pipeline](#pipeline) +- [License](#license) + +## Overview + +[OpenAPI](https://www.openapis.org/) (formerly Swagger) is a widely used standard for describing REST APIs. The `openapi-haystack` integration lets your Haystack pipelines and LLMs call any OpenAPI-compliant service: you can invoke endpoints directly from a specification, or turn a spec into tool/function definitions that an LLM can call. + +> **💡 Consider using MCP instead** +> +> The OpenAPI components are a legacy way to connect Haystack to external APIs. For most use cases, we recommend using the [`MCPTool`](https://docs.haystack.deepset.ai/docs/mcptool) instead: it is the modern, standardized way to give your pipelines and agents access to external tools and services. Reach for the OpenAPI components only when you specifically need to work from an OpenAPI specification. + +## Consider using MCP instead + +If you are building new pipelines or agents that need to call external tools and services, prefer the [`MCPTool`](https://docs.haystack.deepset.ai/docs/mcptool). It provides a standardized, well-supported way to expose tools to LLMs and integrates natively with Haystack's tooling and agents. The OpenAPI components documented below remain available for cases where you must consume an existing OpenAPI specification directly. + +## Installation + +Install the `openapi-haystack` package: + +```bash +pip install openapi-haystack +``` + +## Usage + +### Components + +This integration provides three components: + +- [`OpenAPIConnector`](https://docs.haystack.deepset.ai/docs/openapiconnector): directly invokes a REST endpoint described in an OpenAPI specification, by `operation_id` and explicit arguments. It does not require an LLM. +- [`OpenAPIServiceToFunctions`](https://docs.haystack.deepset.ai/docs/openapiservicetofunctions): converts an OpenAPI specification into tool/function definitions suitable for LLM tool calling. +- [`OpenAPIServiceConnector`](https://docs.haystack.deepset.ai/docs/openapiserviceconnector): invokes a service operation based on the tool calls produced by a Chat Generator, returning the response as a `ChatMessage`. + +### Standalone + +`OpenAPIConnector` calls a REST endpoint directly, without an LLM. The example below queries the keyless [Open-Meteo](https://open-meteo.com/) historical weather API: + +```python +import json + +from haystack_integrations.components.connectors.openapi import OpenAPIConnector + +open_meteo_spec = { + "openapi": "3.0.0", + "info": {"title": "Open-Meteo Historical Weather API", "version": "1.0.0"}, + "servers": [{"url": "https://archive-api.open-meteo.com"}], + "paths": { + "/v1/archive": { + "get": { + "operationId": "get_archive", + "parameters": [ + {"name": "latitude", "in": "query", "required": True, "schema": {"type": "number"}}, + {"name": "longitude", "in": "query", "required": True, "schema": {"type": "number"}}, + {"name": "start_date", "in": "query", "required": True, "schema": {"type": "string"}}, + {"name": "end_date", "in": "query", "required": True, "schema": {"type": "string"}}, + {"name": "daily", "in": "query", "required": False, "schema": {"type": "string"}}, + ], + "responses": {"200": {"description": "Historical weather data"}}, + } + } + }, +} + +connector = OpenAPIConnector(openapi_spec=json.dumps(open_meteo_spec)) + +response = connector.run( + operation_id="get_archive", + arguments={ + "latitude": 52.52, + "longitude": 13.41, + "start_date": "2024-01-01", + "end_date": "2024-01-07", + "daily": "temperature_2m_max", + }, +) + +print(response["response"]["daily"]["temperature_2m_max"]) +``` + +For services that require authentication, pass the credentials wrapped in a `Secret`: + +```python +from haystack.utils import Secret +from haystack_integrations.components.connectors.openapi import OpenAPIConnector + +connector = OpenAPIConnector( + openapi_spec="https://bit.ly/serperdev_openapi", + credentials=Secret.from_env_var("SERPERDEV_API_KEY"), +) +response = connector.run(operation_id="search", arguments={"q": "Who was Nikola Tesla?"}) +``` + +### Pipeline + +`OpenAPIServiceToFunctions` and `OpenAPIServiceConnector` work together to let an LLM decide which operation to call and with which arguments. The pipeline below converts an OpenAPI spec into function definitions, lets an `OpenAIChatGenerator` produce a tool call, invokes the service, and then summarizes the result. It uses the keyless Open-Meteo API, so you only need an `OPENAI_API_KEY`: + +```python +import json +from typing import Any + +from haystack import Pipeline +from haystack.components.converters import OutputAdapter +from haystack.components.generators.chat import OpenAIChatGenerator +from haystack.dataclasses import ChatMessage +from haystack.dataclasses.byte_stream import ByteStream +from haystack_integrations.components.connectors.openapi import OpenAPIServiceConnector +from haystack_integrations.components.converters.openapi import OpenAPIServiceToFunctions + +open_meteo_spec = { + "openapi": "3.0.0", + "info": {"title": "Open-Meteo Historical Weather API", "version": "1.0.0"}, + "servers": [{"url": "https://archive-api.open-meteo.com"}], + "paths": { + "/v1/archive": { + "get": { + "operationId": "get_archive", + "description": "Get historical daily weather data for a location and date range.", + "parameters": [ + {"name": "latitude", "in": "query", "required": True, + "description": "Latitude of the location", "schema": {"type": "number"}}, + {"name": "longitude", "in": "query", "required": True, + "description": "Longitude of the location", "schema": {"type": "number"}}, + {"name": "start_date", "in": "query", "required": True, + "description": "Start date in YYYY-MM-DD format", "schema": {"type": "string"}}, + {"name": "end_date", "in": "query", "required": True, + "description": "End date in YYYY-MM-DD format", "schema": {"type": "string"}}, + {"name": "daily", "in": "query", "required": True, + "description": "Comma-separated daily variables, e.g. temperature_2m_max", + "schema": {"type": "string"}}, + ], + "responses": { + "200": { + "description": "Historical weather data", + "content": {"application/json": {"schema": {"type": "object"}}}, + } + }, + } + } + }, +} + + +def prepare_fc_params(openai_functions_schema: dict[str, Any]) -> dict[str, Any]: + return { + "tools": [{"type": "function", "function": openai_functions_schema}], + "tool_choice": {"type": "function", "function": {"name": openai_functions_schema["name"]}}, + } + + +pipe = Pipeline() +pipe.add_component("spec_to_functions", OpenAPIServiceToFunctions()) +pipe.add_component("functions_llm", OpenAIChatGenerator(model="gpt-4.1-nano")) +pipe.add_component("openapi_container", OpenAPIServiceConnector()) +pipe.add_component( + "prepare_fc_adapter", + OutputAdapter("{{functions[0] | prepare_fc}}", dict[str, Any], {"prepare_fc": prepare_fc_params}), +) +pipe.add_component("openapi_spec_adapter", OutputAdapter("{{specs[0]}}", dict[str, Any], unsafe=True)) +pipe.add_component( + "final_prompt_adapter", + OutputAdapter("{{system_message + service_response}}", list[ChatMessage], unsafe=True), +) +pipe.add_component("llm", OpenAIChatGenerator(model="gpt-4.1-nano")) + +pipe.connect("spec_to_functions.functions", "prepare_fc_adapter.functions") +pipe.connect("spec_to_functions.openapi_specs", "openapi_spec_adapter.specs") +pipe.connect("prepare_fc_adapter", "functions_llm.generation_kwargs") +pipe.connect("functions_llm.replies", "openapi_container.messages") +pipe.connect("openapi_spec_adapter", "openapi_container.service_openapi_spec") +pipe.connect("openapi_container.service_response", "final_prompt_adapter.service_response") +pipe.connect("final_prompt_adapter", "llm.messages") + +system_prompt = "You are a helpful assistant. Use the provided weather data to answer the user's question." +query = ( + "What was the daily maximum temperature (temperature_2m_max) in Berlin " + "(latitude 52.52, longitude 13.41) from 2024-01-01 to 2024-01-07?" +) + +result = pipe.run( + data={ + "functions_llm": { + "messages": [ChatMessage.from_system("Only do tool/function calling"), ChatMessage.from_user(query)] + }, + "spec_to_functions": {"sources": [ByteStream.from_string(json.dumps(open_meteo_spec))]}, + "final_prompt_adapter": {"system_message": [ChatMessage.from_system(system_prompt)]}, + } +) + +print(result["llm"]["replies"][0].text) +``` + +## License + +`openapi-haystack` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. diff --git a/logos/openapi.png b/logos/openapi.png new file mode 100644 index 0000000000000000000000000000000000000000..7d0ca403799dcd65727504ed6be8fd0fedd3f43f GIT binary patch literal 35585 zcmeFZgI3QpUD$-I8ASxvyDh!NbpmYo^Al+a9DjgyU($Y18f*>U* z-Q8VMXU*)rzw*fqR9bQ0DUzJVwRC--y0}ZD z^(XK9nP27s8GE+h`E*`ODREwPIg&vVWS}%dlR zPu{+uMrPQ_`}Ww+P#(Ea7ew->-*%~lcwt3=-9yRM7Ki^E~He!&bp(UJ}Ke#PHk~2r6PYHT`|;Ofn>Q#7EveBxhHgNk?FjKC9J#|yyZFHTrE}35$4GFyB zWkE$jVpiyOZ@6_rF?ReidQUP|TkHlqai(PsJRc%Vf;$xEkq;KP5wg4(Q5J?0a5wK4 zCJf(p(_0zA`B0ieGlhz5SA+JW6;f5Ha!$$StJD#xgftMBhpST&)@d)$0zK7Z#50MGpjSS9@-cC>{};8lM@IMvOUM-gkx6FLkxwD>UX?}v>{mlF45o>a5q@XJi|0dd zon&!8Kf(w9MC7s(-c=JWIrmkW@NeuGNYuht$7alzxSbj`Y6=qP^U1@1`qk^Q zCkXE;9T2xUZYj;NfUetRqOq#gLjP<^JV*Ft%`1?<^CuVd`VIE>`{hX6gfc3^b3V_* zGa#FBb7_uv*zw!4aE5I~4}xqLS|<`iI{gSQA$IcX`4CZbl&Koi4>J3(l8K@>*a?zD zjBAKf)$|gTGP}0Q8&@6{$opt*#&TAL@LR9FZc`?&(}Mvz;(qaM@2LsTZW5#~ zAkDGCe?Os&L7_kj)aAeRD8oWCWwkK~llF_m4Q5@36{fl{_h<%AESUQsig#C0Broesys%v$K{H@fhRf?(~0pLd$DqAl)p zQLiuabd>x##|RIXF>vTrQ&XMfxsw0)$&GO2?`P4x|M!t<&1<1CG*LcFN9jnHMHJtQ zdNo#n7l&O*fo^QGVIJ?yeh?)*K$r>Q`4EZ67}UxMn#XXuPh=~QxV-I9*sj{4&`@7;!b1gq5J?q$uKP`VC-DiQ8TG$M|Bd%(=h`f(SAAs# zH|X(cQ<9j+V>7F6hf{dxrNy~^_lk-bK7a{3oHo=+;(=U%+O)n*)jiT3y5w8Jf8)= zsYzEc7;7zsI^Yj(i7!{w>7a0qtTr=!R;R|iZ#|O3xX?;5SFD|u%+tT>KJ1rj$MWpry9};CmjeI{a(hjJhNDK zig8RYU__JU`3NsEPdu1~IBwB3ajKOZzFb~arf%&!*8=+e{E$dn@xk)G;^i%2@2{#U zWl16)U>1a*wzJ;KvKma?SLAdn*!BaZMb#rkQKQ9exh~{E9go)WE`%E&G11I~qlfsQWh#WW=_F z_bxgx6IG@L?5Oan3~GH!m=tgP>wb5U=Yp=Y_@JR$yXJOgB-6pexBsfl9WtK>IrDVx ztg0MlXfvq|)F=*J!FE*PZQ>obvwHtK?Z~rH_lDQnjx}_-o)B=Sag!dcf}IU`LC`6)n>;nQuA1J-8i=0)K<*Rv_x zRX<0y=i1vUH~5tNY;gRi*HW^#h}NIzZ;4qx|6DF^?cf! zt9G3rURPe^8WYVg%Y9+euRC~WYbo40?TdhNP@|GKo-7NQSZy2~Q4oYN8)31Ipl>V~ z?;4@~z!C+HB@DVKhk0!vj6W*@rJtu5sQhbd#crGpvO5Kl;RyzsM-$YIhHh!cI6lKxR-?ns*av_ z?pNKpOWdM+jBZNS_{4;nRIqq%VhKybZ!L5jZ|GKndR=>c(_CyP`R5T!>CM;{j(=1@ zSC+!16I_=VD*LiHBDO8!e#Nwg+L)>}VWUX*E>QXZ!nH&qHc~x4EbOSSh%?WzP<9>y z^gPFy>J$4@A(E)LV5?cPsxgma$b`E9N7-lzSe}cji<% z1@3)~<9aHG*k4)P2`69go?J5``n>%X8yOfVUD>(w1OeAl8%g zWALss1nroQA%x)&t0y=Fv~o6w&~=F)40c}y9CwmT7*wm%<+-RFu%PyJQ8^haX?2-h zitui(ARZeKZ@jRSV7y?WUT3>wAOxS0W89a5AQ2FF+oD{OPiuD2O-J}m6gv?cAqgK- zGA8rk(RZXauAd^Q(Q>Du=Dn|dCPQ5@co9EXlz0VRCIG3+|KSiS3c1Pkr`1lbUlb#j zD7|vDb2fSDC|bUEJmk1XiIe#Y;iG?&nTot1pDyGAVSKM(82<)AfmPXmUDmp_ZMT$C zqD*hm8WIuH#op&mnv8V}Wg@ERX=Xadnwj4RE%3($9jAUybp71^dGua(!OFU%!{-`F zYVw_5?SSUfM2Xtj5QEK~Xv|CMLY}*`rg%xFve#1_EzhORj=Yz6rdvLl&!p^4^M|GX z0Fb75_kEB^PAV0-8|%SZ{Pux@?-q}$Z=PeWjEZuV1M@dG5yFZIfY5MyaJo%@lg7Pa zE`MyfoUlLi-fG-yzT5H+ZtCpDZNA7{LvxQ%Q5-l2+i@BV6kxew&-{q@3Xe^1j9hHZ*z!O8Vah1Yr43qWHy5Qe=h_Mx&YV4 z=UG(brAv~*qIjo|v_wlUQx<>oq9b#EO;`p0+VQ^Mixi|S%QsEyBv@k=BXXsds0GAf zry1~A!A2dMmu2C<#z8d?+m8HmTsN*=Y;#vpUW8nrpvV31&uJZk1d^=0@&0m^y+d#q z)!~!A-cH9CI6-Ot-CY4SdFh&Hu&8osG+`lL0%ShTPDh(7daB*vNL>BuE4y7!wi&4? zqfl(RWZvp!WW?8A6JBFMN_`C34j+Sc#|Ip@kxURx>Apr=rY3y586qWDVPGKMLV<^X zj7RShmVy`+`$#){?{Irp(HiWCvi)c5p`5ORgu)+IXBOoC>Pj2A3jV1mWDOxB*v^PR z1ElSnl7vqR=sK~29f);I@18(Hqqg$4ggG&Mr22bt#8kZX-oB-~TYH-&de3&rQ>@W* zaQYU(xcE?`LpRuKo;J2rr28X$Jook!LjsO3uiC8(qQcETruPj-yUBTU;GJ`LzbzsA z_*t?h!8>{sHDDo|7}ZnizNXV58@+Oh$tYdKPf)nF+L)z&CSv8(@U_w_j{rah1s9F5zUYY3P*Q^((w8Y;;>*T)6QNfGRQ>H=+E)yJ?dupJ* zSl9P?b@QYi|0}tydAmwlgcE=D*jo0Hm91?SHqlqN2&2~AqN2FaF>JFu&FgtMRZd)c zCu4GF5j8~zlIGT$neg`e^S(PW!N_m8!?RW?9Ie~2y2%6j2MnA1qaRiiEek_Oo%Xi^ zZ&T64CeNoO2#EURh%D}xi}nZac@&U@$hNee-^WzOH-BI>&MDv_q+zq1e{$oRKd^rc zNs8=QYPtJpZE2|Z{)O}VS+m~XDm|SBblNN3&X<;$jb38KV~=o$ZaJoM6zq&b+)uTp zqNk?>s2xC%G~*v41W|ZXq#^#sA0+VQGF~i7F=jwmi)yj#i>r2aR&FSYYL7qom6VVr zkA67$Lj4D&vXE$9|54q3XWUr<9b?1}cWW(1Xz{!P??CzW+j^-x`;U$c{;@5P85{b| zu9El{Bzh=@qc^_|3Z^`Z+U}~0+xj@yo$@$+(Zb++qCTduVr!~8rDV~#%xb&JZUn7m z7)}4K+h{qaliUGwjHV@(Bdkk~V~PGaE#=|LmggYE5yq4|C-4ws(RHR$I}s^&QV}B` zeZ7Cn%dmt73fBgyx>wE4iZ=8Fp#JXqTjJ0Ro}AVw+e&tVl&)t6iOBQA-~ zwT0Zj*D8RzFU|2R5GAn3C*W({8)SV}fP+EJBz%#z@CZ%@GBK$Z`xCUSdhEFmTT{EE zk8J;~`fXch&_(~{x@wXknGZEj=$7lsDV9)StG}%m7$^w=uKED9%*cI-1ftwRQ&W4N zunM{%9%LNm>&<9e>vP)oxw*{Q!#G;%dm>KH??FNVd8ekktiQVlNnbwmx2esVsf!W@ zE{wzCI37bsY3@+R3U<8DqKOnYBV}r!cHgrStKlC6{s4m$AM6Xdf3_wj-ri|sIF$!C z(cPlVl1ce)w7q5t96x*Wr(>U(Xl@m3=rH|()Xo)@Xv0SQ?*&vg|0s|vT{sRT@F+v@ zxPsg8NY?6@>((ahpLg;}=7Ea}tp8W_Zb4Bo_St^;lcHK7U8$G2m#;?K{o zyG=jxY#A9|gy1;GdfcgS<0{q-&Vq{kNho*+UIw)#{?S%pwlC|yZgq0L3Vaj8ek!MF z>pT`Gx3Xiq{s_$YS2S7S&pErp^GR=k8cGtx>?qtbbk#j;QRO(G#OjTI_nC=i@P`by zyaGhh+{J{idwbi&-<5K8}*1lRPOxjhx_`$f>j_+Ef z@GY`K8Sc=*ITV>>!{ZAQIz2lb*D&guuCno1Q`eQ5GWH@tII!YdOe!C z%Z}-)GRdeF2%hsVr6!R_i{H-K$~$O2fH8l}{Ps9Zri=^wP>ftDO0XOLK@^b2WQfwT zbk$&2jO)f&2l-V+Tan02W0rUYQkCJ4j=-{|ArGD%gUn}TEe#h1@uyr z6?8;svkO<&eNoDGOqC8FG_+;B>9Dwegmc7Ymh|Y%>=r$4PQ4CSN}1gHjLfIcQG77A zuH!OZPR8G-9&CZ}j~fIX)M!fdQ|u)O9lqY3+1wwUcu4WwuyMf|W4Vk;@!&DDC{-84 zR*yB)(KGBnHke~xTpdCwXZ!|eK{HxDo4SdO0VxJkz{yTC}^Q z=#b>*AI40t=NmkI1uQS$rit>Mn>ri$eW3G&$E-?5BG!hsvBv6nAJ4;RL+Nd^E3T3W zRUzxC+RFb3^|jDvC)3MMJ`4zNDiR=8L+8NhVSPa-M1Q*s;^GSHj`RuG?%i<+2Lb^-zhjCx=25>}`{{RCxqwxE~wEvt@ z3Y~v8|JMWifmAo9gmm6-r-vouJrRBOX4NJc^}zr7oqOlRKz=l`pKwC;_bI6;q^7YI zTY|rSlDD4Z?hisqKl`bR?zbvsE72xy`fh*UwcMDZqetaLK$6>#xrr0;W+sGEne4}9%olBr1jh>N?&hQYVw{k zJBMlc`I8Mo`@*6(`q9rf1{QdKrLQ5eZu3&W$ehNJ(2q@#G`G=q(SHW@@$y+Q7JGLt zKrsgFCGmHU^Iy?lVe;?gh{o7cwo10%D(uZyVl5OL8wK9L~>q?xm-7Z&Z6&Oj9N zcoVq#KEa;FjIN7bM2N#Z<-D&O?>GD}G8tc=O2Af9XXF>n`uy6S5T$1^K;W*=$rheU z{4CM2Vk7>m88K)7f-!40S6=LhmkGEQ zXmwrna}MD|b2gOX4sEHOb-3lk@y+k5816*mG4`FBPq0s}TZ3ZaoQHi3B6~h+rR7#O zMn$36Won?%UYRX^FVSSAbV{Mp=e1`+78_>!Spg>DXL*p>xKB2uZm($YL^L+_@Z>mm(0vurJbE!zYKX!6M~v0$En6i zqKnMe-wNkq_qvI5N}P%>S-RG^dD1D$Ta5U7Rq`qhjtcy5-0pHsbk#v4>$w27_dTf2mIWAi{L4~MqpO4bypZuzPd#KL# zNY-$Fv#ay@0q@Ked+$fGMLHQgWIpCkx2wDvpV&!n&jLcj7Hl{P}B$aUzQ<;%jYlklX~O9?`*lg*fQEr_xF*@>uuez zB&vO{>VM0)@ygy*3o9abZ-{Bww!9WEJhh98yx#M0jMMC*T-nQ{yt6D%N$|t2gX#yo z!zw zy-W3K!K7!z)#(1{EViD~F=nlZQ0YvXo&}fF&!vMaSmorub}}TfL^3?J0-89dIrmL`l!Lv!@?9 zGtH$)cg8KM%@re>>%?CXOhZ$q8#9Uf3OLuDT*uK+sBTgS!@fl$W$IN|Sqg zNj;HzBwGX2ZI(;45sSoH~#`oQ~3{i(tV29(G=Ab$=Q z@)Wm@A7<@wE;Z(qW*r*-XsPp~%|gShpP1ctz8Vm~+sQrdvEN-^W5WkQCu063Aah&>@r-L`h^gmo$vUw`g2A$)7nL6y(cDath7y@GM+$B-Sf zs@ax0x*yU8A+ao=cSGC`*J@)9J$p(^xsZygXvGRq6IsBQTrMI>-xhDpm)BHT4&6X_%=i~L6Lb0cNw3WbwGaWH|=g!(7N1we zaj9}_n=_ZM^9VvE?4MqMw#Ii>s8P(02ZV?qH^qmTppBH0=R0R@c`Vl*B@?SOFm-yb zF~!JlOB!M*kI+%>rctIwDathrxtM5v*t0CTQx1ZdV&zxQ~TdWQj z?i*EqT@mFGj>0Z^PbK$p+#Z1FdAH=;6@w_ZJ5DPVuCb1B1sylDxfIq;ql!GlUVb=t zwa`I)a4sN9eyGDYFNFX(|G_hZXkXT#1#mHfA9R*m<{0!8Sck|p z@>$?)qD{39*}hTlowwCE6&J&9xty{3rW8oJR@CTX$&=mYrJ%g>8cxTQZHtX6WrO{= zGOy_K>5*9u>t)GjNX-6_`6R}ri6)J_V`9ku6|^cDe9o#c0CGKUz`%nM7xcoJ7J7q* zR9T)6hX8wg-Ka?|id{qzy+!&p+o|#fP=}Qw5wVrREzjA5uJxv8S9TrIF5qfem`SqB zd)xYRLAvlwgb{AK?B0h8ZL|+H1^+0(EZJUGDvN8gHo2Za01d}B60p(Ts6I6K_!e*w z=tGFwVL44~4mQ5is)Z6vd%xI8?isKRtT*Lp>->N{6Y_DEDST7igoV!{B^JY+_}QUN z07oJsWW(pSmCcplH%D=F+Fks%zft|ixrQsVHp{?c9pa}HxU?0~ZU#mUL9oSs*kXNV zMQa-s=GX~WW~7fOnYYP1U?-3(msv177@Pa^$F%j0r;ArgWE|WPtZ~!J$)=&@{n-W| zX}vU06$|u)Y+6Q~tg$X>q4d%9^%k}2dUYPOsSc9K59Z?5;5d7a(x_#5WW8#Gu%N!H zy=lci3P!j1%=*HLsIYoMMbN1C`-R;T^S*hHEv~rq)1_cA#g?8!l#y{(tCCv*AC>#ja^UG5OeQY&$-!Vy^>y5r#eM!wtYpQ^&&sHSU+Rd?5oRW*SlhgjOFhv(}I^vt8$Z3axHf%ftMeWn&4_A*dWZPZ%iz&2M zvyX*52ct3GO`U!c?Ujr8hrL&e8eLFadQ~wNu5})# zZyk{8SN^%A6dSe0CHQgfc1MoM-UasWu^m^zHwpIIe;$Au;!sx)b{SjI#mN38Hu5z0 zJn+1V+kfK;`KWE-^Qn~M1SxaU488>%)4T5aMaAXp7o15zpYY~U_g7_+>E%xN{3}L{ zMe_i=ps->V0sD3mt+;N~sJ8$G@x*2&{i#i^v~PA5t~!yO zeGgvz`_nqRg~BJ9_Tj4=em(?#gi&D%0QiYsx7vJ70N{m}SSnJ@Ke%Y6#P6;RhA{w_ zF2FuvOy#rfa5>phD+~STRijNVJ^Ri+0z23BC$(dxda8bkP zyJSDQ{Zz?y%$4xQtyD>m!A0NwjGo+8l;YOdL_N%SXD-HcCi!Bc)!+U_nZ3=1Lo3;V zD}{Gm1|oMQWS^}vVxOZz}s0)rOvT_Wl6KxEcMcY~@dDcvkyl3^&<#DOs zN?m-Pq3vf#b+BW(*FmvJUzVMqxlprvm&bGJD_-Aw(CNjYho~j+r0F5aSl?{Cn%R?L ztVsP$gF*@J&WjC26@hzJRRc576=CML#WvK20ym#ElSzJcLghz4o2VvKGcPvmaF!>Q zA*w#x;+1TCFn1$HK^E zZ6T%;ck_J*Ww%#+pmSmwmGh?&tVGb>CiZZ!yRH9w(Bf-FPqWW;?%#ESQJ&9ph-{Cz5KFKk$LXf|>a6MB!) zXY%oq`}5Ym-hEwPZFIW$xMEzolEz57UlZh?J|`ucW~8(;%#umrYGGt%HHK!y3A8)D z4gXu&LFiYRyDpw#DE?Nq7T-k>j`8)lur;g7mN)`fAD(ic7i`P7!p90Lm}e*-W2m}@ zsrR2pyM-TlHvtt|*8SIIh$MYjel~QOWDIu+9UN*(0LRwJ*G2B3swBy&7$bfxBKF_Sl?}Vo9Y)3 z@9UVtF_m=s=Q7O&S1>hYq4T6g52R39Q2&dNzK&5Mul~HV4Q8P>zEf7y*!V;q4kfbs z7NrmL0vJ!TS$u-I^hE^*{iHfHiFvZoP?~$v*q8^LT;MBT*5=YW^!(a1NCvG{T+{R`Z+Hmm9uL+fhVlWt=+hQ!T zQ0+R@p$HjrkWBD!c9HqZ)Lc&D!Tc>ayIk`jyOXC0#XJ4#NxopM-fFcK`}uE=2IKq) z+L-tV*de#w?p?~cGX`c;Rf?AvX%+991ImRpw(>89_)NW+I{g&U@C~X2>UGAmD#Nrg zR_1w&9PPV@0}p&~og*&e$Kq-}9SGq_#&f>lvFHjd4B|}RBk2-m)v0Mysep(Ss-_zQ zWYs~a?OlFUG#vANF6|o!?(8dJmn?u?*%$UmSByS15^^UVihEhPDqq=G$t7qAlW+fK zQ5C;+Lvm7;WofQd76@~>x$FuG#GiaX1zL~RK9ZYA`~awBeivFQuG02GJ`w-`7%~~o zcwf~N1mn{+;dX9=C5Il#`rs-8?Ja&?ma9wQ&%9tT-`E}W-hzevfE<^01R+(h^z)9` zf%-PINbN5|jfYUcc0;Zd=T|wcEVtezP!Kluq09rht8dKjvTw-tiVK!)G!8qyC<*=0 zxFb#CWmF;gH8#D$A-_@YgOQO%N+9P#cPh*9z0Y(M&`$8G!A(Nn!14mOyvsa+_lfOZ zJpPO~WjcI&#F%M&gxXZOcot?|fJO&KUa_2r#-!x{;n`|Wl~V*>vgA&s&q@Lpd2G~f z>l!=8sHgj{+eq}p;2l~-sWc>Sm7S_e<2`}P=A(xSlH-luS@KBS#v;`tTFQ()pskFs=d;09UoRzNPpaS-maD4o$e5r9 z{M++;0KGRgSd*_l3z&G!ipa&tAy*V|NC(4XT3gJ31!JM~nzp~$c<533*6yjj**TJ$ ztuLY+(B!d!s%CtmQ2hDdaFlZ=e8qh>(C;A&|GY;DJ4Mka`}gyL{j+K79^9r71Y7)zbSp_k^AudVQO zQ5YX>%4PENakt0`E=*&* zZ=$BylAoYI<^VaZM@ORQigiO3cKcw1Do(?XfNWs~F`}2S6;5x;0@+K4~xm|~lGu;q61c)3!+#NVC2OuO_iRl@a9k{8t+3{7$v*qAy_PgHgo z&&oEKWP0P59}V4#{Rg+aVolg`yVp`KEK4?2Xt`AL8g@xdt~h2tOx@VrV}FT4s)#fC zfdl=oJGTms7_J+#=vnoqTURU3-Wbezla`(8tr>Cn(>87z9dJ&B5cwC{-Vxz6Eu~tl zr7X8Rp~GX@JjzsgDRJEh4PDXHWK!3JZ^!E_p9#pU&|b!XI>;-BXBzDE2V@l0TQiT# zd&fM2Z6$f_Gu~;?#Q}^IRuR#6c1hn^T-!=Ef zH>_QLw_$PqUu{_v4(5tF!hgB=GI6eQ(6WZx*(2WQ)Gc>;( zBlqCCOkwtZ^@8JEmrzjL97PI+j8^)NNI_1yW)7Sy7XVJ!Svpp{p7F__;vY848$?bl z#};Zg(B$#>;T9hk&`(;z+kA6xnZIcDX+J*S^WcT6U2@0|nj|6ixkP6v6we3CFt23!482 z+U15+<=Af$XyGm}xG#2laa9d_bJjlOb%oD|OeNEy5H2lTW~N6hR94Xjz5@ivOq2a{ z>g!*-OUJF7SeFacv!%}3^L)FeG9lA0fa75mf&RsttEgU=y@YA1``7IH6RrC6r0wEX z&q1t}{|2_Eny{pf+~lxGDgC0H>zX-Jgv{kiUlciYP+3Ewk*w#F9xrsUIQoDf~ zwTHX}kk7ymZb|YnGoYDqx6ATphypU7J0?_C#H+`y({2rIYz5~BiUm?IiI$y7^A>MG zb3fUwi$x}{Za<4H3m2JI9hA~~lE5w0-ub0jB^=|U2wlXVfY;h@a3X<_qJT*k_0Azg zZLVR>`2PYnSJ3|&K~_%1m4yX9Cj6VdPpqJiXhvt;jt>o)yv~_$wScCznp({ULjif8N>^cqnZBD{}A`{f7H%K=?=xV}(nNhLqD*)H1~p}* zWCxvwx`$DRy=CJFNO%>a;TJtPr5e&nE>R;8mwNGAUmz6Q0_Euy2C!d(mi!I!vY(u|7<3FkBFysWSc^K<{ z{m|i#ig3v@;t^;+ikl8Tzvyh^-D3>%-0Xw~>SlvQ>sNg=yJGu*8HZ;Y5y@e@^o!`a z(tQe-6z=-KKbHmzvh&`@0%*Oe9@Rzvs!(6P2eJZp!#{W|2Y+MNEe6US1>*L?Y=2e1 zGoB?qeHR+47K9D9r%IfsK6H||Sxi)UTXr8lg&D9H8Y`a-z0WqKb>u%(Gp zYMxg1Juuz1N^?3YM@-`GF`7wvmG$t&egDQw9P`liu6C3`(hHzo^01oBh>4~c_#PR& zMKQOD$<%Ro18BV9KOAD-Emdv;qA0at&3@}#4mslHYg7KOssnvzU$@4XO1~MKyB1I= z%u=|2&F3K(UG&(9>&LmIJYOGbqIp@x*`{RfKyx~4zck*Wl3V?oYxPKMW5{mN{8-c& zz0$C)7^>B3zdjBaMdMjigSv~NDF96xk8A4{xCpTU-yq#u3H=Zie4u>Jj2wR-Ry;Id z%=RmujHr0U>4{}tbmQ9!rC>{jF%PG_VujKrTLp1|k)$Z=bl z;{~2@0H2%AbI>u12m?tz0II`-%+c%0SN>roPud5}uUJaF)QV%1DrasmcMh)}Z}G>( z>R@h@$9JDXmqY3s(eoOHKh#8;RMjOqO&}(JgF+0u%V1ra2Z11O>QuGRD>Z2@{@QwX z%M*$jLM;7d15oj90c6E(aPH5^dU6&}uw2YPI(j2UR~61IO+SG-9xbQXXJ4^GnKh-# z(&bQDhqLH~29EVUVmF%aXPp*=H~Q7I(mP)mxf z4J^5WK{G#;-_&XAqYr6Vsvub1FX16=6V;W{gfZ_B{j}a{stjNoD`C#olxZWg*ex)B z%H5l5UO)h5@VOYYz%K!`H#IEDZ|k#!oJhJQ!br9>UUF#mVVslhAg&C-xdh$db0M9o zH+735wxDaOyT7?D-pyogdC-1<+`n4AE~Rl+gLqbV_gTF0OTca<1$VMncYY6(uKZcYOIpz!Ws#P6w_E9_q3Tv|8E~4-NC-PDtDePn^&!-8nF4QC8PtxGa7}a}gsY zAF;<)oqcAL5K>6ufIkx-MHPx)43 zqCe6mNqV9^q|7|v4pg7M=xA@)=$Dp-t+i9&8xft4AwhvlON#2di`DDUs6YUrg0O@p zg8xt8IfO1`VGP;>KimQjUhigp{cibjhoACeJy(JEyf+^BYsJ;Qr1azL1fYF`Jui4Q zt>8&!6BKwe1(CL3_RxcuGc+r}LeQS;_osjY?(<*yY8W|ou7VJ7ULFdI`P;8gbZ;h( zc1Uk!+dXF-SUZb42;Cg;k%7*DD8b3Lr_kr5gKs8A1JtO=uFnwKW9n*as?5mKm@gA$ zBRMNiAM&tw zDHG_s)9;GRreXr6wJ~+?{zAE8N?xc`qr}QAgf{WB%k~!dT&z6vP=4tBi>CZwn1B^! zBLWY@M=2g#NsYSc&Wo)~*@(L`tKhHtdjHtjGmB7!vtXQtB(^B&iPZ7u?_OhYO9Ver z*&tSfbt9CqQqmXp`wCreU4&3y*w6=7_l}$B8O-7!f^4p=mf2<^7sxsv~hQFE^G)ZCAA z+&^tY&q}nbY*{Mg(@-?+laE|e*X)zBfCkFf@wl!NbWhJGV~gjvxp&eb$|HsV>2PiA zFz{@^Js2-FXEqnnZkL}BNS}6mHTVM;0KxD3VKn#Mt)5~SXQHYpYdQeHU%3Uwy*X^o z3&w4dCOTSWSI|G#VE@1@hKjuWhw5RMoqOU@Hj+-$bHpo!BxweY2#fu{r(S@q3fJ4; zm*lUv%IoWK?`>$Q$j|0xM*`!9Xox$-|MrInN1-CimPo2HyWqo^;a%a)p}CWy0RhzH zvfegHg8=1vuNtp)`p5{k+&9i+G=m-Mf2$tee~ysM7obW+127!u zs%pl_UO!8v)mNJ0a8c#LLD=r#GsqFsL{X@e{%blh*yFz5^V{+yUQrT{&QrE=14xzZ z-95lo;}>0^woDVPSxsUhdiE|r%V6&MMwO?<$%f+BddPf|n|!pR+r9GCw$uWSf5`TW zf|lU1`@D$bn??QFbi-#J3b%ic^@3)3t2nIG>k~GR6tRx~3X2(&ZpVZi!CG23sa}2{ z_yM~NG;$lq5A{HRsK#(-K`mfXS-9cZ<}os_B}28k@=jGmGm+X&kUHQk;6e%kjAfH? zq*WU)XnovKAMc@^UCkc(RntX5$={BKVi!COQX%d5iM!dy%NQ`~rA#!dC+kHK?nAU7 zCf3S8`Fe7NN8l08l3L~EpOL8V+7^rnKge%Ui;&+B=k^riiz*6dTk<_i@G65^<2{3| zlP7r$Zuonz39E$?`je|v#ita*=qB&ZVlSP)LniU3pkb|I^<2(^RJSZ- zMnq_xA>36a1QjcP&herv&#jwIayT5x?TaRi zh(it3_L^-kDz@?QbX&JwdcN6kZko``3%$D;DOqy$On7PC?Oxhlnj&>kJQl*aK-7b3 z@721)XH?|&Cs-cvcq?NKA*y&?H0tIh>wazbLYZqwZ(geV=)(>mbz}yo?m+Sf*M<^OvOM3y!3ch* z^7-a#d6FaThZR4b5jMK#~?3lpeO} z&dL^zS0?cp0%*JWdW@sR`p3rZn>10x(W5j)w;AwBw)X~bE8v&^#F|e~AGpM~YCKd? zPM8I&(|H?vZs5h3%P^#hUX(`YI=Br>ll%Ph>8%rGSD^G$@;EYwfJLUE;n?Cz_K?+Dh zYU(d$N+Ui+VXl2fnZl?M8dh_scq=ppxG`maBS`pi<+8)#IFDe;3ybP`B9$ll*lhw(b(1vOf&gNnZn&W$sPU&+en`KIa zAiyq1{#1F5xXumttj}=!pfF>`#f)uCn6`AVZdyGd)$Fz=L_JojPZ~2QRQTC98O@%h zFG%MI1PCB|$>49Lmif%cDM(+2FO}HZ#WVcwHIK7@Az81lEt4RLQ_vAcBaXI^S3E8G_MnB_c8D55z0 zIv<>uEN0YyL=*CwA#_#9ujBb#s_ZPy&<74KI=s(FKYPf;O3!ilS_tg!tRVP@q;UM= z$AxjYnX!Pb5(>hsd~%PUeL45z)bE|Rp!*w+FgDPWUY}=x_#)`X^y~7xWW@)23JeZ< zhFe^5gxl(~C}H@kw!!|ybp8TAzG=xCF1XXUPAsvGKRWgeS6hQS;`Ht~-LG@FaAX)2 zm#@^2R%baX^S98DyIweZaNonjYsZxTzmQqMK! z=@l2nbD14(JHTalsDuV)pQ-IJ%3=1<#3*Un?JF>fXq`OL#6-0k_?^PX;YPeES}0jh zm>v29Gg@pTLO2sc9sx>CIsw;El~jSO@d|@`-$^L2hWtQn_RS?SZ>11!RXIgPrvRT9 z`xG6G7g;K18dVBbcYkiU#e;LK8oP{^XQs*z7Nqp41W#Blt4-B^rR7@uKzw!Awo#h^ zk+6W|hAU?7@j67{!bYfNskZY-+uUO;)GcirQ7yEu#&>O^uAT0p)-82x*N>Xpik(|x zUnmUK?xT}8-#z}`A{-m}op?Wc%%w5fQ)t@dxUkt-CPa#m%9TG=^| zvoXaI_2=OWDsqe_+-@$`lDFM`*wxktwY?wE4_jsiX)^ziTQH_PIdN{QFViKT)qO@# zq1wuMtn4}Nq6|lxA=^a-gKR18@~k4R!_8x9V|F|fFUQftfKajshR7jC(uOa0h4ywUQw1-3J3A zuJ9EZH*DyZbD`V|l_cn4lE;ZW5b2s>b{bH^te-$>p{lzU7JDa9wmjo-^L#`y*e$Yn zVyM(ANm7%6VkY__kM@1uPgxtVd@Ie&2XHsusCG@M0t#=A$p z3JKi4h(j7Wm_|w0Oo9l3?{wwL{+1!ywGs||3S1TuhC8`aE+rHLuVGV&FHh~n-}GHY zCJc{F;4nNsioe(8Ez}ifXGAf7mbu%cC$28UHWY-|Il&n}UYkMTPTY*1<7f|D%wG2R z=_w;fa=RYd=ip02Jc3G_3<@?mC zTU7B~?*RgHBAXEKonR>U*gn!ad&l{_*McPbRm0Y8iA8dR`k0hW#a2Iem}HZlC!Op5#334{kh!6d!@hE#@w&XM zg)wcX&b;|S?`zrEEfxpXhni!N~)o%2Z__2sA81mMbK z(p`hm@?)FgA*3_i-kR(ewTel-ZtUGJ_mZ+XugW^uCyIE#o%n9?vEZ!_Den`a+xOg= zEPnTIjkWLaZLb!FI@6ag4LXvj-wzc=AXr`Rs>QA;+wjk{JBrw_CG#1HA03MzkqFGh z^Y!}C7B{3uhmWe33|m=+BgVUQ>vBXAJ#56Nd8l>bMdk6h zjXTXe`sE$#%iIXB@8Ti0qLy7GQ+tof5yRy0DNgvt2n3?y;iGade%xyc9h<;A8oNIn zdDO37cV<8!p5EV#sLI1o_G8%)=TDG{mSXRn_DbjDK%a?Y^cGyYM}{bJ|AJAXRygp& zP9+<S&!ERa=Rj6{MI&*$}hgj7){Q>=(q__-M7 zX_%t|m8d|NMVGEONaU&od{>N;Vcrm53#GEb(O1dCDa>noWQY&@gi{uHxoE-u{H{O| ztrCBHhQC#ZEk}Qd7?-8(1s*j8hwo8~PmVRWP~t1!4Y@qCRiILMyP}uz_SnqAHR&e8 z{r9tOchy#Q_)3^}HHuj=cWipp^LS4q>Sd16iGIbQX8zb6L-gw#cy+Mjv4#?t)<5;K z@7T6a9DoufMC)3VM@qWnoY6pX_(mW1!LN&E27!A*h6gLSB<*X%(#0vquHzBxxa zTsH;5Ssxny@ra4|^VixK$D!+6oU?1fo-H4)7s9Px)X46xrhNCOidUqzGyF zUJ^?@J2^tQ!FT0CAMSNpss#7=eHD7xPO5-O6^nIZbo)<7xSu{uS+KMewIHjLX=2Ha zc(5G1K#IWfdMg)x?RZ&Pix|G5fV+x2DMC$|iBq7mn&^7-0VEB#MLi#Xci)v5A+?s~ zCBy6#Ow)Oki?wjj5D4jptnUeTL{qN|p}4a`kFAW?R=t)pwEchDd&|ElpFeJN zX{1ZK1PMVp1te5bK@bUnr9qGsmhKRg6a*xtk&x~XSdfq|rC||?r9-;TEPlOz=l%=M zlQU0z$?ncI^U3!oW-d5*-pAR3=C7+JgWaxZvP8iXkW_j8x1uJg`Aokgw#@0tC?Tag z1vcv7XTdkHn0P*F)bNRHIe-T`32u+-{PJqqrXGCDegXsl;*JkAEBHrH_u@BKG=CeZ z4ca(doX235TT4cqN~r4s2#sqO<0f>l!}i((f%4$$2rfQ zvR=6&p?y&9G(?Qq#5oJ2?x?Y`dM|k**0%C!82dU^lcwOU{Y2ofmM1@632VKrdNW&CXg z>z;<_k!HL#$4!2{7r?}IHV2)h5eLSMs1J?5q1YW2EHujkQp!nlM(DYcy@~G6x^s?& zpbwO*%SgZv+n`%|lhe72-)y*wtzy#2ed=xaRlQ-`c;59^$vq~_w0*f9)sgIT#>OYt ztU0WTumoo9hi=}>*G z{rlobE(RXYr$@$XfGtX=yjNWdQe_$7<`_PMoH}4bsXEtKMHWx_8eJ0Gu%JaY7K4!#iDfg`k zKp;}a>;ndqB^Zh{le`d4I1pFJPHZonnd+6kdBxg+O+!&#-kF@pwbTkqkaRDoZMqL` zDS1jUVfKnfQi+&7bclDoak#0inUX@=r45W;SknEV>9WLrNlTMY+uRYCyVth=~}4185wiRXpj7XBtY|c)R=A?*DX@;T)_f8Ma^KUwvy_W`~QevQrgN z12j!#WW<#x0me4_xIu;q(>XVsW|aSjQ0y>=k+^Z<``h$EVK_dO+F430_F`dQr&hnB`vw246<3VNeUY zM|R`C-a?h~_vOm8JmGs!_qSE!8Q$cvmKFVJa%ExsFmBs{3w(-R$6d!e@>u+j$6EzR1e ziZX$1gClzv|oS@;CsptBWP;Y9!loxOAlN6OzuCBHQ2Jg$MKV{q82Q0M&Y7K$7O7Udl2q6Ql zAK33M>?*|>IzJHc)vTmC-KLBfxI2!P(UD4sJ*-Dn=s-S)lbdomGW@Hg7$DCdz=b2Y zEAh@$MzS~c{B^!P?afcP11?->wboH-!Eu7NGBDXusR#0bzn9qP7n|jk2!EYE$_9>8 z_YaVL`c|vYhXrS`{ zpl!xZ@V2_;aobon617gKG?>Z|gUdknK@9z)?hV%AX+M}JasNf7-tv+D3ap^;c*h%O zNWBCn2u4t&X}8b^u*x?oh|Z5$9wp8RwW}Ja?BkiYN3e<7cwu)v1t|azT8#h+^>;mf zV6jeP#rc25T3=}2_5d&evbp5Rf6O$E)f(2I(-qTD6pt0ZLRA{sG*(r>jT4+- zruZ8TET~&TybQu@Fn$6C$0WCmFCJRcoD6+mmfH8SKV7dj`*Z|RmmCj*Pq?C$Wy!oa zXmFWLsy9|0&(ODD+n_X$uqtA!!MDN(2N7L6Kwy$_m z7GR)gRfgo2QJ={lkOU}+_?Kxl_pi?u!bK<2iX!t&Gw}6h1$O!-vhD5s@%T4KH^IeV zvX-|rW=C!Gw!KMUYzM&eV>5N?i+-m9dquQKU7=-YtKkHVzZ^6uv*V-V?y$c*!*My# zxwtdj=F^5YdMl-Eyg$N;{;ea)0W)f!9<%STf?en)c{4ESI)9G$o;Q;N7-W1+u0W>a1IJeYT(oj}NGs{c$1ZNssNLJS(wHKJeC#YDhacDE~$#KoZ@Ncc`?F z`4!^qj(VDp_}N&s(uw~F6&M0RNNRE zeB3QZuc=`j-65i9wVUWu1F6n9EcB1+aj}3P3~$A2Yf2d}{2G1RM#woEeFV?Pz~yNb2{sg| z*c!;jbGe+QaV7T5%D1)whwm}@Ua{_bLj3he2-;k<=P3GnT9YEr>@$-h!|N7@QuvrT zc>$_;_O#dPtSSQgS5x>eGG&a%;ZMMQE}#2YY93F!xZ9dH`jgqdNVNQTa&cD1vHAu8 z%c{_QIO1T^*|rf|H%5upApQRIImDN>b6ShXS5Kivq1HDx7eQm6NJMk+i`H2>!;H?u zF3uHi?-L;eqSECX6u)QUokeVR*9XzQ*!r9sQvF(*TDWd#lu=*V4T#3JZD<=`=QNw> z`p$$xg0^9@y_~dTHEPRE129{op6HwD`EwiAG-=64wqT_y*ZRbe^&I6|M&5zwWT(Rw z?fvhrMMqOZDu{Z09%c}*5$fT(Bgliv{o*Bw%k_>45?=8Hn1=SpO?&?6ho+5DWXD7D_!(%)WCWMijgaSDF)$CG zL#aAxFSWbldt%G&9kSkNoZ&yz9qF;5C%agfT?;-PulWYP3ial;-hVeToGH}n0+vh( zob|{_S$Z-t^p*6P=TjR6D|)9{aI!^dkT9b6@L8Qle$b-d~>r zC6_%$YhPfb!fk5dfPcj~n!DmP@RG-lt*?M+AjtM7e|Nev5Q94y?Ska$Aa+JX(A1+s9Wr5>%gIBT2FG)?V&> z2dKAWD%EU|*xuq}rb}K*C@>7ICYCc7eNHs0zuT#Y>o?cw-P1e_ym9S-5$<>$pSep5;n(DM|FnkV>ZsN6m#OS&WaW zw$VQ(=`|RuHs~6pz7>|fEB&h;xFg`2w&Qrmn9ZH0pNycE(J=w8uo^PA{PvYt?oqq~ z$SHgW8qxhb9PFwM^DZRbN{^o!z`)W%Puo>#j=bI>8omac>9Ql^EEpd=fEyYpxyWCq zRWqPj^%$6)vG%*qnVDguPmrc$=pb-Jd=NFj5Dy_XBQ=w55e@Q4O>I!q8d5~*gl2Xi z9AM)KSHk0P-GfNN*_98IiUW5nqwgE>skF@Czp|`PXrT#}Ga7k0?b3R08aY%9q5A=n zPSaFqw^$W6Q;>?G%%$?+88?NBvQ00WZy>iIPz z{A*%MUNO>nb}x#)8S9z-LqM3WX_PdmfN=-&!bSLkMj_7U^3iB;p4TDH2stRJ|(o zm{+o;0wS!Avp*|SV-RAKnzHx2weN?`EubY$Aei|ZlAZ4Z&fq16lLm->i?uHq{Nx;c zDQMEqp>*4neZ<0UpC8zc8Q{;YXBiA<{2Prh)?}^^Mov#3xRM(z5 zUIOwWkt6#%4yHyUW}9=1&7!M5;6lL+JROxi$9T8d8KdMm(c z8qD;4Gn+6C>Rt#ja$zh3IT0 zD5IB>5YjU;X1wD@N}zow;mqtIu?Kxx-%wDemX-vVgQh8A1)| zc2dJD46=XzvEBfFMD5A<6JzK8nHn!%qJ_BsVgl-F3Lq4lPc1YwG+9(sIJ_5G#xP4@ zIru<%s%9x`Q=C9SMN%{1;ia2|dA57p;^%=a^7?~jorK5{`P+?APKGjIpI|Urne%fh zf6#I$J}jv#e4yDC!dMXx>zOmXyw*UVT~@&-Fly)&FZ!im+APO%I#hQer=$(~`7}LN z)RNfX?=6Qj)@`iZ6xWphu< zXXpXpp;%x(^y)%Kt6T0kUP*6n^DEG;U9cyfOq)2L4!`hauK^0+wVU6v9NYS$^q>o4+J?Qv?{VVFGl?n+8X*1KJv32v6*0ZCDvMgI4= zIJ<5wzy$s`42J8B9Rbk~vh_D*9GKow)u>2fGKJ05-7i=1Ag@$RrI^`Fc!c zYGglB<#cxf=*MsO>LNXCvtyJ}C>I(i9Zfj6sf;w0a;rhxpCvZYlza$39?xB3+9YT-_MI;uF z5Wz=*28nM+c9{$@g~Hu(p?a#wZ+FS?wl3`%ax=-jv?RVsF-D*6il>3N<7D^pzcoSl zgkQz2>a!QkxrvxvH5T^6W+sNba%W$tIz8b$uGAf2%a-31LPNM+T$E2K(ei6k(C{n# zy-XPb@%{C%E8|;TT}5X|%{_{^k@A9h8G@%Nhh95TH!imfPgo^zVt#WryphyW z8nm|6{n{h50H!{Sp^I+MD1{lA)qYD}d*%urSf9h)fU|kZF9qc$#PCyCVJ7krV?e>O z|K@0A16PzjW^1>72WIU{sUrB|fEVoF6G+ApLoM!jc}}f_DGhg6ZPn7n zKPoxx7MPWBBO5m*xW<;jb6r9LOXpg08s+QMRL+x%!4#*l(%iFy8nMfOp&!re%>rAt zJoJnNP=8^oS1pNO^b^a~ISUnazPfVni+&(>NN>UWo<;q!C8UH8hE6%^2HMb ziAVWWi`&I33(c)hW6cjeB97?WbTu}P52gQYC3m;b?0NxL1r6%?yb**K@LYBESYE0H zPs4@5qc(2Vhs5=b(q7H8ZvGzL<2b%VX+fI_|F<9)d9PE)CC_6Ce}w7Xrl1d%bEC(e zj|(xIt-!Brtybs1M}eoN{WULiYTX$HIo zZ;;$jGmOCZc}_d9^h2WoXW^EcisY-KTlBW2Ng#mxJ6bK~BFW-&z88M1)&HJXoWmE| z$=TcyLHJdtoWE0xHzY9jk3DJ0huX`bh(UwPKYk8z*kP3{XO9|sfK`q^*Qrw9rBFM(}45uM)-Ghw5T3&08zm?dV9t%)lYj#PE^xnED>S)KauTi zBEV*|u2}Q=*m$N2YxPwF zvCJFjPj7$Kp~d}q(AX?FCTGKV<^&6+5Og7%PAaQ5$g70gOATvvP03p1T(*-Y|w8^zV zRYU*QX09hiG#J@Zsb?n5tQDHsu1*^eVX+|}hnV?F?n%35&iDZ#C?1jJj``!Tzy0m} zbqQh!({GmQ=ts;SzWr@qcyiH*Mnfn9(fZm=#fbdHCwz|B1fT&)ZEz%i18r!)?`@j_ z4*lE}o&Pq_iZFW7-o<9-wycl#8*AlnLH$E`hMbk1Lr~jc*k%5TNs5Q zPEhAK?KXFeFbKMv@78@pa463&U9Gm|1qY^px-7kTh&}w3kLbdBN}t)E_xmekM5k~| z9r3>#g9t|*!82$UX>`2BA_)6S?qp`bGW3V2wV;@So44FQ|8YsgSun2bM}qpz_3#H* z|6oUQHL92jhzb|6zX{Z@^qWlqVxV-1Q_s8lRQqeV4^E;F^L`XXJT6Yk-N%j~U3fj* zGr>+`>EC$4f4E!$+7=L`SfBLaW^3N$yw68k5 z9&Nu?Wz)TLj3_;Oq>Ew zCA1MsGWKxGBeX}#QhZqrX;XtMfitW4_o{F3LyECNR07%~uZop3TCg)jx+k)=NKKUx z>w|oq^dH^m-wMTcW9eT!y&k?8-PD2QdjLWVx7f_FXqS-~M(;kh*l z6Wi6-v`l!QChUYroL}R_#PI z%X`RBhC8lrF|Pw-YLjdH-;c=7+g;IAg^7a5m5*Mzg(9Me0U2iRwjH!LV*nX-D{slL zA9J>DQ{QE~-!p4mWH0>&_!*0NrsSal zqsMHVYXa>8#43u>2?35}p5I~AvjCj`9%A7g5{gp_l=iU2YYC z;Wv~5LMfaP@k28$wzL$*b&D%HTmJo!AP}w-(T;e4lnzV>^&9H>2XaW++6;lh2Hdz` zz7=bmKFz@E8ay-jc^ z=P?SRD&Cw}xMh(NB}AiY%GV^D7LyY(uJoja{-ga(X6kc5(SEjmyYU4` z`a?OSW392`h`efbhWF93fcGei!5~}5%^9%;V}X4nf7t&b3GmVt@7eeqQMck_Mm%&mQ=PHBy3R6Nw1M=lzLtAFFRs#1RGafjSjmfxhCc{28AR zGsfF&H)mxQ5GLjK=Kt}POM$=6C`BQxhMhtfYI=6A4ZbT6vhR`C3ZoTWew*H#4%8U` zt|~(TGsp`_W0q?Kh23MI`qZovpf;j%L=`Nv#Zfdjx3bP+&=pIxDd|A~j-$^e?ce=x zI~mxRK{!>$IaVnT;NLK1&mvysV;rn0ou)3-(P>TJdLn+T^S_-WlM+}it}6|L6F9Md z*xCgmNDoH;@*W~&D%$J(8)*I=RDtz+_+w!P(EvYOWtWN2#z9X2LUIf2S)lCKD(DF}As7V0D< zCa36$20pi2S%R|X-(dyh%iEj!&Qzzmx&%Lq6Dq)^{uVhe_F$P_h^ z;DdiL%-vIv@JzM@wUk_w7v$9<*XoA6wk==f0 zq$wAof;YoDubq=I6dsgJ#R9ewM+C#C z%`Oc07m@}(vJ|)!hfnXR79>vir7l>I&V&aW5;#I{f<{eXB19Mk9)pvT4^XOIq!#C( z(!+G~heo{b++vr>&SzGtKd1Mi9Y)*^O3sr8Mq_0BK7KUtl|J#E;{w?t35l&!c|Uq= zBLh6NsImC;Qmu~%&Wzhr9xt;^2a}@cKW&K+1(k$ZP}AWI;y^`?TsEinp=8;Q@CAyj zQXhL9SvhmoL4(&Pn=$&Dotw{nV*24)pZ>~3Q*7L}nLHpL%;uWG2#%vXd;&j}@3x{29&SL9#>^F=y|1V6F2>wdU{SBkhg{&x8r!#&VWya%q`z zq;|vrw{g>>aC=z)3x$1@NAybH2JQ>Qa1WW<326d$3uGvE^KsDPPChxh9I@xb+Ds^!LSL6nY?5S%U!IPlJ^n(uBg_jjUr?tUD1sN&zf-(!q`)A)q!E zfx$a+B54-m*GNK;(48u7Nx7A*zEf&xX;kNvD*mFKhQWgR4i{3vwG&&6jozDo1x3`1 z@6GkXWCRdHjU}+uq|8lAEPH2Dbg${KC=A}IJMThHL4ex~*2?{%@5rX%@dJ3vv=hTKS4||7G%UwMVnj9N3Col1N6mg4X2*Xb%*w_Udj@uU)@Sds?$9ECNHV&nxw*J0YWNm$3-1)}XS#`p!0)(BA8G4MLZUBqCQr z-nN6{oSZ!s!1{XX?c zmuYRQDtJTOtw1tdDJxXotZudLSzA)1EP}5%<4Y#FHLDRu`m-exnWY)5E|C0XP7}Z z0R&1Kfn*W{2cB&*T>ImmmO{Ku;p8u#7XVt5oR)lYnll#ylN()o<9TRAJ9BRW21LDD zV_LAHz{8fv3n&h^z8#gfEX{O0bRBraZqc@IIbHyHtxeu#Tot`Z~a- zEpaRQT3atNVA?IJ;Nlsa%2l9P5UX&n&NZ~M?;FsBBfa@v`;4Yrii#ZyiEPa|OPyIQ5zIGmK==kMp1UN58O@6n{ zgFaqJ{6{UiGpWD6Jg2L>S4BiN~!y|J7?){y5LWN6$G@BI(PM)BR!GrNW1!sQ!(edu?Sy`fa^r2hs`wmGzcYZJ zQhK<*mqa+ezkYYnoFLU{nA)W{=@}td<+fd|lMi&%zY5Ho0qH z;qD+2Vb9iq8Qx`w?K~66 zS2phr8si++^A8rG5|r8y<7Glk@Z-pxHx}WBualG zfbS5X`W60V;|iclnJ2Bd5DQK+_C66(30R2^Z3NU^*hskmK$fr0fP| zoplUpo9Y2*n**l{9z0uCj&aF0D?`J@x?+D3ynfs&kWITL>*XW7u%FWB4AWK=xHo(c zwV|d>6_ly10PO~GS5rS{B5?b25TC56QdfqYD$#3^Agj^6I#^4Aq?~yY8e=osUpN*& z=7vb;>g-MkG#+{#99Y^@(EuXD{AY^K5;Ww*xO_D-Rf2=S)UDio@|9WKjgmd{pyXLf zbF;30TV&SqIYQK*>dCR8xrA)ecwu;OgxwnDBM{DPoq-odeIzQe1csK1>!%vw@7Ew_ zdE#4nv67^S`ZxHG)^NuQ z=I$c4&B2%9(P%WII%EX3R3N- zjqqnI?GgymoVPSBC?7jwPd|$L+F-ra&!1s@9r7h zG(CJ0?mV~A7EB?l-;X!5{0)XlrFEO)39$XrzoZwy+s&{ASZ_?vEPb#z7|mZ}@lS`{ zo_#64rG|XspkJf%5T4WlI`Sa?3IG=AFSQsqk1~a#oq1w(FFrUqB9_e4cl(bQ@X50d(q#hhG7$0_4{U`uU zh}TVZ5WM>5yW5B(MOPe%)khYp%jij?ou$EUuTN&LsHRGkGNiej6qhR>0i^O$ev9~$ zmD-kBNX?nKU?KvlAK@DAxP)p48`WVRm! z)*}rh!tM<&5mGk-bjjp3FRO_HlqVPm1L6c>uxZNrt@}cyb_fStY`QghacX_==4P+y zPar6XA$}^G1lm-$McZGyxDpP;yW+8n%%Red2!=|Tr^7z&jXh=WNo3b=(g+-Ty*o0> zIYTCvzx5{u_)_z?i{|YoclXaBgQ#w0ikAxHMA8ILnU;>`JYR>Pk5XVV_Qtz-MssEM2z3BPmsN82D zi2zE!k4`#oMuD!OhdN|>8{vCKi;dKwavbaHAYNu&nwRDVa|m`4i2X>LFtZq0j zw50D_rXcybF3$YmTc3Gnhpg)B_r%sy&An$SZeXn}R}(b7GaeEOcl-(>+JG>Ju&w0D zW*OnM7qb$0XilqtbvOQph&w1UVvN2+8Osb$F%=G13IRbg3^ZA;8pPKgfdF}5(eT4z zJ>3-z1c?*^00=alUBs?W z+^JYS2F(p(?96CWtKoYs35rvr!p0JKjraU41sN0!IKIij2t50Ou|CHppURtUuZ4Us z9KT6N-wtK4pd*ESHf3r6t=XY_mZ<80uJMDfS(>sEJ!JrNwSXMQgAU3+ejlp7tfo6) zts(O#x*xXUFAK@d+3YYl6S+T*v6m|$XCV)i8w9?x0(boLt2wJ-bJCJUj4o6nO1u*= zefkVO5pmV$C9nW0c29+1V<=I|AA(We&p(#0`|z5&Y@T_@URt%yG?jB|>v6#Jh9nNf zjp^_)e@Yf=+jqc9#|W#J58S4!Nd4x0x&vxYsBod^3P89#+Y~R3SZpA?UN9{%E2PIM z_t$)NxIH%{W1-VzDBcL_%3=BE){wUI(v_5>08vm2R7}{5bY+u0>T^5icMm!g{0vVd zYI1XG$#v(pt~n)-ErUStf|MW0JxAqHe-vj^Bb1;PXBB?=HjX7Qn3cD!-1U>p4#yh6 zVHf{SaC##H9Y&Z{-M13JGCr$VdhXXkd3?{Sb_v}OY#<3#en2#qJ3`X-V+&qSQ(8yN zBs_FGz5i391L#1AG-NtyjEB|Zj(?;99id>{O(e?JMP4pI-p5CODDz(P#|+~n8@O09 zP%leyM}bfDqsRm>ae;iD?|WFG?IQkqjT^|}>z;xvTigoBQM;Ym7|VP_6-c4mdnntd zcMam~Y{$`BeHQt5T*$P$B4jc3zTc%#ahls$5onS}KYS4|ozVeanrREls`7P=-Njq* zNM!0%sJ)!9#(YGp&j%##%vZ+irawsX%Cjx+7HkABQzMp}_hlp6iw!$ZkM`bi)fk(3 z`7LrD1%BM|2As;&ZwgveXwQG6^4PQD?xZCzvmRdu^*N}x6AI40_%{MJ#muvcomo<_ z3~2+sr%{eY(r+v`ZFYKJLIhck0tzfXY!_4QRrI7*CF)*Pf`JG`_2?aAsg4JOX`Rh)<}TI22SU43!#md{S<0 zLuWy4O6_*qh9tJtTSaAzzjfdI&c9m9W_>4b4#E%iq*K0b>#XdTp!dY}>e*#k7N`gf zgZwsEK91uYH~_ZDuN1d^U}*krX9mWJUQa^sOBFOjT=7dq#z#q?8|=<@u)m-AOvqh0 zM8xsmnTQEqR1Qp51ciW!f+TbC?a^daBm=|h%Bw>sNWEAtxjMPBXPXO8ZPp@456Jr!w~>&QR`neT)mX2f|k85FZy6il9XuQEGNGx zkE)gl<9pohEX|lS%?)67m_V(y(csQ3WwuQ{5yUkTZ?2@<(8A)Z&=j9uA=dtJF{ag9 zAO(0KYcGa*j%#9OCf8vZe;Ud(QQgbJy&&HY5O-RRWNu1I!mVB$`p&mm1!T$}K|&Pc zI&jGF>Eqhvo_2whm2^`N7mr+E6{AF9WS!3ACPNzDaaND<{AoQ}KREpN0Dva#5lLlY zw(~k**;BuG`jl6Y^;c?5-8$X^ln{Fb7MsxlV32l0E2S(xDz|IB;%Mj`sxWl3zGj#q z6fHY$SWhu{EwqnbLM$Ty7h7Wjm}{^=1#4Mx?qf4c%O^ z6$2zexp5Sg(emYom34U|NN4Xz)VyE!v})us?BY$M8P2ish3*IfR7+)< zQC^T4zjB^rnh3I~0gJGTxqne8s#9LFlGTFIN@WpsnHqmwIRx@3`F#QYjzt(8<$vo3 z@^-B;mZzk+oe4H5B^;7+;}VS}mJI?$uty`x0VxBjA7eCuj2D>(Sb+AFi`ZT?S~C>P ze;Ie&*F+SMO+t|6#E0Idd4Y?u0_e7SyYm%Gon;;q>qE1@yRzbR)`$ji_SMa_-~+D$ zt+*nq6>?4ZkZUEGZ%8j74=$Yf6(A3&$v4OTQ5)%RHUq#;=UGcgh5y4Em9FzLR0}G^ ze*~4U!fB?%uxio>n6_1Qi}?UVBq5HX4rv9FTZej>-mf?2{NK?i647sh&@RIVqyoP? zQqKmK@o1ce+y~7#mN)spOvzhCIWkW4OghgMwYHoX)1PZRG8{D#7NY9eH@N$hi|aGq z>w(1&c&{8^80_wVrN=#vszMaUhNTtm}8o!owk<)rz&{c{vZYL2D3-W}V z^In&aRlPUk*lM7yq~I7%(=upJgcu6FIJkV;@iewoz*N}?M3yfT*1;OCN5*p)LEAk5 zULOSq=8xO&Z}0(ivNJ^Wpr0-kuv-(EQyOa-f%mV;tcn57OdI{4L}v0$z&=Q)Mc}T3CT2q{a zr>>X$S98fSA8`Lq6QPw4f&ULDcP)tk literal 0 HcmV?d00001 From 830e686eb6cb08591d53206b0223889847774136 Mon Sep 17 00:00:00 2001 From: anakin87 Date: Fri, 19 Jun 2026 16:56:50 +0200 Subject: [PATCH 2/2] docs: tidy OpenAPI page (drop 'formerly Swagger', remove duplicated MCP callout) Co-Authored-By: Claude Opus 4.8 (1M context) --- integrations/openapi.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/integrations/openapi.md b/integrations/openapi.md index d473e991..0cea3c24 100644 --- a/integrations/openapi.md +++ b/integrations/openapi.md @@ -30,11 +30,7 @@ toc: true ## Overview -[OpenAPI](https://www.openapis.org/) (formerly Swagger) is a widely used standard for describing REST APIs. The `openapi-haystack` integration lets your Haystack pipelines and LLMs call any OpenAPI-compliant service: you can invoke endpoints directly from a specification, or turn a spec into tool/function definitions that an LLM can call. - -> **💡 Consider using MCP instead** -> -> The OpenAPI components are a legacy way to connect Haystack to external APIs. For most use cases, we recommend using the [`MCPTool`](https://docs.haystack.deepset.ai/docs/mcptool) instead: it is the modern, standardized way to give your pipelines and agents access to external tools and services. Reach for the OpenAPI components only when you specifically need to work from an OpenAPI specification. +[OpenAPI](https://www.openapis.org/) is a widely used standard for describing REST APIs. The `openapi-haystack` integration lets your Haystack pipelines and LLMs call any OpenAPI-compliant service: you can invoke endpoints directly from a specification, or turn a spec into tool/function definitions that an LLM can call. ## Consider using MCP instead