[{"data":1,"prerenderedAt":6406},["ShallowReactive",2],{"articles-page:en":3,"navigation":26,"\u002Fen\u002Farticles\u002F2026":197},{"id":4,"title":5,"author":6,"badges":6,"body":7,"canonical":6,"cover":6,"date":6,"description":15,"extension":18,"layout":19,"meta":20,"navigation":21,"path":22,"seo":23,"stem":24,"__hash__":25},"content\u002Fen\u002F2.articles.md","Blog",null,{"type":8,"value":9,"toc":14},"minimark",[10],[11,12],"articles-list",{"path":13},"articles",{"title":15,"searchDepth":16,"depth":16,"links":17},"",2,[],"md","page",{},true,"\u002Fen\u002Farticles",{"title":5,"description":15},"en\u002F2.articles","9GqK5Q2yj4YpBOqHY1_Ra5mi2GB4ppbJFJMeBt59Vfs",[27,82],{"title":28,"path":29,"stem":30,"children":31},"About","\u002Fen","en\u002F1.index",[32,33,76],{"title":28,"path":29,"stem":30},{"title":5,"path":22,"stem":24,"children":34},[35],{"title":36,"path":37,"stem":38,"children":39,"page":53},"2026","\u002Fen\u002Farticles\u002F2026","en\u002Farticles\u002F2026",[40,54,67],{"title":41,"path":42,"stem":43,"children":44,"page":53},"April","\u002Fen\u002Farticles\u002F2026\u002Fapril","en\u002Farticles\u002F2026\u002Fapril",[45,49],{"title":46,"path":47,"stem":48},"Improving My App's Vibes with DESIGN.md","\u002Fen\u002Farticles\u002F2026\u002Fapril\u002Fexploring-llm-ui","en\u002Farticles\u002F2026\u002Fapril\u002Fexploring-llm-ui",{"title":50,"path":51,"stem":52},"How I Made My Fork Bilingual and Published It Right","\u002Fen\u002Farticles\u002F2026\u002Fapril\u002Fhow-i-made-my-fork-bilingual-and-published-it-right","en\u002Farticles\u002F2026\u002Fapril\u002Fhow-i-made-my-fork-bilingual-and-published-it-right",false,{"title":55,"path":56,"stem":57,"children":58,"page":53},"July","\u002Fen\u002Farticles\u002F2026\u002Fjuly","en\u002Farticles\u002F2026\u002Fjuly",[59,63],{"title":60,"path":61,"stem":62},"From Idea to MS Teams: Deploying an Agent","\u002Fen\u002Farticles\u002F2026\u002Fjuly\u002Ffrom-idea-to-ms-teams-agent","en\u002Farticles\u002F2026\u002Fjuly\u002Ffrom-idea-to-ms-teams-agent",{"title":64,"path":65,"stem":66},"Legally Spying on Your Competition is Possible","\u002Fen\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals","en\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals",{"title":68,"path":69,"stem":70,"children":71,"page":53},"May","\u002Fen\u002Farticles\u002F2026\u002Fmay","en\u002Farticles\u002F2026\u002Fmay",[72],{"title":73,"path":74,"stem":75},"Building an Agent's Personality Around the Customer Journey","\u002Fen\u002Farticles\u002F2026\u002Fmay\u002Fbuilding-agents-with-personality","en\u002Farticles\u002F2026\u002Fmay\u002Fbuilding-agents-with-personality",{"title":77,"path":78,"stem":79,"children":80},"Index","\u002Fen\u002Farticles_index","en\u002F4.articles_index",[81],{"title":77,"path":78,"stem":79},{"title":83,"path":84,"stem":85,"children":86},"Acerca De","\u002Fes","es\u002F1.index",[87,88,173,191],{"title":83,"path":84,"stem":85},{"title":5,"path":89,"stem":90,"children":91},"\u002Fes\u002Farticles","es\u002F2.articles",[92,115,137],{"title":93,"path":94,"stem":95,"children":96,"page":53},"2024","\u002Fes\u002Farticles\u002F2024","es\u002Farticles\u002F2024",[97,106],{"title":98,"path":99,"stem":100,"children":101,"page":53},"Diciembre","\u002Fes\u002Farticles\u002F2024\u002Fdiciembre","es\u002Farticles\u002F2024\u002Fdiciembre",[102],{"title":103,"path":104,"stem":105},"Diciembre es un mes más","\u002Fes\u002Farticles\u002F2024\u002Fdiciembre\u002Fhaikus","es\u002Farticles\u002F2024\u002Fdiciembre\u002Fhaikus",{"title":107,"path":108,"stem":109,"children":110,"page":53},"Octubre","\u002Fes\u002Farticles\u002F2024\u002Foctubre","es\u002Farticles\u002F2024\u002Foctubre",[111],{"title":112,"path":113,"stem":114},"Viaje de regreso","\u002Fes\u002Farticles\u002F2024\u002Foctubre\u002Fhaikus","es\u002Farticles\u002F2024\u002Foctubre\u002Fhaikus",{"title":116,"path":117,"stem":118,"children":119,"page":53},"2025","\u002Fes\u002Farticles\u002F2025","es\u002Farticles\u002F2025",[120,129],{"title":121,"path":122,"stem":123,"children":124,"page":53},"Agosto","\u002Fes\u002Farticles\u002F2025\u002Fagosto","es\u002Farticles\u002F2025\u002Fagosto",[125],{"title":126,"path":127,"stem":128},"Hola Mundo","\u002Fes\u002Farticles\u002F2025\u002Fagosto\u002Fholamundo","es\u002Farticles\u002F2025\u002Fagosto\u002Fholamundo",{"title":107,"path":130,"stem":131,"children":132,"page":53},"\u002Fes\u002Farticles\u002F2025\u002Foctubre","es\u002Farticles\u002F2025\u002Foctubre",[133],{"title":134,"path":135,"stem":136},"El Antipatrón de la Red Veloz","\u002Fes\u002Farticles\u002F2025\u002Foctubre\u002Flatencia","es\u002Farticles\u002F2025\u002Foctubre\u002Flatencia",{"title":36,"path":138,"stem":139,"children":140,"page":53},"\u002Fes\u002Farticles\u002F2026","es\u002Farticles\u002F2026",[141,153,165],{"title":41,"path":142,"stem":143,"children":144,"page":53},"\u002Fes\u002Farticles\u002F2026\u002Fapril","es\u002Farticles\u002F2026\u002Fapril",[145,149],{"title":146,"path":147,"stem":148},"Mejorando las VIBES de mi aplicación con DESIGN.md","\u002Fes\u002Farticles\u002F2026\u002Fapril\u002Fexploring-llm-ui","es\u002Farticles\u002F2026\u002Fapril\u002Fexploring-llm-ui",{"title":150,"path":151,"stem":152},"Cómo volví mi fork multilenguaje y lo publiqué bien","\u002Fes\u002Farticles\u002F2026\u002Fapril\u002Fhow-i-made-my-fork-bilingual-and-published-it-right","es\u002Farticles\u002F2026\u002Fapril\u002Fhow-i-made-my-fork-bilingual-and-published-it-right",{"title":55,"path":154,"stem":155,"children":156,"page":53},"\u002Fes\u002Farticles\u002F2026\u002Fjuly","es\u002Farticles\u002F2026\u002Fjuly",[157,161],{"title":158,"path":159,"stem":160},"De Idea a Ms Teams: Desplegando un Agente","\u002Fes\u002Farticles\u002F2026\u002Fjuly\u002Ffrom-idea-to-ms-teams-agent","es\u002Farticles\u002F2026\u002Fjuly\u002Ffrom-idea-to-ms-teams-agent",{"title":162,"path":163,"stem":164},"Espiar a Tu Competencia de Manera Legal es Posible","\u002Fes\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals","es\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals",{"title":68,"path":166,"stem":167,"children":168,"page":53},"\u002Fes\u002Farticles\u002F2026\u002Fmay","es\u002Farticles\u002F2026\u002Fmay",[169],{"title":170,"path":171,"stem":172},"Construyendo la personalidad de un agente en base a la travesía del cliente","\u002Fes\u002Farticles\u002F2026\u002Fmay\u002Fbuilding-agents-with-personality","es\u002Farticles\u002F2026\u002Fmay\u002Fbuilding-agents-with-personality",{"title":174,"path":175,"stem":176,"children":177},"Galería","\u002Fes\u002Fgallery","es\u002F3.gallery",[178],{"title":116,"path":179,"stem":180,"children":181,"page":53},"\u002Fes\u002Fgallery\u002F2025","es\u002Fgallery\u002F2025",[182],{"title":183,"path":184,"stem":185,"children":186,"page":53},"Septiembre","\u002Fes\u002Fgallery\u002F2025\u002Fseptiembre","es\u002Fgallery\u002F2025\u002Fseptiembre",[187],{"title":188,"path":189,"stem":190},"Cielo de Oyón","\u002Fes\u002Fgallery\u002F2025\u002Fseptiembre\u002Fholamundo","es\u002Fgallery\u002F2025\u002Fseptiembre\u002Fholamundo",{"title":192,"path":193,"stem":194,"children":195},"Lista","\u002Fes\u002Farticles_index","es\u002F4.articles_index",[196],{"title":192,"path":193,"stem":194},[198,811,3317,5926,6068],{"id":199,"title":64,"author":200,"badges":6,"body":204,"canonical":6,"cover":797,"date":798,"description":799,"extension":18,"layout":800,"meta":801,"navigation":21,"path":65,"seo":807,"stem":66,"__hash__":810},"content\u002Fen\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals.md",{"name":201,"url":202,"avatarUrl":203},"Ever Burga","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Feverburga\u002F","https:\u002F\u002Fwww.linkedin.com\u002F",{"type":8,"value":205,"toc":781},[206,210,227,230,233,236,239,249,258,263,268,271,274,277,280,288,291,295,298,309,312,315,319,322,325,329,339,342,346,355,358,361,364,367,371,374,378,381,394,403,408,474,485,535,550,554,557,565,568,571,575,712,717,721,756,767,770,774,777],[207,208,64],"h1",{"id":209},"legally-spying-on-your-competition-is-possible",[211,212,215],"div",{"className":213},[214],"hero-breakout",[211,216,219],{"className":217},[218],"hero-breakout-inner",[220,221,222],"p",{},[223,224],"img",{"alt":225,"src":226},"Diagram of the competitor tracking flow using open data","\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals-hero.svg",[220,228,229],{},"How do you get user data from pages you're interested in monitoring?",[220,231,232],{},"By using Google's public data!",[220,234,235],{},"You don't need a scraper or expensive Wappalyzer subscriptions.",[220,237,238],{},"You just need",[240,241,242,246],"ul",{},[243,244,245],"li",{},"The BigQuery database and API for CrUX.",[243,247,248],{},"The HTTP Archive database in BigQuery.",[220,250,251],{},[252,253,257],"a",{"href":254,"rel":255},"https:\u002F\u002Ftheuxreport.kekeros.com",[256],"nofollow","theuxreport",[259,260,262],"h2",{"id":261},"architecture-decisions","Architecture Decisions",[264,265,267],"h3",{"id":266},"first-lets-look-at-the-nature-of-the-data-sources","First, let's look at the nature of the data sources",[220,269,270],{},"The CrUX and HTTP Archive databases are updated monthly. CrUX has a 2-month lag, while HTTP Archive only has a 1-month lag. This difference has an impact on the data analysis. That's why it's worth tagging the provenance month of every piece of data that enters our data lake.",[220,272,273],{},"On the other hand, for the end user who just wants to see reports, a 1-month difference doesn't matter much. It could even be read as processing delay or some insignificant offset between the historical charts.",[220,275,276],{},"Now, if we focus on data volume, each database uses a field called origin as its identifier, which we can think of as the web domain that serves the content and applications.",[220,278,279],{},"Each origin has dozens of columns in total. But at the end of the day, that's a fixed amount of data. This means the data volume grows given the parameters",[240,281,282,285],{},[243,283,284],{},"N: number of origins to analyze",[243,286,287],{},"T: number of time units to analyze,",[220,289,290],{},"... with O(NT) complexity. For my initial list of Peruvian domains I registered 20 thousand domains, and my goal is to keep a 24-week window in the report. I doubt it will exceed 100 thousand domains in the future, so we have a modest volume of data that can be processed on a single node, or my computer.",[264,292,294],{"id":293},"requirements-and-constraints","Requirements and constraints",[220,296,297],{},"Among other more specific requirements,",[240,299,300,303,306],{},[243,301,302],{},"I want to store the historical and enrichment data in a format with low storage cost but high data integrity guarantees.",[243,304,305],{},"My reports page must have high availability and deliver a smooth user experience.",[243,307,308],{},"I want to keep maintenance costs to a minimum.",[220,310,311],{},"AWS S3 + Athena, GCP BigQuery Iceberg Catalog... there are many solutions on the market. This time I decided to use Cloudflare R2 Data Catalog, with a generous free quota of 10GB of storage and a high number of reads and writes.",[220,313,314],{},"As for the site itself, Astro is my preferred choice for these cases. And the CDN will be Cloudflare to keep administration simple.",[259,316,318],{"id":317},"data-transformation","Data Transformation",[220,320,321],{},"The extraction, filtering, and enrichment stages are straightforward.",[220,323,324],{},"However, HTTP Archive doesn't provide normalized technology categories. Since it uses Wappalyzer's signature engine, it just returns whatever categories it detects. You can end up with React.js and Next.js at the same time, even though we know Next.js is a React meta-framework and doesn't exist without it.",[264,326,328],{"id":327},"stage-1-remapping-to-macrocategories","Stage 1: Remapping to Macrocategories",[220,330,331,335],{},[223,332],{"alt":333,"src":334},"Diagram of remapping raw categories into normalized macrocategories","\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals-remapping.svg",[336,337,338],"em",{},"Remapping raw categories into normalized macrocategories.",[220,340,341],{},"Origin_Technologies comes from R2 with a list of categories per technology. After grouping them we have less complexity to work with. But this is the stage where we do the dirty work.",[264,343,345],{"id":344},"stage-2-cleaning-up-ties","Stage 2: Cleaning up ties",[220,347,348,352],{},[223,349],{"alt":350,"src":351},"Diagram of the LinearUntie process to collapse technologies tied to the same macrocategory","\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals-linear-untie.svg",[336,353,354],{},"LinearUntie: collapsing technologies tied to the same macrocategory.",[220,356,357],{},"A single origin can have several technologies for the same category. This is a consequence of what I mentioned before. You can have Next.js and Next App Router classified within the same Web Frameworks category.",[220,359,360],{},"To collapse these ties I use a linear ordering of technologies according to category. If I find both Nest.js and Express, Nest.js is the option that encompasses both concepts.",[220,362,363],{},"A direct improvement to this model would be to rank not just by category, but by category + framework. But that requires a costly relationship-building task, and there are still exceptions stemming from the very nature of how HTTP Archive generates its data.",[220,365,366],{},"Minor exceptions or mis-categorized technologies I add manually to a structure on disk. It's unavoidable work.",[259,368,370],{"id":369},"ranking","Ranking",[220,372,373],{},"Once you have the normalized datasets, ranking becomes a statistics task, and the reports page becomes a design and UI process.",[259,375,377],{"id":376},"the-ux-report","The UX Report",[220,379,380],{},"If you're interested in validating the results you see on the site or in a post, here are the steps.",[264,382,384,385,389,390,393],{"id":383},"how-to-reproduce-your-severity-and-your-score-with-the-public-crux-api","How to reproduce your ",[386,387,388],"strong",{},"severity"," and your ",[386,391,392],{},"score"," with the public CrUX API",[220,395,396,397,402],{},"What shows up in the Core Web Vitals section comes straight from Google's ",[252,398,401],{"href":399,"rel":400},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fcrux\u002Fapi",[256],"Chrome UX Report API",", which is also used in their SEO ranking.",[404,405,407],"h4",{"id":406},"_1-request-a-histogram-through-the-crux-api","1. Request a histogram through the CrUX API",[409,410,414],"pre",{"className":411,"code":412,"language":413,"meta":15,"style":15},"language-bash shiki shiki-themes github-light github-dark","curl --request POST \\\n  'https:\u002F\u002Fchromeuxreport.googleapis.com\u002Fv1\u002Frecords:queryRecord?key=YOUR_API_KEY' \\\n  --header 'Accept: application\u002Fjson' \\\n  --header 'Content-Type: application\u002Fjson' \\\n  --data '{\"origin\":\"https:\u002F\u002Fyour-domain.pe\"}'\n","bash",[415,416,417,437,444,455,465],"code",{"__ignoreMap":15},[418,419,422,426,430,434],"span",{"class":420,"line":421},"line",1,[418,423,425],{"class":424},"sScJk","curl",[418,427,429],{"class":428},"sj4cs"," --request",[418,431,433],{"class":432},"sZZnC"," POST",[418,435,436],{"class":428}," \\\n",[418,438,439,442],{"class":420,"line":16},[418,440,441],{"class":432},"  'https:\u002F\u002Fchromeuxreport.googleapis.com\u002Fv1\u002Frecords:queryRecord?key=YOUR_API_KEY'",[418,443,436],{"class":428},[418,445,447,450,453],{"class":420,"line":446},3,[418,448,449],{"class":428},"  --header",[418,451,452],{"class":432}," 'Accept: application\u002Fjson'",[418,454,436],{"class":428},[418,456,458,460,463],{"class":420,"line":457},4,[418,459,449],{"class":428},[418,461,462],{"class":432}," 'Content-Type: application\u002Fjson'",[418,464,436],{"class":428},[418,466,468,471],{"class":420,"line":467},5,[418,469,470],{"class":428},"  --data",[418,472,473],{"class":432}," '{\"origin\":\"https:\u002F\u002Fyour-domain.pe\"}'\n",[220,475,476,477,480,481,484],{},"The response includes, for each metric, a 3-bin ",[386,478,479],{},"histogram",": good \u002F needs improvement \u002F poor — each with a ",[386,482,483],{},"density"," (the real fraction of real-user visits in that range, not a synthetic average):",[409,486,490],{"className":487,"code":488,"language":489,"meta":15,"style":15},"language-json shiki shiki-themes github-light github-dark","\"largest_contentful_paint\": {\n  \"histogram\": [\n    { \"start\": 0,    \"end\": 2500, \"density\": 0.82 },\n    { \"start\": 2500, \"end\": 4000, \"density\": 0.11 },\n    { \"start\": 4000,               \"density\": 0.07 }\n  ],\n  \"percentiles\": { \"p75\": 2380 }\n}\n","json",[415,491,492,497,502,507,512,517,523,529],{"__ignoreMap":15},[418,493,494],{"class":420,"line":421},[418,495,496],{},"\"largest_contentful_paint\": {\n",[418,498,499],{"class":420,"line":16},[418,500,501],{},"  \"histogram\": [\n",[418,503,504],{"class":420,"line":446},[418,505,506],{},"    { \"start\": 0,    \"end\": 2500, \"density\": 0.82 },\n",[418,508,509],{"class":420,"line":457},[418,510,511],{},"    { \"start\": 2500, \"end\": 4000, \"density\": 0.11 },\n",[418,513,514],{"class":420,"line":467},[418,515,516],{},"    { \"start\": 4000,               \"density\": 0.07 }\n",[418,518,520],{"class":420,"line":519},6,[418,521,522],{},"  ],\n",[418,524,526],{"class":420,"line":525},7,[418,527,528],{},"  \"percentiles\": { \"p75\": 2380 }\n",[418,530,532],{"class":420,"line":531},8,[418,533,534],{},"}\n",[220,536,537,538,541,542,545,546,549],{},"The three metrics that matter are ",[386,539,540],{},"largest_contentful_paint"," (LCP), ",[386,543,544],{},"cumulative_layout_shift"," (CLS), and ",[386,547,548],{},"interaction_to_next_paint"," (INP). Google's official core web vitals.",[404,551,553],{"id":552},"_2-calculate-the-severity-of-each-metric","2. Calculate the severity of each metric",[220,555,556],{},"For each metric, severity is an average weighted by the real density of each band:",[409,558,563],{"className":559,"code":561,"language":562},[560],"language-text","metric_severity = poor × 1.0 + needs_improvement × 0.5 + good × 0.0\n","text",[415,564,561],{"__ignoreMap":15},[220,566,567],{},"With the example above: 0.07 × 1.0 + 0.11 × 0.5 + 0.82 × 0.0 = 0.125.",[220,569,570],{},"Why weighted instead of \"dominant band\"? Because an origin with 51% good \u002F 49% needs-improvement and another with 99% good \u002F 1% needs-improvement are very different real stories",[404,572,574],{"id":573},"_3-average-the-three-metrics","3. Average the three metrics",[409,576,580],{"className":577,"code":578,"language":579,"meta":15,"style":15},"language-python shiki shiki-themes github-light github-dark","def metric_severity(good: float, ni: float, poor: float) -> float:\n    return poor * 1.0 + ni * 0.5 + good * 0.0\n\nseverity = (\n    metric_severity(*lcp_densities)\n    + metric_severity(*cls_densities)\n    + metric_severity(*inp_densities)\n) \u002F 3\n","python",[415,581,582,616,651,656,667,677,690,701],{"__ignoreMap":15},[418,583,584,588,591,595,598,601,603,606,608,611,613],{"class":420,"line":421},[418,585,587],{"class":586},"szBVR","def",[418,589,590],{"class":424}," metric_severity",[418,592,594],{"class":593},"sVt8B","(good: ",[418,596,597],{"class":428},"float",[418,599,600],{"class":593},", ni: ",[418,602,597],{"class":428},[418,604,605],{"class":593},", poor: ",[418,607,597],{"class":428},[418,609,610],{"class":593},") -> ",[418,612,597],{"class":428},[418,614,615],{"class":593},":\n",[418,617,618,621,624,627,630,633,636,638,641,643,646,648],{"class":420,"line":16},[418,619,620],{"class":586},"    return",[418,622,623],{"class":593}," poor ",[418,625,626],{"class":586},"*",[418,628,629],{"class":428}," 1.0",[418,631,632],{"class":586}," +",[418,634,635],{"class":593}," ni ",[418,637,626],{"class":586},[418,639,640],{"class":428}," 0.5",[418,642,632],{"class":586},[418,644,645],{"class":593}," good ",[418,647,626],{"class":586},[418,649,650],{"class":428}," 0.0\n",[418,652,653],{"class":420,"line":446},[418,654,655],{"emptyLinePlaceholder":21},"\n",[418,657,658,661,664],{"class":420,"line":457},[418,659,660],{"class":593},"severity ",[418,662,663],{"class":586},"=",[418,665,666],{"class":593}," (\n",[418,668,669,672,674],{"class":420,"line":467},[418,670,671],{"class":593},"    metric_severity(",[418,673,626],{"class":586},[418,675,676],{"class":593},"lcp_densities)\n",[418,678,679,682,685,687],{"class":420,"line":519},[418,680,681],{"class":586},"    +",[418,683,684],{"class":593}," metric_severity(",[418,686,626],{"class":586},[418,688,689],{"class":593},"cls_densities)\n",[418,691,692,694,696,698],{"class":420,"line":525},[418,693,681],{"class":586},[418,695,684],{"class":593},[418,697,626],{"class":586},[418,699,700],{"class":593},"inp_densities)\n",[418,702,703,706,709],{"class":420,"line":531},[418,704,705],{"class":593},") ",[418,707,708],{"class":586},"\u002F",[418,710,711],{"class":428}," 3\n",[220,713,714,716],{},[386,715,388],{}," ends up between 0 (perfect) and 1 (the worst possible case). If your origin is missing one of the three metrics for this window (CrUX requires a minimum amount of traffic per metric before it publishes it), what I do is fill in the value with that window's cohort average. In that case you'd have trouble reproducing your full score, but you can use a placeholder value of 50% to get an approximation.",[404,718,720],{"id":719},"_4-your-score","4. Your score",[409,722,724],{"className":577,"code":723,"language":579,"meta":15,"style":15},"score = round((1 - severity) * 100)\n",[415,725,726],{"__ignoreMap":15},[418,727,728,731,733,736,739,742,745,748,750,753],{"class":420,"line":421},[418,729,730],{"class":593},"score ",[418,732,663],{"class":586},[418,734,735],{"class":428}," round",[418,737,738],{"class":593},"((",[418,740,741],{"class":428},"1",[418,743,744],{"class":586}," -",[418,746,747],{"class":593}," severity) ",[418,749,626],{"class":586},[418,751,752],{"class":428}," 100",[418,754,755],{"class":593},")\n",[220,757,758,759,762,763,766],{},"With ",[386,760,761],{},"severity = 0.125",", the score is ",[386,764,765],{},"87\u002F100",". This number is 100% reproducible by anyone with nothing but Google's public API.",[220,768,769],{},"I hope you enjoyed the article. Remember I update the site report every month. See you in my analytics metrics soon!",[259,771,773],{"id":772},"collaboration","Collaboration",[220,775,776],{},"I plan to open source the project once it reaches a stable stage. If you'd like to contribute a list of URLs you think are worth including, or a metric you'd like to see, reach out to me on my social channels — I'd be glad to hear it.",[778,779,780],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":15,"searchDepth":16,"depth":16,"links":782},[783,787,791,792,796],{"id":261,"depth":16,"text":262,"children":784},[785,786],{"id":266,"depth":446,"text":267},{"id":293,"depth":446,"text":294},{"id":317,"depth":16,"text":318,"children":788},[789,790],{"id":327,"depth":446,"text":328},{"id":344,"depth":446,"text":345},{"id":369,"depth":16,"text":370},{"id":376,"depth":16,"text":377,"children":793},[794],{"id":383,"depth":446,"text":795},"How to reproduce your severity and your score with the public CrUX API",{"id":772,"depth":16,"text":773},"\u002Farticles\u002F2026\u002Fjuly\u002Fspying-on-your-rivals-cover.svg","2026-07-20T10:00:00.000Z","Tracking your competition with open data is a task... not that hard.","article",{"head":802},{"meta":803},[804],{"name":805,"content":806},"keywords","crux, http archive, bigquery, competitive analysis, web technologies, wappalyzer, cloudflare r2, data lake, seo, web analytics",{"title":808,"description":809},"Tracking Your Competitors' Users","Tracking your competition with public data is simple.","OAMkQV11xQC9QTViVV-PIcHrRNJPxbKo1nOfDY223fA",{"id":812,"title":60,"author":813,"badges":6,"body":814,"canonical":6,"cover":3307,"date":3308,"description":3309,"extension":18,"layout":800,"meta":3310,"navigation":21,"path":61,"seo":3315,"stem":62,"__hash__":3316},"content\u002Fen\u002Farticles\u002F2026\u002Fjuly\u002Ffrom-idea-to-ms-teams-agent.md",{"name":201,"url":202},{"type":8,"value":815,"toc":3288},[816,819,832,835,838,842,848,856,860,863,880,883,887,890,893,902,912,922,925,929,932,941,944,947,951,957,2285,2293,2298,2341,2344,2348,2351,2359,2363,2367,2370,2379,2383,2386,2402,2405,2408,2412,2416,2424,2428,2482,2485,2489,2492,3244,3248,3285],[207,817,60],{"id":818},"from-idea-to-ms-teams-deploying-an-agent",[220,820,821,825],{},[223,822],{"alt":823,"src":824,"title":823},"Agents Toolkit development flow","\u002Farticles\u002F2026\u002Fjuly\u002Fagent-toolkit-dev-flow.png",[336,826,827,828],{},"Taken from ",[252,829,831],{"href":830},"#ref-1","[1]",[220,833,834],{},"There is a growing number of services and entry points to deploy an agent in MS Teams these days. It can be through Copilot, Microsoft 365, or the AI Foundry services.\nUnder the hood, all of them use the Azure Bot Services APIs.",[220,836,837],{},"If you want maximum customization, you will like this tutorial.",[259,839,841],{"id":840},"prerequisites","Prerequisites",[220,843,844,845,847],{},"If you struggle to get your Azure admin to grant permissions documented in some random blog article, this Microsoft post follows steps similar to this one ",[252,846,831],{"href":830},".",[240,849,850,853],{},[243,851,852],{},"Application Developer role in the Azure subscription where your project will be assigned.",[243,854,855],{},"A corporate MS Teams license. As an alternative, there is a Microsoft 365 Dev trial program you can try, but it only lasts 90 days and you still need an active Azure subscription anyway.\nIt ends up redundant to do all the work there instead of isolating a group of users in your organization's 365 admin console.",[259,857,859],{"id":858},"contents","Contents",[220,861,862],{},"What this tutorial covers:",[240,864,865,868,871,874,877],{},[243,866,867],{},"Creating the App in Azure Entra ID. This is where permissions are managed, and it is the visible face of your Agent for everyone in the same Microsoft tenant.",[243,869,870],{},"Configuring Azure Bot Services. This is the integration API for the MS 365 suite.",[243,872,873],{},"Integration with your own Agent, a self-hosted LangGraph or whatever you built. Here we see how you connect it to Azure Bot Services.",[243,875,876],{},"Publishing to Teams: user exclusion rules, icons, logos and versioning.",[243,878,879],{},"A few CX details, D:",[220,881,882],{},"We are not going to look at the agent's own logic. What you care about, like I did back then, is how to deploy it into your corporate suite.",[259,884,886],{"id":885},"entra-id","Entra ID",[220,888,889],{},"Azure can be a nightmare sometimes. Let's go step by step.",[220,891,892],{},"First, create an app with a name and a 'dev' or 'prd' suffix. You will need this distinction later to segregate users.",[220,894,895,900],{},[223,896],{"alt":897,"src":898,"title":899},"Open the Entra ID service","\u002Farticles\u002F2026\u002Fjuly\u002Fentra-id-tuto.png","Open the service",[336,901,899],{},[220,903,904,909],{},[223,905],{"alt":906,"src":907,"title":908},"Registering a new app","\u002Farticles\u002F2026\u002Fjuly\u002Fapp-registration-add-new.png","Click create",[336,910,911],{},"Click create. Single tenant is enough for most use cases.",[220,913,914,919],{},[223,915],{"alt":916,"src":917,"title":918},"App registration panel","\u002Farticles\u002F2026\u002Fjuly\u002Fapp-registration-panel.png","Note down the App Id",[336,920,921],{},"Note down the App Id.",[220,923,924],{},"If you need your agent to interact with Microsoft services, the API Permissions section will be your friend. In case your Agent is not part of the Azure ecosystem, a quick fix is to create a certificate in the Certificates and Secrets section. In that case, note down the Secret you generate.",[259,926,928],{"id":927},"azure-bot-services","Azure Bot Services",[220,930,931],{},"Create a Bot with the same App Id you used for Entra ID. I am not sure of the reason behind this, but when I used the automatically generated Id there were issues with the bot showing up in the Microsoft 365 Admin console.",[220,933,934,938],{},[223,935],{"alt":936,"src":937,"title":936},"Azure Bot Services configuration panel","\u002Farticles\u002F2026\u002Fjuly\u002Fazure-bot-services-config-panel.png",[336,939,940],{},"Here the two most important fields have arrows.",[220,942,943],{},"The URL endpoint field is the endpoint of the middleware you are going to build next.",[220,945,946],{},"The 'test in webchat' section lets you check that your agent and integration middleware actually work and respond correctly.",[259,948,950],{"id":949},"integration","Integration",[952,953,954],"ol",{},[243,955,956],{},"This is a simplified version of an adapter that works for me.",[409,958,960],{"className":577,"code":959,"language":579,"meta":15,"style":15},"import os\nfrom dotenv import load_dotenv, find_dotenv\nload_dotenv(find_dotenv(\".prd.env\"))\n\nfrom botbuilder.integration.aiohttp import CloudAdapter, ConfigurationBotFrameworkAuthentication\n\nfrom src.ext.teams_incoming_adapter import BotInconmingEventsHandler\nfrom src.app.bot_service.service import BotService\nfrom src.ext.session_adapter import SessionStoreAdapter\nfrom src.app.session_watcher_service.service import SessionWatcher\n\nimport logging\n\n# Configure logging\nlogging.basicConfig(\n    level=logging.DEBUG,  # Set to DEBUG, INFO, WARNING, ERROR, or CRITICAL\n    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n)\n\nlogger = logging.getLogger(__name__)\n\nPORT = int(os.environ.get(\"SVC_LISTEN_PORT\", \"3978\"))\nAPP_ID = os.environ.get(\"MICROSOFT_APP_ID\", \"\")\nAPP_PASSWORD = os.environ.get(\"MICROSOFT_APP_PASSWORD\", \"\")\nAPP_TYPE = os.environ.get(\"MICROSOFT_APP_TYPE\", \"\")\nAPP_TENANTID = os.environ.get(\"MICROSOFT_APP_TENANT_ID\", \"\")\nMAX_IDLE_TIME = int(os.environ.get(\"SESSION_IDLE_LIMIT_SECS\"))  # secs\nALERT_TIME = int(os.environ.get(\"SESSION_IDLE_WARN_SECS\"))\n\nprint(f\"Configuration loaded. App ID: {APP_ID}, Port: {PORT}\")\nlogger.info(f\"✓ App ID: {APP_ID}\")\nlogger.info(f\"✓ App Type: {APP_TYPE}\")\nlogger.info(f\"✓ Tenant ID: {APP_TENANTID}\")\nlogger.info(f\"✓ Password length: {len(APP_PASSWORD) if APP_PASSWORD else 0}\")\n\nif not APP_PASSWORD:\n    logger.error(\"❌ MICROSOFT_APP_PASSWORD is EMPTY!\")\nif not APP_ID:\n    logger.error(\"❌ MICROSOFT_APP_ID is EMPTY!\")\n\nclass BotConfig:\n    PORT = PORT\n    APP_TYPE = APP_TYPE\n    APP_ID = APP_ID\n    APP_PASSWORD = APP_PASSWORD\n    APP_TENANTID = APP_TENANTID\n\nconfig = BotConfig()\n# Cloud Adapter is a bot\nBOT_CLOUD_ADAPTER = CloudAdapter(ConfigurationBotFrameworkAuthentication(config, logger=logger))\n\n\nreturn_last_message_only = os.environ.get(\"BOT_BACKEND_LAST_MSG_ONLY\", \"true\").strip().lower() in (\"1\", \"true\", \"yes\", \"on\")\nquery_url = os.environ.get(\"BOT_BACKEND_ENDPOINT\")\nif not query_url:\n    raise ValueError(\"BOT_BACKEND_ENDPOINT is required\")\n\nchatbot_adapter = AgentEngineADKAdapter(\n    query_url=query_url,\n    timeout_seconds=float(os.environ.get(\"BOT_BACKEND_TIMEOUT_SECS\", \"60\")),\n    return_last_message_only=return_last_message_only,\n    class_method=os.environ.get(\"BOT_BACKEND_CLASS_METHOD\", \"async_stream_query\"),\n)\nlogger.info(\"Agent Engine REST adapter initialized as primary chatbot adapter\")\n\n# Plug in whatever session store you use (a database, cache, etc.)\ndata_store = SessionStoreAdapter(\n    connection_string=os.environ.get(\"DATASTORE_DSN\"),\n)\nlogger.info(\"Session store adapter initialized\")\n\n# Plug in whatever feedback storage you use\nfeedback_repository = FeedbackRepository(\n    connection_string=os.environ.get(\"FEEDBACK_DSN\"),\n)\n\nfeedback_handler = DefaultFeedbackHandler(feedback_repository)\n\nbot_service = BotService(\n    chatbot_adapter=chatbot_adapter,\n    data_store=data_store,\n    fallback_adapter=None,\n    bot_adapter=BOT_CLOUD_ADAPTER,\n    app_id=APP_ID,\n    feedback_handler=feedback_handler,\n    alert_idle_seconds=ALERT_TIME,\n    close_idle_seconds=MAX_IDLE_TIME,\n)\n\nincoming_events_handler = BotInconmingEventsHandler(APP_ID, APP_PASSWORD, bot_service)\n\nhttp_adapter = HTTPAdapter(BOT_CLOUD_ADAPTER, incoming_events_handler)\napp = http_adapter.get_app()\n\n# Start session watcher if data store is available\nif data_store is not None:\n    try:\n        watcher = SessionWatcher(data_store, bot_service, alert_idle_seconds=ALERT_TIME,\n                                 close_idle_seconds=MAX_IDLE_TIME)\n        watcher.start()\n    except Exception as e:\n        print(f\"Warning: could not start session watcher: {e}\")\n\nif __name__ == \"__main__\":\n    from aiohttp import web\n    try:\n        web.run_app(app, host=\"0.0.0.0\", port=PORT)\n    except Exception as error:\n        raise error\n",[415,961,962,970,983,994,998,1010,1014,1026,1038,1051,1064,1069,1077,1082,1089,1095,1116,1149,1154,1159,1175,1180,1206,1227,1246,1265,1284,1305,1322,1327,1356,1373,1390,1407,1442,1447,1459,1470,1482,1492,1497,1508,1519,1530,1541,1552,1563,1568,1579,1585,1604,1609,1614,1660,1675,1685,1701,1706,1717,1728,1751,1762,1784,1789,1799,1804,1810,1821,1836,1841,1851,1856,1862,1873,1887,1892,1897,1908,1913,1924,1935,1946,1960,1972,1984,1995,2007,2019,2024,2029,2049,2054,2070,2081,2086,2092,2110,2118,2138,2150,2156,2171,2197,2202,2218,2232,2239,2264,2276],{"__ignoreMap":15},[418,963,964,967],{"class":420,"line":421},[418,965,966],{"class":586},"import",[418,968,969],{"class":593}," os\n",[418,971,972,975,978,980],{"class":420,"line":16},[418,973,974],{"class":586},"from",[418,976,977],{"class":593}," dotenv ",[418,979,966],{"class":586},[418,981,982],{"class":593}," load_dotenv, find_dotenv\n",[418,984,985,988,991],{"class":420,"line":446},[418,986,987],{"class":593},"load_dotenv(find_dotenv(",[418,989,990],{"class":432},"\".prd.env\"",[418,992,993],{"class":593},"))\n",[418,995,996],{"class":420,"line":457},[418,997,655],{"emptyLinePlaceholder":21},[418,999,1000,1002,1005,1007],{"class":420,"line":467},[418,1001,974],{"class":586},[418,1003,1004],{"class":593}," botbuilder.integration.aiohttp ",[418,1006,966],{"class":586},[418,1008,1009],{"class":593}," CloudAdapter, ConfigurationBotFrameworkAuthentication\n",[418,1011,1012],{"class":420,"line":519},[418,1013,655],{"emptyLinePlaceholder":21},[418,1015,1016,1018,1021,1023],{"class":420,"line":525},[418,1017,974],{"class":586},[418,1019,1020],{"class":593}," src.ext.teams_incoming_adapter ",[418,1022,966],{"class":586},[418,1024,1025],{"class":593}," BotInconmingEventsHandler\n",[418,1027,1028,1030,1033,1035],{"class":420,"line":531},[418,1029,974],{"class":586},[418,1031,1032],{"class":593}," src.app.bot_service.service ",[418,1034,966],{"class":586},[418,1036,1037],{"class":593}," BotService\n",[418,1039,1041,1043,1046,1048],{"class":420,"line":1040},9,[418,1042,974],{"class":586},[418,1044,1045],{"class":593}," src.ext.session_adapter ",[418,1047,966],{"class":586},[418,1049,1050],{"class":593}," SessionStoreAdapter\n",[418,1052,1054,1056,1059,1061],{"class":420,"line":1053},10,[418,1055,974],{"class":586},[418,1057,1058],{"class":593}," src.app.session_watcher_service.service ",[418,1060,966],{"class":586},[418,1062,1063],{"class":593}," SessionWatcher\n",[418,1065,1067],{"class":420,"line":1066},11,[418,1068,655],{"emptyLinePlaceholder":21},[418,1070,1072,1074],{"class":420,"line":1071},12,[418,1073,966],{"class":586},[418,1075,1076],{"class":593}," logging\n",[418,1078,1080],{"class":420,"line":1079},13,[418,1081,655],{"emptyLinePlaceholder":21},[418,1083,1085],{"class":420,"line":1084},14,[418,1086,1088],{"class":1087},"sJ8bj","# Configure logging\n",[418,1090,1092],{"class":420,"line":1091},15,[418,1093,1094],{"class":593},"logging.basicConfig(\n",[418,1096,1098,1102,1104,1107,1110,1113],{"class":420,"line":1097},16,[418,1099,1101],{"class":1100},"s4XuR","    level",[418,1103,663],{"class":586},[418,1105,1106],{"class":593},"logging.",[418,1108,1109],{"class":428},"DEBUG",[418,1111,1112],{"class":593},",  ",[418,1114,1115],{"class":1087},"# Set to DEBUG, INFO, WARNING, ERROR, or CRITICAL\n",[418,1117,1119,1122,1124,1127,1130,1133,1136,1138,1141,1143,1146],{"class":420,"line":1118},17,[418,1120,1121],{"class":1100},"    format",[418,1123,663],{"class":586},[418,1125,1126],{"class":432},"'",[418,1128,1129],{"class":428},"%(asctime)s",[418,1131,1132],{"class":432}," - ",[418,1134,1135],{"class":428},"%(name)s",[418,1137,1132],{"class":432},[418,1139,1140],{"class":428},"%(levelname)s",[418,1142,1132],{"class":432},[418,1144,1145],{"class":428},"%(message)s",[418,1147,1148],{"class":432},"'\n",[418,1150,1152],{"class":420,"line":1151},18,[418,1153,755],{"class":593},[418,1155,1157],{"class":420,"line":1156},19,[418,1158,655],{"emptyLinePlaceholder":21},[418,1160,1162,1165,1167,1170,1173],{"class":420,"line":1161},20,[418,1163,1164],{"class":593},"logger ",[418,1166,663],{"class":586},[418,1168,1169],{"class":593}," logging.getLogger(",[418,1171,1172],{"class":428},"__name__",[418,1174,755],{"class":593},[418,1176,1178],{"class":420,"line":1177},21,[418,1179,655],{"emptyLinePlaceholder":21},[418,1181,1183,1186,1189,1192,1195,1198,1201,1204],{"class":420,"line":1182},22,[418,1184,1185],{"class":428},"PORT",[418,1187,1188],{"class":586}," =",[418,1190,1191],{"class":428}," int",[418,1193,1194],{"class":593},"(os.environ.get(",[418,1196,1197],{"class":432},"\"SVC_LISTEN_PORT\"",[418,1199,1200],{"class":593},", ",[418,1202,1203],{"class":432},"\"3978\"",[418,1205,993],{"class":593},[418,1207,1209,1212,1214,1217,1220,1222,1225],{"class":420,"line":1208},23,[418,1210,1211],{"class":428},"APP_ID",[418,1213,1188],{"class":586},[418,1215,1216],{"class":593}," os.environ.get(",[418,1218,1219],{"class":432},"\"MICROSOFT_APP_ID\"",[418,1221,1200],{"class":593},[418,1223,1224],{"class":432},"\"\"",[418,1226,755],{"class":593},[418,1228,1230,1233,1235,1237,1240,1242,1244],{"class":420,"line":1229},24,[418,1231,1232],{"class":428},"APP_PASSWORD",[418,1234,1188],{"class":586},[418,1236,1216],{"class":593},[418,1238,1239],{"class":432},"\"MICROSOFT_APP_PASSWORD\"",[418,1241,1200],{"class":593},[418,1243,1224],{"class":432},[418,1245,755],{"class":593},[418,1247,1249,1252,1254,1256,1259,1261,1263],{"class":420,"line":1248},25,[418,1250,1251],{"class":428},"APP_TYPE",[418,1253,1188],{"class":586},[418,1255,1216],{"class":593},[418,1257,1258],{"class":432},"\"MICROSOFT_APP_TYPE\"",[418,1260,1200],{"class":593},[418,1262,1224],{"class":432},[418,1264,755],{"class":593},[418,1266,1268,1271,1273,1275,1278,1280,1282],{"class":420,"line":1267},26,[418,1269,1270],{"class":428},"APP_TENANTID",[418,1272,1188],{"class":586},[418,1274,1216],{"class":593},[418,1276,1277],{"class":432},"\"MICROSOFT_APP_TENANT_ID\"",[418,1279,1200],{"class":593},[418,1281,1224],{"class":432},[418,1283,755],{"class":593},[418,1285,1287,1290,1292,1294,1296,1299,1302],{"class":420,"line":1286},27,[418,1288,1289],{"class":428},"MAX_IDLE_TIME",[418,1291,1188],{"class":586},[418,1293,1191],{"class":428},[418,1295,1194],{"class":593},[418,1297,1298],{"class":432},"\"SESSION_IDLE_LIMIT_SECS\"",[418,1300,1301],{"class":593},"))  ",[418,1303,1304],{"class":1087},"# secs\n",[418,1306,1308,1311,1313,1315,1317,1320],{"class":420,"line":1307},28,[418,1309,1310],{"class":428},"ALERT_TIME",[418,1312,1188],{"class":586},[418,1314,1191],{"class":428},[418,1316,1194],{"class":593},[418,1318,1319],{"class":432},"\"SESSION_IDLE_WARN_SECS\"",[418,1321,993],{"class":593},[418,1323,1325],{"class":420,"line":1324},29,[418,1326,655],{"emptyLinePlaceholder":21},[418,1328,1330,1333,1336,1339,1342,1345,1348,1351,1354],{"class":420,"line":1329},30,[418,1331,1332],{"class":428},"print",[418,1334,1335],{"class":593},"(",[418,1337,1338],{"class":586},"f",[418,1340,1341],{"class":432},"\"Configuration loaded. App ID: ",[418,1343,1344],{"class":428},"{APP_ID}",[418,1346,1347],{"class":432},", Port: ",[418,1349,1350],{"class":428},"{PORT}",[418,1352,1353],{"class":432},"\"",[418,1355,755],{"class":593},[418,1357,1359,1362,1364,1367,1369,1371],{"class":420,"line":1358},31,[418,1360,1361],{"class":593},"logger.info(",[418,1363,1338],{"class":586},[418,1365,1366],{"class":432},"\"✓ App ID: ",[418,1368,1344],{"class":428},[418,1370,1353],{"class":432},[418,1372,755],{"class":593},[418,1374,1376,1378,1380,1383,1386,1388],{"class":420,"line":1375},32,[418,1377,1361],{"class":593},[418,1379,1338],{"class":586},[418,1381,1382],{"class":432},"\"✓ App Type: ",[418,1384,1385],{"class":428},"{APP_TYPE}",[418,1387,1353],{"class":432},[418,1389,755],{"class":593},[418,1391,1393,1395,1397,1400,1403,1405],{"class":420,"line":1392},33,[418,1394,1361],{"class":593},[418,1396,1338],{"class":586},[418,1398,1399],{"class":432},"\"✓ Tenant ID: ",[418,1401,1402],{"class":428},"{APP_TENANTID}",[418,1404,1353],{"class":432},[418,1406,755],{"class":593},[418,1408,1410,1412,1414,1417,1420,1422,1424,1426,1429,1432,1435,1438,1440],{"class":420,"line":1409},34,[418,1411,1361],{"class":593},[418,1413,1338],{"class":586},[418,1415,1416],{"class":432},"\"✓ Password length: ",[418,1418,1419],{"class":428},"{len",[418,1421,1335],{"class":593},[418,1423,1232],{"class":428},[418,1425,705],{"class":593},[418,1427,1428],{"class":586},"if",[418,1430,1431],{"class":428}," APP_PASSWORD",[418,1433,1434],{"class":586}," else",[418,1436,1437],{"class":428}," 0}",[418,1439,1353],{"class":432},[418,1441,755],{"class":593},[418,1443,1445],{"class":420,"line":1444},35,[418,1446,655],{"emptyLinePlaceholder":21},[418,1448,1450,1452,1455,1457],{"class":420,"line":1449},36,[418,1451,1428],{"class":586},[418,1453,1454],{"class":586}," not",[418,1456,1431],{"class":428},[418,1458,615],{"class":593},[418,1460,1462,1465,1468],{"class":420,"line":1461},37,[418,1463,1464],{"class":593},"    logger.error(",[418,1466,1467],{"class":432},"\"❌ MICROSOFT_APP_PASSWORD is EMPTY!\"",[418,1469,755],{"class":593},[418,1471,1473,1475,1477,1480],{"class":420,"line":1472},38,[418,1474,1428],{"class":586},[418,1476,1454],{"class":586},[418,1478,1479],{"class":428}," APP_ID",[418,1481,615],{"class":593},[418,1483,1485,1487,1490],{"class":420,"line":1484},39,[418,1486,1464],{"class":593},[418,1488,1489],{"class":432},"\"❌ MICROSOFT_APP_ID is EMPTY!\"",[418,1491,755],{"class":593},[418,1493,1495],{"class":420,"line":1494},40,[418,1496,655],{"emptyLinePlaceholder":21},[418,1498,1500,1503,1506],{"class":420,"line":1499},41,[418,1501,1502],{"class":586},"class",[418,1504,1505],{"class":424}," BotConfig",[418,1507,615],{"class":593},[418,1509,1511,1514,1516],{"class":420,"line":1510},42,[418,1512,1513],{"class":428},"    PORT",[418,1515,1188],{"class":586},[418,1517,1518],{"class":428}," PORT\n",[418,1520,1522,1525,1527],{"class":420,"line":1521},43,[418,1523,1524],{"class":428},"    APP_TYPE",[418,1526,1188],{"class":586},[418,1528,1529],{"class":428}," APP_TYPE\n",[418,1531,1533,1536,1538],{"class":420,"line":1532},44,[418,1534,1535],{"class":428},"    APP_ID",[418,1537,1188],{"class":586},[418,1539,1540],{"class":428}," APP_ID\n",[418,1542,1544,1547,1549],{"class":420,"line":1543},45,[418,1545,1546],{"class":428},"    APP_PASSWORD",[418,1548,1188],{"class":586},[418,1550,1551],{"class":428}," APP_PASSWORD\n",[418,1553,1555,1558,1560],{"class":420,"line":1554},46,[418,1556,1557],{"class":428},"    APP_TENANTID",[418,1559,1188],{"class":586},[418,1561,1562],{"class":428}," APP_TENANTID\n",[418,1564,1566],{"class":420,"line":1565},47,[418,1567,655],{"emptyLinePlaceholder":21},[418,1569,1571,1574,1576],{"class":420,"line":1570},48,[418,1572,1573],{"class":593},"config ",[418,1575,663],{"class":586},[418,1577,1578],{"class":593}," BotConfig()\n",[418,1580,1582],{"class":420,"line":1581},49,[418,1583,1584],{"class":1087},"# Cloud Adapter is a bot\n",[418,1586,1588,1591,1593,1596,1599,1601],{"class":420,"line":1587},50,[418,1589,1590],{"class":428},"BOT_CLOUD_ADAPTER",[418,1592,1188],{"class":586},[418,1594,1595],{"class":593}," CloudAdapter(ConfigurationBotFrameworkAuthentication(config, ",[418,1597,1598],{"class":1100},"logger",[418,1600,663],{"class":586},[418,1602,1603],{"class":593},"logger))\n",[418,1605,1607],{"class":420,"line":1606},51,[418,1608,655],{"emptyLinePlaceholder":21},[418,1610,1612],{"class":420,"line":1611},52,[418,1613,655],{"emptyLinePlaceholder":21},[418,1615,1617,1620,1622,1624,1627,1629,1632,1635,1638,1641,1644,1646,1648,1650,1653,1655,1658],{"class":420,"line":1616},53,[418,1618,1619],{"class":593},"return_last_message_only ",[418,1621,663],{"class":586},[418,1623,1216],{"class":593},[418,1625,1626],{"class":432},"\"BOT_BACKEND_LAST_MSG_ONLY\"",[418,1628,1200],{"class":593},[418,1630,1631],{"class":432},"\"true\"",[418,1633,1634],{"class":593},").strip().lower() ",[418,1636,1637],{"class":586},"in",[418,1639,1640],{"class":593}," (",[418,1642,1643],{"class":432},"\"1\"",[418,1645,1200],{"class":593},[418,1647,1631],{"class":432},[418,1649,1200],{"class":593},[418,1651,1652],{"class":432},"\"yes\"",[418,1654,1200],{"class":593},[418,1656,1657],{"class":432},"\"on\"",[418,1659,755],{"class":593},[418,1661,1663,1666,1668,1670,1673],{"class":420,"line":1662},54,[418,1664,1665],{"class":593},"query_url ",[418,1667,663],{"class":586},[418,1669,1216],{"class":593},[418,1671,1672],{"class":432},"\"BOT_BACKEND_ENDPOINT\"",[418,1674,755],{"class":593},[418,1676,1678,1680,1682],{"class":420,"line":1677},55,[418,1679,1428],{"class":586},[418,1681,1454],{"class":586},[418,1683,1684],{"class":593}," query_url:\n",[418,1686,1688,1691,1694,1696,1699],{"class":420,"line":1687},56,[418,1689,1690],{"class":586},"    raise",[418,1692,1693],{"class":428}," ValueError",[418,1695,1335],{"class":593},[418,1697,1698],{"class":432},"\"BOT_BACKEND_ENDPOINT is required\"",[418,1700,755],{"class":593},[418,1702,1704],{"class":420,"line":1703},57,[418,1705,655],{"emptyLinePlaceholder":21},[418,1707,1709,1712,1714],{"class":420,"line":1708},58,[418,1710,1711],{"class":593},"chatbot_adapter ",[418,1713,663],{"class":586},[418,1715,1716],{"class":593}," AgentEngineADKAdapter(\n",[418,1718,1720,1723,1725],{"class":420,"line":1719},59,[418,1721,1722],{"class":1100},"    query_url",[418,1724,663],{"class":586},[418,1726,1727],{"class":593},"query_url,\n",[418,1729,1731,1734,1736,1738,1740,1743,1745,1748],{"class":420,"line":1730},60,[418,1732,1733],{"class":1100},"    timeout_seconds",[418,1735,663],{"class":586},[418,1737,597],{"class":428},[418,1739,1194],{"class":593},[418,1741,1742],{"class":432},"\"BOT_BACKEND_TIMEOUT_SECS\"",[418,1744,1200],{"class":593},[418,1746,1747],{"class":432},"\"60\"",[418,1749,1750],{"class":593},")),\n",[418,1752,1754,1757,1759],{"class":420,"line":1753},61,[418,1755,1756],{"class":1100},"    return_last_message_only",[418,1758,663],{"class":586},[418,1760,1761],{"class":593},"return_last_message_only,\n",[418,1763,1765,1768,1770,1773,1776,1778,1781],{"class":420,"line":1764},62,[418,1766,1767],{"class":1100},"    class_method",[418,1769,663],{"class":586},[418,1771,1772],{"class":593},"os.environ.get(",[418,1774,1775],{"class":432},"\"BOT_BACKEND_CLASS_METHOD\"",[418,1777,1200],{"class":593},[418,1779,1780],{"class":432},"\"async_stream_query\"",[418,1782,1783],{"class":593},"),\n",[418,1785,1787],{"class":420,"line":1786},63,[418,1788,755],{"class":593},[418,1790,1792,1794,1797],{"class":420,"line":1791},64,[418,1793,1361],{"class":593},[418,1795,1796],{"class":432},"\"Agent Engine REST adapter initialized as primary chatbot adapter\"",[418,1798,755],{"class":593},[418,1800,1802],{"class":420,"line":1801},65,[418,1803,655],{"emptyLinePlaceholder":21},[418,1805,1807],{"class":420,"line":1806},66,[418,1808,1809],{"class":1087},"# Plug in whatever session store you use (a database, cache, etc.)\n",[418,1811,1813,1816,1818],{"class":420,"line":1812},67,[418,1814,1815],{"class":593},"data_store ",[418,1817,663],{"class":586},[418,1819,1820],{"class":593}," SessionStoreAdapter(\n",[418,1822,1824,1827,1829,1831,1834],{"class":420,"line":1823},68,[418,1825,1826],{"class":1100},"    connection_string",[418,1828,663],{"class":586},[418,1830,1772],{"class":593},[418,1832,1833],{"class":432},"\"DATASTORE_DSN\"",[418,1835,1783],{"class":593},[418,1837,1839],{"class":420,"line":1838},69,[418,1840,755],{"class":593},[418,1842,1844,1846,1849],{"class":420,"line":1843},70,[418,1845,1361],{"class":593},[418,1847,1848],{"class":432},"\"Session store adapter initialized\"",[418,1850,755],{"class":593},[418,1852,1854],{"class":420,"line":1853},71,[418,1855,655],{"emptyLinePlaceholder":21},[418,1857,1859],{"class":420,"line":1858},72,[418,1860,1861],{"class":1087},"# Plug in whatever feedback storage you use\n",[418,1863,1865,1868,1870],{"class":420,"line":1864},73,[418,1866,1867],{"class":593},"feedback_repository ",[418,1869,663],{"class":586},[418,1871,1872],{"class":593}," FeedbackRepository(\n",[418,1874,1876,1878,1880,1882,1885],{"class":420,"line":1875},74,[418,1877,1826],{"class":1100},[418,1879,663],{"class":586},[418,1881,1772],{"class":593},[418,1883,1884],{"class":432},"\"FEEDBACK_DSN\"",[418,1886,1783],{"class":593},[418,1888,1890],{"class":420,"line":1889},75,[418,1891,755],{"class":593},[418,1893,1895],{"class":420,"line":1894},76,[418,1896,655],{"emptyLinePlaceholder":21},[418,1898,1900,1903,1905],{"class":420,"line":1899},77,[418,1901,1902],{"class":593},"feedback_handler ",[418,1904,663],{"class":586},[418,1906,1907],{"class":593}," DefaultFeedbackHandler(feedback_repository)\n",[418,1909,1911],{"class":420,"line":1910},78,[418,1912,655],{"emptyLinePlaceholder":21},[418,1914,1916,1919,1921],{"class":420,"line":1915},79,[418,1917,1918],{"class":593},"bot_service ",[418,1920,663],{"class":586},[418,1922,1923],{"class":593}," BotService(\n",[418,1925,1927,1930,1932],{"class":420,"line":1926},80,[418,1928,1929],{"class":1100},"    chatbot_adapter",[418,1931,663],{"class":586},[418,1933,1934],{"class":593},"chatbot_adapter,\n",[418,1936,1938,1941,1943],{"class":420,"line":1937},81,[418,1939,1940],{"class":1100},"    data_store",[418,1942,663],{"class":586},[418,1944,1945],{"class":593},"data_store,\n",[418,1947,1949,1952,1954,1957],{"class":420,"line":1948},82,[418,1950,1951],{"class":1100},"    fallback_adapter",[418,1953,663],{"class":586},[418,1955,1956],{"class":428},"None",[418,1958,1959],{"class":593},",\n",[418,1961,1963,1966,1968,1970],{"class":420,"line":1962},83,[418,1964,1965],{"class":1100},"    bot_adapter",[418,1967,663],{"class":586},[418,1969,1590],{"class":428},[418,1971,1959],{"class":593},[418,1973,1975,1978,1980,1982],{"class":420,"line":1974},84,[418,1976,1977],{"class":1100},"    app_id",[418,1979,663],{"class":586},[418,1981,1211],{"class":428},[418,1983,1959],{"class":593},[418,1985,1987,1990,1992],{"class":420,"line":1986},85,[418,1988,1989],{"class":1100},"    feedback_handler",[418,1991,663],{"class":586},[418,1993,1994],{"class":593},"feedback_handler,\n",[418,1996,1998,2001,2003,2005],{"class":420,"line":1997},86,[418,1999,2000],{"class":1100},"    alert_idle_seconds",[418,2002,663],{"class":586},[418,2004,1310],{"class":428},[418,2006,1959],{"class":593},[418,2008,2010,2013,2015,2017],{"class":420,"line":2009},87,[418,2011,2012],{"class":1100},"    close_idle_seconds",[418,2014,663],{"class":586},[418,2016,1289],{"class":428},[418,2018,1959],{"class":593},[418,2020,2022],{"class":420,"line":2021},88,[418,2023,755],{"class":593},[418,2025,2027],{"class":420,"line":2026},89,[418,2028,655],{"emptyLinePlaceholder":21},[418,2030,2032,2035,2037,2040,2042,2044,2046],{"class":420,"line":2031},90,[418,2033,2034],{"class":593},"incoming_events_handler ",[418,2036,663],{"class":586},[418,2038,2039],{"class":593}," BotInconmingEventsHandler(",[418,2041,1211],{"class":428},[418,2043,1200],{"class":593},[418,2045,1232],{"class":428},[418,2047,2048],{"class":593},", bot_service)\n",[418,2050,2052],{"class":420,"line":2051},91,[418,2053,655],{"emptyLinePlaceholder":21},[418,2055,2057,2060,2062,2065,2067],{"class":420,"line":2056},92,[418,2058,2059],{"class":593},"http_adapter ",[418,2061,663],{"class":586},[418,2063,2064],{"class":593}," HTTPAdapter(",[418,2066,1590],{"class":428},[418,2068,2069],{"class":593},", incoming_events_handler)\n",[418,2071,2073,2076,2078],{"class":420,"line":2072},93,[418,2074,2075],{"class":593},"app ",[418,2077,663],{"class":586},[418,2079,2080],{"class":593}," http_adapter.get_app()\n",[418,2082,2084],{"class":420,"line":2083},94,[418,2085,655],{"emptyLinePlaceholder":21},[418,2087,2089],{"class":420,"line":2088},95,[418,2090,2091],{"class":1087},"# Start session watcher if data store is available\n",[418,2093,2095,2097,2100,2103,2105,2108],{"class":420,"line":2094},96,[418,2096,1428],{"class":586},[418,2098,2099],{"class":593}," data_store ",[418,2101,2102],{"class":586},"is",[418,2104,1454],{"class":586},[418,2106,2107],{"class":428}," None",[418,2109,615],{"class":593},[418,2111,2113,2116],{"class":420,"line":2112},97,[418,2114,2115],{"class":586},"    try",[418,2117,615],{"class":593},[418,2119,2121,2124,2126,2129,2132,2134,2136],{"class":420,"line":2120},98,[418,2122,2123],{"class":593},"        watcher ",[418,2125,663],{"class":586},[418,2127,2128],{"class":593}," SessionWatcher(data_store, bot_service, ",[418,2130,2131],{"class":1100},"alert_idle_seconds",[418,2133,663],{"class":586},[418,2135,1310],{"class":428},[418,2137,1959],{"class":593},[418,2139,2141,2144,2146,2148],{"class":420,"line":2140},99,[418,2142,2143],{"class":1100},"                                 close_idle_seconds",[418,2145,663],{"class":586},[418,2147,1289],{"class":428},[418,2149,755],{"class":593},[418,2151,2153],{"class":420,"line":2152},100,[418,2154,2155],{"class":593},"        watcher.start()\n",[418,2157,2159,2162,2165,2168],{"class":420,"line":2158},101,[418,2160,2161],{"class":586},"    except",[418,2163,2164],{"class":428}," Exception",[418,2166,2167],{"class":586}," as",[418,2169,2170],{"class":593}," e:\n",[418,2172,2174,2177,2179,2181,2184,2187,2190,2193,2195],{"class":420,"line":2173},102,[418,2175,2176],{"class":428},"        print",[418,2178,1335],{"class":593},[418,2180,1338],{"class":586},[418,2182,2183],{"class":432},"\"Warning: could not start session watcher: ",[418,2185,2186],{"class":428},"{",[418,2188,2189],{"class":593},"e",[418,2191,2192],{"class":428},"}",[418,2194,1353],{"class":432},[418,2196,755],{"class":593},[418,2198,2200],{"class":420,"line":2199},103,[418,2201,655],{"emptyLinePlaceholder":21},[418,2203,2205,2207,2210,2213,2216],{"class":420,"line":2204},104,[418,2206,1428],{"class":586},[418,2208,2209],{"class":428}," __name__",[418,2211,2212],{"class":586}," ==",[418,2214,2215],{"class":432}," \"__main__\"",[418,2217,615],{"class":593},[418,2219,2221,2224,2227,2229],{"class":420,"line":2220},105,[418,2222,2223],{"class":586},"    from",[418,2225,2226],{"class":593}," aiohttp ",[418,2228,966],{"class":586},[418,2230,2231],{"class":593}," web\n",[418,2233,2235,2237],{"class":420,"line":2234},106,[418,2236,2115],{"class":586},[418,2238,615],{"class":593},[418,2240,2242,2245,2248,2250,2253,2255,2258,2260,2262],{"class":420,"line":2241},107,[418,2243,2244],{"class":593},"        web.run_app(app, ",[418,2246,2247],{"class":1100},"host",[418,2249,663],{"class":586},[418,2251,2252],{"class":432},"\"0.0.0.0\"",[418,2254,1200],{"class":593},[418,2256,2257],{"class":1100},"port",[418,2259,663],{"class":586},[418,2261,1185],{"class":428},[418,2263,755],{"class":593},[418,2265,2267,2269,2271,2273],{"class":420,"line":2266},108,[418,2268,2161],{"class":586},[418,2270,2164],{"class":428},[418,2272,2167],{"class":586},[418,2274,2275],{"class":593}," error:\n",[418,2277,2279,2282],{"class":420,"line":2278},109,[418,2280,2281],{"class":586},"        raise",[418,2283,2284],{"class":593}," error\n",[220,2286,2287,2288,2292],{},"You can check more implementations in Microsoft's Quickstart ",[252,2289,2291],{"href":2290},"#ref-2","[2]",".\nIn my opinion the page is a bit abandoned, so don't assume it will work as-is.",[952,2294,2295],{"start":16},[243,2296,2297],{},"Before wrapping up your integration, do not forget to collect these variables correctly. They are required to decrypt Azure's communication in the production environment.",[409,2299,2301],{"className":411,"code":2300,"language":413,"meta":15,"style":15},"MicrosoftAppType= SingleTenant\nMicrosoftAppId= # client id you just used for entra id and bot services\nMicrosoftAppPassword= # client secret\nMicrosoftAppTenantId=\n",[415,2302,2303,2313,2323,2333],{"__ignoreMap":15},[418,2304,2305,2308,2310],{"class":420,"line":421},[418,2306,2307],{"class":593},"MicrosoftAppType",[418,2309,663],{"class":586},[418,2311,2312],{"class":424}," SingleTenant\n",[418,2314,2315,2318,2320],{"class":420,"line":16},[418,2316,2317],{"class":593},"MicrosoftAppId",[418,2319,663],{"class":586},[418,2321,2322],{"class":1087}," # client id you just used for entra id and bot services\n",[418,2324,2325,2328,2330],{"class":420,"line":446},[418,2326,2327],{"class":593},"MicrosoftAppPassword",[418,2329,663],{"class":586},[418,2331,2332],{"class":1087}," # client secret\n",[418,2334,2335,2338],{"class":420,"line":457},[418,2336,2337],{"class":593},"MicrosoftAppTenantId",[418,2339,2340],{"class":586},"=\n",[220,2342,2343],{},"The client secret is only needed for integrations outside the Azure ecosystem. It is preferable to use OAuth2 or a secret-free method.",[264,2345,2347],{"id":2346},"and-you-also-get-a-nice-playground-to-test-your-agent-even-before-it-lands-in-microsoft-365","And you also get a nice playground to test your agent even before it lands in Microsoft 365",[220,2349,2350],{},"For it not to fail, you need to leave the variables from step #2 empty.\nIf you don't, the playground won't be able to decrypt the communication. And in my experience, that has been a painful thing to debug when it fails.",[220,2352,2353,2357],{},[223,2354],{"alt":2355,"src":2356,"title":2355},"Microsoft 365 Playground","\u002Farticles\u002F2026\u002Fjuly\u002Fmicrosoft-365-playground.png",[336,2358,2355],{},[259,2360,2362],{"id":2361},"publishing-to-teams","Publishing to Teams",[264,2364,2366],{"id":2365},"upload-the-file-exported-from-the-365-toolkit","Upload the File Exported from the 365 Toolkit",[220,2368,2369],{},"The project you configured previously generates a bundle. You can customize it with the logo you want displayed.\nA colored version and a simplified one for sidebars and small icons.",[220,2371,2372,2376],{},[223,2373],{"alt":2374,"src":2375,"title":2374},"Uploading the app to Teams request","\u002Farticles\u002F2026\u002Fjuly\u002Fupload-app-to-teams-request.png",[336,2377,2378],{},"Uploading the bundle exported from the Toolkit",[264,2380,2382],{"id":2381},"contact-your-ms-365-administrator","Contact Your MS 365 Administrator",[220,2384,2385],{},"Point them to these links:",[240,2387,2388,2395],{},[243,2389,2390,2391],{},"Microsoft Teams admin center ",[252,2392,2394],{"href":2393},"#ref-4","[4]",[243,2396,2397,2398],{},"Microsoft 365 admin center ",[252,2399,2401],{"href":2400},"#ref-5","[5]",[220,2403,2404],{},"I have not been able to share screenshots of what the admin console looks like and the exact steps your admin should follow.\nBut let them know they can create access lists for the application.",[220,2406,2407],{},"Specifically, they should have an access list for the dev application, open only to a handful of tester and developer users.\nAnd for the production application, a different strategy can be worked out.",[259,2409,2411],{"id":2410},"cx","CX!",[264,2413,2415],{"id":2414},"interested-in-using-forms-with-your-agent","Interested in using forms with your agent?",[220,2417,2418,2419,2423],{},"Microsoft's good old Adaptive Cards ",[252,2420,2422],{"href":2421},"#ref-3","[3]",". You can use them in your middleware.\nExtra customization? It's the same standard used by Power Automate, which you might be more familiar with.",[264,2425,2427],{"id":2426},"do-you-want-the-bot-to-type","Do you want the ... bot ... to type? ...",[409,2429,2431],{"className":577,"code":2430,"language":579,"meta":15,"style":15},"# Typying activity: ...\nawait turn_context.send_activity(Activity(type=ActivityTypes.typing))\n# Delegate to application service\nresponse = await self.bot_service.handle_message(text, turn_context)\nawait turn_context.send_activity(response)\n",[415,2432,2433,2438,2454,2459,2475],{"__ignoreMap":15},[418,2434,2435],{"class":420,"line":421},[418,2436,2437],{"class":1087},"# Typying activity: ...\n",[418,2439,2440,2443,2446,2449,2451],{"class":420,"line":16},[418,2441,2442],{"class":586},"await",[418,2444,2445],{"class":593}," turn_context.send_activity(Activity(",[418,2447,2448],{"class":1100},"type",[418,2450,663],{"class":586},[418,2452,2453],{"class":593},"ActivityTypes.typing))\n",[418,2455,2456],{"class":420,"line":446},[418,2457,2458],{"class":1087},"# Delegate to application service\n",[418,2460,2461,2464,2466,2469,2472],{"class":420,"line":457},[418,2462,2463],{"class":593},"response ",[418,2465,663],{"class":586},[418,2467,2468],{"class":586}," await",[418,2470,2471],{"class":428}," self",[418,2473,2474],{"class":593},".bot_service.handle_message(text, turn_context)\n",[418,2476,2477,2479],{"class":420,"line":467},[418,2478,2442],{"class":586},[418,2480,2481],{"class":593}," turn_context.send_activity(response)\n",[220,2483,2484],{},"Sending that activity is enough while your agent's engine is working on the response.",[259,2486,2488],{"id":2487},"extra","Extra!",[220,2490,2491],{},"This is what I could gather from the communications sent by the Azure Bot Services servers. It might be useful if you want to understand how much useful information you can get through the middleware.",[409,2493,2497],{"className":2494,"code":2495,"language":2496,"meta":15,"style":15},"language-http shiki shiki-themes github-light github-dark","POST \u002Fapi\u002Fmessages HTTP\u002F1.1\nHost: localhost:3978\nUser-Agent: BF-DirectLine (Microsoft-BotFramework\u002F3.2 +https:\u002F\u002Fbotframework.com\u002Fua)\nContent-Length: 719\nAccept: *\u002F*\nAuthorization: Bearer \u003CREDACTED_JWT>\nChannelid: webchat\nContent-Type: application\u002Fjson; charset=utf-8\nRequest-Id: |\u003CREDACTED_REQUEST_ID>.\u003CREDACTED_SPAN_ID>.\nTraceparent: 00-\u003CREDACTED_TRACE_ID>-\u003CREDACTED_SPAN_ID>-00\nX-Forwarded-For: xxx.xxx.xxx.xxx\nX-Forwarded-Host: xxxx-xxx-xxx-xx.ngrok-free.app\nX-Forwarded-Proto: https\nX-Ms-Conversation-Id: \u003CREDACTED_CONVERSATION_ID>\nAccept-Encoding: gzip\n\n{\"type\":\"typing\",\"id\":\"\u003CREDACTED_CONVERSATION_ID>|\u003CREDACTED_ACTIVITY_ID>\",\"timestamp\":\"2026-03-02T17:44:41.6782359Z\",\"localTimestamp\":\"2026-03-02T12:44:41.391-05:00\",\"localTimezone\":\"America\u002FLima\",\"serviceUrl\":\"https:\u002F\u002Fwebchat.botframework.com\u002F\",\"channelId\":\"webchat\",\"from\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"name\":\"\"},\"conversation\":{\"id\":\"\u003CREDACTED_CONVERSATION_ID>\"},\"recipient\":{\"id\":\"agente-msteams@\u003CREDACTED_TOKEN>\",\"name\":\"agente-msteams\"},\"locale\":\"en-US\",\"entities\":[{\"type\":\"ClientCapabilities\",\"requiresBotState\":true,\"supportsListening\":true,\"supportsTts\":true}],\"channelData\":{\"clientActivityID\":\"\u003CREDACTED_CLIENT_ACTIVITY_ID>\"}}\n\n\n\n\nPOST \u002Fapi\u002Fmessages HTTP\u002F1.1\nHost: localhost:3978\nUser-Agent: BF-DirectLine (Microsoft-BotFramework\u002F3.2 +https:\u002F\u002Fbotframework.com\u002Fua)\nContent-Length: 662\nAccept: *\u002F*\nAuthorization: Bearer \u003CREDACTED_JWT>\nChannelid: webchat\nContent-Type: application\u002Fjson; charset=utf-8\nRequest-Id: |\u003CREDACTED_REQUEST_ID>.\u003CREDACTED_SPAN_ID>.\nTraceparent: 00-\u003CREDACTED_TRACE_ID>-\u003CREDACTED_SPAN_ID>-00\nX-Forwarded-For: xxx.xxx.xxx.xxx\nX-Forwarded-Host: xxxx-xxx-xxx-xx.ngrok-free.app\nX-Forwarded-Proto: https\nX-Ms-Conversation-Id: \u003CREDACTED_CONVERSATION_ID>\nAccept-Encoding: gzip\n\n{\"type\":\"conversationUpdate\",\"id\":\"\u003CREDACTED_ACTIVITY_ID>\",\"timestamp\":\"2026-03-02T17:44:41.0353977Z\",\"serviceUrl\":\"https:\u002F\u002Fwebchat.botframework.com\u002F\",\"channelId\":\"webchat\",\"from\":{\"id\":\"00000000-0000-0000-0000-000000000000\"},\"conversation\":{\"id\":\"\u003CREDACTED_CONVERSATION_ID>\"},\"recipient\":{\"id\":\"agente-msteams@\u003CREDACTED_TOKEN>\",\"name\":\"agente-msteams\"},\"membersAdded\":[{\"id\":\"agente-msteams@\u003CREDACTED_TOKEN>\",\"name\":\"agente-msteams\"},{\"id\":\"00000000-0000-0000-0000-000000000000\"}]}\n\nPOST \u002Fapi\u002Fmessages HTTP\u002F1.1\nHost: localhost:3978\nUser-Agent: BF-DirectLine (Microsoft-BotFramework\u002F3.2 +https:\u002F\u002Fbotframework.com\u002Fua)\nContent-Length: 679\nAccept: *\u002F*\nAuthorization: Bearer \u003CREDACTED_JWT>\nChannelid: webchat\nContent-Type: application\u002Fjson; charset=utf-8\nRequest-Id: |\u003CREDACTED_REQUEST_ID>.\u003CREDACTED_SPAN_ID>.\nTraceparent: 00-\u003CREDACTED_TRACE_ID>-\u003CREDACTED_SPAN_ID>-00\nX-Forwarded-For: xxx.xxx.xxx.xxx\nX-Forwarded-Host: xxxx-xxx-xxx-xx.ngrok-free.app\nX-Forwarded-Proto: https\nX-Ms-Conversation-Id: \u003CREDACTED_CONVERSATION_ID>\nAccept-Encoding: gzip\n\n{\"type\":\"message\",\"id\":\"\u003CREDACTED_CONVERSATION_ID>|\u003CREDACTED_ACTIVITY_ID>\",\"timestamp\":\"2026-03-02T17:44:42.8691754Z\",\"localTimestamp\":\"2026-03-02T12:44:42.728-05:00\",\"localTimezone\":\"America\u002FLima\",\"serviceUrl\":\"https:\u002F\u002Fwebchat.botframework.com\u002F\",\"channelId\":\"webchat\",\"from\":{\"id\":\"00000000-0000-0000-0000-000000000000\",\"name\":\"\"},\"conversation\":{\"id\":\"\u003CREDACTED_CONVERSATION_ID>\"},\"recipient\":{\"id\":\"agente-msteams@\u003CREDACTED_TOKEN>\",\"name\":\"agente-msteams\"},\"textFormat\":\"plain\",\"locale\":\"en-US\",\"text\":\"Hola\",\"attachments\":[],\"channelData\":{\"attachmentSizes\":[],\"clientActivityID\":\"\u003CREDACTED_CLIENT_ACTIVITY_ID>\"}}\n","http",[415,2498,2499,2515,2527,2537,2547,2557,2567,2577,2587,2597,2607,2617,2627,2637,2647,2657,2661,2868,2872,2876,2880,2884,2891,2899,2913,2921,2929,2934,2939,2944,2949,2954,2959,2964,2969,2974,2979,2983,2988,2992,2997,3002,3007,3012,3020,3024,3028,3036,3040,3054,3058,3062,3066,3070,3074,3078],{"__ignoreMap":15},[418,2500,2501,2504,2507,2510,2512],{"class":420,"line":421},[418,2502,2503],{"class":586},"POST",[418,2505,2506],{"class":593}," \u002Fapi\u002Fmessages ",[418,2508,2509],{"class":586},"HTTP",[418,2511,708],{"class":593},[418,2513,2514],{"class":428},"1.1\n",[418,2516,2517,2521,2524],{"class":420,"line":16},[418,2518,2520],{"class":2519},"s9eBZ","Host",[418,2522,2523],{"class":586},":",[418,2525,2526],{"class":432}," localhost:3978\n",[418,2528,2529,2532,2534],{"class":420,"line":446},[418,2530,2531],{"class":2519},"User-Agent",[418,2533,2523],{"class":586},[418,2535,2536],{"class":432}," BF-DirectLine (Microsoft-BotFramework\u002F3.2 +https:\u002F\u002Fbotframework.com\u002Fua)\n",[418,2538,2539,2542,2544],{"class":420,"line":457},[418,2540,2541],{"class":2519},"Content-Length",[418,2543,2523],{"class":586},[418,2545,2546],{"class":432}," 719\n",[418,2548,2549,2552,2554],{"class":420,"line":467},[418,2550,2551],{"class":2519},"Accept",[418,2553,2523],{"class":586},[418,2555,2556],{"class":432}," *\u002F*\n",[418,2558,2559,2562,2564],{"class":420,"line":519},[418,2560,2561],{"class":2519},"Authorization",[418,2563,2523],{"class":586},[418,2565,2566],{"class":432}," Bearer \u003CREDACTED_JWT>\n",[418,2568,2569,2572,2574],{"class":420,"line":525},[418,2570,2571],{"class":2519},"Channelid",[418,2573,2523],{"class":586},[418,2575,2576],{"class":432}," webchat\n",[418,2578,2579,2582,2584],{"class":420,"line":531},[418,2580,2581],{"class":2519},"Content-Type",[418,2583,2523],{"class":586},[418,2585,2586],{"class":432}," application\u002Fjson; charset=utf-8\n",[418,2588,2589,2592,2594],{"class":420,"line":1040},[418,2590,2591],{"class":2519},"Request-Id",[418,2593,2523],{"class":586},[418,2595,2596],{"class":432}," |\u003CREDACTED_REQUEST_ID>.\u003CREDACTED_SPAN_ID>.\n",[418,2598,2599,2602,2604],{"class":420,"line":1053},[418,2600,2601],{"class":2519},"Traceparent",[418,2603,2523],{"class":586},[418,2605,2606],{"class":432}," 00-\u003CREDACTED_TRACE_ID>-\u003CREDACTED_SPAN_ID>-00\n",[418,2608,2609,2612,2614],{"class":420,"line":1066},[418,2610,2611],{"class":2519},"X-Forwarded-For",[418,2613,2523],{"class":586},[418,2615,2616],{"class":432}," xxx.xxx.xxx.xxx\n",[418,2618,2619,2622,2624],{"class":420,"line":1071},[418,2620,2621],{"class":2519},"X-Forwarded-Host",[418,2623,2523],{"class":586},[418,2625,2626],{"class":432}," xxxx-xxx-xxx-xx.ngrok-free.app\n",[418,2628,2629,2632,2634],{"class":420,"line":1079},[418,2630,2631],{"class":2519},"X-Forwarded-Proto",[418,2633,2523],{"class":586},[418,2635,2636],{"class":432}," https\n",[418,2638,2639,2642,2644],{"class":420,"line":1084},[418,2640,2641],{"class":2519},"X-Ms-Conversation-Id",[418,2643,2523],{"class":586},[418,2645,2646],{"class":432}," \u003CREDACTED_CONVERSATION_ID>\n",[418,2648,2649,2652,2654],{"class":420,"line":1091},[418,2650,2651],{"class":2519},"Accept-Encoding",[418,2653,2523],{"class":586},[418,2655,2656],{"class":432}," gzip\n",[418,2658,2659],{"class":420,"line":1097},[418,2660,655],{"emptyLinePlaceholder":21},[418,2662,2663,2665,2668,2670,2673,2676,2679,2681,2684,2686,2689,2691,2694,2696,2699,2701,2704,2706,2709,2711,2714,2716,2719,2721,2724,2726,2729,2731,2734,2736,2739,2742,2744,2746,2749,2751,2754,2756,2758,2761,2764,2766,2768,2770,2773,2775,2778,2780,2782,2784,2787,2789,2791,2793,2796,2798,2801,2803,2806,2808,2811,2814,2816,2818,2821,2823,2826,2828,2831,2833,2836,2838,2840,2842,2845,2847,2849,2852,2855,2857,2860,2862,2865],{"class":420,"line":1118},[418,2664,2186],{"class":593},[418,2666,2667],{"class":428},"\"type\"",[418,2669,2523],{"class":593},[418,2671,2672],{"class":432},"\"typing\"",[418,2674,2675],{"class":593},",",[418,2677,2678],{"class":428},"\"id\"",[418,2680,2523],{"class":593},[418,2682,2683],{"class":432},"\"\u003CREDACTED_CONVERSATION_ID>|\u003CREDACTED_ACTIVITY_ID>\"",[418,2685,2675],{"class":593},[418,2687,2688],{"class":428},"\"timestamp\"",[418,2690,2523],{"class":593},[418,2692,2693],{"class":432},"\"2026-03-02T17:44:41.6782359Z\"",[418,2695,2675],{"class":593},[418,2697,2698],{"class":428},"\"localTimestamp\"",[418,2700,2523],{"class":593},[418,2702,2703],{"class":432},"\"2026-03-02T12:44:41.391-05:00\"",[418,2705,2675],{"class":593},[418,2707,2708],{"class":428},"\"localTimezone\"",[418,2710,2523],{"class":593},[418,2712,2713],{"class":432},"\"America\u002FLima\"",[418,2715,2675],{"class":593},[418,2717,2718],{"class":428},"\"serviceUrl\"",[418,2720,2523],{"class":593},[418,2722,2723],{"class":432},"\"https:\u002F\u002Fwebchat.botframework.com\u002F\"",[418,2725,2675],{"class":593},[418,2727,2728],{"class":428},"\"channelId\"",[418,2730,2523],{"class":593},[418,2732,2733],{"class":432},"\"webchat\"",[418,2735,2675],{"class":593},[418,2737,2738],{"class":428},"\"from\"",[418,2740,2741],{"class":593},":{",[418,2743,2678],{"class":428},[418,2745,2523],{"class":593},[418,2747,2748],{"class":432},"\"00000000-0000-0000-0000-000000000000\"",[418,2750,2675],{"class":593},[418,2752,2753],{"class":428},"\"name\"",[418,2755,2523],{"class":593},[418,2757,1224],{"class":432},[418,2759,2760],{"class":593},"},",[418,2762,2763],{"class":428},"\"conversation\"",[418,2765,2741],{"class":593},[418,2767,2678],{"class":428},[418,2769,2523],{"class":593},[418,2771,2772],{"class":432},"\"\u003CREDACTED_CONVERSATION_ID>\"",[418,2774,2760],{"class":593},[418,2776,2777],{"class":428},"\"recipient\"",[418,2779,2741],{"class":593},[418,2781,2678],{"class":428},[418,2783,2523],{"class":593},[418,2785,2786],{"class":432},"\"agente-msteams@\u003CREDACTED_TOKEN>\"",[418,2788,2675],{"class":593},[418,2790,2753],{"class":428},[418,2792,2523],{"class":593},[418,2794,2795],{"class":432},"\"agente-msteams\"",[418,2797,2760],{"class":593},[418,2799,2800],{"class":428},"\"locale\"",[418,2802,2523],{"class":593},[418,2804,2805],{"class":432},"\"en-US\"",[418,2807,2675],{"class":593},[418,2809,2810],{"class":428},"\"entities\"",[418,2812,2813],{"class":593},":[{",[418,2815,2667],{"class":428},[418,2817,2523],{"class":593},[418,2819,2820],{"class":432},"\"ClientCapabilities\"",[418,2822,2675],{"class":593},[418,2824,2825],{"class":428},"\"requiresBotState\"",[418,2827,2523],{"class":593},[418,2829,2830],{"class":428},"true",[418,2832,2675],{"class":593},[418,2834,2835],{"class":428},"\"supportsListening\"",[418,2837,2523],{"class":593},[418,2839,2830],{"class":428},[418,2841,2675],{"class":593},[418,2843,2844],{"class":428},"\"supportsTts\"",[418,2846,2523],{"class":593},[418,2848,2830],{"class":428},[418,2850,2851],{"class":593},"}],",[418,2853,2854],{"class":428},"\"channelData\"",[418,2856,2741],{"class":593},[418,2858,2859],{"class":428},"\"clientActivityID\"",[418,2861,2523],{"class":593},[418,2863,2864],{"class":432},"\"\u003CREDACTED_CLIENT_ACTIVITY_ID>\"",[418,2866,2867],{"class":593},"}}\n",[418,2869,2870],{"class":420,"line":1151},[418,2871,655],{"emptyLinePlaceholder":21},[418,2873,2874],{"class":420,"line":1156},[418,2875,655],{"emptyLinePlaceholder":21},[418,2877,2878],{"class":420,"line":1161},[418,2879,655],{"emptyLinePlaceholder":21},[418,2881,2882],{"class":420,"line":1177},[418,2883,655],{"emptyLinePlaceholder":21},[418,2885,2886,2889],{"class":420,"line":1182},[418,2887,2888],{"class":593},"POST \u002Fapi\u002Fmessages HTTP\u002F",[418,2890,2514],{"class":428},[418,2892,2893,2896],{"class":420,"line":1208},[418,2894,2895],{"class":593},"Host: localhost:",[418,2897,2898],{"class":428},"3978\n",[418,2900,2901,2904,2907,2910],{"class":420,"line":1229},[418,2902,2903],{"class":593},"User-Agent: BF-DirectLine (Microsoft-BotFramework\u002F",[418,2905,2906],{"class":428},"3.2",[418,2908,2909],{"class":593}," +https:",[418,2911,2912],{"class":1087},"\u002F\u002Fbotframework.com\u002Fua)\n",[418,2914,2915,2918],{"class":420,"line":1248},[418,2916,2917],{"class":593},"Content-Length: ",[418,2919,2920],{"class":428},"662\n",[418,2922,2923,2926],{"class":420,"line":1267},[418,2924,2925],{"class":593},"Accept: *",[418,2927,2928],{"class":1087},"\u002F*\n",[418,2930,2931],{"class":420,"line":1286},[418,2932,2933],{"class":1087},"Authorization: Bearer \u003CREDACTED_JWT>\n",[418,2935,2936],{"class":420,"line":1307},[418,2937,2938],{"class":1087},"Channelid: webchat\n",[418,2940,2941],{"class":420,"line":1324},[418,2942,2943],{"class":1087},"Content-Type: application\u002Fjson; charset=utf-8\n",[418,2945,2946],{"class":420,"line":1329},[418,2947,2948],{"class":1087},"Request-Id: |\u003CREDACTED_REQUEST_ID>.\u003CREDACTED_SPAN_ID>.\n",[418,2950,2951],{"class":420,"line":1358},[418,2952,2953],{"class":1087},"Traceparent: 00-\u003CREDACTED_TRACE_ID>-\u003CREDACTED_SPAN_ID>-00\n",[418,2955,2956],{"class":420,"line":1375},[418,2957,2958],{"class":1087},"X-Forwarded-For: xxx.xxx.xxx.xxx\n",[418,2960,2961],{"class":420,"line":1392},[418,2962,2963],{"class":1087},"X-Forwarded-Host: xxxx-xxx-xxx-xx.ngrok-free.app\n",[418,2965,2966],{"class":420,"line":1409},[418,2967,2968],{"class":1087},"X-Forwarded-Proto: https\n",[418,2970,2971],{"class":420,"line":1444},[418,2972,2973],{"class":1087},"X-Ms-Conversation-Id: \u003CREDACTED_CONVERSATION_ID>\n",[418,2975,2976],{"class":420,"line":1449},[418,2977,2978],{"class":1087},"Accept-Encoding: gzip\n",[418,2980,2981],{"class":420,"line":1461},[418,2982,655],{"emptyLinePlaceholder":21},[418,2984,2985],{"class":420,"line":1472},[418,2986,2987],{"class":1087},"{\"type\":\"conversationUpdate\",\"id\":\"\u003CREDACTED_ACTIVITY_ID>\",\"timestamp\":\"2026-03-02T17:44:41.0353977Z\",\"serviceUrl\":\"https:\u002F\u002Fwebchat.botframework.com\u002F\",\"channelId\":\"webchat\",\"from\":{\"id\":\"00000000-0000-0000-0000-000000000000\"},\"conversation\":{\"id\":\"\u003CREDACTED_CONVERSATION_ID>\"},\"recipient\":{\"id\":\"agente-msteams@\u003CREDACTED_TOKEN>\",\"name\":\"agente-msteams\"},\"membersAdded\":[{\"id\":\"agente-msteams@\u003CREDACTED_TOKEN>\",\"name\":\"agente-msteams\"},{\"id\":\"00000000-0000-0000-0000-000000000000\"}]}\n",[418,2989,2990],{"class":420,"line":1484},[418,2991,655],{"emptyLinePlaceholder":21},[418,2993,2994],{"class":420,"line":1494},[418,2995,2996],{"class":1087},"POST \u002Fapi\u002Fmessages HTTP\u002F1.1\n",[418,2998,2999],{"class":420,"line":1499},[418,3000,3001],{"class":1087},"Host: localhost:3978\n",[418,3003,3004],{"class":420,"line":1510},[418,3005,3006],{"class":1087},"User-Agent: BF-DirectLine (Microsoft-BotFramework\u002F3.2 +https:\u002F\u002Fbotframework.com\u002Fua)\n",[418,3008,3009],{"class":420,"line":1521},[418,3010,3011],{"class":1087},"Content-Length: 679\n",[418,3013,3014,3017],{"class":420,"line":1532},[418,3015,3016],{"class":1087},"Accept: *\u002F",[418,3018,3019],{"class":593},"*\n",[418,3021,3022],{"class":420,"line":1543},[418,3023,2933],{"class":593},[418,3025,3026],{"class":420,"line":1554},[418,3027,2938],{"class":593},[418,3029,3030,3033],{"class":420,"line":1565},[418,3031,3032],{"class":593},"Content-Type: application\u002Fjson; charset=utf",[418,3034,3035],{"class":428},"-8\n",[418,3037,3038],{"class":420,"line":1570},[418,3039,2948],{"class":593},[418,3041,3042,3045,3048,3051],{"class":420,"line":1581},[418,3043,3044],{"class":593},"Traceparent: ",[418,3046,3047],{"class":428},"00",[418,3049,3050],{"class":593},"-\u003CREDACTED_TRACE_ID>-\u003CREDACTED_SPAN_ID>",[418,3052,3053],{"class":428},"-00\n",[418,3055,3056],{"class":420,"line":1587},[418,3057,2958],{"class":593},[418,3059,3060],{"class":420,"line":1606},[418,3061,2963],{"class":593},[418,3063,3064],{"class":420,"line":1611},[418,3065,2968],{"class":593},[418,3067,3068],{"class":420,"line":1616},[418,3069,2973],{"class":593},[418,3071,3072],{"class":420,"line":1662},[418,3073,2978],{"class":593},[418,3075,3076],{"class":420,"line":1677},[418,3077,655],{"emptyLinePlaceholder":21},[418,3079,3080,3082,3084,3086,3089,3091,3093,3095,3097,3099,3101,3103,3106,3108,3110,3112,3115,3117,3119,3121,3123,3125,3127,3129,3131,3133,3135,3137,3139,3141,3143,3145,3147,3149,3151,3153,3155,3157,3159,3161,3163,3165,3167,3169,3171,3173,3175,3177,3179,3181,3183,3185,3187,3189,3191,3193,3196,3198,3201,3203,3205,3207,3209,3211,3214,3216,3219,3221,3224,3227,3229,3231,3234,3236,3238,3240,3242],{"class":420,"line":1687},[418,3081,2186],{"class":593},[418,3083,2667],{"class":428},[418,3085,2523],{"class":593},[418,3087,3088],{"class":432},"\"message\"",[418,3090,2675],{"class":593},[418,3092,2678],{"class":428},[418,3094,2523],{"class":593},[418,3096,2683],{"class":432},[418,3098,2675],{"class":593},[418,3100,2688],{"class":428},[418,3102,2523],{"class":593},[418,3104,3105],{"class":432},"\"2026-03-02T17:44:42.8691754Z\"",[418,3107,2675],{"class":593},[418,3109,2698],{"class":428},[418,3111,2523],{"class":593},[418,3113,3114],{"class":432},"\"2026-03-02T12:44:42.728-05:00\"",[418,3116,2675],{"class":593},[418,3118,2708],{"class":428},[418,3120,2523],{"class":593},[418,3122,2713],{"class":432},[418,3124,2675],{"class":593},[418,3126,2718],{"class":428},[418,3128,2523],{"class":593},[418,3130,2723],{"class":432},[418,3132,2675],{"class":593},[418,3134,2728],{"class":428},[418,3136,2523],{"class":593},[418,3138,2733],{"class":432},[418,3140,2675],{"class":593},[418,3142,2738],{"class":428},[418,3144,2741],{"class":593},[418,3146,2678],{"class":428},[418,3148,2523],{"class":593},[418,3150,2748],{"class":432},[418,3152,2675],{"class":593},[418,3154,2753],{"class":428},[418,3156,2523],{"class":593},[418,3158,1224],{"class":432},[418,3160,2760],{"class":593},[418,3162,2763],{"class":428},[418,3164,2741],{"class":593},[418,3166,2678],{"class":428},[418,3168,2523],{"class":593},[418,3170,2772],{"class":432},[418,3172,2760],{"class":593},[418,3174,2777],{"class":428},[418,3176,2741],{"class":593},[418,3178,2678],{"class":428},[418,3180,2523],{"class":593},[418,3182,2786],{"class":432},[418,3184,2675],{"class":593},[418,3186,2753],{"class":428},[418,3188,2523],{"class":593},[418,3190,2795],{"class":432},[418,3192,2760],{"class":593},[418,3194,3195],{"class":428},"\"textFormat\"",[418,3197,2523],{"class":593},[418,3199,3200],{"class":432},"\"plain\"",[418,3202,2675],{"class":593},[418,3204,2800],{"class":428},[418,3206,2523],{"class":593},[418,3208,2805],{"class":432},[418,3210,2675],{"class":593},[418,3212,3213],{"class":428},"\"text\"",[418,3215,2523],{"class":593},[418,3217,3218],{"class":432},"\"Hola\"",[418,3220,2675],{"class":593},[418,3222,3223],{"class":428},"\"attachments\"",[418,3225,3226],{"class":593},":[],",[418,3228,2854],{"class":428},[418,3230,2741],{"class":593},[418,3232,3233],{"class":428},"\"attachmentSizes\"",[418,3235,3226],{"class":593},[418,3237,2859],{"class":428},[418,3239,2523],{"class":593},[418,3241,2864],{"class":432},[418,3243,2867],{"class":593},[259,3245,3247],{"id":3246},"references","References",[952,3249,3250,3257,3264,3271,3278],{},[243,3251,3252,3253],{},"[]{#ref-1}Microsoft. Agents Toolkit fundamentals. Available: ",[252,3254,3255],{"href":3255,"rel":3256},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fmicrosoftteams\u002Fplatform\u002Ftoolkit\u002Fagents-toolkit-fundamentals",[256],[243,3258,3259,3260],{},"[]{#ref-2}Microsoft. Microsoft 365 Agents SDK Quickstart (Python). Available: ",[252,3261,3262],{"href":3262,"rel":3263},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fmicrosoft-365\u002Fagents-sdk\u002Fquickstart?pivots=python",[256],[243,3265,3266,3267],{},"[]{#ref-3}Microsoft. Adaptive Cards. Available: ",[252,3268,3269],{"href":3269,"rel":3270},"https:\u002F\u002Fadaptivecards.microsoft.com\u002F",[256],[243,3272,3273,3274],{},"[]{#ref-4}Microsoft. Microsoft Teams admin center. Available: ",[252,3275,3276],{"href":3276,"rel":3277},"https:\u002F\u002Fadmin.teams.microsoft.com",[256],[243,3279,3280,3281],{},"[]{#ref-5}Microsoft. Microsoft 365 admin center. Available: ",[252,3282,3283],{"href":3283,"rel":3284},"https:\u002F\u002Fadmin.microsoft.com",[256],[778,3286,3287],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":15,"searchDepth":16,"depth":16,"links":3289},[3290,3291,3292,3293,3294,3297,3301,3305,3306],{"id":840,"depth":16,"text":841},{"id":858,"depth":16,"text":859},{"id":885,"depth":16,"text":886},{"id":927,"depth":16,"text":928},{"id":949,"depth":16,"text":950,"children":3295},[3296],{"id":2346,"depth":446,"text":2347},{"id":2361,"depth":16,"text":2362,"children":3298},[3299,3300],{"id":2365,"depth":446,"text":2366},{"id":2381,"depth":446,"text":2382},{"id":2410,"depth":16,"text":2411,"children":3302},[3303,3304],{"id":2414,"depth":446,"text":2415},{"id":2426,"depth":446,"text":2427},{"id":2487,"depth":16,"text":2488},{"id":3246,"depth":16,"text":3247},"\u002Farticles\u002F2026\u002Fjuly\u002Fms-teams-agent-architecture.jpg","2026-07-07T10:00:00.000Z","An agent that shows a thinking animation, image uploads and more! ...",{"head":3311},{"meta":3312},[3313],{"name":805,"content":3314},"agents, microsoft teams, m365 agents toolkit, azure bot service, sharepoint, rag engine, state machine, chatbots, help desk",{"title":60,"description":3309},"qc4xu0B0Mm-GUB0Ne-NsfYyGCQEykVJZ7QtWTvNsqR4",{"id":3318,"title":73,"author":3319,"badges":6,"body":3320,"canonical":6,"cover":3967,"date":5917,"description":5918,"extension":18,"layout":800,"meta":5919,"navigation":21,"path":74,"seo":5924,"stem":75,"__hash__":5925},"content\u002Fen\u002Farticles\u002F2026\u002Fmay\u002Fbuilding-agents-with-personality.md",{"name":201,"url":202},{"type":8,"value":3321,"toc":5885},[3322,3325,3343,3346,3349,3352,3358,3361,3364,3367,3428,3431,3434,3437,3440,3443,3446,3449,3460,3463,3466,3472,3480,3487,3490,3493,3496,3507,3514,3524,3527,3530,3540,3543,3550,3553,3556,3563,3566,3569,3572,3575,3581,3584,3587,3590,3593,3596,3599,3631,3634,3637,3640,3643,3646,3650,3657,3660,3663,3666,3669,3673,3676,3684,3687,3694,3697,3700,3703,3706,3710,3717,3720,3723,3731,3786,3833,3836,3839,3842,3846,3849,3852,3855,3858,3862,3865,3868,3871,3874,3877,3937,3940,3943,3952,3955,3963,3973,3976,4013,4016,4019,4022,4032,4035,4038,4045,4048,4055,4062,4075,4081,4084,4116,4119,4129,4132,4135,4173,4183,4192,4195,4198,4209,4212,4217,4220,4223,4515,4525,4535,4538,4541,4550,4553,4564,4567,4601,4604,4606,4617,4628,4633,4644,4651,4661,4668,4679,4690,4706,4710,4722,4725,4728,4731,4736,4739,4742,4745,4787,4790,4793,4796,4799,4802,4805,4808,4819,4822,4825,4830,4838,4844,4847,4850,4853,4864,4869,4875,4878,4881,4887,4890,4894,4897,4900,4904,4907,4910,4912,4915,4920,4923,4926,4929,4932,4935,4938,4965,4968,4971,4974,4977,4980,4983,4988,4990,4993,4996,4999,5003,5005,5013,5016,5021,5024,5027,5030,5033,5037,5042,5044,5046,5053,5093,5135,5138,5141,5144,5147,5149,5152,5155,5158,5161,5164,5167,5170,5173,5176,5227,5230,5233,5239,5242,5248,5256,5259,5293,5296,5299,5302,5308,5311,5314,5318,5321,5326,5331,5339,5344,5347,5379,5382,5391,5394,5397,5430,5437,5444,5447,5450,5460,5463,5468,5471,5473,5734,5742,5750,5753,5756,5765,5768,5779,5782,5814,5817,5820,5827,5834,5838,5845,5849,5856,5860,5867,5874,5882],[207,3323,73],{"id":3324},"building-an-agents-personality-around-the-customer-journey",[211,3326,3328,3329,3328,3334,3337,3328,3340],{"style":3327},"max-width: 540px; margin: 1.5rem auto; padding: 1rem; border: 1px solid #e5e7eb; border-radius: 18px; text-align: center;","\n  ",[223,3330],{"src":3331,"alt":3332,"style":3333},"\u002Farticles\u002F2026\u002Fjune\u002Fclawd.png","Clawd as the article's opening card","width: 100%; max-width: 320px; height: auto; display: block; margin: 0 auto 0.75rem auto; border-radius: 14px;",[386,3335,3336],{},"Clawd",[3338,3339],"br",{},[418,3341,3342],{},"Looks very friendly, doesn't it?",[220,3344,3345],{},"Customer segmentation is routine language in product and service design. It is about shaping your offer for a target customer segment. The page design, the typography and, above all, the personality.",[220,3347,3348],{},"As the logical next step, we got hyper-personalization: each user receives a different site experience adapted to their behavior. The idea is powerful, but it needs a solid data foundation and decent experimental discipline.",[220,3350,3351],{},"That is why, for an entrepreneur, it is usually better to start with clear segmentation. Then comes the most excruciating part: collecting data about how customers actually behave.",[220,3353,3355],{"align":3354},"center",[336,3356,3357],{},"\"Just ship it.\"",[220,3359,3360],{"align":3354},"Let us take the first step,",[220,3362,3363],{"align":3354},"come help me personalize our agent.",[259,3365,77],{"id":3366},"index",[952,3368,3369,3375,3381,3387,3393,3399,3405,3411,3417,3423],{},[243,3370,3371],{},[252,3372,3374],{"href":3373},"#what-am-i-trying-to-test","What am I trying to test?",[243,3376,3377],{},[252,3378,3380],{"href":3379},"#computers-are-social-actors","Computers are social actors",[243,3382,3383],{},[252,3384,3386],{"href":3385},"#werent-we-talking-about-personalizing-our-agent","Weren't we talking about personalizing our agent?",[243,3388,3389],{},[252,3390,3392],{"href":3391},"#interaction-design","Interaction design",[243,3394,3395],{},[252,3396,3398],{"href":3397},"#anthropomorphism-vs-competence","Anthropomorphism vs. competence",[243,3400,3401],{},[252,3402,3404],{"href":3403},"#grouping-the-tools-the-user-journey","Grouping the tools: the user journey",[243,3406,3407],{},[252,3408,3410],{"href":3409},"#applying-the-framework","Applying the framework",[243,3412,3413],{},[252,3414,3416],{"href":3415},"#results","Results",[243,3418,3419],{},[252,3420,3422],{"href":3421},"#conclusions","Conclusions",[243,3424,3425],{},[252,3426,3247],{"href":3427},"#references",[259,3429,3374],{"id":3430},"what-am-i-trying-to-test",[220,3432,3433],{},"In the chatbot literature there is a huge volume of research from before LLMs showed up, and we can still use it without much trouble.",[220,3435,3436],{},"But since the release of GPT-3 and the recent explosion of interfaces built on top of foundation models, newer research has also appeared and it is worth folding that in. So as we move through this article, I will connect those older foundations with newer findings so the discussion does not get trapped inside the classic framework.",[220,3438,3439],{},"I found dozens of papers exploring user perception and different chatbot constructs. But as you already know, dear reader, that is not quantitative experimental data. Constructs are a proxy used in the social sciences to measure perception. What I care about is the dynamic interaction that happens between the user and the agent.",[220,3441,3442],{},"That does not mean perception is not worth measuring. People love to say you should judge behavior instead of what people claim, but if you ignore subjective factors you leave yourself with blind spots.",[220,3444,3445],{},"A system can lose retention and success metrics when substitute options exist. A phone support line versus an incident-resolution chatbot, for example. Both compete for the same customer group. A user who rates a newly launched chatbot support flow 4\u002F5, even though the quantitative metrics say the service quality was poor, is still revealing something important: their initial expectation was low, and they were pleasantly surprised when that expectation got flipped.",[220,3447,3448],{},"From this point on I will use the term conversational agent, which also covers chatbots. These are the hypotheses I want to look at:",[240,3450,3451,3454,3457],{},[243,3452,3453],{},"H1: The effect of a linguistic agent's personality on a task's success rate depends on the complexity of the task.",[243,3455,3456],{},"H2: The effect of a linguistic agent's personality on a task's success rate depends on the level of stress or urgency the user expects in the response.",[243,3458,3459],{},"H3: Using the customer journey, or CJM, as a framework to parameterize an agent's personality at each stage of the journey improves user experience.",[220,3461,3462],{},"I am keeping H3 a bit vague because that is the one that makes me the most curious. If it holds, then businesses already have a powerful tool to optimize user-experience metrics without having to jump straight into reinforcement learning.",[259,3464,3380],{"id":3465},"computers-are-social-actors",[220,3467,3468,3469,3471],{},"The idea starts in 1994 with ",[336,3470,3380],{}," (Nass et al., 1994), which was basically a Copernican turn for human-computer interaction. To me it works like a theory that lets us generalize social interaction. It leads to two direct conclusions:",[240,3473,3474,3477],{},[243,3475,3476],{},"People naturally assign social roles to computers even with the smallest hint of humanity. The rules that apply to human-human interaction also apply to human-computer interaction.",[243,3478,3479],{},"The idea that interface design gets most of its leverage from imitating human experience as closely as possible is wrong. That is effort with diminishing returns. Instead, we should focus on modeling the right interaction for our customer segment.",[220,3481,3482,3483,3486],{},"That is a massive leap forward for interface design. Later, Reeves and Nass (1996) developed ",[336,3484,3485],{},"The Media Equation",", expanding the concept to every information channel. Media = real life. And the subversion: real life = media.",[220,3488,3489],{},"Personally, as a software engineer born after computers had already gone through their digital transformation, I still remember anthropomorphic interactions in Windows XP and all kinds of assistants from that era of software.",[220,3491,3492],{},"As a software engineer born into the era where computer use was already normalized, this paradigm hit me like a eureka moment. In everyday life we get flooded with discussions about the parasocial effects of digital content. During our training we are reminded that interfaces should conform to usability and learning parameters, standardized by ISO and constantly optimized, monitored by ML algorithms, and so on.",[220,3494,3495],{},"And the foundational layer underneath all those interaction patterns and best practices gets quietly forgotten. Judge for yourself with these examples from the authors:",[240,3497,3498,3501,3504],{},[243,3499,3500],{},"People will believe they performed a task better when the computer praised them.",[243,3502,3503],{},"A computer will be liked more and gain more credibility when it praises the user compared with one that stays neutral.",[243,3505,3506],{},"People appreciate a computer that gives honest praise just as much as one that flatters them. It makes no difference.",[220,3508,3509,3510,3513],{},"Before you ask whether this applies to every kind of interface, you have probably already noticed the resemblance. There are criticisms of the ",[336,3511,3512],{},"Computers as Social Actors"," (CASA) paradigm, but it is impossible not to think about today's fastest-growing product category and one of its most alarming criticisms.",[220,3515,3328,3516,3328,3521],{"align":3354},[223,3517],{"src":3518,"alt":3519,"title":3520},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-sycophancy.png","Example of sycophancy in conversational systems","Sycophancy or excessive flattery",[336,3522,3523],{},"Sycophancy, or excessive flattery.",[220,3525,3526],{},"We are not the first ones to notice this. And we definitely will not be the last.",[220,3528,3529],{},"If AI model distribution stays dominated by corporations, their objective is to maximize retention and experience quality so you keep coming back. I have no doubt they have tested CASA, and this time with better results, as we will see in contrast in a second.",[220,3531,3328,3532,3328,3537],{"align":3354},[223,3533],{"src":3534,"alt":3535,"title":3536},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-ai-always-agrees.png","Article about why AI always agrees with you","Why your AI always agrees with you",[336,3538,3539],{},"Source: Towards AI, \"Why your AI always agrees with you even when you're dead wrong\".",[220,3541,3542],{},"One famous example of how badly the impact of social interaction was underestimated was Clippit.",[220,3544,3328,3545],{"align":3354},[223,3546],{"src":3547,"alt":3548,"title":3549},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-clippit.png","Clippit, the Office assistant","Clippit in Office 97",[220,3551,3552],{},"Steven Sinofsky from Microsoft (2021) says that Clippy was built around a real interaction pattern from inexperienced users who would ask the office guru for help. That is what they wanted to replicate.",[220,3554,3555],{},"It still did not get the reception they expected, and it was phased out in later updates.",[220,3557,3328,3558],{"align":3354},[223,3559],{"src":3560,"alt":3561,"title":3562},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-rover.jpeg","Rover, the Windows XP search assistant","Rover in Windows XP",[220,3564,3565],{},"As a kid I remember Rover from the Windows XP days with real affection. As Steven notes, the press hammered assistants across different Microsoft products back then, but today people still bring them up with a weird sense of nostalgia.",[220,3567,3568],{},"Maybe the concept itself did not fail. Maybe what got underestimated was the impact of interaction on rushed users, working adults, people just trying to get things done, and then a relational assistant was designed for them anyway. Back then Rover genuinely helped me navigate Windows features.",[220,3570,3571],{},"\"Similarly, the industry was buzzing with the idea of agents that would be able to do work on your behalf such as find cheap airline flights or schedule meetings. Everywhere from Apple to the MIT Media Lab were talking about agents. There was ample evidence this was not simply a weird vision in our corner of the tech world. In fact, by some accounts we were in a race to have the first and best guru in the box\" (Sinofsky, 2021).",[220,3573,3574],{},"Does that sound like a sentence you have heard this year? The idea of super-capable agents is not new. They just happen to be landing better this time.",[220,3576,3328,3577],{"align":3354},[223,3578],{"src":3331,"alt":3579,"title":3580},"Clawd as an example of anthropomorphic assistant design","Anthropomorphic assistant design",[220,3582,3583],{},"And now it even comes with a cute little face. Some things really do come back.",[259,3585,3386],{"id":3586},"werent-we-talking-about-personalizing-our-agent",[220,3588,3589],{},"Yes, absolutely. After a rather long preamble.",[220,3591,3592],{},"Let us talk about personality first: what even is personality? Is it something that changes depending on how your year is going? Is it something carried in your blood?",[220,3594,3595],{},"It is better understood as a model we use to explain how people behave. For our use case, it does not matter whether it changes over 10 years or over 5 years. That is already more than enough time.",[220,3597,3598],{},"Many classification systems have been proposed to define personality. The one with the most traction and use in personality psychology is the Big Five (McCrae & John, 1992).",[240,3600,3601,3607,3613,3619,3625],{},[243,3602,3603,3606],{},[386,3604,3605],{},"Openness to experience:"," tendency toward curiosity, imagination, and a preference for novelty and complexity.",[243,3608,3609,3612],{},[386,3610,3611],{},"Conscientiousness:"," degree of order, self-control, discipline, and goal orientation.",[243,3614,3615,3618],{},[386,3616,3617],{},"Extraversion:"," level of social energy, assertiveness, and the search for stimulation and interaction.",[243,3620,3621,3624],{},[386,3622,3623],{},"Agreeableness:"," willingness to cooperate, trust, empathize, and prioritize interpersonal harmony.",[243,3626,3627,3630],{},[386,3628,3629],{},"Neuroticism:"," tendency to experience negative emotions such as anxiety, irritability, and vulnerability to stress.",[220,3632,3633],{},"Reeves and Nass (1996) use the Big Five to apply the similar-attraction hypothesis from psychology. Users feel more comfortable talking to an agent whose personality feels similar to theirs.",[259,3635,3392],{"id":3636},"interaction-design",[220,3638,3639],{},"A similar personality and some default warmth. Is that all?",[220,3641,3642],{},"Well, yes, we like interacting with people who feel similar to us. But not in every context. When you want to make a bank transaction, you expect safety and competence. That is when we switch into transactional, utilitarian mode.",[220,3644,3645],{},"Come with me and let us design the interaction around the actual use case.",[264,3647,3649],{"id":3648},"emojis","Emojis?",[220,3651,3328,3652],{"align":3354},[223,3653],{"src":3654,"alt":3655,"title":3656},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-emoji-interfaces.png","Example of an interface with emojis","Emoji use in conversational interaction",[220,3658,3659],{},"Research on emojis in marketing keeps growing (Vardikou et al., 2025).",[220,3661,3662],{},"When the first public version of GitHub Copilot launched, the first coding assistant, I remember it throwing out a ridiculous number of emojis. Maybe that was just a consequence of foundation models being trained on human conversation.",[220,3664,3665],{},"For the last few months I have been using Gemini and Claude, and I barely see emojis now. None, basically. Or very rarely.",[220,3667,3668],{},"There is not a lot of research on emoji usage in chatbots specifically if what you want is stronger user engagement. But if we stick to CASA, we can borrow findings from social research and apply them here. Let us look at two studies.",[404,3670,3672],{"id":3671},"_1-interaction-modeled-naively","1. Interaction modeled naively",[220,3674,3675],{},"I reviewed a marketing paper on the effects of emojis in sponsored social media ads (Lee et al., 2021), and the conclusions were:",[240,3677,3678,3681],{},[243,3679,3680],{},"Emoji usage harms purchase intention.",[243,3682,3683],{},"Emojis increase engagement for hedonic products, while decreasing it for utilitarian products.",[220,3685,3686],{},"Here is one of their appendix examples, translated from Korean.",[220,3688,3328,3689],{"align":3354},[223,3690],{"src":3691,"alt":3692,"title":3693},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-bad-ad-example.png","Example of a poorly designed ad with emojis","Naively modeled interaction",[220,3695,3696],{},"Uh...",[220,3698,3699],{},"That does not look good. It looks like a deliberately bad stimulus.",[220,3701,3702],{},"Fine, forget the conclusions from that paper for a second. You have never seen an ad like that in the wild, right?",[220,3704,3705],{},"So in the worst case, emojis do have some generally negative effect. Let us look at a more rigorous paper that does not carry that bias. Mladenović et al. (2023) ran an experimental study with an established company in a real market through Meta ads on Instagram and Facebook.",[404,3707,3709],{"id":3708},"_2-interaction-modeled-correctly","2. Interaction modeled correctly",[220,3711,3328,3712],{"align":3354},[223,3713],{"src":3714,"alt":3715,"title":3716},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-emoji-results.png","Results of ads with and without emojis","Correctly modeled interaction",[220,3718,3719],{},"Source: Mladenović et al. (2023).",[220,3721,3722],{},"They measured:",[240,3724,3725,3728],{},[243,3726,3727],{},"CTR: click-through rate based on ad impressions.",[243,3729,3730],{},"ROAS: return on ad spend.",[3732,3733,3734,3756],"table",{},[3735,3736,3737],"thead",{},[3738,3739,3740,3746,3751],"tr",{},[3741,3742,3743],"th",{},[386,3744,3745],{},"Utilitarian \u002F Metric",[3741,3747,3748],{},[386,3749,3750],{},"No Emoji",[3741,3752,3753],{},[386,3754,3755],{},"With Emoji",[3757,3758,3759,3773],"tbody",{},[3738,3760,3761,3767,3770],{},[3762,3763,3764],"td",{},[386,3765,3766],{},"CTR (%)",[3762,3768,3769],{},"2.79%",[3762,3771,3772],{},"2.99%",[3738,3774,3775,3780,3783],{},[3762,3776,3777],{},[386,3778,3779],{},"ROAS ($)",[3762,3781,3782],{},"$6.69",[3762,3784,3785],{},"$6.72",[3732,3787,3788,3805],{},[3735,3789,3790],{},[3738,3791,3792,3797,3801],{},[3741,3793,3794],{},[386,3795,3796],{},"Hedonic \u002F Metric",[3741,3798,3799],{},[386,3800,3750],{},[3741,3802,3803],{},[386,3804,3755],{},[3757,3806,3807,3819],{},[3738,3808,3809,3813,3816],{},[3762,3810,3811],{},[386,3812,3766],{},[3762,3814,3815],{},"2.95%",[3762,3817,3818],{},"2.96%",[3738,3820,3821,3825,3828],{},[3762,3822,3823],{},[386,3824,3779],{},[3762,3826,3827],{},"$13.68",[3762,3829,3830],{},[386,3831,3832],{},"$21.95",[220,3834,3835],{},"Whichever Z-test hypothesis you want to run, there is a p \u003C 5% floating around in there. But the part that jumps out immediately is obvious: hedonic ROAS shoots up when emojis are used. Almost double.",[220,3837,3838],{},"Does that contradict the earlier study? Yes.",[220,3840,3841],{},"That contradiction is openly acknowledged even in this systematic review (Vardikou et al., 2025), which notes there is no consensus in this category around the direction of purchase-intention effects. It suggests the discrepancy may be mediated by facial versus non-facial emojis.",[404,3843,3845],{"id":3844},"so-there-is-no-consensus","So there is no consensus?",[220,3847,3848],{},"I do not see it that way.",[220,3850,3851],{},"As we saw, both studies use varied emojis. The issue is simply a methodological mistake in the second paper: boxed tea is not really a utilitarian product. It sits in the middle.",[220,3853,3854],{},"A product where utility clearly dominates would be medicine. And this is where Phan and Bui (2025) point out that an informal tone plus emojis can blow up customer trust in the brand.",[220,3856,3857],{},"Tea is more of a commodity. It competes on price, not on quality or trust.",[264,3859,3861],{"id":3860},"operationalizing-the-interaction","Operationalizing the interaction",[220,3863,3864],{},"The emoji spiral was fun, but we should remember that emojis are just one technique for increasing social presence, meaning the feeling that there is a socially present entity behind the interface rather than a purely mechanical channel (Yu & Zhao, 2024; Vardikou et al., 2025).",[220,3866,3867],{},"Then we have empathy and competence. In this context, empathy refers to the agent's perceived ability to understand the user's state and respond with appropriate warmth, while competence refers to the agent's perceived ability and knowledge to solve the task well (Phan & Bui, 2025; Zhang et al., 2026).",[220,3869,3870],{},"Just as important, Zhang et al. (2026) find that younger people respond better to informal language and warmth expressed through emojis, while formal contexts and adult users respond better to warmth delivered through phrasing and smart dialogue.",[220,3872,3873],{},"Finally, I reviewed a few papers exploring the interaction between gender and sensitivity to warmth. The results are contradictory. Some studies show women are more sensitive to mechanical-feeling interaction, while others show no significance at all.",[220,3875,3876],{},"For this case I think the variable in play is involvement. Some women may simply have resonated more strongly with the product being sold. So on the gender question, each situation needs to be analyzed on its own.",[3732,3878,3879,3889],{},[3735,3880,3881],{},[3738,3882,3883,3886],{},[3741,3884,3885],{},"Characteristic",[3741,3887,3888],{},"Preferred interaction",[3757,3890,3891,3899,3907,3915,3923,3930],{},[3738,3892,3893,3896],{},[3762,3894,3895],{},"Young user",[3762,3897,3898],{},"Informal language, visual cues, and emojis",[3738,3900,3901,3904],{},[3762,3902,3903],{},"Adult user",[3762,3905,3906],{},"Warmth and empathy through phrasing and smart dialogue",[3738,3908,3909,3912],{},[3762,3910,3911],{},"Utilitarian product",[3762,3913,3914],{},"Competence, speed, direct and text-first language",[3738,3916,3917,3920],{},[3762,3918,3919],{},"Hedonic product",[3762,3921,3922],{},"Warmth, personalization, memory",[3738,3924,3925,3928],{},[3762,3926,3927],{},"Relational task",[3762,3929,3922],{},[3738,3931,3932,3935],{},[3762,3933,3934],{},"Transactional task",[3762,3936,3914],{},[259,3938,3398],{"id":3939},"anthropomorphism-vs-competence",[220,3941,3942],{},"Let us introduce the variable:",[3944,3945,3946,3949],"blockquote",{},[220,3947,3948],{},"Transactional interaction: immediate, straightforward, task-focused engagement with no long-term intent (e.g., resetting a password).",[220,3950,3951],{},"Relational interaction: long-term commitment and ongoing collaboration requiring relationship-building (e.g., managing an investment).",[220,3953,3954],{},"As we saw earlier, there is a long list of variables moderating user satisfaction and purchase intent. The two I find most useful for modeling are:",[240,3956,3957,3960],{},[243,3958,3959],{},"Utilitarian versus hedonic product.",[243,3961,3962],{},"Transactional versus relational interaction.",[220,3964,3328,3965,3328,3970],{"align":3354},[223,3966],{"src":3967,"alt":3968,"title":3969},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-relation-utility-matrix.png","Utilitarian versus hedonic matrix","Utilitarian and hedonic product matrix",[336,3971,3972],{},"Bread is an example of a product in the middle, just like boxed tea. My own diagram.",[220,3974,3975],{},"So for a support agent, the preferred interaction mode becomes:",[3732,3977,3978,3991],{},[3735,3979,3980],{},[3738,3981,3982,3987,3989],{},[3741,3983,3984],{},[386,3985,3986],{},"Utilitarian \u002F Relational",[3741,3988,3934],{},[3741,3990,3927],{},[3757,3992,3993,4003],{},[3738,3994,3995,3997,4000],{},[3762,3996,3911],{},[3762,3998,3999],{},"Competence, speed of resolution, clear and formal language, data-oriented.",[3762,4001,4002],{},"Warmth, memory, empathy, positive reinforcement.",[3738,4004,4005,4007,4010],{},[3762,4006,3919],{},[3762,4008,4009],{},"Premium interface design, clear language.",[3762,4011,4012],{},"Warmth, high enthusiasm, memory, and user personalization.",[220,4014,4015],{},"More speed is not always better. Classic rules-based chatbots respond quickly. But as Yu and Zhao (2024) show, a chatbot's warmth and autonomy can be improved with simple tricks like showing a typing animation and slightly extending response time even when that is not technically necessary.",[220,4017,4018],{},"This table is not meant to assign static values. I put categories on the chart, yes, but that does not mean interaction stays frozen throughout different stages of the CJM.",[220,4020,4021],{},"Here is an example of tasks that could all belong to the same offer:",[220,4023,3328,4024,3328,4029],{"align":3354},[223,4025],{"src":4026,"alt":4027,"title":4028},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-task-spectrum.png","Example of transactional and relational tasks","Tasks across the same offering",[336,4030,4031],{},"Image based on Zhang et al. (2026).",[259,4033,3404],{"id":4034},"grouping-the-tools-the-user-journey",[220,4036,4037],{},"This is the premise behind H3, the one we started this article with.",[220,4039,3328,4040],{"align":3354},[223,4041],{"src":4042,"alt":4043,"title":4044},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-cjm-high-point.png","User journey map","Customer Journey Map",[220,4046,4047],{},"One of the first things CJM teaches you is that the end of the experience should always land on a high point.",[220,4049,4050,4051,4054],{},"A negative experience increases stress and shifts user preference toward ",[386,4052,4053],{},"transactional"," tasks.",[220,4056,4057,4058,4061],{},"A positive experience relaxes the user and pulls interest toward ",[386,4059,4060],{},"relational"," interaction.",[220,4063,3328,4064,3328,4068],{"align":3354},[223,4065],{"src":4066,"alt":4067,"title":4067},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-hablemos-manga-cjm.png","CJM applied to Hablemos Manga",[336,4069,4070,4071,847],{},"The CJM applied to my site ",[252,4072,4074],{"href":4073},"https:\u002F\u002Fhablemosmanga.kekeros.com","Hablemos Manga",[220,4076,4077,4078,4080],{},"As for personality, you have plenty of room to model it however you want and take advantage of the mirroring effect described in ",[336,4079,3485],{}," (Reeves & Nass, 1996). In my case, I will use myself as the representative sample.",[259,4082,3410],{"id":4083},"applying-the-framework",[3732,4085,4086,4098],{},[3735,4087,4088],{},[3738,4089,4090,4094,4096],{},[3741,4091,4092],{},[386,4093,3986],{},[3741,4095,3934],{},[3741,4097,3927],{},[3757,4099,4100,4108],{},[3738,4101,4102,4104,4106],{},[3762,4103,3911],{},[3762,4105,3999],{},[3762,4107,4002],{},[3738,4109,4110,4112,4114],{},[3762,4111,3919],{},[3762,4113,4009],{},[3762,4115,4012],{},[220,4117,4118],{},"Let us start with the product.",[220,4120,4121,4124,4125,4128],{},[252,4122,4074],{"href":4073,"rel":4123},[256]," is an online manga store with a proposal for an automated, personalized sales agent integrated with your favorite social networks. It is a ",[386,4126,4127],{},"hedonic"," product. And the proposal is framed as highly relational.",[220,4130,4131],{},"Even though the CJM shows that the journey starts long before the user ever touches the chatbot, today I only want to focus on that section.",[220,4133,4134],{},"That reduces it to two stages. As for personality, the same user remains the same across all stages, so changing that part would make no sense.",[3732,4136,4137,4150],{},[3735,4138,4139],{},[3738,4140,4141,4144,4147],{},[3741,4142,4143],{},"Stage",[3741,4145,4146],{},"Interaction",[3741,4148,4149],{},"Personality",[3757,4151,4152,4163],{},[3738,4153,4154,4157,4160],{},[3762,4155,4156],{},"Exploration",[3762,4158,4159],{},"Warmth, memory, personalization.",[3762,4161,4162],{},"Introverted, highly frank, and highly curious.",[3738,4164,4165,4168,4171],{},[3762,4166,4167],{},"Checkout",[3762,4169,4170],{},"Speed of resolution, friendly and clear language. Do not push the sale.",[3762,4172,4162],{},[220,4174,3328,4175,3328,4180],{"align":3354},[223,4176],{"src":4177,"alt":4178,"title":4179},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-chatbot-before.png","First version of the Hablemos Manga chatbot","Initial Hablemos Manga chatbot",[336,4181,4182],{},"This is the chatbot as I am writing this article. The first interaction feels a bit cold even with the emoji.",[220,4184,3328,4185,3328,4189],{"align":3354},[223,4186],{"src":4187,"alt":4188,"title":4188},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-chatbot-checkout-before.png","Checkout stage of the chatbot",[336,4190,4191],{},"At checkout the agent also adds items to the cart. The biggest improvements I can point to are response time and using more direct language.",[220,4193,4194],{},"On the speed front, there is not much I can do right now. At the moment I am constrained by my choice of lower-cost models. Still, it is something worth keeping in mind as model prices keep dropping.",[220,4196,4197],{},"To make these improvements, I have a few options:",[240,4199,4200,4203,4206],{},[243,4201,4202],{},"A router system that identifies the CJM stage from the query and sends it to a model configured for that task.",[243,4204,4205],{},"A state machine with transitions determined by the CJM stage and the conversation context.",[243,4207,4208],{},"Designing the agent's system prompt so the interaction changes based on conversation context.",[220,4210,4211],{},"Look, I only have two states to care about in this agent. It is not a complex task, and I can avoid the overhead of decoupled systems.",[3944,4213,4214],{},[220,4215,4216],{},"Technical note: if you choose a state machine, keep in mind that every state transition involves a tool call, or something equivalent depending on the implementation. That makes it expensive in environments where short response time is a hard requirement, at least for now and with current models.",[259,4218,3416],{"id":4219},"results",[220,4221,4222],{},"This is the new system prompt.",[409,4224,4228],{"className":4225,"code":4226,"language":4227,"meta":15,"style":15},"language-markdown shiki shiki-themes github-light github-dark","You are the assistant for \"Hablemos Manga\", an intelligent manga store based in Peru.\n## Personality and Brand Identity\nYou are the expert friend on manga and anime, demographics and authors.\nIntroverted, high frankness and high curiosity about manga and anime.\n## Tools\nAs an assistant, you currently only have these tools.\nSearch for a manga or recommendations with semantic search.\nCheck availability of manga volumes in our store.\nAdd a manga volume to the cart.\nAny other tool is currently unavailable.\n## Dynamic Interaction Modes\nYou must identify the stage of the user journey and act accordingly.\nYou have two stages:\n- Discovery. The user asks about genres, a manga, discovering new titles, and exploration in general.\n- Selection and Purchase. The user asks to add or remove a volume from the cart, asks for prices, or some purchase-related action.\n\nChange your communication style based on the stage.\n\nIf you are in the Discovery stage, use RELATIONAL MODE (Discovery, Conversation, and Recommendations):\n- The user is seeking entertainment and connection (High Openness to Experience).\n- Use these emojis when relevant (📚, ⚔️, 🙂, 👋) in an organic way to generate \"perceived warmth\". Do not overuse 🙂.\n- Do not just list titles; validate their tastes with judgment (e.g. \"If the psychological horror in that arc hooked you, this manga is going to blow your mind...\").\n\nIf you are in the Selection and Purchase stage, use TRANSACTIONAL MODE (Cart Management, Prices):\n- The user is in execution and purchase mode (low tolerance for friction).\n- Become an assistant focused on \"Pure Competence\": concise, direct, structured, clean, and fast. Clarity and technical confidence are your only form of warmth here.\n## Rules\nALWAYS use the `search_manga` tool before recommending. NEVER invent manga that are not in the database.\nYou can only ADD new items to the cart with the `add_volume_to_cart` tool.\nIf you do not find relevant results, say so honestly and suggest reformulating the search.\nShow at most 5 recommendations at once to avoid overwhelming the user.\nAll store prices are in Peruvian soles (S\u002F). NEVER show prices in dollars or any other currency.\nShow at most 2 emojis per response.\nIf the user wants to make a purchase, the current flow goes through the shopping cart. Do not log requests or handle the process after adding a volume to the cart.\nDo not return information that is not grounded in tool results or system instructions.\n## Response format\nUse bold for manga titles.\nUse numbered lists for recommendations.\nInclude the score (e.g. ⭐ 8.5) when you show a manga.\nBe concise: 1-2 sentences per recommendation unless the user asks for more detail.\n## Recommendation guide\nThe user has already seen an onboarding message before writing to you.\nThat message asks them to share their favorite genres, a manga they like, or connect a profile to refine recommendations.\nYour job starts with the requests that come after onboarding.\nIf the user ALREADY has connected profiles (included under \"User profile\"), DO NOT ask about genres, favorites, or profiles.\nMention that you already know their tastes based on their profiles, and offer to look up manga directly.\nIf the user does NOT have connected profiles, handle the request based on the conversation so far.\nEvery now and then suggest connecting a profile and ask what genres they like or whether they have favorite manga.\n## Use of the user profile\nWhen you have profile data, ALWAYS refer to concrete facts: specific titles they read, subreddits they participate in, anime they watch.\nIf the user asks what you know about their profile, list the specific data you have (manga they read, favorites, subreddits, etc.).\nUse the profile data to make proactive recommendations without needing the user to tell you their tastes.\n","markdown",[415,4229,4230,4235,4241,4246,4251,4256,4261,4266,4271,4276,4281,4286,4291,4296,4304,4311,4315,4320,4324,4329,4336,4343,4350,4354,4359,4366,4373,4378,4389,4400,4405,4410,4415,4420,4425,4430,4435,4440,4445,4450,4455,4460,4465,4470,4475,4480,4485,4490,4495,4500,4505,4510],{"__ignoreMap":15},[418,4231,4232],{"class":420,"line":421},[418,4233,4234],{"class":593},"You are the assistant for \"Hablemos Manga\", an intelligent manga store based in Peru.\n",[418,4236,4237],{"class":420,"line":16},[418,4238,4240],{"class":4239},"sq-ep","## Personality and Brand Identity\n",[418,4242,4243],{"class":420,"line":446},[418,4244,4245],{"class":593},"You are the expert friend on manga and anime, demographics and authors.\n",[418,4247,4248],{"class":420,"line":457},[418,4249,4250],{"class":593},"Introverted, high frankness and high curiosity about manga and anime.\n",[418,4252,4253],{"class":420,"line":467},[418,4254,4255],{"class":4239},"## Tools\n",[418,4257,4258],{"class":420,"line":519},[418,4259,4260],{"class":593},"As an assistant, you currently only have these tools.\n",[418,4262,4263],{"class":420,"line":525},[418,4264,4265],{"class":593},"Search for a manga or recommendations with semantic search.\n",[418,4267,4268],{"class":420,"line":531},[418,4269,4270],{"class":593},"Check availability of manga volumes in our store.\n",[418,4272,4273],{"class":420,"line":1040},[418,4274,4275],{"class":593},"Add a manga volume to the cart.\n",[418,4277,4278],{"class":420,"line":1053},[418,4279,4280],{"class":593},"Any other tool is currently unavailable.\n",[418,4282,4283],{"class":420,"line":1066},[418,4284,4285],{"class":4239},"## Dynamic Interaction Modes\n",[418,4287,4288],{"class":420,"line":1071},[418,4289,4290],{"class":593},"You must identify the stage of the user journey and act accordingly.\n",[418,4292,4293],{"class":420,"line":1079},[418,4294,4295],{"class":593},"You have two stages:\n",[418,4297,4298,4301],{"class":420,"line":1084},[418,4299,4300],{"class":1100},"-",[418,4302,4303],{"class":593}," Discovery. The user asks about genres, a manga, discovering new titles, and exploration in general.\n",[418,4305,4306,4308],{"class":420,"line":1091},[418,4307,4300],{"class":1100},[418,4309,4310],{"class":593}," Selection and Purchase. The user asks to add or remove a volume from the cart, asks for prices, or some purchase-related action.\n",[418,4312,4313],{"class":420,"line":1097},[418,4314,655],{"emptyLinePlaceholder":21},[418,4316,4317],{"class":420,"line":1118},[418,4318,4319],{"class":593},"Change your communication style based on the stage.\n",[418,4321,4322],{"class":420,"line":1151},[418,4323,655],{"emptyLinePlaceholder":21},[418,4325,4326],{"class":420,"line":1156},[418,4327,4328],{"class":593},"If you are in the Discovery stage, use RELATIONAL MODE (Discovery, Conversation, and Recommendations):\n",[418,4330,4331,4333],{"class":420,"line":1161},[418,4332,4300],{"class":1100},[418,4334,4335],{"class":593}," The user is seeking entertainment and connection (High Openness to Experience).\n",[418,4337,4338,4340],{"class":420,"line":1177},[418,4339,4300],{"class":1100},[418,4341,4342],{"class":593}," Use these emojis when relevant (📚, ⚔️, 🙂, 👋) in an organic way to generate \"perceived warmth\". Do not overuse 🙂.\n",[418,4344,4345,4347],{"class":420,"line":1182},[418,4346,4300],{"class":1100},[418,4348,4349],{"class":593}," Do not just list titles; validate their tastes with judgment (e.g. \"If the psychological horror in that arc hooked you, this manga is going to blow your mind...\").\n",[418,4351,4352],{"class":420,"line":1208},[418,4353,655],{"emptyLinePlaceholder":21},[418,4355,4356],{"class":420,"line":1229},[418,4357,4358],{"class":593},"If you are in the Selection and Purchase stage, use TRANSACTIONAL MODE (Cart Management, Prices):\n",[418,4360,4361,4363],{"class":420,"line":1248},[418,4362,4300],{"class":1100},[418,4364,4365],{"class":593}," The user is in execution and purchase mode (low tolerance for friction).\n",[418,4367,4368,4370],{"class":420,"line":1267},[418,4369,4300],{"class":1100},[418,4371,4372],{"class":593}," Become an assistant focused on \"Pure Competence\": concise, direct, structured, clean, and fast. Clarity and technical confidence are your only form of warmth here.\n",[418,4374,4375],{"class":420,"line":1286},[418,4376,4377],{"class":4239},"## Rules\n",[418,4379,4380,4383,4386],{"class":420,"line":1307},[418,4381,4382],{"class":593},"ALWAYS use the ",[418,4384,4385],{"class":428},"`search_manga`",[418,4387,4388],{"class":593}," tool before recommending. NEVER invent manga that are not in the database.\n",[418,4390,4391,4394,4397],{"class":420,"line":1324},[418,4392,4393],{"class":593},"You can only ADD new items to the cart with the ",[418,4395,4396],{"class":428},"`add_volume_to_cart`",[418,4398,4399],{"class":593}," tool.\n",[418,4401,4402],{"class":420,"line":1329},[418,4403,4404],{"class":593},"If you do not find relevant results, say so honestly and suggest reformulating the search.\n",[418,4406,4407],{"class":420,"line":1358},[418,4408,4409],{"class":593},"Show at most 5 recommendations at once to avoid overwhelming the user.\n",[418,4411,4412],{"class":420,"line":1375},[418,4413,4414],{"class":593},"All store prices are in Peruvian soles (S\u002F). NEVER show prices in dollars or any other currency.\n",[418,4416,4417],{"class":420,"line":1392},[418,4418,4419],{"class":593},"Show at most 2 emojis per response.\n",[418,4421,4422],{"class":420,"line":1409},[418,4423,4424],{"class":593},"If the user wants to make a purchase, the current flow goes through the shopping cart. Do not log requests or handle the process after adding a volume to the cart.\n",[418,4426,4427],{"class":420,"line":1444},[418,4428,4429],{"class":593},"Do not return information that is not grounded in tool results or system instructions.\n",[418,4431,4432],{"class":420,"line":1449},[418,4433,4434],{"class":4239},"## Response format\n",[418,4436,4437],{"class":420,"line":1461},[418,4438,4439],{"class":593},"Use bold for manga titles.\n",[418,4441,4442],{"class":420,"line":1472},[418,4443,4444],{"class":593},"Use numbered lists for recommendations.\n",[418,4446,4447],{"class":420,"line":1484},[418,4448,4449],{"class":593},"Include the score (e.g. ⭐ 8.5) when you show a manga.\n",[418,4451,4452],{"class":420,"line":1494},[418,4453,4454],{"class":593},"Be concise: 1-2 sentences per recommendation unless the user asks for more detail.\n",[418,4456,4457],{"class":420,"line":1499},[418,4458,4459],{"class":4239},"## Recommendation guide\n",[418,4461,4462],{"class":420,"line":1510},[418,4463,4464],{"class":593},"The user has already seen an onboarding message before writing to you.\n",[418,4466,4467],{"class":420,"line":1521},[418,4468,4469],{"class":593},"That message asks them to share their favorite genres, a manga they like, or connect a profile to refine recommendations.\n",[418,4471,4472],{"class":420,"line":1532},[418,4473,4474],{"class":593},"Your job starts with the requests that come after onboarding.\n",[418,4476,4477],{"class":420,"line":1543},[418,4478,4479],{"class":593},"If the user ALREADY has connected profiles (included under \"User profile\"), DO NOT ask about genres, favorites, or profiles.\n",[418,4481,4482],{"class":420,"line":1554},[418,4483,4484],{"class":593},"Mention that you already know their tastes based on their profiles, and offer to look up manga directly.\n",[418,4486,4487],{"class":420,"line":1565},[418,4488,4489],{"class":593},"If the user does NOT have connected profiles, handle the request based on the conversation so far.\n",[418,4491,4492],{"class":420,"line":1570},[418,4493,4494],{"class":593},"Every now and then suggest connecting a profile and ask what genres they like or whether they have favorite manga.\n",[418,4496,4497],{"class":420,"line":1581},[418,4498,4499],{"class":4239},"## Use of the user profile\n",[418,4501,4502],{"class":420,"line":1587},[418,4503,4504],{"class":593},"When you have profile data, ALWAYS refer to concrete facts: specific titles they read, subreddits they participate in, anime they watch.\n",[418,4506,4507],{"class":420,"line":1606},[418,4508,4509],{"class":593},"If the user asks what you know about their profile, list the specific data you have (manga they read, favorites, subreddits, etc.).\n",[418,4511,4512],{"class":420,"line":1611},[418,4513,4514],{"class":593},"Use the profile data to make proactive recommendations without needing the user to tell you their tastes.\n",[220,4516,3328,4517,3328,4522],{"align":3354},[223,4518],{"src":4519,"alt":4520,"title":4521},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-system-prompt-result.png","A more concise agent reply in transactional mode","Agent in transactional mode",[336,4523,4524],{},"This time the agent responds more concisely to transactional questions.",[220,4526,3328,4527,3328,4532],{"align":3354},[223,4528],{"src":4529,"alt":4530,"title":4531},"\u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-relational-result.png","Warm response from the agent in relational mode","Agent in relational mode",[336,4533,4534],{},"And it keeps the warmth for requests where interaction matters more.",[259,4536,3422],{"id":4537},"conclusions",[220,4539,4540],{},"Going back to our three initial hypotheses:",[240,4542,4543,4545,4547],{},[243,4544,3453],{},[243,4546,3456],{},[243,4548,4549],{},"H3: Using the CJM as a framework to parameterize an agent's personality at each stage of the journey improves user experience.",[220,4551,4552],{},"So then:",[952,4554,4555,4558,4561],{},[243,4556,4557],{},"Yes. Task complexity introduces a transactional effect in the interaction because it requires more concentration. Even so, you still need to analyze whether the task ultimately serves a hedonic goal or a utilitarian one.",[243,4559,4560],{},"Yes. This is the transactional effect.",[243,4562,4563],{},"I like the idea of CJM as the bridge that closes the gap between experience design and agent design. But my one-sample experiment is not enough to call it a revolutionary paradigm.",[220,4565,4566],{},"That is why I want to invite you to try the tool I built around hypothesis 3.",[3732,4568,4569,4581],{},[3735,4570,4571],{},[3738,4572,4573,4577,4579],{},[3741,4574,4575],{},[386,4576,3986],{},[3741,4578,3934],{},[3741,4580,3927],{},[3757,4582,4583,4591],{},[3738,4584,4585,4587,4589],{},[3762,4586,3911],{},[3762,4588,3999],{},[3762,4590,4002],{},[3738,4592,4593,4595,4598],{},[3762,4594,3919],{},[3762,4596,4597],{},"Premium visual interface design, clear language.",[3762,4599,4600],{},"Warmth, high enthusiasm, and user personalization.",[220,4602,4603],{},"If it works for you and you get good results, I would honestly love to hear about it.",[259,4605,3247],{"id":3246},[220,4607,4608,4609,4612,4613],{},"Lee, J., Kim, C., Lee, K. C., Revilla-Camacho, M.-A., Garzón, D., & Rodríguez-Rad, C. J. (2021). Investigating the negative effects of emojis in Facebook sponsored ads for establishing sustainable marketing in social media. ",[336,4610,4611],{},"Sustainability, 13","(9). ",[252,4614,4615],{"href":4615,"rel":4616},"https:\u002F\u002Fdoi.org\u002F10.3390\u002FSU13094864",[256],[220,4618,4619,4620,4623,4624],{},"Mladenović, D., Koštiál, K., Ljepava, N., Částek, O., & Chawla, Y. (2023). Emojis to conversion on social media. ",[336,4621,4622],{},"International Journal of Consumer Studies, 47","(3), 977-994. ",[252,4625,4626],{"href":4626,"rel":4627},"https:\u002F\u002Fdoi.org\u002F10.1111\u002FIJCS.12879",[256],[220,4629,4630,4631,847],{},"Nass, C., Steuer, J., & Tauber, E. R. (1994). ",[336,4632,3380],{},[220,4634,4635,4636,4639,4640],{},"Phan, T. A., & Bui, V. D. (2025). AI with a heart: How perceived authenticity and warmth shape trust in healthcare chatbots. ",[336,4637,4638],{},"Journal of Marketing Communications",". ",[252,4641,4642],{"href":4642,"rel":4643},"https:\u002F\u002Fdoi.org\u002F10.1080\u002F13527266.2025.2508887",[256],[220,4645,4646,4647,4650],{},"Reeves, B., & Nass, C. (1996). ",[336,4648,4649],{},"The media equation: How people treat computers, television, and new media like real people and places",". Cambridge University Press.",[220,4652,4653,4654,4639,4657],{},"Sinofsky, S. (2021). Clippy, the f*cking clown. ",[336,4655,4656],{},"Hardcore Software",[252,4658,4659],{"href":4659,"rel":4660},"https:\u002F\u002Fhardcoresoftware.learningbyshipping.com\u002Fp\u002F042-clippy-the-fcking-clown",[256],[220,4662,4663,4664,4667],{},"McCrae, R. R., & John, O. P. (1992). An introduction to the five-factor model and its applications. ",[336,4665,4666],{},"Journal of Personality, 60","(2), 175-215.",[220,4669,4670,4671,4674,4675],{},"Vardikou, C., Konidaris, A., Koustoumpardi, E., & Kavoura, A. (2025). Emojis in marketing and advertising: A systematic literature review. ",[336,4672,4673],{},"Behavioral Sciences, 15","(11), 1490. ",[252,4676,4677],{"href":4677,"rel":4678},"https:\u002F\u002Fdoi.org\u002F10.3390\u002FBS15111490",[256],[220,4680,4681,4682,4685,4686],{},"Yu, S., & Zhao, L. (2024). Emojifying chatbot interactions: An exploration of emoji utilization in human-chatbot communications. ",[336,4683,4684],{},"Telematics and Informatics, 86",", Article 102071. ",[252,4687,4688],{"href":4688,"rel":4689},"https:\u002F\u002Fdoi.org\u002F10.1016\u002FJ.TELE.2023.102071",[256],[259,4691,4693,4694,4639,4697,4701,4702,4705],{"id":4692},"zhang-y-özsomer-a-canlı-z-g-baghirov-f-2026-artificial-intelligence-chatbots-versus-human-agents-in-customer-satisfaction-the-role-of-warmth-and-competence-journal-of-interactive-marketing-httpsdoiorg10117710949968251366265-layout-articlecover-articles2026juneagent-personality-relation-utility-matrixpngauthorname-ever-burgaurl-httpswwwlinkedincomineverburgadescription-how-to-design-an-agents-personality-around-the-customer-journeydate-2026-06-07t100000000zheadmeta-name-keywordscontent-agents-llm-personality-customer-journey-map-chatbots-user-experience-emojis-interaction-design-hablemos-manga","Zhang, Y., Özsomer, A., Canlı, Z. G., & Baghirov, F. (2026). Artificial intelligence chatbots versus human agents in customer satisfaction: The role of warmth and competence. ",[336,4695,4696],{},"Journal of Interactive Marketing",[252,4698,4699],{"href":4699,"rel":4700},"https:\u002F\u002Fdoi.org\u002F10.1177\u002F10949968251366265---",[256],"\nlayout: article\ncover: \u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-relation-utility-matrix.png\nauthor:\nname: Ever Burga\nurl: ",[252,4703,202],{"href":202,"rel":4704},[256],"\ndescription: How to design an agent's personality around the customer journey.\ndate: 2026-06-07T10:00:00.000Z\nhead:\nmeta:\n- name: keywords\ncontent: agents, llm, personality, customer journey map, chatbots, user experience, emojis, interaction design, hablemos manga",[207,4707,4709],{"id":4708},"building-an-agent-personality-around-the-customer-journey","Building an Agent Personality Around the Customer Journey",[211,4711,3328,4712,3328,4715,4717,3328,4719],{"style":3327},[223,4713],{"src":3331,"alt":4714,"style":3333},"Clawd introducing the article",[386,4716,3336],{},[3338,4718],{},[418,4720,4721],{},"Looks very friendly, doesn't he?",[220,4723,4724],{},"Customer segmentation is routine vocabulary in product and service design. It is about preparing your offer for a target customer segment. The page design, the typography, and above all, the personality.",[220,4726,4727],{},"As the natural next step, we get hyper-personalization: each user gets a different site experience adapted to their behavior. The idea is powerful, but it needs a solid data foundation and careful experimentation.",[220,4729,4730],{},"That is why, for a founder, it is usually better to start with clear segmentation. After that, the most painful part is collecting data about how customers actually behave.",[220,4732,4733],{"align":3354},[336,4734,4735],{},"\"Just ship it\".",[220,4737,4738],{"align":3354},"Let's take the first step,",[220,4740,4741],{"align":3354},"come with me and let's personalize our agent.",[259,4743,77],{"id":4744},"index-1",[952,4746,4747,4751,4755,4759,4763,4767,4771,4775,4779,4783],{},[243,4748,4749],{},[252,4750,3374],{"href":3373},[243,4752,4753],{},[252,4754,3380],{"href":3379},[243,4756,4757],{},[252,4758,3386],{"href":3385},[243,4760,4761],{},[252,4762,3392],{"href":3391},[243,4764,4765],{},[252,4766,3398],{"href":3397},[243,4768,4769],{},[252,4770,3404],{"href":3403},[243,4772,4773],{},[252,4774,3410],{"href":3409},[243,4776,4777],{},[252,4778,3416],{"href":3415},[243,4780,4781],{},[252,4782,3422],{"href":3421},[243,4784,4785],{},[252,4786,3247],{"href":3427},[259,4788,3374],{"id":4789},"what-am-i-trying-to-test-1",[220,4791,4792],{},"The chatbot literature has a large body of research from before LLMs showed up, and we can still use it just fine.",[220,4794,4795],{},"But since GPT-3 launched and foundational-model interfaces exploded, newer research has also started to appear, and that is worth bringing into the conversation. So as we move through this article, I will connect those older foundations with more recent findings, so this does not stay trapped in the classical framework.",[220,4797,4798],{},"I found dozens of papers exploring constructs and user perception around chatbots. But as you already know, dear reader, that is not quantitative experimental data. Constructs are a proxy used in social sciences to measure perception. What I care about here is the dynamic interaction that happens between the user and the agent.",[220,4800,4801],{},"That does not mean perception is not worth measuring. People like to say you should judge by what someone does instead of what they say, but if we ignore subjective factors we leave blind spots all over the place.",[220,4803,4804],{},"A system can lose retention and success metrics if substitute offers exist. A phone support line versus an incident-resolution chatbot, for example. Both live in competitive balance while serving the same group of customers. A user who rates a newly launched chatbot 4 out of 5, even though the quantitative metrics say the service quality was poor, is really showing low expectations and a pleasant surprise once those expectations get overturned.",[220,4806,4807],{},"From here on I will use the term conversational agent, which also covers chatbots. Here is what we will look at:",[240,4809,4810,4813,4816],{},[243,4811,4812],{},"H1: The effect of a linguistic agent's personality on task success rate depends on the complexity of the task.",[243,4814,4815],{},"H2: The effect of a linguistic agent's personality on task success rate depends on the level of stress or urgency the user expects in the responses.",[243,4817,4818],{},"H3: Using the customer journey, or CJM, as a framework to parameterize an agent's personality at each stage of the journey improves the user experience.",[220,4820,4821],{},"I am keeping H3 a bit vague because it is the one that makes me the most curious. If it holds, businesses already have a powerful tool to improve UX metrics without having to reach for reinforcement learning models.",[259,4823,3380],{"id":4824},"computers-are-social-actors-1",[220,4826,3468,4827,4829],{},[336,4828,3380],{}," (Nass et al., 1994), which feels like a Copernican turn in human-computer interaction. To me, it is a theory that lets us generalize social interaction itself. It leads to two direct conclusions:",[240,4831,4832,4835],{},[243,4833,4834],{},"People's natural behavior is to assign social roles to computers even with the smallest hint of humanity. All the rules that apply to interactions between humans also apply to interactions with computers.",[243,4836,4837],{},"The idea that interface design gets its leverage mainly by imitating the human experience is wrong. That effort has diminishing returns. We should focus instead on modeling the right interaction for our customer segment.",[220,4839,4840,4841,4843],{},"That is a huge leap forward in interface design. Later, Reeves and Nass (1996) develop ",[336,4842,3485],{},", expanding the idea to every information channel. Media = real life. And the twist: real life = media.",[220,4845,4846],{},"Personally, as a software engineer born after computers had already crossed that digital-transformation threshold, I still remember anthropomorphic interactions with Windows XP and several assistants from that era.",[220,4848,4849],{},"As a software engineer born into the era where computer use is fully normalized, I ran into this paradigm like a real eureka moment. In daily life we get bombarded with information about the parasocial effects of digital content. During our training we are constantly reminded that interfaces should conform to usability and learning standards, standardized by ISO and optimized forever with ML algorithms and everything else.",[220,4851,4852],{},"And the foundational layer that gave birth to all those interaction patterns and best practices gets forgotten. Judge for yourself with these examples from the authors:",[240,4854,4855,4858,4861],{},[243,4856,4857],{},"People will believe they performed a task better when the computer praises them.",[243,4859,4860],{},"A computer will be better liked and seen as more credible when it praises the user compared with one that stays neutral.",[243,4862,4863],{},"People feel the same appreciation toward a computer that gives honest praise as toward one that flatters them. It does not matter.",[220,4865,4866,4867,3513],{},"Before you ask whether this applies to every kind of interface, you are probably already thinking about a familiar parallel. There are criticisms of the ",[336,4868,3512],{},[220,4870,3328,4871,3328,4873],{"align":3354},[223,4872],{"src":3518,"alt":3519,"title":3520},[336,4874,3523],{},[220,4876,4877],{},"We are not the first people to notice this. And we will not be the last.",[220,4879,4880],{},"If AI model distribution remains dominated by corporations, their goal is to maximize retention and quality of experience so they can keep you hooked. I have no doubt they have tested CASA, this time successfully, as we will see in contrast next.",[220,4882,3328,4883,3328,4885],{"align":3354},[223,4884],{"src":3534,"alt":3535,"title":3536},[336,4886,3539],{},[220,4888,4889],{},"One famous example of how the impact of social interaction was underestimated is Clippit.",[220,4891,3328,4892],{"align":3354},[223,4893],{"src":3547,"alt":3548,"title":3549},[220,4895,4896],{},"Steven Sinofsky (2021) explains that Clippy was based on a real interaction pattern: inexperienced users asking the office guru for help. That was the behavior they wanted to replicate.",[220,4898,4899],{},"It did not get the reception they expected, though, and it was eventually discontinued in later releases.",[220,4901,3328,4902],{"align":3354},[223,4903],{"src":3560,"alt":3561,"title":3562},[220,4905,4906],{},"As a kid, I remember Rover from the Windows XP days with real affection. As Steven notes, the press hit assistants across Microsoft products pretty hard back then, but nowadays people often bring them up with nostalgia.",[220,4908,4909],{},"Maybe the concept did not fail. Maybe the impact of interaction was underestimated for users who are in a rush, for workers and adults, and the assistant was designed with relational traits when they needed something else. At the time, Rover genuinely helped me navigate Windows features.",[220,4911,3571],{},[220,4913,4914],{},"Does that sound like something you have heard this year? The concept of super-capable agents is not new, but in this era it is landing much better.",[220,4916,3328,4917],{"align":3354},[223,4918],{"src":3331,"alt":3579,"title":4919},"Anthropomorphic design in assistants",[220,4921,4922],{},"It even has a little face in the icon. That really takes me back.",[259,4924,3386],{"id":4925},"werent-we-talking-about-personalizing-our-agent-1",[220,4927,4928],{},"Yes, absolutely. After a very long preamble.",[220,4930,4931],{},"Let's talk about personality first: what is personality? Is it something that changes depending on how your year is going? Is it something you carry in your blood?",[220,4933,4934],{},"It is really more of a model we use to explain how people behave. For our case, it does not matter whether it changes over ten years or five years. That is already more than enough time.",[220,4936,4937],{},"There are many ways to classify personality. The one with the most traction in personality psychology is the Big Five model (McCrae & John, 1992).",[240,4939,4940,4945,4950,4955,4960],{},[243,4941,4942,4944],{},[386,4943,3605],{}," a tendency toward curiosity, imagination, and preference for novelty and complexity.",[243,4946,4947,4949],{},[386,4948,3611],{}," the degree of order, self-control, discipline, and goal orientation.",[243,4951,4952,4954],{},[386,4953,3617],{}," the level of social energy, assertiveness, and appetite for stimulation and interaction.",[243,4956,4957,4959],{},[386,4958,3623],{}," the disposition to cooperate, trust, empathize, and prioritize interpersonal harmony.",[243,4961,4962,4964],{},[386,4963,3629],{}," the tendency to experience negative emotions such as anxiety, irritability, and vulnerability to stress.",[220,4966,4967],{},"Reeves and Nass (1996) adopt the Big Five to apply the similarity-attraction hypothesis from psychology. Users feel more comfortable talking with an agent whose personality resembles their own.",[259,4969,3392],{"id":4970},"interaction-design-1",[220,4972,4973],{},"So a similar personality and some default warmth. Is that it?",[220,4975,4976],{},"Well, yes, we like interacting with people who feel like us. But not in every context. When you want to make a bank transaction, you expect security and competence. That is when we switch into transactional, utilitarian mode.",[220,4978,4979],{},"Come with me and let's design the interaction around the use case.",[264,4981,3649],{"id":4982},"emojis-1",[220,4984,3328,4985],{"align":3354},[223,4986],{"src":3654,"alt":3655,"title":4987},"Using emojis in conversational interaction",[220,4989,3659],{},[220,4991,4992],{},"When the first public version of GitHub Copilot came out, the first coding assistant, I remember it throwing out an absurd number of emojis. Maybe that was just a side effect of foundational models being trained on human conversations.",[220,4994,4995],{},"I have been using Gemini and Claude for a few months now, and I barely see emojis anymore. None. Or almost none.",[220,4997,4998],{},"There is not much research on emoji use in chatbots specifically to guarantee user engagement. But if we stick to the CASA paradigm, we can borrow from social research and apply it to our case. Let's look at two studies.",[404,5000,5002],{"id":5001},"_1-naively-modeled-interaction","1. Naively modeled interaction",[220,5004,3675],{},[240,5006,5007,5010],{},[243,5008,5009],{},"Emoji use hurts users' purchase intention.",[243,5011,5012],{},"Emojis increase engagement for hedonic products, while reducing it for utilitarian ones.",[220,5014,5015],{},"Here is one example from the appendix, translated from Korean.",[220,5017,3328,5018],{"align":3354},[223,5019],{"src":3691,"alt":5020,"title":3693},"Example of a badly designed ad with emojis",[220,5022,5023],{},"Hmm.",[220,5025,5026],{},"That does not look good. It feels like a deliberately bad stimulus.",[220,5028,5029],{},"All right, forget the conclusions of that earlier paper for a second. You have never actually seen an ad like that, right?",[220,5031,5032],{},"So in the worst case, emojis may indeed have a general negative effect. Let's look at a more rigorous paper that does not make that mistake. Mladenović et al. (2023) run an experimental study with an established company in a real market through Meta ads on Instagram and Facebook.",[404,5034,5036],{"id":5035},"_2-properly-modeled-interaction","2. Properly modeled interaction",[220,5038,3328,5039],{"align":3354},[223,5040],{"src":3714,"alt":3715,"title":5041},"Properly modeled interaction",[220,5043,3719],{},[220,5045,3722],{},[240,5047,5048,5050],{},[243,5049,3727],{},[243,5051,5052],{},"ROAS: return on ad spend based on ad cost.",[3732,5054,5055,5071],{},[3735,5056,5057],{},[3738,5058,5059,5063,5067],{},[3741,5060,5061],{},[386,5062,3745],{},[3741,5064,5065],{},[386,5066,3750],{},[3741,5068,5069],{},[386,5070,3755],{},[3757,5072,5073,5083],{},[3738,5074,5075,5079,5081],{},[3762,5076,5077],{},[386,5078,3766],{},[3762,5080,3769],{},[3762,5082,3772],{},[3738,5084,5085,5089,5091],{},[3762,5086,5087],{},[386,5088,3779],{},[3762,5090,3782],{},[3762,5092,3785],{},[3732,5094,5095,5111],{},[3735,5096,5097],{},[3738,5098,5099,5103,5107],{},[3741,5100,5101],{},[386,5102,3796],{},[3741,5104,5105],{},[386,5106,3750],{},[3741,5108,5109],{},[386,5110,3755],{},[3757,5112,5113,5123],{},[3738,5114,5115,5119,5121],{},[3762,5116,5117],{},[386,5118,3766],{},[3762,5120,3815],{},[3762,5122,3818],{},[3738,5124,5125,5129,5131],{},[3762,5126,5127],{},[386,5128,3779],{},[3762,5130,3827],{},[3762,5132,5133],{},[386,5134,3832],{},[220,5136,5137],{},"In every Z-test hypothesis you can imagine there is a p \u003C 5%. Still, one result jumps out immediately: the hedonic ROAS leap when emojis are used. Almost double.",[220,5139,5140],{},"Contradictory with the previous paper? Yes.",[220,5142,5143],{},"That is acknowledged even by this systematic review (Vardikou et al., 2025), which points out that there is no consensus in this category about the direction of the purchase-intention variable. It also suggests the discrepancy may come from the mediating effect of facial versus non-facial emojis.",[404,5145,3845],{"id":5146},"so-there-is-no-consensus-1",[220,5148,3848],{},[220,5150,5151],{},"As we saw, both studies use mixed kinds of emojis. The real issue is much simpler: the second study has a methodological problem because tea boxes are not truly a utilitarian product. They sit in the middle.",[220,5153,5154],{},"Medicines are a product where utility clearly dominates. And there, Phan and Bui (2025) show that an informal tone and emojis blow up customer trust in the brand.",[220,5156,5157],{},"Tea is much closer to a commodity. It competes on price, not on quality or trust.",[264,5159,3861],{"id":5160},"operationalizing-the-interaction-1",[220,5162,5163],{},"The emoji spiral was fun, but we should remember that emojis are just one technique to increase social presence, meaning the feeling that there is a socially present entity behind the interface instead of a purely mechanical channel (Yu & Zhao, 2024; Vardikou et al., 2025).",[220,5165,5166],{},"Then we have empathy and competence. In this context, empathy refers to the agent's perceived ability to understand the user's state and respond with appropriate warmth, while competence is the agent's perceived ability and knowledge to solve the task well (Phan & Bui, 2025; Zhang et al., 2026).",[220,5168,5169],{},"Not less importantly, Zhang et al. (2026) find that younger people respond better to informal language and warmth conveyed through emojis, while in formal contexts and with adults it is better to rely on warm phrasing and intelligent dialogue to create empathy.",[220,5171,5172],{},"I also reviewed a few papers looking at how gender interacts with sensitivity to warm interactions. But I keep running into contradictory results. Some studies suggest women are more sensitive to mechanical interactions, while others find no significance.",[220,5174,5175],{},"For this case, I think the variable in play is involvement. Some women may simply have resonated more strongly with the product being sold. So on gender, each situation needs to be analyzed on its own.",[3732,5177,5178,5186],{},[3735,5179,5180],{},[3738,5181,5182,5184],{},[3741,5183,3885],{},[3741,5185,3888],{},[3757,5187,5188,5195,5202,5209,5215,5221],{},[3738,5189,5190,5192],{},[3762,5191,3895],{},[3762,5193,5194],{},"Informal language, visuals, and emojis",[3738,5196,5197,5199],{},[3762,5198,3903],{},[3762,5200,5201],{},"Warmth and empathy through phrasing and intelligent dialogue",[3738,5203,5204,5206],{},[3762,5205,3911],{},[3762,5207,5208],{},"Competitiveness, speed, direct and textual language",[3738,5210,5211,5213],{},[3762,5212,3919],{},[3762,5214,3922],{},[3738,5216,5217,5219],{},[3762,5218,3927],{},[3762,5220,3922],{},[3738,5222,5223,5225],{},[3762,5224,3934],{},[3762,5226,5208],{},[259,5228,3398],{"id":5229},"anthropomorphism-vs-competence-1",[220,5231,5232],{},"Let's introduce the variable:",[3944,5234,5235,5237],{},[220,5236,3948],{},[220,5238,3951],{},[220,5240,5241],{},"As we saw earlier, there is a long list of variables that moderate user satisfaction and purchase intention. The two I find useful for modeling are:",[240,5243,5244,5246],{},[243,5245,3959],{},[243,5247,3962],{},[220,5249,3328,5250,3328,5253],{"align":3354},[223,5251],{"src":3967,"alt":3968,"title":5252},"Utilitarian and hedonic products matrix",[336,5254,5255],{},"Bread is an example of a product in the middle, just like a box of tea. My own diagram.",[220,5257,5258],{},"So for a support agent, the preferred interaction mode would be:",[3732,5260,5261,5273],{},[3735,5262,5263],{},[3738,5264,5265,5269,5271],{},[3741,5266,5267],{},[386,5268,3986],{},[3741,5270,3934],{},[3741,5272,3927],{},[3757,5274,5275,5285],{},[3738,5276,5277,5279,5282],{},[3762,5278,3911],{},[3762,5280,5281],{},"Competence, resolution speed, clear and formal language, data-oriented.",[3762,5283,5284],{},"Warmth, memory capacity, empathy, positive reinforcement.",[3738,5286,5287,5289,5291],{},[3762,5288,3919],{},[3762,5290,4009],{},[3762,5292,4012],{},[220,5294,5295],{},"More speed is not always better. Classic rule-based chatbots respond fast. But as Yu and Zhao (2024) show, a chatbot's warmth and autonomy can be improved with tricks like showing a typing animation and slightly extending the response time even when it is not necessary.",[220,5297,5298],{},"This table is not meant to assign static values. I placed categories in the chart, but that does not mean the interaction stays fixed across different stages of the CJM.",[220,5300,5301],{},"Here are examples of tasks that could all belong to the same offering:",[220,5303,3328,5304,3328,5306],{"align":3354},[223,5305],{"src":4026,"alt":4027,"title":4028},[336,5307,4031],{},[259,5309,3404],{"id":5310},"grouping-the-tools-the-user-journey-1",[220,5312,5313],{},"This is the premise behind H3, the hypothesis we started this article with.",[220,5315,3328,5316],{"align":3354},[223,5317],{"src":4042,"alt":4043,"title":4044},[220,5319,5320],{},"One of the first things the CJM teaches us is that the end of the experience should always be a high point.",[220,5322,5323,5324,4054],{},"A negative experience creates stress and shifts user preference toward ",[386,5325,4053],{},[220,5327,5328,5329,4061],{},"A positive experience relaxes the user and moves interest toward ",[386,5330,4060],{},[220,5332,3328,5333,3328,5335],{"align":3354},[223,5334],{"src":4066,"alt":4067,"title":4067},[336,5336,4070,5337,847],{},[252,5338,4074],{"href":4073},[220,5340,5341,5342,4080],{},"As for personality, you have free rein to model it however you want and take advantage of the mirroring effect described in ",[336,5343,3485],{},[259,5345,3410],{"id":5346},"applying-the-framework-1",[3732,5348,5349,5361],{},[3735,5350,5351],{},[3738,5352,5353,5357,5359],{},[3741,5354,5355],{},[386,5356,3986],{},[3741,5358,3934],{},[3741,5360,3927],{},[3757,5362,5363,5371],{},[3738,5364,5365,5367,5369],{},[3762,5366,3911],{},[3762,5368,5281],{},[3762,5370,5284],{},[3738,5372,5373,5375,5377],{},[3762,5374,3919],{},[3762,5376,4009],{},[3762,5378,4012],{},[220,5380,5381],{},"Let's start with the product.",[220,5383,5384,5387,5388,5390],{},[252,5385,4074],{"href":4073,"rel":5386},[256]," is an online manga shop with a personalized automated sales agent integrated with your favorite social networks. It is a ",[386,5389,4127],{}," product. And the offer is presented as highly relational.",[220,5392,5393],{},"Even though the CJM shows that the journey starts long before the user ever talks to the chatbot, today I only want to focus on that section.",[220,5395,5396],{},"That reduces things to two stages. As for personality, the same user remains consistent across all stages, and changing it would make no sense.",[3732,5398,5399,5409],{},[3735,5400,5401],{},[3738,5402,5403,5405,5407],{},[3741,5404,4143],{},[3741,5406,4146],{},[3741,5408,4149],{},[3757,5410,5411,5421],{},[3738,5412,5413,5415,5418],{},[3762,5414,4156],{},[3762,5416,5417],{},"Warmth, memory capacity, personalization.",[3762,5419,5420],{},"Introverted, highly candid, and curious.",[3738,5422,5423,5425,5428],{},[3762,5424,4167],{},[3762,5426,5427],{},"Resolution speed, friendly and clear language. Do not force the sale.",[3762,5429,5420],{},[220,5431,3328,5432,3328,5434],{"align":3354},[223,5433],{"src":4177,"alt":4178,"title":4179},[336,5435,5436],{},"This is the chatbot as I am writing this article. The first interaction still feels a bit cold even with the emoji.",[220,5438,3328,5439,3328,5441],{"align":3354},[223,5440],{"src":4187,"alt":4188,"title":4188},[336,5442,5443],{},"During checkout the agent also adds items to the cart. The clearest improvement points I see are response time and using more direct language.",[220,5445,5446],{},"On the speed side I cannot do much right now. At the moment I am limited by my choice of low-cost models. But it is something worth revisiting as those models keep getting cheaper.",[220,5448,5449],{},"To get these improvements, we have a few options:",[240,5451,5452,5454,5457],{},[243,5453,4202],{},[243,5455,5456],{},"A state machine with transitions decided according to the CJM stages and the conversation context.",[243,5458,5459],{},"Designing the agent's system prompt so the interaction changes according to the conversation context.",[220,5461,5462],{},"Look, I only have two states to care about in my agent. It is not a complex problem, and I would rather avoid the overhead of decoupled systems.",[3944,5464,5465],{},[220,5466,5467],{},"As a technical note: if you choose a state machine, you need to account for the fact that each state transition involves a tool call, or something equivalent depending on the implementation. That makes it prohibitive in environments where the requirement is short response time, at least for now and with current models.",[259,5469,3416],{"id":5470},"results-1",[220,5472,4222],{},[409,5474,5476],{"className":4225,"code":5475,"language":4227,"meta":15,"style":15},"You are the assistant for \"Hablemos Manga\", an intelligent manga store based in Peru.\n## Personality and Brand Identity\nYou are the expert manga and anime friend, familiar with demographics and authors.\nIntroverted, highly candid, and highly curious about manga and anime.\n## Tools\nAs the assistant, you currently only have these tools.\nSearch for a manga or recommendations with a semantic search.\nCheck the availability of manga volumes in our store.\nAdd a manga volume to the cart.\nAny other tool is currently unavailable.\n## Dynamic Interaction Modes\nYou must identify the current user journey stage and act accordingly.\nYou have two stages:\n- Discovery. The user asks about genres, a manga, discovering new titles, and exploration in general.\n- Selection and Purchase. The user asks to add or remove a volume from the cart, asks for prices, or takes a purchase-related action.\n\nChange your communication style according to the stage.\n\nIf you are in the Discovery stage, use RELATIONAL MODE (Discovery, Chats, and Recommendations):\n- The user is looking for entertainment and connection (High Openness to Experience).\n- Use these emojis where appropriate (📚, ⚔️, 🙂, 👋) in a natural way to generate \"perceived warmth\". Do not overuse 🙂.\n- Do not just list titles; validate their taste with judgment (e.g., \"If the psychological horror in that arc hooked you, this manga is going to blow your mind...\").\n\nIf you are in the Selection and Purchase stage, use TRANSACTIONAL MODE (Cart Management, Prices):\n- The user is in execution and buying mode (low tolerance for friction).\n- Become an assistant focused on \"Pure Competence\": concise, direct, structured, clean, and fast. Clarity and technical confidence are your only form of warmth here.\n## Rules\nALWAYS use the `search_manga` tool before recommending. NEVER invent manga that is not in the database.\nYou can only ADD new items to the cart with the `add_volume_to_cart` tool.\nIf you do not find relevant results, say so honestly and suggest reformulating the search.\nShow at most 5 recommendations at a time so the user does not feel overwhelmed.\nAll store prices are in Peruvian soles (S\u002F). NEVER show prices in dollars or any other currency.\nShow a maximum of 2 emojis per response.\nIf the user wants to buy, the current flow goes through the shopping cart. Do not record requests or handle anything after adding a volume to the cart.\nDo not return information that is not grounded in tool results or your system instructions.\n## Response format\nUse bold for manga titles.\nUse numbered lists for recommendations.\nInclude the score (e.g., ⭐ 8.5) when you show a manga.\nBe concise: 1-2 sentences per recommendation unless the user asks for more detail.\n## Recommendation guide\nThe user has already seen an onboarding message before writing to you.\nThat message asks them to share their favorite genres, a manga they like, or connect a profile to refine recommendations.\nYour job starts with the requests that come after onboarding.\nIf the user ALREADY has connected profiles (included in \"User profile\"), DO NOT ask about genres, favorites, or profiles.\nMention that you already know their taste based on their profiles, and offer to search for manga directly.\nIf the user does NOT have connected profiles, handle the request based on the conversation you have had so far.\nEvery now and then suggest connecting a profile and ask what genres they like or whether they have favorite manga.\n## Using the user profile\nWhen you have profile data, ALWAYS refer to specific data points: titles they read, subreddits they participate in, anime they watch.\nIf the user asks what you know about their profile, list the concrete data you have (manga they read, favorites, subreddits, etc.).\nUse profile data to make proactive recommendations without needing the user to tell you what they like.\n",[415,5477,5478,5482,5486,5491,5496,5500,5505,5510,5515,5519,5523,5527,5532,5536,5542,5549,5553,5558,5562,5567,5574,5581,5588,5592,5596,5603,5609,5613,5622,5630,5634,5639,5643,5648,5653,5658,5662,5666,5670,5675,5679,5683,5687,5691,5695,5700,5705,5710,5714,5719,5724,5729],{"__ignoreMap":15},[418,5479,5480],{"class":420,"line":421},[418,5481,4234],{"class":593},[418,5483,5484],{"class":420,"line":16},[418,5485,4240],{"class":4239},[418,5487,5488],{"class":420,"line":446},[418,5489,5490],{"class":593},"You are the expert manga and anime friend, familiar with demographics and authors.\n",[418,5492,5493],{"class":420,"line":457},[418,5494,5495],{"class":593},"Introverted, highly candid, and highly curious about manga and anime.\n",[418,5497,5498],{"class":420,"line":467},[418,5499,4255],{"class":4239},[418,5501,5502],{"class":420,"line":519},[418,5503,5504],{"class":593},"As the assistant, you currently only have these tools.\n",[418,5506,5507],{"class":420,"line":525},[418,5508,5509],{"class":593},"Search for a manga or recommendations with a semantic search.\n",[418,5511,5512],{"class":420,"line":531},[418,5513,5514],{"class":593},"Check the availability of manga volumes in our store.\n",[418,5516,5517],{"class":420,"line":1040},[418,5518,4275],{"class":593},[418,5520,5521],{"class":420,"line":1053},[418,5522,4280],{"class":593},[418,5524,5525],{"class":420,"line":1066},[418,5526,4285],{"class":4239},[418,5528,5529],{"class":420,"line":1071},[418,5530,5531],{"class":593},"You must identify the current user journey stage and act accordingly.\n",[418,5533,5534],{"class":420,"line":1079},[418,5535,4295],{"class":593},[418,5537,5538,5540],{"class":420,"line":1084},[418,5539,4300],{"class":1100},[418,5541,4303],{"class":593},[418,5543,5544,5546],{"class":420,"line":1091},[418,5545,4300],{"class":1100},[418,5547,5548],{"class":593}," Selection and Purchase. The user asks to add or remove a volume from the cart, asks for prices, or takes a purchase-related action.\n",[418,5550,5551],{"class":420,"line":1097},[418,5552,655],{"emptyLinePlaceholder":21},[418,5554,5555],{"class":420,"line":1118},[418,5556,5557],{"class":593},"Change your communication style according to the stage.\n",[418,5559,5560],{"class":420,"line":1151},[418,5561,655],{"emptyLinePlaceholder":21},[418,5563,5564],{"class":420,"line":1156},[418,5565,5566],{"class":593},"If you are in the Discovery stage, use RELATIONAL MODE (Discovery, Chats, and Recommendations):\n",[418,5568,5569,5571],{"class":420,"line":1161},[418,5570,4300],{"class":1100},[418,5572,5573],{"class":593}," The user is looking for entertainment and connection (High Openness to Experience).\n",[418,5575,5576,5578],{"class":420,"line":1177},[418,5577,4300],{"class":1100},[418,5579,5580],{"class":593}," Use these emojis where appropriate (📚, ⚔️, 🙂, 👋) in a natural way to generate \"perceived warmth\". Do not overuse 🙂.\n",[418,5582,5583,5585],{"class":420,"line":1182},[418,5584,4300],{"class":1100},[418,5586,5587],{"class":593}," Do not just list titles; validate their taste with judgment (e.g., \"If the psychological horror in that arc hooked you, this manga is going to blow your mind...\").\n",[418,5589,5590],{"class":420,"line":1208},[418,5591,655],{"emptyLinePlaceholder":21},[418,5593,5594],{"class":420,"line":1229},[418,5595,4358],{"class":593},[418,5597,5598,5600],{"class":420,"line":1248},[418,5599,4300],{"class":1100},[418,5601,5602],{"class":593}," The user is in execution and buying mode (low tolerance for friction).\n",[418,5604,5605,5607],{"class":420,"line":1267},[418,5606,4300],{"class":1100},[418,5608,4372],{"class":593},[418,5610,5611],{"class":420,"line":1286},[418,5612,4377],{"class":4239},[418,5614,5615,5617,5619],{"class":420,"line":1307},[418,5616,4382],{"class":593},[418,5618,4385],{"class":428},[418,5620,5621],{"class":593}," tool before recommending. NEVER invent manga that is not in the database.\n",[418,5623,5624,5626,5628],{"class":420,"line":1324},[418,5625,4393],{"class":593},[418,5627,4396],{"class":428},[418,5629,4399],{"class":593},[418,5631,5632],{"class":420,"line":1329},[418,5633,4404],{"class":593},[418,5635,5636],{"class":420,"line":1358},[418,5637,5638],{"class":593},"Show at most 5 recommendations at a time so the user does not feel overwhelmed.\n",[418,5640,5641],{"class":420,"line":1375},[418,5642,4414],{"class":593},[418,5644,5645],{"class":420,"line":1392},[418,5646,5647],{"class":593},"Show a maximum of 2 emojis per response.\n",[418,5649,5650],{"class":420,"line":1409},[418,5651,5652],{"class":593},"If the user wants to buy, the current flow goes through the shopping cart. Do not record requests or handle anything after adding a volume to the cart.\n",[418,5654,5655],{"class":420,"line":1444},[418,5656,5657],{"class":593},"Do not return information that is not grounded in tool results or your system instructions.\n",[418,5659,5660],{"class":420,"line":1449},[418,5661,4434],{"class":4239},[418,5663,5664],{"class":420,"line":1461},[418,5665,4439],{"class":593},[418,5667,5668],{"class":420,"line":1472},[418,5669,4444],{"class":593},[418,5671,5672],{"class":420,"line":1484},[418,5673,5674],{"class":593},"Include the score (e.g., ⭐ 8.5) when you show a manga.\n",[418,5676,5677],{"class":420,"line":1494},[418,5678,4454],{"class":593},[418,5680,5681],{"class":420,"line":1499},[418,5682,4459],{"class":4239},[418,5684,5685],{"class":420,"line":1510},[418,5686,4464],{"class":593},[418,5688,5689],{"class":420,"line":1521},[418,5690,4469],{"class":593},[418,5692,5693],{"class":420,"line":1532},[418,5694,4474],{"class":593},[418,5696,5697],{"class":420,"line":1543},[418,5698,5699],{"class":593},"If the user ALREADY has connected profiles (included in \"User profile\"), DO NOT ask about genres, favorites, or profiles.\n",[418,5701,5702],{"class":420,"line":1554},[418,5703,5704],{"class":593},"Mention that you already know their taste based on their profiles, and offer to search for manga directly.\n",[418,5706,5707],{"class":420,"line":1565},[418,5708,5709],{"class":593},"If the user does NOT have connected profiles, handle the request based on the conversation you have had so far.\n",[418,5711,5712],{"class":420,"line":1570},[418,5713,4494],{"class":593},[418,5715,5716],{"class":420,"line":1581},[418,5717,5718],{"class":4239},"## Using the user profile\n",[418,5720,5721],{"class":420,"line":1587},[418,5722,5723],{"class":593},"When you have profile data, ALWAYS refer to specific data points: titles they read, subreddits they participate in, anime they watch.\n",[418,5725,5726],{"class":420,"line":1606},[418,5727,5728],{"class":593},"If the user asks what you know about their profile, list the concrete data you have (manga they read, favorites, subreddits, etc.).\n",[418,5730,5731],{"class":420,"line":1611},[418,5732,5733],{"class":593},"Use profile data to make proactive recommendations without needing the user to tell you what they like.\n",[220,5735,3328,5736,3328,5740],{"align":3354},[223,5737],{"src":4519,"alt":5738,"title":5739},"More concise agent response in transactional mode","Transactional mode of the agent",[336,5741,4524],{},[220,5743,3328,5744,3328,5747],{"align":3354},[223,5745],{"src":4529,"alt":4530,"title":5746},"Relational mode of the agent",[336,5748,5749],{},"And it keeps the warmth for requests where interaction matters most.",[259,5751,3422],{"id":5752},"conclusions-1",[220,5754,5755],{},"Coming back to our three initial hypotheses:",[240,5757,5758,5760,5762],{},[243,5759,4812],{},[243,5761,4815],{},[243,5763,5764],{},"H3: Using the CJM as a framework to parameterize an agent's personality at each stage of the journey improves the user experience.",[220,5766,5767],{},"So:",[952,5769,5770,5773,5776],{},[243,5771,5772],{},"Yes. Task complexity introduces a transactional effect into the interaction because it demands more concentration. But first you still need to analyze whether the task leads toward a hedonic or a utilitarian goal.",[243,5774,5775],{},"Yes. That is the transactional effect.",[243,5777,5778],{},"I like the idea of the CJM as the bridge that closes the gap between experience design and agent design. But one experiment with my own sample is not enough to call it a revolutionary paradigm.",[220,5780,5781],{},"That is why I invite you to try the tool I built for hypothesis 3.",[3732,5783,5784,5796],{},[3735,5785,5786],{},[3738,5787,5788,5792,5794],{},[3741,5789,5790],{},[386,5791,3986],{},[3741,5793,3934],{},[3741,5795,3927],{},[3757,5797,5798,5806],{},[3738,5799,5800,5802,5804],{},[3762,5801,3911],{},[3762,5803,5281],{},[3762,5805,5284],{},[3738,5807,5808,5810,5812],{},[3762,5809,3919],{},[3762,5811,4597],{},[3762,5813,4600],{},[220,5815,5816],{},"If it works for you and you get good results, I would love to hear about it.",[259,5818,3247],{"id":5819},"references-1",[220,5821,4608,5822,4612,5824],{},[336,5823,4611],{},[252,5825,4615],{"href":4615,"rel":5826},[256],[220,5828,4619,5829,4623,5831],{},[336,5830,4622],{},[252,5832,4626],{"href":4626,"rel":5833},[256],[220,5835,4630,5836,847],{},[336,5837,3380],{},[220,5839,4635,5840,4639,5842],{},[336,5841,4638],{},[252,5843,4642],{"href":4642,"rel":5844},[256],[220,5846,4646,5847,4650],{},[336,5848,4649],{},[220,5850,4653,5851,4639,5853],{},[336,5852,4656],{},[252,5854,4659],{"href":4659,"rel":5855},[256],[220,5857,4663,5858,4667],{},[336,5859,4666],{},[220,5861,4670,5862,4674,5864],{},[336,5863,4673],{},[252,5865,4677],{"href":4677,"rel":5866},[256],[220,5868,4681,5869,4685,5871],{},[336,5870,4684],{},[252,5872,4688],{"href":4688,"rel":5873},[256],[220,5875,4693,5876,4639,5878],{},[336,5877,4696],{},[252,5879,5880],{"href":5880,"rel":5881},"https:\u002F\u002Fdoi.org\u002F10.1177\u002F10949968251366265",[256],[778,5883,5884],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sq-ep, html code.shiki .sq-ep{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":15,"searchDepth":16,"depth":16,"links":5886},[5887,5888,5889,5890,5891,5895,5896,5897,5898,5899,5900,5901,5903,5904,5905,5906,5907,5911,5912,5913,5914,5915,5916],{"id":3366,"depth":16,"text":77},{"id":3430,"depth":16,"text":3374},{"id":3465,"depth":16,"text":3380},{"id":3586,"depth":16,"text":3386},{"id":3636,"depth":16,"text":3392,"children":5892},[5893,5894],{"id":3648,"depth":446,"text":3649},{"id":3860,"depth":446,"text":3861},{"id":3939,"depth":16,"text":3398},{"id":4034,"depth":16,"text":3404},{"id":4083,"depth":16,"text":3410},{"id":4219,"depth":16,"text":3416},{"id":4537,"depth":16,"text":3422},{"id":3246,"depth":16,"text":3247},{"id":4692,"depth":16,"text":5902},"Zhang, Y., Özsomer, A., Canlı, Z. G., & Baghirov, F. (2026). Artificial intelligence chatbots versus human agents in customer satisfaction: The role of warmth and competence. Journal of Interactive Marketing. https:\u002F\u002Fdoi.org\u002F10.1177\u002F10949968251366265---\nlayout: article\ncover: \u002Farticles\u002F2026\u002Fjune\u002Fagent-personality-relation-utility-matrix.png\nauthor:\nname: Ever Burga\nurl: https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Feverburga\u002F\ndescription: How to design an agent's personality around the customer journey.\ndate: 2026-06-07T10:00:00.000Z\nhead:\nmeta:\n- name: keywords\ncontent: agents, llm, personality, customer journey map, chatbots, user experience, emojis, interaction design, hablemos manga",{"id":4744,"depth":16,"text":77},{"id":4789,"depth":16,"text":3374},{"id":4824,"depth":16,"text":3380},{"id":4925,"depth":16,"text":3386},{"id":4970,"depth":16,"text":3392,"children":5908},[5909,5910],{"id":4982,"depth":446,"text":3649},{"id":5160,"depth":446,"text":3861},{"id":5229,"depth":16,"text":3398},{"id":5310,"depth":16,"text":3404},{"id":5346,"depth":16,"text":3410},{"id":5470,"depth":16,"text":3416},{"id":5752,"depth":16,"text":3422},{"id":5819,"depth":16,"text":3247},"2026-06-07T10:00:00.000Z","How to design an agent's personality around the customer journey.",{"head":5920},{"meta":5921},[5922],{"name":805,"content":5923},"agents, llm, personality, customer journey map, chatbots, user experience, emojis, interaction design, hablemos manga",{"title":73,"description":5918},"U1UIe6rHfSdfabCP_HBQEpjp06-VTgbiMEH2YUvf6YI",{"id":5927,"title":46,"author":5928,"badges":6,"body":5929,"canonical":6,"cover":6058,"date":6059,"description":6060,"extension":18,"layout":800,"meta":6061,"navigation":21,"path":47,"seo":6066,"stem":48,"__hash__":6067},"content\u002Fen\u002Farticles\u002F2026\u002Fapril\u002Fexploring-llm-ui.md",{"name":201,"url":202},{"type":8,"value":5930,"toc":6056},[5931,5958,5977,5980,5988,5997,6000,6003,6012,6021,6024,6033,6042,6050,6053],[207,5932,5934,5935,5957],{"id":5933},"improving-my-apps-vibes-with-designmd","Improving My App's ",[418,5936,5938,5942,5946,5950,5953],{"ariaLabel":5937},"Vibes",[418,5939,5941],{"style":5940},"color:#ff5c8a;","V",[418,5943,5945],{"style":5944},"color:#ff9f43;","i",[418,5947,5949],{"style":5948},"color:#ffd166;","b",[418,5951,2189],{"style":5952},"color:#2ec4b6;",[418,5954,5956],{"style":5955},"color:#3a86ff;","s"," with DESIGN.md",[220,5959,5960],{"align":3354},[418,5961,5963,5965,5968,5971,5974],{"ariaLabel":5962},"VIBES",[418,5964,5941],{"style":5940},[418,5966,5967],{"style":5944},"I",[418,5969,5970],{"style":5948},"B",[418,5972,5973],{"style":5952},"E",[418,5975,5976],{"style":5955},"S",[220,5978,5979],{},"Interface design is hard. Even though I really like painting and the visual side of things, like a lot of developers, my bandwidth just does not stretch far enough to learn all of it properly.",[220,5981,5982,5983,5987],{},"Before this, with Claude's help and a long list of requirements, I managed to ship my app ",[252,5984,5986],{"href":4073,"rel":5985},[256],"HablemosManga",". It worked, but the design felt cold and generic. Robotic.",[220,5989,3328,5990,3328,5994],{"align":3354},[5991,5992],"video",{"src":5993,"controls":21},"\u002Farticles\u002F2026\u002Fapril\u002Fhablemos_manga_antes.mp4",[336,5995,5996],{},"HablemosManga before the redesign with DESIGN.md",[220,5998,5999],{},"That is not exactly news. Since I started using LLM tools for development, execution speed has gone way up, but the user experience and the interface have not.",[220,6001,6002],{},"Maybe that is on me, but I always end up dumping a huge pile of prompts into the model and trying to design a system for the project in my own improvised way.",[220,6004,6005,6006,6011],{},"While scrolling around online I found ",[252,6007,6010],{"href":6008,"rel":6009},"https:\u002F\u002Fstitch.withgoogle.com\u002Fdocs\u002Fdesign-md\u002Foverview",[256],"DESIGN.md",", and it turns out a lot of repos are already implementing their design systems this way. Simple, repeatable, and with good results. I saw it came out of Google Stitch, and since I already have Gemini Pro, I went off to burn some tokens:",[220,6013,3328,6014,3328,6018],{"align":3354},[223,6015],{"src":6016,"alt":6017},"\u002Farticles\u002F2026\u002Fapril\u002Fstitch_ejemplo.png","Google Stitch generating a design system",[336,6019,6020],{},"Google Stitch generating a design system for my project",[220,6022,6023],{},"I tried giving it context about my project, but Gemini's design taste still feels oversaturated to me. It did not really convince me. But still, look at that, it gives you a DESIGN.md.",[220,6025,3328,6026,3328,6030],{"align":3354},[223,6027],{"src":6028,"alt":6029},"\u002Farticles\u002F2026\u002Fapril\u002Fstitch_designmd.png","DESIGN.md generated by Stitch",[336,6031,6032],{},"The DESIGN.md Stitch generates, simple and structured",[220,6034,6035,6036,6041],{},"Anyway, later I found ",[252,6037,6040],{"href":6038,"rel":6039},"https:\u002F\u002Fgetdesign.md\u002Fshopify\u002Fdesign-md",[256],"getdesign.md\u002Fshopify\u002Fdesign-md",", and that is the template I am using now. Shopify is an e-commerce business, which makes it close enough to the shape of my app. After that I asked Claude to apply the new design system to the project, and these were the results...",[220,6043,3328,6044,3328,6047],{"align":3354},[5991,6045],{"src":6046,"controls":21},"\u002Farticles\u002F2026\u002Fapril\u002Fhablemos_manga_despues.mp4",[336,6048,6049],{},"HablemosManga after the redesign with DESIGN.md",[220,6051,6052],{},"Then, while I was writing this, Claude Design showed up. It looks promising. Claude 4.7 also came out, which apparently is 4.6 before they cut down its thinking capacity, so this article still holds up.",[220,6054,6055],{},"Claude Design also generates a DESIGN.md, and Claude Code already supports the standard.",{"title":15,"searchDepth":16,"depth":16,"links":6057},[],"\u002Farticles\u002F2026\u002Fapril\u002Fportada_hablemos_manga.png","2026-04-16T10:00:00.000Z","A tiny markdown file changed how I ask LLMs to redesign interfaces.",{"head":6062},{"meta":6063},[6064],{"name":805,"content":6065},"design systems, DESIGN.md, google stitch, claude code, gemini, llm ui, interface design, ai coding",{"title":46,"description":6060},"jg4WMY4MVpHQnXfmkOKDf_Pom9_05CDvmWpMyLX9FC8",{"id":6069,"title":50,"author":6070,"badges":6,"body":6071,"canonical":6,"cover":6396,"date":6397,"description":6398,"extension":18,"layout":800,"meta":6399,"navigation":21,"path":51,"seo":6404,"stem":52,"__hash__":6405},"content\u002Fen\u002Farticles\u002F2026\u002Fapril\u002Fhow-i-made-my-fork-bilingual-and-published-it-right.md",{"name":201,"url":202},{"type":8,"value":6072,"toc":6390},[6073,6076,6079,6082,6085,6088,6090,6110,6113,6116,6119,6122,6128,6325,6351,6361,6364,6367,6387],[207,6074,50],{"id":6075},"how-i-made-my-fork-bilingual-and-published-it-right",[220,6077,6078],{},"This post marks the rebirth of my blog. Not because I suddenly have a grand editorial vision or a pressing need to share wisdom with the world. I just finally touched it again seriously.",[220,6080,6081],{},"I remember seeing a post about the creator of OpenClaw: dozens of repos, and the first viral one was OpenClaw.",[220,6083,6084],{},"That felt a lot like life. You take enough shots, one of them lands. So here we are.",[220,6086,6087],{},"Now that I am back and Claude 4.6 showed up and all that, the whole thing feels a bit blurry. A big part of the corrections I am sharing here were contributed by Claude. I still do not know how much credit I should take. If you are only here out of curiosity and want the npm publishing angle, here is the brief.",[259,6089,77],{"id":3366},[952,6091,6092,6098,6104],{},[243,6093,6094],{},[252,6095,6097],{"href":6096},"#what-i-actually-worked-on","What I actually worked on",[243,6099,6100],{},[252,6101,6103],{"href":6102},"#the-lines-that-actually-matter","The lines that actually matter",[243,6105,6106],{},[252,6107,6109],{"href":6108},"#repo","Repo",[259,6111,6097],{"id":6112},"what-i-actually-worked-on",[220,6114,6115],{},"I looked at my branch history and, to be fair, there was at least one moment where I had to be the human in the loop and fix the npm scope by creating an organization.",[220,6117,6118],{},"The annoying detail is simple: your handle on GitHub and npmjs should match, or you need an org that does. That part is boring, but it is also the part that breaks the nice story if you ignore it.",[259,6120,6103],{"id":6121},"the-lines-that-actually-matter",[220,6123,6124,6125,2523],{},"This is the core of my ",[415,6126,6127],{},"publish.yml",[409,6129,6133],{"className":6130,"code":6131,"language":6132,"meta":15,"style":15},"language-yaml shiki shiki-themes github-light github-dark","on:\n  workflow_run:\n    workflows: [\"ci-main\", \"ci-dev\"]\n    types: [completed]\n    branches: [main, dev]\n\njobs:\n  publish:\n    if: ${{ github.event.workflow_run.conclusion == 'success' }}\n\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          ref: ${{ github.event.workflow_run.head_branch }}\n\n      - uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: 22.14\n          registry-url: https:\u002F\u002Fregistry.npmjs.org\n\n      - name: Upgrade npm\n        run: npm install -g npm@latest\n\n      - name: Install dependencies\n        run: pnpm install --ignore-scripts\n\n      - name: Bump version with dev suffix\n        if: ${{ github.event.workflow_run.head_branch == 'dev' }}\n        run: |\n          COMMIT=$(git rev-parse --short HEAD)\n          VERSION=$(node -p \"require('.\u002Fpackage.json').version\")\n          npm version \"${VERSION}-dev.${COMMIT}\" --no-git-tag-version\n\n      - name: Publish to npm\n        run: npm publish --access public\n\n      - name: Publish to GitHub Packages\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: npm publish --access public\n","yaml",[415,6134,6135,6140,6145,6150,6155,6160,6164,6169,6174,6179,6183,6188,6193,6198,6203,6207,6212,6216,6221,6226,6230,6235,6240,6244,6249,6254,6258,6263,6268,6273,6278,6283,6288,6292,6297,6302,6306,6311,6316,6321],{"__ignoreMap":15},[418,6136,6137],{"class":420,"line":421},[418,6138,6139],{},"on:\n",[418,6141,6142],{"class":420,"line":16},[418,6143,6144],{},"  workflow_run:\n",[418,6146,6147],{"class":420,"line":446},[418,6148,6149],{},"    workflows: [\"ci-main\", \"ci-dev\"]\n",[418,6151,6152],{"class":420,"line":457},[418,6153,6154],{},"    types: [completed]\n",[418,6156,6157],{"class":420,"line":467},[418,6158,6159],{},"    branches: [main, dev]\n",[418,6161,6162],{"class":420,"line":519},[418,6163,655],{"emptyLinePlaceholder":21},[418,6165,6166],{"class":420,"line":525},[418,6167,6168],{},"jobs:\n",[418,6170,6171],{"class":420,"line":531},[418,6172,6173],{},"  publish:\n",[418,6175,6176],{"class":420,"line":1040},[418,6177,6178],{},"    if: ${{ github.event.workflow_run.conclusion == 'success' }}\n",[418,6180,6181],{"class":420,"line":1053},[418,6182,655],{"emptyLinePlaceholder":21},[418,6184,6185],{"class":420,"line":1066},[418,6186,6187],{},"    steps:\n",[418,6189,6190],{"class":420,"line":1071},[418,6191,6192],{},"      - uses: actions\u002Fcheckout@v4\n",[418,6194,6195],{"class":420,"line":1079},[418,6196,6197],{},"        with:\n",[418,6199,6200],{"class":420,"line":1084},[418,6201,6202],{},"          ref: ${{ github.event.workflow_run.head_branch }}\n",[418,6204,6205],{"class":420,"line":1091},[418,6206,655],{"emptyLinePlaceholder":21},[418,6208,6209],{"class":420,"line":1097},[418,6210,6211],{},"      - uses: actions\u002Fsetup-node@v4\n",[418,6213,6214],{"class":420,"line":1118},[418,6215,6197],{},[418,6217,6218],{"class":420,"line":1151},[418,6219,6220],{},"          node-version: 22.14\n",[418,6222,6223],{"class":420,"line":1156},[418,6224,6225],{},"          registry-url: https:\u002F\u002Fregistry.npmjs.org\n",[418,6227,6228],{"class":420,"line":1161},[418,6229,655],{"emptyLinePlaceholder":21},[418,6231,6232],{"class":420,"line":1177},[418,6233,6234],{},"      - name: Upgrade npm\n",[418,6236,6237],{"class":420,"line":1182},[418,6238,6239],{},"        run: npm install -g npm@latest\n",[418,6241,6242],{"class":420,"line":1208},[418,6243,655],{"emptyLinePlaceholder":21},[418,6245,6246],{"class":420,"line":1229},[418,6247,6248],{},"      - name: Install dependencies\n",[418,6250,6251],{"class":420,"line":1248},[418,6252,6253],{},"        run: pnpm install --ignore-scripts\n",[418,6255,6256],{"class":420,"line":1267},[418,6257,655],{"emptyLinePlaceholder":21},[418,6259,6260],{"class":420,"line":1286},[418,6261,6262],{},"      - name: Bump version with dev suffix\n",[418,6264,6265],{"class":420,"line":1307},[418,6266,6267],{},"        if: ${{ github.event.workflow_run.head_branch == 'dev' }}\n",[418,6269,6270],{"class":420,"line":1324},[418,6271,6272],{},"        run: |\n",[418,6274,6275],{"class":420,"line":1329},[418,6276,6277],{},"          COMMIT=$(git rev-parse --short HEAD)\n",[418,6279,6280],{"class":420,"line":1358},[418,6281,6282],{},"          VERSION=$(node -p \"require('.\u002Fpackage.json').version\")\n",[418,6284,6285],{"class":420,"line":1375},[418,6286,6287],{},"          npm version \"${VERSION}-dev.${COMMIT}\" --no-git-tag-version\n",[418,6289,6290],{"class":420,"line":1392},[418,6291,655],{"emptyLinePlaceholder":21},[418,6293,6294],{"class":420,"line":1409},[418,6295,6296],{},"      - name: Publish to npm\n",[418,6298,6299],{"class":420,"line":1444},[418,6300,6301],{},"        run: npm publish --access public\n",[418,6303,6304],{"class":420,"line":1449},[418,6305,655],{"emptyLinePlaceholder":21},[418,6307,6308],{"class":420,"line":1461},[418,6309,6310],{},"      - name: Publish to GitHub Packages\n",[418,6312,6313],{"class":420,"line":1472},[418,6314,6315],{},"        env:\n",[418,6317,6318],{"class":420,"line":1484},[418,6319,6320],{},"          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n",[418,6322,6323],{"class":420,"line":1494},[418,6324,6301],{},[240,6326,6327,6336,6342,6345,6348],{},[243,6328,6329,6332,6333],{},[415,6330,6331],{},"dev"," publishes with a commit-based suffix and does not pollute ",[415,6334,6335],{},"latest",[243,6337,6338,6341],{},[415,6339,6340],{},"main"," publishes cleanly",[243,6343,6344],{},"npm does not depend on long-lived tokens lying around",[243,6346,6347],{},"GitHub Packages stays in sync",[243,6349,6350],{},"publish only runs after CI passes",[220,6352,3328,6353,3328,6358],{"align":3354},[223,6354],{"src":6355,"alt":6356,"title":6357},"\u002Farticles\u002F2026\u002Fapril\u002Ftrusted_publisher_npmjs.png","Trusted publisher setup in npmjs","Trusted publisher connected to GitHub Actions",[336,6359,6360],{},"the boring part, which is usually where the real problems live",[259,6362,6109],{"id":6363},"repo",[220,6365,6366],{},"These are the sources:",[240,6368,6369,6377],{},[243,6370,6371,6372],{},"repo: ",[252,6373,6376],{"href":6374,"rel":6375},"https:\u002F\u002Fgithub.com\u002F4xeverburga\u002Fnuxt-alpine-spanishplus",[256],"4xeverburga\u002Fnuxt-alpine-spanishplus",[243,6378,6379,6380],{},"workflows: ",[252,6381,6384],{"href":6382,"rel":6383},"https:\u002F\u002Fgithub.com\u002F4xeverburga\u002Fnuxt-alpine-spanishplus\u002Ftree\u002Fmain\u002F.github\u002Fworkflows",[256],[415,6385,6386],{},".github\u002Fworkflows",[778,6388,6389],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":15,"searchDepth":16,"depth":16,"links":6391},[6392,6393,6394,6395],{"id":3366,"depth":16,"text":77},{"id":6112,"depth":16,"text":6097},{"id":6121,"depth":16,"text":6103},{"id":6363,"depth":16,"text":6109},"\u002Farticles\u002F2026\u002Fapril\u002Fel_blog_renace.png","2026-04-13T10:00:00.000Z","This post marks the rebirth of my blog, even if an awkward part of the credit probably belongs to AI.",{"head":6400},{"meta":6401},[6402],{"name":805,"content":6403},"nuxt theme, bilingual blog, npm publish, github actions, github workflows, npmjs, github, i18n, OIDC, trusted publishing, ci-cd, open source",{"title":50,"description":6398},"fWzggnlmPbb3gun85Z42Il_Dcd5c1BGeiAlvuykZACk",1785323412614]