From 5f068a7ecddf29b13dcb86ba53b881d302d31a02 Mon Sep 17 00:00:00 2001 From: "cristiano.hoshikawa" Date: Thu, 20 Aug 2026 13:16:49 -0300 Subject: [PATCH] adjustments: route stickness usefull tokens only --- ..._GENERIC_DETERMINISTIC_INTENT_SHIFT_V15.md | 47 ++++ .../__pycache__/__init__.cpython-313.pyc | Bin 391 -> 391 bytes .../__pycache__/idempotency.cpython-313.pyc | Bin 5675 -> 5675 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 193 -> 193 bytes .../cache/__pycache__/cache.cpython-313.pyc | Bin 16503 -> 16503 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 194 -> 194 bytes .../__pycache__/settings.cpython-313.pyc | Bin 12549 -> 12549 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 286 -> 286 bytes .../mcp_gateway_client.cpython-313.pyc | Bin 3312 -> 3312 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 388 -> 388 bytes .../__pycache__/mcp_mapper.cpython-313.pyc | Bin 4672 -> 4672 bytes .../__pycache__/models.cpython-313.pyc | Bin 3124 -> 3124 bytes .../__pycache__/resolver.cpython-313.pyc | Bin 4693 -> 4693 bytes .../mcp/__pycache__/__init__.cpython-313.pyc | Bin 453 -> 453 bytes .../mcp/__pycache__/client.cpython-313.pyc | Bin 18406 -> 18406 bytes .../mcp/__pycache__/models.cpython-313.pyc | Bin 2116 -> 2116 bytes .../mcp/__pycache__/registry.cpython-313.pyc | Bin 4720 -> 4720 bytes .../__pycache__/tool_policy.cpython-313.pyc | Bin 4717 -> 4717 bytes .../__pycache__/tool_router.cpython-313.pyc | Bin 13998 -> 13998 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 1115 -> 1115 bytes .../message_history.cpython-313.pyc | Bin 8339 -> 8339 bytes .../summary_memory.cpython-313.pyc | Bin 12490 -> 12490 bytes .../__pycache__/summary_store.cpython-313.pyc | Bin 9500 -> 9500 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 194 -> 194 bytes .../__pycache__/session.cpython-313.pyc | Bin 2688 -> 2688 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 199 -> 199 bytes .../__pycache__/sqlite_store.cpython-313.pyc | Bin 14998 -> 14998 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 405 -> 405 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 2276 -> 2276 bytes .../__pycache__/continuity.cpython-313.pyc | Bin 13218 -> 13218 bytes .../enterprise_router.cpython-313.pyc | Bin 14210 -> 18938 bytes .../__pycache__/models.cpython-313.pyc | Bin 2426 -> 2426 bytes .../routing/enterprise_router.py | 62 +++++- .../__pycache__/__init__.cpython-313.pyc | Bin 328 -> 328 bytes .../__pycache__/agent_runtime.cpython-313.pyc | Bin 133760 -> 133760 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 888 -> 858 bytes .../__pycache__/graph.cpython-313.pyc | Bin 1425 -> 1395 bytes .../__pycache__/models.cpython-313.pyc | Bin 5242 -> 5212 bytes .../__pycache__/registry.cpython-313.pyc | Bin 2371 -> 2341 bytes .../__pycache__/repository.cpython-313.pyc | Bin 2724 -> 2694 bytes .../__pycache__/runtime.cpython-313.pyc | Bin 29137 -> 29107 bytes .../__pycache__/tool_executor.cpython-313.pyc | Bin 1976 -> 1946 bytes .../templates/agent_template_backend/.env | 207 ------------------ .../agent_template_backend/.env.example} | 62 +++--- .../conftest.cpython-313-pytest-9.0.2.pyc | Bin 787 -> 787 bytes ...saction_shift.cpython-313-pytest-9.0.2.pyc | Bin 10512 -> 25772 bytes ...nal_tool_flow.cpython-313-pytest-9.0.2.pyc | Bin 38592 -> 38592 bytes ...test_route_stickiness_transaction_shift.py | 80 +++++++ ...te_stickiness.cpython-313-pytest-9.0.2.pyc | Bin 26265 -> 26265 bytes ...nal_workflows.cpython-313-pytest-9.0.2.pyc | Bin 8874 -> 12099 bytes 50 files changed, 217 insertions(+), 241 deletions(-) create mode 100644 agent_framework_oci/Documentacao/RELEASE_NOTES_GENERIC_DETERMINISTIC_INTENT_SHIFT_V15.md delete mode 100644 agent_framework_oci/templates/agent_template_backend/.env rename agent_framework_oci/{.env => templates/agent_template_backend/.env.example} (84%) diff --git a/agent_framework_oci/Documentacao/RELEASE_NOTES_GENERIC_DETERMINISTIC_INTENT_SHIFT_V15.md b/agent_framework_oci/Documentacao/RELEASE_NOTES_GENERIC_DETERMINISTIC_INTENT_SHIFT_V15.md new file mode 100644 index 0000000..114c236 --- /dev/null +++ b/agent_framework_oci/Documentacao/RELEASE_NOTES_GENERIC_DETERMINISTIC_INTENT_SHIFT_V15.md @@ -0,0 +1,47 @@ +# Release Notes — Generic Deterministic Intent Shift v15 + +## Problema corrigido + +A Route Stickiness podia preservar a intent anterior quando a nova mensagem correspondia a uma intent configurada no `routing.yaml`, mas a frase do usuário omitia conectores curtos presentes na keyword configurada. + +Exemplo real de configuração: + +- keyword: `qual é o meu plano` +- mensagem: `qual o meu plano` + +A classificação determinística não reconhecia a nova intent e a continuity acabava mantendo a intent anterior. + +## Correção + +O `EnterpriseRouter` continua usando, nesta ordem: + +1. match exato; +2. sequência completa de tokens com palavras inseridas (`ordered_tokens`); +3. sequência de tokens informativos tolerando a omissão de conectores curtos presentes na keyword (`ordered_content_tokens`). + +A terceira estratégia ignora, somente no lado da keyword, tokens de até dois caracteres e exige pelo menos dois tokens informativos. Não há nomes de intents, agentes, domínios ou verbos de negócio hardcoded. + +Assim, a solução é dirigida integralmente pelas intents carregadas do `routing.yaml` da aplicação. + +## Precedência sobre Route Stickiness + +Quando o candidato determinístico encontrado é diferente da intent ativa, ele preempta a stickiness e retorna: + +- `route_stickiness_preempted: true` +- `previous_agent` +- `previous_intent` +- `keyword_match_strategy` + +A continuity LLM não é chamada nesse caminho. + +## Casos cobertos + +### Mesmo agente, nova intent + +`retail_order_tracking` -> `quero cancelar meu pedido` -> `retail_order_cancel` + +### Mesmo agente, tools diferentes + +`contas_invoice_query` -> `qual o meu plano` -> `contas_plan_information` + +Mesmo que ambas as intents usem `faturas_agent`, as tools mudam de `consultar_faturas` para `consultar_plano`. diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/__pycache__/__init__.cpython-313.pyc index e9b075ce33f823db474fca5882bd9d0604bf91df..3cfa30e4be70334240562717a89ef051441e20cc 100644 GIT binary patch delta 17 YcmZo?ZfD-W&d6$#R+^JDnTN3&04kIO)Bpeg delta 17 YcmZo?ZfD-W&d6$1o?nzbnTN3&04o0k;s5{u diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/__pycache__/idempotency.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/__pycache__/idempotency.cpython-313.pyc index 87c7aba87b67912cf468536bf0672281fbbfa580..932d7d8991889f72d9a77309a4bde5131091c1c8 100644 GIT binary patch delta 18 ZcmZ3jvs!1vBPLdpw9=fM&Ci)!gaJq|2O*inX->|>fI**3eo^+sfI*inX->|>fFb}aWd)%C delta 15 WcmX@ac!+U=H>**3eo^+sfFb}a!UeAY diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/config/__pycache__/settings.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/config/__pycache__/settings.cpython-313.pyc index 7e29e8980af83ba3da27012277a0269524e0a7bc..9cfcddf297b1d7d7264e5533789c5e8190a58963 100644 GIT binary patch delta 18 ZcmZooYE9a3NR8Dbtu!ZR^KmshE&xf&2Ri@& delta 18 ZcmZooYE9a3NR8E~JijP=^KmshE&xhH2T1?` diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/gateways/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/gateways/__pycache__/__init__.cpython-313.pyc index e193ad160c2a584579791a6f2a539eecef104b27..702723acdebf05b5496660fefa070628f7ede7fe 100644 GIT binary patch delta 15 WcmbQoG>>V*ELM}W(wv-$^XmaDPzDA7 delta 15 WcmbQoG>>V*ELNlP{G#lM^XmaDtp*eT diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/gateways/__pycache__/mcp_gateway_client.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/gateways/__pycache__/mcp_gateway_client.cpython-313.pyc index 93e5440405f0352ed0f643b9e6611d289ddbcd47..cfc5b653c2502992bd837bd70bac321674e430d8 100644 GIT binary patch delta 18 Zcmew$`9X5S14dSpw9=fM%}*J*xdBd22R{G+ delta 18 Zcmew$`9X5S14dS(^8BLg%}*J*xdBec2TcF~ diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/identity/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/identity/__pycache__/__init__.cpython-313.pyc index cd32f4193cdf80da4c1e917b40ce3c4a69a6e263..2035238b89ecfce22eb5ba5551f1f14bad75c1ff 100644 GIT binary patch delta 16 XcmZo+ZegDAm(?V#G$&^=6JrwqF(yT4_$s=6L3Zd;mf<2F3sY delta 18 ZcmX@0azJH66f>()d45s$=6L3Zd;mhO2Gjrm diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/identity/__pycache__/models.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/identity/__pycache__/models.cpython-313.pyc index c9bdda711313b80a0d3bdea85e530ce914affc4e..5ea4a982f37a1cfca2d44ca6cd67517c4e578c63 100644 GIT binary patch delta 18 ZcmdlYu|;A-KQpUIT4_$s<|)hzH~>N#2DtzL delta 18 ZcmdlYu|;A-KQpUQd45s$<|)hzH~>PE2FCyZ diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/identity/__pycache__/resolver.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/identity/__pycache__/resolver.cpython-313.pyc index acdea747efed9697a643afe84b6f7cf4b715a47c..5bb348444a635299c4f67796cc593c8118e227b0 100644 GIT binary patch delta 18 Zcmcbra#dwRHZ!Y9T4_$s<^txYd;mr$2NnPT delta 18 Zcmcbra#dwRHZ!YHd45s$<^txYd;mtF2P6Oh diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/__init__.cpython-313.pyc index 40b0f179be68a638fbb6cab7793e593fcb7f176c..f1679da5b163e6d6a3389f8a7212c7c83c311bb6 100644 GIT binary patch delta 17 YcmX@ge3W^E6Cia71830u!rAT4_$s=2WKptN=iV2BiQ1 delta 18 ZcmX>ia71830u!rId45s$=2WKptN=j(2D1PF diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/registry.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/registry.cpython-313.pyc index 00f0f2c6ce750d957735be744b3218d2d1cab5c8..bf1510941cbdb1c2e88a76e46d64c8461ab2ff82 100644 GIT binary patch delta 18 ZcmeyM@0RTic1}Fdk delta 18 ZcmeyM@0RTj=1~vcy diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_policy.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_policy.cpython-313.pyc index f46fe3f577ecd49f81e6937450aef5c5158766f4..028202744af80ba7c9dcde896c046958ffd4cdf3 100644 GIT binary patch delta 18 ZcmaE>@>XR-2@|VHT4_$s=1Qh7`~XS;2W9{O delta 18 ZcmaE>@>XR-2@|VPd45s$=1Qh7`~XUN2Xp`c diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_router.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/mcp/__pycache__/tool_router.cpython-313.pyc index 29cc0c8e4bf96303a216ba53a06d42cb15b419fa..478d318b902f2fce905fbf368ac0b1c3265f9796 100644 GIT binary patch delta 18 acmZ3NyDoRbbuLzuw9=fM&3CviX#)UJrU*&^ delta 18 acmZ3NyDoRbbuLz;^8BLg&3CviX#)UK9|%|g diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/memory/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/memory/__pycache__/__init__.cpython-313.pyc index df7429dcdfa9c6ace1d49d8af400f76cd31db9cd..ab60666bfff585a8698e7a337a3843d86c356522 100644 GIT binary patch delta 17 Zcmcc3ahqeqR%TX{w9=fM$-9^r0suf92MhoJ delta 17 Zcmcc3ahqeqR%TYC^8BLg$-9^r0sugV2O0nX diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/memory/__pycache__/message_history.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/memory/__pycache__/message_history.cpython-313.pyc index 10f3f237c57d9736707b586b58d269063b339b23..9a56d2ae5d071be8e4a12c2a2faf808800c9f2fe 100644 GIT binary patch delta 18 ZcmbR2IN5Q77!#{WT4_$sW@)AhIRH9_1;YRU delta 18 ZcmbR2IN5Q77!#{ed45s$W@)AhIRHBU1*inX->|>fFb}aWd)%C delta 15 WcmX@ac!+U=H>**3eo^+sfFb}a!UeAY diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/models/__pycache__/session.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/models/__pycache__/session.cpython-313.pyc index d46aa28223b39b74748b75d1e6a5eeb3932e239b..352c5f2beaf0b6d98965163dc57769b0482a883c 100644 GIT binary patch delta 18 ZcmZn=Z4lic&CF_&R+^KuS%Eo$9RM<&1tI_d delta 18 ZcmZn=Z4lic&CF_4o?n!`S%Eo$9RM>H1uy^r diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/persistence/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/persistence/__pycache__/__init__.cpython-313.pyc index 6f2a63c0870d7fdb40fb9d151eb8224477abc024..da76b882469fe0e3522202c7c7aee5b76d5919d7 100644 GIT binary patch delta 15 WcmX@kc${&9H>*inX->|>fN}sV_64v2 delta 15 WcmX@kc${&9H>**3eo^+sfN}sWQw6>N diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/persistence/__pycache__/sqlite_store.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/persistence/__pycache__/sqlite_store.cpython-313.pyc index f94aa79bbdf4bcd6bf74fdef8e8177905f516eab..db4bea72769f5876b4f70116b011fb0d11c1f810 100644 GIT binary patch delta 18 ZcmbPMI<0g=4I`^bT4_$s=0-+QO8`fB2D1PF delta 18 ZcmbPMI<0g=4I`^jd45s$=0-+QO8`gl2EhOT diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/__init__.cpython-313.pyc index 5dfaf2f10ea58a21d277cb5d0533774cb9834fdb..2263e9bfe05475c3d2d5feb6a646e564ee8781c4 100644 GIT binary patch delta 17 YcmbQrJe7F^FC(i-T4_$sWFf|804%lz1ONa4 delta 17 YcmbQrJe7F^FC(i_d45s$WFf|804*T}5&!@I diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/config_loader.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/config_loader.cpython-313.pyc index 8c435b9c027456adb27493a8011d38747f10d99d..e510f87c09feb7fd9e1afbd3adbf1b13ef760f51 100644 GIT binary patch delta 18 ZcmaDN_(X8Saz<8@w9=fM&1)Df*a1jG2F?Hg delta 18 ZcmaDN_(X8Saz<98^8BLg&1)Df*a1kq2HXGu diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/continuity.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/continuity.cpython-313.pyc index 4abc2dcbc5bf5efc5083e008caaabe3ba389418d..f614063e579d8fbb1d6d29f773038a68b2af0dac 100644 GIT binary patch delta 18 ZcmZ3Kz9@Y|J`<}+T4_$s<`O17LjXps2B-i4 delta 18 ZcmZ3Kz9@Y|J`<}^d45s$<`O17LjXr52DShI diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/enterprise_router.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/enterprise_router.cpython-313.pyc index ec8193118305c497fefe6efd1d14bc5fd7609b73..67d963b16f5873f0d221fdc44d8c0583ad43e199 100644 GIT binary patch delta 6207 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 JLPTm#{tL;ohG75z delta 1723 zcmZuxZERCj7(VBI^tQL_$JXy{Y?m?zrLuLf1(=l4ec;xy5_VEU7^DH#)d6ngbd#Xy z77aQf#5J!tP=Aa+vH=E6HJKj?KTM3j%=SZRYA_o9K>Q(NXcQCUIkzhd!JG7XpYwh^ z?>*-|y^jFDF>GD3SX9KG^1E*x`F?%I>ctl_YilB6w-lABtRW&1x!Vv`s1h|&W7I@V zy3f$9M$Oc$bEUf^YN3{>m0F`VYSYkuu~&n|N>{b933F|PXsH+Z5iyk`qBaT3zOu~x zEmbTm@X{oFirr&&B9)^fn98J-$c#zUuwNl%#K3t|As102aS%n1nuwDab*2&**Jl-G z;wGxjN{EM;b!K6{5}jFzmsoUWBR*o)nVr~ZX-W)~JM;FAp^+p#P6yM;-r-S3?^&}S z3wsUn#uLNzD2S#pT#s3bVTf(;!D|~_k*%g06fnmQ zFW(5go)6!F5MFXKavsGI!7^ja3fwjdtVE1aeqpE#|J21de#B_n&R`r(N2U*6YM)s> z6Pc~Kw2cOtGl28r(d0?JAhk(+N}kx!C~wX`H3an&3u7HKapcqa`mN8$OYw zkO?{AdZ^Akz~VH;wG_A;3Me>{R@e&K8k&5QjHG{MFphFA-_*X$KG;8@=619~rlGpe z;hNf#*#gbeH@vcKkwf* z_rlG-FZ$+szAKw|?8-SRbMCb>W%I6Qa}M8BI1|pfD{r}L7u>ar4%M#SM`|{($t?-@ zM2KvzHt_Ayf$YF$j}S~U9&k~16%noB@DhhGhkYDIITQ+DX6tpsNxnV>2b%kZD=7O- z^F^U?7RLf&LE&-ntVq}L%nXOk4AOkonx;{HJLv@MY4E^o*e={g@KyNBzL8-5#(w5}F@N7-|&?4NxZEFG&1g?j;y+CxPe>ew#)i?YW%1YC8M7q4OvkmxRE z9;xXOs-4ne!$V1W6()C9j`i@Ab`E;-Cp_6eSG?Ukbmei}%;Qqw{8p;2{h#+0)3L$y zNFVEXfK{w0>V3E(>$9htD|1o$WTU*q-!V`IXP!S;&ORlGc5;~DaF)Xv4sXNiPOU1z zX^?|HL@Q?;_%FR15}kF*L(MCz4;vxZxlVKB)kI=obYzq!6A8-aPfs(*E60XYsllNX vtnWI66L7A}Tk$pX^AAIsU%dMw#`re!-$CY|kQKh|ddBv;h^-G0N4@`lObvmy diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/models.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/__pycache__/models.cpython-313.pyc index 68426e99758feaab6c4b7e3ccd17843d1b9b6e59..f4724fd9952a1f075dcda17da7cc53a49bc04ae8 100644 GIT binary patch delta 18 Zcmew*^h;=i9W$#*T4_$sW@lz|HULC%1}p#o delta 18 Zcmew*^h;=i9W$#@d45s$W@lz|HULEG208!$ diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/enterprise_router.py b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/enterprise_router.py index 0b57ae7..73a9eb2 100644 --- a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/enterprise_router.py +++ b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/enterprise_router.py @@ -181,6 +181,45 @@ class EnterpriseRouter: pos = found return True + @classmethod + def _ordered_content_keyword_match(cls, keyword: str, text: str, *, max_gap: int = 4) -> bool: + """Match determinístico tolerante à omissão de conectores curtos. + + Alguns ``routing.yaml`` usam frases naturais como ``qual é o meu plano``. + A mesma intenção pode chegar como ``qual o meu plano``. O matcher legado + falhava porque exigia também o token ``e`` (resultado da normalização de + ``é``). Aqui tokens de até dois caracteres são tratados como conectores + opcionais *apenas no lado da keyword*. Os tokens informativos continuam + obrigatórios, em ordem e próximos entre si. + + A heurística é propositalmente linguística-neutra e não contém nomes de + intents, agentes, domínios ou listas de verbos de negócio. Assim funciona + com qualquer configuração carregada pelo ``routing.yaml`` sem LLM extra. + """ + wanted_all = cls._keyword_tokens(keyword) + actual = cls._keyword_tokens(text) + if len(wanted_all) < 2 or not actual: + return False + + wanted = [token for token in wanted_all if len(token) > 2] + # Exigimos pelo menos dois tokens informativos para não transformar + # keywords curtas em matches amplos demais. + if len(wanted) < 2 or len(wanted) == len(wanted_all): + return False + + pos = -1 + for token in wanted: + found = None + upper = min(len(actual), pos + max_gap + 2) + for idx in range(pos + 1, upper): + if actual[idx] == token: + found = idx + break + if found is None: + return False + pos = found + return True + def _route_by_keyword(self, text: str) -> RouteDecision | None: normalized = text.casefold() matches: list[tuple[int, int, int, IntentDefinition, str, str]] = [] @@ -195,10 +234,17 @@ class EnterpriseRouter: strategy = "exact" elif self._ordered_keyword_match(kw, text): strategy = "ordered_tokens" + elif self._ordered_content_keyword_match(kw, text): + strategy = "ordered_content_tokens" if strategy: - # menor priority vence; exact vence fuzzy; keyword maior desempata - strategy_rank = 0 if strategy == "exact" else 1 + # menor priority vence; estratégias mais estritas vencem as relaxadas; + # keyword maior desempata dentro da mesma prioridade/estratégia. + strategy_rank = { + "exact": 0, + "ordered_tokens": 1, + "ordered_content_tokens": 2, + }[strategy] matches.append((intent.priority, strategy_rank, -len(kw), intent, kw, strategy)) if not matches: return None @@ -208,11 +254,19 @@ class EnterpriseRouter: route=intent.agent, agent=intent.agent, intent=intent.name, - confidence=0.85 if strategy == "exact" else 0.82, + confidence={ + "exact": 0.85, + "ordered_tokens": 0.82, + "ordered_content_tokens": 0.80, + }[strategy], reason=( f"Keyword '{kw}' correspondeu à intent '{intent.name}'." if strategy == "exact" - else f"Sequência de tokens da keyword '{kw}' correspondeu à intent '{intent.name}'." + else ( + f"Sequência de tokens da keyword '{kw}' correspondeu à intent '{intent.name}'." + if strategy == "ordered_tokens" + else f"Tokens informativos da keyword '{kw}' corresponderam à intent '{intent.name}'." + ) ), method="keyword", metadata={"matched_keyword": kw, "keyword_match_strategy": strategy}, diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/runtime/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/runtime/__pycache__/__init__.cpython-313.pyc index e38d1fb925efaccb826b179c783813c0643a6b8d..eaad4f7b7e6cd1e3f605842bb6ef07c6f196f9b9 100644 GIT binary patch delta 15 WcmX@Xbb@KZQC5?*(wv-$r|JMQ>jtj? delta 15 WcmX@Xbb@KZQC6e!{G#lMr|JMRNCv$C diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/runtime/__pycache__/agent_runtime.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/runtime/__pycache__/agent_runtime.cpython-313.pyc index 6ac1eb5ad687f864c78584c949daca49fa76e27f..6f9eb512b3b75c8335dc6a9d845b5bfc00263cdb 100644 GIT binary patch delta 28 kcmZpe%F!^DW5auPR+F^SoSfz_?CoFJ8Ml97XX;@B0H!(%5C8xG delta 28 kcmZpe%F!^DW5auPR-^L#qU`1`?CoFJ8Ml97XX;@B0H-4h9smFU diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/__pycache__/__init__.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/__pycache__/__init__.cpython-313.pyc index 8a90d5ea743a73f75e330fadfc9e35efa4b72d4c..a3a6732540d64d9cf2eb7abd8a70eb2d505dd79e 100644 GIT binary patch delta 30 mcmeytc8hJpDkh;6{oK3~{glL#MEx>DleE&DoXNMC<^ce;!3)9w delta 60 zcmcb`_JeK1Dkg&_{oK3~{glL#ME%6{)Vz}Tom!Nc9AA`LT#%nvoEl$d P9$%hcl)X8bS%3)u)N2DleE&DoXrBvS%Lt}Aq#Q< delta 61 zcmcbk@k?XF115t8{oK3~{glL#ME%6{)Vz}Tsv{Y!rRYsu{{oK3~{glL#MEx>DleE&DoXxCEcI*JSrwWV! delta 61 zcmZ1~bXaJ^RYrp*{oK3~{glL#ME%6{)Vz}TS38O)aer{fgeoA6VqJCm}YFom!Nc9AA`LT#%nvoEl$d P9$%hcl)d>I;{*->=eih# diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/__pycache__/runtime.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/__pycache__/runtime.cpython-313.pyc index 45e15b4224a6ab7aefd576daba78803718b00c84..bf31e712c83f9f20adf3b9d6032e4944984b35e4 100644 GIT binary patch delta 33 pcmcckm~r!C#tnSTLdp8Mc_sQOi6x2pWrikcr8zm9?U*O$0RY}%4153p delta 63 zcmdn|nDOFc#tnST295f;c_sQOi6x2piRr0%CGpAmc_oR(@j!NJQD$;{QEG8PeqM2E Re3^NCd45s$W(DTSc>pg*89D#} diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/__pycache__/tool_executor.cpython-313.pyc b/agent_framework_oci/libs/agent_framework/src/agent_framework/workflows/__pycache__/tool_executor.cpython-313.pyc index d57454968a2e054b8756d5b1ca9d07be6cbf0e5e..3f5f26a98ed006b7ddb0eda5143828897d1888f4 100644 GIT binary patch delta 31 ncmdnNKZ}3EGDe|H{oK3~{glL#MEx>DleE&DoXyu5AF%=ewV4aJ delta 61 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 rB6GKu`OXSTUP%{*LCKhi4 delta 444 zcmZ2;l5s+i#%Eq$E(Rd*e$ke-i;scfF^B^LOi;$>DGU=erm&|xH7d_9 z%HDj9?Wh=|=H@xF0*oA*j76$I)tZyH$j#<0W&tvrc=#AsGWcmuj*&N)bps0A5{-{9 zE=erOOpZ@1DJjZKDlJJZj*l<$n7lz=n$dCc8F?v2zsb+#0~s|ZTPo~P)nqN=0ctDa z1rb1}F%*S@hzKBYi@i9txHvOEPjj-Aq9>Oo<1Z##TTR9)-O1+^r6+eN%BX8H7m0yX zi-QPBAW_AaSX`W1RHC4&QBY~FS$vBbL`^=eXa=^(BZ8F7m4O@~ zkYYp4Vuj3Nus##bVofHHPD2o3QZ;#vk_u4!MI}#0`^nPEiy0#(?^l)(um@S{2O?}h zMCRn@%DWgFHZM|PW?|A4p8O@LgRyXOZL+#X14!BfL>PbwJs@$5!zMRBr8FniuBZ#h XWd!14_sMUQUAR9o*)n=Ff>i plan must work from configured keywords, even same agent. + + This mirrors applications such as Contas where two intents may be handled by + the same agent but require different MCP tools. The routing core must not + know application-specific intent or agent names. + """ + from agent_framework.routing.models import IntentDefinition + + class _Continuity: + async def evaluate(self, state, *, intents): + raise AssertionError("continuity LLM must not run for explicit configured intent shift") + + router = object.__new__(EnterpriseRouter) + router.state_policies = [] + router.intents = [ + IntentDefinition( + name="domain_plan_information", + domain="customer_domain", + agent="customer_agent", + description="informações de plano", + priority=142, + mcp_tools=["consultar_plano"], + keywords=["qual é o meu plano", "plano contratado"], + examples=[], + enabled=True, + ), + IntentDefinition( + name="domain_invoice_query", + domain="customer_domain", + agent="customer_agent", + description="consulta de fatura", + priority=140, + mcp_tools=["consultar_faturas"], + keywords=["quero minha fatura", "fatura atual"], + examples=[], + enabled=True, + ), + ] + router.continuity = _Continuity() + router.enable_llm_router = False + router.llm = None + router.telemetry = None + router.fallback_agent = "customer_agent" + + message = "qual o meu plano" + decision = await router.route({ + "user_text": message, + "sanitized_input": message, + "active_agent": "customer_agent", + "intent": "domain_invoice_query", + "route_decision": { + "route": "customer_agent", + "agent": "customer_agent", + "intent": "domain_invoice_query", + "domain": "customer_domain", + "mcp_tools": ["consultar_faturas"], + }, + "context": {"session": {}}, + }) + + assert decision.intent == "domain_plan_information" + assert decision.agent == "customer_agent" + assert decision.mcp_tools == ["consultar_plano"] + assert decision.method == "keyword" + assert decision.metadata["route_stickiness_preempted"] is True + assert decision.metadata["previous_intent"] == "domain_invoice_query" + assert decision.metadata["keyword_match_strategy"] == "ordered_content_tokens" diff --git a/agent_framework_oci/tests/unit/__pycache__/test_semantic_route_stickiness.cpython-313-pytest-9.0.2.pyc b/agent_framework_oci/tests/unit/__pycache__/test_semantic_route_stickiness.cpython-313-pytest-9.0.2.pyc index 6ee1938fa826e69a8d3c5475abc3e0a0d45475fa..88a14b69663ac985344d18dd12fb7ae3a859ccc1 100644 GIT binary patch delta 20 ccmbPvmT~4;#tm1QSxwSPb8&njLsi5J>H})&3u^md6Hp?HN~lsF`WA>(si>gtoPQDm4@hNo z{yZ}~Gdr`hJNs?l&u7dVCQ~t@W9r|FQ%j}=a|Kh37aD$9P+IKzDm2A*z$6`tZ36oY z*Zy9z*iJUZq(54$>Y)v+p;dBo4(Kt&;evSuT*$=RXT(SRJ-cCuMO)-GP0|2WlyGg9rsc(z%A>B zsQ7c&7~UZ3uG9KuoM9sBG8uC3;Qe6J0?r8Ifv3Wg8dZhRvJ$c}gx4%<o`AO%t zp1{=nS)s#GlsDZzL%wzzcL_GXuCWLq*(lhBvVgG}Yh3ZDEAM;Mx-jn~2lOT6Prb!h z)QzVv(R@9y19f_+n&1GGdBGUJ5-<#+_;2|j$K&~2J;IJa3C*>9?{uuv#>DX0ZPa6j$z zw^2diOEg-T6L9`mN!Z5>&9&wd@@yvLfrLD<88zXN;|WhF9-EFtrKD$&M&A$7`>@uA zd^p3?Si&^h1lnkFb`7mV9q?F{?F}8zQq1Lw`!OMqe3^DNB7OnlB6*_2u*Hz$!0-OOYIGy1^~2Yw$O|f)d?hzSd7rKc0jYn`!}S-f;sefdF%&9;2+zulPvN?3!5 z+B8?Y$~LCiM$0;5G_vbu$X2;tjyONLS>sK*?i<{T=T{63Yu56$I^RP*Ybl!Ve^i1w z0k0P!&brE$r`hsF{Zdt`vF9#(Xw6>rRo6n-lJRQmirv3z^3NZAz?Xi}{aJU4tzR6_ zAkEjWvbpaLTYtH`z-5VhRJLCulc1F@u=OyL(_R60+YBj7#cSF179DB6W{FMnbt$&- zYFQTeMw)E)yTdl7c)BUT-rYj4fObwRnOCMfm9O!(RoT~a%Vx7-sI>+L3;)K6_g6ZT|eu6WJKnse^ls9A0N>TnD8wQ4-~VvijH%X z@!2zmv6)CT5s_8p2)S6>h7Xe)wIi*kslGy=Poy0P1k9&w5!Tnp&-pBvcc? zBoJZXL9zhZ0xZ%$zrd#;E&(gRDzHYAff0Ta;s&qrr*;tO3|>m+n0r}C3++J?1V+cu2!Va;(`6k=s{63%8Gv>aA)5D