# Phase 3 & 4 — Connections, connection references, and first-party agents

## The blocker nobody documents

A freshly provisioned environment has **zero connections**. Every `connectionreference` record
imported by the managed solutions has `connectionid = null`.

Consequence: **every first-party agent is silently blocked.** Their admin pages in the Copilot
Service admin center show "Step 1: Connection References — Loading…" forever, with no error
message and no indication of what is wrong.

In the reference build: **44 connection references, 0 bound.**

Fix this before you touch any agent configuration.

---

## 1. Create the connections

Go to `https://make.powerapps.com/environments/<envid>/connections`.

Create one connection per connector, signing in as the tenant admin each time. Direct URL:

```
https://make.powerapps.com/environments/<envid>/connections/available/<apiname>?apiName=<apiname>
```

Connectors needed for the standard CE + agent portfolio:

| Connector API name | Display name |
|---|---|
| `shared_commondataserviceforapps` | Microsoft Dataverse |
| `shared_microsoftcopilotstudio` | Microsoft Copilot Studio |
| `shared_conversionservice` | Content Conversion |
| `shared_office365users` | Office 365 Users |
| `shared_teams` | Microsoft Teams |
| `shared_dataflows` | Power Query Dataflows |
| `shared_powerappsnotificationv2` | Power Apps Notification V2 |
| `shared_d365contactcenteradminmcpserver` | D365 Contact Center Admin MCP |

To discover the exact set your environment needs:

```js
const r = await Xrm.WebApi.retrieveMultipleRecords('connectionreference',
  '?$select=connectorid,connectionid&$top=500');
const byApi = {};
for (const e of r.entities) {
  const api = (e.connectorid||'').split('/').pop();
  byApi[api] = byApi[api] || {total:0, bound:0};
  byApi[api].total++;
  if (e.connectionid) byApi[api].bound++;
}
console.table(byApi);
```

### OAuth popups will break automation

Each connection opens an OAuth popup. If you are automating, handle the popup, and expect
some connections to land in **Error** state when the flow is interrupted. Verify with:

```powershell
pac connection list
```

Anything showing `Error` needs the **Reconnect** button on the connections page. Reconnect them
one at a time — batching causes more interrupted popups.

---

## 2. Bind the connection references

Once all connections show `Connected`, bind every reference in one pass.

Use `scripts/bind-connection-references.js`. It maps each reference's connector to the matching
connection and PATCHes `connectionid`.

Verify: re-run the discovery snippet above — every connector should show `bound === total`.

Then re-open the agent admin page. "Step 1: Connection References" should flip from
**Not Started** / perpetual *Loading* to **Ready**.

---

## 3. Where the first-party agents actually live

They are **not** all in one place. This trips people up.

| Agent family | Location |
|---|---|
| SCM / Finance / Project Ops / Field Service agents | PPAC → **Dynamics 365 agents** |
| Customer Service agents | **Copilot Service admin center** (`appid=<guid>`) |
| Sales agents | Copilot Studio + Sales Hub app settings |

Time Agent and Approvals Agent arrive **already Installed** with Project Operations.

### Copilot Service admin center — direct URLs

Base: `https://<org>.crm.dynamics.com/main.aspx?appid=<guid>&pagetype=control&controlName=`

| Page | controlName + data |
|---|---|
| Case Management Agent | `MscrmControls.ModernAdmin.OCGlobalSettingsControl&data={"settingType":"casemanagementagent"}` |
| Customer Intent Agent | `MscrmControls.ModernAdmin.OCGlobalSettingsControl&data={"settingType":"intentassist"}` |
| Knowledge | `MscrmControls.ModernAdmin.OCGlobalSettingsControl&data={"settingType":"knowledge"}` |
| Contact Center Agents | `MscrmControls.ContactCenterAgentManagement.ContactCenterAgentConfigControl` |

URL-encode the `data` value.

> **Gotcha:** navigating directly to a *sub*-settings control (e.g. the Case resolution page)
> often renders an empty page or stale dropdowns. Enter via the parent agent page and click its
> **Manage** button instead. This matters specifically for the application-user dropdown.

---

## 4. Configure the Customer Service agents

### Case Management Agent

