chore: publish from staged [skip ci]

This commit is contained in:
github-actions[bot]
2026-02-19 04:11:47 +00:00
parent 8ac0e41cb0
commit 812febf350
185 changed files with 33454 additions and 0 deletions

View File

@@ -0,0 +1,421 @@
---
mode: 'agent'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems']
description: 'Add GET, POST, PATCH, and DELETE operations to a TypeSpec API plugin with proper routing, parameters, and adaptive cards'
model: 'gpt-4.1'
tags: [typespec, m365-copilot, api-plugin, rest-operations, crud]
---
# Add TypeSpec API Operations
Add RESTful operations to an existing TypeSpec API plugin for Microsoft 365 Copilot.
## Adding GET Operations
### Simple GET - List All Items
```typescript
/**
* List all items.
*/
@route("/items")
@get op listItems(): Item[];
```
### GET with Query Parameter - Filter Results
```typescript
/**
* List items filtered by criteria.
* @param userId Optional user ID to filter items
*/
@route("/items")
@get op listItems(@query userId?: integer): Item[];
```
### GET with Path Parameter - Get Single Item
```typescript
/**
* Get a specific item by ID.
* @param id The ID of the item to retrieve
*/
@route("/items/{id}")
@get op getItem(@path id: integer): Item;
```
### GET with Adaptive Card
```typescript
/**
* List items with adaptive card visualization.
*/
@route("/items")
@card(#{
dataPath: "$",
title: "$.title",
file: "item-card.json"
})
@get op listItems(): Item[];
```
**Create the Adaptive Card** (`appPackage/item-card.json`):
```json
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5",
"body": [
{
"type": "Container",
"$data": "${$root}",
"items": [
{
"type": "TextBlock",
"text": "**${if(title, title, 'N/A')}**",
"wrap": true
},
{
"type": "TextBlock",
"text": "${if(description, description, 'N/A')}",
"wrap": true
}
]
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "View Details",
"url": "https://example.com/items/${id}"
}
]
}
```
## Adding POST Operations
### Simple POST - Create Item
```typescript
/**
* Create a new item.
* @param item The item to create
*/
@route("/items")
@post op createItem(@body item: CreateItemRequest): Item;
model CreateItemRequest {
title: string;
description?: string;
userId: integer;
}
```
### POST with Confirmation
```typescript
/**
* Create a new item with confirmation.
*/
@route("/items")
@post
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Create Item",
body: """
Are you sure you want to create this item?
* **Title**: {{ function.parameters.item.title }}
* **User ID**: {{ function.parameters.item.userId }}
"""
}
})
op createItem(@body item: CreateItemRequest): Item;
```
## Adding PATCH Operations
### Simple PATCH - Update Item
```typescript
/**
* Update an existing item.
* @param id The ID of the item to update
* @param item The updated item data
*/
@route("/items/{id}")
@patch op updateItem(
@path id: integer,
@body item: UpdateItemRequest
): Item;
model UpdateItemRequest {
title?: string;
description?: string;
status?: "active" | "completed" | "archived";
}
```
### PATCH with Confirmation
```typescript
/**
* Update an item with confirmation.
*/
@route("/items/{id}")
@patch
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Update Item",
body: """
Updating item #{{ function.parameters.id }}:
* **Title**: {{ function.parameters.item.title }}
* **Status**: {{ function.parameters.item.status }}
"""
}
})
op updateItem(
@path id: integer,
@body item: UpdateItemRequest
): Item;
```
## Adding DELETE Operations
### Simple DELETE
```typescript
/**
* Delete an item.
* @param id The ID of the item to delete
*/
@route("/items/{id}")
@delete op deleteItem(@path id: integer): void;
```
### DELETE with Confirmation
```typescript
/**
* Delete an item with confirmation.
*/
@route("/items/{id}")
@delete
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Delete Item",
body: """
⚠️ Are you sure you want to delete item #{{ function.parameters.id }}?
This action cannot be undone.
"""
}
})
op deleteItem(@path id: integer): void;
```
## Complete CRUD Example
### Define the Service and Models
```typescript
@service
@server("https://api.example.com")
@actions(#{
nameForHuman: "Items API",
descriptionForHuman: "Manage items",
descriptionForModel: "Read, create, update, and delete items"
})
namespace ItemsAPI {
// Models
model Item {
@visibility(Lifecycle.Read)
id: integer;
userId: integer;
title: string;
description?: string;
status: "active" | "completed" | "archived";
@format("date-time")
createdAt: utcDateTime;
@format("date-time")
updatedAt?: utcDateTime;
}
model CreateItemRequest {
userId: integer;
title: string;
description?: string;
}
model UpdateItemRequest {
title?: string;
description?: string;
status?: "active" | "completed" | "archived";
}
// Operations
@route("/items")
@card(#{ dataPath: "$", title: "$.title", file: "item-card.json" })
@get op listItems(@query userId?: integer): Item[];
@route("/items/{id}")
@card(#{ dataPath: "$", title: "$.title", file: "item-card.json" })
@get op getItem(@path id: integer): Item;
@route("/items")
@post
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Create Item",
body: "Creating: **{{ function.parameters.item.title }}**"
}
})
op createItem(@body item: CreateItemRequest): Item;
@route("/items/{id}")
@patch
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Update Item",
body: "Updating item #{{ function.parameters.id }}"
}
})
op updateItem(@path id: integer, @body item: UpdateItemRequest): Item;
@route("/items/{id}")
@delete
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Delete Item",
body: "⚠️ Delete item #{{ function.parameters.id }}?"
}
})
op deleteItem(@path id: integer): void;
}
```
## Advanced Features
### Multiple Query Parameters
```typescript
@route("/items")
@get op listItems(
@query userId?: integer,
@query status?: "active" | "completed" | "archived",
@query limit?: integer,
@query offset?: integer
): ItemList;
model ItemList {
items: Item[];
total: integer;
hasMore: boolean;
}
```
### Header Parameters
```typescript
@route("/items")
@get op listItems(
@header("X-API-Version") apiVersion?: string,
@query userId?: integer
): Item[];
```
### Custom Response Models
```typescript
@route("/items/{id}")
@delete op deleteItem(@path id: integer): DeleteResponse;
model DeleteResponse {
success: boolean;
message: string;
deletedId: integer;
}
```
### Error Responses
```typescript
model ErrorResponse {
error: {
code: string;
message: string;
details?: string[];
};
}
@route("/items/{id}")
@get op getItem(@path id: integer): Item | ErrorResponse;
```
## Testing Prompts
After adding operations, test with these prompts:
**GET Operations:**
- "List all items and show them in a table"
- "Show me items for user ID 1"
- "Get the details of item 42"
**POST Operations:**
- "Create a new item with title 'My Task' for user 1"
- "Add an item: title 'New Feature', description 'Add login'"
**PATCH Operations:**
- "Update item 10 with title 'Updated Title'"
- "Change the status of item 5 to completed"
**DELETE Operations:**
- "Delete item 99"
- "Remove the item with ID 15"
## Best Practices
### Parameter Naming
- Use descriptive parameter names: `userId` not `uid`
- Be consistent across operations
- Use optional parameters (`?`) for filters
### Documentation
- Add JSDoc comments to all operations
- Describe what each parameter does
- Document expected responses
### Models
- Use `@visibility(Lifecycle.Read)` for read-only fields like `id`
- Use `@format("date-time")` for date fields
- Use union types for enums: `"active" | "completed"`
- Make optional fields explicit with `?`
### Confirmations
- Always add confirmations to destructive operations (DELETE, PATCH)
- Show key details in confirmation body
- Use warning emoji (⚠️) for irreversible actions
### Adaptive Cards
- Keep cards simple and focused
- Use conditional rendering with `${if(..., ..., 'N/A')}`
- Include action buttons for common next steps
- Test data binding with actual API responses
### Routing
- Use RESTful conventions:
- `GET /items` - List
- `GET /items/{id}` - Get one
- `POST /items` - Create
- `PATCH /items/{id}` - Update
- `DELETE /items/{id}` - Delete
- Group related operations in the same namespace
- Use nested routes for hierarchical resources
## Common Issues
### Issue: Parameter not showing in Copilot
**Solution**: Check parameter is properly decorated with `@query`, `@path`, or `@body`
### Issue: Adaptive card not rendering
**Solution**: Verify file path in `@card` decorator and check JSON syntax
### Issue: Confirmation not appearing
**Solution**: Ensure `@capabilities` decorator is properly formatted with confirmation object
### Issue: Model property not appearing in response
**Solution**: Check if property needs `@visibility(Lifecycle.Read)` or remove it if it should be writable

