Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/nuget/dotnet/packages/Microsoft.T…
Browse files Browse the repository at this point in the history
…eamsAI/production-32a9be39d8
  • Loading branch information
singhk97 authored Jan 31, 2025
2 parents ec08168 + 321cd93 commit 6c60156
Show file tree
Hide file tree
Showing 35 changed files with 757 additions and 211 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup NodeJS ${{ env.node-version }}
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: ${{ env.node-version }}
- name: Install Dependencies
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/dotnet-codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Initialize CodeQL
uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
languages: csharp
- name: Setup .NET
Expand All @@ -50,6 +50,6 @@ jobs:
working-directory: dotnet/packages/Microsoft.TeamsAI/
run: dotnet build Microsoft.Teams.AI.sln --configuration Release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
category: "/language:csharp"
2 changes: 1 addition & 1 deletion .github/workflows/js-build-test-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup NodeJS ${{ matrix.node-version }}
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/js-codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ jobs:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Initialize CodeQL
uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
category: "/language:javascript"
4 changes: 2 additions & 2 deletions .github/workflows/python-codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ jobs:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Initialize CodeQL
uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
languages: python
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
category: "/language:python"
2 changes: 1 addition & 1 deletion .github/workflows/scorecards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@ jobs:

# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
sarif_file: results.sarif
2 changes: 2 additions & 0 deletions getting-started/CONCEPTS/STREAMING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ There are three parts to streaming:

