Skip to content
Merged
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
12 changes: 3 additions & 9 deletions .github/workflows/python-claude-sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,10 @@ jobs:
with:
python-version: '3.11'

- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.cargo/bin" >> $GITHUB_PATH

- name: Create virtual environment
run: uv venv

- name: Install dependencies
run: |
uv pip install -e .
python -m pip install --upgrade pip
pip install --pre -e .

- name: Check Python syntax
run: |
Expand Down Expand Up @@ -77,6 +70,7 @@ jobs:
done

- name: Validate imports
continue-on-error: true
run: |
python -c "
import sys
Expand Down
43 changes: 40 additions & 3 deletions nodejs/claude/sample-agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getObservabilityAuthenticationScope } from '@microsoft/agents-a365-runt

// Notification Imports
import '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity } from '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity, NotificationType, createEmailResponseActivity } from '@microsoft/agents-a365-notifications';

import tokenCache, { createAgenticTokenCacheKey } from './token-cache';
import { Client, getClient } from './client';
Expand Down Expand Up @@ -101,8 +101,45 @@ export class MyAgent extends AgentApplication<TurnState> {
}

async handleAgentNotificationActivity(context: TurnContext, state: TurnState, agentNotificationActivity: AgentNotificationActivity) {
context.sendActivity("Received an AgentNotification!");
/* your logic here... */
switch (agentNotificationActivity.notificationType) {
case NotificationType.EmailNotification:
await this.handleEmailNotification(context, state, agentNotificationActivity);
break;
default:
await context.sendActivity(`Received notification of type: ${agentNotificationActivity.notificationType}`);
}
}

private async handleEmailNotification(context: TurnContext, state: TurnState, activity: AgentNotificationActivity): Promise<void> {
const emailNotification = activity.emailNotification;

if (!emailNotification) {
const errorResponse = createEmailResponseActivity('I could not find the email notification details.');
await context.sendActivity(errorResponse);
return;
}

try {
const client: Client = await getClient(this.authorization, MyAgent.authHandlerName, context);

// First, retrieve the email content
const emailContent = await client.invokeAgentWithScope(
`You have a new email from ${context.activity.from?.name} with id '${emailNotification.id}', ` +
`ConversationId '${emailNotification.conversationId}'. Please retrieve this message and return it in text format.`
);

// Then process the email
const response = await client.invokeAgentWithScope(
`You have received the following email. Please follow any instructions in it. ${emailContent}`
);

const emailResponseActivity = createEmailResponseActivity(response || 'I have processed your email but do not have a response at this time.');
await context.sendActivity(emailResponseActivity);
} catch (error) {
console.error('Email notification error:', error);
const errorResponse = createEmailResponseActivity('Unable to process your email at this time.');
await context.sendActivity(errorResponse);
}
}
}

Expand Down
88 changes: 88 additions & 0 deletions nodejs/devin/sample-agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ import {
TurnContext,
TurnState,
} from "@microsoft/agents-hosting";
import '@microsoft/agents-a365-notifications';
import {
AgentNotificationActivity,
NotificationType,
createEmailResponseActivity,
} from "@microsoft/agents-a365-notifications";
import { Stream } from "stream";
import { v4 as uuidv4 } from "uuid";
import { devinClient } from "./devin-client";
Expand Down Expand Up @@ -119,6 +125,22 @@ export class A365Agent extends AgentApplication<ApplicationTurnState> {
}
);

// Handle agent notifications
this.onAgentNotification(
"agents:*",
async (
context: TurnContext,
state: ApplicationTurnState,
agentNotificationActivity: AgentNotificationActivity
) => {
await this.handleAgentNotificationActivity(
context,
state,
agentNotificationActivity
);
}
);

// Handle installation activities
this.onActivity(
ActivityTypes.InstallationUpdate,
Expand Down Expand Up @@ -198,6 +220,72 @@ export class A365Agent extends AgentApplication<ApplicationTurnState> {
}
}

