mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
chore: publish from staged [skip ci]
This commit is contained in:
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user