## Sample Bots
- [C# Streaming ChefBot](https://github.com/microsoft/teams-ai/tree/main/dotnet/samples/04.ai.g.teamsChefBot-streaming)
- [C# Streaming + Tools LightBot](https://github.com/microsoft/teams-ai/blob/main/dotnet/samples/04.ai.c.actionMapping.lightBot)
- [JS Streaming ChefBot](https://github.com/microsoft/teams-ai/tree/main/js/samples/04.ai-apps/i.teamsChefBot-streaming)
- [JS Streaming+Tools LightBot](https://github.com/microsoft/teams-ai/tree/main/js/samples/03.ai-concepts/c.actionMapping-lightBot)
- [Python Streaming ListBot](https://github.com/microsoft/teams-ai/tree/main/python/samples/04.ai.h.chainedActions.listBot-streaming)
- [Python Streaming+Tools LightBot](https://github.com/microsoft/teams-ai/tree/main/python/samples/04.ai.c.actionMapping.lightBot)

## Streaming Response Class
The `StreamingResponse` class is the helper class for streaming responses to the client. The class is used to send a series of updates to the client in a single response. If you are using your own custom model, you can directly instantiate and manage this class to stream responses.
Expand Down
11 changes: 9 additions & 2 deletions js/packages/teams-ai/src/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1021,14 +1021,18 @@ export class Application<TState extends TurnState = TurnState> {
public startTypingTimer(context: TurnContext): void {
if (context.activity.type == ActivityTypes.Message && !this._typingTimer) {
// Listen for outgoing activities
context.onSendActivities((context, activities, next) => {
context.onSendActivities(async (context, activities, next) => {
// Listen for any messages to be sent from the bot
if (timerRunning) {
for (let i = 0; i < activities.length; i++) {
if (activities[i].type == ActivityTypes.Message || activities[i].channelData?.streamType) {
// Stop the timer
this.stopTypingTimer();
timerRunning = false;

// Wait for the last "typing" activity to finish sending
// - This prevents a race condition that results in the typing indicator being stuck on.
await lastSend;
break;
}
}
Expand All @@ -1038,17 +1042,20 @@ export class Application<TState extends TurnState = TurnState> {
});

let timerRunning = true;
let lastSend: Promise<any> = Promise.resolve();
const onTimeout = async () => {
try {
// Send typing activity
await context.sendActivity({ type: ActivityTypes.Typing });
lastSend = context.sendActivity({ type: ActivityTypes.Typing });
await lastSend;
} catch (err) {
// Seeing a random proxy violation error from the context object. This is because
// we're in the middle of sending an activity on a background thread when the turn ends.
// The context object throws when we try to update "this.responded = true". We can just
// eat the error but lets make sure our states cleaned up a bit.
this._typingTimer = undefined;
timerRunning = false;
lastSend = Promise.resolve();
}

// Restart timer
Expand Down
18 changes: 9 additions & 9 deletions python/packages/ai/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions python/packages/ai/teams/ai/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ async def _on_say_command(
for i, citation in enumerate(msg_context.citations):
citations.append(
ClientCitation(
position=f"{i + 1}",
position=i + 1,
appearance=Appearance(
name=citation.title or f"Document {i + 1}",
abstract=snippet(citation.content, 477),
Expand All @@ -315,10 +315,14 @@ async def _on_say_command(

# If there are citations, filter out the citations unused in content.
referenced_citations = get_used_citations(content_text, citations)
channel_data = {}
channel_data: Dict[str, Any] = {}

if is_teams_channel:
channel_data["feedbackLoopEnabled"] = self._options.enable_feedback_loop
if self._options.enable_feedback_loop and not self._options.feedback_loop_type:
channel_data["feedbackLoopEnabled"] = self._options.enable_feedback_loop

if self._options.feedback_loop_type:
channel_data["feedbackLoop"] = {"type": self._options.feedback_loop_type}

await context.send_activity(
Activity(
Expand Down
4 changes: 3 additions & 1 deletion python/packages/ai/teams/ai/ai_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Generic, TypeVar
from typing import Generic, Literal, Optional, TypeVar

from ..state import TurnState
from .moderators.default_moderator import DefaultModerator
Expand Down Expand Up @@ -40,3 +40,5 @@ class AIOptions(Generic[StateT]):
Optional. If true, the AI system will enable the feedback loop in Teams that
allows a user to give thumbs up or down to a response.
"""

feedback_loop_type: Optional[Literal["default", "custom"]] = None
12 changes: 11 additions & 1 deletion python/packages/ai/teams/ai/citations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
from .citations import (
AIEntity,
Appearance,
AppearanceImage,
ClientCitation,
ClientCitationIconName,
Pattern,
SensitivityUsageInfo,
)

__all__ = ["ClientCitation", "Appearance", "SensitivityUsageInfo", "Pattern", "AIEntity"]
__all__ = [
"ClientCitation",
"ClientCitationIconName",
"Appearance",
"AppearanceImage",
"SensitivityUsageInfo",
"Pattern",
"AIEntity",
]
67 changes: 57 additions & 10 deletions python/packages/ai/teams/ai/citations/citations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional
from typing import Literal, Optional, Union

from botbuilder.schema import Entity
from msrest.serialization import Model
Expand Down Expand Up @@ -47,11 +47,11 @@ class ClientCitation(Model):

_attribute_map = {
"type_": {"key": "@type", "type": "str"},
"position": {"key": "position", "type": "str"},
"position": {"key": "position", "type": "int"},
"appearance": {"key": "appearance", "type": "Appearance"},
}

position: str
position: int
appearance: Appearance
type_: str = field(default="Claim", metadata={"alias": "@type"}, init=False, repr=False)

Expand All @@ -63,13 +63,13 @@ class Appearance(Model):
Attributes:
@type (str): Required; must be 'DigitalDocument'
name (str): The name of the document
name (str): The name of the document. (max length 80)
text (str): Optional; the appearance text of the citation.
url (str): The url of the document
abstract (str): Content of the citation. Must be clipped if longer than 480 characters
abstract (str): Extract of the referenced content. (max length 160)
encodingFormat (str): Encoding format of the `citation.appearance.text` field.
image (str): Used for icon; for now it is ignored
keywords (list[str]): The optional keywords to the citation
image (AppearanceImage): Information about the citation’s icon.
keywords (list[str]): Optional; set by developer. (max length 3) (max keyword length 28)
usageInfo (SensitivityUsageInfo): The optional sensitivity content information
"""

Expand All @@ -82,20 +82,44 @@ class Appearance(Model):
"text": {"key": "text", "type": "str"},
"url": {"key": "url", "type": "str"},
"encoding_format": {"key": "encodingFormat", "type": "str"},
"image": {"key": "image", "type": "str"},
"image": {"key": "image", "type": "AppearanceImage"},
}

name: str
abstract: str
keywords: Optional[list[str]] = field(default=None)
text: Optional[str] = field(default=None)
url: Optional[str] = field(default=None)
image: Optional[str] = field(default=None)
encoding_format: Optional[str] = field(default=None)
image: Optional[AppearanceImage] = field(default=None)
encoding_format: Optional[
Union[
Literal["text/html"],
Literal["application/vnd.microsoft.card.adaptive"],
]
] = field(default=None)
usage_info: Optional[SensitivityUsageInfo] = field(default=None)
type_: str = field(default="DigitalDocument", metadata={"alias": "@type"})


@dataclass
class AppearanceImage(Model):
"""
Represents how the citation will be rendered
Attributes:
@type (str): Required; must be 'ImageObject'
name (str): The image/icon name
"""

_attribute_map = {
"type_": {"key": "@type", "type": "str"},
"name": {"key": "name", "type": "str"},
}

name: ClientCitationIconName
type_: str = field(default="ImageObject", metadata={"alias": "@type"})


@dataclass
class SensitivityUsageInfo(Model):
"""
Expand Down Expand Up @@ -144,3 +168,26 @@ class Pattern(Model):
name: str
term_code: str
type_: str = field(default="DefinedTerm", metadata={"alias": "@type"})


ClientCitationIconName = Union[
Literal["Microsoft Workd"],
Literal["Microsoft Excel"],
Literal["Microsoft PowerPoint"],
Literal["Microsoft Visio"],
Literal["Microsoft Loop"],
Literal["Microsoft Whiteboard"],
Literal["Adobe Illustrator"],
Literal["Adobe Photoshop"],
Literal["Adobe InDesign"],
Literal["Adobe Flash"],
Literal["Sketch"],
Literal["Source Code"],
Literal["Image"],
Literal["GIF"],
Literal["Video"],
Literal["Sound"],
Literal["ZIP"],
Literal["Text"],
Literal["PDF"],
]
Loading

0 comments on commit 6c60156

Please sign in to comment.