From 4c678c77237302521f8c8593a0c67b4c5e102658 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 29 Oct 2026 21:24:23 -0700 Subject: [PATCH 1/2] fix(search): unify navigation and preserve action review history --- .../content/docs/search/ask-questions.mdx | 12 +- .../docs/search/connect-your-account.mdx | 18 +- .../static/search/assistant-action-review.png | Bin 25461 -> 100970 bytes .../search/assistant-tool-permissions.png | Bin 73507 -> 77113 bytes .../static/search/connect-account-details.png | Bin 0 -> 39639 bytes .../static/search/connect-account-menu.png | Bin 82707 -> 0 bytes .../chats/[chatId]/actions/receipts/route.ts | 23 + .../components/organization-conversation.tsx | 37 +- .../account-connection-actions.tsx | 80 +++ .../[credentialId]/tool-permissions.tsx | 93 ++- .../integrations/integration-detail.tsx | 126 ++++ .../integrations/integrations.tsx | 31 +- .../live-member-integrations.test.tsx | 107 --- .../integrations/live-member-integrations.tsx | 402 +++++------ .../integrations/search-params.ts | 14 +- .../integrations/secrets/page.tsx | 18 +- .../o/[organizationId]/integrations/utils.ts | 214 +++++- .../[organizationId]/search/search-params.ts | 2 +- .../app/o/[organizationId]/search/search.tsx | 154 +++-- .../home/components/chat-panel-layout.tsx | 12 +- .../home/components/chat-resource-panel.tsx | 3 + .../agent-group/agent-group-view.tsx | 13 +- .../components/agent-group/agent-group.tsx | 56 +- .../components/agent-group/lane-activity.ts | 63 +- .../agent-group/main-agent-activity.tsx | 4 +- .../components/agent-group/tool-call-item.tsx | 12 +- .../message-content/message-content.tsx | 12 +- .../mothership-chat/mothership-chat.tsx | 25 +- .../resource-tabs/resource-tab-controls.ts | 2 + .../[workspaceId]/home/home-fallback.tsx | 16 +- .../[workspaceId]/home/hooks/chat-url.ts | 21 +- .../home/hooks/message-reconcile.ts | 2 + .../home/hooks/stream/handle-session-event.ts | 1 + .../home/hooks/stream/stream-context.ts | 3 + .../[workspaceId]/home/hooks/use-chat.ts | 5 + .../app/workspace/[workspaceId]/home/types.ts | 1 + .../assistant-actions/action-preview.tsx | 114 ++++ .../assistant-actions/action-receipt.tsx | 96 +++ .../sim/components/assistant-actions/index.ts | 1 + .../assistant-actions/presentation.ts | 45 ++ .../components/assistant-actions/review.tsx | 388 +++++++++-- .../secrets/organization-secrets-editor.tsx | 5 +- .../secrets/organization-secrets-page.tsx | 4 +- apps/sim/hooks/queries/assistant-actions.ts | 187 ++++- .../hooks/queries/organization-accounts.ts | 2 + .../lib/api/contracts/assistant-actions.ts | 57 ++ .../application/operations.ts | 7 + .../assistant-actions/application/receipts.ts | 179 +++++ .../assistant-actions/application/review.ts | 1 + apps/sim/lib/assistant-actions/proposal.ts | 2 +- .../lib/mothership/chat/display-message.ts | 1 + .../mothership/chat/effective-transcript.ts | 1 + apps/sim/lib/mothership/chat/lifecycle.ts | 19 +- .../sim/lib/mothership/chat/messages-store.ts | 3 +- .../lib/mothership/chat/persisted-message.ts | 3 + .../sim/scripts/test-assistant-actions-e2e.ts | 642 ++++++++++++++++-- .../scripts/test-organization-search-e2e.ts | 287 +++++++- 57 files changed, 2985 insertions(+), 641 deletions(-) create mode 100644 apps/docs/public/static/search/connect-account-details.png delete mode 100644 apps/docs/public/static/search/connect-account-menu.png create mode 100644 apps/sim/app/api/organizations/[id]/chats/[chatId]/actions/receipts/route.ts create mode 100644 apps/sim/app/o/[organizationId]/integrations/account-connection-actions.tsx create mode 100644 apps/sim/app/o/[organizationId]/integrations/integration-detail.tsx delete mode 100644 apps/sim/app/o/[organizationId]/integrations/live-member-integrations.test.tsx create mode 100644 apps/sim/components/assistant-actions/action-preview.tsx create mode 100644 apps/sim/components/assistant-actions/action-receipt.tsx create mode 100644 apps/sim/components/assistant-actions/presentation.ts create mode 100644 apps/sim/lib/assistant-actions/application/receipts.ts diff --git a/apps/docs/content/docs/search/ask-questions.mdx b/apps/docs/content/docs/search/ask-questions.mdx index 2bbb9f35e5f..3776009270a 100644 --- a/apps/docs/content/docs/search/ask-questions.mdx +++ b/apps/docs/content/docs/search/ask-questions.mdx @@ -127,19 +127,21 @@ Copy the reviewed draft into another app, or ask Assistant to create it using yo When integration actions are enabled, Assistant can answer questions and take supported actions in the same conversation. For example, ask it to draft an email in Gmail or create a Jira issue using your own connected account. -Reads run without a prompt by default. Writes wait for review by default. Each proposal appears inline in the conversation with its app, account, destination, and proposed content. Edit the supported fields, then select **Allow** or **Cancel** for each action. After several proposals, **Allow N shown** or **Cancel N shown** applies your choice to that displayed batch. You can approve individual actions first, then cancel the remaining batch. +Reads run without a prompt by default. Writes wait for review by default. Each proposal appears inline in the conversation with its app, account, destination, and proposed content. Select **Edit** to change supported fields, then choose **Allow** or **Cancel** for each action. After several proposals, **Allow N shown** or **Cancel N shown** applies your choice to that displayed batch. You can approve individual actions first, then cancel the remaining batch. Inline Assistant action review showing the connected Jira account, exact site and project, editable issue summary and description, and Allow or Cancel controls +Decisions remain in the conversation as expandable receipts after reload. **Approved** means review is complete; the status changes to **Running**, **Completed**, or **Failed** as execution proceeds. **Cancelled** records a skipped proposal. **Outcome unknown** means you should check the original app before repeating the action. + Each decision applies to that proposal. Changing its account or destination requires a new proposal. An action can still fail if your account is disconnected or an administrator changes access before execution. If the provider outcome is unknown, check the original app before asking Assistant to repeat a write. -Configure persistent **Allow**, **Ask**, or **Block** preferences under **Integrations → ⋯ → Tool permissions** for your account. See [tool permissions](/search/connect-your-account#tool-permissions). +Configure persistent **Allow**, **Ask**, or **Block** preferences under **Integrations → app → account**. See [tool permissions](/search/connect-your-account#tool-permissions). ## Start from a document diff --git a/apps/docs/content/docs/search/connect-your-account.mdx b/apps/docs/content/docs/search/connect-your-account.mdx index 181194b1972..53968005c5a 100644 --- a/apps/docs/content/docs/search/connect-your-account.mdx +++ b/apps/docs/content/docs/search/connect-your-account.mdx @@ -10,19 +10,19 @@ After your admin adds a source in **Settings → Sources**, connect your own acc ## Connect and verify 1. Join the Sim organization through its invitation or SSO. Use the verified email required by the provider connection. -2. Open **Integrations**, find the provider, and choose **Connect** from its **⋯** menu. +2. Open **Integrations**, select the app, and choose **Connect** in its header. 3. Complete authorization in the new tab. If the popup is blocked, allow it and select **Connect** again. 4. Return to **Search** or **Search → Assistant** and search for content your account can open. Read a result and follow its source link. The Confluence menu in Integrations with Connect available before an account has been authorized -If your organization makes another connection available, choose **Add account** from the same menu. +If your organization makes another connection available, choose **Add account** in the header. When several accounts are connected, select an account to see its permissions and connection actions. The connection is usable when authorization completes; no initial indexing run is required. If a provider is missing, ask an admin to add it in **Sources**. `Not configured` means its app or deployment setup needs an admin's attention. @@ -38,7 +38,7 @@ You do not choose repositories, channels, labels, or an indexing method during p | Confluence service account | Connect Confluence. Both your account and the service connection must read the selected content. | | Coda | Connect personal Coda MCP. Service mode also verifies the parent document with its REST token. | | GitLab | No personal connection. Your verified Sim email must match current GitLab identity and permissions, or the admin's CSV mapping and project grant. | -| [Generic Secrets, Member mode](/search/generic-secrets) | Select **Manage secrets** in Integrations and save your own values for organization Home conversations. | +| [Generic Secrets, Member mode](/search/generic-secrets) | Open **Generic Secrets** in Integrations and save your own values for organization Home conversations. | Gmail, Calendar, and Drive have separate grants. Connecting one does not authorize the others. Except for GitLab's permission model, a service account restricts resources rather than replacing your personal connection. @@ -46,7 +46,7 @@ Creating Jira sprints requires the Jira sprint permission. If your account was c ## Tool permissions -When Assistant integration actions are enabled, open the app’s **⋯** menu in **Integrations** and select **Tool permissions** for your connected account. This option appears when the app has supported Assistant tools available to you. Set a preference for each operation or use the **Read-only tools** and **Write tools** group controls: +When Assistant integration actions are enabled, open the app in **Integrations** and select your account. Tool permissions appear in its details when the app has supported Assistant tools available to you. Set a preference for each operation or use the **Read-only tools** and **Write tools** group controls: | Preference | Behavior | | --- | --- | @@ -66,13 +66,13 @@ These preferences belong to your account. They cannot grant access to another pe variant="overview" /> -Apps used only for actions appear under **Assistant apps**. An admin makes the app available in organization source settings, then each member connects their own account in Integrations. +Search sources and apps used for actions share the same Integrations list. An admin makes the app available in organization source settings, then each member connects their own account. Configured apps remain visible when disabled; their connection actions are unavailable, and existing accounts can still be inspected or disconnected. ## Reconnect or disconnect -Choose **Reconnect** from the app’s **⋯** menu when a grant expires, is revoked, or needs more scopes. A temporary provider outage does not necessarily require reconnecting. +Open the app and select the account, then choose **Reconnect** in the header when a grant expires, is revoked, or needs more scopes. A temporary provider outage does not necessarily require reconnecting. -Choose **Disconnect** from the same menu to stop future use of the grant. This can affect workflows sharing the account. Review the confirmation before removing it. Disconnecting does not remove your Sim membership. +Choose **Disconnect** in the same header to stop future use of the grant. This can affect workflows sharing the account. Review the confirmation before removing it. Disconnecting does not remove your Sim membership. For an account-connection request, sign in as the verified Sim user associated with the requested email, then authorize the provider. The request does not invite you into the organization; membership and Search access are still required. diff --git a/apps/docs/public/static/search/assistant-action-review.png b/apps/docs/public/static/search/assistant-action-review.png index 6dbbddc6454c01ca8f5d7e8b1933c7b760b16f5d..167434244f9f4dbf55a1bcf0dbb6e8cfebcac317 100644 GIT binary patch literal 100970 zcmcG$WmHw&7dMJ@w{$nsCEY2AfYO}`(jnb>Xb_MPBn1ovq+3E70YwFs4iRZkY2JDC z|J?E3PxsS3!|?=i4tuY?=A6G;#OvNtC%~n_ML|I!xS^qP8wCZU2n7Xg9UB$CQbGN$ z3BNzx*Ui$rHN4w|iC>voxb zWzhUV!KvHDaq@%vysqQl7Z-=@S;TWiy?0t}^b3oM>Jy*8G&eWjUmN2={Cgz{Q>y&$ zg+qr%$nx){xl83iO!D`o7da3f^}lZ>mC;gEi8nGfHumuFXjZegFVnCc9UbL`7aw0$ zRn=Y>6Y~8feTibBB`Q3+%4{}+K0Tt5k&&CC=zl+r{WiV?f|ObG$NAYAd?)%jo{5fz z1|lj7O+Y;0^I z|6Ud;Jtmz>Jb}P%L4GzimA_Z5SJE3a8Ba=US!_-BhY0zD^-B7}qqu5uh=?fdss67o zJ!A&RYoo51k>W&Yxe!GqTIb1aEz5_*`uz?y!`Wmgc+lC7D6iRE6<( z@IVUvd{>x2sGHqDO4Xf;cNv^InL-j8f@`~ry)1Js^PM4Y!mqH%1q21*{e4nLadT~1 zJVuZBEn44R#^{#%?=5*r1pVGjq!du&EJWZ5wM3%*R8#Ej>A`;xUE=-q{rmTGb8?e@ z73$WX{I6t+tw8WO!?Y5C$7>)EM7$#$2 zaFbb(@LWRoMZI18p+cw0^{b(Zf$1-eQN;DebQ8S}j$SvB%D z)MuZHmE&l{-CP{=j!u0_zGdwG-ugOTD36!%RHu+Z8mqA3Z@DGh(;!L`=V8;*(yCWi zF-Q2mS=`xStcp)Yr%Pp!ReJGS`|4$Ak!(J~gp%20$CG#>HJz(o|~ z=dZM35ixwLcgm=!xc8;r>GbeN)J=6qQbrdER3;Tn1lwfIfKm-Q{^9y0THDj$zKmX&CU(QL45*|z(6rNbBfhULD7aHj|ie2Es)NgEj zuC9Jub6-(%kNeNYN4&6}d++k~PzmYq6DjxtcNZdJVpNl9#9DoRMBcf2-KIMd1A$Ys znDZKniJzZe6jh;?a;ixzng9GzL$@c&TDMDfW z;^GGKCA|fy6B0aJR|eAw2?_W4=9b|o_VlH7y^w5pK$Q6fgUBy$uz z^*a=A-|!B`uh>o=jc0O`<#ihG6oy?;ufDxguDmGjGEGcP9dB;~4bNEEbO*XhWaLhXq)Xk!n86<{BYr!k|+aqyz6r@VOa6K?llZ7h)_s3OiAXjr(@>A%MkE3^wOSSDbft1d1khMBCJ_x$vay1vhHKfxyYF+~ZT3!$3t z#uQH7$h7UB?O6#bVteZ_TPtRKr5T#*E(l(H8)9FYMx(#ujoo#!GgA4_g?AFQd}uJt ztO@-@FI$W+D2^P(HoLlLXsri%UaGC!MxF!src91GIKsHe26sXu(JdxCA57{cnV6VR z%U>%AZbYSdMdf%>_T7P)D~G$KKQ7iM zSz9Wn{m)OtzKmOS1}o-7#@1F<@zIPMYvqYL?Q*)TOj0GljAFU-W=?_G)x~A^wq;p( zGOc#QZrZ|mrc3p)%m1-_Y=*e|jldWeCJKDY|=WiiY}dJZ}iA1SU1 z&d28l8L5U<1}`2>n3L%jD`C`s7fNC;>P{_)dbrGPDC_z~G?TH;di-0PA5j~j`Z7!@ zA-qUt63QAgDc?=RW_iHDnpeleIUV!RA}Tcs@73X}bY9s4R@;-M165{C(QC^3JIe0v z?!4%^*p{~AyjGp&Ga`5tyn_YOP2W@p^#!2v0`l2*2Zp5W) zE7(TLXb`eebjL;3>$M17OOE}Ab&i&buB4V@T&TNtDn?^h^E*&rNx@rhHdu_!;JJR+ z<%M+0SLj`(4_aXjR)#V@zc3n~pTB$)f%cl7M^xOis3FzPYcP#j;?dgJOtC3Q3oGo4E+-p)r6V4dv+*0wwy)!rZ1FZBX2X;`TyFu>iewyNVPLY z*C1EUu0LtAHHhD|ruN7~@0LBWS5jeN;hYZLDMcH}BIR$+{v>LVyYLSQ2j;Rjaz<8q z`%7=}?4^Wf!#8NWre|hM%4x$_2j?4{KE0&A<;I2b8;y{yxaFEk4(6)9^7cZS z({UDYsW<pY5lAO!jq>ICYlEn!37Zs(HE7rq2TADYmqGsi)~G&AP>_rSNdTve0IP&uUO39X zG;1QHvTnIl(L;y%bZ0pyzKW+NH2Fg6HZiU6sbQEEkU^g$I6H zw)qmob5eXQyFqq#W3I&;i)=w9qCm!BnB0N?EP&s%etqNP3j|K1`+Vr`f+DZs1x+I= z_b6l7Sw#D5z){9;;jgormh8SerhB3oiUJ^piCG{QVwysPgF}KT=NUX95wUO>lPw{* z_O2kYBVufT&`3a1M&{cDwOYtx4ym&BcV5eOsyO0Lh-qioZ9Vp~frq-)O)vxi5R1ts zaUfBzCRfQhJ|Q0<`*m7gy%O||6F@KGp8Ns=)#|AX%n#oP(x|R~Qmc%x;l)KeKl%0Z zTZ@QP(Bw|?b(9iZNu%*6vU+03p&l4G`A#M7TA*0EXA#zIxjJh=C{$|FWdNePE>3tJ zwY$&DEwd}uP7*3EYf?vXaOJf*HsfmgOw5HItPuzk{`z1;e3$u)MuC(V&C~vS1B=n6 zx30Uzl<&p2prWC9V&^`7T&mppsY~#-oE>Ua$O<<=0`=>03W|QYDKrR_Od-eMVXcfM zoJh=;Gngz))GD@)fvpkeu?n233FM{veO=G6O4MAuDsB~|JtpVUMd9fwe4lWYXM%U< zL&bQWm~$FA(>vWqvE#M?O~sr)Wy){T5EC;onzM-d-5!hp;J}1s(s2Kyd)IkvxU$?F zi{|jACx#8hJ1;y+{!9UakR^Y-D?IP);t1(`P*R99se@=w6@SjLY!qKTL3a6Tv}{M~96)(Q^Ld182aUkj#m69#L1!u&}WD z>iqnCd(wzG)8Zd@vojW}U`q4I3tZb7qRg|BQhBUvi9+<_{nLzbzh;=NxD#7ej%F-a z@vj93C0^SPMS7?>zT#0#mGUA}j3=R)9_%6(O=6IxalOk%58#hRi&87K#GtnpWHm9Se)qyL;pHy>b4qi+&Ys+nO{a6S&>& z2B;W^<~!7Lw_Lis`N`@CW&LG3YQD4|A!}F2>Dtm#WWdK{Z}fs`qa)gZ@TBW2Z8>{C z-m%}`_)iP?P+^Si%kiFIG-gI46+l*nj{ zM|bACvav8P{2n}bd#u?)tNQTI=d-;5#%YT`JM&gG))Cd!)!V7d*8t?E^)0Hz>1&*8 zDQK+Lgr%h}9RAY>9yS`!mPEdCnQDaQ!bN+v@*ZHVxy-oZ(yMWos~@P@*+?AU437LF zun2h7>1DQ)AtuP0cZDlexW7+5xg`7Q0fU4GigrrtgP*vX?H(_I0{#Xdxa3RZ^wI+VDA|z0Pb%tS+TOjTCNM4BNrd+so^gffU%452(bB(TM z=!uSZd59WC-#)ujA(;J;PZRe0H|Wa1=G9Z^;tLK=ce?Pj^&>(a@|p;jF;CY66T=(p zl@O{uqb4s7h`tY?&~NKYOqqfsgGfXr3EG2=DM=v83*Aw*19{h719#?R1B^)IczF%C z$*M%c_et-euoa(*?mG1^5~^fQlxx#Qw|H3u%6m$hcLpCr0S($4${Ca2qpEtkC}H02 zFGMJL+*_L~a_`A?*Sv}2zN{@8VSDWNX&l;l*3BWOzs(w5(wBjjKVelTjP^OQ`cq-~ zw~#KB*WZY&=Ap^U%ddXtwi_Dl)9SoBjD{Ms)?Kn5lqpZgB+C32h8=uPS?FyhDZ7S8 z;h~#=Wer{!5@^#)V$Rk%qB8Hip{n23{gGXTdWe%sBc^#hSui}7_=}d3cf<7_gzMMF zp&7jvKMxOuahcXtU>BJcXx}=5C_D1{!>kktI*Q7zUg(gfT-j^_9K$W(KHph&nud4i zzARFuTO5ht@HurBt5_x?T;RS_eltgqdDx0nQAf_}O772Rswyf>6qp?OY}?% zi(j;x6}OmR9`tu=r>s&1{DB6nQz&OJkm!jw7Rr`2l)-6~+Bg3?IXQV-L?wn}z57;% zj-Em4;qGplU*y8m>S_Vs#IpnOn655)-!?<)DIfW^oXOL8bv!~g7v6W);Mae_V-O&U;HE9(P0 zxsIjhA6?BQ2}s=QpO9XoZaGFBirJ1G`Tm$oAX(*VU~Ud&-;+5V8Ph5GDpGc3oq2>I zb&eYnkW8jVjM_qnWRwfWCL}aWRllT@5?B@BTe##kdENJsb+?q>qiE6Qq+l!Xv?Sd@ zzuMB`r(C90=&=J3VUP(5WrKbL5FALNjv7UE)xa;EIled#DsC;aS~oA^_fy|ndK-sN z9Vy!!b{Se6ki-~Cs|$V z;;9JZQyJxl6H{QEqM@SJ^XCi*rAd06V%Pgt4ki zgqn-7aZd5b!Wc-Ke0*D5Te)s*7)P0xMvO-;@2?k?NW*II-Kuc(WQ3ol9S88u$!)Ewm%`=_t!*$$ZL|J}$41Xs7+n}6D=iV6vB|F0iiN3NohX&n<2gMoz=cg7Udi2OHty~MR%$9LMTN@%I)EhD z&ts<3TrwaKq@?6wU&90wIeF`DT0tgGGRkkz7uRQQ^Jw^FS!hkF1DE^vn+q4}E-m zR_>_ABM^hwuuZYBu=Hus^++kchNFckftHD6FZE6zZk~AuUS5O%Acn3|$Tp&s zRTAYMudwj@K`mC+cm(OAq9UezYYf<<={UNs3ag65>;{im)EHp-KU;-8fM)EqIy^ks z==!x>E87i}4s7WJa&8ve4Nx`?zK?f-MA^_Frj!BmURp|Oc(oS*f@Mcw7N1!opf<2p z1k9T!1_mlT7JESK(0C#v$#Jl|n*&OH6c!N}AH$j4A}-T4pi1CCwQxyDPQ;_+2I7N00#XR)N&& z@^T%BWt^Ox?V=(gz4iIkaa-o_?Eo()DEh!2U=ljo9GdFMZWHX<}LF?lxszUt3NPAQPgjr3Ul z>whN_vIj96Ucu@?03KqVQg{=w=r-HB7>1u{%%xvB5l_YmWwR>FfvpV!vPDPW1G0PL z>8x=rEdj^-t1xx;_J4k^=G1wTCv!p>czbwIL2W}xgQo-F+!%HR zCIQWQf$^Uv>z^NA#9a;~)5aP1K?%Y${MzXH|IC8SW>`{{+ zC;ysqgIxQGAZ!dTqGI53Er0Aq zekSrIKdSR5O%HxL@>Q~K`~M!3C2ZXS#^!$KVV7=Q;t%?P%Wi&a@di=0+OmUGJ{N8W z>xedqDJ5Z-RUA96A-y^uxnL^SZmqb#>k#o2n!+aUBDj2|HfR_WAK12a5a7 zk!@ILcHJF+0!G&{ zSJ(_nZc29c=OV?Zr69X_ja^(AD{L&T!nMz<2D45slW}mwuZQUB>cZVlZq7r6!;S^O z`+e+j6DT(zf@t-ngVnP+-(}So15d0(-eY&6o28uC)f(sOHGN_j7!|uQ!uEq{fH`&Y zM1KsXvx2_<6XXflT1GF8ZBCS?C>8s*Fh~&B-aV1!S<;5BoZhqiHRH1<@i__-kdU^h zepekxPOmaN8lSrq>pOQ%?Xl9%{RvWKWeCe87<36h6`nq2f9?pQ>noTm_A8hC=-i-2 zfdm479&z8{(6>{Cr1a z*azoSGwD9Mji&qnF^+vF@(S>_7P?I0kdXECjAbFUS2UfW=Ly-vW5Th&aY*#uN8Dk# zy$??b+V0SoFN}!6@&B{{8Y?b|hELU2ms8K~?7u`jx&)aH=D=s@0ePcWP0fHG|>Y5WDYLT1C82ItSjV+%pg!H(XU>mV!d_FD(5r53o& z83j{<`@hGcMBP_FbeBk$Zabv5W%+KvhG%$z!IXEg>5qj4-B;$4zXs(mj+U3+CISdv zn$NQZcac)S(go1nb4$2T5=(F;K)RBu9Nn6(May8uP;fYe3WK4ozI6b+yE4{RW~1Ds z?(SO@OE9o$&??;kk5D#P-UKD({VNOU+{ZcCt2o%$ZxlQ{1Y@BnQw;`BtuXPaYQXW= zD^;tqX!{MaH`qh(3oPEnq+#?{E|=iLoIZo{*(3ddKlk>{;g1is`SO=%-hdpYi9q1{ zVA?P-m9%&Jmb+siF$p`j2K(sP*hnUKDTAbKA9lXpDkbi%3#wP94cFdpL0iCQkfGwd zoka9eAxF+*K_Qw|f|J#=(%=Qfd*9%en@?m+_>n+FBX{p@#NLt84D@nThbrL(JdAnl zqx-$rz#aAey=j8ZPn9Y_A3TGjtr_VqYLWx{lqF2@QN$FjbEcJ=#){{cfzRl;V3xch zpuLWrG4tii5)TT_5x9%Fp2Tl?gt-x3Eq~OdZ># zi{$)Fx=g4pbPAr7gTXj98^$2XilEddqzibTEATt$8wqq*K1%4b+$qzDFuw9Y5m4Su zU#NQciP&QXL>k1z>_w{rqD}Yg0uL8#EZbEGu8PgVlL99}r*H5fyVk@pM_jt0wLG8? z%3cJ6E}Gha1%Mg+u|!kejW)QS#=1J?=l8E0SJg& zGR*`b-p`+3AfMv2j;P1te&3=|1NCHk!*la{g*%^9zA*_ z>9ryOIRlU>kVtvM36RhO%3p^+?woajRSkc*S?vyT&Os>T>8*VCL?*xs>S~=Tb1$K* zt1CUc)TTEU<~ck=y5}_-H*~)~T88c_4WCFOcE4!pD_BS_*@DA^awI@sFj2RGOVb4Y z0rYd!1&->z11NJIz6O_v@%ZYx$P|Uc$>ERH!O`5yKbbD<3kpg69|(%$HHeM<{r$@{ zvouW*?K8wPO~KsmGToQL!A3G+7v_$ymV2ABgh}V=l@4SLz?Lne^`h=<6s~<&bfLR2lJu^j7)r7X3%|vuzqWE9OkT-!ZG2&ZWoJ_3p!$La@mB9ym2vG7 zU<6%p*NLKtO|lQ{Mwx0DbuW~0ahTu2!o}d&XBjzeQ#*kzRVWvtJHvOUJZbLqPQ7&p zWK4d1Y4`~N9+LY$o6~wJ1A>9SuNl2cDhTiFbQpQ`wT>nH`_3~oABU@NS&Gn9Kgt^v6Sk^TIT&o+mZrw5+NzY)u zp;z8#zmKX=A3L?@gI}^?(dOIXzo&GgBc4l+>U2a!nLJCx@GaL9ke!!bpxRuAAXNgV z*#6m$m38HV;%Ap_ro|p=2VqhOvmNa`BRNVtcuLUs)9rLk=!9&e0i!`2HF3pfd{U*gGgGUZbUaFt-o9hYocHwt8Hkwns+acA5*w3qwsiUt)6bSCk5QQ2(oi zH_zgJV7}#{vz8b|Cwa>$&9k^}?fRHEHzvm6c+*zlYQ`GmUp~XkO~b>dlOWFO0SwUS z^a1mir0C|aTk~Z%G5|N61Ej#_aQoIA(dq=?Sx^pk>Cq)jIBXi|XeFV;cOh1x%dQ$T z-rI}TVPC1sqA3CG?XkE!^q`nB7rfsAJ|R8SL@;lDR8%iK zoCby#qRP5=xguCjJ%Da^w*g~;qETwVkZEFZJt*k(_~1LMR654#R@3}SIK?k>c=Vy5 zkwBY`DPQaG-7=k7j{C@5oHowSr(1+_t7FL{yi?1);4alWs(p9*dd>OMAK`-Ho1mtHyw+zERSH^wB1(T#t<-&`ilRlP+ z@s$|ft>rMlebG2%_BT`AbAgWoX{76g-J`e}>E8-->!?vli1=nHzS6Wwma3X;o`>D{&yTo7EP zv;j#P!nly?e5B3VnyQ!9)oWii!gCA8C7aHZe4VPx+`aE{pvob*?!xRsAfopQCtfCUHa}yQh@&(wz+1Cv2L)LECfEJW_Xy}(PATs66&f%{x@F-SBva3PYfXpKn zAzfN(cXpSw_WwSF+@f6W!pIdA2*?OHe`~Hic|r~{6p&Kr{UAaZ_1_CS-e#d{lZ5-NU{NFoj|&2?KZi~;!WkMjIgpb3}&$K9Uq zDul+wS~r44$%-|U$(<40V*3_%_0R8H5ZHD8%1w;i`L_kR7d06i3@Jm_cMknI^YgPF!g4@}0Q#=09I@T#rf z=5#u|32Zu>4tT=9_x1pT{e5L3R8DaTA+HIlDG45^9>7dyAS?rXdFNY;otxVnbldB$ zUlyvMt0Ctd#7~qmqL5<&$Tc=^enG)r7+|$%4jZIOko8my)Jy1lR5`H7(By%xCoMw9 zOr{cAf>wf*V)CpCk&z_K1WJLq7e)f;j9z;GU5tc^^a5nTYiesf{ro-$kqp2zMQW6* zO1H~zN?N}OhcKeN|1L^#{}b6DpaF(Jw!*{1L9?(f%OCyv_3PLeL4YO>~roLgR9y+1?mG}B zSTKAdA|o}JaICQ!u(H6}lE*^eu0F%$Uj7f)=hH{#l z&(2)PXpYcWo>s&Cf2QYoCF(@9mGQoYS{hFpo{>5q0SQr3pIm7+qBh( zd!M9TR9t+Z9X4p+ZgtlM4LNze%Z#w31E7i;I&?Zvq`owJE<=DBoUWP#a3FBTo-!U; z1yHF2KM~r2-jWt&oeO&#oc((hUtU=BVc!KyeGl@WD<6cC6c|XT zsB&OzRPDi50ZC&}H|{`Va#sdc31C@_)!zPKJGS#%fw z!6{Pl9C`OH#pr)0GT^gLhYXyZe{zLoWN}^h2;bW$DDiIqyw)2>lvp?i{ESh?zesE! zXrZ*<_EfN_f8ABh8)6=ta5U5*>#?L z>+e@1ev3wDD)9#CN$!1zmJFrY39teF)i=HcvN~7QCk-MZB75pqvI>xsm1FTW776&a zK!O2LnsPG2TMxF)gRru16P}w zf9(wzxBGh@8(Ld0KouaBPiUH$7#OSX3ffc?DWFUGJ40`Sa~r`IXD!v$J4buVLU4H^ z*d(Z^sGv@Nt#`U}GnNfCkzO{iK7SQrzfdrcp9zCvCb0x5U=jWwoFPET4}d>qEm^?! z0^tTaj>!Hh&}u$%F;UTaXf9mW`-}Wxng}l_q&K?Fo`7H-Y+&%Q85lEc=-p2M(`s;x zk3d5Nz#oai4($N`bW=G5)xLpg?J$~C3t%+|za`%MS^g>zCSw=)nLyEa21?&R#S#$` zstvw}L`xq<;K&&Sr#40LdCi+^po-zDv++LDS3mg)`xQ9HTTP^kPz=`1-(xZ9LnVX~ z(Q5&8uX{AXHO09716r5Q#?;V1HxTmrX_Pmax!>eKch-k+$d5NLQ|RgF1d|ZVKqc-N zR_b1{gU8zh5Ei<*Eyc~$p#%!Pgd8*h0gKk?zALVw>gwujl$U1*IzSZCeXM`OMPzZ` z!Tf;CicF%sPX;X=beAgdz+ejZDH%do9y03ft4m9-K`b9N09B9|%r;Jl3IvLyM<{{O zQOgILwMP^w^KmfQrtR1+B5uLChRwA#Ul76}t<9PTn1GChs1GZLO0ge08ObLw)=mL^ z0KrkH^U8yRXie-B1+X>wqIb)LCU zluk!N5}|=Q=3l=7c&q9b@x+n3HM3{{mKPQ}otKO)0=TCQ6FhFfKkD1z5-0)(D?@OC zg;sJ5@QG$N|14}nd^o2-y%ns24>}V(c3Lk2bh<%8@G}uBsANpo3g0Gb?bPup!R`W! z4%#yKle-YDt4V-I!|JPeCImqeW!m=uD*Ok&eU^4ft-sd3Z3Z>@PN&&m%^xG0_#Ud9ko+4;n*o2vWzvk>p#I#_* zuAtz?3)8`oA*dlJV=wodl8U$6C z-s*n2+<%DfpnxNhiL-LYD^psL+$(AS%!!TMIFc@Y3hl}Oq-G&tiLKBcneJGRH+C-U zbrOkzR}SLXD?RS0z>d~Tb&{VU9G<0W$)HI3AnoorqC(K^Abbruk%=!?H)2@1CTF?$ zOzXJ7VQTXJek&kO3p`iimxyN8ofN&DO5pdnf2S5TG6bNaadD&pGu&QTR#4Cb3=p_) zfU#xy3osr4z>?*?xJoPvGA2aw7FMC7t*X)qGwLz4K2r#WLrJf`U0Z_bh|LO?s!|61 zAeMpk;{FA>0!6rJ8SshyRVX6|lyrUzsh3(Q_&7L<7c92uc)YjEup39f>H|S?+GEw1 z7H4k&h5`xQ;9&p9k7C1EW{${nB_f#=>0`;X;==ddeXG!6RN(^vhJerk&s$+A5CLzx z%`~XDzX#QXb6c3;X0WvPU@Nei557$2)M4nOhK#fk$27PR6+kgNg9D(Y|F!y{EG{=b z^0YU=`ap;TklIgvBpCo=+}DnbFurz3EGVF-`MzKE{;3u#;qI?r1`jh~>&OC32ID9+ zG*kl}NH?sPa|`iH?A0?kxCHt#cx%+Tpz6a!tyL?#MinKz92QN2ut=K)^$nUcV=qJk z_jY%i0d&LquGUE=>E2azjO=m$)=c7!GghjcE^TeWRd-fQ!3u@MA?mk2xWYBOXUwgc z=&ERc0J-{TvFV||xbJ2^57ON#21KU+%G^X2Gaij*T!VUL1bW`cJkJ=sAHuAeLlZ}r zfa7DTcr-iC>0A_(SKIlz=AGF`bjxZ^>m{!CI{VZGB|UWSy92c6b_-n zMI;MZ(W%vk)-E&*23X9R6iF4Qn`Yq74ZYN+#zr@Yzdr&*6;j+%rF?H^T&s9Z>tfd|~3<-cxeC!Z*h=*L#_7-ZW>61lV8#&LoJi3P4yB{t2- ziG0H+C)7p^GX6Di4MEB-tahn%g5u<-3U z@8YZI*38D)?Ul^^D?RDYD;YPKML+vlC%smKw(xRL*Rh0>BJn&*LrHcY_CM7#nV7z2 zNLwKg*t490R5V1`#V?WRD!oJ5u#5a(_cUK4BMN$?4({&Ne(hPYh=ixHf&{i0RrkWK z;l(?&+So6eQY+#!I2E6zCFIRLptdcxIq~1yk>y2VEOHAW9Eph?AMh2S5-Zh9l#uag zM}t#v_Xi*biOkIm#ns!``};Q|(gz1MehCAS+FV{PJw?&48cIsiPk1h4dCM7c&`%^KC5LPd&46)# zJbb&+>0ob*>`?GZaKGGBR)excp7SIkN(CY+DIo!D;5A$$a7mC7#OCOwd@5sN-a@4c zjREk4`rG{RBNsR>{OwSoyb883unoX6gFh9a?_=RprCl?44nVUGPR1E)K>i2DZUfv5 ze5B3N-;fHNr~u=af}A{ha~V=XRRBalj6|9rUMqtD;%xL_RLDZA!rIyzPItnEJb`}0 z8w`^lpb0meCI&SyZCU@hK2GB6*RS{g{3#T&>j(W*cM5RcuOA-<4lB0*EftAgJ|e38 z2%ZeQ`RDiVafeqX!_QXR0ep%(PM~y0?*#xFNti-u=>;Jba8nz&GEm~#(4~R-K%U%X zvIIjo5duccv&b`vQabB-)>k}wZ_==h3c`dX& zfHTO0HSod4E`W>D?^s*IFoBJ(UQ!!!>PwE2j+<~zG<8v-Bq9Pdi$bXfxIdM2BLm_H zXpxy7khN`dksJ^PI@~~Qt+77Dr_w53nl@}ezW`zAfuG+%Cbh8r8{z+=7v~DK1QNu! zaDEPdFQT+`8IBwPX-5u;BuEOu9Bl(#nQWC5!ffe=3zuNy!I`Wb5T#-K!trYbYrUtM zSM4cs?gH=y0Z3^hViAt~$oTJCgVNLmrPmwfE)PiEzXe;@mf1(a&I& zJAG~Bi$%s_pzFbSu(N>n(??Y%xY5Jpq1ZZEZPf)y=miHj)*$7#oy27iK^HGnm1~2# zf(vVFu_d@;WH*Szicr8^TU%Q@n{@iOPfHjDIIdvj?G0ByWg=0i*8`wh9Pki>=5jw0 zJ18g!ow1y^3RX))e8mGoZopIOIo?o#c>*&MPK>Ij>>VCL7wwoZ=ZwrpwTW(PI|VzM zB$CT}C|ZdSv>Eh8yoZEFMn*{>4vFdKz%?&~^)c>4JWDwS_bPxtE-T=wBR6Sckzxn^P09@>Um&|ffYfI_@qK_TO1+Uq60C=@q!#1E&ASH=n zl&yXJT3AjI&fZU$-(>XaWoNgsCnG>@XH9T@Hm!7Oa&mKK~{tnH+1-UerEa zrJ&#t)xkIDFT0t0d&qo>=(8>ZcY;1UAWLXy%2Qq!XU9lb;x=pgH&hEjWFqp6@KUHI zsPUYR{t9lAk6!H+)`()5+nOJUsxL3>=09(Kr zG$_tn`G`f>BpduzkSJF=x&*Mh&s^>SdLGmYUhj3cZ#mF?p3tzWB_YpB|Ce?xVdUkw z5(oJYFA)SB?gUntC+^O_lo>4b19&Ixc21_uX` zIQ}-E3`_8|)8rPapwSJgJHd*-F2jt49FQ+~)&U0yug60W#sDM|hg}ZT9B`E3r(Yui zT?>~$Qh_(>Sj57`+c^ON*Z?L01OwWj0i4S%Zsk<92&Iw_ZLg|wg|=7Al_a{_@*Fvx z;6>gvTE8tCk5pA5BpR~V6N6xzT801#AfusLyMYAb-GhTf1VZ;od4!FCfB+kfu=zCT zkI)doJzy%uYUc@adI~0GYvRf8E!szRuC7%K@x*_B_{^ld}SfJ(X6RAIQ_j9^5X7 z&K-yXXo}CQSYmanpMw1it&&dC%O3iDnj4s646HncFDw1@G=zNAS*UM-;V}1ukC*qR zj(GIiL$WGF91>-~D>P@?vYQ#Y#k=`=D_IU0ou+##!3y)pJP<@^tQ{P(pt(TReIHC$ z)@AA8k>HA7zKYCBlk>GlLQoa?c4l+pON_H0K36!5zyO!|=G#aO=Nhw*V8wi_@ZL*PXE(Qz;&7=c6q4kq^e4m}!V{24LNJw!E>YYpw85oWR$rz9Yeflnx)K9qN$-Gqmk=?>>TLJ>)_la&8~l z+@cC7F4PnGIdo>^^KCY?++z02)vFXcT+PK3BpQle(p#a ze*qhn3OdOF_%_h-o!#B%LGn31oiSyA^Uk2^-u$t$5{&`)oSqfNB+|VE>|ILbHME|j zY6o(LJeUDF_;`I9aBvuQVsRQ3zg~$75bepDT+r&Qt(k@cfa=21;Aww20k;%@vNouW zVB5i^2#AKX!`V&b5k*HwN0>>O`+)APTD*{(td-A_cNZ=#2Sra6@WN!IaJ|l93O+8b z*MkRHSK?m#ibg@R3xOl(yn;|PaJESCU8KQ0oH-_NcS#S<$L%lu7#9yeFIo0Odw_Sa z6eQ3g^S$$>;l=*Cb4L)4bRG0JcxU&QS}d51(H0#*lc9MoSOf>d38-EQ?#J;$NaYJg z0MvJ_H((t$d2Lq4$~jqHQTdeEg5R*hKxMe)`v_t3zddxktkBAS1%sC>_0y|RSl|dW ztQsDVBO6r^sQY=5r}xYt$p|Uow-95|KF<8Lty86H(`1*Jxio}EIx+Oy%m{u(i#6~v7Irv=UXA`!|}fuHtxg7QFLR+XLN66t$hW}?Kki}9|0r7uPuOWWd6Iu3i2z^svW<8Lxxx7CrTtpI>tP8 zkwraet)Rt#b`%ChBqt~57*&k%>JJ04&$!#nYm6%C`f^aEKfSWxk?xpuQ;fpp6Q`E7 z?tl_j^{xbk2#mQewRUk6_UMksMQL4U`&s}sCLVPL{o(HycY2S0S!xqck!g-$n5;&b z5a9(uF-R?_A69r zDFxpvzQJz3<8j5*&pt}1NDAT6yvUJ*=9=>dc8?ku`9aff-(nEl z<-OvdW*uQLvdWsK)Fuw+g^$W=MA^hl+h`&N;Ww;IJkS1tMlv#36%wp!)Mv^kN(_;($RLWoZ!KNwF-u z;qb*^@ns$0YO(G>c>ejZ&{bv?!*JJ7F=_kw7d(m9mfmak42!y?- z)#g3KFFlS}EwV_4R2uG}K~dI6knviWxiIrGr$t5e;Fr;ad#Lc=2{^(&8JhHgW69B< z)>ekI@MhZq0Fvg-v#OKbdZf4`7w@HRV`RMrxR^B0w}A9E_E`1fKkJj=RH4$37~_3; z;Pu^3yu^+U4HESlIyI`(PFzuE9p0=#I0BOe;0=ltJ5|G8qDOOlY3n}N8CXnooq~P= zetl7{s1xZ)ZJqs)?K+y+>$r3b9|%{h_T5A3i7oasFIDYm9h8N9!mdqtutl@> zoNPNZ$R_gMP9l15Q&6>i&eWNixX>5SynDYDi)~IdOs<4KS~vE0ykKtoeFeD)j6!nU za9y2H(bxK1Pd@PmYPnTLZ}7c;dL{-bbY_xu;PAkOR~lJQ-)s(Q3U)&4_NrJs())6Z zOf8tm^dSOMuXKdbLoQA)dw8OK*wjO20Zr8_qD#)fohe(7(Bh_mI*sJigCDYUB{J9_ z@wY@_7{z1!)xikq->pllD#LwG7C+-wFKLK>gk#F_J-?&+P?>UK zaA)a>4H=v&cOt9ItzDWO__`N@KiM#<3_x(?k>rDa13eAZvvWXsaH1Z=;) zOdjcXC6?2Fsi#V-;$HnTl~tvDhx%uhGyzVe3xZ}wODW^sU_g3fkt@edraMUjAgg=u zVoEDSK}te`NiwGPHq%DMax z_K7(=ii3qBMvWsDRPGu$VaUkHD7rvkaf^la(S|J(d78YFjnnbv_g}-|B$F2c;^snZgVl#vh8kZ4D(q;*>;+vAY_Ute|Mu-$X3V-pfw1*D+Q+uInDP;e4m$@m z4$-lF2*(s>rFh`BkyqJP8L&Qvb3KHC`;$p3%^WwaEAe}FVc~v;_tki1L{2p6+>ArH zKk*orh>u7(5z$e5Y{ z5>@<3{~!dsvEr5lTKD)cY5gl9BLEH^0sOk;GR01GETPd?02>GD z!zkE6r$$CHr24|JYB#=A{t|Q=(^MA~B1vSN5Z|;aXEKxVR8;@}5clTMRQCV-sCgE9 zn};$*TbaqwXeLucB_d<(LLmvsJkN@f6gG*9DAhwqW!PvSDrpo7DG`ODbKUhk-}O7^ zth3HqXRULNzdoPpVY~15`!!sz>$+YEquY=TRxV2eD>>EiKCSw~T=&RZj!hMqPIn}F zzvE+^g&AMgk`gi)jUtzqJ&OAdEY4t3|hzICWDa7sIWh8p4~L-nI=Nyr%n`0TW1HR_c7A4DOQ^7RXP z+u5ZZYZfel-TeYKd_}PLL4lrt$^~g5(L!oYa)etK1 zjrMx&vG2a~MeS(y-O@$d$T?jf;>+%aPV}qmUClpvQXt=pvg)SGl6G9_(ZbQ?6*~YT zpmlUJL0$Xy`o7F0?yw&xvd4P*Q59=iP~Xpf|MLbgmb{1G$go%Bvh8Lz^5KVto28WR z-3qGy4+{tne-^@hH*SYBiIG1gj!*EIgjr5~GxZ_uv+}JjL~HuZ%OV$SmzjqL>y`#k zJ3d;7#*kHDpmDb1$Lm|-)D5bzKte@~Cj8`3&Aw^@!fb3&wNP}mRNHaiP3BGgiiGdmBr{4l z;mF^Mx5AygK%oKAXq8r`kp9P2`9`DXTXQxHEMHbMa5#RNy7F zBLTy7l2%IfI64f)&6g{hoK`Haq`F*jxxIsWa1}7+^mJ3C+hzNUlFMJ6U_j+|FRZ8Y z90o9$K6fkJ)w))(`+`L-01^)dZhWZp-3klMJ*!VW^sUXub0Zi)m9%H&cFYpGKF^ej zL-{Kb6B7$uCpY!1-}XA~_sHozSFT(Em=-q(b>H}+7>AroOV}a#?%Stp%XX?>2Y-pu zjDb+t%qT8u2IaXAQgLnK)L2nP10l5DayRFrE{p_)tlLpgb3KIA?0BV6@nYoS!VxVw z^#XZIVL?}6MRY&JxHRO7NMeCv;kDw$3fG));Va=gkL!C(x=VEqz3AR#z$}sON_21( zUS&Y1g83iq-F^U0-s3950A7YMv+GhHhb%$gk+`$PqA}P=zHdO!$x^NIeaZW1O7(sQN?$bRcC0j{CPkQTI!dT_nv@0Cv>NzaZHmfjp z{rK_2>_=0Wm$^B|KngXGdZVSzpKEUl}x5E|h$c;i6ZP}@rPDw85^i4nWZCXq&;=dbru zE}lt{wwU`582NKSri?0GCS!SmUKYH6yH9@HCF9N5jSsn-Y5OJfv+L8vjFjao`|ow% z94+G;&DyzH)hM-i)%wxbrg9P)5fcE?=|1cPCz+NXaWW(rdR@4 zi%EJP4cHRIL^u!<3g2x8v(hV9vTSEH$QgzJ)Df`_aAVGCVsKD@1&l0Hk?d0}!a=^Xx%e+Xv8K!4JTY z9>Mv*KyAft@x3pgtuRHi_6-mX-As*el|olxMuu43gJ(A?MG%gRlgSXg-6!Y}FX|3o zM1(FW@dWf^_qyFYPKiKl-tL7v9igSe;MlVRe2lt?#dV!oz?q1Kjt51PnYy8ok=-Q} zxK7T_7`d^?XB-yf5XlOvJ@j@(XbaH0se}6Z3~fWNq3ENVbOa3n z4g(<%dVOQjDR3NR&J#|ps1T-9m`J4(bOn6qz|R9~;}jfc0o|TM29YsJ5Cl;K$d_XV zW)2v!ps0L-SvvsL*-y_sp~ljwX~tM?cJi&1fb^37ljx^UA^S#2mgJxo4M;J{HW&Dh z1T7uG;+^j=u$lS-`MJJz>JkrAK2;d=5&OQaIL=q8qP%m z!ZFuD2?5IfIuxG8$*cLDc|_HuVU`dGJ=(y#ts>0$722JEf5lbH0Wq7C!+*2BO`65P zAzF6(RoCSwZ}`5L#&Lnq!<}!=H@smASDv+c*Al);Y>_p(+Ix1?Umx=7sCIE z${YeH*l9VVDVI(*7UU~f>tD~!#dWXn4c2!*5V*#LM!qovh1H4TG8#_QYz=N7V)Wb{$vx4mF$3jCd*qn2ssw_0uciRz6Z7bBZ zVp39tV3og9wkrA+B>U_L`ayt|XfueisY@__ht4`ZL{jw;+-|#@Fn5$G*$)|H zWteLjoVn?UuGv2H(@COP#`G?oA{>1{i{NhQ9zVgQDAAgxPTyR_Jd53&NCtR1`-yUzKD^)k+ zhPcUKZZR`GoxlF5N&u@NqSYNIfMNYfmB>02J2h@zUZE-GF*ZYjh}pZ( zz>u_JMaGN)^~)B64G;yhgjU2ata7Pw92O7MxB*QEMxK?d9?Yavil>^Vn_JN{FTtJA z@@ArfPX1>IK4x=&Z4pT%F(KqjD|gr%R|YXFt*te^RKjcIx$ z{>|z%Da936-z8lD^8%yLB{nm1`=4A(q+7wM5LPoKIO1u(CbAjvW#2Nq^FObfq=?l- z#{Bd3|Ef97|JW$}Us~$yQ^X@JPEJdMuZ6(W7-(d8g(5XD1DS>$BWA+Y)oS2L&N_q8 zML)SJ^Utr7vL3XM7}%gQG1j3^)Mo(Ld*&C+pzB?{T@nn7x*U?k;IuuszQ+O1nhkyoq=R>aSL|9tlP z_3JR^nX|JEFdKQ((XoY})LH>%EcBq45KXBMd>Z3#HYRZ+!U3kpLyQ2?7Pj8K7c5uN zCJ|cAb-+J|2xlI1c(7xg7FD=5!{!lbAmyJZ^G3Lb;p59^)6;X9O8nU@aSFoSq9EJGk$819LK( zls!R*v=38bMGIfuFao+*zBGa*k^p)pKgeYy4k|yX?r*gzMKeO_xb%TeS$roWOI#`;}bfU%*4+Po1*^=G3Ad5O|mM(Nlcu zU8tE*B>f>`$ZzjiMyY+N_a7FZTT4!dXgUG!FD?!o#LV3ocRzjZF?!tG3>=pcef;j( z>x;xIZ~PM7p!c|Yw??skTX8MpjLj~XH=>JM6VQg(q#kv8)CI6y(VWgS1!R~UAFY|) zCn%OaUeN&>=aa~1@bi(AHe#0GGz5zI6yZE?l9DtEah|fx@g(hrhK6BHC1P&*rlv|a!6$;nNqN&\A@U#PLxQoHqcEjtxDGin#K2&yTc zs`^fRn3{e}H9K%+B0`JV6CR^L#>|~all1HolrZ=tEp%uiksw)JvPDH9Lk+u4sFlKI z4>-IB*F1Llk$26EGpP_rh`vl}V@^qtFEI%KC<{;BAy4Fq9EzWf}<`H!AFA$OrX`2|D=Ly1ZyGZkUQ zKaQ2Wyu2WKFg;1ZRG;JFS`zB7cG2Q3I)r*u&6`lEGP}(IX%x-e{Q+;C;4{6F)osmqlO8K`E}?)TLe35wS{j)xn+L0u`bO+t`!jFToQm$_Ut6Oqc3q7(dQxyo+vbhI4?B*>(>Tw!NAZFdt`g$rck)3IG@9BzT z$&!!m1GB`1DC1N%Ed%nI2lD``# zlpDhNbmrV?9M2*{RXM(Sh71UTb1<46V@tpS1wC-_)9k8p_5X?b9(BzzZrSKgSPoYy zJpnIpDiS?Yk3q^>HWn6&kD0biS8Pn>?z(GW_*40ccsLGr-%p;xOE;N9fKPVa;VUS- zrcn9)%1k3`Rv`&AF_VjWY{Jl?{_x@6n>@Z;1&S@ z!p4j^>7T(hJHOouOoGF+5m|Sh#>B{s=?0BvS?z1??Im^_#3YfIfy^CPS5(NdV^y9udlM%#Ta0YG@ z*r8!Oyf7-#uEKhR#v8;ybKi68pv$b%wUnz(9%37#JNbG$69dW#nR@wlkSeBeDWJdG zR>hJ%yqrR5CI(&p5M=Ua6M*){tUPY9#4n$}jM@nPUJ|c5_;xSwge+r#;r2~nHhu)W zN%*$vdx1hl$&@^_Z{NiSCuB{yiaC!~TM3fg*-u5ytU{|D$mDzV;74F|NxNMxMnZFF z*eH=q=_z-*afzI{q(%<~3a;d_8tij~KbTr%H1PAO$0hlg>tqG|4NCXkE4@n^Q9TNk z%nhjba0v)5MT4RdMj&rc>EleM2RA)4vLeNEJY+V=RX3OA**N?g0fQ(rU{LOngEHT3 zKlHl8jQ&bCWA)$K~@Rzx}_^)z2yuOGW0W9$ru3ws@9+@%m$qG8k zoUoHR2Vdzz@0YV%xa7l~YA^eU$MH#Im4X}KTn)`e4(?9mcuME<{1h+1VRJCyjY&Q+ zd6?(INv)2RSF#Ggkj{2BTlwf>szDAAM(g9FH2Yxk;UF{9Tnf)9Ihj~Y#qdLE!*92%lUBwljAeO(QF{|L8b*-YK_};IMW%Rp!{_4B^y!!k zH0dC*i@BsiW)lLfF|HbX6yvg(wucKkyQW6-7Q!bHx5lmk@7dEi@Z+QO>=5q345$mi zFv@M!235AM1FyrWmI~32CW{f#`_Ccy6U;qUBc8Y%FFby{$rcM_z-=J&INgcZ_-OTb zw(hrg6Nqstq~!?EXtjAB$)LJy5AAPnH(RWNIb`5vmo#sB7URANBoZ($U)fS5J#{a1 z&6Gl?H16}BXeuaMl7pMw(XcFBV6=06R_rA_8u}Bh7G$Ftg9zKQJ+@^PVC3N3=lrxE z*6S-Vu)*J1|R_Mmi`td=)CMkYqvq4@?KZ!8a7z)uB;@ z;9=P7W{&M3lCh$)y1Jt2C9C&?RkX+f6KPS?z0nVM?= zq2mLfS*X;rchyFG-%3@{QCpl32C^}&D5L<^-`SFql4n=hRCZk(20IhdR1Lw?Me8z_ zOa-J`!9(@CEaSoc^Df$lPc*W<+vIU5Hn&(Iie;fF(^9VHqn(CP7#{A>o~e zlLZPXQx&!vv|WpdY}pn`|L|A7GvzJLeA8?=$@|sxn&`alHf8$S8I^*6`^SJ(yld!~ z%8uyk>l0S6$F}pE7Kvf^!_}Y1qEJTw^ zzE%F037D-&?l>v__gg1X6#wrV$p3ZU7J*U!`TGCallA|bPksJEQZ}$h&y}cbB z6`;Z)aH#9(Y({QuY$QOI|48N_7JrU{#fdKvD4cKr8;|nTORymay(H9$&k%`W25f10 zQW)fe{p;7?{?k_xZ5y(qBi?WTniPOzF!_`&Zteoxo-hyr9TvDu$k^x4jZh@FND*~) zcX2ELVn|Ez!m+pl3O9QoZKypD^;h3*ZEbz^>K8ypY)O(}BLttgM2M+4dz(jw^K3r8PzxF-kwW!z25XQ@T+bRKG;0Mkrk{8?mZaA@q?2y0c0OgEYmo3o%FAnYu`8JV$h+q?G}9v|Sjji?X+ zasOw1VBABza&XW<_rn>%gPz311%ripye41*;70G5oB>#Xq7HRA<`GpIPaZv5rU{~o z2PX<#^k0{7iolYA)h98{AinIhOmJaGU)2$G)901Wi6QrZ;%A%TQyp1#lCKZup^p$Y zvG`&bPWkWNNxuapU=BJ{aMDq-bpup~@xnI*I?=bFSN)4k8Vg$Q1@0_c_G@twDqL7e zr)^D;TuGsD*o%w7l+|tDK9La`rQ$!i`QL-7v07oLKP6|4Mw+IM&T|W$AhU5B{eL5X zm+X?#n!g|U|B)5*lm7PB|FD2RFNNITxM-zBe8)u|JP#Oe<7vu5>LjnSR~+1Q#B*U` z;h3Zu_douaIZ?n3;0?efYtiQwoXjt%<5XQL`HjyDA|47qT@{sny`xl&iY1uzBIB1bM2Q1p?0 z6>OF=XxU>&(B&<3vwYM5`mIekZ_M@YH)A`iZd__#bQHhxR-iD_rE{x<&{k#ZxzgG`Rj9S!O(wDhDMn(HrTRz8>cP+ z3W&mq<6*}n_-CSM)!fS}?~SE!Fcr4la{*Bw1t}yQf<1jehH>yxrBFb~022@j7)G~) zxpwf8BSOF9e+PfY+nX7hdOY_|%G%=9=B zA4Z<3XOU)RPk1AYq3|ObP{^5ajZs&p>W+N)P*$~chG~E5<;$0+El)wxeF-Ig66@y8 zcksKXhVcKq)~b)t@wLK4Pi$EN08WSr{1NWkn3cSvQMtn0CImJ&bG!C0mq5FV(wC5f zq&* z|H(Y^4-Q^};S-P}&CqEttF&9hs1UWA@}4Hi;`<RK3NaYL77&o2rBy4RvZ2;@v|f#PkhC$>t)x1b9Nl9LZ$5~euZ@1_f5k* zrZ0J-Kkq(&E+Vvif<{obLikC)^uEr|bsxH@?webG%B88}gZ3Daj$55-os`Ohcwu$< z_GkGmI1#WiW1?$x;Syh#6j*Gr4>xzw1Lj@0{l;miLG}_k6-RDD4d@<>D10PUQ<2;bgz}J zq~2dHDydfPVx~j4H~PdDpQD$fC?T{;)ZccS@XN%s_nE@`WNUv-eN6erDw_xTy5DE>VyB39#)d^TxcK2L5G4E%K?z0GQ?aUSzX~BrBEgK9esIi+|;B6`Rj)Gt&P6ZNT?W&-q5~ zx|)P$Rgjs4}*o2C&w1(j9!0e-Vn(TDe;lT|V+d6zD2G#c(m&(33dv{%3=Ag5j zQPX=Vwy%VUrH3!^{K~#~7)!-x@b)=J%#Vl|OF&+wpLoZYS2j=osSo@YpdbLqAGuKg z>`t=_Os`j$Qz4{y3MGvS*DP8W259-TBu(>VOWiie(`Su9WKJ{Gr3 zlt&9iJo=B$5Qnd}?nd667vNTTU1JG=-RM3;d434bzI67KFr2Vgjp*huX5s^#;|yKcm|Vlx7b(Zb>9|XV1_b$hr&tLET0xUlA&m#5yd=Bz=*^y(SoFu zHyfiYI*uK=N)pzI%h*DIoq2%ld<=%K$RPORrdF`h+J4%lE z7M&y?@r6y(EZZqKIv$&a|58|2^}*Nc1n1Db-fQkDKhn%$owgQrA`Ca*sTrlee)-b* zXpQ6YCC9ij9T80|*%Vb?9v%!|9Joy7CoP*b9b4k14eL5}9w;jK70N=(OCA)G)V+(E z&W&M^$tIlYHgsq$N@lulKvhdffi%IuWeoo~Xq?O$_~AkFA=ZLi)P@SG-M07ZQ~|6T z9-LaYi`!& zkQNxy&Mp&G)Avb7jX<~ecWSS;QsJ*yX?bb_l`*Aq;w@#@H6opST}=5VcS0mB`%~-K z78RDaUb=E?dP|x|SG=e{vgV0!1AP5~Z>le~PmJmrR180|JG=2%FgWsGk7Ud-f7I1u z{JtG|!Im7Z^X@0Z+a#D`-1Z-2I=JIX?zX1Q&>@tA5v3SOd0Zu+lZY z%45#&ZOeah%BjM#X|!E`J7X?ms7xj8MuMd2BJbjsas^OKDTpleWu}=c(o^`wU8vK= zt*Hz5_e3tnD*};8YLW^PDb@xH*{Kf3XZo%Ch$T9D1_@SAKx0UzAp$Ju~mwKqP#Yt?TOio6-QS=$jN*}`G{<6 z0h6kCT->c{_F8T0OS2hcRaf(4*w8ln{*v)6sez~c2d=PM2OV**{$aZh z7}k36;qqgiJnNdPmCOAw>>^+H6lFDSecb&)bbuMM8zXA`g^mHFywGBELM_skp=&)+~HGbvtSy6$Gw-K1~w z8XNcWOdIW-B4c&gsy~mCO*?92C%A?+HczvQC6Uub*(B%Iw;YvV^ABvy#64^LjA-HvCPD7l*k9ws7kzukl3M{6&Au*p%>6`+l3I7DX$nN>@urct=N&(Wz&5?;7~H8k2R~2Q69O=1+@k@n1SIxGoS& zc$&1ahe4Ug=zH|y!DLbQO>zX_kRN!X!%Xyc~sfyjPXqK zi5jc8_2w#H*Tx>wwe0%+BU>!rG9vQTok*#Ro)0pj=7G@alH}fHG4c{c)DG|~5bU3K zG6fZL-P-$5eC8a7wf%QY0>IJCsoW&yT;!eV#Px*H;j`BwT9u*bI=aLaGC|51MzaP|G>O}E%i|;ALi(s51-}F^_^a<5a zg4TCvFnBB%G+I`&DVa@q^=7IL?RW$>9iN$W>nJaw-P*HbnVnml2x>9SC(NZsS4oHQ zn-;&nbYuT$D2Bt&S2J9?&Eajk@6_3Zx^C(Ak5ACpvhd&IHq%mV8JTq@Zmmp=%DR5632DJ;Dma z=lU^KOG^UzlO~m+Js;Y2PJPL>G_n_YWyuFS5g!{N|rS9AA1 ziI}T?vzJCR4YC5jB^f`xC&C~Pfm395BH_cmqpLKQ7re;6jRJhdp6_#I=-1W5ID=GW zl8tukA5RD$xDWx70pc1q@|y4>v<;mswvcw-VR(4|>PuTg6c1@Xex=hDArqQUSk<*)sN?0tA4>8`>w5C(7^hcL)kU#Tpmo@mGS1#i@SR{E)}7c zIeD6|XdpI+J$FlAZ}+FzgKBl*LB_>S7lMu#+oVPW)<*Q0c~ff?zQj>AYRwNUi+y?7`Dbn#l!7h_#z{Qg??5hBV#`{# z`*yH0kd15aQzCAlBv!OETHqhq`g73UzUsx@_LTd~=dzvdrjJSJ?tSpPj#GU3<;Y)C z_;(v~F1|h!p+!@p8*quJqzweF;3Wx-^jznN?aoYn?9h_4aESk>t*dEVDRWl~DfQk^ z*7fRYeq+Jq0bjH1I3v^lj7_@1ENo~=-k$Lmyuqa)5_#yV;79RL#dC^iKhUBl9#VXe zarJg902HPyb{6u?t_Vm1< zuJZdh6&)@yWo@pDA;ptA7e-WHzX4G)xpt~D3ki;79Vi^`mqW2Lq>=@U$8Ft7)hfAyhpau3uw=CSrWVVz+y4Wj=&i<3t!q=E>om; zaku*=k@~y2gE%m>t7_rpcT1G+{*rQM>8lpU}B8zxCbNy<^BR^zTNAxFBS9T@79n-kR-u(!5??!Eb zIyR5xrDVusTif1WSeQ;9-E<%I;Dhngl*;gJ35r2Fw%kv6f2l@#>1!-f;U_$bLL1&y z>1A

$+m4Y57&I_T4q}VtZ%bO8cT)Kvy*P&erqvv9!lr@+r}}+`7Yslx;k5B6Jz>e?+s0G&BAPRUuO3Kh~0b-5NPSXw1r@`-9fi-;ZzagWItAHXotKaq;dm9C}W*AQqQ;M;GDq~$N zkjlrLsl(Z&+BHt0Uw`(97&K}Ii_&*;M)$ zra0ZCMA8g=I(KdfEh*rByR~1_@S7;aI`=MGce#`PAF6({g1H00|m$h|Kko0EkJH~LEd;MqB$^HAG%r!NSOE)x(Q@8l& z4IbvK%8u8h^4Tth&RpG2%ihA!tGA<__^qUuVAQ8R{(E{IsW;QqVHyWEqjm%e>~cL% z%@O&JHPKqU$(&&ayeV==Q+F(P6WO-3LDn^|nA@jE_sEH*P(kCSM@rQ2#n_1Da+bL)I$8Ug=?;T#EVF8jy_cFHG zMVP2?a!4z{T4Kfvvo;*k+&iaY%9-ZZoe&KF0gem9zF`ci_{6o$_p&(c6K;rCW7=bf zmcZ^yi$MOx2w<{@G2{{bjb<4nqON0u!?}vnI=lM1&TKlqPTLPf9A*5k?*e8Ocj4w; zb}ahLvjk5Q%E!q&zcW5>1iEYEKRwMqHL1BNhu!kJ>BR}?seE?B9*JynGjiW=jM)t+n z_QCLdb+6n{>SBrXA}5X0f(Pj7OL(?n9@8Y^9;6KdMi zb|<@e@fF>_hEa%aNY)8KP?X%+x5a{=HhBHi@x2K}Z>Io5SX33~UPU@`ohONvN~ox) zBvh&NyymNyNMd%LuhTD{|Gd4{!1fU!c{=-dvCZPS+uxNK3n!Fu9azG5TEx6<%C0kn zqTRg+1T{*&>vU2|%N_M}k}kDoYqy1A3FoPJ+*$fA&`N~YTc%U4$^L@H4Vd{B1o>M$t#>+vs#y0Y zUHT@bfO9*Vy&OvxjtM@Dc<|-Zr_{08P4>*{EHthhVFQLoA3A%lXJ<;w-&N#OOj`)B zPYMCL@#)JKm0LD1I2|`V;SFyr<{6(PS0*O7opECA9`N@CVtkm?`L3XRHg8R(Vs_aY zA03V7pnK)Ghwl_y=tFX+WE(u@9k4_IG94mTm{FTL-|TPPyq*g^t?P{gLJOANi?Nr8 zjmheZc(it(jINRwPNApB3?q$en~UYt*~%EKS$5os+9S3rCd>qywl1#5Ug~7W$8N$M z@L1o&9aX!NmqPmvchCJo846sac7=a}sqQ6xG=>IeckGC}w4<`#f6y?fq1e)jI=u|R zU^_`k?CEL;W4l3P2la?wAu}t*>X@0Y23J-%zVF*F`y&|4PvvziimBp6Q|^sU%zryurI zgGTZ7?5`uhYc#1Zj@v~3PR=k5RqX($$iI1X)73tDO|h@^2g6CZQ?b)sg}J%5nr3It zYVD7?RqbM$VLHngyHz;a5G0M7+iK+3wUnr_&B-1d`8*to)uz6zwfrIc7Z3%5{>USCOC)9xb8y{Fkuj8Sy1cm7w=;JtU zH_GUQ6~x_;W5;D-6<4HO%#uc4Ty5(NSmeo3(oC1L@`JF!wa5J0-lH z@thIefxvEqWV+)^ieHvCW!Dsg-SC4c^IN zW39OMVc4&serYjNwW34;EipF_mA)LFJfYBeIjZJB=>|sy!;|1S7jGCpN?JqTqXv)G zJ>7LlJcd8&N=-9(y_o~3cw5|y6`hM3Tn;_iOwx%1sQ$A{?2b3TYt91+8wdZZ0Wu|O z$y>ltQx{!ibf08Z41UFOE%r^^aXya6a#AZV_ki#-oRIWw_~EWVm0!7oqW24<)WjzJ zic23@eOggBN7zCeXU+{7zlu7H18V(3e3bx9=8DQ>aqCXpY;JDOd)@jDriTir>YeEv zGoC*e7O*7oFHhJ7AmH&*GpCw#wmOF<+VWjL#2U{drU-5|1U#LJHvlj*kpz^Yu0?X zw2Sdvkkh2tv{v@-et!#uDF=~_-1wUn?SYB3HSNUteD&v?xOGoXP?(O9v?Z3PKF6@tc zR%H`AGx4LU^Uj_HFZ!FSkSr5+u420;*V3OkmK~GadS9cp5MqG>vT^$E{qQeX-TB7~ zipH|#re9V723QzQSzM{C6!YUB`@8ooC#oY4y8t%8o*55en-M=&jh2D14mFbd{ti>g z?1*142}+g4S0ybBh3v>}?e_S{#Ft&n|1zs@kP`G~VPU~t15_?1HU>Lvaq-oECT)o3 z6)C~ZL<(H^ec;tUQ!sAAE=8%4-GIfLb7WT#J08dT#t0^I2AtI{A?o4V%SIc~;`l}Z z8~!^+rqui&#z&0IZ2kTH1knToBUzbGFKmp{o zFyKFh4Jtz?D{h_p`@tyDL?s0o&@I>l5w>C~PtwuHXd&{*<#OUl5`#-6nNChx!IK>M zJPm6qwH&ntSTo_fjEwTyx~DPA1wTsU^%Op^MG(32bIKQ+<`g_(%y|!Y0z$6B%*?I-GbVWi zA`G_390BGW7=vol75g)R1;XS49YiS1lj7q|;GT#{IY??6R$qrZ1WH#s#)Cfur9+wX zC0uI|16=C@1u!C_3V%`+NwQ4~SvcfUgptjR(alwAfL??VtUF<;KyUj;_s ztj7YFu%0FeLdK57>avDUqoYYverqAOS;9XAvIH!&2+XI>0kEagwtK#VtDtr6>Zcf- zs4Kwt%JDh)VAb;ghj!oe6(jS*Cn@I+IP8H{Fhq0v+#ftq52zL!3RVm)E-u1ZCtA$z z!(S^wv!$=IQ0D;k7#^c-k!>JsuP|{_i{g6^xSt>n1DwW4 z0uOl(48uylt2-+5lj4)!J&u0do*41-?X2{U3ZEAvXMGQzbp4k<(0WHVgkFvj6Ou52 zqz_`iAh(u&e&bIt4?tPIjx&iVPWh@gw~wmQvOvtclw1i7|X^QGt{)gtmnzat(&Rc(#C3ZRj^`D!GtkReEL1NAWtvhAvMo>jZMkF zC5be>zYHc<9NxqlFAeE+23oOoIX4J<#Q^40$*i)wnnhc52oSfU<^YdpDzQMNp9ZoZ z2i9-w9@fHpj)X<>spNZZsvS9AAW`FYZ%=UBPfTUBL_z-UA)JyGw|Rkg-2bxQbzYDx z=nJ4DNe%6(@*dew+01z>>Nta4;47(?W@T~orO5=#CJBM}H`i(muUT?u_{+#AW-6qY zYjjKTL}5a^NkfDDFtE0YBV6^6CC4Vwg~*%8!Pmt=psu?KMx&ow@t%xI!wVeTYDKQg%FMRpj6p1zT*_P= z+wg$Vd6mv}RLuPaxUyYOJJb;$VH45o^bVhlq%K_v#^&mjM0L>nba5e(p-JoBUBJd; z8vCz3hy*aKLXP9^!dO{3Sdhl=wXWZCdXu!T#FRRiTR{jkrDVqZX{6Qiq8Oz{#j~QJ^#VhTYxO;?& zn>Re~5CX3O6$c#{S|UB(Z3&pM66Tf=23PF)V^WPeSW0%;`MWikh{CK5=icKVkiHPiF3qcIm5yji3lg(E zCQAuv4Qjj-8Ea=LhhsV`O#bah<@!La{vKPN#k?)wMKWDVYH#VCM9_hf{H@p!&{ zfAWOtky{)0PE0?pe$@Zy!8+yteH^$SMVvQW3t|lyj$+RaFw<@Di^qLf;wWXHtMc=1 zfSVtxYHHTyeVCG&h{yB|;bM(Tshb>=P-GL1?~?s~&SO~Q|gY}wljU9gyJdN@31x$wFrGX_~gt+w31?#il z@tgsKY=6&3fkG96G;Mx~m|bm%&>Uq@XWe5#ebGLUU5q^nyFMwGN-}p8jn`~UbmN1zYz*-ZM+u{poKz> zA!}CK4af3f?rG&&EyHhGJM`27-WyNUASH5Ii^}{kMR+BV-8ajb-c19W86?wdQ!(!C z#BT8T?AuPEHYs5*F|Ylz86LG9S^7HVP<9eQQe|gnH{!cA2lLHoZU{HuBk+L|;0n4w z4%5>iuzk7{wqoD%Gea<)vJ6BIJjTimH)Xt*wg#s|tSl_Xrly@{5pectiu_&G{eicE0+vk+WdNQlI@Iv3%?n>+KzxLt(Xq~VsW zE9G7;6&@y5{Ye_3a>tjK@vC1cDJt_Xs}iU;E|C0S>PysJK;@oUz?XB|vPSOgt({sd zbqU3{wNbGiF_TSI@4J^dby7DsardZ3tzAO@{?Ux1!NI}`M$2eN!{lE6$Geqo+1X4| zMqZ6TZiH(i>IDVL3iv5m>*)Q>81SZg{|Ve&-Mh~J>PG2;0bez1{(dxLgkUQKqE=BTYa`VwF4Q$qxyU zX{w_xlIJu_WW{G zUta}zQJvpQZ9QVu#))=acT@wkxwfd-q|tpl36aa}_~LYzDy;DHpv25SXOZs@FV5lR ztXzWBzVaR@In+UGCye<}AKULW`+XRbQOG8ezW+iV%(d~=I!?-muXhEiCj8hg-U8+R9q9Pf-mhn5#qVF- z0R0zuSKbY8m>GUb`Lr*!7t;jqcQ?V`@9_^L3`Gp=HYw==jLe<0$KNlC1dKu$!`Es$b@rm%xSQMX2caD78fkcQhA(PD! z(XU5364Mj3irAQeVSeR z^EH(dKAV~F1J%As5L(~uU!3bsSKEPAV_@0e*2cD<^j&S>DK>t=&%z%*mDRFxmf)}B zWPXMfKm!EGrJM6ywflI}&0@uT98Se1ajA}YGnsxDeUgrx=UMn0GBTWeLY?~NbJ({J zytEXs*oN%E|Cm8t;BD+N%Fw*jULU7Wb59@WW7>qX@k%6kSa8a5DPEm*L}tU}Ci|kB zt1n^xR(<527Y7I7IV#BDqpqoWUuLBztI{w^77l8bApQP>?v$^jcYKV8-S-f!K4KpI zVBDhsd7fYM<=iJB#jRU|N;8HLc~ma~jR;6^E$3V6AzPdO{8C5njcxYV%}Zs%N{&&I zT%0}Vxxc<}zv{st){fLXwTf^vpr|;eQ16}As^_=+-TY&tD~&B-HEDd~+y~Rh)UmEH z5D>?`uH7U>+8#4X+=9}}M6wPg(t(uG8i&lZOh1E@46~20Ks)K51lLW1|3v;?3Wzwf zj?}876@+5%98@vrMBd9k+JHW|K*O6W!FfNL1E~%sapLg*oSTw!x@g!Now-*g-)lTv zxUrMK(Nje}`!!(ebh+<4nQG|0egnqzx4B=pT-i~pp8yvQFM<4z#TC$UmZ^}pMWM4U zazHFL8`_i65{P0xX)P@T0hmy;My_ouai5%+NYgx z)hfSK+uhPBmn2QMh->>Moe$TtCjC>Co+3||m&@yi&krg(SC5iv=k7~8#V_>4Yga32 zLJCxtTj>!rFf^Pt83X#Nc)rL5lLv8*?1LPSYSH<&SE*^d;gCDV)4>$1dV)2r9sS#= z3)8k-Fzin$+M7~USnt(Di%p#oU&mlUC3Xq@l#)ojl{GE;;uf`hXuaLRq>C3nVwigh z)4s>%R9W&BDn59*HirORdvgrud}aFbjA7RF$WlJT!>wFzP9zp)3(2f794!*$W9Qto zzIgH2<>Ac)+f=09Hu@ype$ey zx)ixf2LX>u+--uc9a|#)tP%QOnsjcOi(E+}A^CXeTV{r+r~8qsVxy$n+ce zY*c|smEh-%##Q5~A~S|^{F=1nq-It>H?7HRRg_|&4X~%Xmi7l8MjNQ${4OeCO;e@E zH&M$vN6upmQjEe${EX?LR|G4fvqNjr=YqP`PVJP!290eB)(LGA?p~Sh8%}Vq6dc{( zytBIaf%sUI6$-7xciEM%+N%XJP}Q3b*{vM8-gaV2xQ(teeKhPpEWlfKce4RO{B{>t z64+vaurgxlwGMJ@hjo0m4wC(LRTMx79J<)He)jg|XwINWJvzN`YYzWDI-_wk=HJbK@A)XJ2Xv+2O@g20?M`~}r9vBd>aR}OJVEnrn}Eft=)eAu&) zE7IMucRK=MtwLL&rVR%antEX~RIqls8BFahe!NIQ8De(w3Q)T7?CAP!5UxUzo1 zV9(8Vu?QqJMzilY^~$Vka$RN;iV7v2;Xzyp<45d~IK153 zsFyU)9h~ax;(556`Raq1rXK*X?u1OykRD}C{VzG3_6Nh9o?QI~Ox_~3`pji^Mtr{! zwLUy9yaQ4=xnQoAH`ul%b&L&fI5B~QP! zogDOQFc%i@44GX$Hv$wxFwtX$Kdw33_RkRStXUpAYV6b$uGdz=mDE&37^3d+z#w^) z$9QvY!CveLEcc`Dsr(6pu><3ys)q3&0Bz=;zQ<*K!xM0Ad48$QIq}7n<&7OzBl{{( zgKtV@IP%Zih@X{!H${^zRw)=&inxRV(lvPMg?&(?gT~fOYo0o@w|e2df18>z*mwv4 z+qA~eO>y+n?O{FNl0DWuZGwXd7Lzib+dDe3tv<6>bU^s^k>ciSK7uDQ}GkE70BD9*Bh&|+MNPXjEH3|H5x@3Fo zCBjqRRxR{rjS|m}MkuF!70b+ax}tDKaolYK&K}m6JvFi)M2%u@HGJX2Xu0uK#YD4Cf#=?xyeD zsr)3%aki(aQi+f@kc zZ>ynXBVQVD*q=!1iZ!iGF6}1CA-MOVu?cT9pm&j{Bmmy zs}c`^$)12(jRK+8w2WMR;pwT(g`!C#Hw7>p!Nv|F)1J?oD1><^nK`l0x)f{(C3|)o z#XHG`o$S^&J?UBzC?luOQ|zE%TLaJa&+}L$u>@&rIkei3d12-Vapv9JX0e(z}{(JITXuUv+g3G!FVQ zShFoNa+SHrH;I`*ho|B9EcsM!zBi020SkIjZ_}L;ms-vFXTI<^zN8&>nbzA^-dNlj zU&Kga?o6v?8i5vM)%Yh+jZStM52C|L&PMjf&Q$XF)$z5o#^_gs#JyZnZmR)T?5xM& z-0m!E!ltQ93H!b;^}xz3P}u4un$o(O=~d+JHL2Rndkx!hN?KOEH~A302f4aiTmR23kLBHOcf)* zVi40ZtBsD@>7Mhjb4)7Gfvp5W;EB)9N-V{zAAQsn$^rE}8b)41{@SKp)^#roPET8| zF%?vHa&U2L(Mt0D8ku8x86&5LQwDFUqy9JI{yUuOz7HSAsnnH1iCihP$OxGkp(Uea z?-jB)k;q6zl2O@2R`y;YR8|q$vQmVsBzu3)SJ&@8j^7`j@4w$q$8p_9*L8R3{eHck z&&N2=^Km{%)W5pF?3ebQi(OSeV`ow=qog;H;Nx;}qkv9mgucqo&2J#5W2JUSqc6l8}WL9YyvhBnn#p7$N2F?#eH7a>` z##8eynPvUs_V1wk@*BdU$J~4ccK`8Z-j{^4pKPt9e$PES@+I(p$IjqwybjkI%$9_` zT&a88K=q`7*kZ4FbWDNmvKY0PZYtkLQC`CC%%?(0;>rN!^lwNo*HI3mV-33v(ezOw9m%|L9AEfT`D?F8)IL72*g8dj#*-EiEZiJh^z?lxtmQieX<1r)~Dc!Ij z#PEB9Ps8{hYl?d38t(VBFv3pb&(WZLQTujnC93>nuW^nSf823N{Mfbduhy;QTvp=g z7hLwZ?c8uk9cbW9%-J1%#<1p}DGu=C!NWI*Ac-a~Yd!TIeJ|$+DFt~+?jvC>zAX{P**auSY+v% zKH9PI;A!|}8aFh))hiU%Mv;m`CxtN`iFS8wWn}=;5(rZhi&T?&N32g`j6>7JL>*fsM{UcbNGpy07u2qQEoxFo0ib4cPpirPJ{?%A!( zezg+7KXe(h#t+!+8zjGFINkPXIVVPX>Qao>Q_UOt21Bg2)bF|}nuGr-&wD=WBnU$v zR?mYsp*urMT6g=niLm|9gD24ePwKZmoK}e43aZ#52}*G7-+AKlfVPWV{}PJ@`>thY_ZZVJ0& zeYTU3Jo~xHt=QU}?fj%8W9wJ>%&l{>yB?nIvrQ7-F&?MPI+F^icQ%qch{&GkwM zmUx#Ov1w=St?lseS)?y&PZLvL6EAG|NfJnDnwFD&pHsx<4zPsjPv&D^E8CT^Y1c9M zGPikmQ)Ra?(~R_;dz8Db>Kw8G-R$hT-TG>TCmc zbl2AAPZi#u)EMg(G!cTa=3-y^nxuM#|P# z5G`e0*U3=S+4lSzjR3ozocAi1*LZ|7J$9pVr>hK`mq~`l>&@F~ekyUxvgle@cQ2V+-1=Ww$*PRCa&f!DHOE+!R{HSE(We$Jqh0cM`P zr!W#r2E9y(1zVpsKx@7vFwf|Rlmz*+6BC#RR@ zX9fp#_|^fw_08?!Dc{z6NQp_ioO0rmWlrs8`mp)O(XswpEhp;g#J~2xyjrmYe9=Px z7!XX6`6RI!=&5=d&BANB^Do_XzBnf#N!qUOuYrGXw4SNrHWTXV7q1pFqCOYe z+f&BcWnX-{Ub03%`}^zm87osQxAm?qt}ki@LSLsl`>n4xs&Y$Gq~6a6WP4&)3AW>jViQ!W&*BP=ps?P)U*76aij2_-i5HQa`*-0-D2-^KqG_l7 zHKxN1dR9Q$Z7#kV z6u+4?e3kplmpH*fV&HspIwIEDyW?Z`7FT`F_If+bE$ZP@YysBTqM7OWzIij}aoNj> zi`ZfyGiVsNcG?O?&l;hZ_*``EJ!+Jyi zalvfZw7(KtvFpO94O<|sU6?9tMof zGMw|qw~=^V9vEY0AAPcY+SIZ{bzm7fhlpzNUj0l<5MD3vPh`ber+BB!7k$O&i>xJH ze90d;@>To|mJ?2sn+;~5Ug!-foVklmyFGu}0;{G~$|(ul0|XZ@WxH_DrFOkHF0CFW zQmJw=ynv0};hS)4`MR$?rnpas7oJUgP}}h?Pkfg7HJ6NL*y3D=&?28GKhv}ii_4Yl zJ-vMG)J4jAOP*+EjINiT>Hdsp6ExbdUZ3`LbB z2#NkJ^GfMN#r8f|m$BBko%0>re&;CIHfS!LR-ACEAMgLl^pKKko4?RJ6L0JLi8PV5 z3lwzoac5e&5-OuR?l^y&cE3uoVj*eZ1t}`*ohwVqF zrcAPB21%Z^75j8GKiJdd&Qs;_>|3Oij7~76Z|c(nndjH1+1Z%ll5G2^@_!{ACLuZZ za;<+Q*Alb87bzI3TRnmT$;Q7x!Qpo6CHB>`k)OC$rQ74%@H5SOcYV%X<`WVd^Uo=7 z0-lzgmBNGpf4(_X@$@CBRLD!y4Mkqw0tU+v*I}Q6rK?FZ(mibEgy1nOd$INVON50;w@0b(I;Sk| z8XvT87UMGH13XDcN-tktM}y}&17*8q&-J~n4=n5)2V|*lcknL%m~*@35Lk9>wVgyF zej5pXEqC|h3@&o8-0~W!rjnTIEt*V;^GGKh*}r|~-droGV?Y_rJ^Y*Vby;~pstTFz z`#BDkMpMxJb90~gaw-<1c7jGbd-Fpuo>8P*BgRZyKjlJ*2}t^^F(lgYH8mX<+-=>A zZ_!Npb5|;a{O;1W)huqmZ97m#o8p)q9>RiA*Z%ws{!G`+S@njeVT5xZI5(I`@Sr*V zjD4k;{~4ycYNs2+nE`Q113e&sOsTAKEGMV!0U{;IP0OnA_VO`%_5%`zXUL{**Sjoq zs)r_h$?-PFm{MtBUx(B?-{BXRr{)7E#rW=|cT*6vmUF8!3 zzL({xDXFNI78acB)5kFW))6PaO4X4O3r@n(oj$j~32}LDyTf9;VW(MC_4dsqoom;w z!9-^wGE@3upV!x-julI16bsNo93(yk30LynxBKgn2X774_~8cvKQ98SdNBCNjw8hX z@0Ij=E6z_Y0f2xGrmmpQCC)m2ePj9)6!(tw+&|6V{{H((va>-u{{GG;$P0xKe!Ujk zM)~(Q-xmK7`uiKNz7ya6{)XiL^oPzpSNe&02EsEe&o3aL$ZKun`}d~+eu+sGH@C^w zzlZ54^GQZK;C@o$K4eKd$ZjrKK_~}W^{%@+=ii^r7?I(1f`w%iM6_$6m#3F^L24>1 ztPb`bdaXiE{E6S^b(~H+J$Z3!`xdM9jowelsQAVBq#ZBlcJ;PRgV9B<|DF!jTl2T? z?48yvAGQ7cGgKeO#e^VkFeTk07ZfD^)7$M1^mcZgB%1Z%1?fSw0?GZk_Qb1~I zD()1Zo-!_H^bsf!FzU{Yl-oS&h?fene$TGcN!!vajJEe*y?OJ;z!qRt%CSqNB*BX} zKSi{5cX!uc*$&U8gI*6@SPI^N=`O|Np*k#>iSyW1#VjPWjN3#wSb(;S2}RXi18Jk7 zp&^oXcd4Uk_Z)=crvH$nX=0NeM9@Ba58bs!ue*@SaC8p|NfM`smwi3U@#6$XEg}+u z!6?eEZL`eqoGJ3%1)Is2Vs6F_}^GmzThuokTx|88gLF6QE{93&_*_{$WG} zXwA`eV1)$Pt6MgY?7aTFnks`b$^hO)syFaI2#ySZk0`??#!=?yoFtZU2J*EQLgavP ze0{70FmB}i>M~5x2~mNA)(9Go^h=luKggVkYR`4LsGIlZha1Vlc~9w#k>et+(fVL#u>57H4k+<&%({Uo~;w4JtZmV7pt;Zs{?l%;>CtZs707U+KO! zU4k*a^pvoyJ|>v^a~u7lO>eGxzlVZ#4MNjwZ!d6Hf&cQn4{3$TuDT!)V*vT+IbrFtx9oo$g41clvw%k93?wZ-$RhHF2d@rfn|X1 zesI@t!4rlbaOTU)@}TlGK;MIIgYi1VnsT&XusNuX$W*eFa+?V3(HWyi0z9x_Xp$8u zYzzC6J2-r9#QVt6WLA$RC^*0=6Y*=;g#J&VjIxV58QYRR9l~-IM%y>DKH};?r|I!( zM1J$|@c3;mnxb&{bRHGtLh4&Wc1o{s(x7hgMEXmtx8NO3Q+gsa@}dbQ)604FjLK!- zU%v!KU(0RYc3>?gGy?4U2;PVqHyqdDz54<*DI5;8kVF7z<$N>2Z@`?Zo;3nUF^Ho^ z+n5a1=9ih>^EC(LBj~kAg84_ovxILW%%7AN-91qt6nmXANuJHwuK@}nsKu_5`Qjp; zabLcC$8~e-GgICm!wC_QUi-TVBQN~&@+1VtWKaJ4D1uo;X&b0dISNAZM_LbElE4+q zA0s2lDX0QkT^gOUmj|~TvHQA_8E1aY4#MR5fA{YVsAElJ0<8*~y9F8L#1Od@qdi89~OAKjj>8x=2=?AP!Qe=Z!(y63P&{DE=#nIz0} zm=rVJ{e92Gl35w@FU)=BzyPVS{d5Uzy=VC-L;1 zP%EZm%l7GW=lXSg+KVjJ>sLS+X%*|AJtJR49+>m1ujI41l^(CZwB_SBOP<;tTQAVLGbvY*aCz9-EpVYn zWe-ex-m3)xiZ_LA4rPGK%3`fykcUrGwYfS8hb&@{IU}bM8$qwZz#;Rd>*{z4x6bRA zD`pO=GYC|tu|j_INYzcKWM#un3wx})s1m|fXsKFH;*xY+MJma4rNMFF>+vY4j*hPhKa@VTT2)1@ z|K|Yv`Nu61`?%6@as8AE;|F%`k*@zWw>J=~J5h0WfGhfUMrg?nfs#^YRX_}YazeY< z@)EwoJj{Iv@&Jhs;uDQhhh*OX<8pzt$o|=9&vA{}7zob%;(;a$@Fe(g5^jr`1%Cpk zhEbagKt%wc8`Q-Gd1x%)9WL)i+Ekyn4b5~m^*+vy(~8UjrIGTWn-J>OKb#2C*ecI6 z!<#&Ps;~w+ZyZ7OYLsupg!x9v4S{OZJ($MPt_Bf1)14DXMk4dFLt`ta?FZG>?Id0y z$qYNE1o>WEQ|n0P>{eXKclKG7pxPDXvj6t>9$o@*BLzGm>%vXed{p1##z0L?O+#~&bUbv^ z7UZ4Xc2rft#EWW#y;1L4>6N2?N~4TNeE#@*d3h}lhn`?rTDKr0W&30KNM_3la`xGG z?G%l7q{K8sNlAuLzVy2jH}|RY;ZIGZ_vSyEzl~Qp-a2?kQVI7^>|OsZXTQzUl)*M^ z-@ffc5qQ*(#?J0AWs>Rj?SZJo>b7>P_WPo^(zcU198GrgSj;;Vw9lHmyVXUh4hHK9 zSFr7LzrJqyW)^|SNtj>Px-m-HPN}2!a<{Q)>xiRwFFtUBw*Q_1T$lw3W zc6`>Y8%j#oJ9n_7icrb3u=orH*4{@6_Tfh2t^02Nf2&6&*=IJ*Ie}(SRQy-=d8znm z|E=6eNJ^yM{{2}b{fwl$hz~(x=O$COYZuAe0m=R%N}c7cSXYx=b~@R%2Pji|3eA;K zQ8i$Q7ML7|Ko7Pg6L%||%N?%VkB6jW7tLhiDlDgdDvkXcpaj%~j`AN@w+b?duY$U?7Gh2``b&N<7sGz$xCI+jv_&%ST!>#r8@c|vEDjL4TV0Yx4 ziyg4g&*E#R@gvI~rPGD%$ZC4qNpevdJ7Rx2A`{HF=H})K zNRp1Aq?e}qb2E>nB=1UA@x|=*t@_Jf9aZ&qMTt01rP^!}^$fHW3dH($fM`wd8$>H) zo%{eGB&_DAE^MPL2kH?VybmFL(u1wnqQ*ZzFB6|v7A*p_YO z3JdA3;QZHk3rY6+*#*5#kKJdZqvNena*r+;ifzf@w74063y)rRSDtn0^dI2%00d|vWz+=YC=7J&b zms|taUKFgTRdEZcYGyf8D zfP<SXYyRn z8|Az8Q(?L^odI`_+O(DWz=6b+S8oagNlB6nm^_xhqvwfp`&Ei_&bHaL6u6O$rq7*? zu;BDN72Bfh&cya77sr=Nk<_bjeCrpxtGJq&vwqM|1E-m3AzHTywPFb>t;)z54~;?k z{But~E=~0${(kRtXgZQj>P$8I3G75bicQBx4rr8%B+f!F%n;oWD^_m!5aN}QPm#*C zC_h1;dTJIIFoqmul~wpWm_IOcX#@${QZ6Iq@i_<&ijcfbWAD_JaT6&to{ulH@Z$77 zME4%=CwM;40>k#9wxrk3TUP4e%(4>fv z<$*mU-!`#E&R{FyDYT5mX01b*@PQ2R7pzk+ItO%wOG5iSbWH<>Z*mywsY4@z2i~|X z*a2PnQR^~V^9sT46Cw>|cZRz#m=^v0tgC>hkYllxxJOAWw`J#^d>wsGY;5?2JKOC~ z2-DqNP+K>ULBMz;7Wy}ZAY?bV1fpitMGXuS2V!-`MyW58htOswF$g0@tfxU2RTOls za2pp$(FSoH=*EHI5TyWk)w8n=5MAl+I09`N4%IDG;i0l-OogDzP3}U830q@rz?IlN z@v|kStI^@3WHkE5vty_gYx*|}(Mh?UyStpr79{MLg8o#dep zI*IWbHRq;V6Mc=#^@fSjuN_EKwB#7j`!F~-=y7$A)M(w2QtK&4yS;3CAJRacH-jPF z(0|=1RDJ(*$DVsgr$_jyUyS6gTzW z?@*OnPp^lFOncOt;avhpa-V;CDDed(KC3Is%dBjV^ed54T#ukNl{pw<31@~oZf;w+ zsi;c&(WnXULDHz$&6SPw7B-!74ROx4$7T-9Q#^`{IyQ_+wsI`~K z);)`3u?VKb+mQ*0hBSK&$5`Pr^yi!U?hC4@*HtvQu>lBJKl}BvW5ia3se;cTEUW`9 z8RViV|KnduPJRCI@0L^T+mtd8x#p^OonNKFe!wl>fHg$kNcP63%PVb;8LYaYpuzb{GuSb`+BKzH+;=Rp~mKn~HWSo5;b5{G@rjc8Oj zxv1E_e9`FES6yvr?|xn|6S(HQ{M%qL?x~IaP9*I;9#nQ?yXYi@sN+_IzXU1jpDTm=A|PyO#NGU%68P3f4L-=OH>LP7#=vlIc#i1DlJTqgT$}1 z|A$KUKRlP@?eu=T|NhYbsoed)`G+={h)x!&@60u7?1Y1ugPPg_?bMzyobhbjA8mZ@ z<*_?jI0&XFu^ZUFx-aQ+tN=I}9v|1l)WA(SCn#Ugw_-nDZzBsYFE0zrD`2HKpG{$$ z(V=<_m^=d>iE9t|jN~^J&}gqh6XbK$JMC|=cLw#8B2pNjEJ$hKx2tx7LoE|PRy&lJ z=zU%R*1G}%}~u472V@xH#iu$_u3NGR*+jYu>krcF_*bBd%zo$#FnI-Q}#tZ}L6Erc}!E5Py!y^)T$ zh=%`#sOe}hCV!RtkOwRriZpKAxB)B*6licr6ml?$^f8@;Z6xM$n7xpj(bAnosZw88 z=K=f?u#ziENaCa8x#2>=nn-uUk?erUGu-a9wJff(;k!12m13~q#0Mm%RUUdmw*lx? zyO{q6(PEa^boOJjqeahgk`b1Pbq?*7w^znL66Ddf%aISSq<_M(Krc2vIhpZ^nH9nj zKZhNS&J*?E2MC*nFSYgcrid{pfZAL*FCI`!SCNrab8BFenm}wL{UJ1!%6>Z7Q-zk@RFE=+A5&^6?Dn-(9P1m@I-XPs)m|ciN z8JkBtQKT}H3Iepbt$3*-=?64Ug7gag1&H3Lfzyh$ECn99Yg$y`9O?#W7F%gP6iqLn z7jFIk9T-HJ;6<#*!vXEq*_rUI`XmDk29RAtT?a4#FAAKr;IsH)({u=YSl{OkUP#2v z8r9ibopc!bURtqHWDf9mxT1Ied_1*40AjeNxmM=>)T9)kPV(?zqN)!aZge(zp!s;z zimU7Q;-cC?BmD=ZtCv)E9pHb&ZX4zT?7z`jEHEu}=--C|_G<4WBXQz_=mm&zAtL8o zy{&esK!NY2#Z453A>Hg)8`u|~+;Vx`$M~uU{9Mx{MRy*NNh3g8#vOm#E+EKjL;l>D zcf*-YKV7XuV%W3#ot%vrcG)&z6}@IDq_p(4v9WPeWxN{V*x}C-01w}!=f3rze56FO z)+Tqv4v;Hi#vNDJbV`)Rx)rWPY=oc1@URhcoD37c=UgGsTP+1EtIXj5PMwg}ME8nM zUIp~BN;YBNzo?B0W_-;0|NBI!qHuP6HijNy%6jc8{8}~flvlq@wDq0XT@C_%sP6Cu&6NLP0Wc9btzY>Dg$6+pTnqrah?Rf#@B{%Wq&%TmU?NA0 z2$JcrLsh1lsCoA`-34ZS3s=baczWy=kUljYv5(Sx_HW(XRnd!P6OvY9FI>K^eLGR1 zvFZpRKt>9_<88PVav{|atTDZ2;uQ+j%1k+LfhScu9LG?b>fns3)%5k1|5aXNDca8^#qPkar~O#>Z`8jXIf3ow>Ym!Vv*CKKA8YSo z2|~fmk3&PQkCA`@j&Sgrp&VZ!r8%)F#-g%|Y+saijBx4?#C%wUSaA8ugke4ySl?&+ zQmqHR0sg$rLK*RvL=T7tcd|1hr6_lhO2Ds(jN~X8gZSNu4bvp;zkxYyV=>a?%WRtQ zRe896cwnfro{38)xb#EqL-4hWKU;|)i=zD#f-7vCOzOOS zxV*#~;Q36lZN_NzXzL}VuA$9esUVoWE~COaFXDto2ox~lVI&+Mjy5IXqoP4nH*`P| z$<3W}D%K^ztTjPxRRLHev{%30TzpH80s@LLIPmG`r;c;G-gYCRMOY4NAe+5=!DAoddQ63d8;3xh(Jd~P10 z(}c@DIy-jtY^&r#)Y**irF<&IDD%4$Z{|8|4N3yse_(ze?w3e^woH(_6Alv-js|-8 zDYk%Cr*en|m-tvX5`6O2)zw%sau$6FNXG?4lc)yly6K5QHROcki`r0|)=3BjDjt&jcTpWX!d@y=Z%zPJ+gzWM=gV|9>nqMu)2~Ln z+#FAd({mkXet4pJ^bO7&;*2Il8v0}Aq$F(t2y;=FnlPYJQkDr4vky4|H1`HT87366 zIH+L!fcz19#Nk$}VGt8299w7CF-HMdumWJ5$Rh&P#s_Er7J;k`^P8raHArf|T^hK! za16x+&Axpt=!hVlVb)-7`VPXWBYqRW1;cZ7-*b2aqs$Cv^g-qXUN&C`%;5xGY@0R; zaYRJGcNZ2w$)Cjrlv}U$+QrwV3S2E%I^H=;aze>VnEs<68jj0*_U)oC#opOR8y0aeK2Nx`SR#OU+ArxNVQ#sPBrBK zPba3*?q~f5I_<7b!Frshw&R3q&L5=FiE55fh1=?6I!D&Guwh6&ORKZY$ufE8#Lr&Q z0Fi`j_B8)KTr7rTX9untb3}bc!3l^c$s)sdt5aRy>1WG@tLhS(AH5q`eH3oQ$9m#0 zb=FP~l$U6ZT&7ERI-3LL?JUsw#rLoLGmc2TxWiD^ZSNsx*^_P1+NN5KuS`IT=>7R0 z3Y5YCixEL4!=?7L?sQs%M)84N9rP2@mH|)!5j|l64J~+Rp9Io}7i2G8dGhc6s;rn$ zMQs2bS8Yc)a^B>Fm;feIrtxAeF|0eWcwgf|s&> zCLt(OnYdg4O2~}?p6~sO#jG9DV~3@!T?iRf(nTU0jjJO%b?z>)GBr&t(a*mrgDG$) z%1|0Kv0A!v_3x21P`9g>C|6U7%?H2VQ?K5caT+wRFr{rz*(@~-TJ?wm zIPztu76+(bavo|GXPD!qTh?XNqc#~X8T9x|WOlo_T~4?^=PKiVec^j&a<_q}*g&qq z{ez0YEwIelQc`^R+xF1ALw=`dWLWDJyG2?bLUgS+f*JaSXGY&KQMVVn2PX9ZC>L0u z7E?9dL|fvD0)nn~S5(&yF(e4Zx>l@;7YG@BHGi^sK&C?+eJ)>9>h;&u!Dyu;o~r@T zN*1cif6+}W&*V6UmPZ&GAY#4K8T}3IfG3Y0y~a$tSSYJ?;yo0ulX>Xh!m=bXf4&3etaHWw$sH%u zaOrP`L|ZiPV{;Va!8hcF!g;KV97bfB1s0vVa?SI0-ON77 z69vNy`69R~TenfP?o4cmxO#nkeVxXtXGY!tVDq>pn!lwf80452Z|;6{ z$+ihe+1uN@@N$zg3S8HTsovCO6{U~eI1oj5`lO-`FR-0)u&)=d=r%Dr14C#FQWCGN zZA7EAxJRNKYd`Q9pF=s)#<=3h>*|Yn*fX~fFbFwT0M=3eSsL^trbBUZEN;L*IMA`( z0e%v+`}Vyo?aa|1oV`Y|M&#<1H{T<&R-iosz-nQTW}cxWJkCyQKS&9FpO@=> zY{bxh^ktTo?Fg7P8~q*vA-^w9HMMN%}&l zS{6>py^X*B#qX>4g8xJZ}w6;B>h9wHTq+n-oyXDON2J76c6;c~(^}DF*c!j5-Q-!NQIvj((4^R9>Anz^>waA=sjj`B3Rg|mQ8qRmN2`|Dal(T>^s-iAvG#~7szX7e zjt`4oiHN;Gkp!y4rqd5q$j!<-%q}bt;y9@%|HhX^$_G$0QxMy`ko#HowML7BWK1@) zS35vLvOf0uBP)(64)|Btz9Gw^fOiKCf&)^@700P9xIoo8(ysUmAK;XR2_%lVsgx8H zsD zdD&I<>IyVN)VePqYh-nC(7j@vtZ6P#)L=1z$>_*-5o( zr){<7f@B|}t+?M1Jzv@~8XrDyBCPk=P#q*q^0Co;`eAe!?d_;NG2^CpwbkqEI~2N5 zOB@aTz84hGePFZkjFn}9VbdlQqv5g?j*{nNGR`%Gah5|pxp0oNkAX{tWz+a*6rmf$ zy|M23b#nzpVNGOEng3&z%H<({BA;jLXzFTqzN=vd@OH~N`ihf4s6HVW+M_Dap(;4M z3%L#DpkwL1KaWr&^yW0%>6op%3R-&J4~zHmZrMp5}>>98ng)0fV7{}i?g$e1rc$_iNevI-ok5 z!%Z*5`8%PMH|zOzWA(>#`AwX_$5t5Rd;0BSXm|z6=*1LrH5F208IZa~K`M3M$Hr1- z$#v#mv2H5(7}~HN{`cS1tby4M#(Ii0utK92ClcZ7*{g*f*~EkO6fjwG*&~-?gbo{! z>)j&e;%cjVW)?})?zu7$+VfyNvR%7G^#+1WMw#`F4cQP;x^O~7cbmj zDQ(#Sv2M4H*Nq;VEkI%v49T|#M%phrSxMk4%-WvW4-8b8^_iXfV8C*r*+N+-os*8c z`$&&%`8UIO(3&de_nG=lFlMl@Gnu|2w+wBnr3>6czGsgz?~qk3I+i47L7vMA90}LG7;3@R{5{p_)m)T|20YT|JvuvR)U2g zcCuA8q1%GU91OrW*Jmhc;vfw`PwvO(0R|a02Lvila&l}@zrZV+xZQMorJyc=)nz8} z@Npw$0Px7XnXi5tZFrZ&>C#DKj9L`|pTp*dDd3+4j9vwy#4dC~qzh-m7$N(MGuPoP z`z!Go_?pY2R8tZs28R9yg};K$VITnDTye7ocY(IWM11#iLKcs}A0V*_b!?QXi;D{w zTL>RlS}suy)L%PNfp7qX=Lw%9#|q=k-XF3JuFM2AoBjjzN9L|!D`UL=>@xH7tyh3- zpe&j;WC`S?g7R*W$hc7gppc;VG2u-3}nV2^gH+)B2u88 zN6K!GfW`&BhQgbBVGjnEMq3|(?0~ausvV*VCP^B>0}z@UcxT*!5~+!rq3Ay`2dbdf z2Sn&Sfd{ovci7g9+NnyQ^w6RG`{P~H?; zt*e`8MG2Iz%WojD|Ge0D*28nRK!^e>N>$D10?s(-Hd6tlrYLi0vxPQ` zf}C6n9>eHaUu3;FH~@Dj&O(F_kR%$Qfk5JYa>)98 zIFG0fvhXhP;~tyxfd=)3n&!m0#Vedw*!nh2(REdyB7XPEo~-x*y2V(?nyLiZd` z=Q46B|3@GnQ$l*AzG_`b$F$r>G!c+9^{XlyI2!D`{@{|E?=BZ22{svTsaPF*_wL<9 zNydGwV6*QYQ60qu;70($&%A*Zp%)|C)ZJl!buH*`Ht|N;_wkJV^Tm|cx|bgaA^?E2 zX!q~$$?E&$p(y+gpg0qG8{cy31e)&-#A2LFY(;j(#l%6CKq1xkfKU*_pN8x!5En2g zx2C?dYBsqc@}s_U8W(^VM44GY&2XqgnMV$JKGcTQLh%Hy4l-{f}y%PYDz&9&0-Oo}vVDmBDaRV#V(t`?Am7gT2 z6Q`h;eU?Yv@YI+89tqJ9XcGDo_vQOk;#hf+IQfUrBaiQeyi!l>Ci97AS@GGL0~6Cr zI6HVX1SO28T2TepU*Uxe0rXE~WTY@Y_WP<&I5fLBe>A@^=jzEH%l9qn-n0bWyiO>RMEy`<`B_%tt4`$q_E_#n%OlVMn-m5JB ztUKvp_Bvh9<;Bf+hV07HE$^x&FN^&w#pIq;k7x2_!CiGBFd{~}QB_S9^cW)gQ3gV{ z$)5p|0L2en)<8of2vZ!RtS{IOth~=&XmfyR3cHieVe$eI(+Z~@Bs4J;7+V)9)0T5T zH@q0P5wHw?&E_AKg(R$y6wQHDdd9xj>Xrj>S4ss1aQIOKkPg1n}pA^8=8$X3hPq(mQ)>u2qT&yo(t?Qk(&S z11!>x911Vr;yC8uy+DRvE5GPddr-U8k(a*xYyh!-;44NQWd@AAT;k0moLI?vrzrPp-S@#x> zLrTe^ng0Xm6u&C^-^`N=qN(pOjuc=K4WPVpJ>Hkmfx+(NYkbc{TKK8{Ml{JZBZLLb zy>}rG2cP$^pjCvif5KE1!{nDgTsGhF4!^znQbp>;|Dj*<_yx=vH9S8>?6f8R>{z%^ zhpAvm9${vSdi9f-=z*B;K){rsmcXfd11%OV2Au0{kzO;C?qHQJP#%f(-_^trXDuY6&?gzl)Rzu)8dI{{AE-hs#hx&+v-1j3ERq{BWUE01@FbVFhM8)$Sf zb>i|%gankr^mqb*8s~rbldhO?L_A}`oQ|AJ2@pKmu7y_0u^BaTyR(n zkj*F*6l_wUJ44UG>Z+13Flv#ikh zak&|MA))Z)xlG+Cs{QUq^C|Hx@2{81js%`~{uM#$tkeI*Iw;+eq_{-ZcYh7!zYuAa z`9s+*xJJBqGH#EIq48g#j+-~jzab|j+dkjq!54EFJD~6VUAj%1ksxqD@E{2g(sGF%vv{yF-E>F~}?I7`5J5GeINzB!uvX~qwUqT@Rr+G6mFXRh; z^h!uPn3U4LJ6nrsJmcg-LWC0Awc(IScx3~=Ay7JwNXA^sv@ReFAeRl24bk$#oqicA z@XQcMGeVG$PFYgdXMI>TP3pAXOXAhxMF<;@GI%ozJN!T<1P9s-awQf43lkw=;qsmI zJEl7d2}Lqy{h*dX=utwnYe~0;8^_$9{5cYw8NPG554n^t`oHn4F zl&;3~z!SADK(Ug~>umGD!&5Pcs03s-=Zdu9lTU$5K?o>Zoj6|!;T8%G#WgcRUIl@l zZkCon=+gXpmF-s);qIv8k>8Y4$^f&%!08ier}f2KndiM})wX*;6OX^`Oh6Z=4drYa zEZwoKAgQi9vv6p(Tlyj4?gO19IHGrjRXd^3Na<2OKyipS2{MRRq#P=#xp?D5no|r?oou?CiUS5YqthBk(< z%@M;PW_4VhbCp1(Y#+0JSG^;U;~ymBJw0wUDJvWOdfBXgOMRbb#!l#OG2rdR zPgq9E9+(>UG25l9EAZSVbvXWoxls#Gz)h{8B_!l8|lwPyvr;)*&9oDXiuR_ZS{tx$-Jk`Ix0n^f?nL=$0HHW ziGLy&6=x(FBpxzM7@JRj+A9J6qbUVYdiorQ`Ofm|xnk2Xsv09j-iue-qoS^~OD{BZ z+?sd>*!k3JXPhNo@C#k}x^=wRNbhvNvloV;MEEPq3dY=J>#+E$YrN;{?4ie6|JODpmzzDbqj za8#7)wQ^VtN?NFLdlYe2a$uC8zd>E8(IhXa?+MrnO!dzW@6g3^&w3yhZdv{t?%jv8 zx>{bPuCSg~a7l4OF&0;>LHGB}301g{G6fDmFH)#G&H(F&FA%1%au)q}#AaTKUjX;r zDw>gb!I7^!QP|_RB-5q2j-L7&O*fIgGHUAsjU!T`n^oRI+5#ls-u)H7UJ!|x8e*qj zFu3)NnE&g_4Q$IemAU!j5|vm|ipUosxMDD95k9VUlexJ&VJ(8`??Dg)LIbpy+)3*B zzIM8`9&>MWKBDKFR#cvIC!IT~I?JA=qdyiVMhi6^aV0@_F?sTsjyroIZ4WVM2fK$! zg>*{ZjOM60I5HzI9A4nTV3bi@64YbamZ?rEbhY^m{en`rRg{%GHUCiE+*1XztV#Nu&&wYKIt< zxYV;_j3De&m2SQe5gE7v zT8LLZ=uFd`R5qGE{xh)_xugQcQwl~S*xXxkUA-3jW!;4rViue&HTXK%C(oBq+GBT_ z^oCx2$rr$^I~8*@AX%IAPjBYx;=gYFf|ILRNu?S&+&or`I~0NGxyguCFV2yFke|{0 z)QGY{*?s((!l@VLeR}Wjdi0b?E=h-(%yWna1IDc*9utG~3%Le#h+DwYWf` z1;vM*#7K4ft|Y)-QTG!bAl++S-<%UVoMU%klAz*$s$y-1H{g#vPwyDNEgpO9KP~3! zwjNqdWZ2Tb5R*ku^7|Vx#X_O9tJCB1SxRFHk#zGJ@`*>;jL4F5pXCM|94Q_Omu0*> z>A}rRxn{oQGamlfRT;40t^@-H0l6V=<)3d~GZJD^$|r$k(PidZ3{wJRAl=~)YRD{w z>)Yhz${_O9#;3D$1<(!@AddZYdeh4~g%OmlTL5lFOtQt(DNkfLW{6~zByz>LJG6K5 zY#)7{m$qeixUtK!^T^c5aAC>|e{xa5sNQ-#F~<|TE8@wy0~y6EN|VlBeJ&r#D_Nnh zEYDCbNa|Z5i?rGuZ{=qC$zGtS%k`s2%I-$zK?OR0zJQn2%cE(Aln3lIWZW#Dy%uU3 zw7MrNQn=qDo?Pe|Z`NdxU&V!Mc_?gR!3yLL$XpJhR~zeb7~d>*bb2E9%`6tRMdyOj zwMQ?n7YUz|X80pSR;VCGO!SYYb*VG$>#Pq^xn)*2Szsl>K+MUFk_&XxUjM!26CNI} zbtQVk0AI&zl-YFa4)u{7jmxS6Ggc5J(?~Fnm~hNWur&9!*B%@ylhg4m9NywUYbiub zTk%V~t=qdw0p}I@a0ep31uf1#y~;x~m^{<--FRcu9)4yxE6Gopcl+di-$aRFT|}_Vb!rVL@+i;%$vgXq%_J_Gnz^Y- zJao@e$%~9@2_?+}-L3ydeZ&gsv?2^$>7mYnT9L-nC#-r`O-DbY$m`A1gY~=SFhn7% zjaED>s{&UqkXv}|^Yd>m$yCtp6icWUy%;GCq_&#d(T7L)EK|^LuJ!tF$d9Bo|LWC( zDW3x{)c1YYIVos_o=X&ZBj6yG^19{SA|7UekMv&KUGOzfo={iZ+%2Mo=e39ickmWx z$4r3dQIS$il=CyKMg9=EF`1CN`lVUxnv-(XZ8UWzFTrM^LQwUrbCTyq%^5@tMef~O zXq6(F>N{HY`FSQeyuJp}x{FLU*>FkI>GE)>& zjWY5~Lp3wu7*(*!**9=dr~XQMJR>0zrR<2-e$3)7_x!ccnpLN9=LHwXtBpz5CWqvL z^shl;`do!m@+lBN;mjXb8=SLwiGtQ5;r0c2T8(q_EtjB6=$?pBmad7By^&g#rB1M9 z%%ZY69#}`c_L1JFhX!^aHZ}?7*E#H7Tw~67Z~xbyNJXIV9Y@kKjQBFwlmNlNr!m^V zy`N?juq)Wv1tILT?dr|1uv9b52)^OQa@(l5JSa$zN|uCAV;p%#at*^K>#8yTmpJf@lb+F53e5)3W4nl3oDE1}h+HI>T>>1!^E zOylXCf?BqNeJ_JZ$GW&b`zv!ae(?l)5L0m%;|*Uu)~v0KKny{o!54m7xblRFGGT2- zuVXEWSxV01ehh!smTycjbdE`Ze1q`^br8nN}$us(< z!P!5-JA^GipR_qPJ5VpxXP?nkw+L)J;%XQP$&xRjyR~*DrcH;lD^rE9rRy%1e06Pn z!w)bSmO^`v2({!dICmVdbI-WgZE9TZ()m@{L2VROyLOca?$0zsd4v6^PLlL~CvMem zxZbVpfE8=2j7_L5&2oZ7XrU%rYq-MD4IH{G_P+l?H`GpGovg0+oVjiB$g%4DTFmrz zl%<3xA6N<8|5J_52fZR4V+;eIX&W#E&-9h#xVi#mR|$N{&K%)KkhT-gVGP-|-sQ8Z z{>r*@RykbAqbV6^I|@pylgqWLA~o1*4ThpDT`FaQ5Q)imem+|=(XplqPUY<2UFC|) zj#5`H)qh%ug>0>Sv_v`<*yqB@qN8+{6B^p4{{F*hDX~%F?q#dfaL0vdmnfBKd!4xw zoo$(s3~f8!rnQ>vb0Ix3gQN~;L=^*N6U-{QY5^=m?`8QCoF`DX7h-OpBNu`@E6zrj zStJ*E0GH(KyK~5uZS((O?mfV3M@%*0u|2G`>aoqRab;arX{fzhfwcgSR z%Jovw9a?+~3px*o)jCvkZV1!;B!S~N?XE^2$1`@W{{o(Q3NFz`D8cEDq}MSfNx3d zmZ!8dbu*Od@F<13KzpoDtfmY+ks$NVZ6ug>40k6nM`M0cw{{Ym8Ma+Z5 zb)yfd3fX#A?Kd7ctAO3q(Zup)22Mc&s zosjUXq$k%#yN%7!a85>s}# zpcKY-=*`&J%lhev*1>%pfYBkqM944HHILWrL5hP7m)}mzaX;h3aRb(Fb+t-pWonwh z=bE`G;|arl3rVG<4HteFh`ajNYaMuCh-U9#Px=T6IR#fB*%lxbv0g4ON86XO$W|k1SL*}3lPTOk_Yt%IMQ(o zGDV>H#`sY$xYb7Ufu2Q!P@Xl$_repv6uDezN-^5I@i0!J5(w3I&|HzZfG!RyWGtJo zt{H>}CUv26)fmkO;{>23A3vF4Dd7}8+JG%E$~`vjulW5CJ|Rjev7^U=aKZAw%_)oS ziUkxo2VMbV?7N5>C5S86iU0Z|-$R7V`2|pctQ07?Kqrp8PsA=`a3jEQ;%Rk`%U7-p zvESk`)X*U4BH=$j5rtqwXQy1357=-PeEEdo91h$hV^XCGzPzSyQx=dUG8hmr;{K0dI94`5S_;0GZ;XJRwiGG+MJ%kZ!e z1h%KR@A{6F%a%z1y#ud~sH}F>rMN@w&x6~S>m<#(KVV=~8cRJpU2P-PrR0v? ZO?mnc;K=Y&A0?res5KH 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 YY20Lk literal 25461 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 diff --git a/apps/docs/public/static/search/assistant-tool-permissions.png b/apps/docs/public/static/search/assistant-tool-permissions.png index 5d8aac853ba8861cbe6172266cf65a39451c31e6..90dd2f891ad9fb5b714c1de10edeef199bdbc021 100644 GIT binary patch literal 77113 zcmcfpcR1GlA3ly}Zy`j;mX#2hS&^$EGo+FkN@Zqbla)=Sl(I!-q(L&Wr7}xGvNDoU zD*Jn0b-zEy@1O5K-`{b3{Ba-m!PRwLujlJA&hvbnk5{zeQC$Yw9kg4vY+*P=&^F$( zh2q|pEo76_r1(uf=i8huTbQ;S($+Nfx&3XB!jrYNUVbe`f+U$K^aXyTzF)YyyX@-B ztC8DKKQwzWgTp9|=C`+^ho4{Ji=s$9@1=+A>rqkE znmPAx-??*@eYbejzaN%diU0mDs+^mQQQ+TCmmj_2f4?To$PDxS_v?qv!D0XXx_syV zl^3rFEWdj7Dl{xiP*Bj$)^=p~z3lAl;^K>E&z`ln7y92f?>b&a#+btu7#J9RLvx;) znK{Jv=3d7$O-Wz&2d@2TisM==77!8=l9Q7=_x`~&#k`|o{?R*S4zFqdU02r6q;J83 zqN1Y5uWX}H%-DZ<--Utak50Y#HTU^+;w4%}MytnX^jCk)(y>cMJ$rXoJ!pMJeyH$< z=C4w>(I$u2*JWn^dmqo_ZziSJ;(8{PdGUQEW zmuGNy=N!M8mcmpp{)G3uA!gF_`Sa(xI{vBdrX9Q&OSP}3dnP3%g;onoO6nOH%%wNd zGcY7EQZxJ*X}nrntC6JF+1VNGKRq?|vDB^^*KyVJ@uk^*HVLy98xxc6#qrl)U*9lb z!tpUPuMcz$i;2I>*k3>MCS4)L%e{GN=7Zb4KdW;!CoC*lOq7Jkd2yD`A0C}TFddBN zUj9C)66@*d`K>GWb?%WHm0mLu3)@8WsA*~Ys{<~l?>pcB^!y9=@x#KMJ{xPx!*yXs zlvFoAJw1P9&BAoeoBhy9^J1&@iSnG@?*kP--l=a6&*|qJeIUosNh$l{`D6VHEcqK> zw-@!{x|y?EY=m@wOuRW@nAY&IiOcZ6yEuCzIlrJGbbv&YjPz=A0BFO~# z4wCp>@5v6$fU(A_+h4wX=@1}#pb`*#HZ3U`P0vpB<+Z-~COYZ8$;#e^h*wB@=msw8!@0z;d*p_c^y z1+u!^4D|GgEN}0q{KlUO#AWMj>LaFR^6Mx={s!n|Bw?15d*{xbr>p(zN=?>RmWoeS zBsbjm_xDF0MG#2qsTEzVBMiyv)7U5@w(<_;8{8Gqza@F9l2wc>i&lw^v2W$q>?ec^ zvUGK2Mar_g09W0j=swZDyteGY+E?MRD#CP>>Ncd7LgWrq#6-xUa` zJ)KukvD})n%lx4wF)4+QTt`Np`StB%vDHg0lC`DkfK_&}Xvu^%Qk!u4#p}CIMAW#h z-QiXCq<-A^VB+1~i?+6lpDxyXxe@wdpu%Hxj{8UPiD!=t2O|zxZG`FY*=SluJ|J&> zJ=vM996u$h=sp3 zO@j^Pt6t|PebB}lCzYw<&y@*N$G5lZ&OJHX+YuRSb&lInAlj*~B=hQ3x~A;YmhAPq zicR&k-T4L!{RKvXN<;78zkl^A%c(PK@jR|+oMh)p*MhQj?G~k>cklLyz4O;>3fVXx zE~xnH@#Dw!9AhG(vZ8A`A3uE>-RwUg{67DqX|ke(o!zMXx%b0tM*Z2k3Ew~0BD%}q@Q zhbqWu8cS^IrH9AH!e#gS{j7D3=T=%-nu+A4zJ4W~)Xws$%Y7?Oa;dNH?()jmhOf;u zp7uh``Tc!xwV5}lg%sJo=j3x~%6Y+;mw!u9CYB6;h@qXFnVFfMW|uJ2`&X)*ADU8d zfBEu7@!)iC(T&{PT*E=NQG_(|cyl6r@afeh0*3+thvIS3cGYkMNM~^@M#(zY?EU;#J%zM#FMjEY}TU2#x0Yt zT)D!n=r+=T44S`B&u92U`?_$w=8{T;t!CR^+n#z&;g8O!@6jy6NZas}i)b%llnm4T zPm2D#mZSG8si-QW#w&grUza@2E_E`^r;^`vt5j!iFOR~7lTS8>rHc{892f2E!U89d zrK-M*V>lDVtjoW@-%;&VcUwFfH(2R)z%O*?+@90bRsPE?&U9MalI-;q0xA9c{AxBg zUKk4VwEBHFC=-3g*mzfYqmXNTmyi%SXLw4=wl0P>3nceb-yaikTnYknQ7S3>FaPQ( zFe1B)#{ap$U-|o5?=`7YJBqjNR5ffGs1A6c5ke|pqjKrn{K5jKtbNP(!56Pn#Zn&d z(*5n3NqL7Z)h0DuRbvs09TolQ+&sO0uxSB>NLRO6=PG;VYd@6asG~%Daru|an25XD z^vmv2DWf_g2`fap`k8hPa$!_ZE|p6zk4{#g;Y*3`cX)gIxRO2}vtr`WH$3~huUA)Z z{8<>4DLLC)C>O+0Qgx*n%|<I{ijb{H>qE#tudu8D7lZhy1M@PIhC@qU%O<$IQKAr&w)o@zJHIW z;O9>Ly+LR}VKt(1baZT={_*wQ)2B~E{}wF5IpI|nHf@?k`#(bL@hXcA(c9c~_n9Qs z11HrAxb{8ZX34&MeCUShbY@mnqvjpifs>6NK743zm%O%}&(N54j}^B}UHi?waj~)C z(<02MlW0gLd%}|b@ETp9Euxu!CIcLHg>HMb?+=j*g%7D;c3AcPP#HJixli6z`BJ=P z5v}8DxK>4F4nP>vT{n-<^sBe&0}G=9ss5Fj;uxstIdRTI0u3Gn&eRvq)_u**y8xnOPZFEl$W|2<70&&`-R!$9 zfgAIYzHW}=Q&Z8)4J*HxLVbLEEKZzge);KwsVOUqu;dXThK<)H%!Y-B|9zj_WFA-Q zUXtC6wm{0g#hlCPdwV-OKYUP-mv^Ytyq}XxqC0}30~~ZbPwyt8hkx+7|8iMT(M+Cx zI&yQ@zaAv2W6a{p6rjKG@9$7peb!oOZNbt>%v1*_7OW zKV3WZsqs>p#eXb8K)?3?Hcj~d%2uZ61OyJ705tRS^V^7LW@Z{08GXL3efsq0Np%qs z5ubnDNK~mWLPX&35j8b6YI*740s-7KAN|9YA$r<*{2?JBh}^uqyyIo|%zsZK)xJvm zN|fk%5P^WTKg>otN7*DKB=+uoER=CI#8x!+khBfb8;2!bG&$*%Bmi`ve@o8I%WG+A z>HNnsG|ycW#DZdUkVv;g8TgVl?gfXxLPO2jaVGS5#q;NUQp~N}w`~)o($m*R<+!`& zwA$aWOzm7?VH3#eiHV8v+uR8F^6H9Czve!p972-9#UWNn3qx~-D>mhsnO~}Wf7r&w z#>bnTi4xV;)z$smNuAX*>NK@eE$^xYwB6jBPoPTMeMZVS)8p&g-*caDkWp>j`R&uQ zi)hXZzW~|LkuUU@6A8e(J1YO8=P!ZGGF@0&0wmriFV8kr+uq*Z($do0teeAHxSfSX zfC|(qO;9%;C=%D9cUSGD>3w6g*$2lTPk^P|xqX|Qc_C#7A|5GX3fQtP%#^| zwWbJGhjnyx^iXjFek78ikUe|yWDxWRFl?wg;OfoQ)m6j*e$F=?F^!5cmQqz6XlWtj z?6tGAlN4Q$MN2T~&@Zmu98V7oB#q@|_ve_BA}-?B@1P2}T;D@saA#xm+MizVKl zyz1z$7yIYog|!rvuh%KEEH>8G^B+zJ#qE%9>+M|{YfVA-)EoO!Mo@TFU!N3hU5In| zch$4a|E^kA*7&r#?;*GEl3AyF?e+OfsEHR}WcHAjhK3XE1%wAxT@gU^xdT|6rM_UO#gp-9T} zTVL@iwQba18^$MIctdlhRtJ7vUbD1w55P%&{2lE_74PYRmk z>HWL-)!bh!Y!@%iq3H#!{G39|1NC`aUcNRV#H;4dq3R=@CvK7#E6Wm)fS~1*$4>1pWeY46?J z)^zf3HW^Llst&ulxoKt@;TS&$uDp>>FJLnQ=a$(YaAly3z-03knI@kF_MBl3FC9A>EQcM^8_WEKzXjGXxC> zh;{&jOA*o6Dg~Cbu(Y&QC58HthucNZwU0i8dNF=@c=(!x`P*CabiTObE8lkpG6iw> zM#r;!$^2r&U-u<5bMwXOL8r-{N6SAM9!G6baBr%_T_EUpW+zkAZvR)dZ6UQ-;f&{p z>rjHfLiZRVb!bbi%ZDQKxU5XvIESG1qarIyjk1;63cO@^YN`VC-hX-V%Xu*Ez}4Aj z=?WL$7nvJW>%@eRjPW32G-A6Ro=~U?*xcCPW?hS$@%eL5cb@+7vbDKkO5JYQN0R zo+>cp7aoMXqV=3FQpQ+KjQyi_T_{D8i4coxgI`P=S~{<)PjCo8{aE`=lRU0qB^;cx zqGC&M_MsFJcYiRk`F^m4@$(jan>)+@tSp_Y+Spi~b62fAvM@a{(S+Vpt-g({G`~2_ z_wc~#z3qG(H{4o+1ru_up7@WvRmr?)&G#2Hi0;n$B~!ZhOnXbR@YReAD|>r;YwO`G zovYf@4FR`lCwQ5d_#zoL=IVm01HY}jPRoYkF)g@F`D1vL=*#gEru52I&6j77#Htsu zF!Jnw>2;@Zz+9Yai11 z|u!o>b zP29gvC{JE&ZpcdkB!VELpP{;p;`r#%Ba|E&X=xA;ovJINYIIMJKR)AgXW#i9wn+we z)!sk^{9GLX*g@E4`g+&TpGypJab8|QYX@l-7VZXZaL&Y5G%T;KetzyoRF*(kUivS~ zl3qx1Q&Lm}cRo%m5lO!Y;0sC~XXLKd9B)UD%m__l;^DbtVdv?!Y0jzl#I})^K9)!2 z(qu=blK~jcNwrP+@22i7UhM4bVA-GwGxJ~SspvU|zkjc`t|Rr`hn{z<`@@HX*jPQ= zFAEGhGU=NR+?B0*r%I!qn~yb)Oin&`e77^no;oVU%43WV!O=hx1n`e~AYob%EVGFK zKU9z{r{Xz8U6QYLxrdurBfK|pM6yPmt*rMkJh zYe~zv4%dPlyv^9pmEHz?!>t~u%E!0ms#A9!!_#>SfmaUgUvWaH+%sT}>uYO%zrP0n zy+A+$U0|Rqv?v`xxs)Y|v);lWR5I7c2dqDUrDUn_?;9r$8yr=Qv(kx#7d-;ds1Cg`wi=ly+v^IS-8)uq`TXQJlj@tcBumx74mp8LZ6zd`&aTfwd=)?Pn2&lS}L zb;lxyz+6r(6CB|}!{+eZ^2u3C1+}0US2hlNI6bfTkhW? zGjgS`K5l%rvrS>_BwHM5xDh()idL%@u)-&zVebm4gEKL|Z%lEBDs;Wf~T2rolE(J&yFej#ix7CAon(&`);!ZTQw#(S-_%@7ctH7Yo(lnbI zkgkK1lPKe#t85Yx$%KQ_+gLTaWSlzqw1uE|q7|_`{X*bP)V5}9F^lI>F@s`hU|^sZ z<&+I+9X$8hvuDi_mB=gtJ0#;URSM1quzAZOzA%kD=Xwi;&85HVq72Y&-Ku*HYS6QQ z)l1*fOU89M?d5h`miwT2MsDRzEaa=uunghZMtjm+b299vwNSN1xM0g3rVcw6Q;5`5 z7W(!IXr7u3GHl`z#aUp{2y-GIEi@{#KlHcr-P$Gmdsu^x<#+_We20noh>(gh&Y_(h}PI)MCN^nIE{LOOyc8VlLp?j=!Xx_ z8yYfoZEHVX(XCs>+gp5^xAPsUHnism(^mrn+-}0kwER9?#9>SJC-;Hq90?(-~3;iD6l;Ka?h+Q=&$#@mSFzYU7 z{QR}A7Wuq6EI>Yo_F#bHxAtcNY0I~$5fv;=TB@}$(g<{8`M^RZwvMF6T|u~k9D+|$ zeGA3n#G9Fk38>Qi3!nEs1uh(4ia`B5{8r#y=Yd9PmeZtNDJYZHW@pZvAy8#yWie@h zD@#0M)T|CR*WO(adzNvT&!9mc4Zvp|<6BZ2$7i9|(m_#imXl+6F{e$DEwvxJL4=ffSlt8aUKAF_m zcmTAis;Z_wtFEqIUK}^M%OyZ#&rU77`1M`Tj|qKp;TADN2|YG$?%QG}A`POz+i$N) ze1IOoe5vI{h{f^a%gf7Rdwtjb$cSwJ9D0xBvpueF{KSJR?n#zay!?kMyytcfSyi~_ zqG1w6G5{7dq*7XFxtEuwuMu|mZbTX0krceRIW{^f*v!`nX_?=ab=led;z=Fi9sC^E zv|r?U6yb$^Ycj=sP38S=n3PfPHCW3uWl5&6-)1CEU}sX`8`PlB%%O+O)i{8w&JGNq zO%*kIWkgY*uyg+_AxwnK_S`EfItML}I}`OClpEDxpwjEyL(3=N3A5k6ReDYdm_F0o z4Z(MMe*Vh=CALLsdlF!UxaeqTbZ?N2xb-y^?7(C|!-+SDf}lOlEbRxF$jOr@N7g5S zdRhcUj^6%*$qe|awS&H%p8MCgaYCeQM^_HG?y;(hayHs|E?m35e`T|V3Nnua-~j+i zFq;x)F=!Y68lKQUCJec(f!QZXKu6nh74le>gXvhTeV5Tk3r*QK}WBNz_IkdcwK zSKz=DCvNNtlRMx46O$>7W=hJ+lHa9jc1WYW;WN-M7%vi8)VXu3jWI5~FV3e8l#n*cZY730ALC}`K1~c`*x_XM` z4%uf0t2&|MQ!6H3fYPL^s}mS*(fsMtW#|PKqGk-eO#d?1)92}KXIV9o>*YH3_BlmG z5(2@j>I2HxfwdEO)zM?5kH7oGNKda#F;-WxQWD-%-`~H(?V#2Xy)n(*IBG@DNka^) z5XlL)85tRnIns`S7TA;Ikf8^;ePv={v2}5|ZCJ*%XG}y>Q*%M>t4dNr&y6T*k*V!V z?YJ*AjG;n8A~XSHe>NMx%O3aE;wK{DxmZV6Cgxlc?xTXSf7X`w+Ft4ToKTP4Q&r`T z9H^{peUWIm-f}wN5268I^w-kTEaX3}ZjlX+{$xzyq)zrVHd4$?&d#29c2@G7?0^O- zL1EbI^EENlaEmiRi}|1cZ|<4s#6Mv^OUM4|5zf*Gh#hf`u8Hp#e*B=LrDZ8hx8>mE z{30(#)r45a_1K8Z$jB&m9c>FxNM^hr9vMj`kajVTOg$4{!Sck3(V)YBG2cF-a27{G zLtyqF~^X=o~8@o@K{dWY+ z!lw^^uPgPQ8w#bMyYzkF`1&nYP*5m7Ae^ruE-bX7w?==Ev1>ws$^x_lVCwGeeHpO& z)bD0mTAEM3zLP&Bj+lJmzj_9gp&MYf&}#5?V^q|@3&0F(yyvV&QnER$u5mXE4EO`n z9f+V$x`;A{nKC%TRiLJmHG!w%>1k+gss{yP01gl)kJ1$!yhSMzS&B(+9t5N#*CnIn zX8|fwg#-W0+x(gT;=YEQ|3Bv<2~vt-D!xh?ko#Od(KB!>@eg-fs+gUPO)0LQbMG0x z2xw!qHPf<3trz;o~JW5^o{rhyOtquwi zv;S>nFWPR~2~6uXAE+Q>RW163r8{pSJVb*w4IwIDSf%>6mK33JxZlTJpie zhYOY%wZ;BkS~~UY!X4RX@E|boD6^6QF&3IV?1w-gGXUWr*3;Eh^mv)j(Dgm11HlY9 z3UIR^2V|%RNjd&)O^9^P18{zLcz6i0e*gY`A){dd9}6569f89OT3R2umHF(q z!51Ge76tW1rP*bW(Lgxf{^`>y{?=jwfbKQh{{*}b5_}CNjmpZF(MB*VNSGSjUi$s} zVoyO5cl04hmj#lKoV)Yf`Eb`-OvbuT{1eTiMC%EyCZ;%eZ)gY1f(ILRBn%HDE)lT? z{)9vK5YgAdzlkT9Kee@q zL*$P(2>jMp3fT`8=JhjWWo5876sZ4zJ(Ot8;K}+cx_3Yowq)E(ev>IZyg>UK5TNl3=J66NGAj1 zyhNNQ8fptrwPq8H72(r8TQe^ibVI4Nfw1*KfT~Uvd;>2(zic$(t@D5CLw=Z|MvfRL zFklLQRibw@LEFj6$UBgVBz|7ryP&-S`G&kxQ&Z08&p%X?wSp9sc0Kc8)9|-% zC(E6T{;R901?5{6qq>;>=dC&%lR6OgKg$&%Tl)WhCssx^pFmbQ6Yl-&EDs9{3#0@# zHeq5Mm)}H_E{(weJw863ugixxQ|St>si}eE48z{&Xd0_dzQ53*pPpwQYBu^FxCX|7 zH)S1Iv~TS`L_)Pu*2&NLFjVTWW~y;ipqH1I+c!rirxrntHfiX2Ks+c&f1ORTwENlU z)6&x~U%os_V0x(-N(c*38AcV;spOC9BHee@NE{Fuq2JWh6iRpvDTRuh90C^6>yt%K ztIuQ4J^66VmpiAGyf+v8E}ico zJNjVpyBG4?pzj-yyvgY3FocbcgVSAD`!ZT}S`S$V*HAJsfosxyu}`i6Td& zhpqFK0~FTm1ZS_*4E?;k(@;-O55elE{z6<*lKu$uRO{!@>JZ)$+ez0CJdV`&?y{%J zIR56v#SZU!^?hx9YOpI|*gHII4L=4ExriB$rKj+DDh94SPf1DfPgf7xz*O$m&70Al zt|+vy8NijKm6MKO1(T`vSs3}7!lHvh9IirLj!_+N>*~H>ggY&$udffmr#5}oh&IQY zO1^U|$YBw>^_RYCBs6#!nDqsGS-|UUcc%f62nv?vPDyC@=&VSnsn0>1Jkr*|e>9P< z#=!8%=zkLh{alG;;*f|4+~pTBokFcV)RuIXKp=pbbdGG_QUC5;G5(5g3*puI>zDe- zzV{3}Ri7Wdqf9}^{s8%fI)<;{2Z5_$7YY`U61XR#o|+$9n4dSS8I#Y9JMZ4SE7tQfbN1xmE@UQMC6mY)7bsTCba+GGavRqI4Nx+7RABA!T0a?iS0eKR!9y>gJzpZ z`yG|-ahH?SHkQBMMey?80g6>D8Tv= zh!l}t1Z!J#yMPG^x&jXd~$$K4-{w*=72aVk+sgyt4J~=KNtGBS*(bj7+^IB}4$3S{lDBeIFW73RVDEcR}w4;UI?)$F$Em0`TLM>?Hc83V_33``tmYYw}lcC$A@>cmR ziI31A#cy7)j=(?v_51f6E*LZgfB+7PsD&0*Ms7u7ktR-zGBw)xz9uB&Mm2N8{TSMA zi&s)h?!Y0S_ix{RBWQEoT#B*r!sqI^B!V$U*HGN=^^hOZ1{GwEVih+nzzi{}Bv-FO9(Q^UJvp~sji~wh?b$AM(#gT$%2D<5 z(azw5zCVM^ip=y2{AA4^ScFJva@vC&J9OOBbc)|&QF0FoJu)7WkeLLk8KMn~5HA=~**%yckA@u2breuDnE$ZRJ&qc{b}%97(tc3_To*uEQv9;f49k$Jh!#xwc5OBcT$cOeE>9HkAWIYS4yV zQui|{&2#$wd%9Nw3drME{InBc6<;iD+tXw$w$qO)lK)`U{@Gpsl;WmK6|c>?75lS*@L_}nyUAp9J>mR}j zuW>V)%#P%785-*_rl+S%m~Xdzu|Dx8J^UY=+a1L_K;>~R%4!=5)r^iXo zT~M;v!|_1&>DQ=28AD9+Y?KBs}ea9TF1T`@55 zWl7AXduY7oa;8{WM=OYYdq{4)vo1<)KRG+J_?BxD+uQgQoB_iD^kibK+7PSY4QFAO zBCt!BCDUqMNBm{YN*T0Y_*j;EvJ!GZR}4bKj$?`}o(VTF(qXVVfXi-&{Mj5U&Tv+O z!U}S~%GaYxM@`nYAqt?8kw@8-9b;E^S=P+T`{IS-rrtuDc06nvkF7EqcSl8;<~#G5 z>l}@FU>2~3`ESx)5%(8a7&o{KB!0b>mWC9}1ymDFh}+3R>-)tDFuLcpUD4IuEG$f5 zuJ!^gjF=S^`4~6LHX#veUG5O`h zU`&>g9upZ;Cg%Hm{fYrAaLYZq5=_CpadY;0@ePE@lST(~p*sdgWC`Z&T= zmK9MC=$V`xEQoRq@%_3ZPquH|7Si25>gwwB1l6 z-VK%l(2!pxcPEM(=p|&9?CDMT0tuq7F6uU~!Vz+|_JA%UcgWN4K&Luc<-^QL6~9?} zbHB#~{ZsXpW6%`?(PPnyws-E{mjQK7<7_bZ`;HE#E2TV5#zeMaYbJVWxHbf%2Z4#& zOI&r~s_#b96HoJrp$u|N7=rEf)Ik=z90J@l`111hPmY2XF}6L)Z2iFlYCw zmoN7#({%2S^0Y&CI{g-WOPJ&@R(z!Km`j(HFDQ>U{%Zv#>?>FyA) zQMA;k?L09Kqdjqa1G-^senclg4|6D##>5!2Vypc_hbq12;%}4kBl*qe-*XqC&|r49QXV_j2qCduF6tLQqa(q zCBQdeXBm6nC_ADmC+Tkn>gNazYuHs1hu9o1T~Rm>ZqFr{IQfpU%?<t>qF?@l*+onCPADIF@3Pntr;+#Hg*u zF#6bCv@V-ZQCHehMyHGJU4T+Hy-bi{Gpz^HSWi`O;lJk4`|yPM(X^jjL4S#`aO2j? z_wKv&H=P|8zu2h(eWKIo8br0MbSQ|X6_ws@`a#@h@ zrr}ienTI%LFHr-1dGU)_a4aQBGqjncjFzh>bKt8WiV#3Va78O_`2(mr7Dj37>wOA51bN^3_B#D}}8XT#nei ziTroZCR_69o5sI>-Icth5x3w6^k^}j=q@NUM2qv;9?>LP=rXWH=1E5c1Oy~GwYYwP z$`_>${417C<=>Ck0EohR1^@R42>DKS-TbT-LO37BE7z}IcT-`>&dMSsB^|q?mQ2c% z4r=Q1BtNYx()Q%^Z&{%(4Jj!p!oKcb)2gUJ0&l{zg|=?pIwW{o&g|^F;aWH65K;>0 z*?fD%jX=3H)o#kmk9AYAMe+CCFwWGvLPo{deoMZ{wlRjFaABw_ItdC+oVQtN;Vyp8 zx}-x@<8IHBe|jDe>PSBfwrOk9(D2ufIO!OC#^6Exd4ag(VNULijg7WrJ3o(2Oc42` znh5+ir6bWlgTJpsB|^}DtgYoUe{}NAE&0*i(&fy_dEqV18EGbKhHVn)>VUK8DqLBlRj|CZn|Iqp#FUAuN^R}!h8Xg0`;2?iMC zNqL9oMSiJ{-m2!>C{6m+)!EsavHt~zs6<__t)pYO^vM%8P~^Jc1MBz0wWnf&TylCP zB_(AY+8Sbs3WTh*oR_TQ+xAHD#E2vFBH5Fs3j6jkGBB`dPqj8QghLvC`Z`&dZX=es z^zgDegm$wqIx33rNe4gZG6xT?tge3Q@0T6qdvl}D#1ufczP=uMGlkJgM{n==6j!Q@ zz45}r0u3$g;?j~%m}Pbt2@45#-uMDsC;W3(3*Z z(f_HM0$qf^=S4i?e+D~ZoCpZ~-(Pt9|LSD@e_hf$d<5Rs|CGGR7cdW%LcxS2DRvQ) zIaGM7@rT*jg0%h~BH(c-R_30b<@aJ?J6HPu{YNlzY!GL1+?<@tC>5aZV(Y(r&YeBG z^5$kkLxZ*D{{{o8>_2s6;hJ9oSpm#KyG80j%mWL#~Z&O3Fu; zPiV=AFg-s0kzuA5saj;cW9Qu!NEYgUQ=C-XvZEz zZG@;dMiQq4(>*j^K8s^Cg$RxiORsNzohZEjDUM0Mj{M@}2Heyg2zDZ?$5=}=FO-C6 z=n8<(3FE9p6TXugUEpY2$CxqSZ^(!5n zsK$R-L#VqL?6+Z3h|$A7t!<(X-tT^{Us=c|s-VU>OZ0K>L_hU-} zYEMKG#Fct_2$B138>m?|)Q=QdbP#EXARu>pjB}{n z<4{7mxVQkjxA~GEoB+qVn4~S|)Nv1^0@2S<8z6z>VB1xA~akoE#j`q_Lbg1)4!5?P`lyk+7F*QN%4H&+UiB_}b>l+Mq~GcoyHo zhTxp~Uy>en#4O|yOdQmlYto}YZ>v3+Y+aWOnP zyXdjzbu2(_@l5WbSvK^ghI{~Mo#_z!9CW|3*eX&AY-Nnj%oJs3Z)0P70v3^&m&bZ#Z3b`S;tw z!Bf6h)oFZ{6T;_i{+qz9mv=CH8y(%o&CR`IN1@j{3)DMMXici8xw*oO4dh8pM-J5* zL1O{FLPju%Q5uuQ)@go2Lq|tDd`BO)mrPz5`pFh9bbXS1&@jfYTRUf8CSZhY+=4$+x z-TlK!Thzu>OCJE2-GF-%^AXK3%Cvk#9xq*OZR^p{WTNMC5GeCXEOAy9YOI@~nC$~W z14`cCL3yXaRw~I!x`sMtThc0lJxrDq(XpzxJYdgym#dm5*kv!a9LKMs5fORdBVhb% z83^_DC)S+Cm6+iOIOreTL84Bh&HqQ(9#`<)U%CtmJb@Q1Z56#AtCG90lM5vRdPIwg zJ*Qs03$}R49TGEInx9x#5SZTGRuX*8iggJD7aT#&Bd{dJCKHSesURyi2(-wfoV;}I z7TLNr0VBJhKl3CqkyyUu9n~UIV(lq%-2>FbMMGyGE*F;vUQ-cT7( zg%Td;j?puU!hi-0oOrI~SrkX2c1yRyJ)F}Y8LT?8M3V_5fS&C7d3m3l+_#~Zt4LA5 zU*B#*fkDy87V6S$*hWovWjZ+pGfitgkQlg+G=4=Vzz7l|g8>a|VM;Z|J$*o$u&D_? zuBAsQjJYZ2($~@4>^((}_MWg6LJ&ZK1 z2|z5TeK$;?^*v}(CemphEpNQPpWqbBs_-;QO=sGF1$!64$A(Phb?#GZgu8AKr-V+>5 zM$-cR<8uByGP~1Yi(3u$n(iCtg5a_3*l{aW*PyAP0gx)nlbw_ErqRWO!|F5}%Ph>f zGT{_X#pDze$1N1}~+d$0&>`L5WodG?T!>YuZBu~qjiJkpATIqy_(O>@JsKfB=8=JrhB^Am9Oy>UqPOi5m{Y_m^jRlsYeUplq-EPKj~5jcHmbH! zxCKNXqtX?>haHBH|12~#f^%~nAhR2ij0?6Gx_)_8rav(=bM;u@@}h7ACMMYV4JGkE z;x0s-%&i;(u3%iPCN_Oe*)iyH@apO1%p-y?ee3&zb@5Ynz_^$?cl&_f4 z?O-R$vGef2%EA$c%g^)@D1P0CVQcQ;YaL9`KHt`CZg63m$HViIXz;47g<0zNw~yOO z30ibzj~~ClFbA>SDfH?SqQXx6=QQ7kl4sAL&y!6APm+_w$VTfi;dq5U3k+(|9byzT z;ZXJzrDRH_=T>C;*oH4?c%Z!sOLK4EzQupp3Zuw-4}8H+14CTNRq?j9(x2$1*D$8X zlBwupeAp5#hK66^J1@w%8QD94c@z==LjXnZ?I~M=J)vqEvo%};ZK4xa&=HRqBC0HvgFvHa>t9{Uz7*4u99Aq3C@Vt?qblO3iDIZ zJkE4Wrp!EyaQW|A3>jvZ633XV`1mv|f|CHg-el}oQ9jmTD~cJ?NEl{L={Ii@ZJ~pE z6#I3LP&5)}Y`UB{g zQV(pY@0+-a!o0c zjR?V#Z^6b&~&G;!M59(e{Zg>w2sz@hKx89PU0ftDG0i@C}45f_V>vI3QyvBen z%2N1sP+^_&h_E3p7A}e9qP~wGTVN46hIen+@o#Jp;z0NZ8u?U@8S01wX?c29I z@-&Y!&soCsQ)o`MS6evg8s9ymLLpQ08{t>3i2c^UI^)#fi{DW9q54HWIk08~7fEhO zQWEofMly?!*jknt#SnBA^aKul8?TNVS8PFHCU?0mjvW%(p#IIgp8aWfu4WShEPnu) z(d*hP2?Lr3`HkU%LFJ1-<%)%=#KSNK+}lP7 zUB~Gz%2J`&+a^mcUNd(py!#O5&>5;+lx?*qaq{O|O?>tvHD#>r8l7()*d9CpFJHcd5WS~)W@^e|WotigS_$UO zY10sb(zs7)Pz#EiJxEKnZ1p%U^W*t=l59&1QNM0)cR?|j+^iD^!s24Mk5R*QEM^yZ z0E$Y!ee-4(j#@TxQ^W7$@ySl6{7>pQKF-H1o#*?g`GM(7ygkt`RzP+pltl7K;8to+ zpe<3r2w7#{ZACEa=&c(-1P-6h7;vL|{le+~Zy9TIsdrm+_JxSlp_8LVbrc7elU|+% z0!EFqx+Ek-af^Ji-nvqglja?97td~yJtK;~(7ZT4EU1Cq=j!`|h$y%6gwbW#b)`-| zXA;Dkc-TS<1(Q8-U#ayK#<rsu(h#?#^CV-eV;yMx5{HchW3~J3bJaWkDMPRJqO=t8X%~kMbfh&jpC%0=m*sD z^X#WIQ1K6Z!8UQh>5HKgACMoAALD3$&VACW>vwgPWL4rni1=nKrUZQF)%M%494KWk>}P%gOLy_~SHva-^m!g6<4 zR~&e@iHS*)JtPXkv5xQ2zhk#HNTuZ)^ZM@k_57J}v!1kU=CqCcoA&mR30VlQ@L>PI z&4j->+i)=bKtc6wfb0(sPy9~z)&{-oVvkztoja9F6c#{;qL<3OJTGFX{sV3W9UmDy ztpMYvSYGv=o$7u(^Th2z$lYU{_gYl2ODO2w0K7Fupsw-!r-w6)c5M@JumvGThz zL6P4tn*C_I14rxkwgZ)4;O^R}4ew&etjya%VW?;2bmytGBgjzB4P6Jro$5LZJp5ar zwXqS&koM0MXvggZze#HS8efKSBu!vBiJ6r(we1z2k>IjZ7YV4-g=Z|3p=LlSIwZ-< z$r-(fc1y!XG~tT7jx^9X(33L9VqLV#uN1KH&21$Up*JWd#3F=?BGzKKNf+gGPIe8XY6jkO=|u(=6bOiqGugu-H~zFlzWwMEt_P@aooLEGXRegg;Az`DAx$P_4RdNSQY249GnC3 zTER09+v4k_Vm{SVcu!IiS!*hTgsHQ*2UTE?`SgAm5NIQ?WhMIEn z)G1)Fup|yV!6gWfX-ZwT&H!-(OxA}`FwbrxkFBZ4FM~F#=@prLTej_&_D4Z~c;XpU zJ9bgSd&qPE+lCg%E0ByHLo(yQvyaq!KFkm;mYeI|pc<7Rt9z#5Qi9kAPT!<#n-W=Q z`xdM6Xt8_ck8^|^Txq2vyC5qP`qSy*t>K^@u_E?v5W zlG$_#Pmei+Co=#y{-cCH2QwwMM~ZWbjn-BUOViH4rPY@Zlvw5o?;>3Fd=zOa-jAZA zThaSVbu^mX(D9Gge)zDx;sDg3o_x@bkAOL7#J}<29)33tl}nOZB(a+-OA_wn_MEsr zJSIWM(AL^o`h33}<`3;Pm?QztdAhk7O$a((WhEMX6SS)W!NVEF`OMu5ELppNO3#A657N6WrU=-Mxyf0;53m z2!gBh2Kqgs@8H=masK_9sVObzb^j)r=qZS|oa@{msm_d_K$j)pp6 ze|0DGLEyQCr$}!=VvyfG@oNqtAQeTYZ-$bS^Xq_-z?u^*bZq?*ca%C4E#Gi0_fAzG zKGP(snV!(%lNuVWx#O4ZsbS)s3i?pn!MA5@t5lIq7fP3B>^-}Ljtl)(S z@#6a_baB_xG+^{k)Rwd;(Wu^SQ8J9CO?;k<263gQAc4DhBS+YGXuBk!9-C4-mbWo2WY+(YHAcs{hrsc_-;$_K*VN~@h(ntQx9scn}x%-+wCz=)f<55;$@ zL=T*O{{YIzC)5Df+q^R(c~M&7(-HUDIE0vSZVBES(E2dXmVicXn+mLMcL9?)qdkfH zFJH=G1Ma^XAAeAPtOWt91}z6sy!bYcz>82A+jcBfSl|ya%Btvy9)fV1Z7}BePxpvb zy##qg+M_^Lg0ka~to@yw3JgyLX6c3cP!vb)MOB`|3OVi(u$kbn>!nNADPp$oc~sp7 zu>+fvYGhXc04*scnJan4{k2g7L@#t{Rj2 z0Nif)8UGNhqPzcj#BF(AR#h=&4}Zdw0xSO0{#TTQR(JkC)V*a?m22BJN=SDp9g{|o z5T%rER6-hQ6|e|VK@sV$iKu`@sem9M2BFer0fJ(HNGKpGpeUfoK5kv>dEf8d`x|?F zKlYE!SmRk^t;YqEIj{S?&hw~K5IS}uN{%eX+y2YWkyKOnU8&Z&XO2sa}@^^ zSe(rbOY+yOBf5f00F)s25{uR~RDs?D*J$Ua;&@z#n)8JAiZnQJ|NH zcSXTgZ7q&LwY)uU974_q{Gxc7hxtShxL zc1wy{(BD!MJY`dBRpzSS^*2$9!@9i?U@p0g0hIT|W5rB;cXu5p%kb~tzSY1z46a|K z7Gne^0U;z`es4aUlt9v)|C^y9LP3FN zDUrDp|I08`nDwV@B_w3ZygXOTe$tWvEdG3Dl3o(dFfx(LNOaMYKFzGAeU1dBYLliF zf=P}_ zd3otc2Q!)@#?X=i{6gN(6O60?gTbQ~UcY_Tit&(0nVuHio0O2y zs0&RzV3}rCy`q)i}rbd4n(p2h06u)fLMOx zYZTxtP|q+@LTwR(oWS}+Lz=B3;GW^j#S=r%z(Dx@06Wil!{_P=VI7=K?`CGo@Jpc% zVOH_>K%<8z1@JQxgE}Gm_}eI4rtVuKs3G2qnrmDm7A_cSM4PAGxho`RoBZPC=2PrX z$3(ZEojIQZz?ddKZkw9KuS9%nWjuYn_*Z*yxf4E})ToOWh1&ln6?mX`MX#+LIJzb( z1s4beD3xfjfu!E5uGUwN;!6|W`U>fQv45C0juqAMGqO5chOFXq^R%NzNA?&Ny~`AO zKtn@Qa!sIW{NcF@6m;HV_~me=DO7Q!T`&55;vG%bPu_^W!9R95^9~ROm@!U8=5PUS0wAOo;!fP%DADR{rz;=|Wdvb&+#}D%-xc z2=NVWwFbHJFMYO+KR*8g>ilQVcJhtAdsnq@KyE>K8V&PlAW%r6u*_Bx8>T|t2cmLb zJC25fF;xbZMj-O{6Y?#7rdO~%vGL+pN1_u#`z*e&N;S99mi z4+tK>MM6gz4e$ZK%}#gsRY09_adGqfT-+g;5zyvw90Zz**S7uAXk?fKU>&ewxHBNg zv%!@?-cR`QZUzMf?R$M&p_)_g8^Rhy5G3}ec=3@NXxGqjB(8gnxd|a77+bH0S1N&i zKrR(#R0BSCKb9uLQJNcW_v&CA6lCu**&wmT!~ifgq~xWhG=iSx2*6lAMKJsjoa&qk zU!#nyw>O|qF!Uy$#EFcfR)ux4$a4Pis$zkNq@+VVBsaHq>M{H6+gECM9^JNWw`gbM zW_s$y9J?F4G*nf&CC^wwDyMOBIT#W+DrR)U2(7%nm?t-#TkFa`L~dnD%N zk2Dm#urJyede9V~F4;shG!*wJ7@(euyFhm88OoK^T};o(ak5F8nw~DbCNP(l;t~P+ zZ`b`W4GD=NShvtz;-)KisJLV*)p{S2DhyS(z#3w_g_GdIs89dNm1Ul-M!2Ei2gDdn zST=AV`*z@cZcMucF#*QZmisEQS{?9ye(5=aRSs0vS=3$>L0oP8M(F~ zgOQC~Zzxq8GDo_aq&58H3F|Y`dOfaLV4mQ(KZuh$aLkd*`9=sf1RA| zBoYRELqJS0Q2XA>5wnA0ncF?*Vb@Xc0U<2(^dZ2( zF|m$6-lXK=>kGPVFA^7-;5c-{+1z#r{L;(rxxuC(d`u{nuwef2^xrj(45mJ@duDED zSO@!~RWzl(6nU2c9^64^HGP@1uj%sw0D{GK++L923k277o=70gU=Gkjm=|F}=pO^D zZ+(h>L%WAQWQDe`-@Mty?kBxHY*dwlY;RB<;YQZ6#rZjo#~yH~p)jG{37O494j0N9 zdsMM|Su*X~S2B|ut)Cp)v~i=sqe$AMu;lN8{4z37mk`1hIlIyt*djk=qFkV?`nIR= z0kX=HB&Xy_ss)VbPRu;R6-rp1U{BURa(M}ZM?njto&K|ZP^~0b_ei-QU?IYo))u@$pN zTklLbE=BVkTKxr_k%NnRqJ5HZey-GQ3_3HCjCsC zVNyf*3jbHV#z@Zwe2&6X4Bu}Lp77d+P6Ww^a90gH%`;RA1b7PuhUCRAdjwQhEhDcn zC&$P4d6Rv*n-IE8dQgCYN4!(_QRLQY_}QUpk#o3_GUuB#a$Zk3OU>UcUvtVEh#~~2 zxO}%yzRNarj{FlbplrzNd%}}~gMyPKIG-@Z;!VbrEr6tki~7$a=FqhmIukIiLsnBG*yWy#W|vkGVD~1` zeh3u7qlw308jP6LUVL|7Z9LC{RZLXe<67wFx@~_N=>CfZJhHYl6b2o-^~f|gzoWQu zN}~jC;zH2TqsC#;a`{JM+wFs%o)Uw#at8f8k}R7%x3E6A4uD2^FkQlS5tCd({~4b! zkGJs-bae3;lYkYit(W+wDf+fUcrEpy6Jg{OCzCqO**!&jbv4s}Q>1{aW^jWEE$szB zuR?F?BWL|%OG6`qsi~0@#9q>aCJ+^_V83T$1m)n(RnUdgm+NY4-+i=k=Ju8Ic$@m0 zb7m!W+Alk3OKIv*%{H|WoW8+caTd=yy;o_3v_ey54OZ^%?pwERoj8aZe}0AT;5kh0NX%n*weiifEw$}xY^2DcYVQm`kB{~G+j%|~ z?$B!ET_6vQo+DwIO7%8-l*b5OJ3aUKwV*A_SxT#z14%AT7dY}nmB}>n3JSdi%|X^% z8;qVYn$f+FF3GS0I#TeJafvB69ZDa+H+Plig&Z6l_7L&KhT@!Wshuxp^Eg}UA317< zWQ=hK0{a3UTzIgxS%=icC|Fy$K$O#^La!tU-c zfr3rI-r;nf@uu2*Z@n+yx7`D?v;GlnDL0_V+Ck%{@_?xxJ$Z5ng2QfGN%O3p7cX>< z&SaZzLW3_)@5%E0_Vm+g^w;`dqK=ytDHWH8Q6(Su7GFCOwi%mzz5En~Jm#D`bOhJ*qBs6<>7!s-DO zL$rbZeL38d8`(=O_GZ1d18WUfnv;@JpHD(%lP#|HNNt8a9XLK(!3rLyegNiH4INgn zH!K#mEJ@M3%(yRVo5|-gj%p7&SIFuhn`f{)q5JtFN9YW4u7O6(N4=zF;kPY!K7xXp z;0+6#@W((UL+2Rc^fDqB4W>pwzj4)`k?r0hA zVBBnQ$0n{8L?Xkd)3SF_mkHKX&-qWlULXt1vMNVOYk<@(M$s`tF#4!)ZXAIZYDuZ8 z_P>4W{$3o-#bW34=k{(^r_EKGvtgNZHs#gT#h=`lmK%21*;W><6ku)RWaN~+oMf~p zI+lj_R(Q}Gs#6=cN?FhJP$;6bwCY2s)9^-mox9`POA1zk>g;LGM!L3fw_AXOQRK-V zbh>wn2G%GZtCx-7rTOU;O3lhpzh!1pWb5&mV2aDmPEHfhoz@4Pm@iv0IVV7A>5s9$&xb7qsOs$o3kebxRo?%di&Ki6y(92^__In$FL z4a6T^b?>o)V4XZE-$%ip-z}^&LnHA+%o^N-Z11z3# z%*iA-g4VvwlEd*Af^sG`nj*IborYr&Sac9JRH)CGL{ooa-YtTD+ISti^ASQ|`IPNy zGjp#+^bX#I!#klH!ihf={2=dB)SmpRO*kzO-T=icFp6FK2&kF0o$CI*Pc9_h-hn_6 zBWK;ir6|^&Qeb7QEo(9=-xvxvNc%gbr^)xT2<<`#g|V8!`2ql|?M^=Yh(u8u%=chR zex!d=;;34J94MdYlPurY&8NNU*2N7`b*#lL2+kvPksWFNKwg8IkuAYs_ekt5ltls+ zvL~_<4OEnj5>HKE-l~ z9MtroGNC($ieY<#+$&5cQ^uRdn<}I^7*wdZHmjF`#evua6SMe^nr2Ff1bn z#7R!h+&9ydM=!AT-ko*i_a6U*7U`rk)}QF!fz+?xT)ShBhLGm@gGn~Ck4a9 z{rlm6;zjcaU}%`F_Jd4NYH_j5rFt^^uNSk++kK!n$i2 z?|(Y|Ha-~^HhUf>@4u{fk>_}=047uXz)tm9xk-~}y}e|ggG#SN50Ymd^n>4rsM9ob z|A7O92_C}%vRabHp^o!~*y`H09Mb({BnkDGyBx!#NK$|R@&q15)WI$ot`#t$`+Vgc|Lv6mq$C7ie&*f6}4%a$O#LZsLXX$cwO)#&ih zvm}4nj|<*33ov}Dr;E#L0NJ~-7T_1X&e5sANU9;fOza1K9>j5W4DuF3!WJB?s=|s8 zWhN%3CE2L-yLV`kHU)uE4fHvm#XuzV3=N%D@g$AyR3aE`Q0k<3oLe1?1zC@!hpF_B zP&slwl-~dEx7UeQy_;=*DFLX_K@X2gIHAz^8yguBnm@?rfipFmKpUtodhGDw(-RzA z2VT`MNCxH++g>m`d2_Cj#Aw?R1B5+S$unw;#wSQG&~Y1F@I;y>l$%%y1J$fR?3^`( z7iDE-&nw)&OibJY9ER_Jg++EHHWSEGL$tmL<-#0*hm;?3_t6~_-jLpH_$Z{e=h{|! z=%u72BRV^E=~xKz}*<45;zDazrznb%Cp~e>a9ojH7B0;NM3Q&RM8!p!mvC za5?%9mmX#{fX*VHAI=gr3}ZrI0P^n#*Ah%%MpO>B%bwt$CW7W9fxG$RB6hSV zRJRfszV!C+BmYuf=vJ!MKmv!j6|F_91nyN-C{@O>6X0WEH5a{K0Nyn@m|f_*WNV;t z%m*4~0Y^0z+08C5kX%3jB`_&H=+}NvM{Y&G6EL1m{RK@vDU;x>(^}BPow>;z@a+=D ztS}-kv0-K6oO{6Tw87?%4my9b;uf4AjNpjd`8;s_1$vzfMUP+jozYY{p-llkI2I8` z1i+cY6$>IqNd6F7a2&CgcUwsm7-6$o1BqlLY%PlQLpDWV#wrHiu%z8L1aS@=2C@+idYl_ zA%Lkaa+1}c$u9ei;;$@hu?5E-DqiKw2wwGcQpvUMaTJY;Qsx9zN}HEL47 z*8ldT@c)aUa`YY}H*ZuAP(QePcMN3=lX_n}SHG%gX zbjh!?#^Y+>_8@$y$c#%ukyrd2Vdc}{D&hs_XC7*M7jp`3Vxw0i+hZQCxAyV4DKDWH zuwK73Q4Ds?8rCFubD|c}xA0X{+`kSCs!$53qk(>;k_-+AAX=m9op>SvId=MS<)Sfm zrq`am1<20ZIqbCz7A}Q`Rds4-F&*sN71L2`IL!Ia$-K->D+tkvu}nlH9u&J$TeH1f zc-xH`D-XO>L2?ILeX+%a#6*IZCxlepmvtU&i4{YGS@j;09N7;PILriAMGJGi&;I@O z7?|;DYU}Do1BS4p=y}W{eFY)5^M@3EmH_1DfZ(ePW!wTdlDtWQ#2`Tf2nu|u@xfR* z8}hLqAVeeOqdVW@e33jmwP%xl>ECa&0d68@c`gDhrT9=ri|JY_YU;5klvA{B5VJ%( z*uF=rXs^AzI4Ax-C6x3=F9}G-q<517OU4NM$P}{ z{==j!6-!CSnm@7Kc;GQQU=CxD34wxcdAgA(q{*wF^FnoLr~zlC2m}<1)T}?&9UK${ z^;uSJEg}3s`qv#C_`3u2Y-}C-K{*VVkX|6hE9pqb_R#x@n%F7jc8`Cd3?B+QL%fM{ zwl8ictO{G6;jV62X3<6z4M;ogWA{d5xs6X6p%*K;?;C2#zFQEd19C?F?7lnx?h9R9 zx!wK!+&NFecO|I*iv{3e0r~3;=l~5P0obD;;MfORikTVEzRZm~rCt2{-!gP^onOFd z>#nCy*{0gz=mYYYdIw^1L!DvS@K!K#3afwbXh)qOo6B$T}!2Lb$qIq6q zC1O9g4Z?G?N-~sjRWK*E*Z4h~y@kDXFg9}@&bWM)>-6Z?*tE#y?Z*FA7hauDkpr0# zJDny#FCLJw3Q@R*aQyR58n`{8bv+@BfB|+< zo=sj@AtFUdAiVT>MiF~Eb`TQAjQ0|OrTBC`Kg~WyL=A^O$3&hNOeCf+OuDA|U*?_} z%DR%j@waD0x)l+riPr23jVs{(YiNjul^TAj6nd=$4l0w9c2 zcsY1^iyw(SFU#^?gmp&r&?HJ8pe1F_mg?QmTOsgM2h%4ZUz+NI9RxK^?(*5F1W)AC z6MIr_?sWx#KTig^n9je+eD9j7KFY8d@83uZVM7k!5&L#Uq!)TLMG^gchy*|8!?VXG zvV5*~`cxM`^}%iLcnjYozZ8}00@{g&5W3`@?weXSkb1wcGwE-|;GD3q6~Y_;2P;yR zY#ggYV}*XtLT)UY`j$c-H1<$$k>pPm)nE|%Pl8)_NHE?4!&ixEX<*iEEx7>4?BBch z>IKpq#61$M5Q1f;r>sbgi_=q~_u}5)aPHi?z1QC~bG20(9zOilu?;>wD=G4ceR;R( zsm7bj-ceNqyRJ2vT2&Vv~_NJ`LY%|1cI!_ zmyETaU_k2;bdsnWFo0EJB_F6rC@uP4yudDt4mJNqGemi1w4YA5AwIR`&`O9>*AG#% zVwVqWlrP}w%Y=a+y~-+vTE6*R)aGpeI*Mgv@0&F0WqJMAKljbZ5*pP%UpmP1B)%oS z{=Z!Qx%~H6HKhhn25w_)la!QkPx{qAOFh#akRGL1#PaVL!4_vFj!l*sQhJZLVa$z$ zk}(k_sFu_Z~QthY_NgQ zzNlsTr08=TwQ+>MKJpg9fuwO9oq3_@^6wT^=jMtR45#3hU5j6N86@GSVhtd=A%efvBl@YS03 zuZwp@6cCyIk&i6-p&<&!4IvY(e$~5IeJ4JhQq4f@N6>RPG*&XS{$9-1L0!>IuCCj+ zRP5Tgf1$;1W=@oBnr>m6DKI5zt6e(=<`%A_y2T>THti6H`uA(fmgQ^^F+c~zB39kmNtR&OEN#Pzg2N5yEEe(Z1e zW8J;w)Net5#O>hCQ4T=S1S)jPw-*6F98e)uZ$r!@ykWSKr905}yXE}CAQ1S_0-7s8 zcini>m0km2^iH{X^DA&MtGnn6&<$Bg>}s_9hWq;SV3qhjZNEMVBpjrGcq5n>StcSV z|0amOTVYxNVK6XtvXyHpex)Ay03)*#cdh8Ey#V-VnlL04L6N28a1GrH7 zhKJpRo$l7wmctRW=NLs>%shR947KUa2yaY+^rEOG$-&f1Z6JbUZNCh~;3cTeHTW?Cb34DB6#x^Ow}pxuF%T);hp>^Pp|pf|@$uuw$_M=X5+nFNrtv4GNH&k{BKaq( zG{BA~{`>%7Cfq-jd}TO-)lw#MNfh63G6&6}*DuFWC6%L%dh+zCgS*}z8wX@XdsoU36G5s=B#vDtnA>7mowPU5iX@9a;tK8+D3+PP}i>apKmZKoX zS$n5wn`M@UxH1u}6CG`UVXHC=s>8d;Q$2A43eYcu;hrr?SvAl~;L1jz?8{k^-Rnu# z^oG0ZC~?u8+r$mICGiA;JJBC_P=lUs_jVlgDY?zWZlgg*Vv`DW)*V^TY6jOk zf?XrB4A<&jn}Nu5d=~xU97i8Y5*kqbSAE#BX}fL3c>y#NWVyUst1;Om{(NKnEgxLi zmhDd(8vDkE8F=cypuzxa4*(AbBg4)e@$j4KJJ1<#aIB zt5B^sgos)LoxI6f?1~l&WnSIh9epnA@|A{r+x0Ckq`7E|^~!a-gx)Z0h)md3aC|Mn zc{*`g%TT4EN6!Dqxj)9)lPN*oz_@5~&<X@4Cc02DBD16C-#r>t4e+?~HOkoVIXb zJPkuNey~sLsYfZWIr9Jta)E>smp=NTjt`F@obdGb_4kLX>KR1k;ID{G&_r%L+Fvp6 z#7^H3glfXzekJr&5b31oT^FuEtQ4AH>wA`2=NRIthcU5}LVIHbYc)&osss3fLFf^4~dIc!|2@8Ls>`)zW?r%J=^ zF8wM-O(L}@%WAt%@*0NxuAqC}SVuOidKoo&jffT=zjUgY$PYjXGSvWSGgR+z$heY5 zmp&6Jpgo+hCN&iB*dQl6zwV+Hs?6?J$!7&~rF@$PU%g60>*_{|uRMae56_k!l@^vm z*1Q`pPXjTKutVTL5>Sl?fn&zO{T?4D{g7p8vw4FU=-$)jR@Mo%t`zkO};q& zb^}1kq1Sv4xc1WO|L8~IQL4txi3YiSpVtuZy56tRpN3)bz%l{!hm`&K2>5s0Q>zFq zi@D}E$~?RDdu(y==|B$3uUcDPRyL}TVh}ttVnrJ-_7Bhg6MJ`Qw|qZ|(rOqldDJso z?A0om0F#Fz^-5$C)Bx>a>;WFU6_{I0juTxZ{uSeZHSN*QlX-SK^4Lp#)?Gj@EJpqW zUPJSI7EuSv7E{vhutMDr>r0h)cd{?>yt_-QN6XLaOAGM~A&GaRPQFTipKn|boexi` z5RnnyYl>+>v6)}5=$1_gEnWE2^np$h-f%Hf%Bq|YWXH)%Q77ZGL}IJZgHYAOT$dHX zcVP5!tKQAv{K%J7IQ8rI%88}x7Hd^MTjxOK;1y)+k4M4xt+-68iwfQWf@y7WbxW;= zlx!OoF8hbYuHrOTB{v~KL5Mx0?{Tt@^?r;vWYPMWxABSd zrSJ_lYn&KJ%o6;aa}(n90rcX(wWt6kY|`9p<+Eg8oJ(h_7V~OhQTEw&2Sruh%4Cyc z^hY~3nV0c24@=*}OOQCQsNCsdH!Gkjk{c^hhOj z?rYO#ZiORD_TO_!lROOBSEIgAwy2Lc-ZrkyqE%M7eY-P7c^BN!(D%`kmNi7TXXMD{ zuA|rNy&S!blDz)5!t^ommUg=H^1(J@Ov8wb)pQ}EE%EIBBR6<$bAWa|1Uw+oaLIYO zEF=8PlR6d-)9vgoov(Rr`M(v`NNDI>yIn-$CU4?F*4tgxbX|RYHrmK*P~>+*cW8S^ zHkaO(r(8{*=Cy9W0`6m6f6aYpY!w8yq5QXyAjpw^xQa02L5hL~tF5AfXLg}(b?=~% z`m=neZsOj?eoGBviSe5|?Pq#or&V^|#S219Q*{SY6MA8jpMx&43ah*I>`7V-Jy%Lo zTAv7QEkwx?(Fl@QCX@s4N>+-%fLkw51S$|1r`FMJe5bwCFEmB5KOYG(SusoVrEaa` zBH8fv+iOP}Sz0RQ^A)TP;8GXj9DK+`DnBz5A&z2cx;UEFK})p~>HCG`)^?VvHcl|T zvJiScdJ}vuNpthZxel20`$QeRJ-_xrBS2V8i^S&7R~h15vK6{g1;20KX58#HNn^(< zmbFy;l)Zz;RBiUW$vZ~`?%P|-t^Ja;KA<(qo9$cuXb2Garo?%UG!bM1|K_a-*I^~~ z?el$^H*n>RqQ)?SrWAO^#S5YQK{;SMPanEjcC%LZb2Dw7`ZUH|S%5wUX+5QO>n(XE zYHbIp3d`f1@?WYVM@4n#_{sh=`+d)E+8^f->SEPe5+qRc+ zf*G=YF9et+0OMf|i>lh$o z^t*~SEbB?Xzpya&mPF*rq@OqZNOdCMTLod<_J50X8%qh3@krJ)nE1Mx_Ht0z{S`E* zU*JPfivAr#iM}wu!)&Y!I^`jj`}FT;_v{H`z~U)~zSMrxJ?4HJ`H+Vh2>T>A|W(Q|`0L?LF`T zossVE{;*BVK+mfWgBU0~Lcb*BPA@-h){Ni(+|%h6Qr3Av*~julb=gNT#`u0fa)iLi zUDJ_BTj*8uOou4SY@EKEcjhPhrM*5r>--zB64|9lY|_b)j{3MG;k5Lc&$$0r2BA0T zc_Zoxt>C9))BR>}6>-n>Ot7d+%v4tuo`RzUfLBt>Ww?I<+ZeeU{W>Ne@lC`|6RU)9 zm+d^-5Uox7%`#7iS4iO>9mKp0ZN4T4wN~&<$=sEEsl|d>*;mqo?g-Qy{b_iO=D0fA zUHKDNCv1xuj=uE`{{^35@%e@d5_z-v&1=P0`h@hpdgI#!)0VEwn_1`oRYRDovO6IA zq~W1vHHB)W*U6+sihJ88H6V0&q zxf81OV@`|Q_lzOx3^;P6Z8Sq3l$@;;N8jW*0~QJB7vK zXW4VNCzSUV85pos(U=!p-*?r#tTz8OEPsBW3G}pVF0~RXg)^B?D9?D3or=?257Ao_ z3uY>PS}z&7h1_8FxD&g=@%;>%8A4585Q7W2n_*(l`ECWH3D@s7-(|SQe|LWFrOwyp z)Sz1X0gu4{P5e-+@80}GXnz&pYBC8|seX7Mpf_+TVo%^LinprgeB0k|d&xBIy*TssfqSvDzi%!GD7xBqnE8+ty}?%Pf$r=a{8w0!M)?r$;pql? zn%75**ucc3rlsAkscBVmcBQx14*wv(r|Q$eRnMY^!r(3!;OxVVrw} zyOU|lrmsaom!^dkhc{hNHR%7m)Jy&rh6;?;RKz__M7O$shd=z3}&n{SY*|fxxb|!)lyS ztNd=4_4x^H!A&PjaEP@i}w}a&n9nz-y2I)r8p*Z!r+Z2jCa;AH#NZ6oPw=U5KXum@_qf zb^6WP7;WOw(#e8zj9?(}yoM+*9FhJ5Z<6|Kmcb6erH$w*W^7vHo@z(AfJiKrY#y1N z%_}5y(eVB3W2(3EIawMKR|t?2ls(|tiPyApBtOpF2Uu?iWaP~pUaxs@X4!)I=W`J> zeEj@RayClO%~w4q_M_s<)Z&WLh}DR1DD-+rBLGPrzvV(WN;>Fco$z12d-p!a6Ampv ztEPY#7!&kwSTFSSyxNx{v(tzrxeF;ErmiR1$_8r(@e%;EKzsP{f1`vTcKeFjHIYCL z^#M%1dked|o#1>x+lesT?sJMdK$q|wdT!Z!7XgoO8b0Lv4PY_53kE3;I;^1$#YG1# zux<`M3eQ@ZFHjoO5M7X`9tNe^lGs?9_G3FW0I7iBIe6fJahjkL06 zu?{hvc#+;Iw{C4Zy8yjq8L{?<$mdzp+SkXqfc5N&7vwONIch!^a(4yvasumj=Ag7j zN$iLzK8&&whi#t~s}ELh0SUoG^bk>*JiHLcK)bcOt+IzpdI$1g_BVnJAwKDt5PL1ygrbk`U3!La`&jGg+Uu~ggMkNhwH`qW4T-_Fsh z@gaM$#OdbM)2F%O2w#1_D9A+c^OKmyaLwVcRzNFB7EjQJ*AwZPySAwVbrbYBhuEh? zUEG%P-abC)JF4)3dkH{cz&CC1 zMuP45sM)|_hzByK-!a{tK`(kcd-K8E^72o3R@j?FAMh%9=pylleP8EkMJwg3Q`n_F z&$OE*`yGI`@u6*a>^QoKrtFAraFj3YPFV~8-U6CY+DBX)4XY!R6Z|2ROUw1{5+5toHRwXjCSeCPJr0gO`gEuBT9H|k9<{yzZ3CAaw^v6}kP8YcKA6q>1+i=Wa>SaV$ogIb;(EE=3~O~d2U_&$4N z!Cn6fxV%y)kxsNTIH+W`(&H&sb8rj$kddce<5WoH~ zM18=nZ0Q|ce=xd`$aVvUa8H!kZ3n<&Y~X6GXilT01|xlq}%3iMk* zgiELn{|X_(e|)|uADxvCsT25r^+)#!F(;E?DljYl%f$BF9lS{2acC6*?S#Aj>^8ML zbQe`rtl2;Ix%`U-*m}b&Qrrc;88mNY78X|(2}2wM?M3%?wT~qd)i%Y_nKW0zKvyd$ zD3HZFOW3(O=Q`apv}CSbmRNIoY<;sXiZ2obIW~A0vAe~@#mV`c8nMu=6N^7Q(Jkqp z8c9=*2M^D=sj3p8r-KSjVJ;(LfH2nj!`8B}>3hFOenn*O-Q z{1Q~@)!9YfJUHb}OW7$D@CZs(|A}XgcN%MM-gLp@cDQNA-z|f2o(KtbrtHgr=e*P4 z2WZ2F(x;4--10k4Ucwa`cwH4;D9RK9Icm}MI6jB|A$EF6(Of>08^PgK!fVgNJ0#g@ z`n)VgZX|;m)+>Y{s6czB8eO&<0FOCe=;2gH+#jyMF2}VK4&WQ9z=gwS*IGX+YDt@D zk+?$?8o&@EtIXS!@p`wfzPrp;`rxnP5cV!3{x{Lkw+Ian591kV4glT>%^Ux3I=a4j zVfG}j7s%fSpS6I$Zr;9aPw*lfanPy8+dPyqcSf zOI*4&plo?@X-RB|7h}5@u|A;td^CkrFlg!@KhF6RJKU_*w z(%K>m^StfHl2>JyHh-?WmSQ%y6sJ-Dk@wYz2<_~D=}2Um)v-BX0oXMZcSJ|qF%5@U ziET-ym8(c3H^mZ7K_u?XCs_MQH$Kh94~~{aZ~7gKf4|vx3i^w;HI`)@AAfq;{ns%w z8rC6Y14Dsq9&Mw>UX=d^SJ>?_W)K-Ik&Z_YJJY(pTU3h>97~-WBl1hG0O4N2)rP;h zVv{t=I6BEWa%$>h)M>~vN?S#UT@7HH%0%tgoW`w5!?6vA(2x^Quh&$k6|_{GAH|CV zz>6YX9Ce6rrK|Z6=r1JbAZt8QmDC>biO)#_6=8m>U`$#BzM^d}Hn#+S1o7#73_;hj z#tc{7>9H}_A6dPdsyD5#m$fkP`PD)plK)S_!`tnQiq?>KCtJB*wT74oqPq2JH)UYd z!=?SA%t>72I}sI(c8T#8lO1H*sR_g?TKzL|qBpJHCmK?l%-}aV>#ra$kBBtldc@Q8 zuKdcC33&KmnyN~`Qpd5sDR^7F$OwIeRl#DVfJcHJ!jG3A89*Cl_=++Sd7~Fvz!+!9 zc1ow<(y=gegns=N7$Gz;qQ=&H&tM~2jHrzG7wSv|Wo+9ZqPBi?*KsZj)ByHp9z%0= z*tpQYQ}!*|gmDhM#&?nAr6*q2* z!6Sf^dvuhiWnKNj*PCsP!w0%g+VsD;hX~Vu#1f`VQ(<2@6SIhviy8s-O2sZe+LO$?;z* zY5Xzr;ls7?ffOohs`qQJhuJ{j<0-dr-d(2Brnr{#To~7M1plZ-@}}X}ueI=eCtgz^ zqOXe-==El=fG=_~vn(=vz7h|W(EIIze+Gnv$@6{hW#t09eCnkno>!?Bq=J-u_3|ZQ zm$k1Gv%MD7s>Kz0?NN;A3)9I`7P#u~ij&(Uf@3a^Y6Z%v)h4XZKVzPdX#Qpn(T}9A zjA&Sx$^YqV8K-yxBmiHyyWJ0a3EB`DKJ?~vc$bsU3lh@+zV`4=9Z6)g&K)7t=)_kR zx8E!_a{v7*5J95Z-#^Ilzif$B9hEBl`{z*+(e;L42{XsHLMSY-Xkcsr2mreu^}o|m zv{*ke7hrhds}6UlDP zihIK4*$L72?1ua){|-7zrd$EzDTXcZ3iZY<29ERaMJ$URez!-ZYUC8-s@|6LXjMLc z74tu@51Mh6iTG;*(^g#lCRTzCDG92A{|q$Hs4EC#vQm{E%CHg{cG~DR{~*P5bmqn{Cj4>BMIquq(DG(5L zSuuVxe$n$>F_d+p$GE2+LCq{6L_TWe)4%0;=Qqc7wgP9?85V7Y#^b*n*FM!(jT!?{ zLmXdU2Tlcb24B8G!)Zc>GG|gohTaAj?a$JAP^TycDMDJC6V<3&V$gSSc5(Y}!t3el zL5)SZ#M*F7f+z9xv@&6P9}AxfhB7IrqOqZGJ?ncAbpKG%*-D+uBH?DTQw%)cA^-vibWUO~1k*cnJ5I8e-CLynxI@dlN#6)j9Qh z3p9iIb?Z%V$Nw>ABXEJ=dz>!~T=b;QT~N_8ms%sRx&!yF(Y%qXj9_jPC~~#pkqX=K|2egdqm(m_6?)z_e_z# zh$U4LVx)gLX~JSp_qJR`4Cd_MHwCX4Zf#9ab+1;mP8{G$_^ek{M6Z|3vtCNZkAT=& zSTy&xr4#$zS*o^Fr6%;Xpm*+BKOb+7gNnf%;?}56>d=q){z&R$;+BbEA3wkDV?jv` zcy&-Ih3jcolzelbL=#)!RrYGdZQ4_<$5*5O3L^#n3i)7FWXh4RxphtX+DC*N3;+P8 z!$U|UVn22F?%h1SxEQ20T#||Vl!+7x-1y2V@5P4;Uhe*n4V-@9<-W=9dWDPw(9y7R zj>8jaagQIu^F%vKZI5&$-AtjfsQY#tqG=iQLA%}l@Zm%31RiewpT28?59S`h`$-VO z{*vFfXNw)J9#kMDB17bcDVY%ZYx_EQ|3e5zZIwS-&%3kKR<@=N#_Ka&G88|1Fe^ce zvX&#-v;^JPL%T+$OnSbzGPrx=_A&FR7=|06wKmC!%qDQ($yua}nxS7(7T(Sgwy`rB zD9w5-CO{_oChXHwV60(TLw;^<_v|nfUxPA8N-cweb$V>#*`-XG{N^s9ir)sFj$qzMNLZ6-P-e_|+^@m5vP3T_QkgKdm-QqD zV_qW?4C$D2Xf&IYT9CQ=#fm&|Hrc=qC{6OOQ6lz0sG!vMx~EpOG87K<=2k2>sg;G!e;aS37st0Go> zne1?au?FI^ya6qUkbcEM?jZ9pFaLtHrSNW&{y<5>jb_{~1-DYeb*`jhXGqFzmD_rQ z8SqE)Y7{guu{LKxqxG)C?~n86)S3)l4bUFkKcU0783eXIqI(i^Hu`j+YT5H4uy3gtL#Nl^uwdN^gmM|3iEv8SdWN^J=n#j zMSEcV#Ct`=C!C;K^UiE4E|v8s=cu}P^Vd^9M3pKJ?Y22^`v$pObh-B32l>K}u!3Pli7?IBD+4nFQ7Q|`Qd#q$<2$tt@m054H=FoP zcsxrw*bjVDS@@uM{`4UBj=j0H-vNVumPQ`MX8Xl=gFKcIk(tB{Loft-mT?Eid}}a3^YdBOHJC_@9o`{WN&RL-8l3w7BKAP9_LWRtg=&A z6Nm8=@|E%f?;rlKL-km1tI?oXrsa1*4~oYjdnAs2_Koy*NH$1B*~+g?L&)@pr$8<@ zFlEVDj}lT$sIA(Ic%7*n*_-);EsEc=u+yLF1wM~#f zpd|}(Z8wfS!UY5M3|nXi#;pv|)}OJh^&93kTnFhhSnXloxyzcFgZlZpTShBY8tq{{ z&*~9(n$Nhs=cFbvM^k4DI?3Os+mo0eTSU? zl8%t2A2Qh4L>ICyiHJSO!H*hEZd<$7L~HO3*11u&$fTs04ZHIFq$ZDl)%xRj3bSI3 zKlN(87wJ*=ig<#`2ExLx&$|9?`%epNXC=TNgL$6fiJb&mwlAoEC)eZ2R^Q+FeokurGF7L#)6uyb0Jm}pfXAE^CtY}j|@yq#s zEj+DTJ79#)t%oJTdrk1ct6g6YO?>JaaG<MCzq< zWGD5I07}@Ib&p6C%}uPVEIrpF3o|8dTPCPlLGqq+h<-rP>2@H;Hc?;Q4WeHTM}MNv zUBKN(tgYC*4Vqy~gl*&% zx&9=cb23*11yW5~xAE(-*$ zHQjZye9vIgYe(yFt-%8Y6q*;YGAB`qqpQSJ1zy2lNgQ9i1fs&FcXtG;9b&XK)?kt! z&h@xn5PsfsTqxVHJ&*I1rtfUm&QCFNz3md%1~w=v>VHN-I zH2}OsZoQN!p}Gdj_?UarN5A>HiVHPfQ%}+>#w_37~)S0e4sY zd(CCj9*ZRE7(%PbqWD44b59^|tgF(0WenWoMrQM(cCSF>`xW3jfxdZf9#C)6^CmKp zCl4A8d3}1DSYz7#r3tPKR*90qeWI%^uR)xS9DzG(#jbJ>N9oaxo6Q!L#nT&IuzCe! z)cVA{zE85YFDb*lvw5N{51h<$GjVzkfz4nT5fiB=K1y9g>+7@r>EY(5jPzGXQ_EjJnAqs)b$1G1E{&&B&*Yd(Jm$*jbe8J1 z-h$@C`mN`4a~bW_$}&d~hUOCfw5s#wf|X@!4IFJ*?%J8$2YTQ$O0THHrMdXZ`aLky z#dNE;TzBj07zg&G65YQf)^*72PYB;@OF>P4p5x$%*0_*n!l-0R(`x#?pAqQ=uU1!2 z^_fm4n6n$@##|LGmZ48dP^IChBCV@>x8Np_P&~p@D;FgrXJpOJeM3~#{7avqc}7}I z55q3-@y? zTiSkpHa`24fg<9RZCPooozW+)ou88VRU{Yo71>t3zTK{s&${E5;lA6!BYBLwu6%** z%HN^JA@@W)_keYx@JjueM5>dw;-;BrFO~@E`CntDI9Ln5N{*QzxTI`W$dtmvk^@hs zcNY8fE*jb0n@>gudj03l4y|;Z-*@LA*V-a|x-{j*yNEe%wrOem2PMaK&m8jIfoRP$ zfs-dODwJm$1jhYv?7DH|y$hYzGCi6Y+5l;trz0VAZR_l=etg>TQ1L<8Y8@h->h68B zSUni_)VI3DWirCOV{rL$nfa?9$2EjZPh2|~Ua}gwu0CML>SMR#Q<7K8iOgZfk=IL8 z_tv;N?Y(;Z)ei;vE7`9+S9)s~p1Yj!U3A-Y>|L#6&LO_j6SOy% zW7y5XWFhIn9S%PyKJK3r`ZRE<^V*M-KR?}BpxNMD)2SA#eChhcLNT>K?A_yvpW-w_ zJ}r$qxP?w2DQrR7vOM@kVM)Qe?l1D_h{EAQLIN9Xe z+gUHB>%S-QsKAs~Q}o+=Z|L>C0xT}(@gm`io?0u-Op1dC9G)Q&tL8)ORC@ljz(PxL z+*j7RK;`?=6{X2$1DAf2R-mzH|0@0JhnK;a*$%t9Da&|Q>r;0=4IE6;SKYagF&C^m zO64ko{y8;y^1;2`r&iI+#ZUr9fseXs4BfGa$-jLQ+8d_ z$@<8XcS5hnQ|@~BG@|8FU|z<26P<`{V%h4AW$Gdg^Q}-}`fr)bw=vMVRLPouYI#ap z;i`@@n55Z5Y&uD2sX1;5F_sCsmZx_ZG{qzub`|^92%)_Udr+@S*KY}pooAjWu z#w+m8-VJ7lS*I$phpkV|H%Mp0od5a~q$p1A^(422lH-=vRWld8Zr#w_oBF}zs^zs* zUdyoS!`_n5&bc1VS$Z39{8GmGa0CPWoY3xmic?4BsKS3Q`K~9CTnc1Ny(7-)_=a1=*KV8y`)n{1DQ7mX}Jz8%1ZPoUk!SZ^Dbe&Iq zy&Ir4oj)&h`1kws{?A2ZRwk;BRo>i)Ec^p}MTQG6eJ+dS*`2a=nD!gK~WJ@ zBuu0P1wk5=5CtUP7nBrH2_=-2HV{PxgHV)~77(S8P$Ucxq#Gq9C8Q+JHFd4M_pkQY z`#aw^&N*Wo#`! zF?zs}&#HTQX{P99+at&puKV~DjF+*YVQNAK-EKj{!wd=Q^ez`dfFxygc=~(6j4=lb zk8zFhz`ordcHTt>lE!1Y*?d~s>4BZNo7?rZOmYg2 z@AjoqK56mut78#gt$X&8mFMeUlEh{d+S&;px1u>UCb?I4P7?;jX+Gf3gZ(Rj%6dimCgb zuhDV36ua208FCvp2oAa2&jGzfvigU;g|qT>D}dFYW1921b>`;@Y-PawbQ-GTHMYtO zKJc6yi1#}W$TT%1wQ$ag&F6H>BZg&vm%SM;HR{cica^%GQpFYCiV^BkDT`WTU!?Be z2=P1&+r~WBq)H%9ltv>UIyYM1arW!HUC-Nd7g$y-O)|e4Tzjv8nTF&|y@8qe^j@t` z@9s|1e4Kf6$wgv}o5qF4WmG><&jINl+iM>dqlhp7hKT4HVUFyfS!t+;7))lDd)_d7 z8&`Hdq_J-gLPJ9X1D~qv*iwes!P>XT zTwNAGe3bLEgT-1CvRxIYp$A7R_!w9p?AoIo&U6*qsToNmZ#gkHseO*tl7n?5B{q8T z)q=%733e~sizZLvULhA_u%kd~fEI7!tu|b(?zBtX7lAc)bxY#PaTjt(@$Y8#i+iiS zW@X23c)6-<7%tuRniC3<6aM}ooq^|`#>U3FZZee|JT3R$q?TSKV7aXiBCo%6;J&E3q5|kht}Ku z`WI5;&aU78lB!%xd@2&jFyOzuP{GL+q_IYTvup4gCPx(&uTinz#BVJquULz}A-*ys z;n!dN*Iw;^@nh|6BHqJ$#Z$Ps;^T*ecJ3^Rd`^Q{e>%D$p@NMm^I zB*PnRp1N*cu=R_W?B(g(=Y93}#o`fB+2GLgOp$Q()?DY6#+F*M#AE+O_>tP=gU@Sk z{1ERty;_(auNqn1#IHjy(>@j}Q?s<$(EG!UF1z2ifZmtm>vnutiGk~}i>9Y5_cU*1 z?Na;m&y-zV^Tt;fm_G46C-mZNkd&S9QY~@6dDxxK*AyS*cFLEuPoob*8CLbyOCNtg z@+k>t?CO-!Ib~*syR*?%ij-13t;l zpNDATfXxkmf5h$Pc)G#S zeFT^z1RxI{JOF&miTK@(8yk=ZvZDAZKF&lLQn|q%5l&n{0|+%nIUKe-glWSD6pi_4 zRU#uJkvWl&{64^~F0o8M_hM{V1GF=GMc6+tiZi}yICkWS1*CXXq+%f=c}w&eusNeb z_uQ8EPelCjc9&c(zbjQ#R*t}Y6?A4ex{e$@`mU~}uU3|vpm}ICfnYhYi;OnEPby_-^k zEc<|G#UFd@)MkdxW3*tVBRQ=wv}C+E<16F>#{{k0^C(~ZsYu(rptO1kbPGIyx`u`c zJeAW7%1TNyGi~el!WbIUC|G9S=r!HQ6F?bi}(8L=L+O{kE#Yx)&rod%nJ8SA3 z9mk5$OV&Lm>N~Q0iKx~i66sl?FDq?$v1u1*{r$BIATy?i8b7Hg`wcd~jCT!&WZQaa z@A6z@k=pmf+d87n_^lPBgT^}jMVRVPx(?hP+L|y~4_92Yy;);O3JUjHx+E}-V+f~U zZ6Cwlg30^F#7z%F-Q~j+S`4|i|q^2Gae6jjAmD~pLE11?pVc}Oz2>+ z(^i;udd!5mD!ICX)lIn0qo2{QXW}7>sSPlqy)7+80F=`98>6Lpe9y@-37_5?m^1G+ zUbrLHfmFXpk0e)u6V#7`nx3zYte$Dzs#{u#rQ@|Qu1vE5g>%J4bBt$8Rb~-GZPA`> z8$rLxQ4Hv$El#Ki_lb94EXWTmi5Q`VQ?9qbToP~o!C54{R-ta-X@Pdlbl26jvUoyl z3#N2WpMGjQSRGZeVy$#FpjX_J4#+Nj7+av`jEh53lYf_-up%}OOGM;46{L- z$4tAv+Q{ew4cTU}z_@WTi<7mutiW&UXoHm7oLa3_c6`t2X6)WX!_%S;7EL6j9Bc!R z4DX2-Pg@KtwXSI)>Zz2zV*}4=yaQ6UwHPnrS=r*1cqn`8p<0z4sX1TiJN2^9H%GT? zZoRqahe*h0P4agBc39=@Bvz=TIV>`OTFl3^CFJ;A$Km+jH0UO3l%Yu3ynt3 zk5tFrZqNY7YEZCELuM-Qls_8J*E98y$axrb_{qm!kzY5ZM%bY=u-~{!ndGO~Y<_H0 zfwU0{H_w{w?cS{yXz55jF@Oa55A6$=4GxfGe6c}Qbkm{Ey1Xg}*6)J-MT^r0ty#uA?IrW%HIF!hgqze%K~uo^uB{OF%oLBB zWQ*S8gy$ta;V+m(`$K2ZS{LlE&k;i~gS7NQ#PY&7I786o2w{OkIDpPxi<_ALh<&xs zt;Wx*ZsX7$=7xlqhgRKk_C(-x+|cQuHx{-d7KVkThj&|**SBLz$@|eMmdmLBV z-*KT4xS%zORG|R~yU`3*ySj{K2}p#G=Q$+4xT9pQyLEg|Jx$FyH!t`;K>*_6z=9oJ%s}u=Z?<7NX^4W)OVzDN=9)~ z7bF_RfnR{kdU+r|;=uW)yWBJR^>j5cqslqcE$1@1tr{q{{g&F=pP{a=FS^d^X;fOiF;(3#tHeNEyT4S9ePur%^E~qO9|5!GQ^K68oJE0|Se} zrj7g^sZ1;s{exlZQ1hbOFGGL!J^vxcAu~Ku5MB$18#Bv58&+4C^i_eSsdIVBd7kV+ z1fG95Tb?18^(@z}FsynI6~S8eFJp4T}fML{4|@R_Q>O5-9~hjZ9;$xZSokgH5pT+(D@?;@W_?Yok) za&mwo$M!*s6VUl#5J`Js?AqkQJ0L9kRcpihZ+%Wq(tw8o^7yn-VniDV8>1JeZ@LP< z>UOr!Ag_|1tX3d)qv?^t`S1I^rG)U{&b|w;ll%opBH>SKy&2v2_uB66uQ<*u!mh{n zT(}@X;kUTHYktx}q9&d{k*)M3Noa(~zIqjZ_DJw(6Y4yV&tTpLIKVb8)+ldHjCk*o z6pcNue??MJ1&MT58SH($lky{5{$G0%&y0gSFgTq8S za10-?l?CA-PTiJNBRZm1u9Ks>yNT?DJ9j7=-lJ;0f4E9zerUM}W1qLq zfVhd!HO67c&e-0(v`O&+4H*r=caelrJu@U)9oH4V3-ElsZ zIPk@AShH=gNJo&YG>X9_^5lK1KnQr6fAVP#yRhQi_xMpMCW_k2#KpIG7DXYHC^4V8 zYg743#W55HSfWLQRXecQ<3hf1qlNP}N}F3)N5f5qIqG#L-*HDYjUOUM6wH3T1&G~nw|<)DR}yHm)nbk(S^y$ z$=?!-hU`r|qN1X*vP&;M2=4dPS~RykWgfxztj2)I{D176ac)3omXRFC#0R7x|4V1k zN0N8ZGk1FN3BOLN@(4C6I`&&C%p}2jA5+Bxs!I_CNBOn{f?PgSnG1wv|Cu%KcQ2@m z-Tvl!(l#$0(;u)NOK12V@9C^b4YJ(qBoM=ORE$K*J=5yHhi*{Np{gxeUfF&vx7l4S zQt`45L}y;h^PSo4PLHWbk&!$?*)vX+eT;EFr8E97$1Zkh(2wotB9Rv4P=t$+NX&cO zBoC^n_^nv`I5${M^~q~0?(Xaj=z_=Q6o#L`0e<+B$B2D z*z%-uT$*mAkhA)?Z2k6JZclOgjZWfEnM0Ai3c^j`Gy=g;EK z-KQpFzRWR;v;XSuz27iz*^;EWlb83V-Rtzp{a?Q_i*Nm(0R*=O+8Pw}on+#T{MRut zMVG@)w3$>PlNv>Im?Y9aYybZj8}`592*%H;NVDhA&jCT{N<)tB8xlq{Q<0WpE)z%v z`xVt+pX=X6CH{?%rF~Xx?k_9=-*wY@;wu+ZX+x}9TRZje-aS*zCIq0t7B;n+iRlzc zY+D!c8=4i&R=WT-ir+jH7Z}KV44F;7a0CqR^L{xl^{dg}$F+Mm?zQEPrky-IJlnPv zGmCS4Iwz(rvwBIaRAcTUv;F4c*S|p*<}IGm3WNzo8tT62@`dy{}IkNR~ zu3AkYumL#H5bpNc8I4*Y)E-AVZ(c#w{sQV<_&eq1OOcS84PG%+71KiY7nhqycwnNW zJewH$aHt~Miq;>@JVk7tOUyZn#8>u?seC9@BHQ88eW&aw#Co<{iHc|9QNe+yP?Vxi z1g3$~BH;Gz)eH>hV9BEDI)smNiGXrprLu)r51KJB`J=CXs6S8z_=gP~V^Yik>cE{* zN9iq>86=yfAneN7UnLcv`b7Rr#m<1!xhg6u@1;gx)uR35PtDm;tBP}dalUie69ozz z;JA0l%Z<8DM8iX)s%P-%K^c&zoon~*%Y6tXG2VrO#3x8Ztkm|mJ90%#BYTG4Rrwft zK;#U#0hP&JBTnDNYlHLn*?(E$QU2z)Cz1}ME~{(HWYD@qX8cca1T zVe~2nIHuw`P~JTbOLQi$AkJ(wpZ#D8i=K}o<);>ju0;H;{kzHUoBXdOeGkR~wT4~X z4ujD6Rxz(?{%Q3cHze&5+KZ?{Ru6$kx@zj`x*QW|CXJt+Bs~fEUqlu5)_z1qPD?|> z3W!oEY8m!>76k~k5hm#f=a*HD;6K9;&Y*w`>f@gj3lGjlBq45PqZyj_W8ZoAHUTmq zXo>m{LHzNRxXg_%u6ycaB5C!bKCTWZ=XCp+AN=_ayj=Crx}l>f+uO2)f1Aw2{gpa! zAPaR-VH%$mQiL6}weJ^l$q>%u!NGpKlAYc2H;`XCwc&~pUETuW+MjsO-| zVJfmGAu@VH`c6DsmxjR~=%gLdfCTc7`gN%476+5lFc@hc{w}1In4rV6a=hTU9!;EfJ4p0_mfhA zz;;f{Zf5>V6p6O;h)bPb*>kMZBEaJV#p#gM@^ zxHH{E3p^)_0WqxtPo9d{_uOyc#N+*g;@AIJi_>8wvvJF(qgy-Oe^i2fMFp1hyo{7u z%Ed>zTh45nFfAPZ{NT;&d72p9nvWbyY+BQU_2x3 zg-)nu4fw57qkc)j#weCcdEizV=qxJAa~*b{TF+}-6R$ZHbLt4!JyakE)i50d79L5E z=`$(W9Z3>^I0~EI5O5GQPJuQ}@zaKDx#mHl0mVwwSD2Cnv~@(_+3vdI5fc!CP&tYMc*Ib~6opoIsA@;_k%g6<|khE6+b zkDNd7Qd9ZCf!H;CtdGQO!)NxKpq%wnXMWxEroY{}(*w2eoo|yTWw1R{f~w;qJO?`y zUy(>X!Txz8O{`#=i=6wiJ3Y^}HZa7xxkMzz*2ZYlKITORuM;}Kw1Vl-7qm1pk}Ydj zuO>H{Ueq{obBn_RrcvSc?lI9`4&p3$%+x9MG@(`b@{R1)a<@}ATqD5#E!AqsCGJncv5Yy_ z=^?BuNO#jvWH%{I zXLq;`!D^1VFS5{bIkFjwA2C;l_x+uV;G=OyJt7el3V+^hnmjSaeup`MnQKN|8{xi- z#F+D)g+?O-V2vkwJhSJvxlS(rG3Zwv&Qq&Z5EXy)=+VJE&1FC9?+8Y*omXPMbbG5@ zA=L2GS5D9zM0gaUMV?A(8M}P(QOmwcWq6I?n=&A!gohBbzuGo#1~uk4Mt05@(S+*k5<;-koIfftCj(;maSQ@t_Nqe}3{Jr%#P`niNo+#KCq=1nGao zy>DeWAdvYG=ST!n^Ma|A@i&65ug0JSj@7Vy0@MuO_%daX!?{feHWnWaF6lbf$QX~- z;kiRXep?)*NWQUU`fGsT3Hc=I@VLH-d~mZ=%vA}6>(X{LtEfC7?3E2;VFZE zXeoa{(l}_8k!b;sCe-c;3i2kQ(~2g6#uSfe#@le`56uI-F$2c`ht6_$KJYeWlV-1w6>C%F+sIbS6;nh@j;UfXSIFxF`V&qX$W2Ts+p z4faj(Fk#ljcx4L{!TL;IQ!=wvWdF!)o&0A4$t4GUUL#^~X1JL!1(Mc|-nVL);)PGf zV&Mh$;@(X-x4+4Uk2 z0}SQ2fA|DvM}3fULhIqJ+cC13^qsj&#*E%>8^?f>qT=S_MA%+JO#C9(bu2(YenvC91Kkbot?p{$=W zAs7D{x4UrmE5qm!b}$d^0Bp!}v)|*H=qWBviH82K&mgH?H&lx-?eMk<|1&|yoNl$ z@p*SizSmjo;;^k(m5SR^%w|3NjY*GgVlDb}Fwm)yP0?VtBqY)fsV42NDD2Qq3<(T8 zt+8<`EFwJI6NMT$qPc16*toc|^78o$wYt_Sl#tP*DUYVNBM!ATneXPL@lu!u1Lg?D~vZ^3H!3Wnh;4tAjEQ7{Fi`iFz5;+oFtrZ`-?N@R|PBwilPuj!{4H z{zaG`j7nc2Nwk6Gf0F)mF}B5D{>P?Wp4Fb5dstt8%QqXt+nyqZ5!AlFId;v5u$8e8 z4dr@4@dlrn06O*?om#&>?ng|2xqtuuy?ar&6#{5|1kgxg#B&B!c9$3ne!+Vu%KrXz z6t1+Sivj0;lkNW|hyQPM%l~K5fdBpSgn#d=#eOG2GO>goCfeZ&KqS z2n4W$VWilpu|a<(RUQ7-PLpT^kWR3DJJB|lC0>yhA*|8BlYyH-(aKi*dh^v^vJQGO z5)Itl7tVwjoi&WcdtTtAwcGdSTZ#isB3ufmPZ}yoJ!?Pkmtx`IYc#^Vl%&85QFt+= zWqc;7EB*Pl+&HGhn}V)xM@t2{32SlUZObZE;L9>E9VEg?C%RAeOMDw)O7HZHJ*q^RczC7Rz}qxd{j-X zZW0OuCMKqf6UMkPp5;5x+t!AkF1kHE2yO|rVZJjWaLh4cgm9~-Bx|%JXzlcn{PpgH zoG`)aHK{@f7dmHGqp_PcTDrUw!?gejn)j5rO!9c27ziu6-VyA%h#pt>>F6x0i@Yn!QfHBvTXw&=$ z?-Q(HY-|CJZ=8x+1w^#XPgF=kde2sVIz5w z2tVDlHh%?L>zMn@mFTcAgQXiqMt3_@l*;h5EdX131zfttyt77u`I5z2esaReh@^}b z#3FR?W3=T=2^7RZ`Zd_x-D7C;a8a^izM@d0NSJ;@K`bXOJ{#uTp=JIK6PW6Del_9( za1QRX_6ZjHSw!<=YpMTm-;$8MW5s_N(WNrX!U(P z!waRTmZ1r(Nz~!4d^HgFxQ->pe^Wuyg1kmhl!YgjV`~0)Nr8d(Bl`NGoNHkNKoSS2 zdS0IK!qaps(=S}#h_RFYx^LqFUJDAM-ZLUMiJk!4{01dx@yfDQ4$nBXsZqeSXH97OWqX?jS9NtS3jzxC`N6r zLn&zEi3}0z?DhuWPT$LHv<7P0cO=*s9T6)R0^kNi9 za+Rp7Gl`Pc85d%i-YdS!b`T0@e{0jAO?|PHMGyWR{_Wc#Qdvc0S0OXdgO`Wr$iQu< z<1%t8GLt8UA(uLfqvE~n?Qc6m@TmNHYL|XQEcd6Q8S9WhZ=l8hjCK)1mg5AvLP@UU z5C&7Qvt=NS4D5cZTiT)o42L#b|n9)O-o zm2Q|GB>!yfT#6f32-}KOlEQ*M5$-J_7LgPLx|+X%DD*BJJeL?o^%MI(2HTfZCE{p2 zc`{PcVE6{xqv(|;#G0;0mUhwPXeYs*6HPd{#)O}E{Cuv^c5(rl)WbdxWtR5(5(1>r zBP8_(ZFR|dpTZ4YYmbR>?b?Ou&eoW{&~h2bBR~DP&7ti#_~Owel(`%xY032Dd$35V zP+;S>-K&>d4IM+>C!JUo7UJl6jf1Yvolq*j-}`Dmh5OfI4T#@iZqibT6EGGObK}O* z(K}G_^aG93o*swReMrdHHvUa9$!iDIT!1MlUOU@~@zaYHh5`~25}+d7itgitNmk2k zI?{)|zg86y3LQRETA*vV}|-Hajn8xTA|zz^x-dc@J~GE>P@Ek%z7Z+Q6dyHazA+_Z_imNLxIZFh8PN z5htyPjto220xTLDOYLL8vO?$B{ZaZTqZFrqcqJesBLii@*`I@e!wJ3H`KrSpH!x zt%6QFFBNb9t7g>4>4}I7KsV32wuy`9pn-6;da?`ASE%?v#tI6iLT~nz%}(~O+I3pm zAH^p&Lx}PuaTCRlfehSNqKkM3UqX;c{QTdRGXHxY>tE^*{*~|dUtfqIMe##-C*W=D?PplbWG``oURa1SkX*Dk+DsG>yfJ$b?o>i2mGsj6(0 z2e07$CJ?s_{RsP>zeva)UY|eah7&ozp7?+ zch5O{Xqab;|B-}b_dKIg7{^vPDd@Vl`@G@dm4EfI;=}9K`m-=GY43xIdFJAhT{z?N zy)S$He|O7Yj%a9zG3t(mn29e_ud}gR!QD;GM|@SEk}qbrXlXY(c-g%!GP99bP`+Ly z{(I?biVOBScw^b2cAi)7$$gb)?l-*;jS;u%+>HO*eAU7i->n!w(=Vkp_IHMI`+O|zd9{!z*jMK30zK+5iRpGoCb%HLUPlbyk zsDF#t?K0rgXf22Bjg|Y+Uy|lyvM&)x12zsn5)zjH_Ms0kH8sUyAw-fEM~n7L$V|vF zZep9lSt6o0#3^of5)DqFeO-t!lpPPukTAn3X7hxK)TO~KDLDse9gc;zbTef}+b>%C zR+tjWmY`x$#X`S)2?rnVT@M5m$b;a(&?fBMX%2+Udw0lYE@rP&Sax^CfL5hrigouu z**oh7f`g0joO_qurCA`1;bBi~O_7cX*+}Kt%Q%>b?E|fB_K70T0{xYQkj+ALGn)S ze@^&>V0__6b_m43IQBv+-=H3;iOSy{c)c!(at>Ec^66fnRz$<86Cl~rNdzNuNDV&^ z1)IEfm4k5a<-f3iRlFG4_O1YpIs!Ma5erL8zruV&B24iIssjvq=>d&Bjf9N`Hr``n zM&|&EBC$0OO%W$-aow9negNvm*tGifD5hI6fT>fDC6lL9tNfP#k9h?Bx6@lV}8uM(XK~4PHcq`6U5)uD_0=k^$#)eY%XeHBzZ5yos_2=p%?!x z8+Agl7vYTURx{Pn?f032i)jON>yhqpcS=c5Zh>$PSTJ zI{pDgP(~PvY76}oVloy^Eytg|A*1d2jV_1Z6H$JjA7BT#r1wa|KCXqJPm`4nEa~Sv zr7Zpts>^f%#p-Nf9)JN4IdIxfrWG|X)b80f1tDcZ9h~(K>R_!i(cuB-(h3?}B;}b` zqjS_X3CoTqwcYqdJ@dZNycx5qlwC!n&Ic1FJJGpf{B;)E&-a^B3288+L|dq23^_G% zv={xMp7UK@y&hBPt2PjnO@hDri9(I?EaBse59frqHu1fzTN|@QwfC0aLu@BQu_4B; zmIM`^B@*>sdH4;pwU1tAT7lBA;@gO19w3b++M; zXwaTuu00o*65Y@DqIK)e?Rc%Qm$e97AZ7ja37TGNkTJ=9z&Z>9-s?=xLbnfd-w-TO zNJ2_9T0$oPweR@H{huEGrS_diS?)5J7|(1^sQe4lFtF}i+WEZg0HO5$hz`FG_259F z{8lNG&iFi2{D0g4Nzf_6Hl-XleM*-6Qw**gX`< zzvtX>Ntxy0i~Hc;P{dZc*oeo+A+$2t%zRzdg;$jiv3PmDj? zSjam@-4B8IFS$W0pc1X_Pn5r#Nu(#rBXzit^$woHrgS|Bh5K0={Ap|qGH7nAoste> z;o~WQ6;jI5Q9@(dQ(Y}`+Fk;v=;;h8(+!^{-IJknOu=%U-4>v#M6D9XH=~=&y5=bykw;xW7*M*Xz;0GX_ z{m9#;@cD6LRNIiz;mj5sRKt^?V3IqM0Dvdi@M}Lk5@)2{>HpJq{aMT+s7Gld?Kg1e z8}+);gmqB4c0hsQUjhec5<`fde!BChv8|g`+D2aFLfF~aL90jzJVHbDkr_Hgg^u$i z_CX+yxr9{rp`2GCfn!89G*s2l5}gek{-V__1?AFZm~RSNZ**S-5UhGx^c!9{w6M=a zq64=x? z8N0kTh#;jZV9j`H@2&ouQny|N>(4Ci3~0I}+YIkhcvSg5J{0Q4gEeEMMib15X+XU) zTDrAa8-TS8*%a4>b+0j$~yT6VE^hX?+xEL+j}i32-pEC&y{eUOyJ1jSLJ&-JT^+t zjH4oWfI{I;x=6_5jYAM8ogj<|?!1|{yQusKk^Obd-Q6N|>e`%v$V(i-02y>IM|ZFZ z5TQw}KJXTk$%!@yflIcfj^;DReRHLpIfZti&f}>J(AbYsoG1)@wXR~yQ1Zt&&T)*5 z^{kP7+H^muILqt{u7_#PrLCAnmDQSFP@g4>t;DGm8kO#w62m&JF()<5D^jqW5(kii zTrjFuN>9HR9Ns+q1{M+ZS%WDs2i0Pf@96gvKtA{Ya91gJzdwzLq&bV<^jqB$k?2|W zW6kDIiIG^_FR$K9)=(URxmw@L8MFY*oY-LEK8fG|ahmxT9zF*3U3n`b@Qp473= zTZ*P#B{qh>|+uyRLA&BXM&&4u33p{1e1t5Q)YXSNcpyHX1{tArka^Mlt}< z=?!JWlw43sam^RTADAs4WdpDtm$d1%RFipXg4i2F;UK#AQi89vDJ)7T1I1d#KK%!| zZMqWf-NlRR(}Kyz?pDU8(C-d(0F_%NrA(#l;4ldQ_F->cl2PEf{`UQq(jIdeGVOKF zg&bxd4U#RDD4uQGHj*@NuzNmw3T16<#RCkqS#MXIPIQfeLAIP1ZmRO#&uJ1qQH6Al z3P?>JbqIZOKl5G~xUD6GW@M{b_wstDEuG^<48t6EUj7u@!>_pyEpKrRu(Q5}aF|UO z;1KTV@m81*u1ul)7{G6_jBTRsp$Bp=9?J2a8J1fv-w4LL_wQ>Lm;b2RdeD16+>;AV zL_5vH9wN(VQK*8(2t73oSAB{2;}Wmav$y`F(Ja_y+Z-Xa;#~*YgJ#;;)9n03arSWl zQzUQs4VyP_W@jI6+P~>@Z7ml56`3nnu1vUp)au;=WrmG}^VK1pznL+0puBjof;*z9 z%a63fWWfAwDX*QZr!vu)F$=r-DMA~Fwk&$(w@!hnv~B;7lXCyBXp(7&>rArq2AefG z=^z7&Vl#7=x3@Qfuw|}aySBM_&2R97S=eU_G#<3-(GPi1&}@K!Gb$>IUTSsM`33)9 zw^tFW>@>{iV?HiGw!Us*+)y5x8>j?Q$vETlafvve*@St`L*B10#eh1W+ zo`+n%QMi&uM!oQWvK+6++9%~yzm(kgWIknI^x}HX<$X~djh+#%D*KP(*{l#o1+{pFMeKhHle> zRA2C~rAY7%_{rVK#)kU#guUf|)4yt(=&1)!j&iU_!u`iuWKn9^UR?TxyS;0#KMGMS z)`faZ-x;l-8H`TDkO}x*G!g&beFXmguh{XB`uGh>(X%g`phBZy=Y*lJzNZNN7KoOw zXcf~CJnh^EoOK;1XXEF>G9P|`N}I>aA7b`xIkD}XTAi} z9fzD}ThBcVOdXn)sQri?9Gm4;Y_LMPQJG+(QjO;jGqt(=INHpa8ZBhceew8cJKeI5 zYfFI4^h3`VC{u3UzP*4(YPI(=1X13vqU7z+OocY(T<8X$VP6;>ybP^^`!_X2U59BE z+7slQW$o@x37n-LGFFp{-yzpvaE?<_WTZVmyAPJSX6MU$_BK?!`-t`pM-jBKKpAVU z-w$LMy>xGpvfb(f9Q5EST)!N0Grc3oij-7vl;}u^alF3SV>}Oy7U2bfj~cZEg3c!1 zzE#xOHjn1p2f7<&Ma2vxTt(OJd3{&pcejjh)M&2{bkko}cIqqn4YjP9SO{>Lz-T zqdy2f^i0OFlmu%6EAMdPet_;BlMQ=tpR1|$KU7I$0b_;5vSg~lzf~!6`s%b3CfGta zba#i_gS8N2r|rDtp)~ggKE?-6Q;%ez*h^?8eAlqW*(%J(^(*H)&yJbq7hhYoAx=Ha zDjtVqN(k_H+lA=SB#1%$k~0WXG~rVw@?KF!5jSFbcwn*lQe}i(5qgjimt4QtwB9#| zj!s?J4N%3ds~Bro10BWVR|&<{2It}mp8(13!?d7ZdSaNghS8*2CNmV@!Q=berCiI( z+MG-z^B<`I*=H4zY?rn47v`6YrXSQX0_nl>%3oYfM? zn8I?Yzf1SrrGTFW%pv{WhQ~gl8?ux(w{Q9>+20P2zSH5yp-B4BkX!6AQY!z^QUDz* z|D|^UT1t~)NFJpaphzO{kHAs$mqa?QLx1Y3*zJ%g625810adWA5=5&M<3G)^eSklc z^^R;>XxFgsmfX!;I*3OjH!&j)9?|h00#1dC%`)@DFX6Gu>NsL~WmJDoWvV;>?-0jJ z&y7|yQ?&ti?pU|wq>m=gjc6Czk98dyd3c2{mOSW?zE#(>9KBWt8hpSTdYxCPg*$6a zMU?sZK5MT$OWd!`rzN8jgOc`br(q6xtE=3CUT-HT@yjBVNV?c z6>mL>Z1f)lr}jr%cx`;q&$$Pwa#NwHCPho=+?hqB@jh06pgfObZ*vYjmMMzJ53Bpk z6hpU>OoU{cJU@B)6f;NRASH7z7%<(Er*ZF{xiMjd1r897mp5;Qw*;OB`|f&9^f0&) z*LUHUPf7dM(pxwj=>&uV{^g;2~rJ1)=*Zv1-i3-O7rF0 zusAp1T;ifWr@7Ao=bwk8%DvTH`tU)KE~%}*uEO5U8h?yXRoC@mbo!s7YE_!=qK$?> z8VqcIrbgdabxbO_{DeLZL{!peqXO5=@jCV-)$^aD-Ydio61*tEH)oqOCP(v`6uwI0 za;!}JO76`7BDY=PI?sgW^JwJxTT>OUs(Xi&9XE~{K%q4YGkh#=VHM!a^IZG)z6wuL z(o~4NN%)apzXlgHqNDVMUN&zjjD`$uEz|f zll7LJzogkc%9VB5DTj3yspdEX&n0YcP`u(R_Uv5>d;@%MGz%j~2XPhZpWs0r(z@iw z$wDq5_U4E%9y4vWl$++^m&y#UaEH6d7qQqPQG+1-9`3C5Hbjbj3;$!A8+OP>}XV#NI{}x zVx5*5o}wfG#VTC4zlAb#L_&ugLP)I{Tkd?jn+cMsgKNsy$Sa#$?O~+c0Ib-p+!5}O zTYe=x2)B5Ld0BKZy@Ii`-S}x2+a+QYc&#Rb)%DxvhTP*-PoSp-io#L}{8lwTN}O=` zNGj?Xm~F~|g7qxw1X#33pGZH=`WXIk0%ee!dD0q+!lT{^R?d$2>6Q)FZ+8phNNWan z3_=t^BAM&CL@|k;UP|pdFC#IgP9$n;^e^5G&p?SmhyKdH-XY_axuWOZwVdN8$G z%}23A!m~C&77#E_=fOkiMM}Da$=iQTslpuXFvoE;6@ppFodj!*$|rX)DH+Qji2QHB z=#_cT*-O#a{sAuXll}!4A>eVa1zo(G&f2NniFSlEYf!&*1K$U7bn~G%ufl9kyl`fJ z0tygYsLi(oV<8fWyT)V|k8KJRv^anV_cyY0Bp$G+E_MmMk3N)`vI5DDWS#p*Gwgiu zm+?n_cjnM@Gy4u2;U{CXY1)aLyJ5EZ-|Hn^Gb2Y|WsY-R(v!G- zUH`>anbH4cYFvGgFL5lA!a!#fSjE2PxEq&%_ zCq-NO%Z&xJkvxw2zm#=Omu0els6Hf-bP9OX9IYVx)BW6p=3Lo><^9cJc5BUnPk`U? zPv88@+O>63AI0$e5X@>3B{Z9zvrn^wPE|l6EyaQp<`~P9S0#|l}p@Yfuxg;E83!!KBd9g$%<2V zHfs9J0d|_7o_0ypQ+AAJx&y$w^@UoyPO|jy6tC{I_>+4V`m48#u9JMvfq1}B7LLna$Uu{9n37>td!X-SVlhCAW~%7++14X*0^DD^z8v$wIaJ~jqHB@{te2twmvWJ zLyj=0JX)};+(q(0-8o^?H!H1|!C!<{Cj;(_aXmIEW05^&-#B`6_vCm%w==Mb!&1xD z3Tt_V#+S6IYzViL=ZoINf*);!0^O$NPX)TKm)<*3_zD>|X+DX1rpW3$lVNa-a1pf2 zPFr=HxA?#pKWy}!Y?eq%8Hl+*iSykP97bKcIX0xqnTz+)E)81La>f=xu>}~6$oqhv zKoS-@l)?j0>3B`N<92-3fgF6C38(Ru;f$ym1mQOd<%@quzQe!-(0vp8N>TU-{o5n^ z61MlZ<-YWH^XTjaT~oi^2E_<;pn$*>tg&ujoIwHQ4*3B@>O)2@udmRQ+20cE^Z*;O z!mM;9;lVzBya^Yu6EQ0stN3Na!aufq@^EPJ$7o53!#MfC*}*+ELwCd)T*x9 z7oZ2j*z?YmumtpJs4yK@+m=u3icg^AZe;-v_|a?B&}>PH*3avkMAAJJWo(;b%ZnqQHFEJD zP9HB$B{msU4LK{wNmbUQ`Fak4Gfi0N{YRlY$WO!0lu_IDU4m4FVsz9`4s+0CiBdnY z#B)BlM#^pa*~rXu0E;l)7Z_}HAG@4XjKdOb<~x_~BaJW3HCU|l(bfd>dDmS!#lV<` z_A&V!AxoSNHC^=3l?$?3Uk|6o@&W5(ERSVknvCC`E8lMb&J13z#G6Fq9jjkQ3p6Ni zl%|q*tX)B}%R=S}$E~ED?apVdtdiudM!oMDTOFI+BwOpa(n>VLF3!#B;c`cYk_7x6 zhT8-MzZ1Um-1uEaqhH&};hJn#6PKMRodKhXYnI06uP1JrZ|+r$OV?V6i3prv>`XU8 zd6W=6c9?A`_ig><1t8ndj(GDYRFgA99^7(yx##GQYxIe;vo5x;L(fF5CVAKPV0fqA z0;9N~Qus>tpHSoZmm-|aF7aac&K{Gmk?MS%-*a{lK&!dVOmXRTWk>2!mspyg{$fR?*A4U%1$2_M0UCt0Qlp?Bfmgv*8tO4#{%dEYTZEPtEY zZEumpf-lXwA_C>&5y8QT+S6agemkav02}!wA^23zPD#BN9NZUdFP0-q!}yzSkKBh5 zIDAre6F(VJ|JXJWbJVuKj6d@9>C@AvPxGkQEwyVe(*w{MKEbBQX2;;E zL%f%`JX8&wx0rcPk+#j`T>ljs_J1O*?(Yf@2)Db^PLA{f65?rG`gF8OA4R{{6L7}Novt5)v4mI09FNEKs)+mbiOF{ zdNTi`quk-*#fW=&W?$vy?P7!T(^r21no$hlF}&jvrz`c_Yd*&(0)0SKs41YS|G{d` zX8sRWbJSkCEcf%yz|hx$GbzZSj|sZJy)Ea}gWJ&U!ZTQajT_El%oJIMa|!+Sop+DG zIay>w*8iwd7?RgT^iqg|%+1C$jWcwRS%diK1V}Z_uvNIu2o)wqX`WV%<&@iEKbN@3hmI}Kh+D5uNac^K4wI}Un|=G--<|*4O61; ze+BlK3iLEdFlDKX%{Ds|E262mKiJr3Y>=T=Q3X$Mr}-a#E2>roxv^J?s~AEb85J zo)ayn9sfrO${;O_7XOm!L{}jHHyi`5juk{D{OS`3wgadfAqFMnv41m(h1E4Vf(Gq0udZX)Wj!y-r3Z z;@oszUvnn(v2me&5E%i~%Y{vBAU@Pg?v~#!$HM|x?P27Wv$(Fq?kqP3zi6d}(#Mr= z^>T-_3iX6Xoq|u8vG$o}pf^(w3+4us^?RX{2fuzJDgDZ;?>GXS=yy9*r+O>Yx*9$| zc?h9Lm3ss;PQPQy6b4Yc1`&THdI+k;sH@HkXJN+5)K-hDR;7@)=Rwm{ z2NHAk49LkAb+nZtDbp8_pP9u*yHO7n?i79wb_2MMW}?BJ!jQyMH)BVb);095 zU5NsdJD9BFcN)QVU>qvUR9MMhEf8!cPxqgK?Lz#=2+cYKA|IStD4cwn!a>YPvoU}G zY;T+Y#k=S}l(xUYR+KVAj1u~AC;78BxL_-2RZw+mDgiG16IjuVu6{dHO*l_CB(ptDxTt}-{56^fG1SGeGJU`+82B|g-^n_bZF*phSldbS zBo4BFTAa!+?TfC}KWbk>Z8JT7XSHFDWe5ry;NBeeA>0hB5Iwh)vsxQIN&mQ= zyHZ1XToE`JL4d@EyQ&D41I_E2w{mdEn0_C}7Oiq{`;9q1?1FLe^d7_R9uY|^|J1#F zNc~rIFSFsBFxb;Ay(&Sil@*2xm=08f_+n4>#yz&tZmdR)`=TvpBetxh9@zcrdt(nO z8i^qJ-nu5*M}C8&@uh5&L~X7!JbPb_T}cu-LukInI>yy)7YU2&lFpmYSUC{VU1|i6 z95Gm-mY?MM9sOS8f-k2lrb$@iu~`wC7S{OICxjkVu#i<2NSkL3BW3|`hg-xkP2UoT z`0~ZW>eH>d!$5*>V(B8N!azVDZY)GgC&pU^F*`kM(_ufUyt$xL!8&8ykTt0scRx|? zpg>%^b*JDRj08&jLU2ZvTsouj7-a_-pe~YsZoEoERrSXr?d@;7j(Mz@X553I@g~~( z!^khaAj8|{j~Jg~4Zd7*8_%BS8vE-v1kcbLD6Qsmh9)j(Q`5_%6f2kV%X*uM+)lNj za7oAa#uvZlhdtoTdb2ON+UT#{XCUr$XX2kl5W?P5WcKF1fO&XSeA<%fA z5Bw<@NS-z$xP98{9)_LK(9vNit(FnB)k8>|!yi6OX!AldV|98_wS!17A#C!20tSSH zrao}ADZLv`nm;8pw!Uk#KY#$xo3BPNI3V{9z}bEGn}jWxf5fV;S-sCj8DK+Xy5A=kEH z6+a3dcM3`ripF`;<-qB57Kq4pKT2B_|oFqeT=8G!OR6q8Z!@ESgJ9fA2Z-I@~4#&3C*+^KaFp^YmdEwg0#Fn7zqV8T+1w?WSBDvjV8bb zdIphlmx~*_bG>7+^sN#zUyYtTF0qM&Bjvimv0O=gn8a8)IluqH8}<>BMM3(J#~u3f zF?y5;%+elktF}RMq1MPOH2r@A94hA&;5lj_NSsSdg(ROV6U?NA(`mz*&f$-N=_8k8 zq}b?$_M#XlIHX<12m*mSK;BnPHL33*KvWo9Aj2jf zAu9eeNCaTjeK7H+0t4;o~R_IG3bjd#_uwcU^?8^k>CVOz8HhhH0#)4r`5DoZ? zf~pgc@FT@DwlES2%4Y-zM}%_Yx2Vp)v;IaRNjT#uZ)!SzX5;_W-kAqdxwdP3mC#OG zDy)Q5lBvj)S!ImMoOWeOY+9v6856NfsZf&4kxXSsNo0ymqzs{fOvy}?IX2(*(B8Xm zpMAb_&Ue1=oPV}I8VqYK@B6&#eeUbNuHT&}aq^KVT7wx!Qlw-=OhJ7 z?zH^F%w<2p=kX?G#nPn*6vTYoX+BM*CzK8{CyMPpn0&6mDb9laEVbv3^ZN_@4=Rb8 z(L^vm`0YkMMk4i{iu{Y^%FDu?NYdQ(kGn1h9Ny#%)KSh#X>&~RU>7!e&diu{bcs|m z?rOa+Z(rnYA~@z}GDI6VeFZLFfr>P17w0{ICm!W=&!m0&zD0Xp9`y{J_N`U+4J+qW zJizV=K&Y;k=25pdkc*kQT>+XV_Z6ITY#Q&!t0i2;NR0SJQX3O5ZKV%z)jKu79}}a> zy-P^rfs`Vd#kpl>LPuUaWWe#kjh-NEmN_bAS%r*91ReoEJd8Vbd>OItmlgBW^SNE{ zT@(uaN#%;qSR)Wf5M~oIj@;74>PGv_7;(EV8<74nTQ{--fwL?ytB5Q z51JmHD^Judruy|KZ&nl&tNstkc*|&#jL))EA<6jZmqwhy&I8mizV@Xsa2hRq-@tpV zy=1pJ!8$p6jdm9hm7wX92)GJtuD`GV-zgwiDd|^m)&{`PD1*7Ks z<>(8%xIU!gyspLbAYnZkCms1bf6Mjfn$0yp;#0-H0@ay$Vu5Af zjs*M54<1NnhChBXBKR8@O;A$O@a>tvN;5k(%9YeV^6=DPsU<*tJ+GmG>tFV;u&|g{ z)~~Mj+&>sbWQc;L%F4>aKVYsU9VP3j)EtcNpJnC$E7%D)cb|0gfYiyUW)%vKtW2JrkU332hoi}s^2gNXAg6=mhc zEevzN!J-i5%U~AL@#{UmcJ*q^1@PhEf<4R4V7K|JS1JzH5}cDZ^VxF*lkIvPLDed2 zosmtXk@ zVx_aW7Ui}>4F zUc%8op5~R$RWw2MwDaba;h^fys$E>nJo_a#rQMwLW}4=9D4$)5glddKUU*zEo({un zMG!u8T3gv(r)coN2PKv4UKiHoZNF*(FY}!YyI81H>!}zvhm&+vpQsbw`Cr+5e#i`b z1>iN$+H%qm7X%k?48`U{n`#S)qi;otA%~b{jYHwwoTsET*(c#n`$t$j^nK<~`Z8s> z@%KS#ZnF7@SUfU?B0w4@eQ`|S+l2(=aTKN{q6ow7Me}Df6WO-pO3H>u0XCt?f$9%; z5gC|PP~oGVeW(6CVkw=VzCMC2gR80VmN`S=)PLoSG3_ov<720Yn3llw&$H49Vks5~ zxs}vhmVo~@&`nD{50P|~fHGlLq-O=warkrpix+#Fawi#iPTAqcfYS+WKnaq1y=L2{ zFQs@_#8qPaGumY**EPen2_yolNvr%p^t~`OKH1U(6q%I|XqDsjT3uSJN@&955eZ1S@@C}Z9e#n`D{|49@9fJD`YZl872^);hKi--2efl`OOV(sVdFn@LS`p{ z8{owIk3F#MVYG$o0P zOdDbP-ld8Ct+%%~sa7GXiJIn&0}-uD$I8Z5ht~)BfRTZL=Itx{t<0d-fA=A5Qk=Uo zZ5tf1$gzXThDb-kTnfBa2{p>yW%xyM?qHS#5$wqRf2GnlCJvg1`|nbNwp&a*(Hb05 zZ>WrTexo&Hd`{X~`(#dQ@bLZT>3xVORVg#2`<>2C2D#p?N}tdUxON`#GFhm=nS`R*9VJRog~#pF(xlmd}6g|z-| z!%ZekWC#p(X~eMXI8|O**(~f&OB~cXi`k7HVtVH{I>Z$@tYYAOnLh`8HE)=TpAJE+ zW$og2CK|`Dp#F!eg5tYAA$EBBmyy@NHv^Ap@Hi(_59TiCju7kTd}Q-o8+yl}H8DO? zUl9$wE#rABv4_h|?>?8Hv29H$UY7swN<@z{v2n1jA(8r(%GvWWVR-gD6`RMaMiE*~ zY~?$*UGR3bul0`=;;-3s2=6a}%+qysx0HDJxUqrD_yAtFVag#UbRAPn#w~_&`<%I4 z$2N@7;0$n0h2$Y*;f!wcvFz?Rh&XTaV)G*4EFkF<)1E2V6Yqo?vRWumg&M33??DvW z-e?2#r>@~FilIS|FJ5;&wzY8^U3a%*BYWFWrXoyQw5DVvPKYt^>QzH4T3#N{E@Njl zF-nUl8Qcami&4$Qy{B;FNID={LEW!ZR5V#@>K1dktIA|KbP2uvapy=Dp19Ktq!fum zBQYX__fpe9^us3Sqa1fM+NXP->++xZO_qq>(?An}+_V)~^w5JNJOXo~M7iX-g!gM^ zH3@jIs0}w)T8#MFRSSHhNnrIBD!s7ZX+KcR3nTKZD#0c^fktn4|V`O_OI+ymL z6;EA!{Rg39F6-lmTlb-{RYSV|g}7jIi%ubCH7iwkNIm{G>Z3&GuGXWL7QxlCL)U*h zVp~V{=im*qA>(GL%H*qbs~!9K2_SNg#rGjrGY~L7`eW|%A2E|Inr7}+6oC);jk^+Q zp`6EZ#A?KWUc&Iy(lMz6SwNM-cAw_5z*f3-7(ORSt(+7 zZ^AU`m|;YMBh);9r#MH+t4I5#HoU?GQpaTZ`MhhH;SK_O98L5sFBf_I9OxLg z+0;)rcd*tUQa|-d#f(tG{rvrBCOV@se!$Wj(MLH`$1K#ha74E@C57JY&;_2_Yj|gF z$jpRmlVOhIcYU)G8VYI~p@r(_dxai+Ar={4>?~q_20RkU~E&`9pfW;!ATryoI+;AoP=&l}FL*H6hQ5C6hOJ;OwhG5vZH#3ffXCZI z|Mn)wN#r}Ac;JgGkX4mXQ*do`Y)I1%le@&`C+0K%Jlvg0 zoAvc#LWJsBIcyFDIqj_&Yb?ZuP06O}CYJLs*41kRHfbaxZLo->k{fl)5`tMhY?5JX zXjob;5+StC&Ho0ryKhW=?>3SErpUvzRU^5VIV9AX+|9Zvj@3vmpg@Jx~?e5m@j_Wo>9iv zHPZGSvrI_g{GeU3S?BlcNQxb7d-)2zhI8l6ePO4)tsJ|ZKa@1oSGjA6))ZYJGVqhE3X*J{*d`d zYwDQ~v`e3R;Z?NstL~}5rZk&4-(_Y#qxD4_IR;ll@aF5K|d@oN= z%KtBF|6k@?`0IhlqNMy`qT#&tPu(b##q5L~NWS{N=AQf;ohN^tL2`!vcm~O5{yJ+U z*agw+e>Mg5Pb5TWJ%2sWzh&g=|H;9o58J`wA=C0E?$S{F^DKjTuKW5vUy2D18_b@^ zCu|8h5Fegi@2v~2MADe2Xfdx>1TJlf;BXRH{V_oHVVQAbm0@<#f)AB%*Wfk?v6NVx z&lG|6kOEH(e5okT;omrg7J2XMRGyV9X|s=5YCZ26(@v2H#UCAaE|K90Y!ojp59zU$ z@b$6&q>nNPts4nZvz&2kpKR>Sp@R_Z1P&CUDYdLX&xTvfLKVVV3O)_v2*K7Dp1sD}en|8v2SdpaMhl|Z zcpQK&jJktM*aJ~ZQ*?jK+(&}+lVN9ubrBz*HB#vO4u(lwnurpJR)1WutbMw(JI|^+ z-tm{pg|{?bh4t^q|5z%x!Lo5_vn$JQ{+1jZH z@$Gr|nb2pVCRjpdkQ{)U;Wl(>fR_%T421EGabP~E@@jxYu?4UA5Rb2! zAQ0x5jcekW3{pyBm<)*H_qyV)Vd6`i{;x+&IxA0=Z_}Gtz7U1@b;?f*U|(xTIRO}G zsw_I}FsX~~PO625$OGDt6$et1m_>gA%~{tRoR7X5d<6qyY`{<*?MBreFUv5Iil8H| zi@fGhsJSr2d_T~rGkgoSMdTjwvAX%gm&JbX+do^i;-KTe9>m3lR=5j9qTC^)}AUVY>eg;*+1uCm^r*JJ9S%zyI1D9Uj+(y^DyDviHH6{{9 zAmA5@&@CtHUCiZiK=G5OY2Z9Q^G;p^Ji(}DOeX*40yKTSz%t|IS?NRHFA{4V*~tvR zjO6j8#zS3AUM7ZZlwtLGc*0@X3HIj+ zB7Pr5PS1~)k+G!mQ@5SyzLwZ8#LS>ocJusCs%eK@X~Ivm>VEJRRj6bUd3s#Bd0=|1 zseQDhL|rK=KY{SS2e*FYl6k4T!qw@d^~AxU$<8}PD^&(mLYGJzPwU*j5fzncD1`CJ z4h{}&ZEgKejdMcmvtFs&N9v1o&|klPU0q$Bol3n}{C;$F6k`Dg2kj;gb^F~FwzaiQ zPDzOj54ZHdnA`N`BW_k!R@TKSga(ZZ{Y=(k^Vicw}AcMA)mUhWi7_ z?`pn$`7%8{-Ohs+W_Ei)Yt&WG?#F;o0X{?K+=y0$CK#kmYqg5*ZZ=MOCK-fBtuV qEY}R*H!~x4GM5McU?3F&9p${aNKvzREGCjrD4J^8swv9mUVj5F#WZgK literal 73507 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 diff --git a/apps/docs/public/static/search/connect-account-details.png b/apps/docs/public/static/search/connect-account-details.png new file mode 100644 index 0000000000000000000000000000000000000000..565965e7773f9cfc92d1402a81bd8f710a63b66c GIT binary patch literal 39639 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

Vsr2%$5hKr-KV*H1S>t)k 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 F{|EmTc=G@N diff --git a/apps/sim/app/api/organizations/[id]/chats/[chatId]/actions/receipts/route.ts b/apps/sim/app/api/organizations/[id]/chats/[chatId]/actions/receipts/route.ts new file mode 100644 index 00000000000..de2f563799e --- /dev/null +++ b/apps/sim/app/api/organizations/[id]/chats/[chatId]/actions/receipts/route.ts @@ -0,0 +1,23 @@ +import { listAssistantActionReceiptsContract } from '@/lib/api/contracts/assistant-actions' +import { + defineInternalJsonRoute, + internalOrchestrationErrorPolicy, + internalRateLimits, + internalSessionAuth, +} from '@/lib/api/server/routes' +import { assistantActionOperations } from '@/lib/assistant-actions/application/operations' +import { listOrganizationAssistantActionReceipts } from '@/lib/assistant-actions/application/receipts' + +export const GET = defineInternalJsonRoute({ + contract: listAssistantActionReceiptsContract, + auth: internalSessionAuth, + operation: assistantActionOperations.receipts, + rateLimit: internalRateLimits.user({ + bucketName: 'assistant-action-receipts', + config: { maxTokens: 120, refillRate: 120, refillIntervalMs: 60_000 }, + }), + errorPolicy: internalOrchestrationErrorPolicy, + mapInput: ({ params, query }) => ({ organizationId: params.id, chatId: params.chatId, ...query }), + useCase: listOrganizationAssistantActionReceipts, + staticResponseHeaders: { 'Cache-Control': 'private, no-store' }, +}) diff --git a/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx b/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx index 50673e47748..1879deb50a7 100644 --- a/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx +++ b/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx @@ -1,6 +1,6 @@ 'use client' -import { useCallback, useEffect, useState } from 'react' +import { type ReactNode, useCallback, useEffect, useRef, useState } from 'react' import { toast } from '@sim/emcn' import { toRecord } from '@sim/utils/object' import { useQueryClient } from '@tanstack/react-query' @@ -57,10 +57,20 @@ import { useHydrated } from '@/hooks/use-hydrated' import { useMothershipDraftsStore } from '@/stores/mothership-drafts/store' import type { ChatContext } from '@/stores/panel' +export interface OrganizationSummaryRequest { + id: string + message: string + assistantSearch: WorkspaceSearchFilters +} + interface OrganizationConversationProps { + active?: boolean + summaryRequest?: OrganizationSummaryRequest + onSummaryConsumed?: (id: string) => void userName?: string chatId?: string requestMode: ChatRequestMode + header?: ReactNode } /** Shared conversation surface; the destination fixes its intent before the first turn. */ @@ -74,7 +84,8 @@ export function OrganizationConversation(props: OrganizationConversationProps) { (props.requestMode === 'assistant' ? !searchAccess.memberScoped : !canBuild) ) return null - if (isRestoredChatEntry || !isClient || !session?.user?.id) return + if (isRestoredChatEntry || !isClient || !session?.user?.id) + return return ( { - if (chat.resolvedChatId && !chat.isSending && !chat.isReconnecting) + if (active && chat.resolvedChatId && !chat.isSending && !chat.isReconnecting) markRead(chat.resolvedChatId) - }, [chat.resolvedChatId, chat.isSending, chat.isReconnecting, markRead]) + }, [active, chat.resolvedChatId, chat.isSending, chat.isReconnecting, markRead]) + + const consumedSummary = useRef(null) + useEffect(() => { + if (!active || !summaryRequest || consumedSummary.current === summaryRequest.id) return + consumedSummary.current = summaryRequest.id + onSummaryConsumed?.(summaryRequest.id) + void sendMessage(summaryRequest.message, undefined, undefined, { + requestMode: 'assistant', + assistantSearchLevel, + assistantSearch: summaryRequest.assistantSearch, + }) + }, [active, summaryRequest, onSummaryConsumed, sendMessage]) useEffect(() => { if (chatId) return @@ -370,6 +397,7 @@ function OrganizationConversationContent({ enabled={requestMode === 'assistant'} > addResource({ type: 'sources', @@ -428,6 +456,7 @@ function OrganizationConversationContent({ ) return ( void + connectLabel: 'Connect' | 'Add account' + onReconnect: () => void + canReconnect: boolean + canConnect: boolean + connectionPending: boolean +} + +/** Header actions act on the selected account; adding a connection uses its available slot. */ +export function AccountConnectionActions({ + organizationId, + integrationName, + account, + onConnect, + connectLabel, + onReconnect, + canReconnect, + canConnect, + connectionPending, +}: AccountConnectionActionsProps) { + const disconnect = useDisconnectPersonalOrganizationAccount(organizationId) + const [confirming, setConfirming] = useState(false) + const pending = connectionPending || disconnect.isPending + return ( + <> + {account && ( + + Reconnect + + )} + {onConnect && ( + + {connectLabel} + + )} + {account && ( + <> + { + disconnect.reset() + setConfirming(true) + }} + > + Disconnect + + { + if (!disconnect.isPending) setConfirming(open) + }} + title={`Disconnect ${integrationName}`} + text={`Disconnect ${account.displayName} from all ${integrationName} connections in this organization. Workflows using this account will also lose access. You can reconnect later.`} + confirm={{ + label: 'Disconnect', + pendingLabel: 'Disconnecting', + pending: disconnect.isPending, + disabled: disconnect.isPending, + onClick: () => + disconnect.mutate(account.credentialId, { onSuccess: () => setConfirming(false) }), + }} + > + {disconnect.error?.message} + + + )} + + ) +} diff --git a/apps/sim/app/o/[organizationId]/integrations/accounts/[credentialId]/tool-permissions.tsx b/apps/sim/app/o/[organizationId]/integrations/accounts/[credentialId]/tool-permissions.tsx index 792bc279324..e8d86c823a0 100644 --- a/apps/sim/app/o/[organizationId]/integrations/accounts/[credentialId]/tool-permissions.tsx +++ b/apps/sim/app/o/[organizationId]/integrations/accounts/[credentialId]/tool-permissions.tsx @@ -2,13 +2,14 @@ import { Chip, ChipInput, ChipLink, ChipSelect, ChipSwitch, Tooltip, toast } from '@sim/emcn' import { ArrowLeft, Search } from '@sim/emcn/icons' +import { useQueryStates } from 'nuqs' import type { AssistantToolPermissionsResponse, UpdateAssistantToolPermissionsBody, } from '@/lib/api/contracts/assistant-actions' import { resolveCredentialDisplay } from '@/lib/integrations/credential-display' import { organizationRoutes } from '@/lib/navigation/paths' -import { useOrganizationPageFilters } from '@/app/o/[organizationId]/components/organization-page' +import { integrationViewParsers } from '@/app/o/[organizationId]/integrations/search-params' import { CredentialDetailHeading, CredentialDetailLayout, @@ -23,6 +24,7 @@ import { useAssistantToolPermissions, useUpdateAssistantToolPermissions, } from '@/hooks/queries/assistant-actions' +import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter' const POLICY_OPTIONS = [ { value: 'allow', label: 'Allow' }, @@ -43,9 +45,38 @@ export function AccountToolPermissions({ organizationId, credentialId, }: AccountToolPermissionsProps) { + return ( + + Integrations + + } + > + + + ) +} + +interface AccountToolPermissionsContentProps extends AccountToolPermissionsProps { + showHeading?: boolean +} + +export function AccountToolPermissionsContent({ + organizationId, + credentialId, + showHeading = false, +}: AccountToolPermissionsContentProps) { const query = useAssistantToolPermissions(organizationId, credentialId) const update = useUpdateAssistantToolPermissions(organizationId, credentialId) - const { search, setSearch } = useOrganizationPageFilters() + const [{ tools: search }, setParams] = useQueryStates(integrationViewParsers) + const setSearch = useDebouncedSearchSetter((value, options) => + setParams({ tools: value }, options) + ) const data = query.data const display = data ? resolveCredentialDisplay({ ...data.account, type: 'managed_oauth' }) @@ -59,13 +90,7 @@ export function AccountToolPermissions({ } return ( - - Integrations - - } - > + <> {query.error ? ( Loading tool permissions ) : (

-
- - ) : undefined - } - /> - {!data.canAutoApprove && ( -

- Your organization requires approval before tools run. -

- )} - {!data.account.active && ( -

- This account is disconnected or paused. Reconnect it before allowing tools - automatically. -

- )} -
+ {(showHeading || !data.canAutoApprove || !data.account.active) && ( +
+ {showHeading && ( + + ) : undefined + } + /> + )} + {!data.canAutoApprove && ( +

+ Your organization requires approval before tools run. +

+ )} + {!data.account.active && ( +

+ This account is disconnected or paused. Reconnect it before allowing tools + automatically. +

+ )} +
+ )} {data.tools.length > 0 && ( )} - + ) } diff --git a/apps/sim/app/o/[organizationId]/integrations/integration-detail.tsx b/apps/sim/app/o/[organizationId]/integrations/integration-detail.tsx new file mode 100644 index 00000000000..b7906e5cfb8 --- /dev/null +++ b/apps/sim/app/o/[organizationId]/integrations/integration-detail.tsx @@ -0,0 +1,126 @@ +'use client' + +import type { ReactNode } from 'react' +import { toast } from '@sim/emcn' +import { AccountConnectionActions } from '@/app/o/[organizationId]/integrations/account-connection-actions' +import { AccountToolPermissionsContent } from '@/app/o/[organizationId]/integrations/accounts/[credentialId]/tool-permissions' +import type { MemberIntegration } from '@/app/o/[organizationId]/integrations/utils' +import { + CredentialDetailHeading, + CredentialDetailLayout, +} from '@/app/workspace/[workspaceId]/components/credential-detail' +import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase' +import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' +import { SettingsField } from '@/app/workspace/[workspaceId]/settings/components/settings-field' +import { + RESOURCE_LIST_STACK, + SettingsResourceRow, +} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' +import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' +import { + useConnectOrganizationAccount, + useReconnectPersonalOrganizationAccount, +} from '@/hooks/queries/organization-accounts' + +interface IntegrationDetailProps { + organizationId: string + integration: MemberIntegration + accountId: string | null + accountHref: (accountId: string) => string + back: ReactNode + children?: ReactNode +} + +/** The selected account owns every permission and connection action in this view. */ +export function IntegrationDetail({ + organizationId, + integration, + accountId, + accountHref, + back, + children, +}: IntegrationDetailProps) { + const connect = useConnectOrganizationAccount() + const reconnect = useReconnectPersonalOrganizationAccount() + const onError = (error: Error) => toast.error(error.message) + const selected = accountId + ? integration.accounts.find((account) => account.credentialId === accountId) + : integration.accounts.length === 1 + ? integration.accounts[0] + : undefined + const target = integration.connectionTarget + return ( + connect.mutate({ organizationId, ...target }, { onError }) : undefined + } + onReconnect={() => { + if (selected) reconnect.mutate(selected.credentialId, { onError }) + }} + connectionPending={connect.isPending || reconnect.isPending} + canConnect={integration.ready} + canReconnect={Boolean( + selected && integration.reconnectAccountIds.includes(selected.credentialId) + )} + /> + ) + } + > + {children} + } + /> + {integration.managed ? ( + Organization managed + ) : ( + + {accountId && !selected ? ( + + This account is no longer connected. + + ) : selected ? ( + + {selected.displayName} + + ) : integration.accounts.length ? ( +
+ {integration.accounts.map((account) => ( + + ))} +
+ ) : ( + No account connected + )} +
+ )} + {selected && integration.permissionAccountIds.includes(selected.credentialId) && ( + + )} +
+ ) +} diff --git a/apps/sim/app/o/[organizationId]/integrations/integrations.tsx b/apps/sim/app/o/[organizationId]/integrations/integrations.tsx index 0869432d66d..b85c2901409 100644 --- a/apps/sim/app/o/[organizationId]/integrations/integrations.tsx +++ b/apps/sim/app/o/[organizationId]/integrations/integrations.tsx @@ -2,8 +2,7 @@ import type { SearchConnectionTarget } from '@/lib/knowledge/search/connection-target' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' -import { OrganizationPage } from '@/app/o/[organizationId]/components/organization-page' -import { useOrganizationPageFilters } from '@/app/o/[organizationId]/components/organization-page/use-organization-page-filters' +import { useOrganizationPageFilters } from '@/app/o/[organizationId]/components/organization-page' import { LiveMemberIntegrations } from '@/app/o/[organizationId]/integrations/live-member-integrations' import { SlackSearchActions } from '@/app/o/[organizationId]/integrations/slack-search-actions' import { useOrganizationContext } from '@/app/o/[organizationId]/providers/organization-provider' @@ -27,24 +26,24 @@ export function OrganizationIntegrations({ const sourceSearch = useDebounce(search.trim(), SEARCH_DEBOUNCE_MS) return ( - ) } - > - {connectionRequest && ( - - )} - - + intro={ + connectionRequest && ( + + ) + } + /> ) } diff --git a/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.test.tsx b/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.test.tsx deleted file mode 100644 index 89f76f6ebaa..00000000000 --- a/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.test.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/** @vitest-environment jsdom */ -import { act } from 'react' -import { - organizationAccountsQueriesMock, - organizationAccountsQueriesMockFns, -} from '@sim/testing/mocks/organization-accounts-queries.mock' -import { - organizationProviderMock, - organizationProviderMockFns, -} from '@sim/testing/mocks/organization-provider.mock' -import { createRoot, type Root } from 'react-dom/client' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import type { OrganizationAccountsSettings } from '@/lib/api/contracts/organization-accounts' -import { LiveMemberIntegrations } from '@/app/o/[organizationId]/integrations/live-member-integrations' - -const mocks = vi.hoisted(() => ({ connect: vi.fn() })) -vi.mock('@/hooks/queries/organization-accounts', () => organizationAccountsQueriesMock) -vi.mock('@/hooks/queries/organization-secrets', () => ({ - useOrganizationSecretSource: () => ({ data: { source: null } }), -})) -vi.mock('@/hooks/queries/search-integrations', () => ({ - useSearchIntegrations: () => ({ - data: [{ connectorType: 'coda', approved: true }], - isSuccess: true, - }), -})) -vi.mock('@/app/o/[organizationId]/providers/organization-provider', () => organizationProviderMock) -vi.mock('@/app/workspace/[workspaceId]/integrations/components/integrations-showcase', () => ({ - IntegrationTile: () => null, -})) - -let root: Root -let container: HTMLDivElement -beforeEach(() => { - organizationAccountsQueriesMockFns.mockUseConnectOrganizationAccount.mockReturnValue({ - mutate: mocks.connect, - }) - organizationProviderMockFns.mockUseOrganizationContext.mockReturnValue({ - organization: { id: 'org', name: 'Example Organization' }, - }) - vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) - container = document.createElement('div') - document.body.appendChild(container) - root = createRoot(container) -}) -afterEach(() => { - act(() => root.unmount()) - container.remove() -}) -it('never presents another MCP provider as a Coda connection', async () => { - const inventory = { - credentialGroup: { - id: 'group', - workspaceId: null, - organizationId: 'org', - name: 'Organization accounts', - description: null, - status: 'active', - options: [], - mcpServers: [ - { - id: 'coda-server', - name: 'Coda', - description: null, - authType: 'oauth', - managedConnectorId: 'coda', - enabled: true, - }, - ], - createdAt: '2026-01-01T00:00:00.000Z', - updatedAt: '2026-01-01T00:00:00.000Z', - }, - availableProviders: [], - assistantProviders: [], - availableMcpConnectors: ['coda'], - viewerAccounts: [], - viewerMcpAccounts: [ - { - credentialId: 'other', - mcpServerId: 'other-server', - displayName: 'Other private account', - status: 'active', - }, - ], - canManage: false, - indexingAvailable: true, - } satisfies OrganizationAccountsSettings - organizationAccountsQueriesMockFns.mockUseOrganizationAccounts.mockReturnValue({ - data: inventory, - }) - await act(async () => root.render()) - expect(container.textContent).not.toContain('Other private account') - const menu = container.querySelector('[aria-label="Coda integration actions"]') - if (!menu) throw new Error('Missing Coda actions menu') - await act(async () => - menu.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true, button: 0 })) - ) - const connect = [...document.querySelectorAll('[role="menuitem"]')].find( - (item) => item.textContent === 'Connect' - ) - if (!connect) throw new Error('Missing Coda connection control') - await act(async () => connect.click()) - expect(mocks.connect).toHaveBeenCalledWith( - { organizationId: 'org', mcpServerId: 'coda-server' }, - expect.any(Object) - ) -}) diff --git a/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.tsx b/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.tsx index 6297deb3a6c..d8fc4bdf7f7 100644 --- a/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.tsx +++ b/apps/sim/app/o/[organizationId]/integrations/live-member-integrations.tsx @@ -1,267 +1,209 @@ 'use client' -import { toast } from '@sim/emcn' -import { findCredentialGroupProviderFromProviderId } from '@/lib/credential-groups/providers' -import { hasSlackSearchUserScopes } from '@/lib/credential-groups/slack-managed-user-scopes' -import { LIVE_SEARCH_SCOPE_FIELDS } from '@/lib/sim-search/live/policy-schema' +import type { ReactNode } from 'react' +import { ChipLink } from '@sim/emcn' +import { ArrowLeft } from '@sim/emcn/icons' +import { useQueryStates } from 'nuqs' +import { organizationRoutes } from '@/lib/navigation/paths' +import { OrganizationPage } from '@/app/o/[organizationId]/components/organization-page' +import { IntegrationDetail } from '@/app/o/[organizationId]/integrations/integration-detail' import { - LIVE_SEARCH_SOURCE_TYPES, - liveSearchMcpConnector, - liveSearchMemberAccountProvider, -} from '@/lib/sim-search/live/source-catalog' -import { AccountActionsMenu } from '@/app/o/[organizationId]/integrations/account-actions-menu' -import { AssistantAccountIntegrations } from '@/app/o/[organizationId]/integrations/assistant-account-integrations' -import { assistantAccountOptions } from '@/app/o/[organizationId]/integrations/utils' -import { GenericSecretSourceRow } from '@/app/o/[organizationId]/settings/components/integrations/generic-secret-source' + integrationViewParsers, + serializeIntegrationView, +} from '@/app/o/[organizationId]/integrations/search-params' +import { + memberIntegrationEntries, + memberIntegrationStatus, +} from '@/app/o/[organizationId]/integrations/utils' +import { + GenericSecretSourceIcon, + GenericSecretSourceRow, +} from '@/app/o/[organizationId]/settings/components/integrations/generic-secret-source' +import { CredentialDetailLayout } from '@/app/workspace/[workspaceId]/components/credential-detail' import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase' import { SettingsEmptyState, SettingsQueryErrorState, } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' -import { SettingsResourceRow } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' import { - useConnectOrganizationAccount, - useOrganizationAccounts, - useReconnectPersonalOrganizationAccount, -} from '@/hooks/queries/organization-accounts' + RESOURCE_LIST_STACK, + SettingsResourceRow, +} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' +import { useOrganizationAccounts } from '@/hooks/queries/organization-accounts' import { useOrganizationSecretSource } from '@/hooks/queries/organization-secrets' import { useSearchIntegrations } from '@/hooks/queries/search-integrations' interface LiveMemberIntegrationsProps { organizationId: string search: string + navigationSearch: string + intro?: ReactNode + action?: ReactNode } -/** Personal OAuth apps and administrator-managed GitLab have distinct connection states. */ -export function LiveMemberIntegrations({ organizationId, search }: LiveMemberIntegrationsProps) { - const connect = useConnectOrganizationAccount() - const reconnect = useReconnectPersonalOrganizationAccount() - const onError = (error: Error) => toast.error(error.message) +/** Member integrations share one inventory and the platform's list/detail layout. */ +export function LiveMemberIntegrations({ + organizationId, + search, + navigationSearch, + intro, + action, +}: LiveMemberIntegrationsProps) { + const [{ integration, account }] = useQueryStates(integrationViewParsers) const inventory = useOrganizationAccounts(organizationId) const policies = useSearchIntegrations(organizationId) const secrets = useOrganizationSecretSource(organizationId) - if (inventory.error) - return ( - void inventory.refetch()} - variant='inline' - /> - ) - if (!inventory.data) - return Loading your connections - const data = inventory.data - const loadedPolicies = policies.isSuccess ? policies.data : undefined - const approvals = new Map(loadedPolicies?.map((policy) => [policy.connectorType, policy])) - const permissionAccountIds = (data.viewerAccounts ?? []) - .filter((account) => { - const provider = findCredentialGroupProviderFromProviderId(account.providerId) - return provider !== null && data.assistantProviders.includes(provider) + const routes = organizationRoutes(organizationId) + const href = (selected: string | null, selectedAccount: string | null = null) => + serializeIntegrationView(routes.integrations, { + q: navigationSearch, + integration: selected, + account: selectedAccount, }) - .map((account) => account.credentialId) - const group = data.credentialGroup - const mcpProviders = new Map( - group?.mcpServers.map((server) => [server.id, server.managedConnectorId]) + const entries = inventory.data + ? memberIntegrationEntries(inventory.data, policies.isSuccess ? policies.data : undefined) + : [] + const selected = entries.find((entry) => entry.id === integration) + const status = inventory.error ? ( + void inventory.refetch()} + variant='inline' + /> + ) : !inventory.data ? ( + Loading your connections + ) : null + const errors = ( + <> + {policies.error && ( + void policies.refetch()} + variant='inline' + /> + )} + {secrets.error && ( + void secrets.refetch()} + variant='inline' + /> + )} + ) - const mcpAccounts = (provider: string) => - (data.viewerMcpAccounts ?? []).filter( - (account) => mcpProviders.get(account.mcpServerId) === provider + if (integration) { + const back = ( + + {account ? (selected?.name ?? 'Integration') : 'Integrations'} + ) - const accountsForProvider = (provider: string) => { - if (liveSearchMcpConnector(provider)) return mcpAccounts(provider) - const memberProvider = - provider === 'slack' ? 'slack' : liveSearchMemberAccountProvider(provider) - return (data.viewerAccounts ?? []).filter( - (account) => findCredentialGroupProviderFromProviderId(account.providerId) === memberProvider + if (selected && !status) { + return ( + href(selected.id, credentialId)} + back={back} + > + {errors} + + ) + } + return ( + + {status ?? ( + <> + {errors} + {integration === 'secrets' ? ( + secrets.data?.source ? ( + + ) : ( + + {secrets.isPending + ? 'Loading connection' + : 'This integration is no longer available.'} + + ) + ) : ( + + {policies.isPending + ? 'Loading connection' + : 'This integration is no longer available.'} + + )} + + )} + ) } - const available = LIVE_SEARCH_SOURCE_TYPES.filter( - ([provider]) => - (approvals.get(provider)?.available !== false || accountsForProvider(provider).length > 0) && - LIVE_SEARCH_SCOPE_FIELDS[provider] && - ((provider !== 'hubspot' && provider !== 'zoom') || - data.availableMcpConnectors.includes(provider) || - mcpAccounts(provider).length > 0) && - (approvals.get(provider)?.approved || accountsForProvider(provider).length > 0) - ) const query = search.trim().toLowerCase() - const visible = available.filter(([provider, meta]) => - `${provider} ${meta.name} ${accountsForProvider(provider) - .map((account) => account.displayName) - .join(' ')}` + const visible = entries.filter((entry) => + [entry.provider, entry.name, ...entry.accounts.map((item) => item.displayName)] + .join(' ') .toLowerCase() .includes(query) ) - const secretSource = secrets.data?.source - const showSecrets = secretSource && 'generic secrets'.includes(query) + const showSecrets = secrets.data?.source && 'generic secrets'.includes(query) return ( -
- -
- {policies.error && ( - void policies.refetch()} - variant='inline' - /> - )} - {secrets.error && ( - void secrets.refetch()} - variant='inline' - /> - )} - {showSecrets && ( - - )} - {visible.map(([provider, meta]) => { - const approval = approvals.get(provider) - const approved = approval?.approved === true - const name = meta.name - if (provider === 'gitlab') - return ( - } - title={name} - description='Access follows project permissions' - trailing={ - Organization managed - } - /> - ) - const memberProvider = - provider === 'slack' ? 'slack' : liveSearchMemberAccountProvider(provider) - const accounts = accountsForProvider(provider) - const options = - group?.options.filter( - (option) => - option.provider === memberProvider && - option.status === 'active' && - option.configurationStatus === 'ready' && - (provider !== 'slack' || - (option.provider === 'slack' && hasSlackSearchUserScopes(option.requiredScopes))) - ) ?? [] - const servers = liveSearchMcpConnector(provider) - ? (group?.mcpServers.filter( - (server) => server.managedConnectorId === provider && server.enabled - ) ?? []) - : [] - const option = options.find( - (option) => - !accounts.some((account) => 'optionId' in account && account.optionId === option.id) - ) - const server = servers.find( - (server) => - !accounts.some( - (account) => 'mcpServerId' in account && account.mcpServerId === server.id - ) - ) - const connectionTarget = server - ? { mcpServerId: server.id } - : option - ? { optionId: option.id } - : undefined - const ready = - approval?.available !== false && - group?.status === 'active' && - (options.length > 0 || servers.length > 0) && - approved && - ((provider !== 'hubspot' && provider !== 'zoom') || - data.availableMcpConnectors.includes(provider)) - const reconnectAccountIds = ready - ? accounts - .filter((account) => - 'optionId' in account - ? options.some((option) => option.id === account.optionId) - : servers.some((server) => server.id === account.mcpServerId) - ) - .map((account) => account.credentialId) - : [] - const scope = - approval?.policy?.accessMode === 'service_account' - ? 'Selected resources you can access' - : 'All accessible content' - const state = !loadedPolicies - ? undefined - : approval?.available === false - ? 'Currently unavailable' - : !approved - ? 'Disabled by your organization' - : group && group.status !== 'active' - ? 'Connections are paused by your organization' - : !ready - ? 'Not configured' - : accounts.length - ? scope - : undefined - const description = [ - accounts - .map( - (account) => - `${account.displayName}${account.status === 'needs_reauth' ? ' · Reconnect needed' : ''}` - ) - .join(', '), - state, - ] - .filter(Boolean) - .join(' · ') - return ( + + {intro} + {status ?? ( +
+ {errors} + {showSecrets && ( } - title={name} - description={description} - trailing={ - connect.mutate({ organizationId, ...connectionTarget }, { onError }) - : undefined - } - onReconnect={(credentialId) => reconnect.mutate(credentialId, { onError })} - connectionPending={connect.isPending || reconnect.isPending} - connecting={ - connect.isPending && - (('optionId' in connect.variables && - connect.variables.optionId === option?.id) || - ('mcpServerId' in connect.variables && - connect.variables.mcpServerId === server?.id)) - } - connectionReady={ready} - reconnectAccountIds={reconnectAccountIds} - permissionAccountIds={permissionAccountIds} - /> + icon={} + title='Generic Secrets' + description={ + secrets.data?.source?.mode === 'organization' + ? 'Organization managed' + : 'Personal secrets' } + href={ + secrets.data?.source?.mode === 'member' + ? serializeIntegrationView(routes.memberSecrets, { q: navigationSearch }) + : href('secrets') + } + clickLabel='Open Generic Secrets integration' + navigable + /> + )} + {visible.map((entry) => ( + } + title={entry.name} + description={memberIntegrationStatus(entry)} + href={href(entry.id)} + clickLabel={`Open ${entry.name} integration`} + navigable /> - ) - })} - {!visible.length && - !showSecrets && - !assistantAccountOptions(data, search).visible.length && - loadedPolicies && - secrets.data && - query && ( - No matching integrations + ))} + {!visible.length && !showSecrets && policies.isSuccess && secrets.isSuccess && ( + + {query ? 'No matching integrations' : 'No integrations available'} + )} -
-
+
+ )} + ) } diff --git a/apps/sim/app/o/[organizationId]/integrations/search-params.ts b/apps/sim/app/o/[organizationId]/integrations/search-params.ts index ea4bdcb4477..b1d784d7f7d 100644 --- a/apps/sim/app/o/[organizationId]/integrations/search-params.ts +++ b/apps/sim/app/o/[organizationId]/integrations/search-params.ts @@ -1,4 +1,16 @@ -import { createLoader, parseAsString } from 'nuqs/server' +import { createLoader, createSerializer, parseAsString } from 'nuqs/server' +import { organizationPageParsers } from '@/app/o/[organizationId]/components/organization-page/search-params' + +export const integrationViewParsers = { + integration: parseAsString, + account: parseAsString, + tools: parseAsString.withDefault(''), +} as const + +export const serializeIntegrationView = createSerializer({ + ...organizationPageParsers, + ...integrationViewParsers, +}) export const integrationConnectionParams = { connectorType: parseAsString.withDefault(''), diff --git a/apps/sim/app/o/[organizationId]/integrations/secrets/page.tsx b/apps/sim/app/o/[organizationId]/integrations/secrets/page.tsx index d7801951208..083ca5c6423 100644 --- a/apps/sim/app/o/[organizationId]/integrations/secrets/page.tsx +++ b/apps/sim/app/o/[organizationId]/integrations/secrets/page.tsx @@ -1,13 +1,27 @@ import type { Metadata } from 'next' +import { createLoader, type SearchParams } from 'nuqs/server' import { OrganizationSecretsPage } from '@/components/secrets/organization-secrets-page' +import { organizationRoutes } from '@/lib/navigation/paths' +import { organizationPageParsers } from '@/app/o/[organizationId]/components/organization-page/search-params' +import { serializeIntegrationView } from '@/app/o/[organizationId]/integrations/search-params' export const metadata: Metadata = { title: 'Generic Secrets' } interface MemberSecretsPageProps { params: Promise<{ organizationId: string }> + searchParams: Promise } -export default async function Page({ params }: MemberSecretsPageProps) { +const loadSearch = createLoader(organizationPageParsers) + +export default async function Page({ params, searchParams }: MemberSecretsPageProps) { const { organizationId } = await params - return + const { q } = await loadSearch(searchParams) + return ( + + ) } diff --git a/apps/sim/app/o/[organizationId]/integrations/utils.ts b/apps/sim/app/o/[organizationId]/integrations/utils.ts index 061bf684808..ac6c0719e2e 100644 --- a/apps/sim/app/o/[organizationId]/integrations/utils.ts +++ b/apps/sim/app/o/[organizationId]/integrations/utils.ts @@ -1,7 +1,17 @@ +import type { ComponentType } from 'react' +import type { SearchIntegrationStatus } from '@/lib/api/contracts/knowledge/search-integrations' import type { OrganizationAccountsSettings } from '@/lib/api/contracts/organization-accounts' -import { getCredentialGroupProviderService } from '@/lib/credential-groups/providers' +import { assistantSearchSourceForProvider } from '@/lib/assistant-actions/providers' +import { + findCredentialGroupProviderFromProviderId, + getCredentialGroupProviderId, + getCredentialGroupProviderService, +} from '@/lib/credential-groups/providers' +import { hasSlackSearchUserScopes } from '@/lib/credential-groups/slack-managed-user-scopes' +import { LIVE_SEARCH_SCOPE_FIELDS } from '@/lib/sim-search/live/policy-schema' import { LIVE_SEARCH_SOURCE_TYPES, + liveSearchMcpConnector, liveSearchMemberAccountProvider, } from '@/lib/sim-search/live/source-catalog' @@ -39,3 +49,205 @@ export function assistantAccountOptions(data: OrganizationAccountsSettings, sear ) return { providers, configured, visible } } + +export interface MemberIntegration { + id: string + provider: string + name: string + icon: ComponentType<{ className?: string }> + accounts: MemberIntegrationAccount[] + permissionAccountIds: string[] + reconnectAccountIds: string[] + connectionTarget?: { optionId: string } | { mcpServerId: string } + ready: boolean + managed?: boolean + description?: string +} + +type MemberIntegrationAccount = + | NonNullable[number] + | NonNullable[number] + +/** One member inventory, preserving native grant and managed MCP server identities. */ +export function memberIntegrationEntries( + data: OrganizationAccountsSettings, + policies: SearchIntegrationStatus[] | undefined +): MemberIntegration[] { + const group = data.credentialGroup + const approvals = new Map(policies?.map((policy) => [policy.connectorType, policy])) + const permissionIds = new Set( + (data.viewerAccounts ?? []) + .filter((account) => { + const provider = findCredentialGroupProviderFromProviderId(account.providerId) + return provider !== null && data.assistantProviders.includes(provider) + }) + .map((account) => account.credentialId) + ) + const mcpProviders = new Map( + group?.mcpServers.map((server) => [server.id, server.managedConnectorId]) + ) + const entries: MemberIntegration[] = [] + for (const [provider, meta] of LIVE_SEARCH_SOURCE_TYPES) { + const memberProvider = + provider === 'slack' ? 'slack' : liveSearchMemberAccountProvider(provider) + const mcp = liveSearchMcpConnector(provider) + const accounts: MemberIntegrationAccount[] = mcp + ? (data.viewerMcpAccounts ?? []).filter( + (account) => mcpProviders.get(account.mcpServerId) === provider + ) + : (data.viewerAccounts ?? []).filter( + (account) => + findCredentialGroupProviderFromProviderId(account.providerId) === memberProvider + ) + const approval = approvals.get(provider) + const available = + (provider !== 'hubspot' && provider !== 'zoom') || + data.availableMcpConnectors.includes(provider) + const configured = + group?.options.some((option) => option.provider === memberProvider) || + group?.mcpServers.some((server) => server.managedConnectorId === provider) + if ( + !LIVE_SEARCH_SCOPE_FIELDS[provider] || + (!accounts.length && + !configured && + (approval?.available === false || !available || !approval?.approved)) + ) + continue + const options = + group?.options.filter( + (option) => + option.provider === memberProvider && + option.status === 'active' && + option.configurationStatus === 'ready' && + (provider !== 'slack' || + (option.provider === 'slack' && hasSlackSearchUserScopes(option.requiredScopes))) + ) ?? [] + const servers = mcp + ? (group?.mcpServers.filter( + (server) => server.managedConnectorId === provider && server.enabled + ) ?? []) + : [] + const option = options.find( + (candidate) => + !accounts.some((account) => 'optionId' in account && account.optionId === candidate.id) + ) + const server = servers.find( + (candidate) => + !accounts.some( + (account) => 'mcpServerId' in account && account.mcpServerId === candidate.id + ) + ) + const ready = + (mcp + ? available + : memberProvider !== null && data.availableProviders.includes(memberProvider)) && + approval?.available !== false && + group?.status === 'active' && + (options.length > 0 || servers.length > 0) && + approval?.approved === true && + available + const description = + provider === 'gitlab' + ? 'Access follows project permissions' + : !policies + ? undefined + : approval?.available === false + ? 'Currently unavailable' + : !approval?.approved + ? 'Disabled by your organization' + : group && group.status !== 'active' + ? 'Connections are paused by your organization' + : !ready + ? 'Not configured' + : approval.policy?.accessMode === 'service_account' + ? 'Selected resources you can access' + : 'All accessible content' + entries.push({ + id: `source:${provider}`, + provider, + name: meta.name, + icon: meta.icon, + accounts, + ready, + managed: provider === 'gitlab', + description, + permissionAccountIds: accounts + .filter((account) => permissionIds.has(account.credentialId)) + .map((account) => account.credentialId), + reconnectAccountIds: ready + ? accounts + .filter((account) => + 'optionId' in account + ? options.some((candidate) => candidate.id === account.optionId) + : servers.some((candidate) => candidate.id === account.mcpServerId) + ) + .map((account) => account.credentialId) + : [], + connectionTarget: server + ? { mcpServerId: server.id } + : option + ? { optionId: option.id } + : undefined, + }) + } + const { providers, configured } = assistantAccountOptions(data, '') + for (const provider of new Set(configured.map((option) => option.provider))) { + const options = configured.filter((option) => option.provider === provider) + const accounts = (data.viewerAccounts ?? []).filter((account) => + options.some((option) => option.id === account.optionId) + ) + const source = assistantSearchSourceForProvider(getCredentialGroupProviderId(provider)) + const policy = source ? approvals.get(source) : undefined + const readyOptions = options.filter( + (option) => + group?.status === 'active' && + option.status === 'active' && + option.configurationStatus === 'ready' && + providers.includes(provider) && + data.availableProviders.includes(provider) && + (!source || (policy?.approved === true && policy.available !== false)) + ) + const target = readyOptions.find( + (option) => !accounts.some((account) => account.optionId === option.id) + ) + const service = getCredentialGroupProviderService(provider) + entries.push({ + id: `app:${provider}`, + provider, + name: service.name, + icon: service.icon, + accounts, + ready: readyOptions.length > 0, + description: + source && !policies + ? undefined + : readyOptions.length + ? undefined + : 'Connections unavailable', + connectionTarget: target ? { optionId: target.id } : undefined, + permissionAccountIds: accounts + .filter((account) => permissionIds.has(account.credentialId)) + .map((account) => account.credentialId), + reconnectAccountIds: accounts + .filter((account) => readyOptions.some((option) => option.id === account.optionId)) + .map((account) => account.credentialId), + }) + } + return entries.sort((left, right) => left.name.localeCompare(right.name)) +} + +export function memberIntegrationStatus(entry: MemberIntegration) { + if (entry.managed) return 'Organization managed' + if (!entry.ready) return entry.description ?? 'Checking availability' + if ( + entry.accounts.some( + (account) => + account.status === 'needs_reauth' && + entry.reconnectAccountIds.includes(account.credentialId) + ) + ) + return 'Reconnect needed' + if (entry.accounts.length) + return entry.accounts.length === 1 ? '1 account' : `${entry.accounts.length} accounts` + return 'Not connected' +} diff --git a/apps/sim/app/o/[organizationId]/search/search-params.ts b/apps/sim/app/o/[organizationId]/search/search-params.ts index b0bc0b3c71a..40faaad7f1f 100644 --- a/apps/sim/app/o/[organizationId]/search/search-params.ts +++ b/apps/sim/app/o/[organizationId]/search/search-params.ts @@ -2,7 +2,7 @@ import { parseAsString, parseAsStringLiteral } from 'nuqs/server' export const organizationSearchParsers = { q: parseAsString.withDefault(''), - mode: parseAsStringLiteral(['search', 'assistant']).withDefault('search'), + mode: parseAsStringLiteral(['search', 'assistant']), } as const /** A query is a filter-like view change, not navigation: replace, and clear when empty. */ diff --git a/apps/sim/app/o/[organizationId]/search/search.tsx b/apps/sim/app/o/[organizationId]/search/search.tsx index 90b9bf6dc1c..6eb1813c337 100644 --- a/apps/sim/app/o/[organizationId]/search/search.tsx +++ b/apps/sim/app/o/[organizationId]/search/search.tsx @@ -1,16 +1,17 @@ 'use client' -import { lazy, Suspense, useEffect, useRef } from 'react' -import { Chip, ChipSwitch, ComposerActionButton } from '@sim/emcn' +import { lazy, Suspense, useCallback, useEffect, useRef, useState, useTransition } from 'react' +import { Chip, ComposerActionButton, cn } from '@sim/emcn' import { ArrowUp, Plus, Search, Sparkles, StopFilled } from '@sim/emcn/icons' +import { generateId } from '@sim/utils/id' import { useIsFetching, useQueryClient } from '@tanstack/react-query' import { usePathname, useRouter } from 'next/navigation' import { useQueryStates } from 'nuqs' -import { HEADER_ACTION_CLUSTER, PAGE_HEADER_BAR } from '@/components/page-header-bar' +import { HEADER_ACTION_CLUSTER } from '@/components/page-header-bar' import type { WorkspaceSearchFilters } from '@/lib/api/contracts/knowledge' import { resourceScopeKey } from '@/lib/core/resource-scope' -import { MothershipHandoffStorage } from '@/lib/core/utils/browser-storage' import { organizationRoutes } from '@/lib/navigation/paths' +import type { OrganizationSummaryRequest } from '@/app/o/[organizationId]/components/organization-conversation' import { SearchInputBar } from '@/app/o/[organizationId]/components/search-input-bar' import { SearchLandingHistory } from '@/app/o/[organizationId]/components/search-landing-history' import { useOrganizationContext } from '@/app/o/[organizationId]/providers/organization-provider' @@ -20,6 +21,7 @@ import { } from '@/app/o/[organizationId]/search/search-params' import { SearchResultsView } from '@/app/o/[organizationId]/search/search-results-view' import { useSearchHistoryActions } from '@/app/workspace/[workspaceId]/home/components/message-content/components/source-history-context' +import { RESOURCE_HEADER_CLASSES } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-tabs/resource-tab-controls' import { MicButton } from '@/app/workspace/[workspaceId]/home/components/user-input/components/mic-button/mic-button' import { MicrophonePermissionHelp } from '@/app/workspace/[workspaceId]/home/components/user-input/components/microphone-permission-help/microphone-permission-help' import { HomeFallback } from '@/app/workspace/[workspaceId]/home/home-fallback' @@ -167,24 +169,43 @@ function OrganizationSearchContent({ userId, chatId }: OrganizationSearchProps) organizationSearchUrlKeys ) const activeMode = - mothershipAvailable && (hasConversation || mode === 'assistant') ? 'assistant' : 'search' + mothershipAvailable && (mode ?? (hasConversation ? 'assistant' : 'search')) === 'assistant' + ? 'assistant' + : 'search' + const [assistantOpened, setAssistantOpened] = useState(activeMode === 'assistant') + const [conversationInstance, setConversationInstance] = useState(0) + const [isStartingNew, startNewTransition] = useTransition() + const [summaries, setSummaries] = useState([]) + const consumeSummary = useCallback( + (id: string) => setSummaries((current) => current.filter((request) => request.id !== id)), + [] + ) const changeMode = (next: 'search' | 'assistant') => { - if (hasConversation) { - const params = new URLSearchParams() - if (next === 'assistant') params.set('mode', 'assistant') - if (q) params.set('q', q) - router.push(`${routes.search}${params.size ? `?${params}` : ''}`) + if (next === 'assistant') setAssistantOpened(true) + void setParams({ mode: next }, { history: 'push' }) + } + const startNew = () => { + setSummaries([]) + const { clearDraft } = useMothershipDraftsStore.getState() + const scope = `${userId}:organization:${organization.id}` + if (activeMode === 'assistant') { + clearDraft(`${scope}:search-assistant`) } else { - void setParams({ mode: next }) + clearDraft(`${scope}:search`) + clearDraft(`${scope}:search:query:`) } + startNewTransition(() => { + setConversationInstance((current) => current + 1) + router.push(activeMode === 'assistant' ? `${routes.search}?mode=assistant` : routes.search, { + scroll: false, + }) + }) } const summarize = (message: string, assistantSearch: WorkspaceSearchFilters) => { - const stored = MothershipHandoffStorage.store( - { message, requestMode: 'assistant', assistantSearch }, - { organizationId: organization.id } - ) - if (stored) void setParams({ mode: 'assistant' }) + setSummaries((current) => [...current, { id: generateId(), message, assistantSearch }]) + changeMode('assistant') } + const submit = (draft: string) => { const next = draft.trim() if (!next) return @@ -201,38 +222,79 @@ function OrganizationSearchContent({ userId, chatId }: OrganizationSearchProps) void setParams({ q: next }) } } + const newLabel = activeMode === 'assistant' ? 'New chat' : 'New search' + const header = ( + <> + + {(hasConversation || (activeMode === 'search' && q.trim())) && ( + + {newLabel} + New + + )} + + ) return ( -
-
-
- {mothershipAvailable ? ( - - ) : ( - Search +
+
+ {(assistantOpened || hasConversation || activeMode === 'assistant') && + mothershipAvailable && ( +
+ }> + + +
)} -
- {hasConversation && ( - changeMode('search')}> - New search - - )} -
-
- {activeMode === 'assistant' ? ( - }> - - - ) : ( - } - query={q.trim()} - onSummarize={mothershipAvailable ? summarize : undefined} - /> + {activeMode === 'search' && ( + <> +
+ {header} +
+
+ + } + query={q.trim()} + onSummarize={mothershipAvailable ? summarize : undefined} + /> +
+ )}
diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/chat-panel-layout.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/chat-panel-layout.tsx index 29a40a09990..23ceefc8305 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/chat-panel-layout.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/chat-panel-layout.tsx @@ -13,6 +13,7 @@ import { RESOURCE_HEADER_CLASSES } from '@/app/workspace/[workspaceId]/home/comp interface ChatPanelLayoutProps { children: ReactNode + header?: ReactNode panel: ReactNode collapsed: boolean label: string @@ -27,6 +28,7 @@ interface ChatPanelLayoutProps { /** Shared resize handle and collapse control for resources and Search results. */ export function ChatPanelLayout({ children, + header, panel, collapsed, label, @@ -48,7 +50,15 @@ export function ChatPanelLayout({ RESOURCE_HEADER_CLASSES.layout )} > -
{children}
+
+ {header &&
{header}
} + {children} +
{!collapsed && (
panel: ReturnType children: ReactNode + header?: ReactNode onSummarize?: (message: string, filters: WorkspaceSearchFilters) => void } @@ -33,6 +34,7 @@ export function ChatResourcePanel({ chat, panel, children, + header, onSummarize, }: ChatResourcePanelProps) { useBrowserTabResources(panel.desktopTabResourceOptions) @@ -71,6 +73,7 @@ export function ChatResourcePanel({ ) return ( + reviewedToolIds?: ReadonlySet /** Supplies tool behavior without coupling the group layout to the block registry. */ ToolCallComponent: ComponentType renderBrowserTakeover?: (reason: string) => ReactNode @@ -117,6 +119,8 @@ export function AgentGroupView({ ToolCallComponent, renderBrowserTakeover, liveIndicator, + standaloneToolIds, + reviewedToolIds, }: AgentGroupViewProps) { const AgentIcon = getAgentIcon(agentName) const isMainAgent = agentName === 'mothership' @@ -148,7 +152,7 @@ export function AgentGroupView({ const [manualExpanded, setManualExpanded] = useState(defaultExpanded) const [expandedTakeoverId, setExpandedTakeoverId] = useState(null) - const pendingInteraction = hasPendingInteraction(items) + const pendingInteraction = hasPendingInteraction(items, false, reviewedToolIds) /** Blocking interactions override manual collapse so the user can resume the turn. */ const expanded = pendingInteraction || @@ -161,12 +165,16 @@ export function AgentGroupView({ : getLaneLiveIndicator( isMainAgent ? { + standaloneToolIds, + reviewedToolIds, kind: 'main', parts: [items], isActive: isStreaming, isOpen: isStreaming && isLaneOpen, } : { + standaloneToolIds, + reviewedToolIds, kind: 'subagent', parts: [items], isActive: isStreaming && isWorking, @@ -246,6 +254,8 @@ export function AgentGroupView({ return ( @@ -13,11 +16,54 @@ function renderBrowserTakeover(reason: string) { /** Workspace adapter retains permission, handoff, and integration lookup behavior. */ export function AgentGroup(props: AgentGroupProps) { + const layout = useAssistantActionLayout() + const lifted: ToolCallData[] = [] + const items = liftNestedActions( + props.items, + layout.standaloneToolIds, + props.agentName !== 'mothership', + lifted + ) return ( - + <> + + {lifted.length > 0 && ( +
+ {lifted.map((tool) => ( + + ))} +
+ )} + ) } + +/** A nested approval or receipt stays outside its agent's collapsible history. */ +function liftNestedActions( + items: AgentGroupItem[], + ids: ReadonlySet, + includeOwn: boolean, + lifted: ToolCallData[] +): AgentGroupItem[] { + if (!ids.size) return items + return items.flatMap((item): AgentGroupItem[] => { + if (item.type === 'tool' && includeOwn && ids.has(item.data.id)) { + lifted.push(item.data) + return [] + } + if (item.type === 'agent_group') + return [ + { + ...item, + group: { ...item.group, items: liftNestedActions(item.group.items, ids, true, lifted) }, + }, + ] + return [item] + }) +} diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts index 1d40da46ba6..9b124caa1e8 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts @@ -13,17 +13,22 @@ import { needsToolInput } from '@/app/workspace/[workspaceId]/home/components/me import { type ToolCallData, ToolCallStatus } from '@/app/workspace/[workspaceId]/home/types' /** Keep answers and interactions in the transcript, outside collapsible tool history. */ -function isStandaloneItem(item: AgentGroupItem): boolean { +function isStandaloneItem(item: AgentGroupItem, standaloneToolIds?: ReadonlySet): boolean { return ( item.type !== 'tool' || + standaloneToolIds?.has(item.data.id) || needsToolInput(item.data) || item.data.toolName === RETIRED_BROWSER_REQUEST_TAKEOVER_ID ) } /** Interactions render as their own cards, so they never hold a lane's live indicator. */ -function canHoldIndicator(tool: ToolCallData): boolean { - return !needsToolInput(tool) && tool.toolName !== RETIRED_BROWSER_REQUEST_TAKEOVER_ID +function canHoldIndicator(tool: ToolCallData, standaloneToolIds?: ReadonlySet): boolean { + return ( + !standaloneToolIds?.has(tool.id) && + !needsToolInput(tool) && + tool.toolName !== RETIRED_BROWSER_REQUEST_TAKEOVER_ID + ) } /** A run of consecutive calls the main lane renders together, as one activity group. */ @@ -40,11 +45,14 @@ export type MainLaneEntry = * including search and document reads, and an interaction stands * on its own and closes the run before it. */ -export function splitMainLane(items: AgentGroupItem[]): MainLaneEntry[] { +export function splitMainLane( + items: AgentGroupItem[], + standaloneToolIds?: ReadonlySet +): MainLaneEntry[] { const entries: MainLaneEntry[] = [] let run: ActivityRun | undefined for (const [index, item] of items.entries()) { - if (item.type === 'tool' && !isStandaloneItem(item)) { + if (item.type === 'tool' && !isStandaloneItem(item, standaloneToolIds)) { if (!run) { run = { tools: [] } entries.push({ type: 'run', run }) @@ -91,22 +99,26 @@ export function getActiveBrowserTakeover(items: AgentGroupItem[]): ActiveBrowser */ export function hasPendingInteraction( items: AgentGroupItem[], - includeBrowserTakeover = false + includeBrowserTakeover = false, + reviewedToolIds?: ReadonlySet ): boolean { return ( (includeBrowserTakeover && getActiveBrowserTakeover(items) !== null) || items.some((item) => item.type === 'tool' - ? needsToolInput(item.data) + ? needsToolInput(item.data) && !reviewedToolIds?.has(item.data.id) : item.type === 'agent_group' && - hasPendingInteraction(item.group.items, includeBrowserTakeover) + hasPendingInteraction(item.group.items, includeBrowserTakeover, reviewedToolIds) ) ) } /** The lane, or a lane nested in it, is waiting on the user rather than on work. */ -function isLaneAwaitingUser(items: AgentGroupItem[]): boolean { - return hasPendingInteraction(items, true) +function isLaneAwaitingUser( + items: AgentGroupItem[], + reviewedToolIds?: ReadonlySet +): boolean { + return hasPendingInteraction(items, true, reviewedToolIds) } /** @@ -130,6 +142,8 @@ export function isLaneWorking( export type LaneLiveIndicator = { type: 'call'; tool: ToolCallData } | { type: 'narration' } export interface LaneActivityInput { + standaloneToolIds?: ReadonlySet + reviewedToolIds?: ReadonlySet kind: 'main' | 'subagent' /** The lane's items; the main lane passes one part per transcript segment, in order. */ parts: AgentGroupItem[][] @@ -140,8 +154,11 @@ export interface LaneActivityInput { } /** The latest call of the main lane's last run, which owns the trailing gap. */ -function getMainTrailingCall(items: AgentGroupItem[]): ToolCallData | undefined { - const last = splitMainLane(items).at(-1) +function getMainTrailingCall( + items: AgentGroupItem[], + standaloneToolIds?: ReadonlySet +): ToolCallData | undefined { + const last = splitMainLane(items, standaloneToolIds).at(-1) return last?.type === 'run' ? last.run.tools.at(-1) : undefined } @@ -154,9 +171,14 @@ export function getLaneLiveIndicator({ parts, isActive, isOpen, + standaloneToolIds, + reviewedToolIds, }: LaneActivityInput): LaneLiveIndicator | undefined { - if (!isActive || parts.some(isLaneAwaitingUser)) return undefined - const calls = parts.flatMap(collectGroupTools).filter(canHoldIndicator) + if (!isActive || parts.some((items) => isLaneAwaitingUser(items, reviewedToolIds))) + return undefined + const calls = parts + .flatMap(collectGroupTools) + .filter((tool) => canHoldIndicator(tool, standaloneToolIds)) const running = getNewestRunningTool(calls) if (running) return { type: 'call', tool: running } if (!isOpen) return undefined @@ -165,7 +187,8 @@ export function getLaneLiveIndicator({ ? { type: 'narration' } : undefined } - const latest = kind === 'main' ? getMainTrailingCall(parts.at(-1) ?? []) : calls.at(-1) + const latest = + kind === 'main' ? getMainTrailingCall(parts.at(-1) ?? [], standaloneToolIds) : calls.at(-1) return latest?.status === ToolCallStatus.success ? { type: 'call', tool: latest } : undefined } @@ -217,12 +240,17 @@ export interface TurnLiveIndicators { * activity changes split it into segments, but it is one lane with one * indicator. */ -export function getTurnLiveIndicators(lanes: TurnLane[], isStreaming: boolean): TurnLiveIndicators { +export function getTurnLiveIndicators( + lanes: TurnLane[], + isStreaming: boolean, + layout: Pick = {} +): TurnLiveIndicators { const byLane = new Map() - const isAwaiting = lanes.some((lane) => isLaneAwaitingUser(lane.items)) + const isAwaiting = lanes.some((lane) => isLaneAwaitingUser(lane.items, layout.reviewedToolIds)) if (!isStreaming) return { isAwaitingUser: isAwaiting, byLane } const mainParts = lanes.filter((lane) => lane.agentName === 'mothership') const mainIndicator = getLaneLiveIndicator({ + ...layout, kind: 'main', parts: mainParts.map((lane) => lane.items), isActive: true, @@ -234,6 +262,7 @@ export function getTurnLiveIndicators(lanes: TurnLane[], isStreaming: boolean): lane.agentName === 'mothership' ? mainIndicator : getLaneLiveIndicator({ + ...layout, kind: 'subagent', parts: [lane.items], isActive: working, diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/main-agent-activity.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/main-agent-activity.tsx index f0d9da25cb3..e1972211631 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/main-agent-activity.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/main-agent-activity.tsx @@ -8,6 +8,7 @@ import { ToolActivityGroup } from '@/app/workspace/[workspaceId]/home/components import type { ToolCallItemProps } from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item' interface MainAgentActivityProps { + standaloneToolIds?: ReadonlySet activity?: ToolActivity items: AgentGroupItem[] ToolCallComponent: ComponentType @@ -31,8 +32,9 @@ export function MainAgentActivity({ renderItem, autoScrollActivity, liveToolId, + standaloneToolIds, }: MainAgentActivityProps) { - const entries = splitMainLane(items) + const entries = splitMainLane(items, standaloneToolIds) const runActivity = groupActivity && !isAgentGroupResolved(items) ? omit(groupActivity, ['completedTitle']) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.tsx index 2790d36178f..9278ef7ff1b 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.tsx @@ -188,5 +188,15 @@ export function ToolCallItem({ ), } - return renderStatus ? renderStatus(activity) : + const fallback = renderStatus ? renderStatus(activity) : + return toolCallId && getToolMetadata(toolName)?.assistant ? ( + + ) : ( + fallback + ) } diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx index 5be65281a6b..753becb41e9 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx @@ -13,6 +13,7 @@ import { import { cn } from '@sim/emcn' import { CircleStop } from '@sim/emcn/icons' import { isPlainRecord } from '@sim/utils/object' +import { useAssistantActionLayout } from '@/components/assistant-actions' import type { ToolActivity } from '@/lib/mothership/generated/protocol' import { PrepareFileEdit, Read as ReadTool } from '@/lib/mothership/generated/tool-catalog-v1' import type { TaskBlockInfo } from '@/lib/mothership/request/types' @@ -895,11 +896,13 @@ export function assistantMessageHasRenderableContent( /** The turn's live indicators, decided once by {@link getTurnLiveIndicators} for every lane. */ function getMessageLiveIndicators( segments: MessageSegment[], - isStreaming: boolean + isStreaming: boolean, + actionLayout: ReturnType ): TurnLiveIndicators { return getTurnLiveIndicators( segments.flatMap((segment) => (segment.type === 'agent_group' ? [segment] : [])), - isStreaming + isStreaming, + actionLayout ) } @@ -1042,9 +1045,10 @@ function MessageContentInner({ ) const visibleStreamActivityKey = getVisibleStreamActivityKey(segments) /** Decided once per parse, not on every idle-timer or text-reveal render. */ + const actionLayout = useAssistantActionLayout() const liveIndicators = useMemo( - () => getMessageLiveIndicators(segments, isStreaming), - [segments, isStreaming] + () => getMessageLiveIndicators(segments, isStreaming, actionLayout), + [segments, isStreaming, actionLayout] ) // Every visible stream update restarts the quiet-period clock. A layout diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx index e382f6ae427..661ec14641a 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx @@ -114,6 +114,7 @@ interface MothershipChatProps { onWorkspaceResourceSelect?: (resource: WorkspaceResourceRef) => void draftScopeKey?: string layout?: 'mothership-view' | 'copilot-view' + reserveResourceHeader?: boolean initialScrollBlocked?: boolean animateInput?: boolean onInputAnimationEnd?: () => void @@ -402,6 +403,7 @@ export function MothershipChat({ onWorkspaceResourceSelect, draftScopeKey, layout = 'mothership-view', + reserveResourceHeader = true, initialScrollBlocked = false, animateInput = false, onInputAnimationEnd, @@ -874,6 +876,17 @@ export function MothershipChat({ }, [lastUserMessageId, lastIndex, isSending, initialScrollBlocked, virtualizer, find.isOpen]) const virtualItems = virtualizer.getVirtualItems() + const receiptQueryOwners = new Map() + const mountedReceiptMessages = new Map() + for (const item of virtualItems) { + const message = messages[item.index] + if (message.streamId) { + receiptQueryOwners.set(message.streamId, message.id) + const ids = mountedReceiptMessages.get(message.streamId) ?? [] + ids.push(message.id) + mountedReceiptMessages.set(message.streamId, ids) + } + } return ( - + {msg.role === 'user' ? ( interactionPairing.hiddenUserByIndex[index] ? null : msg.origin ? ( +export function HomeFallback({ header }: HomeFallbackProps) { + return ( +
+ {header &&
{header}
} +
+ ) } diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts index 776c10f7535..f430ec1a481 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts @@ -1,19 +1,34 @@ import { organizationRoutes } from '@/lib/navigation/paths' -import { resourceParam } from '@/app/workspace/[workspaceId]/home/search-params' +import { organizationSearchParsers } from '@/app/o/[organizationId]/search/search-params' +import { + resourceParam, + searchFilterParsers, +} from '@/app/workspace/[workspaceId]/home/search-params' import type { ChatRequestMode } from '@/app/workspace/[workspaceId]/home/types' -/** Preserve the selected resource when a new conversation receives its chat URL. */ +/** Preserve resource and Search context when a new conversation receives its chat URL. */ export function chatUrl( owner: string | { organizationId: string }, chatId: string, mode?: ChatRequestMode ): string { + const routes = typeof owner === 'object' ? organizationRoutes(owner.organizationId) : null const current = new URLSearchParams(window.location.search) const carried = new URLSearchParams() const resource = current.get(resourceParam.key) if (resource) carried.set(resourceParam.key, resource) + if (typeof owner === 'object' && mode === 'assistant') { + for (const key of Object.keys({ ...organizationSearchParsers, ...searchFilterParsers })) { + const value = current.get(key) + if (value) carried.set(key, value) + } + if ( + organizationSearchParsers.mode.parse(current.get('mode') ?? '') === null && + window.location.pathname === routes?.search + ) + carried.set('mode', 'search') + } const search = carried.toString() - const routes = typeof owner === 'object' ? organizationRoutes(owner.organizationId) : null const path = routes ? mode === 'assistant' ? routes.searchChat(chatId) diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/message-reconcile.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/message-reconcile.ts index d5d895f2857..47a3250fac4 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/message-reconcile.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/message-reconcile.ts @@ -128,6 +128,7 @@ function toRawPersistedContentBlockBody(block: ContentBlock): PersistedContentBl export function buildAssistantSnapshotMessage(params: { id: string + streamId?: string content: string contentBlocks: ContentBlock[] requestId?: string @@ -138,6 +139,7 @@ export function buildAssistantSnapshotMessage(params: { return normalizeMessage({ id: params.id, + ...(params.streamId ? { streamId: params.streamId } : {}), role: 'assistant', content: params.content, timestamp: new Date().toISOString(), diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts index 55103f21c02..7c8cee48915 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts @@ -41,6 +41,7 @@ export function handleSessionEvent(ctx: StreamLoopContext, parsed: SessionEvent) const activeStreamId = deps.streamIdRef.current if (userMsg && activeStreamId) { const assistantMessage = deps.buildAssistantSnapshotMessage({ + streamId: activeStreamId, id: deps.activeTurnRef.current?.assistantMessageId ?? getLiveAssistantMessageId(activeStreamId), diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts index 691393fddaf..241dde16c46 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts @@ -158,6 +158,7 @@ export interface StreamLoopDeps { buildAssistantSnapshotMessage: (params: { id: string + streamId?: string content: string contentBlocks: ContentBlock[] requestId?: string @@ -292,6 +293,7 @@ export function createStreamLoopContext(deps: StreamLoopDeps): StreamLoopContext const snapshot: Partial = { content: modelContent, contentBlocks: modelBlocks, + ...(deps.streamIdRef.current ? { streamId: deps.streamIdRef.current } : {}), } if (state.streamRequestId) snapshot.requestId = state.streamRequestId deps.setPendingMessages((prev) => { @@ -312,6 +314,7 @@ export function createStreamLoopContext(deps: StreamLoopDeps): StreamLoopContext const assistantMessage = deps.buildAssistantSnapshotMessage({ id: deps.assistantId, + ...(deps.streamIdRef.current ? { streamId: deps.streamIdRef.current } : {}), content: modelContent, contentBlocks: modelBlocks, ...(state.streamRequestId ? { requestId: state.streamRequestId } : {}), diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index d210de4c57e..60f6f83debf 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -3489,6 +3489,7 @@ export function useChat( if (assistantId && activeChatId) { const snapshot = buildAssistantSnapshotMessage({ id: assistantId, + ...(streamIdRef.current ? { streamId: streamIdRef.current } : {}), content: streamingContentRef.current, contentBlocks: blocks, ...(streamRequestIdRef.current ? { requestId: streamRequestIdRef.current } : {}), @@ -3690,6 +3691,7 @@ export function useChat( })) const cachedUserMsg: PersistedMessage = { id: userMessageId, + streamId: userMessageId, role: 'user' as const, requestMode: options?.requestMode ?? 'agent', content: message, @@ -3709,6 +3711,7 @@ export function useChat( const optimisticUserMessage: ChatMessage = { id: userMessageId, + streamId: userMessageId, role: 'user', requestMode: options?.requestMode ?? 'agent', content: message, @@ -3718,6 +3721,7 @@ export function useChat( } const optimisticAssistantMessage: ChatMessage = { id: assistantId, + streamId: userMessageId, role: 'assistant', requestMode: options?.requestMode ?? 'agent', content: '', @@ -3731,6 +3735,7 @@ export function useChat( const applyOptimisticSend = () => { const assistantSnapshot = buildAssistantSnapshotMessage({ id: assistantId, + streamId: userMessageId, content: '', contentBlocks: [], }) diff --git a/apps/sim/app/workspace/[workspaceId]/home/types.ts b/apps/sim/app/workspace/[workspaceId]/home/types.ts index 1997858ae44..e768743f4f2 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/types.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/types.ts @@ -194,6 +194,7 @@ export interface ChatMessageContext { export interface ChatMessage { id: string + streamId?: string role: 'user' | 'assistant' requestMode?: 'agent' | 'assistant' | 'plan' content: string diff --git a/apps/sim/components/assistant-actions/action-preview.tsx b/apps/sim/components/assistant-actions/action-preview.tsx new file mode 100644 index 00000000000..73dd143aa89 --- /dev/null +++ b/apps/sim/components/assistant-actions/action-preview.tsx @@ -0,0 +1,114 @@ +import { useId, useRef, useState } from 'react' +import { + Chip, + cn, + overflowFadeSizeClass, + scrollFadeAttributes, + scrollFadeClass, + useScrollEdges, +} from '@sim/emcn' +import { ChevronDown, ChevronRight } from '@sim/emcn/icons' +import { assistantActionPresentation } from '@/components/assistant-actions/presentation' +import type { AssistantActionsResponse } from '@/lib/api/contracts/assistant-actions' + +type ReviewField = AssistantActionsResponse['actions'][number]['fields'][number] + +interface ActionPreviewProps { + action: Pick + full?: boolean +} + +/** Readable content first; supplied secondary parameters remain inspectable. */ +export function ActionPreview({ action, full = false }: ActionPreviewProps) { + const [expanded, setExpanded] = useState(false) + const detailsId = useId() + const { targets, primary, details } = assistantActionPresentation(action) + return ( +
+ {targets.length > 0 && ( +
+ {targets.map((field) => ( +
+
{field.label}
+
+ {field.value} +
+
+ ))} +
+ )} + {primary.map((field, index) => ( + + ))} + {details.length > 0 && ( + <> + {!full && ( +
+ setExpanded(!expanded)} + > + Details + +
+ )} + {(expanded || full) && ( +
+ {details.map((field) => ( + + ))} +
+ )} + + )} +
+ ) +} + +interface PreviewFieldProps { + field: ReviewField + primary?: boolean + prominent?: boolean +} + +function PreviewField({ field, primary = false, prominent = false }: PreviewFieldProps) { + const scroll = useRef(null) + const edges = useScrollEdges(scroll) + let value = field.value + if (field.format === 'json') { + try { + value = JSON.stringify(JSON.parse(value), null, 2) + } catch {} + } + return ( +
+ {(!primary || field.format === 'json') && ( +
{field.label}
+ )} +
+
+ {value} +
+
+
+ ) +} diff --git a/apps/sim/components/assistant-actions/action-receipt.tsx b/apps/sim/components/assistant-actions/action-receipt.tsx new file mode 100644 index 00000000000..c6b39fadae4 --- /dev/null +++ b/apps/sim/components/assistant-actions/action-receipt.tsx @@ -0,0 +1,96 @@ +import { useState } from 'react' +import { Chip, cn, OverflowText } from '@sim/emcn' +import { ChevronDown, ChevronRight, ShieldCheck } from '@sim/emcn/icons' +import { ActionPreview } from '@/components/assistant-actions/action-preview' +import { assistantActionPresentation } from '@/components/assistant-actions/presentation' +import type { AssistantActionReceiptsResponse } from '@/lib/api/contracts/assistant-actions' +import { resolveCredentialDisplay } from '@/lib/integrations/credential-display' +import { InteractionCard } from '@/app/workspace/[workspaceId]/home/components/message-content/components/interaction-card' +import { BrandIcon } from '@/blocks/brand-icon' + +type ActionReceipt = AssistantActionReceiptsResponse['receipts'][number] + +const STATE_LABELS: Record = { + pending: 'Waiting for review', + approved: 'Approved', + running: 'Running', + succeeded: 'Completed', + cancelled: 'Cancelled', + failed: 'Failed', + uncertain: 'Outcome unknown', +} + +interface AssistantActionReceiptProps { + receipt: ActionReceipt +} + +/** Durable execution state and the exact approved fields, independent of transcript tool status. */ +export function AssistantActionReceipt({ receipt }: AssistantActionReceiptProps) { + const [expanded, setExpanded] = useState(false) + const presentation = assistantActionPresentation(receipt) + const display = receipt.account + ? resolveCredentialDisplay({ ...receipt.account, type: 'managed_oauth' }) + : undefined + return ( +
+ + {display?.icon ? ( + + ) : ( + + )} + {presentation.title} + + } + actions={ + setExpanded(!expanded)} + > + {STATE_LABELS[receipt.state]} + + } + > +
+ {!expanded && presentation.primary[0] && ( + + )} + {receipt.state === 'uncertain' && ( +

Check the app before retrying.

+ )} + {receipt.warning && ( +

+ {receipt.warning} +

+ )} + {expanded && ( + <> +

+ {receipt.account?.displayName ?? 'Account unavailable'} +

+ {receipt.detailsAvailable ? ( + + ) : ( +

+ Details are no longer available for this action. +

+ )} + + )} +
+
+
+ ) +} diff --git a/apps/sim/components/assistant-actions/index.ts b/apps/sim/components/assistant-actions/index.ts index f173ee786cc..3196a4f864e 100644 --- a/apps/sim/components/assistant-actions/index.ts +++ b/apps/sim/components/assistant-actions/index.ts @@ -2,5 +2,6 @@ export { AssistantActionReviewMessage, AssistantActionReviewProvider, AssistantActionReviewStatus, + useAssistantActionLayout, useHasAssistantActionReview, } from './review' diff --git a/apps/sim/components/assistant-actions/presentation.ts b/apps/sim/components/assistant-actions/presentation.ts new file mode 100644 index 00000000000..c023e4e2968 --- /dev/null +++ b/apps/sim/components/assistant-actions/presentation.ts @@ -0,0 +1,45 @@ +import type { AssistantActionsResponse } from '@/lib/api/contracts/assistant-actions' + +type PresentedAction = Pick< + AssistantActionsResponse['actions'][number], + 'toolId' | 'name' | 'fields' +> + +/** Display labels and preview fields only; model-facing tool definitions remain unchanged. */ +const PRESENTATIONS: Record = { + gmail_draft_v2: { title: 'Draft email', primary: ['subject', 'body'] }, + gmail_send_v2: { title: 'Send email', primary: ['subject', 'body'] }, + google_docs_create: { title: 'Create Google Doc', primary: ['title', 'content'] }, + google_docs_write: { title: 'Update Google Doc', primary: ['content'] }, + google_sheets_write_v2: { title: 'Update spreadsheet', primary: ['values'] }, + jira_add_comment: { title: 'Add Jira comment', primary: ['body'] }, + jira_create_sprint: { title: 'Create Jira sprint', primary: ['name', 'goal'] }, + jira_update: { title: 'Update Jira issue', primary: ['summary', 'description'] }, + jira_write: { title: 'Create Jira issue', primary: ['summary', 'description'] }, + microsoft_excel_write_v2: { title: 'Update Excel spreadsheet', primary: ['values', 'formulas'] }, + microsoft_teams_write_channel: { title: 'Send Teams message', primary: ['content'] }, + microsoft_teams_write_chat: { title: 'Send Teams message', primary: ['content'] }, + outlook_draft: { title: 'Draft email', primary: ['subject', 'body'] }, + outlook_send: { title: 'Send email', primary: ['subject', 'body'] }, + salesforce_create_task: { title: 'Create Salesforce task', primary: ['subject', 'description'] }, + salesforce_update_task: { title: 'Update Salesforce task', primary: ['subject', 'description'] }, + slack_message: { title: 'Send Slack message', primary: ['blocks', 'text'] }, +} + +export function assistantActionPresentation(action: PresentedAction) { + const presentation = PRESENTATIONS[action.toolId] + const fields = action.fields.filter((field) => field.value !== '') + const targets = fields.filter((field) => field.target) + const primary = presentation + ? presentation.primary.flatMap((name) => + fields.filter((field) => field.name === name && !field.target) + ) + : fields.filter((field) => !field.target).slice(0, 2) + const primaryNames = new Set(primary.map((field) => field.name)) + return { + title: presentation?.title ?? action.name, + targets, + primary, + details: fields.filter((field) => !field.target && !primaryNames.has(field.name)), + } +} diff --git a/apps/sim/components/assistant-actions/review.tsx b/apps/sim/components/assistant-actions/review.tsx index e91372b3a7a..f6f5c1df4c7 100644 --- a/apps/sim/components/assistant-actions/review.tsx +++ b/apps/sim/components/assistant-actions/review.tsx @@ -13,8 +13,14 @@ import { Chip, ChipInput, ChipTextarea, cn } from '@sim/emcn' import { ShieldCheck } from '@sim/emcn/icons' import { getErrorMessage } from '@sim/utils/errors' import { omit } from '@sim/utils/object' +import { ActionPreview } from '@/components/assistant-actions/action-preview' +import { AssistantActionReceipt } from '@/components/assistant-actions/action-receipt' +import { assistantActionPresentation } from '@/components/assistant-actions/presentation' import { ActivityStatus } from '@/components/ui/activity-status' -import type { AssistantActionsResponse } from '@/lib/api/contracts/assistant-actions' +import type { + AssistantActionReceiptsResponse, + AssistantActionsResponse, +} from '@/lib/api/contracts/assistant-actions' import { ASSISTANT_REVIEW_FIELD_MAX_CHARS } from '@/lib/assistant-actions/limits' import { resolveCredentialDisplay } from '@/lib/integrations/credential-display' import { getLiveAssistantMessageId } from '@/lib/mothership/chat/live-message-id' @@ -22,12 +28,17 @@ import { InteractionCard } from '@/app/workspace/[workspaceId]/home/components/m import { type ChatMessage, ToolCallStatus } from '@/app/workspace/[workspaceId]/home/types' import { BrandIcon } from '@/blocks/brand-icon' import { + useAssistantActionReceiptBatches, useAssistantActionReview, + useAssistantActionTurnReceipts, useDecideAssistantAction, + useRefreshAssistantActionReceipts, } from '@/hooks/queries/assistant-actions' import { getToolMetadata } from '@/tools/metadata' type ReviewAction = AssistantActionsResponse['actions'][number] +type Receipt = AssistantActionReceiptsResponse['receipts'][number] +type ReceiptBatchQuery = ReturnType[number]['query'] type ReviewEdits = Record }> type ReviewErrors = Record @@ -37,11 +48,24 @@ interface ReviewDrafts { errors: ReviewErrors } +interface ReviewTurn { + messageId: string + representedIds: Set + hasApprovalRows: boolean + writeIds: Set +} + interface ReviewContextValue { + organizationId: string + chatId: string + active: boolean + streamId: string | null + messageStreams: ReadonlyMap + messageReceiptIds: ReadonlyMap> + turns: ReadonlyMap query: ReturnType actions: ReviewAction[] byId: ReadonlyMap - assistantMessageId: string | null recoveryMessageId: string | null recoveryActions: ReviewAction[] hasApprovalRows: boolean @@ -58,6 +82,11 @@ interface ReviewContextValue { interface ReviewMessageContextValue { messageId: string + streamId?: string + receipts: ReadonlyMap + receiptQuery: ReturnType + receiptQueries: ReadonlyMap + layout: { standaloneToolIds: ReadonlySet; reviewedToolIds: ReadonlySet } submit: (actions: ReviewAction[], decision: 'allow' | 'skip', source: HTMLButtonElement) => void } @@ -65,6 +94,15 @@ const reviewContext = createContext(null) const reviewMessageContext = createContext(null) const pendingReviewContext = createContext(false) const EMPTY_ACTIONS: ReviewAction[] = [] +const EMPTY_ACTION_LAYOUT = { + standaloneToolIds: new Set(), + reviewedToolIds: new Set(), +} + +/** Keeps bound actions visible without changing ordinary tool activity or workspace chat. */ +export function useAssistantActionLayout() { + return useContext(reviewMessageContext)?.layout ?? EMPTY_ACTION_LAYOUT +} /** Lets the current turn yield its activity footer to pending review controls. */ export function useHasAssistantActionReview() { @@ -91,6 +129,7 @@ export function AssistantActionReviewProvider({ const inFlight = useRef(null) const query = useAssistantActionReview(organizationId, chatId ?? '', active, enabled) const mutation = useDecideAssistantAction(organizationId, chatId ?? '') + const refreshReceipts = useRefreshAssistantActionReceipts(organizationId, chatId ?? '') const [submitting, setSubmitting] = useState(false) const [drafts, setDrafts] = useState({ runId: null, edits: {}, errors: {} }) const actions = query.data?.actions ?? EMPTY_ACTIONS @@ -100,43 +139,64 @@ export function AssistantActionReviewProvider({ () => new Map(actions.map((action) => [action.toolCallId, action])), [actions] ) - const { assistantMessageId, recoveryMessageId, recoveryActions, hasApprovalRows } = - useMemo(() => { - if (!streamId) { - const hasApprovalRows = messages.some((message) => - message.contentBlocks?.some( - ({ toolCall }) => - toolCall?.status === ToolCallStatus.awaiting_approval && - getToolMetadata(toolCall.name)?.assistant + const { messageStreams, messageReceiptIds, turns } = useMemo(() => { + const messageReceiptIds = new Map>() + const messageStreams = new Map() + const turns = new Map() + for (const message of messages) { + messageReceiptIds.set( + message.id, + new Set( + message.contentBlocks?.flatMap(({ toolCall }) => + toolCall && + getToolMetadata(toolCall.name)?.assistant && + (getToolMetadata(toolCall.name)?.assistant?.effect === 'write' || + toolCall.status === ToolCallStatus.awaiting_approval) + ? [toolCall.id] + : [] ) ) - return { - assistantMessageId: null, - recoveryMessageId: hasApprovalRows ? null : (messages.at(-1)?.id ?? null), - recoveryActions: EMPTY_ACTIONS, - hasApprovalRows, - } + ) + const messageStreamId = + message.streamId ?? + (streamId && (message.id === streamId || message.id === getLiveAssistantMessageId(streamId)) + ? streamId + : undefined) + if (!messageStreamId) continue + messageStreams.set(message.id, messageStreamId) + const turn = turns.get(messageStreamId) ?? { + messageId: message.id, + representedIds: new Set(), + hasApprovalRows: false, + writeIds: new Set(), } - const messageId = getLiveAssistantMessageId(streamId) - const assistant = messages.find((message) => message.id === messageId) - const representedIds = new Set( - assistant?.contentBlocks?.flatMap(({ toolCall }) => + turn.messageId = message.id + for (const { toolCall } of message.contentBlocks ?? []) { + if (!toolCall || !getToolMetadata(toolCall.name)?.assistant) continue + turn.representedIds.add(toolCall.id) + if (getToolMetadata(toolCall.name)?.assistant?.effect === 'write') + turn.writeIds.add(toolCall.id) + if (toolCall.status === ToolCallStatus.awaiting_approval) turn.hasApprovalRows = true + } + turns.set(messageStreamId, turn) + } + return { messageStreams, messageReceiptIds, turns } + }, [messages, streamId]) + const currentTurn = streamId ? turns.get(streamId) : undefined + const hasApprovalRows = + currentTurn?.hasApprovalRows ?? + messages.some((message) => + message.contentBlocks?.some( + ({ toolCall }) => toolCall?.status === ToolCallStatus.awaiting_approval && getToolMetadata(toolCall.name)?.assistant - ? [toolCall.id] - : [] - ) ) - return { - assistantMessageId: messageId, - recoveryMessageId: assistant - ? messageId - : (messages.find((message) => message.role === 'user' && message.id === streamId)?.id ?? - null), - recoveryActions: actions.filter((action) => !representedIds.has(action.toolCallId)), - hasApprovalRows: representedIds.size > 0, - } - }, [actions, messages, streamId]) + ) + const recoveryMessageId = + currentTurn?.messageId ?? (hasApprovalRows ? null : (messages.at(-1)?.id ?? null)) + const recoveryActions = actions.filter( + (action) => !currentTurn?.representedIds.has(action.toolCallId) + ) useEffect(() => () => inFlight.current?.abort(), [runId]) @@ -224,6 +284,7 @@ export function AssistantActionReviewProvider({ } } } finally { + await refreshReceipts() if (inFlight.current === controller) { inFlight.current = null setSubmitting(false) @@ -239,7 +300,13 @@ export function AssistantActionReviewProvider({ query, actions, byId, - assistantMessageId, + organizationId, + chatId: chatId ?? '', + active, + streamId, + messageStreams, + messageReceiptIds, + turns, recoveryMessageId, recoveryActions, hasApprovalRows, @@ -259,17 +326,104 @@ export function AssistantActionReviewProvider({ interface AssistantActionReviewMessageProps { messageId: string + isReceiptQueryOwner: boolean + mountedReceiptTurnCount: number + mountedMessageIds: readonly string[] children: ReactNode } export function AssistantActionReviewMessage({ messageId, + isReceiptQueryOwner, + mountedReceiptTurnCount, + mountedMessageIds, children, }: AssistantActionReviewMessageProps) { const turn = useRef(null) const focusOrigin = useRef(null) const review = useContext(reviewContext) const submitting = review?.submitting ?? false + const streamId = review?.messageStreams.get(messageId) + const receiptQuery = useAssistantActionTurnReceipts({ + organizationId: review?.organizationId ?? '', + chatId: review?.chatId ?? '', + streamId: streamId ?? '', + active: Boolean(review?.active && review.streamId === streamId), + enabled: isReceiptQueryOwner, + mountedTurnCount: mountedReceiptTurnCount, + }) + const pagedReceipts = new Map( + receiptQuery.data?.pages + .flatMap((page) => page.receipts) + .map((receipt) => [receipt.toolCallId, receipt]) + ) + const receiptTurn = streamId ? review?.turns.get(streamId) : undefined + const candidates = new Set([ + ...mountedMessageIds.flatMap((id) => [...(review?.messageReceiptIds.get(id) ?? [])]), + ...(streamId && streamId === review?.streamId ? review.byId.keys() : []), + ]) + const receiptBatches = useAssistantActionReceiptBatches({ + organizationId: review?.organizationId ?? '', + chatId: review?.chatId ?? '', + streamId: streamId ?? messageId, + candidateIds: candidates, + coveredIds: new Set(pagedReceipts.keys()), + enabled: isReceiptQueryOwner && (!streamId || receiptQuery.isSuccess || receiptQuery.isError), + pageCount: receiptQuery.data?.pages.length ?? 1, + mountedTurnCount: mountedReceiptTurnCount, + }) + const receiptQueries = new Map( + receiptBatches.flatMap(({ ids, query }) => ids.map((id) => [id, query] as const)) + ) + const receipts = new Map([ + ...receiptBatches + .flatMap(({ query }) => query.data?.receipts ?? []) + .map((receipt) => [receipt.toolCallId, receipt] as const), + ...pagedReceipts, + ]) + const layout = { + standaloneToolIds: new Set([ + ...(receiptTurn?.writeIds ?? []), + ...receipts.keys(), + ...(streamId && streamId === review?.streamId ? review.byId.keys() : []), + ]), + reviewedToolIds: new Set( + [...receipts.values()] + .filter((receipt) => receipt.state !== 'pending') + .map((receipt) => receipt.toolCallId) + ), + } + const ownsReceipts = receiptTurn?.messageId === messageId + const missingRecovery = ownsReceipts + ? receiptBatches.filter(({ ids }) => + ids.some( + (id) => !receiptTurn.representedIds.has(id) && !review?.byId.has(id) && !receipts.has(id) + ) + ) + : [] + const recoveryReceipts = ownsReceipts + ? [...receipts.values()].filter( + (receipt) => + !receiptTurn.representedIds.has(receipt.toolCallId) && + !review?.byId.has(receipt.toolCallId) + ) + : [] + const ownsReview = review?.recoveryMessageId === messageId + const recovery = new Map< + string, + { kind: 'review'; value: ReviewAction } | { kind: 'receipt'; value: Receipt } + >() + for (const receipt of recoveryReceipts) + recovery.set(receipt.toolCallId, { kind: 'receipt', value: receipt }) + if (ownsReview) { + for (const action of review.recoveryActions) + recovery.set(action.toolCallId, { kind: 'review', value: action }) + } + const recoveryItems = [...recovery.values()].sort( + (left, right) => + (left.value.sequence ?? Number.MAX_SAFE_INTEGER) - + (right.value.sequence ?? Number.MAX_SAFE_INTEGER) + ) useEffect(() => { const origin = focusOrigin.current @@ -305,11 +459,15 @@ export function AssistantActionReviewMessage({ focusOrigin.current = document.activeElement === source ? source : null }) } - const ownsReview = review.recoveryMessageId === messageId return ( - + 0 || review.submitting)} + value={ + (ownsReview && (review.actions.length > 0 || review.submitting)) || + (ownsReceipts && [...receipts.values()].some((receipt) => receipt.unsettled)) + } >
- +
)} - {ownsReview && review.recoveryActions.length > 0 && ( -
- {review.recoveryActions.map((action) => ( - + {recoveryItems.length > 0 && ( +
+ {recoveryItems.map((item) => ( +
+ {item.kind === 'review' ? ( + + ) : ( + + )} +
))}
)} + {missingRecovery.length > 0 && ( +
+ query.isLoading) + ? 'Loading action history' + : 'Action details unavailable' + } + isActive={missingRecovery.some(({ query }) => query.isFetching)} + /> + {missingRecovery.some(({ query }) => query.isError) && ( + { + for (const { query } of missingRecovery) void query.refetch() + }} + > + Retry + + )} +
+ )} + {ownsReceipts && receiptQuery.isError && ( +
+ + void receiptQuery.refetch()}> + Retry + +
+ )} + {ownsReceipts && receiptQuery.hasNextPage && ( +
+ void receiptQuery.fetchNextPage()} + > + More action history + +
+ )} {ownsReview && }
@@ -349,39 +552,55 @@ interface AssistantActionReviewStatusProps { toolCallId: string title: string fallback: ReactNode + awaitingApproval?: boolean } export function AssistantActionReviewStatus({ toolCallId, title, fallback, + awaitingApproval = true, }: AssistantActionReviewStatusProps) { const review = useContext(reviewContext) const message = useContext(reviewMessageContext) + const receipt = message?.receipts.get(toolCallId) if (!review) return fallback - if (review.query.isPending) return - if (message?.messageId === review.assistantMessageId) { + if (message?.streamId === review.streamId) { const action = review.byId.get(toolCallId) if (action) return - if (!review.query.isError && review.query.data?.nextCursor != null) - return } + if (receipt) return + const batch = message?.receiptQueries.get(toolCallId) + if (!awaitingApproval && !batch) return fallback + if (review.query.isPending || message?.receiptQuery.isLoading || batch?.isPending) + return + if ( + message?.streamId === review.streamId && + !review.query.isError && + review.query.data?.nextCursor != null + ) + return if (review.query.isError) - return + return + if (batch?.isError) + return + if (message?.receiptQuery.isError && !batch?.isSuccess) + return + if (!awaitingApproval) return fallback return } interface ReviewAvailabilityProps { label: string - review?: ReviewContextValue + query?: { isFetching: boolean; refetch: () => Promise } } -function ReviewAvailability({ label, review }: ReviewAvailabilityProps) { +function ReviewAvailability({ label, query }: ReviewAvailabilityProps) { return (
} /> - {review && ( - void review.query.refetch()}> + {query && ( + void query.refetch()}> Retry )} @@ -395,6 +614,8 @@ interface ActionReviewProps { } function ActionReview({ action, review }: ActionReviewProps) { + const [editing, setEditing] = useState(false) + const { title } = assistantActionPresentation(action) const message = useContext(reviewMessageContext) const draft = review.drafts.runId === action.runId ? review.drafts.edits[action.toolCallId] : undefined @@ -410,44 +631,63 @@ function ActionReview({ action, review }: ActionReviewProps) { ? resolveCredentialDisplay({ ...action.account, type: 'managed_oauth' }) : undefined return ( -
+
+ {display?.icon ? ( ) : ( )} - {action.name} + {title} } + actions={ + action.fields.some((field) => field.editable) ? ( + setEditing(!editing)}> + {editing ? 'Done' : 'Edit'} + + ) : undefined + } > -
+

{action.account?.displayName ?? 'Account unavailable'}

-
- {action.fields - .filter((field) => field.value || field.editable) - .map((field) => ( - review.edit(action, field.name, value)} - /> - ))} -
+ {editing ? ( +
+ {action.fields + .filter((field) => field.value || field.editable) + .map((field) => ( + review.edit(action, field.name, value)} + /> + ))} +
+ ) : ( + ({ + ...field, + value: edits[field.name] ?? field.value, + })), + }} + /> + )} {!action.account?.active && (

This account is no longer available.

)} {review.query.isError && ( - + )} {error?.proposalVersion === action.proposalVersion && (

diff --git a/apps/sim/components/secrets/organization-secrets-editor.tsx b/apps/sim/components/secrets/organization-secrets-editor.tsx index 60ace35afef..e9f9bccd214 100644 --- a/apps/sim/components/secrets/organization-secrets-editor.tsx +++ b/apps/sim/components/secrets/organization-secrets-editor.tsx @@ -18,9 +18,10 @@ import { interface OrganizationSecretsEditorProps { mode: SecretSourceMode + backHref?: string } -export function OrganizationSecretsEditor({ mode }: OrganizationSecretsEditorProps) { +export function OrganizationSecretsEditor({ mode, backHref }: OrganizationSecretsEditorProps) { const { organization, viewer } = useOrganizationContext() const router = useRouter() const secrets = useOrganizationSecrets(organization.id, mode, mode === 'member' || viewer.isAdmin) @@ -29,7 +30,7 @@ export function OrganizationSecretsEditor({ mode }: OrganizationSecretsEditorPro const back = mode === 'organization' ? { text: 'Sources', href: routes.settingsSection('integrations') } - : { text: 'Integrations', href: routes.integrations } + : { text: 'Integrations', href: backHref ?? routes.integrations } if (!secrets.data || secrets.error) return ( Loading secrets…} > - + diff --git a/apps/sim/hooks/queries/assistant-actions.ts b/apps/sim/hooks/queries/assistant-actions.ts index 72054f3accb..4819379f4b9 100644 --- a/apps/sim/hooks/queries/assistant-actions.ts +++ b/apps/sim/hooks/queries/assistant-actions.ts @@ -1,26 +1,47 @@ -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { useCallback } from 'react' +import { compareStrings } from '@sim/utils/string' +import { + type InfiniteData, + type QueryClient, + useInfiniteQuery, + useMutation, + useQueries, + useQuery, + useQueryClient, +} from '@tanstack/react-query' import { requestJson } from '@/lib/api/client/request' import { type AssistantActionDecisionBody, + type AssistantActionReceiptsResponse, decideAssistantActionContract, + listAssistantActionReceiptsContract, listAssistantActionsContract, readAssistantToolPermissionsContract, type UpdateAssistantToolPermissionsBody, updateAssistantToolPermissionsContract, } from '@/lib/api/contracts/assistant-actions' -const assistantActionKeys = { +export const assistantActionKeys = { all: ['assistant-actions'] as const, permissions: () => [...assistantActionKeys.all, 'permissions'] as const, permission: (organizationId: string, credentialId: string) => [...assistantActionKeys.permissions(), organizationId, credentialId] as const, review: (organizationId: string, chatId: string) => [...assistantActionKeys.all, 'review', organizationId, chatId] as const, + receipts: (organizationId: string, chatId: string) => + [...assistantActionKeys.all, 'receipts', organizationId, chatId] as const, + turnReceipts: (organizationId: string, chatId: string, streamId: string) => + [...assistantActionKeys.receipts(organizationId, chatId), 'turn', streamId] as const, + receiptBatches: (organizationId: string, chatId: string, streamId: string) => + [...assistantActionKeys.receipts(organizationId, chatId), 'batches', streamId] as const, + receiptBatch: (organizationId: string, chatId: string, streamId: string, toolCallIds: string[]) => + [...assistantActionKeys.receiptBatches(organizationId, chatId, streamId), toolCallIds] as const, } const ASSISTANT_PERMISSIONS_STALE_TIME = 10_000 const ASSISTANT_REVIEW_STALE_TIME = 3_000 const ASSISTANT_REVIEW_POLL_INTERVAL = 3_000 +const RECEIPT_BATCH_CONCURRENCY = 2 export function useAssistantToolPermissions(organizationId: string, credentialId: string) { return useQuery({ @@ -70,10 +91,170 @@ export function useDecideAssistantAction(organizationId: string, chatId: string) signal, }), onSettled: () => - client.invalidateQueries({ queryKey: assistantActionKeys.review(organizationId, chatId) }), + Promise.all([ + client.invalidateQueries({ queryKey: assistantActionKeys.review(organizationId, chatId) }), + client.invalidateQueries({ + queryKey: assistantActionKeys.receipts(organizationId, chatId), + refetchType: 'none', + }), + ]), + }) +} + +interface ReceiptTurnOptions { + organizationId: string + chatId: string + streamId: string + enabled: boolean + mountedTurnCount: number +} + +interface ReceiptBatchOptions extends ReceiptTurnOptions { + candidateIds: Iterable + coveredIds: ReadonlySet + pageCount: number +} + +/** Pages only mounted turns; an unresolved execution keeps polling after chat streaming stops. */ +export function useAssistantActionTurnReceipts({ + organizationId, + chatId, + streamId, + active, + enabled, + mountedTurnCount, +}: ReceiptTurnOptions & { active: boolean }) { + const client = useQueryClient() + return useInfiniteQuery({ + queryKey: assistantActionKeys.turnReceipts(organizationId, chatId, streamId), + queryFn: ({ signal, pageParam }) => + requestJson(listAssistantActionReceiptsContract, { + params: { id: organizationId, chatId }, + query: { streamId, cursor: pageParam }, + signal, + }), + initialPageParam: undefined as number | undefined, + getNextPageParam: (page) => page.nextCursor ?? undefined, + enabled: enabled && Boolean(organizationId && chatId && streamId), + staleTime: ASSISTANT_REVIEW_STALE_TIME, + refetchInterval: (query) => + enabled && + (active || + query.state.data?.pages.some((page) => page.receipts.some((receipt) => receipt.unsettled))) + ? receiptPollInterval( + client, + organizationId, + chatId, + streamId, + query.state.data?.pages.length ?? 1, + mountedTurnCount + ) + : false, }) } +/** Immutable batch keys retain recovery-only receipts after a decision removes the pending action. */ +export function useAssistantActionReceiptBatches({ + organizationId, + chatId, + streamId, + candidateIds, + coveredIds, + enabled, + pageCount, + mountedTurnCount, +}: ReceiptBatchOptions) { + const client = useQueryClient() + const existing = client.getQueriesData({ + queryKey: assistantActionKeys.receiptBatches(organizationId, chatId, streamId), + }) + const batches = existing.flatMap(([key]) => { + const ids = key.at(-1) + return Array.isArray(ids) && ids.every((id): id is string => typeof id === 'string') + ? [ids] + : [] + }) + const known = new Set([...coveredIds, ...batches.flat()]) + const missing = [...new Set(candidateIds)].filter((id) => !known.has(id)).sort(compareStrings) + for (let index = 0; index < missing.length; index += 32) + batches.push(missing.slice(index, index + 32)) + const interval = receiptPollInterval( + client, + organizationId, + chatId, + streamId, + pageCount, + mountedTurnCount + ) + let initialRequests = 0 + const queries = useQueries({ + queries: batches.map((toolCallIds) => { + const key = assistantActionKeys.receiptBatch(organizationId, chatId, streamId, toolCallIds) + const state = client.getQueryState(key) + const started = state?.status === 'success' || state?.status === 'error' + const uncovered = toolCallIds.some((id) => !coveredIds.has(id)) + const eligible = started || (uncovered && initialRequests++ < RECEIPT_BATCH_CONCURRENCY) + return { + queryKey: key, + queryFn: ({ signal }: { signal: AbortSignal }) => + requestJson(listAssistantActionReceiptsContract, { + params: { id: organizationId, chatId }, + query: { toolCallIds }, + signal, + }), + enabled: enabled && eligible && Boolean(organizationId && chatId && streamId) && uncovered, + staleTime: ASSISTANT_REVIEW_STALE_TIME, + refetchInterval: + enabled && + uncovered && + existing + .find(([key]) => key.at(-1) === toolCallIds)?.[1] + ?.receipts.some((receipt) => receipt.unsettled && !coveredIds.has(receipt.toolCallId)) + ? interval + : false, + } + }), + }) + return batches.map((ids, index) => ({ ids, query: queries[index] })) +} + +/** A review batch refreshes receipts once, after all of its decisions settle. */ +export function useRefreshAssistantActionReceipts(organizationId: string, chatId: string) { + const client = useQueryClient() + return useCallback( + () => + client.invalidateQueries({ queryKey: assistantActionKeys.receipts(organizationId, chatId) }), + [client, organizationId, chatId] + ) +} + +function receiptPollInterval( + client: QueryClient, + organizationId: string, + chatId: string, + streamId: string, + pageCount: number, + mountedTurnCount: number +) { + const pages = client.getQueryData>( + assistantActionKeys.turnReceipts(organizationId, chatId, streamId) + ) + const covered = new Set( + pages?.pages.flatMap((page) => page.receipts.map((receipt) => receipt.toolCallId)) + ) + const batches = client + .getQueriesData({ + queryKey: assistantActionKeys.receiptBatches(organizationId, chatId, streamId), + }) + .filter(([, data]) => + data?.receipts.some((receipt) => receipt.unsettled && !covered.has(receipt.toolCallId)) + ).length + return Math.max( + ASSISTANT_REVIEW_POLL_INTERVAL, + (pageCount + batches) * Math.max(1, mountedTurnCount) * 1_000 + ) +} + export function useUpdateAssistantToolPermissions(organizationId: string, credentialId: string) { const client = useQueryClient() return useMutation({ diff --git a/apps/sim/hooks/queries/organization-accounts.ts b/apps/sim/hooks/queries/organization-accounts.ts index 6fe908733ed..54765a07de1 100644 --- a/apps/sim/hooks/queries/organization-accounts.ts +++ b/apps/sim/hooks/queries/organization-accounts.ts @@ -45,6 +45,7 @@ import { import { connectCredentialGroupInPopup } from '@/lib/credential-groups/oauth-popup' import { isDesktopApp } from '@/lib/desktop' import { connectDesktopSource } from '@/lib/desktop/source-connect' +import { assistantActionKeys } from '@/hooks/queries/assistant-actions' import { personalCredentialKeys } from '@/hooks/queries/personal-credentials' import { mcpKeys } from '@/hooks/queries/utils/mcp-keys' import { resetOrganizationSearchAccess } from '@/hooks/queries/utils/reset-organization-search-access' @@ -249,6 +250,7 @@ export function useUpdateOrganizationAccounts() { async function refreshAccounts(client: ReturnType) { await Promise.all([ client.invalidateQueries({ queryKey: organizationAccountsKeys.all }), + client.invalidateQueries({ queryKey: assistantActionKeys.permissions() }), client.invalidateQueries({ queryKey: personalCredentialKeys.lists() }), client.invalidateQueries({ queryKey: mcpKeys.managedCatalog() }), invalidateSelectorQueries(client), diff --git a/apps/sim/lib/api/contracts/assistant-actions.ts b/apps/sim/lib/api/contracts/assistant-actions.ts index 112a7518a75..5c0e6306494 100644 --- a/apps/sim/lib/api/contracts/assistant-actions.ts +++ b/apps/sim/lib/api/contracts/assistant-actions.ts @@ -96,6 +96,7 @@ export const listAssistantActionsContract = defineRouteContract({ .array( z.object({ toolCallId: z.string().min(1).max(256), + sequence: z.number().int().nonnegative().nullish(), runId: z.uuid(), toolId: toolIdSchema, name: z.string().max(512), @@ -157,3 +158,59 @@ export const decideAssistantActionContract = defineRouteContract({ export type AssistantActionsResponse = z.output export type AssistantActionDecisionBody = z.input + +export const listAssistantActionReceiptsContract = defineRouteContract({ + method: 'GET', + path: `${reviewPath}/receipts`, + params: reviewParamsSchema, + query: z.union([ + z + .object({ + streamId: z.string().min(1).max(256), + cursor: z.coerce.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(), + }) + .strict(), + z + .object({ + toolCallIds: z + .union([toolIdSchema, z.array(toolIdSchema).min(1).max(32)]) + .transform((ids) => [...new Set(typeof ids === 'string' ? [ids] : ids)]), + }) + .strict(), + ]), + response: { + mode: 'json', + schema: z.object({ + receipts: z + .array( + listAssistantActionsContract.response.schema.shape.actions.element + .omit({ proposalVersion: true }) + .extend({ + sequence: z.number().int().nonnegative().nullable(), + streamId: z.string().min(1).max(256), + state: z.enum([ + 'pending', + 'approved', + 'running', + 'succeeded', + 'cancelled', + 'failed', + 'uncertain', + ]), + unsettled: z.boolean(), + decision: z.enum(['allow', 'skip', 'allow_chat', 'always_allow']).nullable(), + decidedAt: z.iso.datetime().nullable(), + completedAt: z.iso.datetime().nullable(), + detailsAvailable: z.boolean(), + warning: z.string().max(2048).nullable(), + }) + ) + .max(32), + nextCursor: z.number().int().nonnegative().nullable(), + }), + }, +}) + +export type AssistantActionReceiptsResponse = z.output< + typeof listAssistantActionReceiptsContract.response.schema +> diff --git a/apps/sim/lib/assistant-actions/application/operations.ts b/apps/sim/lib/assistant-actions/application/operations.ts index 3e86b5ee1d3..2a7d37d16be 100644 --- a/apps/sim/lib/assistant-actions/application/operations.ts +++ b/apps/sim/lib/assistant-actions/application/operations.ts @@ -1,6 +1,13 @@ import { defineOrganizationOperation } from '@/lib/core/application/organization-operation' export const assistantActionOperations = { + // permission-group-exempt: reads the owner's existing action history without granting tool access. + receipts: defineOrganizationOperation({ + id: 'assistant_actions.receipts', + minimumRole: 'member', + capability: 'none', + principalKinds: ['session'], + }), list: defineOrganizationOperation({ id: 'assistant_actions.list', minimumRole: 'member', diff --git a/apps/sim/lib/assistant-actions/application/receipts.ts b/apps/sim/lib/assistant-actions/application/receipts.ts new file mode 100644 index 00000000000..238a2a41384 --- /dev/null +++ b/apps/sim/lib/assistant-actions/application/receipts.ts @@ -0,0 +1,179 @@ +import { db } from '@sim/db' +import { copilotAsyncToolCalls, copilotChats, copilotRuns } from '@sim/db/schema' +import { truncateAtCodePoint } from '@sim/utils/string' +import { and, asc, eq, gt, inArray, isNotNull, isNull, or, sql } from 'drizzle-orm' +import type { AssistantActionReceiptsResponse } from '@/lib/api/contracts/assistant-actions' +import { assistantActionOperations } from '@/lib/assistant-actions/application/operations' +import { assistantReviewFields } from '@/lib/assistant-actions/proposal' +import { loadAssistantAccount } from '@/lib/assistant-actions/tool-permissions' +import { + defineAuthorizedOrganizationUseCase, + type OrganizationUseCaseContext, +} from '@/lib/core/application/authorized-organization-use-case' +import { OrchestrationError } from '@/lib/core/orchestration/types' +import { TERMINAL_RUN_STATUSES } from '@/lib/mothership/async-runs/repository' +import { + requireOwnedChatReadable, + resolveOwnedChatContext, +} from '@/lib/mothership/chat/application/context' +import { toolStartWindowClosed } from '@/lib/mothership/request/tools/deadline' +import { getToolMetadata } from '@/tools/metadata' + +type ReceiptInput = { organizationId: string; chatId: string } & ( + | { streamId: string; cursor?: number } + | { toolCallIds: string[] } +) +type ReceiptState = AssistantActionReceiptsResponse['receipts'][number]['state'] + +const receiptColumns = { + toolCallId: copilotAsyncToolCalls.toolCallId, + runId: copilotAsyncToolCalls.runId, + streamId: copilotRuns.streamId, + currentStreamId: copilotChats.conversationId, + runStatus: copilotRuns.status, + closedAt: copilotRuns.toolAdmissionClosedAt, + executableName: copilotAsyncToolCalls.executableName, + toolName: copilotAsyncToolCalls.toolName, + args: sql`coalesce(${copilotAsyncToolCalls.approvedArgs}, ${copilotAsyncToolCalls.args})`, + binding: copilotAsyncToolCalls.assistantAction, + status: copilotAsyncToolCalls.status, + decision: copilotAsyncToolCalls.permissionDecision, + requestedAt: copilotAsyncToolCalls.permissionRequestedAt, + decidedAt: copilotAsyncToolCalls.permissionDecidedAt, + completedAt: copilotAsyncToolCalls.completedAt, + persistSeq: copilotAsyncToolCalls.persistSeq, + startedAt: copilotAsyncToolCalls.executionStartedAt, + settledAt: copilotAsyncToolCalls.executionSettledAt, + revokedAt: copilotAsyncToolCalls.executionRevokedAt, + leaseExpiresAt: copilotAsyncToolCalls.executionLeaseExpiresAt, + deadlineAt: copilotAsyncToolCalls.executionDeadlineAt, + outcomeUnknown: sql`coalesce(${copilotAsyncToolCalls.result}->'outcomeUnknown' = 'true'::jsonb, false) or coalesce(${copilotAsyncToolCalls.result}#>'{output,outcomeUnknown}' = 'true'::jsonb, false)`, + warning: sql< + string | null + >`case when ${copilotAsyncToolCalls.executableName} = 'jira_write' then left(${copilotAsyncToolCalls.result}#>>'{output,warning}', 2048) else null end`, +} + +/** History remains readable after a turn closes; it never grants authority to execute it. */ +export const listOrganizationAssistantActionReceipts = defineAuthorizedOrganizationUseCase({ + operation: assistantActionOperations.receipts, + async authorizeResource({ principal, input, context }: OrganizationUseCaseContext) { + const chat = await resolveOwnedChatContext(principal, input.chatId) + if (chat.organizationId !== context.organizationId || chat.mode !== 'assistant') + throw new OrchestrationError('not_found', 'Chat not found') + await requireOwnedChatReadable(chat) + }, + async execute({ + input, + context, + }: OrganizationUseCaseContext): Promise { + const records = await db + .select(receiptColumns) + .from(copilotAsyncToolCalls) + .innerJoin(copilotRuns, eq(copilotRuns.id, copilotAsyncToolCalls.runId)) + .innerJoin(copilotChats, eq(copilotChats.id, copilotRuns.chatId)) + .where( + and( + eq(copilotRuns.chatId, input.chatId), + eq(copilotRuns.organizationId, context.organizationId), + eq(copilotRuns.userId, context.userId), + eq(copilotChats.organizationId, context.organizationId), + eq(copilotChats.userId, context.userId), + isNull(copilotChats.deletedAt), + isNotNull(copilotAsyncToolCalls.assistantAction), + or( + isNotNull(copilotAsyncToolCalls.permissionRequestedAt), + sql`${copilotAsyncToolCalls.assistantAction}->>'effect' = 'write'` + ), + 'streamId' in input + ? eq(copilotRuns.streamId, input.streamId) + : inArray(copilotAsyncToolCalls.toolCallId, input.toolCallIds), + 'cursor' in input && input.cursor !== undefined + ? gt(copilotAsyncToolCalls.persistSeq, input.cursor) + : undefined + ) + ) + .orderBy(asc(copilotAsyncToolCalls.persistSeq)) + .limit(33) + const page = records.slice(0, 32) + const credentialIds = [ + ...new Set(page.flatMap((record) => (record.binding ? [record.binding.credentialId] : []))), + ] + const accounts = new Map( + await Promise.all( + credentialIds.map( + async (credentialId) => + [credentialId, await loadAssistantAccount({ ...context, credentialId })] as const + ) + ) + ) + const now = Date.now() + const receipts = page.flatMap((record) => { + if (!record.binding) return [] + const account = accounts.get(record.binding.credentialId) + const toolId = record.executableName ?? record.toolName + const tool = getToolMetadata(toolId) + const detailsAvailable = Boolean( + tool?.assistant && tool.assistant.version === record.binding.operationVersion + ) + const running = + !record.settledAt && + !record.revokedAt && + record.leaseExpiresAt !== null && + record.leaseExpiresAt.getTime() > now + const closed = + record.closedAt !== null || + TERMINAL_RUN_STATUSES.includes(record.runStatus) || + record.currentStreamId !== record.streamId || + toolStartWindowClosed(record.deadlineAt?.getTime(), now) + let state: ReceiptState + if (record.status === 'completed') state = 'succeeded' + else if ( + record.outcomeUnknown || + (record.startedAt && record.revokedAt) || + (record.startedAt && record.status === 'cancelled') + ) + state = 'uncertain' + else if (record.decision === 'skip' || record.status === 'cancelled') state = 'cancelled' + else if (record.status === 'failed') state = 'failed' + else if (running) state = 'running' + else if (record.startedAt || record.status === 'delivered') state = 'uncertain' + else if (closed) state = 'cancelled' + else state = record.decision || record.requestedAt === null ? 'approved' : 'pending' + return [ + { + toolCallId: record.toolCallId, + sequence: record.persistSeq, + runId: record.runId, + streamId: record.streamId, + toolId, + name: tool?.name ?? record.toolName, + effect: record.binding.effect, + state, + unsettled: + running || + state === 'approved' || + state === 'pending' || + (!closed && + !record.settledAt && + !record.revokedAt && + ['pending', 'running', 'delivered'].includes(record.status)), + decision: record.decision, + decidedAt: record.decidedAt?.toISOString() ?? null, + completedAt: record.completedAt?.toISOString() ?? null, + detailsAvailable, + warning: record.warning === null ? null : truncateAtCodePoint(record.warning, 2048, ''), + account: account + ? { + credentialId: account.credentialId, + displayName: account.displayName, + providerId: account.providerId, + active: account.active, + } + : null, + fields: detailsAvailable ? assistantReviewFields(record) : [], + }, + ] + }) + return { receipts, nextCursor: records.length > 32 ? (page.at(-1)?.persistSeq ?? null) : null } + }, +}) diff --git a/apps/sim/lib/assistant-actions/application/review.ts b/apps/sim/lib/assistant-actions/application/review.ts index 97775bfaa65..6716e59c4c1 100644 --- a/apps/sim/lib/assistant-actions/application/review.ts +++ b/apps/sim/lib/assistant-actions/application/review.ts @@ -103,6 +103,7 @@ export const listOrganizationAssistantActions = defineAuthorizedOrganizationUseC const tool = getToolMetadata(record.executableName ?? '') return { toolCallId: record.toolCallId, + sequence: record.persistSeq, runId: record.runId, toolId: record.executableName ?? record.toolName, name: tool?.name ?? record.toolName, diff --git a/apps/sim/lib/assistant-actions/proposal.ts b/apps/sim/lib/assistant-actions/proposal.ts index abd006ab5aa..eb70e90a04c 100644 --- a/apps/sim/lib/assistant-actions/proposal.ts +++ b/apps/sim/lib/assistant-actions/proposal.ts @@ -57,7 +57,7 @@ export function applyAssistantReviewEdits( } /** Every supplied non-authentication argument remains visible, even without a custom review label. */ -export function assistantReviewFields(record: ActionRecord) { +export function assistantReviewFields(record: Pick) { const tool = getToolMetadata(record.executableName ?? '') const args = toRecord(record.args) const declared = tool?.assistant?.reviewFields ?? [] diff --git a/apps/sim/lib/mothership/chat/display-message.ts b/apps/sim/lib/mothership/chat/display-message.ts index 6454d94fc20..cd7cbb98c35 100644 --- a/apps/sim/lib/mothership/chat/display-message.ts +++ b/apps/sim/lib/mothership/chat/display-message.ts @@ -206,6 +206,7 @@ export function toDisplayMessage(msg: PersistedMessage): ChatMessage { const display: ChatMessage = { id: msg.id, + ...(msg.streamId ? { streamId: msg.streamId } : {}), role: msg.role, ...(msg.origin ? { origin: msg.origin } : {}), content: msg.content, diff --git a/apps/sim/lib/mothership/chat/effective-transcript.ts b/apps/sim/lib/mothership/chat/effective-transcript.ts index 754ed08da1f..5e664ccffe7 100644 --- a/apps/sim/lib/mothership/chat/effective-transcript.ts +++ b/apps/sim/lib/mothership/chat/effective-transcript.ts @@ -549,6 +549,7 @@ export function buildLiveAssistantMessage(params: { return normalizeMessage({ id: getLiveAssistantMessageId(streamId), + streamId, role: 'assistant', content: runningText, timestamp: lastTimestamp ?? new Date().toISOString(), diff --git a/apps/sim/lib/mothership/chat/lifecycle.ts b/apps/sim/lib/mothership/chat/lifecycle.ts index a873e538ca4..915639411dc 100644 --- a/apps/sim/lib/mothership/chat/lifecycle.ts +++ b/apps/sim/lib/mothership/chat/lifecycle.ts @@ -127,12 +127,19 @@ export async function loadCopilotChatMessages( const rows = await db .select({ content: options?.projection === 'display' ? displayMessageContent : copilotMessages.content, + streamId: copilotMessages.streamId, }) .from(copilotMessages) .where(and(eq(copilotMessages.chatId, chatId), isNull(copilotMessages.deletedAt))) .orderBy(...TRANSCRIPT_ORDER) // Also strip on read: rows written before the backfill still carry outputs. - return rows.map((row) => stripToolResultOutput(row.content as PersistedMessage)) + return rows.map((row) => + stripToolResultOutput( + options?.projection === 'display' + ? { ...(row.content as PersistedMessage), streamId: row.streamId ?? undefined } + : (row.content as PersistedMessage) + ) + ) } /** Messages in the newest window the chat UI opens on. */ @@ -178,9 +185,10 @@ async function loadCopilotChatTranscriptPage( createdAt: preciseTimestampText(copilotMessages.createdAt), role: copilotMessages.role, content: displayMessageContent, + streamId: copilotMessages.streamId, } - let rows: Array + let rows: Array let hasOlder: boolean if (window.kind === 'from') { const [page, older] = await Promise.all([ @@ -219,7 +227,12 @@ async function loadCopilotChatTranscriptPage( : window.position const windowStartCursor = windowStart ? encodeTranscriptCursor(windowStart) : null return { - messages: rows.map((row) => stripToolResultOutput(row.content as PersistedMessage)), + messages: rows.map((row) => + stripToolResultOutput({ + ...(row.content as PersistedMessage), + streamId: row.streamId ?? undefined, + }) + ), olderCursor: hasOlder ? windowStartCursor : null, windowStartCursor, } diff --git a/apps/sim/lib/mothership/chat/messages-store.ts b/apps/sim/lib/mothership/chat/messages-store.ts index 31468727f21..727af290c36 100644 --- a/apps/sim/lib/mothership/chat/messages-store.ts +++ b/apps/sim/lib/mothership/chat/messages-store.ts @@ -31,7 +31,8 @@ function toRow( options?: { chatModel?: string | null; streamId?: string | null } ): typeof copilotMessages.$inferInsert { const ts = new Date(message.timestamp) - const content = stripToolResultOutput(message) + const { streamId, ...storedMessage } = message + const content = stripToolResultOutput(storedMessage) return { chatId, messageId: message.id, diff --git a/apps/sim/lib/mothership/chat/persisted-message.ts b/apps/sim/lib/mothership/chat/persisted-message.ts index 761859ec9fb..b4fc382acb9 100644 --- a/apps/sim/lib/mothership/chat/persisted-message.ts +++ b/apps/sim/lib/mothership/chat/persisted-message.ts @@ -133,6 +133,8 @@ export function copyPersistedMessageContext(c: PersistedMessageContext): Persist export interface PersistedMessage { id: string + /** Server-owned turn association for display; never persisted in message content. */ + streamId?: string role: 'user' | 'assistant' requestMode?: 'agent' | 'assistant' | 'plan' content: string @@ -896,6 +898,7 @@ export function normalizeMessage(raw: Record): PersistedMessage if (raw.requestId && typeof raw.requestId === 'string') { msg.requestId = raw.requestId } + if (typeof raw.streamId === 'string') msg.streamId = raw.streamId const origin = TurnOrigin.safeParse(raw.origin) if (origin.success) msg.origin = origin.data diff --git a/apps/sim/scripts/test-assistant-actions-e2e.ts b/apps/sim/scripts/test-assistant-actions-e2e.ts index 3d8dde08afc..59a8acfc992 100644 --- a/apps/sim/scripts/test-assistant-actions-e2e.ts +++ b/apps/sim/scripts/test-assistant-actions-e2e.ts @@ -7,13 +7,15 @@ import { createLogger } from '@sim/logger' import { createDeferred } from '@sim/testing/helpers/deferred' import { getErrorMessage } from '@sim/utils/errors' import { generateId, generateShortId } from '@sim/utils/id' -import { toRecord } from '@sim/utils/object' +import { toArray, toRecord } from '@sim/utils/object' import { makeSignature } from 'better-auth/crypto' import postgres from 'postgres' import { + listAssistantActionReceiptsContract, listAssistantActionsContract, readAssistantToolPermissionsContract, } from '@/lib/api/contracts/assistant-actions' +import { getOrganizationAccountsContract } from '@/lib/api/contracts/organization-accounts' import { closeRedisConnection } from '@/lib/core/config/redis' import { acquirePendingChatStream, @@ -59,6 +61,10 @@ const organizationId = generateId() const otherOrganizationId = generateId() const assistantId = generateId() const credentialId = generateId() +const secondCredentialId = generateId() +const codaServerId = generateId() +const firefliesServerId = generateId() +const firefliesCredentialId = `mcp-cg-${generateId()}` const nativeCredentialId = generateId() const groupId = generateId() const enrollmentId = generateId() @@ -73,6 +79,9 @@ const lagStreamId = generateId() const lagFirstCallId = generateId() const lagSecondCallId = generateId() const lateCallId = generateId() +const bulkChatId = generateId() +const bulkStreamId = generateId() +const bulkRunId = generateId() const reviewChatId = generateId() const reviewRunId = generateId() const reviewStreamId = generateId() @@ -87,6 +96,7 @@ const requestId = generateId() const firstCallId = generateId() const secondCallId = generateId() const fixtureStreams = [ + { chatId: bulkChatId, streamId: bulkStreamId }, { chatId: assistantId, streamId }, { chatId: lagChatId, streamId: lagStreamId }, { chatId: reviewChatId, streamId: reviewStreamId }, @@ -119,13 +129,18 @@ const answer = 'Review the two Jira issues before I create them.' const reviewAnswer = 'Review these keyboard and batch proposals.' const checks: { name: string; status: 'passed' | 'failed'; durationMs: number; error?: string }[] = [] +const browserMessages: { type: string; text: string }[] = [] const browserErrors: string[] = [] const serverErrors: { path: string; status: number }[] = [] const httpResponses: { method: string; path: string; status: number }[] = [] const browser = await chromium.launch() const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } }) const page = await context.newPage() -const reviewCards = page.getByRole('region', { name: 'Review Jira Write', exact: true }) +const reviewCards = page.getByRole('region', { name: 'Review Create Jira issue', exact: true }) +page.on('console', (message) => { + if (browserMessages.length < 40) + browserMessages.push({ type: message.type(), text: message.text().slice(0, 1000) }) +}) page.on('pageerror', (error) => browserErrors.push(error.message)) page.on('response', (response) => { const url = new URL(response.url()) @@ -233,13 +248,37 @@ try { await tx`insert into session (id, token, user_id, expires_at, created_at, updated_at) values (${generateId()}, ${token}, ${userId}, now() + interval '1 day', now(), now())` await tx`insert into credential_group (id, organization_id, public_id, name, options) - values (${groupId}, ${organizationId}, ${generateId()}, 'Personal Jira', ${tx.json(['jira', 'salesforce', ...catalogAccounts.map((account) => account.option)].map((provider) => ({ id: provider, provider, label: provider, authorizationAppId: 'fixture', requiredScopes: [], scopeVersion: 1, required: false, status: 'active' })))})` + values (${groupId}, ${organizationId}, ${generateId()}, 'Personal Jira', ${tx.json([{ id: 'jira', provider: 'jira' }, { id: 'jira-team', provider: 'jira' }, { id: 'salesforce', provider: 'salesforce' }, ...catalogAccounts.map((account) => ({ id: account.option, provider: account.option }))].map(({ id, provider }) => ({ id, provider, label: id, authorizationAppId: 'fixture', requiredScopes: [], scopeVersion: 1, required: false, status: 'active' })))})` await tx`insert into resource_policy (id, organization_id, resource_type, resource_id, document, created_by, updated_by) values (${generateId()}, ${organizationId}, 'credential_group', ${groupId}, ${tx.json({ version: 2, resource: { type: 'credential_group', id: groupId }, statements: [] })}, ${userId}, ${userId})` await tx`insert into credential_group_enrollment (id, credential_group_id, user_id, email, status, invitation_token_hash, invitation_expires_at, invited_at) values (${enrollmentId}, ${groupId}, ${userId}, ${email}, 'completed', ${enrollmentId.replaceAll('-', '').repeat(2)}, now() + interval '1 day', now())` + for (const [id, provider] of [ + [codaServerId, 'coda'], + [firefliesServerId, 'fireflies'], + ] as const) { + await tx`insert into mcp_servers (id, organization_id, credential_group_id, managed_connector_id, name, transport, auth_type, url) + values (${id}, ${organizationId}, ${groupId}, ${provider}, ${provider}, 'streamable-http', 'oauth', 'https://example.invalid/mcp')` + } + await tx`insert into credential (id, organization_id, type, display_name, credential_group_enrollment_id, mcp_server_id, managed_oauth_status, encrypted_oauth_token_set, mcp_tools, granted_at) + values (${firefliesCredentialId}, ${organizationId}, 'managed_mcp', 'meetings@acme.example', ${enrollmentId}, ${firefliesServerId}, 'active', 'fixture-not-a-provider-token', '[]'::jsonb, now())` + for (const source of [ + 'coda', + 'jira', + 'gmail', + 'google_calendar', + 'google_drive', + 'confluence', + 'github', + 'google_meet', + ]) { + await tx`insert into organization_search_integration (organization_id, connector_type, approved) + values (${organizationId}, ${source}, true)` + } await tx`insert into credential (id, organization_id, type, created_by, display_name, provider_id, credential_group_enrollment_id, credential_group_option_id, managed_oauth_status, managed_oauth_scope_version, granted_scopes, provider_subject_id, authorization_app_id, encrypted_oauth_token_set, granted_at) values (${credentialId}, ${organizationId}, 'managed_oauth', ${userId}, 'taylor@acme.example', 'jira', ${enrollmentId}, 'jira', 'active', 1, '{}'::text[], ${userId}, 'fixture', 'fixture-not-a-provider-token', now())` + await tx`insert into credential (id, organization_id, type, created_by, display_name, provider_id, credential_group_enrollment_id, credential_group_option_id, managed_oauth_status, managed_oauth_scope_version, granted_scopes, provider_subject_id, authorization_app_id, encrypted_oauth_token_set, granted_at) + values (${secondCredentialId}, ${organizationId}, 'managed_oauth', ${userId}, 'launch-team@acme.example', 'jira', ${enrollmentId}, 'jira-team', 'active', 1, '{}'::text[], ${secondCredentialId}, 'fixture', 'fixture-not-a-provider-token', now())` await tx`insert into credential (id, organization_id, type, created_by, display_name, provider_id, credential_group_enrollment_id, credential_group_option_id, managed_oauth_status, managed_oauth_scope_version, granted_scopes, provider_subject_id, authorization_app_id, encrypted_oauth_token_set, granted_at) values (${nativeCredentialId}, ${organizationId}, 'managed_oauth', ${userId}, 'taylor@acme.example', 'salesforce', ${enrollmentId}, 'salesforce', 'active', 1, '{}'::text[], ${userId}, 'fixture', 'fixture-not-a-provider-token', now())` for (const account of catalogAccounts) { @@ -247,7 +286,8 @@ try { values (${account.credentialId}, ${organizationId}, 'managed_oauth', ${userId}, 'taylor@acme.example', ${account.provider}, ${enrollmentId}, ${account.option}, 'active', 1, '{}'::text[], ${userId}, 'fixture', 'fixture-not-a-provider-token', now())` } await tx`insert into copilot_chats (id, user_id, organization_id, type, title, conversation_id, config) - values (${assistantId}, ${userId}, ${organizationId}, 'mothership', 'Launch follow-up', ${streamId}, ${tx.json({ conversationMode: 'assistant' })}), + values (${bulkChatId}, ${userId}, ${organizationId}, 'mothership', 'Paginated action review', ${bulkStreamId}, ${tx.json({ conversationMode: 'assistant' })}), + (${assistantId}, ${userId}, ${organizationId}, 'mothership', 'Launch follow-up', ${streamId}, ${tx.json({ conversationMode: 'assistant' })}), (${lagChatId}, ${userId}, ${organizationId}, 'mothership', 'Delayed action transcript', ${lagStreamId}, ${tx.json({ conversationMode: 'assistant' })}), (${reviewChatId}, ${userId}, ${organizationId}, 'mothership', 'Keyboard and batch review', ${reviewStreamId}, ${tx.json({ conversationMode: 'assistant' })})` const oldResponseId = generateId() @@ -286,12 +326,14 @@ try { values (${generateId()}, ${assistantId}, ${data.id}, ${data.role}, ${stream}, ${tx.json({ ...content, requestId, timestamp: new Date().toISOString() })}, ${index + 1})` } await tx`insert into copilot_messages (id, chat_id, message_id, role, stream_id, content, seq) - values (${generateId()}, ${lagChatId}, ${lagStreamId}, 'user', ${lagStreamId}, ${tx.json({ id: lagStreamId, role: 'user', content: 'Create two more Jira issues.', requestId, timestamp: new Date().toISOString() })}, 1), + values (${generateId()}, ${bulkChatId}, ${bulkStreamId}, 'user', ${bulkStreamId}, ${tx.json({ id: bulkStreamId, role: 'user', content: 'Review this batch of Jira issues.', requestId, timestamp: new Date().toISOString() })}, 1), + (${generateId()}, ${lagChatId}, ${lagStreamId}, 'user', ${lagStreamId}, ${tx.json({ id: lagStreamId, role: 'user', content: 'Create two more Jira issues.', requestId, timestamp: new Date().toISOString() })}, 1), (${generateId()}, ${reviewChatId}, ${reviewStreamId}, 'user', ${reviewStreamId}, ${tx.json({ id: reviewStreamId, role: 'user', content: 'Prepare follow-up actions for review.', requestId, timestamp: new Date().toISOString() })}, 1)` await tx`insert into copilot_runs (id, chat_id, user_id, organization_id, execution_id, stream_id, tool_execution_version, status, started_at, completed_at, tool_admission_closed_at) values (${previousRunId}, ${assistantId}, ${userId}, ${organizationId}, ${generateId()}, ${previousStreamId}, 3, 'complete', now() - interval '1 hour', now() - interval '59 minutes', now() - interval '59 minutes')` await tx`insert into copilot_runs (id, chat_id, user_id, organization_id, execution_id, stream_id, tool_execution_version, status) - values (${runId}, ${assistantId}, ${userId}, ${organizationId}, ${generateId()}, ${streamId}, 3, 'paused_waiting_for_tool'), + values (${bulkRunId}, ${bulkChatId}, ${userId}, ${organizationId}, ${generateId()}, ${bulkStreamId}, 3, 'paused_waiting_for_tool'), + (${runId}, ${assistantId}, ${userId}, ${organizationId}, ${generateId()}, ${streamId}, 3, 'paused_waiting_for_tool'), (${lagRunId}, ${lagChatId}, ${userId}, ${organizationId}, ${generateId()}, ${lagStreamId}, 3, 'paused_waiting_for_tool'), (${reviewRunId}, ${reviewChatId}, ${userId}, ${organizationId}, ${generateId()}, ${reviewStreamId}, 3, 'paused_waiting_for_tool')` }) @@ -329,26 +371,199 @@ try { sameSite: 'Lax', }, ]) + await check( + 'Receipts restore actions before the transcript arrives and conceal foreign turns', + async () => { + const url = `${baseUrl.origin}/api/organizations/${organizationId}/chats/${assistantId}/actions/receipts` + const response = await context.request.get(url, { params: { streamId } }) + assert.equal(response.status(), 200, await response.text()) + const result = listAssistantActionReceiptsContract.response.schema.parse( + await response.json() + ) + assert.deepEqual( + result.receipts.map((receipt) => receipt.toolCallId), + [firstCallId, secondCallId] + ) + assert(result.receipts.every((receipt) => receipt.state === 'pending')) + assert( + result.receipts.every((receipt) => + receipt.fields.every((field) => field.name !== 'credential') + ) + ) + const foreign = await context.request.get(url, { params: { streamId: lagStreamId } }) + assert.equal(foreign.status(), 200) + assert.deepEqual( + listAssistantActionReceiptsContract.response.schema.parse(await foreign.json()).receipts, + [] + ) + const overflow = new URL(url) + for (let i = 0; i < 33; i++) overflow.searchParams.append('toolCallIds', `call-${i}`) + assert.equal((await context.request.get(overflow.toString())).status(), 400) + } + ) + await check( + 'Historical receipts distinguish approval, completion, cancellation, and uncertain outcomes', + async () => { + await insertProposal(previousRunId, previousCallId, 'Original historical title') + await sql`update copilot_async_tool_calls set status = 'completed', permission_decision = 'allow', permission_decided_at = now(), approved_args = ${sql.json(proposalArguments('Approved historical title'))}, execution_started_at = now(), execution_settled_at = now(), completed_at = now(), result = ${sql.json({ output: { warning: 'Issue created; assignment needs attention. Do not recreate the issue.', privatePayload: 'not-for-the-receipt'.repeat(20_000) } })} where tool_call_id = ${previousCallId}` + const url = `${baseUrl.origin}/api/organizations/${organizationId}/chats/${assistantId}/actions/receipts` + const response = await context.request.get(url, { params: { toolCallIds: previousCallId } }) + assert.equal(response.status(), 200, await response.text()) + const result = listAssistantActionReceiptsContract.response.schema.parse( + await response.json() + ) + const receipt = result.receipts[0] + assert(receipt) + assert.equal(receipt.state, 'succeeded') + assert.equal( + receipt.fields.find((field) => field.name === 'summary')?.value, + 'Approved historical title' + ) + assert.equal( + receipt.warning, + 'Issue created; assignment needs attention. Do not recreate the issue.' + ) + assert(!JSON.stringify(result).includes('privatePayload')) + const cases = [ + { + status: 'pending', + decision: 'skip', + started: false, + revoked: false, + unknown: false, + expected: 'cancelled', + }, + { + status: 'cancelled', + decision: 'allow', + started: true, + revoked: false, + unknown: false, + expected: 'uncertain', + }, + { + status: 'failed', + decision: 'allow', + started: true, + revoked: true, + unknown: true, + expected: 'uncertain', + }, + { + status: 'failed', + decision: 'allow', + started: true, + revoked: false, + unknown: false, + expected: 'failed', + }, + { + status: 'failed', + decision: 'allow', + started: false, + revoked: false, + unknown: false, + expected: 'failed', + }, + { + status: 'pending', + decision: 'allow', + started: false, + revoked: false, + unknown: false, + expected: 'cancelled', + }, + ] as const + for (const fixture of cases) { + const id = generateId() + await insertProposal(previousRunId, id, 'Historical outcome fixture') + await sql`update copilot_async_tool_calls set status = ${fixture.status}, permission_decision = ${fixture.decision}, execution_started_at = ${fixture.started ? new Date() : null}, execution_settled_at = ${fixture.started ? new Date() : null}, execution_revoked_at = ${fixture.revoked ? new Date() : null}, result = ${sql.json({ outcomeUnknown: fixture.unknown, notStarted: !fixture.started })} where tool_call_id = ${id}` + const stateResponse = await context.request.get(url, { params: { toolCallIds: id } }) + assert.equal(stateResponse.status(), 200) + const state = listAssistantActionReceiptsContract.response.schema.parse( + await stateResponse.json() + ).receipts[0] + assert.equal(state?.state, fixture.expected) + assert.equal(state?.unsettled, false) + await sql`delete from copilot_async_tool_calls where tool_call_id = ${id}` + } + await sql`update copilot_async_tool_calls set result = ${sql.json({ output: { warning: '😀'.repeat(1400) } })} where tool_call_id = ${previousCallId}` + const unicodeResponse = await context.request.get(url, { + params: { toolCallIds: previousCallId }, + }) + assert.equal(unicodeResponse.status(), 200) + assert.equal( + listAssistantActionReceiptsContract.response.schema.parse(await unicodeResponse.json()) + .receipts[0]?.warning, + '😀'.repeat(1024) + ) + await sql`update copilot_async_tool_calls set result = ${sql.json({ output: { warning: receipt.warning } })} where tool_call_id = ${previousCallId}` + const scoped = await context.request.get( + `${baseUrl.origin}/api/organizations/${organizationId}/chats/${lagChatId}/actions/receipts`, + { params: { toolCallIds: previousCallId } } + ) + assert.equal(scoped.status(), 200) + assert.deepEqual( + listAssistantActionReceiptsContract.response.schema.parse(await scoped.json()).receipts, + [] + ) + } + ) + await check( + 'Display history carries the canonical turn identity and clears copied identities', + async () => { + for (const suffix of ['', '?window=latest']) { + const response = await context.request.get( + `${baseUrl.origin}/api/mothership/chats/${assistantId}${suffix}` + ) + assert.equal(response.status(), 200) + const messages = toArray(toRecord(toRecord(await response.json()).chat).messages).map( + toRecord + ) + assert.equal( + messages.find((message) => message.id === previousStreamId)?.streamId, + previousStreamId + ) + } + const copiedId = generateId() + await sql`insert into copilot_messages (id, chat_id, message_id, role, content, seq) values (${copiedId}, ${lagChatId}, ${copiedId}, 'assistant', ${sql.json({ id: copiedId, role: 'assistant', content: 'Copied history', timestamp: new Date().toISOString(), streamId: previousStreamId })}, 2)` + try { + const response = await context.request.get( + `${baseUrl.origin}/api/mothership/chats/${lagChatId}` + ) + assert.equal(response.status(), 200) + const messages = toArray(toRecord(toRecord(await response.json()).chat).messages).map( + toRecord + ) + const copied = messages.find((message) => message.id === copiedId) + assert(copied) + assert.equal(copied.streamId, undefined) + } finally { + await sql`delete from copilot_messages where id = ${copiedId}` + } + } + ) await check('A native Assistant account exposes its own tool permissions', async () => { await page.goto(`${baseUrl.origin}${root}/integrations`, { waitUntil: 'domcontentloaded', timeout: 180_000, }) - await page.getByRole('button', { name: 'Salesforce integration actions', exact: true }).click() - await expect(page.getByRole('menuitem', { name: 'Add account', exact: true })).toHaveCount(0) - await expect(page.getByRole('menuitem', { name: 'Reconnect', exact: true })).toBeVisible() - const permissions = page.locator( - `a[href="${root}/integrations/accounts/${nativeCredentialId}"]` - ) - await expect(permissions).toBeVisible({ timeout: 180_000 }) - await permissions.click() + await page.getByRole('link', { name: 'Open Salesforce integration', exact: true }).click() + await expect(page.getByRole('button', { name: 'Add account', exact: true })).toHaveCount(0) + await expect(page.getByRole('button', { name: 'Reconnect', exact: true })).toBeVisible() + await capture('integration-account-actions') + await page.getByRole('button', { name: 'Disconnect', exact: true }).click() + await expect(page.getByRole('dialog', { name: 'Disconnect Salesforce' })).toBeVisible() + await capture('integration-disconnect-confirmation') + await page.getByRole('button', { name: 'Cancel', exact: true }).click() const policy = page.getByRole('radiogroup', { name: 'Create Task in Salesforce permission' }) await expect(policy).toBeVisible({ timeout: 180_000 }) await expect(policy.getByRole('radio', { name: 'Ask', exact: true })).toBeChecked() + await capture('integration-detail-salesforce') }) - await check('Connected app menus agree with the real Assistant tool catalog', async () => { - await page.goto(`${baseUrl.origin}${root}/integrations`, { waitUntil: 'domcontentloaded' }) + await check('Integration details agree with the real Assistant tool catalog', async () => { for (const account of catalogAccounts) { + await page.goto(`${baseUrl.origin}${root}/integrations`, { waitUntil: 'domcontentloaded' }) const response = await context.request.get( `${baseUrl.origin}/api/organizations/${organizationId}/connected-accounts/personal/${account.credentialId}/tool-permissions` ) @@ -356,26 +571,175 @@ try { const data = readAssistantToolPermissionsContract.response.schema.parse(await response.json()) assert.equal(data.account.credentialId, account.credentialId) assert.equal(data.tools.length > 0, account.supported, account.name) - const menu = page.getByRole('button', { - name: `${account.name} integration actions`, - exact: true, - }) - await expect(menu).toHaveCount(1) - await menu.click() - const permissions = page.getByRole('menu').locator('a[href*="/integrations/accounts/"]') - await expect(permissions).toHaveCount(account.supported ? 1 : 0) + await page + .getByRole('link', { name: `Open ${account.name} integration`, exact: true }) + .click() + const permissions = page.getByRole('textbox', { name: 'Search tools', exact: true }) if (account.supported) { - await expect(permissions).toHaveAttribute( - 'href', - `${root}/integrations/accounts/${account.credentialId}` - ) + await expect(permissions).toBeVisible() + await expect(page.getByRole('radiogroup').first()).toBeVisible() } else { await expect(permissions).toHaveCount(0) } - await page.keyboard.press('Escape') + await capture(`integration-detail-${account.name.toLowerCase().replaceAll(' ', '-')}`) } + await page.goto(`${baseUrl.origin}${root}/integrations`) + await expect( + page.getByRole('link', { name: 'Open Salesforce integration', exact: true }) + ).toBeVisible() await capture('integrations-desktop') }) + await check( + 'Multiple accounts isolate permissions and disconnect the selected account only', + async () => { + await page.goto(`${baseUrl.origin}${root}/integrations`) + await page.getByRole('link', { name: 'Open Jira integration', exact: true }).click() + await expect(page).toHaveURL((url) => url.searchParams.get('integration') === 'source:jira') + const accountsUrl = page.url() + const firstAccount = page.getByRole('link', { + name: 'Open taylor@acme.example account', + exact: true, + }) + const secondAccount = page.getByRole('link', { + name: 'Open launch-team@acme.example account', + exact: true, + }) + await expect(firstAccount).toBeVisible() + await expect(secondAccount).toBeVisible() + await expect(page.getByRole('textbox', { name: 'Search tools', exact: true })).toHaveCount(0) + await capture('integration-multiple-accounts') + await expect( + page.getByRole('button', { name: 'Jira integration actions', exact: true }) + ).toHaveCount(0) + await page.setViewportSize({ width: 390, height: 844 }) + await capture('integration-multiple-accounts-mobile') + assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)) + await page.setViewportSize({ width: 1440, height: 1000 }) + await secondAccount.click() + await expect(page).toHaveURL((url) => url.searchParams.get('account') === secondCredentialId) + const selectedUrl = page.url() + const policy = page.getByRole('radiogroup', { name: 'Jira Write permission' }) + await expect(policy.getByRole('radio', { name: 'Ask', exact: true })).toBeChecked() + await capture('integration-selected-account') + await policy.getByRole('radio', { name: 'Block', exact: true }).click() + await expect(policy.getByRole('radio', { name: 'Block', exact: true })).toBeChecked() + await page.reload() + await expect(policy.getByRole('radio', { name: 'Block', exact: true })).toBeChecked() + for (const [id, expected] of [ + [credentialId, 'ask'], + [secondCredentialId, 'block'], + ] as const) { + const response = await context.request.get( + `${baseUrl.origin}/api/organizations/${organizationId}/connected-accounts/personal/${id}/tool-permissions` + ) + assert.equal(response.status(), 200) + const permissions = readAssistantToolPermissionsContract.response.schema.parse( + await response.json() + ) + assert.equal( + permissions.tools.find((tool) => tool.toolId === 'jira_write')?.policy, + expected + ) + } + await page.getByRole('link', { name: 'Jira', exact: true }).click() + await expect(firstAccount).toBeVisible() + await firstAccount.click() + await expect(policy.getByRole('radio', { name: 'Ask', exact: true })).toBeChecked() + await page.goto(selectedUrl) + await expect(page.getByRole('button', { name: 'Reconnect', exact: true })).toBeVisible() + await expect(policy.getByRole('radio', { name: 'Block', exact: true })).toBeChecked() + await capture('integration-selected-account-actions') + await page.getByRole('button', { name: 'Disconnect', exact: true }).click() + const confirmation = page.getByRole('dialog', { name: 'Disconnect Jira', exact: true }) + await expect(confirmation).toContainText('launch-team@acme.example') + await expect(confirmation).not.toContainText('taylor@acme.example') + await capture('integration-selected-account-disconnect') + const disconnected = page.waitForResponse( + (response) => + response.request().method() === 'DELETE' && + new URL(response.url()).pathname === + `/api/users/me/organization-accounts/${secondCredentialId}` + ) + await confirmation.getByRole('button', { name: 'Disconnect', exact: true }).click() + assert.equal((await disconnected).status(), 200) + await expect(confirmation).toBeHidden() + await expect( + page.getByText('This account is no longer connected.', { exact: true }) + ).toBeVisible() + await expect(page.getByRole('textbox', { name: 'Search tools', exact: true })).toHaveCount(0) + const states = + await sql`select id, managed_oauth_status from credential where id in (${credentialId}, ${secondCredentialId})` + assert.equal( + states.find((account) => account.id === credentialId)?.managed_oauth_status, + 'active' + ) + assert.equal( + states.find((account) => account.id === secondCredentialId)?.managed_oauth_status, + 'revoked' + ) + await page.goto(accountsUrl) + await expect(policy.getByRole('radio', { name: 'Ask', exact: true })).toBeChecked() + } + ) + await check( + 'Enabled, disabled and paused empty integrations preserve MCP account isolation', + async () => { + const inventoryResponse = await context.request.get( + `${baseUrl.origin}/api/organizations/${organizationId}/connected-accounts` + ) + assert.equal(inventoryResponse.status(), 200) + const inventory = getOrganizationAccountsContract.response.schema.parse( + await inventoryResponse.json() + ) + assert( + inventory.viewerMcpAccounts?.some( + (account) => account.credentialId === firefliesCredentialId + ) + ) + await page.goto(`${baseUrl.origin}${root}/integrations`) + await page.getByRole('link', { name: 'Open Coda integration', exact: true }).click() + await expect(page).toHaveURL((url) => url.searchParams.get('integration') === 'source:coda') + const detailUrl = page.url() + const connect = page.getByRole('button', { name: 'Connect', exact: true }) + await expect(connect).toBeEnabled() + await expect(page.getByText('No account connected', { exact: true })).toBeVisible() + await expect(page.getByText('meetings@acme.example', { exact: true })).toHaveCount(0) + await capture('integration-enabled-empty') + const forgedUrl = new URL(detailUrl) + forgedUrl.searchParams.set('account', firefliesCredentialId) + await page.goto(forgedUrl.toString()) + await expect( + page.getByText('This account is no longer connected.', { exact: true }) + ).toBeVisible() + await expect(page.getByRole('button', { name: 'Disconnect', exact: true })).toHaveCount(0) + await expect(page.getByRole('textbox', { name: 'Search tools', exact: true })).toHaveCount(0) + await sql`update organization_search_integration set approved = false where organization_id = ${organizationId} and connector_type = 'coda'` + try { + await page.goto(`${baseUrl.origin}${root}/integrations`) + await expect( + page.getByRole('link', { name: 'Open Coda integration', exact: true }) + ).toBeVisible() + await page.getByRole('link', { name: 'Open Coda integration', exact: true }).click() + await expect(page).toHaveURL((url) => url.searchParams.get('integration') === 'source:coda') + await expect(page.getByText('Disabled by your organization', { exact: true })).toBeVisible() + await expect(connect).toBeDisabled() + await capture('integration-disabled-empty') + } finally { + await sql`update organization_search_integration set approved = true where organization_id = ${organizationId} and connector_type = 'coda'` + } + await sql`update credential_group set status = 'disabled' where id = ${groupId}` + try { + await page.reload() + await expect( + page.getByText('Connections are paused by your organization', { exact: true }) + ).toBeVisible() + await expect(connect).toBeDisabled() + await capture('integration-paused-empty') + } finally { + await sql`update credential_group set status = 'active' where id = ${groupId}` + } + } + ) await check('Personal permissions persist through the real settings route', async () => { await page.goto(`${baseUrl.origin}${root}/integrations/accounts/${credentialId}`, { waitUntil: 'domcontentloaded', @@ -402,6 +766,15 @@ try { 'A live Assistant turn restores exact inline actions without duplicating older rows', async () => { await page.setViewportSize({ width: 1440, height: 1000 }) + const reviewUrl = `${baseUrl.origin}/api/organizations/${organizationId}/chats/${assistantId}/actions` + await page.route(reviewUrl, async (route) => { + const response = await route.fetch() + const review = listAssistantActionsContract.response.schema.parse(await response.json()) + await route.fulfill({ + response, + json: { ...review, actions: review.actions.map(({ sequence, ...action }) => action) }, + }) + }) const streamResponse = page.waitForResponse( (response) => new URL(response.url()).pathname === '/api/mothership/chat/stream' && @@ -413,15 +786,35 @@ try { timeout: 180_000, }) assert.equal((await streamResponse).status(), 200) - await expect(reviewCards).toHaveCount(2, { timeout: 180_000 }) - await expect(page.getByText('Earlier Jira proposal', { exact: false })).toBeAttached() + const reviewResponse = await context.request.get( + `${baseUrl.origin}/api/organizations/${organizationId}/chats/${assistantId}/actions` + ) + assert.equal(reviewResponse.status(), 200, await reviewResponse.text()) + const restoredReview = listAssistantActionsContract.response.schema.parse( + await reviewResponse.json() + ) + assert.equal(restoredReview.actions.length, 2) + await expect(reviewCards).toHaveCount(2) + await page.unroute(reviewUrl) + await expect( + page + .getByRole('region', { name: 'Create Jira issue receipt' }) + .filter({ hasText: 'Approved historical title' }) + ).toBeAttached() await expect(page.getByRole('button', { name: 'Allow', exact: true })).toHaveCount(2) + await expect(reviewCards.getByRole('textbox')).toHaveCount(0) + await expect(reviewCards.getByText('Priority', { exact: true })).toHaveCount(0) + const previewBounds = await reviewCards.nth(0).boundingBox() + assert( + previewBounds && previewBounds.height < 310, + 'The default review should fit in a compact preview' + ) await expect( - reviewCards.nth(0).getByRole('textbox', { name: 'Summary', exact: true }) - ).toHaveValue('Publish the launch checklist') + reviewCards.nth(0).getByText('Publish the launch checklist', { exact: true }) + ).toBeVisible() await expect( - reviewCards.nth(1).getByRole('textbox', { name: 'Summary', exact: true }) - ).toHaveValue('Confirm the rollout owners') + reviewCards.nth(1).getByText('Confirm the rollout owners', { exact: true }) + ).toBeVisible() const prompt = await page.getByText(question, { exact: true }).elementHandle() assert(prompt, 'The current user turn must be restored') assert( @@ -456,11 +849,15 @@ try { await page.reload() await expect(reviewCards).toHaveCount(2) await expect( - reviewCards.nth(0).getByRole('textbox', { name: 'Summary', exact: true }) - ).toHaveValue('Publish the launch checklist') - await page.getByText(question, { exact: true }).scrollIntoViewIfNeeded() + reviewCards.nth(0).getByText('Publish the launch checklist', { exact: true }) + ).toBeVisible() + await expect( + page + .getByRole('region', { name: 'Create Jira issue receipt' }) + .filter({ hasText: 'Approved historical title' }) + ).toBeAttached() + await reviewCards.last().scrollIntoViewIfNeeded() await capture('assistant-actions-desktop') - await reviewCards.nth(0).scrollIntoViewIfNeeded() await capture('action-review-desktop') await page.setViewportSize({ width: 390, height: 844 }) await reviewCards.nth(0).scrollIntoViewIfNeeded() @@ -502,10 +899,16 @@ try { await check( 'An edited approval and a cancellation affect only their saved proposals', async () => { + await reviewCards.nth(0).getByRole('button', { name: 'Edit', exact: true }).click() await reviewCards .nth(0) .getByRole('textbox', { name: 'Summary', exact: true }) .fill('Publish the reviewed launch checklist') + await capture('action-review-edit') + await reviewCards.nth(0).getByRole('button', { name: 'Done', exact: true }).click() + await expect( + reviewCards.nth(0).getByText('Publish the reviewed launch checklist', { exact: true }) + ).toBeVisible() const approval = page.waitForResponse( (response) => response.request().method() === 'PATCH' && @@ -516,12 +919,17 @@ try { const approvalResponse = await approval assert.equal(approvalResponse.status(), 200, await approvalResponse.text()) await expect(reviewCards).toHaveCount(1) - await expect(reviewCards.getByRole('textbox', { name: 'Summary', exact: true })).toHaveValue( - 'Confirm the rollout owners' - ) await expect( - page.getByText('No longer waiting for review', { exact: false }).first() + reviewCards.getByText('Confirm the rollout owners', { exact: true }) ).toBeVisible() + const approvedReceipt = page + .getByRole('region', { name: 'Create Jira issue receipt' }) + .filter({ hasText: 'Publish the reviewed launch checklist' }) + await expect(approvedReceipt.getByText('Approved', { exact: true })).toBeVisible() + await approvedReceipt.getByRole('button', { name: 'View Create Jira issue receipt' }).click() + await expect(approvedReceipt.getByRole('textbox')).toHaveCount(0) + await expect(approvedReceipt.getByText('acme.atlassian.net', { exact: true })).toBeVisible() + await approvedReceipt.getByRole('button', { name: 'Hide Create Jira issue receipt' }).click() const cancellation = page.waitForResponse( (response) => response.request().method() === 'PATCH' && @@ -532,6 +940,16 @@ try { const cancellationResponse = await cancellation assert.equal(cancellationResponse.status(), 200, await cancellationResponse.text()) await expect(reviewCards).toHaveCount(0) + const cancelledReceipt = page + .getByRole('region', { name: 'Create Jira issue receipt' }) + .filter({ hasText: 'Confirm the rollout owners' }) + await expect(cancelledReceipt.getByText('Cancelled', { exact: true })).toBeVisible() + await capture('action-receipts-mobile') + await page.setViewportSize({ width: 1440, height: 1000 }) + await capture('action-receipts-desktop') + await page.reload() + await expect(approvedReceipt.getByText('Approved', { exact: true })).toBeVisible() + await expect(cancelledReceipt.getByText('Cancelled', { exact: true })).toBeVisible() const rows = await sql`select tool_call_id, permission_decision, args, approved_args, execution_started_at from copilot_async_tool_calls where run_id = ${runId} order by persist_seq` assert.equal(rows[0]?.permission_decision, 'allow') @@ -568,7 +986,7 @@ try { assert.deepEqual(initialData.actions, []) await insertProposal(lagRunId, lagFirstCallId, 'Review the support handoff') await insertProposal(lagRunId, lagSecondCallId, 'Prepare the launch announcement') - await page.route(`${reviewUrl}*`, (route) => + await page.route(reviewUrl, (route) => route.request().method() === 'GET' ? route.abort('failed') : route.continue() ) try { @@ -577,16 +995,16 @@ try { }) await expect(reviewCards).toHaveCount(0) } finally { - await page.unroute(`${reviewUrl}*`) + await page.unroute(reviewUrl) } await page.getByRole('button', { name: 'Retry', exact: true }).click() await expect(reviewCards).toHaveCount(2) await expect( - reviewCards.nth(0).getByRole('textbox', { name: 'Summary', exact: true }) - ).toHaveValue('Review the support handoff') + reviewCards.nth(0).getByText('Review the support handoff', { exact: true }) + ).toBeVisible() await expect( - reviewCards.nth(1).getByRole('textbox', { name: 'Summary', exact: true }) - ).toHaveValue('Prepare the launch announcement') + reviewCards.nth(1).getByText('Prepare the launch announcement', { exact: true }) + ).toBeVisible() await appendStreamEvents(lagChatId, lagStreamId, [ pendingToolEvent(lagFirstCallId, 'Review the support handoff'), pendingToolEvent(lagSecondCallId, 'Prepare the launch announcement'), @@ -636,8 +1054,8 @@ try { ]) await expect(reviewCards).toHaveCount(1) await expect( - reviewCards.getByRole('textbox', { name: 'Summary', exact: true }) - ).toHaveValue('A later proposal that was never approved') + reviewCards.getByText('A later proposal that was never approved', { exact: true }) + ).toBeVisible() const cancellation = page.waitForResponse( (response) => response.request().method() === 'PATCH' && @@ -814,6 +1232,7 @@ try { } }) try { + await expect(reviewCards.getByRole('button', { name: 'Cancel', exact: true })).toBeEnabled() await reviewCards.getByRole('button', { name: 'Cancel', exact: true }).focus() await page.keyboard.press('Enter') await expect.poll(() => decisionPersisted).toBe(true) @@ -907,11 +1326,130 @@ try { ) assert.equal(response.status(), 404) }) + await check( + 'A 64-action recovery preserves sequence, pagination and receipts with bounded requests', + async () => { + const batchIds = Array.from({ length: 64 }, () => generateId()) + for (const [index, id] of batchIds.entries()) { + await insertProposal(bulkRunId, id, `Batch issue ${index + 1}`) + if (index % 2 === 0) { + await sql`update copilot_async_tool_calls set status = 'delivered', permission_decision = 'skip', permission_decided_at = now() where run_id = ${bulkRunId} and tool_call_id = ${id}` + } + } + await appendStreamEvents(bulkChatId, bulkStreamId, [ + { type: 'session', payload: { kind: 'start' } }, + { type: 'text', payload: { channel: 'assistant', text: 'Review the remaining actions.' } }, + ]) + const responsesBefore = httpResponses.length + await page.goto(`${baseUrl.origin}/o/${organizationId}/chat/${bulkChatId}?mode=assistant`) + const cards = page.locator( + 'section[aria-label="Review Create Jira issue"], section[aria-label="Create Jira issue receipt"]' + ) + await expect(cards).toHaveCount(48) + await expect(cards.nth(0)).toContainText('Batch issue 1') + await expect(cards.nth(0)).toContainText('Cancelled') + await expect(cards.nth(1)).toContainText('Batch issue 2') + const initialReceiptRequests = httpResponses + .slice(responsesBefore) + .filter((response) => response.path.endsWith('/actions/receipts')) + assert( + initialReceiptRequests.length <= 6, + `Recovery made ${initialReceiptRequests.length} receipt requests` + ) + await cards.nth(1).getByRole('button', { name: 'Allow', exact: true }).click() + await expect(cards.nth(1)).toContainText('Approved') + await expect(cards.nth(1)).toContainText('Batch issue 2') + await expect(cards.last()).toContainText('Batch issue 64') + await cards.last().getByRole('button', { name: 'Allow', exact: true }).click() + await expect(cards.last()).toContainText('Approved') + await expect(cards).toHaveCount(48) + await page.getByRole('button', { name: 'More action history', exact: true }).click() + await expect(cards).toHaveCount(64) + await page.reload() + await page.getByRole('button', { name: 'More action history', exact: true }).click() + await expect(cards).toHaveCount(64) + await expect(cards.nth(1)).toContainText('Approved') + await expect(cards.last()).toContainText('Approved') + await expect(cards.last()).toContainText('Batch issue 64') + await capture('approval-paginated-receipts') + const lastCallId = batchIds.at(-1) + const precedingCallId = batchIds.at(-3) + assert(lastCallId && precedingCallId) + await cards.nth(61).getByRole('button', { name: 'Allow', exact: true }).click() + await expect(cards.nth(61)).toContainText('Approved') + await sql`update copilot_async_tool_calls set status = 'completed', execution_started_at = now(), execution_settled_at = now(), completed_at = now(), result = ${sql.json({ success: true })} where run_id = ${bulkRunId} and tool_call_id = ${lastCallId}` + const receiptsUrl = `${baseUrl.origin}/api/organizations/${organizationId}/chats/${bulkChatId}/actions/receipts` + for (const [index, fixture] of [ + { id: lastCallId, summary: 'Batch issue 64', state: 'Completed' }, + { id: precedingCallId, summary: 'Batch issue 62', state: 'Approved' }, + ].entries()) { + const events = [pendingToolEvent(fixture.id, fixture.summary)] + if (fixture.state === 'Completed') + events.push({ + type: 'tool', + payload: { + phase: 'result', + executor: 'sim', + mode: 'async', + toolCallId: fixture.id, + toolName: 'jira_write', + success: true, + status: 'success', + output: { success: true }, + }, + }) + await appendStreamEvents(bulkChatId, bulkStreamId, events) + await page.route(`${receiptsUrl}*`, (route) => { + const ids = new URL(route.request().url()).searchParams.getAll('toolCallIds') + return ids.includes(fixture.id) ? route.abort('failed') : route.continue() + }) + try { + await page.reload() + await expect( + page.getByText('Could not load action history', { exact: true }) + ).toHaveCount(index + 1, { timeout: 15_000 }) + await capture(`receipt-history-${fixture.state.toLowerCase()}-retry`) + } finally { + await page.unroute(`${receiptsUrl}*`) + } + await page.getByRole('button', { name: 'Retry', exact: true }).first().click() + await expect( + page + .getByRole('region', { name: 'Create Jira issue receipt' }) + .filter({ hasText: fixture.summary }) + ).toContainText(fixture.state) + } + } + ) + await check( + 'Automatically allowed writes wait for execution, not a second approval', + async () => { + const autoCallId = generateId() + await insertProposal(runId, autoCallId, 'Automatically allowed issue') + await sql`update copilot_async_tool_calls set permission_requested_at = null where run_id = ${runId} and tool_call_id = ${autoCallId}` + try { + const response = await context.request.get( + `${baseUrl.origin}/api/organizations/${organizationId}/chats/${assistantId}/actions/receipts`, + { params: { toolCallIds: autoCallId } } + ) + assert.equal(response.status(), 200, await response.text()) + const result = listAssistantActionReceiptsContract.response.schema.parse( + await response.json() + ) + assert.equal(result.receipts[0]?.state, 'approved') + } finally { + await sql`delete from copilot_async_tool_calls where run_id = ${runId} and tool_call_id = ${autoCallId}` + } + } + ) await check('Browser runtime and HTTP responses', async () => { assert.deepEqual(browserErrors, []) assert.deepEqual(serverErrors, []) }) } catch (error) { + await writeFile(`${artifactDirectory}/failure.txt`, await page.locator('body').innerText()).catch( + () => undefined + ) logger.error('Assistant actions E2E failed', { error: getErrorMessage(error) }) await page.screenshot({ path: resolve(artifactDirectory, 'failure.png') }).catch(() => undefined) process.exitCode = 1 @@ -942,7 +1480,7 @@ try { await writeFile( reportPath, JSON.stringify( - { checks, browserErrors, serverErrors, httpResponses, artifactDirectory }, + { checks, browserErrors, browserMessages, serverErrors, httpResponses, artifactDirectory }, null, 2 ) diff --git a/apps/sim/scripts/test-organization-search-e2e.ts b/apps/sim/scripts/test-organization-search-e2e.ts index 48b456d5e99..4dd2881ad16 100644 --- a/apps/sim/scripts/test-organization-search-e2e.ts +++ b/apps/sim/scripts/test-organization-search-e2e.ts @@ -4,6 +4,7 @@ import { dirname, resolve } from 'node:path' import { type BrowserContext, chromium, expect } from '@playwright/test' import { assertDisposableTestDatabaseUrl } from '@sim/db/testing/test-infrastructure' import { createLogger } from '@sim/logger' +import { createDeferred } from '@sim/testing/helpers/deferred' import { toStringOrNull } from '@sim/utils/coerce' import { getErrorMessage } from '@sim/utils/errors' import { generateId, generateShortId } from '@sim/utils/id' @@ -11,6 +12,8 @@ import { toRecord } from '@sim/utils/object' import { truncate } from '@sim/utils/string' import { makeSignature } from 'better-auth/crypto' import postgres from 'postgres' +import { searchWorkspaceKnowledgeContract } from '@/lib/api/contracts/knowledge/search' +import { type CreateEventInput, createEvent } from '@/lib/mothership/request/session/event' /** * Runs against a local app and disposable PostgreSQL with member Search and Access Control enabled. @@ -362,29 +365,49 @@ try { 'Search and Assistant preserve independent drafts across tabs and reloads', async () => { await page.goto(`${baseUrl.origin}${root}/search`) - await expect(page.getByRole('radio', { name: 'Search', exact: true })).toBeChecked() + await expect( + page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Search', exact: true }) + ).toHaveAttribute('aria-current', 'page') const searchInput = page.getByRole('textbox', { name: 'Search your sources' }) await searchInput.fill('Launch notes') - await page.getByRole('radio', { name: 'Assistant', exact: true }).click() + await page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Assistant', exact: true }) + .click() const assistantInput = page.getByRole('textbox', { name: 'Ask Sim' }) await expect(assistantInput).toHaveValue('') await assistantInput.fill('Summarize launch readiness') - await page.getByRole('radio', { name: 'Search', exact: true }).click() + await page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Search', exact: true }) + .click() await expect(searchInput).toHaveValue('Launch notes') - await page.getByRole('radio', { name: 'Assistant', exact: true }).click() + await page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Assistant', exact: true }) + .click() await expect(assistantInput).toHaveValue('Summarize launch readiness') await expect(page).toHaveURL( (url) => url.pathname === `${root}/search` && url.searchParams.get('mode') === 'assistant' ) await page.reload() - await expect(page.getByRole('radio', { name: 'Assistant', exact: true })).toBeChecked() + await expect( + page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Assistant', exact: true }) + ).toHaveAttribute('aria-current', 'page') await expect(assistantInput).toHaveValue('Summarize launch readiness') } ) await check( 'Traditional search submits the organization query and keeps results in Search', async () => { - await page.getByRole('radio', { name: 'Search', exact: true }).click() + await page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Search', exact: true }) + .click() const responsePromise = page.waitForResponse( (response) => new URL(response.url()).pathname === '/api/knowledge/search' && @@ -414,24 +437,258 @@ try { 'Summarize launch readiness' ) }) - await check('Saved assistant history opens inside Search and starts a fresh search', async () => { + await check('Changing Search views preserves the conversation, filters, and draft', async () => { + const path = `${root}/search/chat/${assistantId}` + await page.goto(`${baseUrl.origin}${path}?q=Launch&source=slack&updated=7d`) + const input = page.getByRole('textbox', { name: 'Ask Sim' }) + await input.fill('Which owners still need to reply?') + await page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Search', exact: true }) + .click() + await expect(page).toHaveURL( + (url) => url.pathname === path && url.searchParams.get('mode') === 'search' + ) + await page.reload() + await page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Assistant', exact: true }) + .click() + await expect(page.getByText(answer, { exact: true })).toBeVisible() + await expect(input).toHaveValue('Which owners still need to reply?') + const restored = new URL(page.url()) + assert.equal(restored.pathname, path) + assert.equal(restored.searchParams.get('q'), 'Launch') + assert.equal(restored.searchParams.get('source'), 'slack') + assert.equal(restored.searchParams.get('updated'), '7d') + }) + await check('New chat stays in Assistant and starts with a fresh draft', async () => { await page.goto(`${baseUrl.origin}${root}/search/chat/${assistantId}`) - await expect(page.getByRole('radio', { name: 'Assistant', exact: true })).toBeChecked() + await expect( + page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Assistant', exact: true }) + ).toHaveAttribute('aria-current', 'page') await expect(page.getByText(answer, { exact: true })).toBeVisible() await capture('assistant-conversation-desktop') - await page.getByRole('button', { name: 'New search', exact: true }).click() - await expect(page).toHaveURL(`${baseUrl.origin}${root}/search`) - await expect(page.getByRole('radio', { name: 'Search', exact: true })).toBeChecked() + await page.getByRole('button', { name: 'New chat', exact: true }).click() + await expect(page).toHaveURL(`${baseUrl.origin}${root}/search?mode=assistant`) + await expect(page.getByRole('textbox', { name: 'Ask Sim' })).toHaveValue('') + await expect( + page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: 'Assistant', exact: true }) + ).toHaveAttribute('aria-current', 'page') }) + await check( + 'Admission, New chat and repeated summaries preserve mode, context and drafts', + async () => { + const releaseAdmission = createDeferred() + const posts: Record[] = [] + const createdChatIds: string[] = [] + const chatEndpoint = `${baseUrl.origin}/api/mothership/chat` + const searchEndpoint = `${baseUrl.origin}/api/knowledge/search` + const documentId = generateId() + const searchRequests: Record[] = [] + const searchBody = searchWorkspaceKnowledgeContract.body + assert(searchBody) + await page.route(searchEndpoint, async (route) => { + const body = searchBody.parse(route.request().postDataJSON()) + searchRequests.push(body) + await route.fulfill({ + json: searchWorkspaceKnowledgeContract.response.schema.parse({ + success: true, + data: { + query: body.query, + retrieval: { status: 'complete', timedOutLegs: [] }, + results: [ + { + documentId, + knowledgeBaseId: generateId(), + knowledgeBaseName: 'Team documents', + documentName: 'Launch checklist', + sourceUrl: 'https://example.invalid/launch', + connectorType: 'slack', + sourceModifiedAt: new Date().toISOString(), + author: null, + content: 'The launch checklist is ready for review.', + chunkIndex: 0, + similarity: 1, + }, + ], + }, + }), + }) + }) + await page.route(chatEndpoint, async (route) => { + if (route.request().method() !== 'POST') return route.continue() + const body = toRecord(route.request().postDataJSON()) + const number = posts.push(body) + if (number === 1) await releaseAdmission.promise + const chatId = toStringOrNull(body.chatId) ?? generateId() + const streamId = toStringOrNull(body.userMessageId) + assert(streamId) + assert.equal(body.organizationId, organizationId) + assert.equal(body.mode, 'assistant') + createdChatIds.push(chatId) + const responseText = `Deterministic assistant response ${number}.` + const requestId = generateId() + await sql`insert into copilot_chats (id, user_id, organization_id, type, title, config) + values (${chatId}, ${userId}, ${organizationId}, 'mothership', 'Navigation test', ${sql.json({ conversationMode: 'assistant' })}) on conflict (id) do nothing` + for (const message of [ + { id: streamId, role: 'user', content: String(body.message) }, + { id: generateId(), role: 'assistant', content: responseText }, + ]) { + await sql`insert into copilot_messages (id, chat_id, message_id, role, stream_id, content, seq) + values (${generateId()}, ${chatId}, ${message.id}, ${message.role}, ${streamId}, ${sql.json({ ...message, requestId, timestamp: new Date().toISOString() })}, (select coalesce(max(seq), 0) + 1 from copilot_messages where chat_id = ${chatId}))` + } + const base = { chatId, streamId, requestId } + const events: CreateEventInput[] = [ + { ...base, cursor: '1', seq: 1, type: 'session', payload: { kind: 'chat', chatId } }, + { + ...base, + cursor: '2', + seq: 2, + type: 'text', + payload: { channel: 'assistant', text: responseText, textOffset: 0 }, + }, + { + ...base, + cursor: '3', + seq: 3, + type: 'complete', + payload: { status: 'complete', textLength: responseText.length }, + }, + ] + await route.fulfill({ + status: 200, + headers: { 'content-type': 'text/event-stream', 'x-mothership-chat-id': chatId }, + body: `${events.map((event) => `data: ${JSON.stringify(createEvent(event))}\n\n`).join('')}data: [DONE]\n\n`, + }) + }) + try { + await page.goto(`${baseUrl.origin}${root}/search?q=Launch&source=slack&updated=7d`) + const navigation = page.getByRole('navigation', { name: 'Search views' }) + await navigation.getByRole('button', { name: 'Assistant', exact: true }).click() + const composer = page.getByRole('textbox', { name: 'Ask Sim' }) + await composer.fill('A new conversation before admission') + await composer.press('Enter') + await expect.poll(() => posts.length).toBe(1) + await page.goBack() + await expect( + navigation.getByRole('button', { name: 'Search', exact: true }) + ).toHaveAttribute('aria-current', 'page') + releaseAdmission.resolve() + await expect(page).toHaveURL( + (url) => + url.pathname === `${root}/search/chat/${createdChatIds[0]}` && + url.searchParams.get('mode') === 'search' + ) + assert.equal(new URL(page.url()).searchParams.get('q'), 'Launch') + assert.equal(new URL(page.url()).searchParams.get('source'), 'slack') + assert.equal(new URL(page.url()).searchParams.get('updated'), '7d') + await expect( + page.getByText('Deterministic assistant response 1.', { exact: true }) + ).not.toBeVisible() + await navigation.getByRole('button', { name: 'Assistant', exact: true }).click() + await expect( + page.getByText('Deterministic assistant response 1.', { exact: true }) + ).toBeVisible() + await composer.fill('An unsent follow-up') + await page.getByRole('button', { name: 'New chat', exact: true }).click() + await expect(page).toHaveURL(`${baseUrl.origin}${root}/search?mode=assistant`) + await expect(composer).toHaveValue('') + await composer.fill('A distinct new conversation') + await composer.press('Enter') + await expect( + page.getByText('Deterministic assistant response 2.', { exact: true }) + ).toBeVisible() + assert.equal(posts.length, 2) + assert.equal(posts[1]?.createNewChat, true) + assert.equal(posts[1]?.chatId, undefined) + assert.notEqual(createdChatIds[0], createdChatIds[1]) + await expect(page).toHaveURL( + (url) => url.pathname === `${root}/search/chat/${createdChatIds[1]}` + ) + await page.reload() + await expect( + page.getByText('Deterministic assistant response 2.', { exact: true }) + ).toBeVisible() + await expect( + page.getByText('Deterministic assistant response 1.', { exact: true }) + ).toHaveCount(0) + await capture('assistant-new-chat-after-admission') + const summaryStartedAt = Date.now() + await page.goto(`${baseUrl.origin}${root}/search?q=Launch&source=slack&updated=7d`) + await page + .getByRole('button', { name: 'Actions for Launch checklist', exact: true }) + .click() + await page.getByRole('menuitem', { name: 'Summarize', exact: true }).click() + await expect( + page.getByText('Deterministic assistant response 3.', { exact: true }) + ).toBeVisible() + const summaryChatId = createdChatIds[2] + assert.equal(posts[2]?.createNewChat, true) + assert.equal(posts[2]?.assistantSearchLevel, 'fast') + const { modifiedAfter: firstCutoff, ...firstSummaryFilters } = toRecord( + posts[2]?.assistantSearch + ) + const { modifiedAfter: searchCutoff, ...searchFilters } = toRecord( + searchRequests.at(-1)?.filters + ) + assert.equal(searchFilters.source, 'slack') + assert.deepEqual(firstSummaryFilters, { ...searchFilters, documentIds: [documentId] }) + assert.equal(typeof firstCutoff, 'string') + assert(Date.parse(String(firstCutoff)) >= summaryStartedAt - 7 * 24 * 60 * 60 * 1000) + assert(Date.parse(String(firstCutoff)) <= Date.now() - 7 * 24 * 60 * 60 * 1000) + await composer.fill('Keep this unsent draft') + await navigation.getByRole('button', { name: 'Search', exact: true }).click() + await page + .getByRole('button', { name: 'Actions for Launch checklist', exact: true }) + .click() + await page.getByRole('menuitem', { name: 'Summarize', exact: true }).click() + await expect( + page.getByText('Deterministic assistant response 4.', { exact: true }) + ).toBeVisible() + assert.equal(posts.length, 4) + assert.equal(posts[3]?.chatId, summaryChatId) + assert.equal(posts[3]?.createNewChat, false) + const { modifiedAfter: repeatedCutoff, ...repeatedSummaryFilters } = toRecord( + posts[3]?.assistantSearch + ) + assert.deepEqual(repeatedSummaryFilters, firstSummaryFilters) + assert.equal(typeof repeatedCutoff, 'string') + assert(Date.parse(String(repeatedCutoff)) >= Date.parse(String(firstCutoff))) + assert(Date.parse(String(repeatedCutoff)) <= Date.now() - 7 * 24 * 60 * 60 * 1000) + await expect(composer).toHaveValue('Keep this unsent draft') + await capture('assistant-repeat-summary-preserves-draft') + } finally { + releaseAdmission.resolve() + await page.unroute(chatEndpoint) + await page.unroute(searchEndpoint) + } + } + ) await check('Existing assistant bookmarks redirect into Search', async () => { await page.goto(`${baseUrl.origin}${root}/chat/${assistantId}`) await expect(page).toHaveURL(`${baseUrl.origin}${root}/search/chat/${assistantId}`) await expect(page.getByText(answer, { exact: true })).toBeVisible() }) + await check('New search clears its draft while Back restores the prior query draft', async () => { + await page.goto(`${baseUrl.origin}${root}/search?q=Launch`) + const input = page.getByRole('textbox', { name: 'Search your sources' }) + await input.fill('Edited launch query') + await page.getByRole('button', { name: 'New search', exact: true }).click() + await expect(page).toHaveURL(`${baseUrl.origin}${root}/search`) + await expect(input).toHaveValue('') + await page.goBack() + await expect(input).toHaveValue('Edited launch query') + assert.equal(new URL(page.url()).searchParams.get('q'), 'Launch') + }) await check('Search URLs cannot change an agent conversation into an assistant', async () => { await page.goto(`${baseUrl.origin}${root}/search/chat/${agentId}`) await expect(page).toHaveURL(`${baseUrl.origin}${root}/chat/${agentId}`) - await expect(page.getByRole('radiogroup', { name: 'Search mode' })).toHaveCount(0) + await expect(page.getByRole('navigation', { name: 'Search views' })).toHaveCount(0) }) await check('Assistant history rejects a chat from another organization', async () => { await page.goto(`${baseUrl.origin}${root}/search/chat/${deniedChatId}`) @@ -447,8 +704,10 @@ try { for (const mode of ['search', 'assistant'] as const) { await page.goto(`${baseUrl.origin}${root}/search?mode=${mode}`) await expect( - page.getByRole('radio', { name: mode === 'search' ? 'Search' : 'Assistant', exact: true }) - ).toBeChecked() + page + .getByRole('navigation', { name: 'Search views' }) + .getByRole('button', { name: mode === 'search' ? 'Search' : 'Assistant', exact: true }) + ).toHaveAttribute('aria-current', 'page') await expect( page.getByRole('textbox', { name: mode === 'search' ? 'Search your sources' : 'Ask Sim' }) ).toBeVisible() From 366f2e976a7d0ba06bc0743a99fd06d9dc411c14 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 29 Oct 2026 22:07:07 -0700 Subject: [PATCH 2/2] fix(search): preserve current view and uncertain action outcomes --- .../components/organization-conversation.tsx | 22 +++++++++- .../o/[organizationId]/integrations/utils.ts | 6 +-- .../agent-group/lane-activity.test.ts | 36 ++++++++++++++++ .../components/agent-group/lane-activity.ts | 14 +++++- .../[workspaceId]/home/hooks/chat-url.ts | 19 +------- .../hooks/stream/handle-session-event.test.ts | 17 +------- .../home/hooks/stream/handle-session-event.ts | 14 +----- .../home/hooks/stream/stream-context.ts | 3 +- .../home/hooks/stream/stream-test-helpers.ts | 1 - .../[workspaceId]/home/hooks/use-chat.ts | 17 +++++--- .../assistant-actions/application/receipts.ts | 4 +- .../sim/scripts/test-assistant-actions-e2e.ts | 29 +++++++++++++ .../scripts/test-organization-search-e2e.ts | 43 ++++++++++++++++++- scripts/check-explicit-any.baseline.json | 1 - 14 files changed, 159 insertions(+), 67 deletions(-) diff --git a/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx b/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx index 1879deb50a7..10b68ba5a24 100644 --- a/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx +++ b/apps/sim/app/o/[organizationId]/components/organization-conversation.tsx @@ -4,7 +4,7 @@ import { type ReactNode, useCallback, useEffect, useRef, useState } from 'react' import { toast } from '@sim/emcn' import { toRecord } from '@sim/utils/object' import { useQueryClient } from '@tanstack/react-query' -import { useQueryStates } from 'nuqs' +import { createSerializer, useQueryStates } from 'nuqs' import { AssistantActionReviewProvider } from '@/components/assistant-actions' import { requestJson } from '@/lib/api/client/request' import type { WorkspaceSearchFilters } from '@/lib/api/contracts/knowledge' @@ -16,6 +16,7 @@ import { getMothershipAttachmentUrl, } from '@/lib/mothership/chat/attachment-preview' import { createSearchResource } from '@/lib/mothership/resources/search' +import { organizationRoutes } from '@/lib/navigation/paths' import { OrganizationLanding } from '@/app/o/[organizationId]/components/organization-landing' import { Composer } from '@/app/o/[organizationId]/home/components/composer' import { GetStarted } from '@/app/o/[organizationId]/home/components/get-started' @@ -41,6 +42,7 @@ import { import { useRestoredChatEntry } from '@/app/workspace/[workspaceId]/home/hooks/use-restored-chat-entry' import { fetchWorkspaceResourceRef } from '@/app/workspace/[workspaceId]/home/resolve-resource-ref' import { + resourceParam, searchFilterParsers, searchFiltersFromParams, } from '@/app/workspace/[workspaceId]/home/search-params' @@ -63,6 +65,12 @@ export interface OrganizationSummaryRequest { assistantSearch: WorkspaceSearchFilters } +const serializeSearchConversation = createSerializer({ + ...organizationSearchParsers, + ...searchFilterParsers, + [resourceParam.key]: resourceParam.parser, +}) + interface OrganizationConversationProps { active?: boolean summaryRequest?: OrganizationSummaryRequest @@ -110,10 +118,11 @@ function OrganizationConversationContent({ const [planning, setPlanning] = useState(false) const requestMode = destinationMode === 'agent' && !chatId && planEnabled && planning ? 'plan' : destinationMode - const [{ q, source, updated, from, to }] = useQueryStates( + const [searchParams] = useQueryStates( { ...organizationSearchParsers, ...searchFilterParsers }, organizationSearchUrlKeys ) + const { q, source, updated, from, to } = searchParams const controller = useResourcePanelController() const queryClient = useQueryClient() const chat = useChat( @@ -121,6 +130,15 @@ function OrganizationConversationContent({ chatId, getMothershipUseChatOptions({ requestMode, + getChatUrl: + destinationMode === 'assistant' + ? (id) => + serializeSearchConversation(organizationRoutes(organization.id).searchChat(id), { + ...searchParams, + mode: active ? 'assistant' : 'search', + resource: controller.activeResourceState[0], + }) + : undefined, onResourceEvent: controller.onResourceEvent, activeResourceState: controller.activeResourceState, }) diff --git a/apps/sim/app/o/[organizationId]/integrations/utils.ts b/apps/sim/app/o/[organizationId]/integrations/utils.ts index ac6c0719e2e..e00352082a5 100644 --- a/apps/sim/app/o/[organizationId]/integrations/utils.ts +++ b/apps/sim/app/o/[organizationId]/integrations/utils.ts @@ -27,13 +27,9 @@ export function assistantAccountOptions(data: OrganizationAccountsSettings, sear const providers = data.assistantProviders.filter( (provider) => !SEARCH_ACCOUNT_PROVIDERS.has(provider) ) - const ownedOptions = new Set(data.viewerAccounts?.map((account) => account.optionId)) const configured = data.credentialGroup?.options.filter( - (option) => - !SEARCH_ACCOUNT_PROVIDERS.has(option.provider) && - ((option.status === 'active' && providers.includes(option.provider)) || - ownedOptions.has(option.id)) + (option) => !SEARCH_ACCOUNT_PROVIDERS.has(option.provider) ) ?? [] const query = search.trim().toLowerCase() const visible = configured.filter((option) => diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.test.ts b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.test.ts index 580318ef609..8b48a308a20 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.test.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.test.ts @@ -13,6 +13,42 @@ const liveId = (items: AgentGroupItem[], isOpen = true) => { } describe('getLaneLiveIndicator', () => { + it.each([false, true])( + 'leaves the turn indicator visible when a settled action is lifted (nested: %s)', + (nested) => { + const action = call('action', 'jira_write') + const items: AgentGroupItem[] = nested + ? [ + { + type: 'agent_group', + group: { + id: 'child', + agentName: 'research', + agentLabel: 'Research', + items: [action], + isDelegating: false, + isOpen: true, + }, + }, + ] + : [action] + const input = { + kind: 'subagent' as const, + parts: [items], + isActive: true, + isOpen: true, + standaloneToolIds: new Set(['action']), + } + expect(getLaneLiveIndicator(input)).toBeUndefined() + expect( + getLaneLiveIndicator({ + ...input, + parts: [[...items, { type: 'text', content: 'Checking the result.' }]], + }) + ).toEqual({ type: 'narration' }) + } + ) + it('gives the gap to a succeeded trailing call, including search, never a failure', () => { expect(liveId([call('s', 'search_workspace'), call('a', 'read')])).toBe('a') expect(liveId([call('a', 'read'), call('s', 'search_workspace')])).toBe('s') diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts index 9b124caa1e8..946322ab9b5 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts @@ -162,6 +162,18 @@ function getMainTrailingCall( return last?.type === 'run' ? last.run.tools.at(-1) : undefined } +function hasVisibleLaneContent( + items: AgentGroupItem[], + standaloneToolIds?: ReadonlySet +): boolean { + return items.some((item) => { + if (item.type === 'tool') return !standaloneToolIds?.has(item.data.id) + if (item.type === 'agent_group') + return Boolean(item.group.error) || hasVisibleLaneContent(item.group.items, standaloneToolIds) + return hasAgentGroupItemContent(item) + }) +} + /** * The one live indicator of a lane, if it has one. See * {@link getTurnLiveIndicators} for the rule this implements. @@ -183,7 +195,7 @@ export function getLaneLiveIndicator({ if (running) return { type: 'call', tool: running } if (!isOpen) return undefined if (kind === 'subagent' && calls.length === 0) { - return parts.some((items) => items.some(hasAgentGroupItemContent)) + return parts.some((items) => hasVisibleLaneContent(items, standaloneToolIds)) ? { type: 'narration' } : undefined } diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts index f430ec1a481..834735f1bcb 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/chat-url.ts @@ -1,12 +1,8 @@ import { organizationRoutes } from '@/lib/navigation/paths' -import { organizationSearchParsers } from '@/app/o/[organizationId]/search/search-params' -import { - resourceParam, - searchFilterParsers, -} from '@/app/workspace/[workspaceId]/home/search-params' +import { resourceParam } from '@/app/workspace/[workspaceId]/home/search-params' import type { ChatRequestMode } from '@/app/workspace/[workspaceId]/home/types' -/** Preserve resource and Search context when a new conversation receives its chat URL. */ +/** Preserve the selected resource when a new conversation receives its default chat URL. */ export function chatUrl( owner: string | { organizationId: string }, chatId: string, @@ -17,17 +13,6 @@ export function chatUrl( const carried = new URLSearchParams() const resource = current.get(resourceParam.key) if (resource) carried.set(resourceParam.key, resource) - if (typeof owner === 'object' && mode === 'assistant') { - for (const key of Object.keys({ ...organizationSearchParsers, ...searchFilterParsers })) { - const value = current.get(key) - if (value) carried.set(key, value) - } - if ( - organizationSearchParsers.mode.parse(current.get('mode') ?? '') === null && - window.location.pathname === routes?.search - ) - carried.set('mode', 'search') - } const search = carried.toString() const path = routes ? mode === 'assistant' diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.test.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.test.ts index 2cfef4249de..00a7b942797 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.test.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.test.ts @@ -18,23 +18,8 @@ function chatSessionEvent(chatId: string): PersistedStreamEventEnvelope { } describe('handleSessionEvent', () => { - it.each([ - ['assistant', '/o/organization-1/search/chat/chat-new'], - ['agent', '/o/organization-1/chat/chat-new'], - ['plan', '/o/organization-1/chat/chat-new'], - ] as const)( - 'keeps a newly created %s conversation on its owning surface', - (requestMode, path) => { - window.history.replaceState(null, '', '/o/organization-1/search?view=assistant') - const deps = { ...makeStreamLoopDeps(), organizationId: 'organization-1', requestMode } - handleSessionEvent({ deps } as StreamLoopContext, chatSessionEvent('chat-new') as never) - expect(window.location.pathname).toBe(path) - } - ) - it('adopts a newly assigned chat before chatIdRef is written', () => { const deps = makeStreamLoopDeps() - deps.workflowIdRef.current = 'workflow-1' vi.mocked(deps.adoptResolvedChatId).mockImplementation((chatId) => { expect(deps.chatIdRef.current).toBeUndefined() deps.chatIdRef.current = chatId @@ -42,7 +27,7 @@ describe('handleSessionEvent', () => { handleSessionEvent({ deps } as StreamLoopContext, chatSessionEvent('chat-new') as never) - expect(deps.adoptResolvedChatId).toHaveBeenCalledWith('chat-new') + expect(deps.adoptResolvedChatId).toHaveBeenCalledWith('chat-new', { replaceHomeHistory: true }) expect(deps.chatIdRef.current).toBe('chat-new') }) }) diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts index 7c8cee48915..2dced15c209 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts @@ -1,7 +1,6 @@ import { getLiveAssistantMessageId } from '@/lib/mothership/chat/live-message-id' import { MothershipStreamV1SessionKind } from '@/lib/mothership/generated/mothership-stream-v1' import type { PersistedStreamEventEnvelope } from '@/lib/mothership/request/session/contract' -import { chatUrl } from '@/app/workspace/[workspaceId]/home/hooks/chat-url' import type { StreamLoopContext } from '@/app/workspace/[workspaceId]/home/hooks/stream/stream-context' import { type MothershipChatHistory, mothershipChatKeys } from '@/hooks/queries/mothership-chats' @@ -24,7 +23,7 @@ export function handleSessionEvent(ctx: StreamLoopContext, parsed: SessionEvent) // This synchronously migrates provisional browser/terminal ownership // before writing chatIdRef. Assigning the ref here first would make the // adoption path believe there was no provisional scope to move. - deps.adoptResolvedChatId(payloadChatId) + deps.adoptResolvedChatId(payloadChatId, { replaceHomeHistory: true }) } else { deps.chatIdRef.current = payloadChatId if (payloadChatId === selected) { @@ -61,17 +60,6 @@ export function handleSessionEvent(ctx: StreamLoopContext, parsed: SessionEvent) ) } deps.setPendingMessages([]) - if (!deps.workflowIdRef.current) { - window.history.replaceState( - null, - '', - chatUrl( - deps.organizationId ? { organizationId: deps.organizationId } : deps.workspaceId!, - payloadChatId, - deps.requestMode - ) - ) - } } } diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts index 241dde16c46..8acb6b2c2ae 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts @@ -115,7 +115,7 @@ export interface StreamLoopDeps { setPendingMessages: Dispatch> setResolvedChatId: Dispatch> /** Adopts a server-created chat before any event handler mutates chatIdRef. */ - adoptResolvedChatId: (chatId: string) => void + adoptResolvedChatId: (chatId: string, options?: { replaceHomeHistory?: boolean }) => void setResources: Dispatch> setActiveResourceId: Dispatch> @@ -185,7 +185,6 @@ export interface StreamLoopDeps { pendingUserMsgRef: MutableRefObject activeTurnRef: MutableRefObject resourcesRef: MutableRefObject - workflowIdRef: MutableRefObject activeResourceIdRef: MutableRefObject onTitleUpdateRef: MutableRefObject<(() => void) | undefined> onToolResultRef: MutableRefObject< diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-test-helpers.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-test-helpers.ts index 7167f21d267..eab43892e2d 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-test-helpers.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-test-helpers.ts @@ -79,7 +79,6 @@ export function makeStreamLoopDeps(overrides: Partial = {}): Str pendingUserMsgRef: ref(null), activeTurnRef: ref(null), resourcesRef: ref([]), - workflowIdRef: ref(undefined), activeResourceIdRef: ref(null), onTitleUpdateRef: ref<(() => void) | undefined>(undefined), onToolResultRef: ref< diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index 60f6f83debf..77a5192e5f5 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -657,6 +657,8 @@ export function shouldQueueOutgoingMessage( export interface UseChatOptions { /** Intent for new turns; persisted chat intent remains authoritative on reload. */ requestMode?: ChatRequestMode + /** Build the admitted conversation URL from the owning surface's current view state. */ + getChatUrl?: (chatId: string) => string onResourceEvent?: ResourceEventHandler apiPath?: string stopPath?: string @@ -707,6 +709,7 @@ export function getMothershipUseChatOptions( | 'activeResourceState' | 'onRequestStarted' | 'requestMode' + | 'getChatUrl' > = {} ): UseChatOptions { return { @@ -771,6 +774,8 @@ export function useChat( const [activeResourceId, setActiveResourceId] = options?.activeResourceState ?? internalActiveResourceState const onResourceEventRef = useRef(options?.onResourceEvent) + const getChatUrlRef = useRef(options?.getChatUrl) + getChatUrlRef.current = options?.getChatUrl const revealedSimKeysRef = useRef(null) const revealedSimKeys = (revealedSimKeysRef.current ??= new Map()) onResourceEventRef.current = options?.onResourceEvent @@ -1367,11 +1372,12 @@ export function useChat( window.history.replaceState( null, '', - chatUrl( - organizationId ? { organizationId } : workspaceId!, - chatId, - requestModeRef.current - ) + getChatUrlRef.current?.(chatId) ?? + chatUrl( + organizationId ? { organizationId } : workspaceId!, + chatId, + requestModeRef.current + ) ) } if (options?.invalidateList) { @@ -2414,7 +2420,6 @@ export function useChat( pendingUserMsgRef, activeTurnRef, resourcesRef, - workflowIdRef, activeResourceIdRef, onTitleUpdateRef, onToolResultRef, diff --git a/apps/sim/lib/assistant-actions/application/receipts.ts b/apps/sim/lib/assistant-actions/application/receipts.ts index 238a2a41384..8f7bd7dca40 100644 --- a/apps/sim/lib/assistant-actions/application/receipts.ts +++ b/apps/sim/lib/assistant-actions/application/receipts.ts @@ -126,9 +126,9 @@ export const listOrganizationAssistantActionReceipts = defineAuthorizedOrganizat record.currentStreamId !== record.streamId || toolStartWindowClosed(record.deadlineAt?.getTime(), now) let state: ReceiptState - if (record.status === 'completed') state = 'succeeded' + if (record.outcomeUnknown) state = 'uncertain' + else if (record.status === 'completed') state = 'succeeded' else if ( - record.outcomeUnknown || (record.startedAt && record.revokedAt) || (record.startedAt && record.status === 'cancelled') ) diff --git a/apps/sim/scripts/test-assistant-actions-e2e.ts b/apps/sim/scripts/test-assistant-actions-e2e.ts index 59a8acfc992..2457d8b8d07 100644 --- a/apps/sim/scripts/test-assistant-actions-e2e.ts +++ b/apps/sim/scripts/test-assistant-actions-e2e.ts @@ -425,6 +425,14 @@ try { ) assert(!JSON.stringify(result).includes('privatePayload')) const cases = [ + { + status: 'completed', + decision: 'allow', + started: true, + revoked: false, + unknown: true, + expected: 'uncertain', + }, { status: 'pending', decision: 'skip', @@ -738,6 +746,27 @@ try { } finally { await sql`update credential_group set status = 'active' where id = ${groupId}` } + await sql`update credential set managed_oauth_status = 'revoked' where id = ${nativeCredentialId}` + await sql`update credential_group set options = (select jsonb_agg(case when value->>'id' = 'salesforce' then value || '{"status":"disabled"}'::jsonb else value end) from jsonb_array_elements(options)) where id = ${groupId}` + try { + await page.goto(`${baseUrl.origin}${root}/integrations`) + const salesforce = page.getByRole('link', { + name: 'Open Salesforce integration', + exact: true, + }) + await expect(salesforce).toBeVisible() + await salesforce.click() + await expect(page).toHaveURL( + (url) => url.searchParams.get('integration') === 'app:salesforce' + ) + await expect(page.getByText('No account connected', { exact: true })).toBeVisible() + await expect(page.getByText('Connections unavailable', { exact: true })).toBeVisible() + await expect(connect).toHaveCount(0) + await capture('integration-disabled-app-empty') + } finally { + await sql`update credential set managed_oauth_status = 'active' where id = ${nativeCredentialId}` + await sql`update credential_group set options = (select jsonb_agg(case when value->>'id' = 'salesforce' then value || '{"status":"active"}'::jsonb else value end) from jsonb_array_elements(options)) where id = ${groupId}` + } } ) await check('Personal permissions persist through the real settings route', async () => { diff --git a/apps/sim/scripts/test-organization-search-e2e.ts b/apps/sim/scripts/test-organization-search-e2e.ts index 4dd2881ad16..69c247772a6 100644 --- a/apps/sim/scripts/test-organization-search-e2e.ts +++ b/apps/sim/scripts/test-organization-search-e2e.ts @@ -484,6 +484,8 @@ try { 'Admission, New chat and repeated summaries preserve mode, context and drafts', async () => { const releaseAdmission = createDeferred() + let heldAdmission: Promise | undefined + let includeAdmissionHeader = true const posts: Record[] = [] const createdChatIds: string[] = [] const chatEndpoint = `${baseUrl.origin}/api/mothership/chat` @@ -525,6 +527,7 @@ try { const body = toRecord(route.request().postDataJSON()) const number = posts.push(body) if (number === 1) await releaseAdmission.promise + await heldAdmission const chatId = toStringOrNull(body.chatId) ?? generateId() const streamId = toStringOrNull(body.userMessageId) assert(streamId) @@ -562,7 +565,10 @@ try { ] await route.fulfill({ status: 200, - headers: { 'content-type': 'text/event-stream', 'x-mothership-chat-id': chatId }, + headers: { + 'content-type': 'text/event-stream', + ...(includeAdmissionHeader ? { 'x-mothership-chat-id': chatId } : {}), + }, body: `${events.map((event) => `data: ${JSON.stringify(createEvent(event))}\n\n`).join('')}data: [DONE]\n\n`, }) }) @@ -662,6 +668,41 @@ try { assert(Date.parse(String(repeatedCutoff)) <= Date.now() - 7 * 24 * 60 * 60 * 1000) await expect(composer).toHaveValue('Keep this unsent draft') await capture('assistant-repeat-summary-preserves-draft') + for (const selectedMode of ['search', 'assistant'] as const) { + includeAdmissionHeader = selectedMode === 'search' + await page.goto(`${baseUrl.origin}${root}/search?mode=assistant&q=Launch&source=slack`) + await composer.fill(`Preserve the pending ${selectedMode} selection`) + const admission = createDeferred() + heldAdmission = admission.promise + const requestNumber = posts.length + 1 + try { + await composer.press('Enter') + await expect.poll(() => posts.length).toBe(requestNumber) + if (selectedMode === 'assistant') { + await navigation.getByRole('button', { name: 'Search', exact: true }).click() + await expect(page).toHaveURL((url) => url.searchParams.get('mode') === 'search') + } + await page.clock.pauseAt(new Date(Date.now() + 100)) + const selected = navigation.getByRole('button', { + name: selectedMode === 'assistant' ? 'Assistant' : 'Search', + exact: true, + }) + await selected.click({ force: true }) + await expect(selected).toHaveAttribute('aria-current', 'page') + assert.notEqual(new URL(page.url()).searchParams.get('mode'), selectedMode) + admission.resolve() + await expect(page).toHaveURL( + (url) => + url.pathname === `${root}/search/chat/${createdChatIds.at(-1)}` && + url.searchParams.get('mode') === selectedMode + ) + assert.equal(new URL(page.url()).searchParams.get('source'), 'slack') + } finally { + admission.resolve() + heldAdmission = undefined + await page.clock.resume() + } + } } finally { releaseAdmission.resolve() await page.unroute(chatEndpoint) diff --git a/scripts/check-explicit-any.baseline.json b/scripts/check-explicit-any.baseline.json index fe4c7d33dea..df78587a75a 100644 --- a/scripts/check-explicit-any.baseline.json +++ b/scripts/check-explicit-any.baseline.json @@ -1190,7 +1190,6 @@ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-tabs/resource-tabs.tsx": 1, "apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/use-prompt-editor.test.tsx": 1, "apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx": 2, - "apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-session-event.ts": 1, "apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts": 2, "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/components/chunk-context-menu/chunk-context-menu.tsx": 1, "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx": 1,