Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions skills/add-node/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ When the agent has `GenerativeActionsEnabled: true`:

- Prefer **AutomaticTaskInput** over Question nodes for collecting user info (the orchestrator handles prompting automatically).
- Still use Question nodes when: conditional asks (ask X only if Y), or end-of-flow confirmations.
- A `Question` node consumes the next user message inside the current topic. If the next message must be routed as a new utterance so the orchestrator can select another topic or connector action, use `SendActivity` followed by `EndDialog` with `clearTopicQueue: true` instead.
- Prefer **topic outputs** over SendActivity for returning results.
- Do NOT use SendActivity to show final outputs unless it's a precise mid-flow message.

Expand Down
6 changes: 6 additions & 0 deletions skills/edit-action/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ node ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js summary ModelCont
Read: ${CLAUDE_SKILL_DIR}/sharepoint-actions.md
```
This covers OData filter syntax, the critical `"'$filter'"` quoting pattern, which inputs should be Manual vs Automatic, and dynamic output handling.
- **If the connector is Microsoft Dataverse (`shared_commondataserviceforapps`)**, read the Dataverse-specific reference before making any edits:
```
Read: ${CLAUDE_SKILL_DIR}/dataverse-actions.md
```
This covers direct List rows retrieval, logical-name grounding, dynamic row schemas, filter inputs, and runtime field-selection checks.

4. **Determine the action type** from the YAML:
- If `action.kind` is `InvokeConnectorTaskAction` → regular connector action
Expand Down Expand Up @@ -175,5 +180,6 @@ node ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js summary ModelCont
- **Property names must match the connector definition** — use `connector-lookup operation` to verify exact property names.
- **ManualTaskInput values are strings only** — if the value needs to be a number, enum, or complex type, warn the user that it may need UI configuration.
- **Output propertyName values must match the connector definition's output schema** — use `connector-lookup operation` to see available output properties.
- **Dataverse List rows descriptions must name exact logical columns** — dynamic schemas can contain similarly named fields whose values look plausible. Verify the filter and returned fields against the pulled `dynamicOutputSchema`, and preserve that generated schema.
- **MCP actions must not have `AutomaticTaskInput` entries** — the MCP protocol handles tool parameter discovery dynamically. `ManualTaskInput` entries are OK for passing context (e.g., user identity via Power Fx expressions like `=System.User.Email`).
- **MCP modelDescription should be single-line** — multi-line descriptions have been reported to break MCP tool registration after push.
94 changes: 94 additions & 0 deletions skills/edit-action/dataverse-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Microsoft Dataverse Connector Actions - Reference

Read this file whenever editing a Microsoft Dataverse connector action, especially the **List rows** operation (`ListRecordsWithOrganization`). Dataverse list actions have dynamic row schemas, and the orchestrator needs exact logical names to build filters and select the correct returned fields.

## Prefer List Rows for Direct Retrieval

Use a Dataverse **List rows** connector action when the agent only needs to retrieve existing rows and report their stored values. Do not add a Power Automate flow solely to wrap the same read unless the request also needs transformation, multi-step business logic, side effects, or a stable custom response contract.

The connector action must still be created and authenticated in Copilot Studio. After it is saved, pull the generated action and preserve its opaque connection reference, operation ID, and dynamic output schema.

## List Rows Input Recommendations

| Parameter | Recommended input kind | Why |
|-----------|------------------------|-----|
| `organization` | `ManualTaskInput` | The Dataverse environment URL is fixed at design time. |
| `entityName` | `ManualTaskInput` | Use the table's entity set logical name, not its display label. |
| `"'$filter'"` | `AutomaticTaskInput` when based on the conversation; otherwise `ManualTaskInput` | Dynamic filters must use exact Dataverse column logical names and valid OData syntax. |

Example action header for a lookup by reference number:

```yaml
kind: TaskDialog
inputs:
- kind: ManualTaskInput
propertyName: organization
value: https://contoso.crm.dynamics.com

- kind: ManualTaskInput
propertyName: entityName
value: cr123_requests

- kind: AutomaticTaskInput
propertyName: "'$filter'"
description: Build an OData filter using cr123_reference, for example cr123_reference eq 'REF-12345'.
entity: StringPrebuiltEntity
shouldPromptUser: true

modelDisplayName: Look up a request
modelDescription: "Use when a user asks for an existing request by reference number. Filter cr123_requests by cr123_reference. Return cr123_reference, cr123_requesteremail, and cr123_requeststatus. Treat cr123_requeststatus as the current status; do not use cr123_deliverypreference as status."

action:
kind: InvokeConnectorTaskAction
connectionReference: <preserve-the-pulled-connection-reference>
connectionProperties:
mode: Maker
operationId: ListRecordsWithOrganization