Three prerequisites, then three capability sections.

**Prerequisites**
1. Connection References → becomes **Ready** once phase 3 is done
2. Power Automate Flows → click **Enable** (takes ~45 s)
3. Copilot Studio Agent → **Publish** (see the publish caveat below)

**Case creation and update** — turn on:
- *Make Case Processing Agent available for case creation from conversations*
- *AI-assisted case creation* for **Email** and **Conversation**
- Leave *Allow AI agent to override human edits during autonomous updates* **off** unless you
  specifically want to demo that

**Case follow-up and closure** — turn on:
- *Turn on the case follow-up and closure automation*
- *Form-fill assistance during case resolution*

**Case resolution** — needs an Entra application user. See section 5.

### Customer Intent Agent

Single master toggle (`settingType=intentassist`). Flip it on. It becomes **disabled** once
enabled, which is expected — that is the confirmation, not a failure.

Optional follow-on config: lines of business, intent discovery, intent groups, user groups.

### Customer Knowledge Management Agent

Under **Knowledge → Customer knowledge management agent** (`settingType=knowledgeharvesting`).

Same 3-step prerequisite chain. Step 2 **Enable** works. Step 3 **Publish** hits the publish
problem below.

Separately, **Knowledge → Knowledge creation (preview)** is gated behind a supplemental AI
terms acceptance — tick *"I agree to the terms"* then **Opt in**. This is a legal acceptance;
get explicit sign-off from whoever owns the tenant before clicking it.

---

## 5. Entra application user for Case resolution

The docs describe a manual 4-step process. **One `pac` command does all of it:**

```powershell
pac admin create-service-principal `
  --environment <envid> `
  --name "Caldova Case Management Agent" `
  --role "Customer Service Representative"
```

This creates the Entra app registration, the service principal, the Dataverse application user,
and assigns the role. It prints:

```
Application Id, Service Principal Id, Client Secret, Client Secret Expiration, System User Id
```

> **The client secret is printed in clear text.** Do not paste it into notes, chat, or files.
> Store it in a secret manager or discard it — the agent configuration does not need it again.

Then: **Case Management Agent → Manage settings for case resolution**

1. **Application user** → select the new `# <name>` entry
2. **Level of automation per line of business** → select Default LOB → **Edit**
   - `Disabled` (default)
   - `Require human confirmation` ← recommended for demos
   - `Full automation` — lets the agent autonomously send customer email
3. Save

Prefer **Require human confirmation**. It demonstrates the capability with a human gate, which
is both safer in a shared demo tenant and a better responsible-AI story.

> **Gotcha:** the application-user dropdown does not pick up a newly created app user until you
> re-enter the settings control via the parent page's **Manage** button. Navigating straight to
> the settings URL shows a stale dropdown containing only "None".

Optional: create a shared mailbox and set the app user's email to it, so agent-sent email comes
from a sensible address.

---

## 6. The agent publish problem — read before you burn time

38 of 44 Copilot Studio agents ship as **Draft**. In the reference build they could not be
published by any route:

| Route | Result |
|---|---|
| `PvaPublish` Web API action | `400` wrapping `409 Conflict / ExternalServiceException` |
| `pac copilot publish --bot <id>` | `OrganizationServiceFault`, CLI terminates |
| Copilot Service admin center → Publish | "Unable to publish Copilot Studio agents…" |
| Copilot Studio → agent → Publish | Button **disabled**, status "Setting up…" |

Three independent paths failing identically indicates a **server-side provisioning state**, not
a permissions or configuration problem. Waiting 25+ minutes did not clear it.

**What still works:** agents whose capability is enabled through the admin surface (Case
Management, Customer Intent, Knowledge) function for demo purposes without a manual publish.
The 6 agents that *were* published got published automatically by their app installs.

**If you hit this:** file support referencing the `PvaPublish` 409 `ExternalServiceException`,
and check `publishedon` to track state:

```js
const r = await Xrm.WebApi.retrieveMultipleRecords('bot','?$select=name,publishedon&$top=100');
console.log('unpublished:', r.entities.filter(b=>!b.publishedon).length, 'of', r.entities.length);
```

Do **not** use `pac copilot list` to check this — it reports everything as Published regardless.