View File

@@ -0,0 +1,94 @@
---
mode: 'agent'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems']
description: 'Generate a complete TypeSpec declarative agent with instructions, capabilities, and conversation starters for Microsoft 365 Copilot'
model: 'gpt-4.1'
tags: [typespec, m365-copilot, declarative-agent, agent-development]
---
# Create TypeSpec Declarative Agent
Create a complete TypeSpec declarative agent for Microsoft 365 Copilot with the following structure:
## Requirements
Generate a `main.tsp` file with:
1. **Agent Declaration**
- Use `@agent` decorator with a descriptive name and description
- Name should be 100 characters or less
- Description should be 1,000 characters or less
2. **Instructions**
- Use `@instructions` decorator with clear behavioral guidelines
- Define the agent's role, expertise, and personality
- Specify what the agent should and shouldn't do
- Keep under 8,000 characters
3. **Conversation Starters**
- Include 2-4 `@conversationStarter` decorators
- Each with a title and example query
- Make them diverse and showcase different capabilities
4. **Capabilities** (based on user needs)
- `WebSearch` - for web content with optional site scoping
- `OneDriveAndSharePoint` - for document access with URL filtering
- `TeamsMessages` - for Teams channel/chat access
- `Email` - for email access with folder filtering
- `People` - for organization people search
- `CodeInterpreter` - for Python code execution
- `GraphicArt` - for image generation
- `GraphConnectors` - for Copilot connector content
- `Dataverse` - for Dataverse data access
- `Meetings` - for meeting content access
## Template Structure
```typescript
import "@typespec/http";
import "@typespec/openapi3";
import "@microsoft/typespec-m365-copilot";
using TypeSpec.Http;
using TypeSpec.M365.Copilot.Agents;
@agent({
name: "[Agent Name]",
description: "[Agent Description]"
})
@instructions("""
[Detailed instructions about agent behavior, role, and guidelines]
""")
@conversationStarter(#{
title: "[Starter Title 1]",
text: "[Example query 1]"
})
@conversationStarter(#{
title: "[Starter Title 2]",
text: "[Example query 2]"
})
namespace [AgentName] {
// Add capabilities as operations here
op capabilityName is AgentCapabilities.[CapabilityType]<[Parameters]>;
}
```
## Best Practices
- Use descriptive, role-based agent names (e.g., "Customer Support Assistant", "Research Helper")
- Write instructions in second person ("You are...")
- Be specific about the agent's expertise and limitations
- Include diverse conversation starters that showcase different features
- Only include capabilities the agent actually needs
- Scope capabilities (URLs, folders, etc.) when possible for better performance
- Use triple-quoted strings for multi-line instructions
## Examples
Ask the user:
1. What is the agent's purpose and role?
2. What capabilities does it need?
3. What knowledge sources should it access?
4. What are typical user interactions?
Then generate the complete TypeSpec agent definition.