/**
* Handles agent notification activities.
*/
async handleAgentNotificationActivity(
context: TurnContext,
state: ApplicationTurnState,
agentNotificationActivity: AgentNotificationActivity
): Promise<void> {
switch (agentNotificationActivity.notificationType) {
case NotificationType.EmailNotification:
await this.handleEmailNotification(context, agentNotificationActivity);
break;
default:
await context.sendActivity(
`Received notification of type: ${agentNotificationActivity.notificationType}`
);
}
}

/**
* Handles email notification activities with proper EmailResponse.
*/
private async handleEmailNotification(
context: TurnContext,
activity: AgentNotificationActivity
): Promise<void> {
const emailNotification = activity.emailNotification;

if (!emailNotification) {
const errorResponse = createEmailResponseActivity(
"I could not find the email notification details."
);
await context.sendActivity(errorResponse);
return;
}

try {
// Collect the response from Devin using a stream
let responseContent = "";
const responseStream = new Stream()
.on("data", (chunk) => {
responseContent += chunk as string;
})
.on("error", (error) => {
console.error("Stream error:", error);
});

// Process the email notification with Devin
const prompt = `You have a new email from ${context.activity.from?.name} with id '${emailNotification.id}', ` +
`ConversationId '${emailNotification.conversationId}'. Please process this email and provide a helpful response.`;

await devinClient.invokeAgent(prompt, responseStream);

const emailResponseActivity = createEmailResponseActivity(
responseContent || "I have processed your email but do not have a response at this time."
);
await context.sendActivity(emailResponseActivity);
} catch (error) {
console.error("Email notification error:", error);
const errorResponse = createEmailResponseActivity(
"Unable to process your email at this time."
);
await context.sendActivity(errorResponse);
}
}

/**
* Handles agent installation and removal events.
*/
Expand Down
43 changes: 40 additions & 3 deletions nodejs/langchain/sample-agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ActivityTypes } from '@microsoft/agents-activity';

// Notification Imports
import '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity } from '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity, NotificationType, createEmailResponseActivity } from '@microsoft/agents-a365-notifications';
// Observability Imports
import { BaggageBuilder } from '@microsoft/agents-a365-observability';
import { AgenticTokenCacheInstance, BaggageBuilderUtils } from '@microsoft/agents-a365-observability-hosting';
Expand Down Expand Up @@ -99,8 +99,45 @@ export class A365Agent extends AgentApplication<TurnState> {
}

async handleAgentNotificationActivity(context: TurnContext, state: TurnState, agentNotificationActivity: AgentNotificationActivity) {
context.sendActivity("Recieved an AgentNotification!");
/* your logic here... */
switch (agentNotificationActivity.notificationType) {
case NotificationType.EmailNotification:
await this.handleEmailNotification(context, state, agentNotificationActivity);
break;
default:
await context.sendActivity(`Received notification of type: ${agentNotificationActivity.notificationType}`);
}
}