outputMode: All
```

`Maker` uses the maker's shared connection. `Invoker` requires each user to authenticate. Confirm the intended security model instead of changing the pulled mode casually.

## Ground Dynamic Outputs in Logical Names

List rows returns a dynamic table schema. Similar display labels or legacy columns can cause the orchestrator to report the wrong value even when the correct row was retrieved.

1. Verify each required column's logical name in Dataverse metadata or the pulled `dynamicOutputSchema`.
2. Name the exact filter and return columns in `modelDescription` and relevant input descriptions.
3. Explicitly exclude a similarly named legacy column when confusing it would produce a plausible but incorrect answer.
4. Tell the orchestrator to report only values returned by the connector. Do not infer stages, next steps, or policy from fields that are not present.

Display names are presentation only. Filters and output guidance must use logical names such as `cr123_requeststatus`, not labels such as `Request Status`.

## Keep Read and Write Contracts Aligned

Changing a lookup action or cleaning existing rows does not change how future rows are created. If another connector action or Power Automate flow writes the table, inspect that write path separately and verify it populates the same logical column the lookup reports.

For status scenarios, check all three layers:

1. The create/update path writes the intended status column and value.
2. Existing rows contain the intended value after any data cleanup.
3. The List rows action reports that same column in `modelDescription` and at runtime.

Publishing an agent does not publish, activate, or repair an independent Power Automate cloud flow. Likewise, an active flow definition can change independently without another agent publish. Verify both resources when they participate in one user journey.

## Runtime Verification

Schema validation cannot prove that a dynamic filter or output field is correct. Test the action in Copilot Studio with a known row and verify all of the following:

1. The orchestrator selects the expected connector action.
2. The action trace shows the intended OData filter and exact logical column name.
3. The returned identifier and status match the source row in Dataverse.
4. A missing identifier produces a not-found response rather than a fabricated record.
5. If the table has similarly named fields, the response uses the field named in `modelDescription`.
6. If the scenario creates records, the writer maps future rows to the same logical field used by the lookup.

## Pitfalls

- Do not use a table display name for `entityName`; preserve the entity set name from the generated action.
- Do not reconstruct `connectionReference` or `dynamicOutputSchema`; preserve the portal-generated values.
- Do not reuse a dynamic output schema from another table; save and pull the action again after changing the selected table.
- Do not assume a successful connector call means the response used the correct returned column.
- Do not describe a field as status merely because its stored value looks status-like.
- Do not treat a published agent timestamp as proof that an independently managed connector connection or Power Automate flow is healthy; verify each runtime dependency separately.
6 changes: 6 additions & 0 deletions skills/int-reference/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ Some connectors (notably SharePoint) use OData parameters like `$filter`, `$orde

Never mix these two formats.

### Dataverse List Rows

For Microsoft Dataverse `ListRecordsWithOrganization`, keep `organization` and `entityName` fixed with `ManualTaskInput`. Use `AutomaticTaskInput` for `"'$filter'"` only when the filter depends on conversation context. The table name and every filter/output column must be Dataverse logical names verified from metadata or the pulled `dynamicOutputSchema`.

List rows returns a dynamic table schema. A successful call does not prove that the orchestrator selected the correct returned field. Name the exact return columns in `modelDescription`, explicitly exclude confusing legacy fields when necessary, and verify the answer against a known Dataverse row at runtime. See `skills/edit-action/dataverse-actions.md` for the complete pattern.

## System Variables

| Variable | Description |
Expand Down
7 changes: 7 additions & 0 deletions skills/manage-agent/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ Optional: `--agent-id "<agentId>"` overrides the bot ID from `conn.json`.
- In an improvement loop (edit → push → publish → test), publish is required between push and test
- The command confirms publish completion via API — **do not use time-based waits**

#### Publish scope

`publish` promotes the Copilot Studio agent draft. It does not publish, activate, or repair independent runtime dependencies such as Power Automate cloud flows or connector connections. A flow definition can also be updated independently without requiring another agent publish.

When an agent journey invokes a flow or connector, verify each resource separately: confirm the bot `publishedon` timestamp changed, confirm the flow is active after any flow edit, and run an end-to-end behavior test. Do not infer dependency health from the agent publish result alone.

### List Agents

Uses Dataverse REST API directly (no LSP binary needed). `--client-id` is optional.
Expand Down Expand Up @@ -265,5 +271,6 @@ All commands output JSON to stdout with a `status` field:
| ConcurrencyVersionMismatch | Push without fresh row versions | Pull first, then push |
| Token expired + silent refresh failed | Refresh token expired (~90 days) | Run `auth` command for new device code flow |
| Binary missing | Extension installed but binary not present | Reinstall the extension |
| HTTP 403 from push/pull while other environment APIs work | LSP/Island authoring access is denied for this operation | Report the exact error, try the VS Code extension UI, and use the Copilot Studio portal as the authoring fallback. Treat local files as out of sync until a later pull succeeds. |
| PvaPublish failed | Insufficient permissions or bot not found | Verify the user has publish permissions and the agent ID is correct |
| Publish timed out | Publish still in progress after timeout | Increase `--timeout` or check the Copilot Studio UI for status |
18 changes: 18 additions & 0 deletions skills/new-topic/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,24 @@ When a topic exists alongside other topics or other actions (i.e. TaskDialog), t
- Use a global variable: the topic sets it (one-shot or by asking multiple questions and consolidating into the same variable via PowerFX), and the action's body references it via Power FX. This is more complex but can be useful for multi-turn data gathering that feeds somewhere else, especially if you need to do some logic on the data before sending it.
- Output the collected data in a topic output variable so the orchestrator can pass it to the next action/topic.

## Hand Off the Next Utterance to Generative Orchestration

A `Question` node consumes the user's next message as an answer inside the current topic. That answer is not a new utterance for generative orchestration. Do not use `Question` when a welcome choice or routing topic only needs to tell the user what to type next and then let the orchestrator select a connector action.

For that handoff, send a prompt and end the current dialog:

```yaml
- kind: SendActivity
id: sendMessage_requestReference
activity: "Please type your request with the reference number, for example: Check status REF-12345."

- kind: EndDialog
id: endDialog_handoff
clearTopicQueue: true
```

The user's following message can then be recognized as a new utterance and routed by the generative orchestrator. Runtime-test the full path from the welcome choice through action selection; schema validation alone cannot prove this routing behavior.

## Power Fx Quick Reference

- Expressions start with `=`: `value: =Text(Topic.num1 + Topic.num2)`
Expand Down