From 22444c82ecfd616ca7fb219b9669c190ce17782d Mon Sep 17 00:00:00 2001 From: Reilly Bova Date: Fri, 11 Sep 2026 00:32:20 -0700 Subject: [PATCH 1/7] feat(announcements): wire maker discovery and packaged entry points Add the announcements skill, prompt, setup materialization, and Maker Profile entry point. Keep discovery on the announcements provider, require deployed-agent context, and document recovery and credential limits. Preserve the reviewed 0.4.25 package and existing upstream setup behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: eddd3818-bb74-42d3-bcf3-7e0670a57f27 --- .github/workflows/ci.yml | 1 + setup/README.md | 2 +- .../.github/copilot-instructions.md | 20 +- .../.github/prompts/menu.prompt.md | 1 + .../prompts/org-announcements.prompt.md | 8 + .../.vscode/mcp.defaults.json | 5 + solutions/ess-maker-skills/README.md | 42 ++ .../src/skills/onboarding/SKILL.md | 3 +- .../src/skills/onboarding/step1.md | 1 + .../src/skills/onboarding/step2.md | 4 + .../src/skills/org-announcements/SKILL.md | 466 ++++++++++++++++++ .../test_setup_materialization.py | 261 ++++++++++ tests/scripts/test_mcp_config.py | 5 + .../scripts/test_setup_preserves_title_id.py | 33 +- tests/setup/test_foundation_setup_router.py | 168 +++++++ tools/ess-maker-profile/README.md | 1 + .../ess-maker-profile/extension/CHANGELOG.md | 5 + .../extension/ess-maker-profile-0.4.25.vsix | Bin 30666 -> 31073 bytes .../ess-maker-profile/extension/extension.js | 15 + .../extension/extension.test.js | 19 +- 20 files changed, 1052 insertions(+), 8 deletions(-) create mode 100644 solutions/ess-maker-skills/.github/prompts/org-announcements.prompt.md create mode 100644 solutions/ess-maker-skills/src/skills/org-announcements/SKILL.md create mode 100644 tests/mcp/agentconfig_org_announcements/test_setup_materialization.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 232b1abdf..68d941e59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,6 +165,7 @@ jobs: run: >- python -m pytest tests/mcp/agentconfig_org_announcements + tests/setup/test_foundation_setup_router.py -q flightcheck-tests: diff --git a/setup/README.md b/setup/README.md index a99d3efc8..adcfe01a1 100644 --- a/setup/README.md +++ b/setup/README.md @@ -36,7 +36,7 @@ iex (irm https://raw.githubusercontent.com/microsoft/Employee-Self-Service-Agent This installs everything the standard installer does, plus the **ESS Maker Profile** extension which provides: - A chat-only layout with all developer surfaces hidden -- Big-button "Quick Actions" rail for common tasks (Connect, Customize landing page, Create, Scan, FlightCheck, Push) +- Big-button "Quick Actions" rail for common tasks (Connect, Customize landing page, Post an announcement, Create, Scan, FlightCheck, Push) - A built-in tutorial explaining each button You can switch between lite mode and standard VS Code at any time using the toggle buttons in the Quick Actions panel. diff --git a/solutions/ess-maker-skills/.github/copilot-instructions.md b/solutions/ess-maker-skills/.github/copilot-instructions.md index b0e2a58d3..f7bf971a1 100644 --- a/solutions/ess-maker-skills/.github/copilot-instructions.md +++ b/solutions/ess-maker-skills/.github/copilot-instructions.md @@ -98,8 +98,8 @@ Order of grounding sources (highest to lowest): microsoft/CopilotStudioSamples Employee Self-Service Agent samples. 3. `src/skills/` - kit-shipped skill instructions for /create, /update, /delete, /test, /scan, /evaluate, /push, /flightcheck, - /backup-template-configs, /restore-template-configs, and landing-page - configuration. + /backup-template-configs, /restore-template-configs, /org-announcements, + and landing-page configuration. 4. `src/reference/` (other subfolders) - additional kit-shipped guidance. 5. Web fetch / general knowledge - only when none of the above answer the question and only after telling the user you're falling back. @@ -322,7 +322,9 @@ After a successful push, `.baseline/` is updated to match the new state. | Restore Workday HCM template configs after a package update | `src/skills/restore-template-configs/SKILL.md` | | Re-apply / put back Workday reference-data customisations | `src/skills/restore-template-configs/SKILL.md` | | View or configure ESS landing-page branding, quick links, starter prompts, insight cards, name, or icon | `src/skills/landing-page-config/SKILL.md` | -| Invoke any tool from the `ess-landing-page-config` MCP server | `src/skills/landing-page-config/SKILL.md` | +| Invoke a landing-page configuration tool | `src/skills/landing-page-config/SKILL.md` | +| Create, edit, republish, archive, or manage organization announcements or bulletins | `src/skills/org-announcements/SKILL.md` | +| Invoke any tool from the `ess-org-announcements` MCP server | `src/skills/org-announcements/SKILL.md` | **Trigger phrases for connect:** "connect ServiceNow", "set up ServiceNow", "integrate ServiceNow", "connect Workday", "set up Workday", "add ServiceNow", @@ -346,6 +348,18 @@ links, starter prompts, Stay Up to Date, Quick Access, the agent name, or the agent icon, or asks what any landing-page setting controls for employees. Do not call an AgentConfiguration MCP tool from a generic flow. +**Org Announcements invocation:** Before invoking ANY tool from the +`ess-org-announcements` MCP server, read and follow +`src/skills/org-announcements/SKILL.md`. Its own `list_agent_configs` and +`search_agents` tools resolve missing deployed titleIds; do not start or call +the landing-page server for announcement discovery. This applies whether the user asks to +see, create, edit, republish, archive, or delete an announcement, mentions +announcements, org announcements, bulletins, or alerts, or asks who an +announcement reaches. Org Announcements are scoped to the authenticated tenant +and selected deployed agent's required `titleId`. The tenant is token-derived; +the title is not an audience group or author permission. Do not call an Org +Announcements MCP tool from a generic flow. + **FlightCheck results rendering:** When presenting `/flightcheck` results (Step 3 of `src/skills/flightcheck/SKILL.md`), read `workspace/flightcheck/results.json` with your file-reading tool and format the summary banner and tables **yourself, diff --git a/solutions/ess-maker-skills/.github/prompts/menu.prompt.md b/solutions/ess-maker-skills/.github/prompts/menu.prompt.md index def4ef545..b5a560d62 100644 --- a/solutions/ess-maker-skills/.github/prompts/menu.prompt.md +++ b/solutions/ess-maker-skills/.github/prompts/menu.prompt.md @@ -14,6 +14,7 @@ Here's what I can help you with: | Command | What it does | |---------|-------------| | `/landing-page` | Configure the branding and content employees see when they open the ESS agent | +| `/org-announcements` | Create and manage announcements for the selected deployed ESS agent | | `/connect` | Type Enter to connect ServiceNow or Workday to your agent | | `/create` | Create a simple topic with evals, a workflow, or an evaluation test set | | `/update` | Update a simple topic with evals, a workflow, or an evaluation test set | diff --git a/solutions/ess-maker-skills/.github/prompts/org-announcements.prompt.md b/solutions/ess-maker-skills/.github/prompts/org-announcements.prompt.md new file mode 100644 index 000000000..c3ca03cc7 --- /dev/null +++ b/solutions/ess-maker-skills/.github/prompts/org-announcements.prompt.md @@ -0,0 +1,8 @@ +--- +mode: agent +description: "Create and manage announcements for the selected ESS agent" +--- + +# Org Announcements + +Read `src/skills/org-announcements/SKILL.md` and follow it. diff --git a/solutions/ess-maker-skills/.vscode/mcp.defaults.json b/solutions/ess-maker-skills/.vscode/mcp.defaults.json index 13dbccae3..b72a37cb2 100644 --- a/solutions/ess-maker-skills/.vscode/mcp.defaults.json +++ b/solutions/ess-maker-skills/.vscode/mcp.defaults.json @@ -4,6 +4,11 @@ "command": "{pythonExecutable}", "args": ["server.py"], "cwd": "${workspaceFolder}/src/mcp/agentconfig_landing_page" + }, + "ess-org-announcements": { + "command": "{pythonExecutable}", + "args": ["server.py"], + "cwd": "${workspaceFolder}/src/mcp/agentconfig_org_announcements" } } } diff --git a/solutions/ess-maker-skills/README.md b/solutions/ess-maker-skills/README.md index f696b8f00..6213e66c7 100644 --- a/solutions/ess-maker-skills/README.md +++ b/solutions/ess-maker-skills/README.md @@ -48,6 +48,47 @@ Copilot Studio and deployed to the organization. `/setup` installs and extracts the Power Platform agent; publication, admin approval, and Integrated apps deployment are separate steps. +### 📢 Post Organization Announcements + +Publish announcements for the selected deployed ESS agent and its audiences. Run +`/org-announcements`, ask `Create an announcement`, or use the **Post an +announcement** Quick Action. + +- **Standard announcements** carry a title, description, priority, and up to two + actions. +- **Alerts** carry a single link action for time-sensitive notices. +- **Audiences** are security groups, mail-enabled security groups, or classic + distribution groups, searched by name or email in one combined query. +- **Scheduling** publishes an announcement for a start/end window, and expired + announcements can be published again through the normal editor after reviewing + and updating their schedule. +- **Lifecycle** actions archive, unarchive, move back to draft, duplicate, or + delete an announcement. + +Describe the announcement in chat and the kit opens a pre-filled editor for you +to review — nothing is saved until you publish or save a draft in that editor. + +Org Announcements are **scoped to the authenticated tenant and selected agent's +`titleId`**, not shared across agents. The current100 limit and latest50 archive +window apply per tenant-and-agent pair. There is no tenant-wide fallback. +The title is resolved using `list_agent_configs` and `search_agents` on the +`ess-org-announcements` provider. Discovery shares neutral Python code with the +landing-page provider, but does not require its MCP process or initialize its +configuration. Announcement authoring +requires the Org Announcements feature to be enabled for your tenant, and +audience search requires the `Directory.Read.All` Microsoft Graph permission to +be consented in your tenant. + +Graph uses a separate resource token for the same authoring tenant and account. +The current account-context check requires readable `tid` and `oid` claims; +opaque tokens or credentials missing those claims return an explicit +authentication failure rather than using a different account. The API still +validates tokens and authorizes every request. + +This development surface requires the matching agent-qualified v1.1 backend +and scoped widget. The MCP rejects unscoped canonical responses instead of +silently consuming records from an older backend. + ### 📖 Pre-Loaded ESS Documentation, Samples & Best Practices The kit ships with a complete reference library that the AI agent reads at task time — you don't need to look anything up yourself. @@ -332,6 +373,7 @@ Then **run `/setup`** in GitHub Copilot Chat to configure your environment. |---------|-------------| | `/setup` | First-time environment setup — authenticate, discover agent, extract, configure | | `/landing-page` | Configure landing-page branding and content | +| `/org-announcements` | Create and manage announcements for the selected ESS agent | | `/connect` | Connect an external system (ServiceNow, Workday) — guided setup with MCP verification | | `/create` | Create an eval-driven topic, workflow, or evaluation test set | | `/update` | Update a simple topic with evals, a workflow, or an evaluation test set | diff --git a/solutions/ess-maker-skills/src/skills/onboarding/SKILL.md b/solutions/ess-maker-skills/src/skills/onboarding/SKILL.md index 209569850..fc3e253f8 100644 --- a/solutions/ess-maker-skills/src/skills/onboarding/SKILL.md +++ b/solutions/ess-maker-skills/src/skills/onboarding/SKILL.md @@ -58,7 +58,8 @@ If dependency installation fails, show the error and stop. **Message:** Setup is already complete! Run `/landing-page` to configure the branding and -content employees see, or type `/menu` to see everything you can do. +content employees see, `/org-announcements` to post an announcement for your +selected deployed agent, or type `/menu` to see everything you can do. **End message.** diff --git a/solutions/ess-maker-skills/src/skills/onboarding/step1.md b/solutions/ess-maker-skills/src/skills/onboarding/step1.md index bd0d1ffff..5f3a46232 100644 --- a/solutions/ess-maker-skills/src/skills/onboarding/step1.md +++ b/solutions/ess-maker-skills/src/skills/onboarding/step1.md @@ -137,6 +137,7 @@ Run this command in the terminal without showing it to the user: ```powershell python -m pip install -r src/mcp/agentconfig_landing_page/requirements.txt +python -m pip install -r src/mcp/agentconfig_org_announcements/requirements.txt ``` If installation fails, show the error and stop. diff --git a/solutions/ess-maker-skills/src/skills/onboarding/step2.md b/solutions/ess-maker-skills/src/skills/onboarding/step2.md index 99f987de8..c70c60163 100644 --- a/solutions/ess-maker-skills/src/skills/onboarding/step2.md +++ b/solutions/ess-maker-skills/src/skills/onboarding/step2.md @@ -79,9 +79,13 @@ You can customize the active agent's landing page from chat, including accent colors, categorized starter prompts, quick links, Stay up to date cards, and Quick Access cards. Run `/landing-page` whenever you're ready. +You can also post announcements for the selected deployed ESS agent and its +chosen audiences. Run `/org-announcements` to create or manage them. + | Command | What it does | |---------|-------------| | `/landing-page` | Configure landing-page branding and content | +| `/org-announcements` | Create and manage announcements for the selected ESS agent | | `/create` | Create a new topic or workflow | | `/connect` | Set up ServiceNow or Workday integration | | `/scan` | Scan for compile errors | diff --git a/solutions/ess-maker-skills/src/skills/org-announcements/SKILL.md b/solutions/ess-maker-skills/src/skills/org-announcements/SKILL.md new file mode 100644 index 000000000..080ba3aa2 --- /dev/null +++ b/solutions/ess-maker-skills/src/skills/org-announcements/SKILL.md @@ -0,0 +1,466 @@ +--- +name: org-announcements +description: >- + Create, edit, republish, and manage announcements for a deployed ESS agent + through the Org Announcements MCP server. Use for announcements, org + announcements, bulletins, alerts, announcement audiences, archiving or + republishing an announcement, and any call to the ess-org-announcements + MCP server. +--- + +# Org Announcements + +Orchestrate organization announcements through the Org Announcements MCP +server. Open the right view once, let the widget own the editing session, and +never claim a save the tools did not return. + +## Tenant-and-agent scope + +Org Announcements belong to **one deployed ESS agent in the authenticated +tenant**, selected by its required `titleId`. They are not shared across every +agent. `titleId` is an agent identifier, not an author permission, a Dataverse +`botId`, or a Graph audience group. Tenant identity comes only from the +authoring sign-in; never supply `tenantId` to a tool. + +The 100-current-item limit and latest-50 archived window apply separately to +each tenant-and-agent pair. There is no migration or tenant-wide fallback. +Tell the maker which selected agent they are managing: + +> These announcements belong to **{agent name}**. Their selected audiences apply +> within that agent, not across your other ESS agents. + +## Setup-state check + +For every request that reads or authors an announcement, read +`.local/config.json` before calling any MCP tool. + +If the file does not exist, or its `setup` value is not `"complete"`, show: + +> Welcome to the ESS Maker Kit. Before using `/org-announcements`, type `/setup` to set up your environment. + +and STOP. + +Requests that only ask what announcements are, or what this skill can do, do not +require local setup. Answer them directly. + +## MCP availability check + +Before any request that requires an announcement tool, inspect the tools +available in the current conversation for the `ess-org-announcements` server. + +When its tools are available, continue to **Resolve the target**. + +When its tools are unavailable: + +1. Run: + + ```text + python scripts/mcp_config.py validate --server ess-org-announcements + ``` + +2. Parse `MCP_CONFIG_STATUS_JSON:`: + - `configured`: follow **Start the announcements MCP server**. + - `missing-file` or `missing-server`: run: + + ```text + python scripts/mcp_config.py materialize-defaults + ``` + + Parse `MCP_CONFIG_RESULT_JSON:` and confirm `ess-org-announcements` + appears in `addedServers`, or run `validate` again and confirm its status + is `configured`. Then follow **Start the announcements MCP server**. + - command failure or any other result: show the exact error and stop. Do not + replace malformed JSON or overwrite an existing configuration. + +### Start the announcements MCP server + +Show: + +> The announcements server is configured, but its tools are not available in +> this chat yet. +> +> 1. Press `Ctrl+Shift+P`. +> 2. Run `MCP: List Servers`. +> 3. Select `ess-org-announcements`. +> 4. Choose `Start`. +> +> Type `done` when the server shows `Running`. + +Wait for the maker. When they confirm, inspect the available tools again. If the +tools are available, continue the original request. If they remain unavailable, +tell the maker to reload the VS Code window, rerun `/org-announcements`, and +stop. + +## Resolve the target + +Reuse the setup configuration already loaded. Do not guess an identifier or +use announcement content to decide which agent owns it. + +1. Select the active agent from the backward-compatible `agent` object. For + another configured agent, match an `agents` entry by `slug`, `botId`, or + unambiguous `name`. +2. Use the maker's explicit `titleId`, otherwise the selected entry's stored + `titleId`. A verified target can be reused for this conversation; do not + force `get_agent_config` before each opener. +3. If the title is missing, use this provider's read-only discovery tools: + `list_agent_configs`, then `search_agents` with a distinctive agent-name + substring when the list has no unambiguous match. These discover deployed, + tenant-visible agents; a `botId` is never a substitute for `titleId`. + Both tools belong to `ess-org-announcements`. No landing-page MCP process + is needed; follow this skill's availability check if they are unavailable. +4. Ask the maker to choose among ambiguous candidates. If no candidate matches, + stop and ask them to confirm the agent name and have the published agent + approved and deployed to the organization. Never fall back to tenant-wide + announcements. +5. Persist a discovered, verified `titleId` using the existing local-agent + convention: reread the complete config, find the selected `agents` entry by + `botId` then `slug` (name only if unambiguous), and change only its `titleId`. + If the active agent exists only as `agent`, copy that complete object into + `agents` first. Also update `agent.titleId` when the target matches + `activeAgent` or the active object's botId/slug. Preserve all other fields + and agents. Reread to verify both copies before calling another tool. + With no matching local entry, use the discovered title for this request + without fabricating a partial local agent. + +Discovery does **not** initialize landing-page configuration. Never call +`create_agent_config` or `update_agent_config` as part of this flow, including +when a target was found only through search. No landing-page existence check +or creation is needed to open announcements. + +## Hard rules + +1. Route every call to the `ess-org-announcements` MCP server through this + skill. +2. Call `open_org_announcements` **at most once per maker turn**. It is the only + announcement tool you may call to open a view. +3. `open_org_announcements` reads only. It never creates, updates, publishes, + archives, or deletes. +4. After the widget opens, **stop**. The widget owns every save, publish, + lifecycle action, and audience search for that editing session. Do not call + `save_bulletin`, `transition_bulletin`, or `duplicate_bulletin` — they are not + available to you, and asking for them is a bug. +5. Do not issue any further `search_audience_groups` call once the widget is + open. The widget performs its own searches. +6. Treat all suggested content as reviewable draft state. A suggestion is never + authorization to publish. Say what will open, not what was saved. +7. Never manufacture a bulletin ID, a status, an audit field, or a version. Only + the tools produce canonical state. +8. Never claim an announcement was created, saved, published, archived, or + deleted. The widget reports every outcome. Chat must not duplicate the + widget's success message. +9. Use the announcement tools for server access. Do not call the backing REST + API directly. +10. Pass the resolved `titleId` on every opener. Only the widget may call + mutations, and it retains this title throughout navigation and retries. + On an agent change, open the new scope; never reuse the previous agent's + IDs, drafts, manager state, or retry request. +11. Keep `titleId` outside `suggestedDraft` and bulletin/editor content. + Audience search remains `{query}` in the tenant directory, not per-agent. + +## Classify the request + +Classify every announcement request into exactly one of these, then follow the +matching flow. + +| Maker intent | Flow | +|---|---| +| "Show me our announcements", "manage announcements", "what's published" | **Open management** | +| "Create an announcement", "new announcement", "let me write one" | **Empty create** | +| "Announce the benefits deadline to Finance", any request with real content | **Pre-hydrated create** | +| "Edit the all-hands announcement", "change the end date on X" | **Edit** | +| "Repost the parking notice", "that one expired, run it again" | **Edit** (review the schedule before publishing again) | + +When the intent is ambiguous, ask one short clarifying question before opening +anything. Opening the wrong view costs the maker a turn. + +### Open management + +Call `open_org_announcements` with: + +```json +{ "titleId": "", "view": "manager" } +``` + +Then stop and let the maker work in the widget. + +### Empty create + +Use this when the maker wants to write the announcement themselves. + +Call `open_org_announcements` with: + +```json +{ "titleId": "", "view": "editor", "mode": "create" } +``` + +Do not invent a title or description to "help". An empty create means empty. + +### Pre-hydrated create + +Use this when the maker's message already carries real announcement content. + +1. Build a `suggestedDraft` from what the maker actually said. Include only the + fields they supplied or clearly implied. Every omitted field falls back to + the editor default, which is what the maker would have seen anyway. +2. Resolve any named audience through `search_audience_groups` **before** the + opener call. See **Resolve suggested audiences**. +3. Call `open_org_announcements` once: + + ```json + { + "titleId": "", + "view": "editor", + "mode": "create", + "suggestedDraft": { + "type": "standard", + "priority": 1, + "title": "", + "description": "", + "primaryAction": { + "actionType": "externalLink", + "label": "