private async handleEmailNotification(context: TurnContext, state: TurnState, activity: AgentNotificationActivity): Promise<void> {
const emailNotification = activity.emailNotification;

if (!emailNotification) {
const errorResponse = createEmailResponseActivity('I could not find the email notification details.');
await context.sendActivity(errorResponse);
return;
}

try {
const client: Client = await getClient(this.authorization, A365Agent.authHandlerName, context);

// First, retrieve the email content
const emailContent = await client.invokeInferenceScope(
`You have a new email from ${context.activity.from?.name} with id '${emailNotification.id}', ` +
`ConversationId '${emailNotification.conversationId}'. Please retrieve this message and return it in text format.`
);

// Then process the email
const response = await client.invokeInferenceScope(
`You have received the following email. Please follow any instructions in it. ${emailContent}`
);

const emailResponseActivity = createEmailResponseActivity(response || 'I have processed your email but do not have a response at this time.');
await context.sendActivity(emailResponseActivity);
} catch (error) {
console.error('Email notification error:', error);
const errorResponse = createEmailResponseActivity('Unable to process your email at this time.');
await context.sendActivity(errorResponse);
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions nodejs/n8n/sample-agent/src/n8nAgent.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { AgentNotificationActivity, NotificationType, createAgentNotificationActivity } from '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity, NotificationType, createAgentNotificationActivity, createEmailResponseActivity } from '@microsoft/agents-a365-notifications';
import { AgentApplication, TurnContext, TurnState } from '@microsoft/agents-hosting';
import { N8nClient } from './n8nClient';
import { McpToolRegistrationService, McpServer } from './mcpToolRegistrationService';
Expand Down Expand Up @@ -140,7 +140,8 @@ export class N8nAgent {
`You have received the following email. Please follow any instructions in it. ${emailContent}`
);

await turnContext.sendActivity(response);
const emailResponseActivity = createEmailResponseActivity(response);
await turnContext.sendActivity(emailResponseActivity);
}

async getN8nClient(turnContext: TurnContext): Promise<N8nClient> {
Expand Down
43 changes: 40 additions & 3 deletions nodejs/openai/sample-agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getObservabilityAuthenticationScope } from '@microsoft/agents-a365-runt

// Notification Imports
import '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity } from '@microsoft/agents-a365-notifications';
import { AgentNotificationActivity, NotificationType, createEmailResponseActivity } from '@microsoft/agents-a365-notifications';

import { Client, getClient } from './client';
import tokenCache, { createAgenticTokenCacheKey } from './token-cache';
Expand Down Expand Up @@ -120,8 +120,45 @@ export class MyAgent extends AgentApplication<TurnState> {
}

async handleAgentNotificationActivity(context: TurnContext, state: TurnState, agentNotificationActivity: AgentNotificationActivity) {
context.sendActivity("Received an AgentNotification!");
/* your logic here... */
switch (agentNotificationActivity.notificationType) {
case NotificationType.EmailNotification:
await this.handleEmailNotification(context, state, agentNotificationActivity);
break;
default:
await context.sendActivity(`Received notification of type: ${agentNotificationActivity.notificationType}`);
}
}

private async handleEmailNotification(context: TurnContext, state: TurnState, activity: AgentNotificationActivity): Promise<void> {
const emailNotification = activity.emailNotification;

if (!emailNotification) {
const errorResponse = createEmailResponseActivity('I could not find the email notification details.');
await context.sendActivity(errorResponse);
return;
}

try {
const client: Client = await getClient(this.authorization, MyAgent.authHandlerName, context);

// First, retrieve the email content
const emailContent = await client.invokeAgentWithScope(
`You have a new email from ${context.activity.from?.name} with id '${emailNotification.id}', ` +
`ConversationId '${emailNotification.conversationId}'. Please retrieve this message and return it in text format.`
);

// Then process the email
const response = await client.invokeAgentWithScope(
`You have received the following email. Please follow any instructions in it. ${emailContent}`
);

const emailResponseActivity = createEmailResponseActivity(response || 'I have processed your email but do not have a response at this time.');
await context.sendActivity(emailResponseActivity);
} catch (error) {
console.error('Email notification error:', error);
const errorResponse = createEmailResponseActivity('Unable to process your email at this time.');
await context.sendActivity(errorResponse);
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion nodejs/perplexity/sample-agent/src/notificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { TurnContext, TurnState } from "@microsoft/agents-hosting";
import {
AgentNotificationActivity,
NotificationType,
createEmailResponseActivity,
} from "@microsoft/agents-a365-notifications";
import type { InvokeAgentScope } from "@microsoft/agents-a365-observability";

Expand Down Expand Up @@ -207,7 +208,9 @@ export class NotificationService {
"EmailNotification_Success",
]);

await stream.sendFinal(response);
// Send email response with proper EmailResponse entity
const emailResponseActivity = createEmailResponseActivity(response);
await turnContext.sendActivity(emailResponseActivity);
}

/* ------------------------------------------------------------------
Expand Down
Loading
Loading