View File

@@ -0,0 +1,167 @@
---
mode: 'agent'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems']
description: 'Generate a TypeSpec API plugin with REST operations, authentication, and Adaptive Cards for Microsoft 365 Copilot'
model: 'gpt-4.1'
tags: [typespec, m365-copilot, api-plugin, rest-api]
---
# Create TypeSpec API Plugin
Create a complete TypeSpec API plugin for Microsoft 365 Copilot that integrates with external REST APIs.
## Requirements
Generate TypeSpec files with:
### main.tsp - Agent Definition
```typescript
import "@typespec/http";
import "@typespec/openapi3";
import "@microsoft/typespec-m365-copilot";
import "./actions.tsp";
using TypeSpec.Http;
using TypeSpec.M365.Copilot.Agents;
using TypeSpec.M365.Copilot.Actions;
@agent({
name: "[Agent Name]",
description: "[Description]"
})
@instructions("""
[Instructions for using the API operations]
""")
namespace [AgentName] {
// Reference operations from actions.tsp
op operation1 is [APINamespace].operationName;
}
```
### actions.tsp - API Operations
```typescript
import "@typespec/http";
import "@microsoft/typespec-m365-copilot";
using TypeSpec.Http;
using TypeSpec.M365.Copilot.Actions;
@service
@actions(#{
nameForHuman: "[API Display Name]",
descriptionForModel: "[Model description]",
descriptionForHuman: "[User description]"
})
@server("[API_BASE_URL]", "[API Name]")
@useAuth([AuthType]) // Optional
namespace [APINamespace] {
@route("[/path]")
@get
@action
op operationName(
@path param1: string,
@query param2?: string
): ResponseModel;
model ResponseModel {
// Response structure
}
}
```
## Authentication Options
Choose based on API requirements:
1. **No Authentication** (Public APIs)
```typescript
// No @useAuth decorator needed
```
2. **API Key**
```typescript
@useAuth(ApiKeyAuth<ApiKeyLocation.header, "X-API-Key">)
```
3. **OAuth2**
```typescript
@useAuth(OAuth2Auth<[{
type: OAuth2FlowType.authorizationCode;
authorizationUrl: "https://oauth.example.com/authorize";
tokenUrl: "https://oauth.example.com/token";
refreshUrl: "https://oauth.example.com/token";
scopes: ["read", "write"];
}]>)
```
4. **Registered Auth Reference**
```typescript
@useAuth(Auth)
@authReferenceId("registration-id-here")
model Auth is ApiKeyAuth<ApiKeyLocation.header, "X-API-Key">
```
## Function Capabilities
### Confirmation Dialog
```typescript
@capabilities(#{
confirmation: #{
type: "AdaptiveCard",
title: "Confirm Action",
body: """
Are you sure you want to perform this action?
* **Parameter**: {{ function.parameters.paramName }}
"""
}
})
```
### Adaptive Card Response
```typescript
@card(#{
dataPath: "$.items",
title: "$.title",
url: "$.link",
file: "cards/card.json"
})
```
### Reasoning & Response Instructions
```typescript
@reasoning("""
Consider user's context when calling this operation.
Prioritize recent items over older ones.
""")
@responding("""
Present results in a clear table format with columns: ID, Title, Status.
Include a summary count at the end.
""")
```
## Best Practices
1. **Operation Names**: Use clear, action-oriented names (listProjects, createTicket)
2. **Models**: Define TypeScript-like models for requests and responses
3. **HTTP Methods**: Use appropriate verbs (@get, @post, @patch, @delete)
4. **Paths**: Use RESTful path conventions with @route
5. **Parameters**: Use @path, @query, @header, @body appropriately
6. **Descriptions**: Provide clear descriptions for model understanding
7. **Confirmations**: Add for destructive operations (delete, update critical data)
8. **Cards**: Use for rich visual responses with multiple data items
## Workflow
Ask the user:
1. What is the API base URL and purpose?
2. What operations are needed (CRUD operations)?
3. What authentication method does the API use?
4. Should confirmations be required for any operations?
5. Do responses need Adaptive Cards?
Then generate:
- Complete `main.tsp` with agent definition
- Complete `actions.tsp` with API operations and models
- Optional `cards/card.json` if Adaptive Cards are needed