← All projects
in-progressApr 20264 min read

Event Swag Agent

AI swag allocation for a large events program: a Copilot Studio agent that proposes and negotiates packages within budget, paired with a dense admin app for the ops team, on one Dataverse backend.

Copilot StudioPower FxPower AutomateDataverseMicrosoft EntraViteReactTypeScriptFluent UI

The Problem

A central team manages all the swag for seller events at a company with more than 5,000 account managers and sellers: 90 events per quarter, 7-8 per week, each hosted by an account team for customers somewhere between the C-suite and the technical staff. Each tier of attendee warrants a different level of swag, every event draws against a single budget that has to last the whole period, and the budget, inventory, allocation rules, and orders are tracked across scattered spreadsheets. One hard constraint applied from the start: it had to be built Power-Platform-first (Copilot Studio for the agent, Dataverse for the data) so it lived natively inside the org's existing tools, identity, and governance rather than as one more outside app to adopt and secure.

The Insight

This is really two products with two opposite users, and forcing them into one interface would have made both worse. So I built two surfaces on a single shared Dataverse backend:

  • A Copilot Studio agent for the people requesting swag. Conversational and low friction: the requester just describes the event.
  • An admin Code App for the ops team. Dense and data-first.

Same data underneath, two surfaces each tuned to a completely different user.

What I Built

The agent. Someone describes an event in natural language; the agent proposes a swag package, negotiates within budget, and finalizes it. The budget optimization is portfolio-aware, allocating against the program's remaining budget across all events rather than just the one in front of it. The negotiation math lives in Power Fx, with two Power Automate flows handling context loading and finalization.

The admin app. A Vite + React + TypeScript app in Fluent UI, built in the spirit of the Azure Portal's Cost Management rather than a marketing page: an events-first budget dashboard, a packages editor, personas managed as data, inventory, and orders. Budget health is a real business rule: green, yellow, or red, derived from remaining budget against the program total.

The Hard Part

Two things were genuinely hard, and both came partly from the Power-Platform-first constraint.

First, budget-aware negotiation inside Copilot Studio. A Copilot Studio agent isn't a free-form LLM loop; you build within its topics, flows, and Power Fx. Getting it to propose a package, hold a budget constraint, and negotiate down meant pushing the optimization math into Power Fx and keeping the agent's state honest across the conversation.

Second, personas-as-data. The customer-attendee tiers (C-suite down to technical staff) started life hardcoded as a TypeScript union, which meant a code change and a deploy every time the program renamed or re-cut a tier. I made personas editable data instead: rename a tier in settings and it propagates everywhere without a deploy. That's the difference between a tool the ops team owns and one they file tickets against.

Building on the Microsoft Stack

Everything lives natively: Dataverse for storage, an Entra-backed people picker for identity, Dataverse security roles for access, Power Automate for orchestration. Deployment is pac solution import for the agent and pac code push for the app. The UI follows Fluent 2 with WCAG-redundant status encoding (color and icon), feature flags for chrome surfaces, and a test suite pinned with fake timers so date-bucketed assertions don't flake on the CI clock.

What I Learned

  • Two users means two surfaces. A conversational agent for requesters and a dense admin for ops. A single interface would have served neither well.
  • Configuration shouldn't require a deploy. Making personas editable data is what let the ops team own the tool.
  • Power-Platform-first is a deliberate tradeoff. You give up flexibility and gain native identity, permissions, governance, and adoption you'd otherwise have to build and defend yourself. Worth it when the tool has to live inside an existing org.