$npx -y skills add microsoft/skills-for-copilot-studio --skill chat-directlineSend a message to a Copilot Studio agent via DirectLine v3. Use for agents with no auth or manual auth. Requires a token endpoint URL or DirectLine secret.
| 1 | # Chat via DirectLine |
| 2 | |
| 3 | Send a single utterance to a published agent via the DirectLine v3 REST API. Use this for agents with **no authentication** (authenticationmode 1) or **manual authentication** (authenticationmode 3). |
| 4 | |
| 5 | ## Instructions |
| 6 | |
| 7 | 1. Run the script with `--token-endpoint` (from detect-mode output) and the utterance from `$ARGUMENTS`: |
| 8 | |
| 9 | ```bash |
| 10 | node ${CLAUDE_SKILL_DIR}/../../scripts/chat-with-agent.bundle.js \ |
| 11 | --token-endpoint "<tokenEndpoint>" "<utterance>" |
| 12 | ``` |
| 13 | |
| 14 | If the user provided a DirectLine secret instead: |
| 15 | |
| 16 | ```bash |
| 17 | node ${CLAUDE_SKILL_DIR}/../../scripts/chat-with-agent.bundle.js \ |
| 18 | --directline-secret "<secret>" "<utterance>" |
| 19 | ``` |
| 20 | |
| 21 | 2. Parse the JSON output from stdout. |
| 22 | |
| 23 | ### Normal response (`status: "ok"`) |
| 24 | |
| 25 | ```json |
| 26 | { |
| 27 | "status": "ok", |
| 28 | "protocol": "directline", |
| 29 | "utterance": "hello", |
| 30 | "conversation_id": "abc123-XYZ", |
| 31 | "directline_token": "eyJ...", |
| 32 | "watermark": "3", |
| 33 | "start_activities": [ ... ], |
| 34 | "activities": [ ... ] |
| 35 | } |
| 36 | ``` |
| 37 | |
| 38 | Display the agent's response from the `activities` array: |
| 39 | - **Text**: activities where `type === "message"` — show `text` |
| 40 | - **Suggested actions**: `suggestedActions.actions` array |
| 41 | - **Adaptive cards**: `attachments` with `contentType === "application/vnd.microsoft.card.adaptive"` |
| 42 | |
| 43 | **Save `conversation_id`, `directline_token`, and `watermark`** — needed for follow-ups. |
| 44 | |
| 45 | ### Sign-in required (`status: "signin_required"`) |
| 46 | |
| 47 | The agent requires the user to authenticate (manual auth agents): |
| 48 | |
| 49 | ```json |
| 50 | { |
| 51 | "status": "signin_required", |
| 52 | "protocol": "directline", |
| 53 | "signin_url": "https://...", |
| 54 | "resume_command": "...", |
| 55 | "followup_command": "..." |
| 56 | } |
| 57 | ``` |
| 58 | |
| 59 | 1. Show the `signin_url` to the user, ask for the validation code |
| 60 | 2. Send the code: `node ${CLAUDE_SKILL_DIR}/../../scripts/chat-with-agent.bundle.js <resume_command with code substituted>` |
| 61 | 3. Re-send the utterance: `node ${CLAUDE_SKILL_DIR}/../../scripts/chat-with-agent.bundle.js <followup_command>` |
| 62 | |
| 63 | Use `resume_command` and `followup_command` exactly as given. |
| 64 | |
| 65 | ## Multi-turn |
| 66 | |
| 67 | Pass all three values from the previous response: |
| 68 | |
| 69 | ```bash |
| 70 | node ${CLAUDE_SKILL_DIR}/../../scripts/chat-with-agent.bundle.js \ |
| 71 | --token-endpoint "<url>" "<follow-up>" \ |
| 72 | --conversation-id "<id>" --directline-token "<token>" --watermark "<watermark>" |
| 73 | ``` |
| 74 | |
| 75 | - **`directline_token`** is bound to the conversation — do NOT fetch a new token. Always reuse from the previous response. |
| 76 | - **`watermark`** tracks seen activities — pass it to avoid duplicates. |
| 77 | - Tokens expire after **~30 minutes**. If expired, start a new conversation (omit `--conversation-id`). |
| 78 | |
| 79 | ## Error Handling |
| 80 | |
| 81 | | Error | Cause | Resolution | |
| 82 | |-------|-------|------------| |
| 83 | | `Token endpoint rejected` | Agent not published or wrong URL | Verify agent is published | |
| 84 | | `Conversation not found` | Token expired (>30 min) | Start a new conversation | |