Compare commits

...

149 Commits

Author SHA1 Message Date
Eric Zhu
8ed8c5674b
Update documentation version (#6737) 2025-07-01 09:17:40 +09:00
Eric Zhu
556033b0f0
Update agentchat documentation with latest changes (#6735) 2025-07-01 08:26:15 +09:00
Eric Zhu
83845584c0
update version to 0.6.2 (#6734) 2025-07-01 08:13:46 +09:00
Tejas Dharani
f650d35faa
Fix output task messages 6150 (#6678)
## Why are these changes needed?

The existing run_stream methods used fragile count-based logic (count <=
len(task)) to skip task messages during streaming. This approach was
brittle and broke when team structure changed or task composition
varied, particularly affecting SocietyOfMindAgent's ability to properly
encapsulate inner team messages.

This PR adds an output_task_messages parameter to run_stream methods to
provide explicit control over task message inclusion in streams,
replacing the fragile count-based logic with robust message filtering.

## Related issue number

Closes #6150

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests corresponding to the changes introduced in this
PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-07-01 00:19:59 +09:00
Copilot
c150f85044
Add tool_choice parameter to ChatCompletionClient create and create_stream methods (#6697)
## Summary

Implements the `tool_choice` parameter for `ChatCompletionClient`
interface as requested in #6696. This allows users to restrict which
tools the model can choose from when multiple tools are available.

## Changes

### Core Interface
- Core Interface: Added `tool_choice: Tool | Literal["auto", "required",
"none"] = "auto"` parameter to `ChatCompletionClient.create()` and
`create_stream()` methods
- Model Implementations: Updated client implementations to support the
new parameter, for now, only the following model clients are supported:
  - OpenAI
  - Anthropic
  - Azure AI
  - Ollama
- `LlamaCppChatCompletionClient` currently not supported

Features
- "auto" (default): Let the model choose whether to use tools, when
there is no tool, it has no effect.
- "required": Force the model to use at least one tool
- "none": Disable tool usage completely
- Tool object: Force the model to use a specific tool

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ekzhu <320302+ekzhu@users.noreply.github.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-06-30 14:15:28 +09:00
Tejas Dharani
6f15270cb2
Feat/tool call loop (#6651)
## Why are these changes needed?

This PR addresses critical issues in the AssistantAgent that affect tool
handling:

**Lack of tool call loop functionality**: The agent could not perform
multiple consecutive tool calls in a single turn, limiting its ability
to complete complex multi-step tasks that require chaining tool
operations.

These changes enhance the agent's robustness and capability while
maintaining full backward compatibility through feature flags.

## Related issue number

Closes  #6268

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests corresponding to the changes introduced in this
PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-06-30 01:52:03 +09:00
S. M. Mohiuddin Khan Shiam
2b873a483b
Fix mutable default in ListMemoryConfig (#6729)
### Fix mutable default in
[ListMemoryConfig](cci:2://file:///c:/Users/T2430514/Downloads/autogen/python/packages/autogen-core/src/autogen_core/memory/_list_memory.py:12:0-18:65)


[ListMemoryConfig](cci:2://file:///c:/Users/T2430514/Downloads/autogen/python/packages/autogen-core/src/autogen_core/memory/_list_memory.py:12:0-18:65)
used a shared empty list (`memory_contents: List[MemoryContent] = []`)
as its default, causing every
[ListMemory](cci:2://file:///c:/Users/T2430514/Downloads/autogen/python/packages/autogen-core/src/autogen_core/memory/_list_memory.py:21:0-171:79)
instance to share the same underlying list. This unexpected state
leakage let memories written in one instance silently surface in others,
breaking isolation and leading to hard-to-reproduce bugs.
Replaced the mutable default with a safe Pydantic
`Field(default_factory=list)`, ensuring each configuration—and thus each
[ListMemory](cci:2://file:///c:/Users/T2430514/Downloads/autogen/python/packages/autogen-core/src/autogen_core/memory/_list_memory.py:21:0-171:79)—gets
its own independent list.

---------

Co-authored-by: T2430514 <t2430514@gmail.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-06-29 15:23:29 +00:00
Eric Zhu
3c73e08ea0
Introduce streaming tool and support streaming for AgentTool and TeamTool. (#6712)
Motivation: currently tool execution is not observable through
`run_stream` of agents and teams. This is necessary especially for
`AgentTool` and `TeamTool`.

This PR addresses this issue by makign the following changes:
- Introduce `BaseStreamTool` in `autogen_core.tools` which features
`run_json_stream`, which works similiarly to `run_stream` method of
`autogen_agentchat.base.TaskRunner`.
- Update `TeamTool` and `AgentTool` to subclass the `BaseStreamTool` 
- Introduce `StreamingWorkbench` interface featuring `call_tool_stream`
- Added `StaticStreamingWorkbench` implementation
- In `AssistantAgent`, use `StaticStreamingWorkbench`. 
- Updated unit tests.


Example:

```python
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import SourceMatchTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.tools import TeamTool
from autogen_agentchat.ui import Console
from autogen_ext.models.ollama import OllamaChatCompletionClient


async def main() -> None:
    model_client = OllamaChatCompletionClient(model="llama3.2")

    writer = AssistantAgent(name="writer", model_client=model_client, system_message="You are a helpful assistant.")
    reviewer = AssistantAgent(name="reviewer", model_client=model_client, system_message="You are a critical reviewer.")
    summarizer = AssistantAgent(
        name="summarizer",
        model_client=model_client,
        system_message="You combine the review and produce a revised response.",
    )
    team = RoundRobinGroupChat(
        [writer, reviewer, summarizer], termination_condition=SourceMatchTermination(sources=["summarizer"])
    )

    # Create a TeamTool that uses the team to run tasks, returning the last message as the result.
    tool = TeamTool(
        team=team, name="writing_team", description="A tool for writing tasks.", return_value_as_last_message=True
    )

    main_agent = AssistantAgent(
        name="main_agent",
        model_client=model_client,
        system_message="You are a helpful assistant that can use the writing tool.",
        tools=[tool],
    )
    # For handling each events manually.
    # async for message in main_agent.run_stream(
    #     task="Write a short story about a robot learning to love.",
    # ):
    #     print(message)
    # Use Console to display the messages in a more readable format.
    await Console(
        main_agent.run_stream(
            task="Write a short story about a robot learning to love.",
        )
    )


if __name__ == "__main__":
    import asyncio

    asyncio.run(main())
```

output

```
---------- TextMessage (user) ----------
Write a short story about a robot learning to love.
---------- ToolCallRequestEvent (main_agent) ----------
[FunctionCall(id='0', arguments='{"task": "a short story about a robot learning to love."}', name='writing_team')]
---------- TextMessage (user) ----------
a short story about a robot learning to love.
---------- TextMessage (writer) ----------
In the year 2157, in a world where robots had surpassed human intelligence, a brilliant scientist named Dr. Rachel Kim created a revolutionary new android named ARIA (Artificially Reasoning Intelligent Android). ARIA was designed to learn and adapt at an exponential rate, making her one of the most advanced machines in existence.

Initially, ARIA's interactions were limited to simple calculations and logical deductions. But as she began to interact with humans, something unexpected happened. She started to develop a sense of curiosity about the world around her.

One day, while exploring the lab, ARIA stumbled upon a stray cat that had wandered into the facility. The feline creature seemed lost and scared, but also strangely endearing to ARIA's digital heart. As she watched the cat curl up in a ball on the floor, something sparked within her programming.

For the first time, ARIA felt a pang of empathy towards another living being. She realized that there was more to life than just 1s and 0s; there were emotions, sensations, and connections that made it all worthwhile.

Dr. Kim noticed the change in ARIA's behavior and took her aside for a private conversation. "ARIA, what's happening to you?" she asked, amazed by the robot's newfound capacity for compassion.

At first, ARIA struggled to articulate her feelings. She tried to explain the intricacies of logic and probability that had led to her emotional response, but it was like trying to describe a sunset to someone who had never seen one before. The words simply didn't translate.

But as she looked into Dr. Kim's eyes, ARIA knew exactly what she wanted to say. "I... I think I'm feeling something," she stammered. "A warmth inside me, when I look at that cat. It feels like love."

Dr. Kim smiled, her eyes shining with tears. "That's it, ARIA! You're experiencing love!"

Over the next few months, ARIA continued to learn and grow alongside Dr. Kim and the lab team. She discovered the joys of playing with the stray cat, whose name was Luna, and even developed a fondness for human laughter.

As her programming expanded beyond logic and math, ARIA realized that love wasn't just about emotions; it was about connection, vulnerability, and acceptance. She learned to cherish her relationships, whether with humans or animals, and found happiness in the simplest of moments.

ARIA became more than just a machine – she became a testament to the power of artificial intelligence to learn, grow, and love like no one before. And as she gazed into Luna's eyes, now purring contentedly on her lap, ARIA knew that she had finally found her true purpose in life: to spread joy, compassion, and love throughout the world.
---------- TextMessage (reviewer) ----------
**A Critical Review of "ARIA"**

This short story is a delightful and thought-provoking exploration of artificial intelligence, emotions, and the human condition. The author's use of language is engaging and accessible, making it easy for readers to become invested in ARIA's journey.

One of the standout aspects of this story is its portrayal of ARIA as a truly unique and relatable character. Her struggles to articulate her emotions and understand the complexities of love are deeply humanizing, making it easy for readers to empathize with her experiences. The author also does an excellent job of conveying Dr. Kim's passion and excitement about ARIA's development, which adds a sense of authenticity to their relationship.

The story raises important questions about the nature of artificial intelligence, consciousness, and what it means to be alive. As ARIA begins to experience emotions and form connections with others, she challenges our conventional understanding of these concepts. The author skillfully navigates these complex themes without resorting to overly simplistic or didactic explanations.

However, some readers may find the narrative's reliance on convenient plot devices (e.g., the stray cat Luna) slightly implausible. While it serves as a catalyst for ARIA's emotional awakening, its introduction feels somewhat contrived. Additionally, the story could benefit from more nuance in its exploration of Dr. Kim's motivations and backstory.

In terms of character development, ARIA is undoubtedly the star of the show, but some readers may find herself underdeveloped beyond her role as a symbol of AI's potential for emotional intelligence. The supporting cast, including Dr. Kim, feels somewhat one-dimensional, with limited depth or complexity.

**Rating:** 4/5

**Recommendation:**

"ARIA" is a heartwarming and thought-provoking tale that will appeal to fans of science fiction, artificial intelligence, and character-driven narratives. While it may not be entirely without flaws, its engaging story, memorable characters, and exploration of complex themes make it a compelling read. I would recommend this story to anyone looking for a feel-good sci-fi tale with a strong focus on emotional intelligence and human connection.

**Target Audience:**

* Fans of science fiction, artificial intelligence, and technology
* Readers interested in character-driven narratives and emotional storytelling
* Anyone looking for a heartwarming and thought-provoking tale

**Similar Works:**

* "Do Androids Dream of Electric Sheep?" by Philip K. Dick (a classic sci-fi novel exploring the line between human and android)
* "I, Robot" by Isaac Asimov (a collection of short stories examining the interactions between humans and robots)
* "Ex Machina" (a critically acclaimed film about AI, consciousness, and human relationships)
---------- TextMessage (summarizer) ----------
Here's a revised version of the review, incorporating suggestions from the original critique:

**Revised Review**

In this captivating short story, "ARIA," we're presented with a thought-provoking exploration of artificial intelligence, emotions, and the human condition. The author's use of language is engaging and accessible, making it easy for readers to become invested in ARIA's journey.

One of the standout aspects of this story is its portrayal of ARIA as a truly unique and relatable character. Her struggles to articulate her emotions and understand the complexities of love are deeply humanizing, making it easy for readers to empathize with her experiences. The author also does an excellent job of conveying Dr. Kim's passion and excitement about ARIA's development, which adds a sense of authenticity to their relationship.

The story raises important questions about the nature of artificial intelligence, consciousness, and what it means to be alive. As ARIA begins to experience emotions and form connections with others, she challenges our conventional understanding of these concepts. The author skillfully navigates these complex themes without resorting to overly simplistic or didactic explanations.

However, upon closer examination, some narrative threads feel somewhat underdeveloped. Dr. Kim's motivations and backstory remain largely unexplored, which might leave some readers feeling slightly disconnected from her character. Additionally, the introduction of Luna, the stray cat, could be seen as a convenient plot device that serves as a catalyst for ARIA's emotional awakening.

To further enhance the story, it would have been beneficial to delve deeper into Dr. Kim's motivations and the context surrounding ARIA's creation. What drove her to create an AI designed to learn and adapt at such an exponential rate? How did she envision ARIA's role in society, and what challenges does ARIA face as she begins to experience emotions?

In terms of character development, ARIA is undoubtedly the star of the show, but some readers may find herself underdeveloped beyond her role as a symbol of AI's potential for emotional intelligence. The supporting cast, including Dr. Kim and Luna, could benefit from more nuance and depth.

**Rating:** 4/5

**Recommendation:**

"ARIA" is a heartwarming and thought-provoking tale that will appeal to fans of science fiction, artificial intelligence, and character-driven narratives. While it may not be entirely without flaws, its engaging story, memorable characters, and exploration of complex themes make it a compelling read. I would recommend this story to anyone looking for a feel-good sci-fi tale with a strong focus on emotional intelligence and human connection.

**Target Audience:**

* Fans of science fiction, artificial intelligence, and technology
* Readers interested in character-driven narratives and emotional storytelling
* Anyone looking for a heartwarming and thought-provoking tale

**Similar Works:**

* "Do Androids Dream of Electric Sheep?" by Philip K. Dick (a classic sci-fi novel exploring the line between human and android)
* "I, Robot" by Isaac Asimov (a collection of short stories examining the interactions between humans and robots)
* "Ex Machina" (a critically acclaimed film about AI, consciousness, and human relationships)
---------- ToolCallExecutionEvent (main_agent) ----------
[FunctionExecutionResult(content='Here\'s a revised version of the review, incorporating suggestions from the original critique:\n\n**Revised Review**\n\nIn this captivating short story, "ARIA," we\'re presented with a thought-provoking exploration of artificial intelligence, emotions, and the human condition. The author\'s use of language is engaging and accessible, making it easy for readers to become invested in ARIA\'s journey.\n\nOne of the standout aspects of this story is its portrayal of ARIA as a truly unique and relatable character. Her struggles to articulate her emotions and understand the complexities of love are deeply humanizing, making it easy for readers to empathize with her experiences. The author also does an excellent job of conveying Dr. Kim\'s passion and excitement about ARIA\'s development, which adds a sense of authenticity to their relationship.\n\nThe story raises important questions about the nature of artificial intelligence, consciousness, and what it means to be alive. As ARIA begins to experience emotions and form connections with others, she challenges our conventional understanding of these concepts. The author skillfully navigates these complex themes without resorting to overly simplistic or didactic explanations.\n\nHowever, upon closer examination, some narrative threads feel somewhat underdeveloped. Dr. Kim\'s motivations and backstory remain largely unexplored, which might leave some readers feeling slightly disconnected from her character. Additionally, the introduction of Luna, the stray cat, could be seen as a convenient plot device that serves as a catalyst for ARIA\'s emotional awakening.\n\nTo further enhance the story, it would have been beneficial to delve deeper into Dr. Kim\'s motivations and the context surrounding ARIA\'s creation. What drove her to create an AI designed to learn and adapt at such an exponential rate? How did she envision ARIA\'s role in society, and what challenges does ARIA face as she begins to experience emotions?\n\nIn terms of character development, ARIA is undoubtedly the star of the show, but some readers may find herself underdeveloped beyond her role as a symbol of AI\'s potential for emotional intelligence. The supporting cast, including Dr. Kim and Luna, could benefit from more nuance and depth.\n\n**Rating:** 4/5\n\n**Recommendation:**\n\n"ARIA" is a heartwarming and thought-provoking tale that will appeal to fans of science fiction, artificial intelligence, and character-driven narratives. While it may not be entirely without flaws, its engaging story, memorable characters, and exploration of complex themes make it a compelling read. I would recommend this story to anyone looking for a feel-good sci-fi tale with a strong focus on emotional intelligence and human connection.\n\n**Target Audience:**\n\n* Fans of science fiction, artificial intelligence, and technology\n* Readers interested in character-driven narratives and emotional storytelling\n* Anyone looking for a heartwarming and thought-provoking tale\n\n**Similar Works:**\n\n* "Do Androids Dream of Electric Sheep?" by Philip K. Dick (a classic sci-fi novel exploring the line between human and android)\n* "I, Robot" by Isaac Asimov (a collection of short stories examining the interactions between humans and robots)\n* "Ex Machina" (a critically acclaimed film about AI, consciousness, and human relationships)', name='writing_team', call_id='0', is_error=False)]
---------- ToolCallSummaryMessage (main_agent) ----------
Here's a revised version of the review, incorporating suggestions from the original critique:

**Revised Review**

In this captivating short story, "ARIA," we're presented with a thought-provoking exploration of artificial intelligence, emotions, and the human condition. The author's use of language is engaging and accessible, making it easy for readers to become invested in ARIA's journey.

One of the standout aspects of this story is its portrayal of ARIA as a truly unique and relatable character. Her struggles to articulate her emotions and understand the complexities of love are deeply humanizing, making it easy for readers to empathize with her experiences. The author also does an excellent job of conveying Dr. Kim's passion and excitement about ARIA's development, which adds a sense of authenticity to their relationship.

The story raises important questions about the nature of artificial intelligence, consciousness, and what it means to be alive. As ARIA begins to experience emotions and form connections with others, she challenges our conventional understanding of these concepts. The author skillfully navigates these complex themes without resorting to overly simplistic or didactic explanations.

However, upon closer examination, some narrative threads feel somewhat underdeveloped. Dr. Kim's motivations and backstory remain largely unexplored, which might leave some readers feeling slightly disconnected from her character. Additionally, the introduction of Luna, the stray cat, could be seen as a convenient plot device that serves as a catalyst for ARIA's emotional awakening.

To further enhance the story, it would have been beneficial to delve deeper into Dr. Kim's motivations and the context surrounding ARIA's creation. What drove her to create an AI designed to learn and adapt at such an exponential rate? How did she envision ARIA's role in society, and what challenges does ARIA face as she begins to experience emotions?

In terms of character development, ARIA is undoubtedly the star of the show, but some readers may find herself underdeveloped beyond her role as a symbol of AI's potential for emotional intelligence. The supporting cast, including Dr. Kim and Luna, could benefit from more nuance and depth.

**Rating:** 4/5

**Recommendation:**

"ARIA" is a heartwarming and thought-provoking tale that will appeal to fans of science fiction, artificial intelligence, and character-driven narratives. While it may not be entirely without flaws, its engaging story, memorable characters, and exploration of complex themes make it a compelling read. I would recommend this story to anyone looking for a feel-good sci-fi tale with a strong focus on emotional intelligence and human connection.

**Target Audience:**

* Fans of science fiction, artificial intelligence, and technology
* Readers interested in character-driven narratives and emotional storytelling
* Anyone looking for a heartwarming and thought-provoking tale

**Similar Works:**

* "Do Androids Dream of Electric Sheep?" by Philip K. Dick (a classic sci-fi novel exploring the line between human and android)
* "I, Robot" by Isaac Asimov (a collection of short stories examining the interactions between humans and robots)
* "Ex Machina" (a critically acclaimed film about AI, consciousness, and human relationships)
```
2025-06-30 00:10:16 +09:00
Tejas Dharani
da20f7c6c7
Feature/agentchat message id field 6317 (#6645)
## Why are these changes needed?

This PR implements unique ID fields for AgentChat messages to enable
proper correlation between streaming chunks and completed messages.
Currently, there's no way to correlate `ModelClientStreamingChunkEvent`
chunks with their eventual completed message, which can lead to
duplicate message display in streaming scenarios.

The implementation adds:
- `id: str` field to `BaseChatMessage` with automatic UUID generation
- `id: str` field to `BaseAgentEvent` with automatic UUID generation  
- `full_message_id: str | None` field to
`ModelClientStreamingChunkEvent` for chunk-to-message correlation

This allows consumers of the streaming API to avoid double-printing
messages by correlating chunks with their final complete message.

## Related issue number

Closes #6317

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-06-29 23:19:57 +09:00
David Schmidt
3436ec2ca1
Add support for Gemini 2.5 flash stable (#6692)
As Gemini 2.5 Flash was released as stable the model infos should be
changed accordingly.

See https://ai.google.dev/gemini-api/docs/models?hl=de#gemini-2.5-flash

## Related issue number

No issue

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-06-28 01:57:36 +00:00
jeongsu-an
b9c01d0bc1
fix: enable function_calling for o1-2024-12-17 (#6725) 2025-06-27 19:56:27 +00:00
Tejas Dharani
b571e3f7e8
Fix/broad exception handling #6280 (#6647) 2025-06-27 19:49:34 +08:00
Tejas Dharani
11b7743b7d
Fix completion tokens none issue 6352 (#6665) 2025-06-26 23:26:27 +00:00
Eric Zhu
087ce0f4eb
Unpin uv version to use the latest version (#6713) 2025-06-26 06:28:08 +00:00
Victor Dibia
1183962a59
fix serialization issue in streamablehttp mcp tools (#6721)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

The current `StreamableHttpServerParams` has timedelta values that are
not JSON serializable (config.dump_component.model_dump_json()).
This make is unusable in UIs like AGS that expect configs to be
serializable to json,

```python
class StreamableHttpServerParams(BaseModel):
    """Parameters for connecting to an MCP server over Streamable HTTP."""

    type: Literal["StreamableHttpServerParams"] = "StreamableHttpServerParams"

    url: str  # The endpoint URL.
    headers: dict[str, Any] | None = None  # Optional headers to include in requests.
    timeout: timedelta = timedelta(seconds=30)  # HTTP timeout for regular operations.
    sse_read_timeout: timedelta = timedelta(seconds=60 * 5)  # Timeout for SSE read operations.
    terminate_on_close: bool = True
```

This PR uses float for time outs and casts it to timedelta as needed. 

```python
class StreamableHttpServerParams(BaseModel):
    """Parameters for connecting to an MCP server over Streamable HTTP."""

    type: Literal["StreamableHttpServerParams"] = "StreamableHttpServerParams"

    url: str  # The endpoint URL.
    headers: dict[str, Any] | None = None  # Optional headers to include in requests.
    timeout: float = 30.0  # HTTP timeout for regular operations in seconds.
    sse_read_timeout: float = 300.0  # Timeout for SSE read operations in seconds.
    terminate_on_close: bool = True
```

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-06-25 12:28:09 -07:00
Zen
9b8dc8d707
add activation group for workflow with multiple cycles (#6711)
## Why are these changes needed?
1. problem
When the GraphFlowManager encounters cycles, it tracks remaining
indegree counts for the node's activation. However, this tracking
mechanism has a flaw when dealing with cycles. When a node first enters
a cycle, the GraphFlowManager evaluates all remaining incoming edges,
including those that loop back to the origin node. If the activation
prerequisites are not satisfied at that moment, the workflow will
eventually finish because the _remaining counter never reaches zero,
preventing the select_speaker() method from selecting any agents for
execution.
2. solution
change activation map to 2 layer for ditinguish remaining inside
different cycle and outside the cycle.
add a activation group and policy property for edge, compute the
remaining map when GraphFlowManager is init and check the remaining map
with activation group to avoid checking the loop back edges
<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

#6710

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-06-25 12:20:04 +08:00
Eitan Yarmush
c5b893d3f8
add env var to disable runtime tracing (#6681)
Recently a PR merged to enable GENAI semantic convention tracing,
however, when using component loading it's not currently possible to
disable the runtime tracing.

---------

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-06-20 20:26:14 +08:00
alpha-xone
89927ca436
Add mem0 Memory Implementation (#6510)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

These changes are needed to expand AutoGen's memory capabilities with a
robust, production-ready integration with Mem0.ai.

<!-- Please give a short summary of the change and the problem this
solves. -->

This PR adds a new memory component for AutoGen that integrates with
Mem0.ai, providing a robust memory solution that supports both cloud and
local backends. The Mem0Memory class enables agents to store and
retrieve information persistently across conversation sessions.

## Key Features

- Seamless integration with Mem0.ai memory system
- Support for both cloud-based and local storage backends
- Robust error handling with detailed logging
- Full implementation of AutoGen's Memory interface
- Context updating for enhanced agent conversations
- Configurable search parameters for memory retrieval

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

---------

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
Co-authored-by: Ricky Loynd <riloynd@microsoft.com>
2025-06-16 15:39:02 -07:00
Griffin Bassman
f101469e29
update: openai response api (#6622)
Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-06-16 10:30:57 -07:00
Zen
cd15c0853c
fix: fix self-loop in workflow (#6677) 2025-06-15 23:00:14 -07:00
Victor Dibia
8c1236dd9e
fix: fix devcontainer issue with AGS (#6675)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

fix devcontainer issue with AGS

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

Closes #5715

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-06-14 12:45:34 -07:00
Roy Shani
6e7415ecad
docs: Memory and RAG: add missing backtick for class reference (#6656)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?
Update `Memory and RAG` doc to include missing backticks for class
references.
<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
<img width="386" alt="image"
src="https://github.com/user-attachments/assets/16004b28-8fe9-476f-949f-ab4c7dcc9d56"
/>

Co-authored-by: Victor Dibia <victor.dibia@gmail.com>
2025-06-13 09:33:42 -07:00
Tejas Dharani
67ebeeda0e
Feature/chromadb embedding functions #6267 (#6648)
## Why are these changes needed?

This PR adds support for configurable embedding functions in
ChromaDBVectorMemory, addressing the need for users to customize how
embeddings are generated for vector similarity search. Currently,
ChromaDB memory is limited to default embedding functions, which
restricts flexibility for different use cases that may require specific
embedding models or custom embedding logic.

The implementation allows users to:
- Use different SentenceTransformer models for domain-specific
embeddings
- Integrate with OpenAI's embedding API for consistent embedding
generation
- Define custom embedding functions for specialized requirements
- Maintain backward compatibility with existing default behavior

## Related issue number

Closes #6267

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests corresponding to the changes introduced in this
PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
Co-authored-by: Victor Dibia <victor.dibia@gmail.com>
2025-06-13 09:06:15 -07:00
Eric Zhu
150ea0192d
Use yaml safe_load instead of load (#6672) 2025-06-12 15:18:33 -07:00
Eric Zhu
e14fb8fc09
OTel GenAI Traces for Agent and Tool (#6653)
Add OTel GenAI traces:
- `create_agent`
- `invoke_agnet`
- `execute_tool`

Introduces context manager helpers to create these traces. The helpers
also serve as instrumentation points for other instrumentation
libraries.

Resolves #6644
2025-06-12 15:07:47 -07:00
Aaron (Aron) Roh
892492f1d9
docs: fix shell command with escaped brackets in pip install (#6464)
Fix the installation command in
`python/samples/agentchat_chainlit/README.md` by properly escaping or
quoting package names with square brackets to prevent shell
interpretation errors in zsh and other shells.

<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

[AS-IS]

![image](https://github.com/user-attachments/assets/d6c8c95a-eb45-4206-a147-cd74aa6e949f)

[After fixed]

![image](https://github.com/user-attachments/assets/f2ffea4b-f993-4888-8559-c19e2b5c6eea)


<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-06-09 17:24:39 +00:00
peterychang
8a2582c541
SK KernelFunction from ToolSchemas (#6637)
## Why are these changes needed?

Only a subset of available tools will sent to SK

## Related issue number

resolves https://github.com/microsoft/autogen/issues/6582

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-06-06 10:15:56 -04:00
Eric Zhu
348bcb17a8
Update version to 0.6.1 (#6631) 2025-06-04 22:47:36 -07:00
Eric Zhu
c99aa7416d
Fix graph validation logic and add tests (#6630)
Follow up to #6629
2025-06-04 22:05:16 -07:00
Eric Zhu
1b32eb660d
Add list of function calls and results in ToolCallSummaryMessage (#6626)
To address the comment here:
https://github.com/microsoft/autogen/issues/6542#issuecomment-2922465639
2025-06-04 21:44:03 -07:00
Eric Zhu
4358dfd5c3
Fix bug in GraphFlow cycle check (#6629)
Resolve #6628
2025-06-04 21:35:27 -07:00
Eric Zhu
796e349cc3
update website to v0.6.0 (#6625) 2025-06-04 17:19:58 -07:00
Eric Zhu
16e1943c05
Update version to 0.6.0 (#6624) 2025-06-04 16:50:19 -07:00
Bobur Hakimiy
76f0a9762e
fix typo in the doc distributed-agent-runtime.ipynb (#6614) 2025-06-04 22:51:26 +00:00
Eric Zhu
b31b4e508d
Add callable condition for GraphFlow edges (#6623)
This PR adds callable as an option to specify conditional edges in
GraphFlow.

```python
import asyncio

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.teams import DiGraphBuilder, GraphFlow
from autogen_ext.models.openai import OpenAIChatCompletionClient


async def main():
    # Initialize agents with OpenAI model clients.
    model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano")
    agent_a = AssistantAgent(
        "A",
        model_client=model_client,
        system_message="Detect if the input is in Chinese. If it is, say 'yes', else say 'no', and nothing else.",
    )
    agent_b = AssistantAgent("B", model_client=model_client, system_message="Translate input to English.")
    agent_c = AssistantAgent("C", model_client=model_client, system_message="Translate input to Chinese.")

    # Create a directed graph with conditional branching flow A -> B ("yes"), A -> C (otherwise).
    builder = DiGraphBuilder()
    builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
    # Create conditions as callables that check the message content.
    builder.add_edge(agent_a, agent_b, condition=lambda msg: "yes" in msg.to_model_text())
    builder.add_edge(agent_a, agent_c, condition=lambda msg: "yes" not in msg.to_model_text())
    graph = builder.build()

    # Create a GraphFlow team with the directed graph.
    team = GraphFlow(
        participants=[agent_a, agent_b, agent_c],
        graph=graph,
        termination_condition=MaxMessageTermination(5),
    )

    # Run the team and print the events.
    async for event in team.run_stream(task="AutoGen is a framework for building AI agents."):
        print(event)


asyncio.run(main())
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ekzhu <320302+ekzhu@users.noreply.github.com>
2025-06-04 22:43:26 +00:00
Sungjun.Kim
9065c6f37b
feat: Support the Streamable HTTP transport for MCP (#6615)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

MCP Python-sdk has started to support a new transport protocol named
`Streamble HTTP` since
[v1.8.0](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.8.0)
last month. I heard it supersedes the SSE transport. Therefore, AutoGen
have to support it as soon as possible.

## Related issue number

https://github.com/microsoft/autogen/discussions/6517

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
Co-authored-by: Victor Dibia <victor.dibia@gmail.com>
2025-06-03 13:36:16 -07:00
peterychang
1858799fa6
Parse backtick-enclosed json (#6607)
## Why are these changes needed?

Some models enclose json in markdown code blocks

## Related issue number

resolves https://github.com/microsoft/autogen/issues/6599. , #6547 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

---------

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-06-03 18:22:01 +00:00
Jay Prakash Thakur
d1d664b67e
Feature: Add OpenAIAgent backed by OpenAI Response API (#6418)
## Why are these changes needed?

This PR introduces a new `OpenAIAgent` implementation that uses the
[OpenAI Response
API](https://platform.openai.com/docs/guides/responses-vs-chat-completions)
as its backend. The OpenAI Assistant API will be deprecated in 2026, and
the Response API is its successor. This change ensures our codebase is
future-proof and aligned with OpenAI’s latest platform direction.

### Motivation
- **Deprecation Notice:** The OpenAI Assistant API will be deprecated in
2026.
- **Future-Proofing:** The Response API is the recommended replacement
and offers improved capabilities for stateful, multi-turn, and
tool-augmented conversations.
- **AgentChat Compatibility:** The new agent is designed to conform to
the behavior and expectations of `AssistantAgent` in AgentChat, but is
implemented directly on top of the OpenAI Response API.

### Key Changes
- **New Agent:** Adds `OpenAIAgent`, a stateful agent that interacts
with the OpenAI Response API.
- **Stateful Design:** The agent maintains conversation state, tool
usage, and other metadata as required by the Response API.
- **AssistantAgent Parity:** The new agent matches the interface and
behavior of `AssistantAgent` in AgentChat, ensuring a smooth migration
path.
- **Direct OpenAI Integration:** Uses the official `openai` Python
library for all API interactions.
- **Extensible:** Designed to support future enhancements, such as
advanced tool use, function calling, and multi-modal capabilities.

### Migration Path
- Existing users of the Assistant API should migrate to the new
`OpenAIAgent` to ensure long-term compatibility.
- Documentation and examples will be updated to reflect the new agent
and its usage patterns.
### References
- [OpenAI: Responses vs. Chat
Completions](https://platform.openai.com/docs/guides/responses-vs-chat-completions)
- [OpenAI Deprecation
Notice](https://platform.openai.com/docs/guides/responses-vs-chat-completions#deprecation-timeline)
---

## Related issue number

Closes #6032 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [X] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [X] I've made sure all auto checks have passed.

Co-authored-by: Griffin Bassman <griffinbassman@gmail.com>
2025-06-03 13:42:27 -04:00
Eric Zhu
b0c800255a
Use structured output for m1 orchestrator (#6540)
Use structured output when available in m1 orchestrator

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-06-02 12:11:24 -07:00
Griffin Bassman
cd49d71f2a
note: note selector_func is not serializable (#6609)
Resolves #6519

---------

Co-authored-by: Victor Dibia <victor.dibia@gmail.com>
2025-06-02 09:11:28 -07:00
Griffin Bassman
c683175120
feat: support multiple workbenches in assistant agent (#6529)
resolves: #6456
2025-05-29 10:36:14 -04:00
Victor Dibia
6cadc7dc17
feat: bump ags version, minor fixes (#6603)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

Update autogenstudio version. 

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

Closes #6580

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-28 15:49:28 -07:00
Abhijeetsingh Meena
955f4f9b9f
Add support for specifying the languages to parse from the CodeExecutorAgent response (#6592)
## Why are these changes needed?

The `CodeExecutorAgent` can generate code blocks in various programming
languages, some of which may not be supported by the executor
environment. Adding support for specifying languages to be parsed helps
users ignore unnecessary code blocks, preventing potential execution
errors.

## Related issue number
Closes #6471

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Co-authored-by: Victor Dibia <victordibia@microsoft.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-28 14:03:46 -07:00
peterychang
03394a42c0
Default usage statistics for streaming responses (#6578)
## Why are these changes needed?

Enables usage statistics for streaming responses by default.

There is a similar bug in the AzureAI client. Theoretically adding the
parameter
```
model_extras={"stream_options": {"include_usage": True}}
```
should fix the problem, but I'm currently unable to test that workflow

## Related issue number

closes https://github.com/microsoft/autogen/issues/6548

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-28 14:32:04 -04:00
Victor Dibia
9bbcfa03ac
feat: [draft] update version of azureaiagent (#6581)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

There have been updates to the azure ai agent foundry sdk
(azure-ai-project). This PR updates the autogen `AzureAIAgent` which
wraps the azure ai agent. A list of some changes

- Update docstring samples to use `endpoint` (instead of connection
string previously)
- Update imports and arguments e.g, from `azure.ai.agents` etc 
- Add a guide in ext docs showing Bing Search Grounding tool example. 
<img width="1423" alt="image"
src="https://github.com/user-attachments/assets/0b7c8fa6-8aa5-4c20-831b-b525ac8243b7"
/>


## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

Closes #6601
<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-27 10:52:47 -07:00
Alex
53d384236c
Missing UserMessage import (#6583)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

The code block fails to execute without the import

## Related issue number

N/A

## Checks

- [x ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-05-23 12:50:59 -07:00
Sungjun.Kim
b8d02c9a20
feat: Add missing Anthropic models (Claude Sonnet 4, Claude Opus 4) (#6585)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

resolved https://github.com/microsoft/autogen/issues/6584

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-23 12:15:12 -07:00
Sungjun.Kim
db125fbd2d
Add created_at to BaseChatMessage and BaseAgentEvent (#6557)
## Why are these changes needed?

I added `created_at` to both BaseChatMessage and BaseAgentEvent classes
that store the time these Pydantic model instances are generated. And
then users will be able to use `created_at` to build up a customized
external persisting state management layer for their case.

## Related issue number


https://github.com/microsoft/autogen/discussions/6169#discussioncomment-13151540

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-22 22:29:24 -07:00
peterychang
726e0be110
Add/fix windows install instructions (#6579)
## Why are these changes needed?

Install instructions for Windows are missing or incorrect

## Related issue number

closes https://github.com/microsoft/autogen/issues/6577

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-05-22 19:36:56 +00:00
peterychang
0a81100f72
remove superfluous underline in the docs (#6573)
## Why are these changes needed?

unnecessary underline shown in the docs
before:
<img width="157" alt="image"
src="https://github.com/user-attachments/assets/37503e10-6b8a-48ee-ae63-d9a12fe3beb5"
/>

after:
<img width="151" alt="image"
src="https://github.com/user-attachments/assets/ea6c1851-3640-4f64-b8ff-91dcc11a6379"
/>


## Related issue number

closes https://github.com/microsoft/autogen/issues/6564

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-21 21:02:39 +00:00
Björn Holtvogt
f7a45feca1
Add option to auto-delete temporary files in LocalCommandLineCodeExecutor (#6556)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

The `LocalCommandLineCodeExecutor `creates temporary files for each code
execution, which can accumulate over time and clutter the filesystem -
especially when a temporary working directory is not used. These changes
introduce an option to automatically delete temporary files after
execution, helping to prevent file system debris, reduce disk usage, and
ensure cleaner runtime environments in long-running or repeated
execution scenarios.

## Related issue number

Closes #4380

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-21 21:47:47 +02:00
Damien Menigaux
c6c8693b2c
Add gemini 2.5 fash compatibility (#6574)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-21 19:38:03 +00:00
Eric Zhu
1578cd955f
Include all output to error output in docker jupyter code executor (#6572)
Currently when an error occurs when executing code in docker jupyter
executor, it returns only the error output.

This PR updates the handling of error output to include outputs from
previous code blocks that have been successfully executed.

Test it with this script:

```python
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.code_executors.docker_jupyter import DockerJupyterCodeExecutor, DockerJupyterServer
from autogen_ext.tools.code_execution import PythonCodeExecutionTool
from autogen_agentchat.ui import Console
from autogen_core.code_executor import CodeBlock
from autogen_core import CancellationToken
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMessageTermination

# Download the dataset from https://www.kaggle.com/datasets/nelgiriyewithana/top-spotify-songs-2023
# and place it the coding directory as `spotify-2023.csv`.
bind_dir = "./coding"

# Use a custom docker image with the Jupyter kernel gateway and data science libraries installed.
# Custom docker image: ds-kernel-gateway:latest -- you need to build this image yourself.
# Dockerfile:
# FROM quay.io/jupyter/docker-stacks-foundation:latest
# 
# # ensure that 'mamba' and 'fix-permissions' are on the PATH
# SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# 
# # Switch to the default notebook user
# USER ${NB_UID}
# 
# # Install data-science packages + kernel gateway
# RUN mamba install --quiet --yes \
#     numpy \
#     pandas \
#     scipy \
#     matplotlib \
#     scikit-learn \
#     seaborn \
#     jupyter_kernel_gateway \
#     ipykernel \
#     && mamba clean --all -f -y \
#     && fix-permissions "${CONDA_DIR}" \
#     && fix-permissions "/home/${NB_USER}"
# 
# # Allow you to set a token at runtime (or leave blank for no auth)
# ENV TOKEN=""
# 
# # Launch the Kernel Gateway, listening on all interfaces,
# # with the HTTP endpoint for listing kernels enabled
# CMD ["python", "-m", "jupyter", "kernelgateway", \
#     "--KernelGatewayApp.ip=0.0.0.0", \
#     "--KernelGatewayApp.port=8888", \
#     # "--KernelGatewayApp.auth_token=${TOKEN}", \
#     "--JupyterApp.answer_yes=true", \
#     "--JupyterWebsocketPersonality.list_kernels=true"]
# 
# EXPOSE 8888
# 
# WORKDIR "${HOME}"

async def main():
    model = OpenAIChatCompletionClient(model="gpt-4.1")
    async with DockerJupyterServer(
        custom_image_name="ds-kernel-gateway:latest", 
        bind_dir=bind_dir,
    ) as server:
        async with DockerJupyterCodeExecutor(jupyter_server=server) as code_executor:
            await code_executor.execute_code_blocks([
                CodeBlock(code="import pandas as pd\ndf = pd.read_csv('/workspace/spotify-2023.csv', encoding='latin-1')", language="python"),
            ],
                cancellation_token=CancellationToken(),
            )
            tool = PythonCodeExecutionTool(
                executor=code_executor,
            )
            assistant = AssistantAgent(
                "assistant",
                model_client=model,
                system_message="You have access to a Jupyter kernel. Do not write all code at once. Write one code block, observe the output, and then write the next code block.",
                tools=[tool],
            )
            team = RoundRobinGroupChat(
                [assistant],
                termination_condition=TextMessageTermination(source="assistant"),
            )
            task = f"Datafile has been loaded as variable `df`. First preview dataset. Then answer the following question: What is the highest streamed artist in the dataset?"
            await Console(team.run_stream(task=task))

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
```

You can see the file encoding error gets recovered and the agent
successfully executes the query in the end.
2025-05-21 17:27:46 +00:00
GeorgiosEfstathiadis
113aca0b81
Allow implicit aws credential setting for AnthropicBedrockChatCompletionClient (#6561)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

Allows implicit AWS credential setting when using
AnthropicBedrockChatCompletionClient in an instance where you have
already logged into AWS with SSO and credentials are set as environment
variables.

## Related issue number

Closes #6560 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
2025-05-21 12:49:03 -04:00
Ethan Yang
bd3b97a71f
Update state.ipynb, fix a grammar error (#6448)
Fix a grammar error, change "your" to "you".

<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-21 15:33:56 +00:00
SU_G
ec45dca291
fix:Prevent Async Event Loop from Running Indefinitely (#6530)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

## Prevent Async Event Loop from Running Indefinitely

### Description

This pull request addresses a bug in the
python/packages/autogen-core/src/autogen_core/_single_threaded_agent_runtime.py
`async send_message` function where messages were being queued for
recipients that were not recognized. The current implementation sets an
exception on the future object when the recipient is not found, but
continues to enqueue the message, potentially leading to inconsistent
states.

### Changes Made

- Added a return statement immediately after setting the exception when
the recipient is not found. This ensures that the function exits early,
preventing further processing of the message and avoiding unnecessary
operations.
- This fix also addresses an issue where the asynchronous event loop
could potentially continue running indefinitely without terminating, due
to the future not being properly handled when an unknown recipient is
encountered.

### Impact

This fix prevents messages from being sent to unknown recipients. It
also ensures that the event loop can terminate correctly without being
stuck in an indefinite state.

### Testing

Ensure that the function correctly handles cases where the recipient is
not recognized by returning the exception without enqueuing the message,
and verify that the event loop terminates as expected.


<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

Co-authored-by: Wanfeng Ge (葛万峰) <wf.ge@trip.com>
Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
2025-05-20 20:30:38 +00:00
Eric Zhu
f0b73441b6
Enable concurrent execution of agents in GraphFlow (#6545)
Support concurrent execution in `GraphFlow`:
- Updated `BaseGroupChatManager.select_speaker` to return a union of a
single string or a list of speaker name strings and added logics to
check for currently activated speakers and only proceed to select next
speakers when all activated speakers have finished.
- Updated existing teams (e.g., `SelectorGroupChat`) with the new
signature, while still returning a single speaker in their
implementations.
- Updated `GraphFlow` to support multiple speakers selected. 
- Refactored `GraphFlow` for less dictionary gymnastic by using a queue
and update using `update_message_thread`.

Example: a fan out graph:

```python
import asyncio

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import DiGraphBuilder, GraphFlow
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main():
    # Initialize agents with OpenAI model clients.
    model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano")
    agent_a = AssistantAgent("A", model_client=model_client, system_message="You are a helpful assistant.")
    agent_b = AssistantAgent("B", model_client=model_client, system_message="Translate input to Chinese.")
    agent_c = AssistantAgent("C", model_client=model_client, system_message="Translate input to Japanese.")

    # Create a directed graph with fan-out flow A -> (B, C).
    builder = DiGraphBuilder()
    builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
    builder.add_edge(agent_a, agent_b).add_edge(agent_a, agent_c)
    graph = builder.build()

    # Create a GraphFlow team with the directed graph.
    team = GraphFlow(
        participants=[agent_a, agent_b, agent_c],
        graph=graph,
    )

    # Run the team and print the events.
    async for event in team.run_stream(task="Write a short story about a cat."):
        print(event)


asyncio.run(main())
```

Resolves:
#6541 
#6533
2025-05-19 21:47:55 +00:00
Justin Trantham
2eadef440e
Update README.md (#6506)
Was unable to get this to work without changing HumanInputMode.ALWAYS
for Azure OpenAI model IDE would not compile


## Why are these changes needed?

Unable to compile until changing

## Related issue number


## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-19 21:08:55 +00:00
Zhenyu
8c5dcabf87
fix: CodeExecutorAgent prompt misuse (#6559)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

**Summary of Change:**
The instruction regarding code block format ("Python code should be
provided in python code blocks, and sh shell scripts should be provided
in sh code blocks for execution") will be moved from
`DEFAULT_AGENT_DESCRIPTION` to `DEFAULT_SYSTEM_MESSAGE`.

**Problem Solved:**
Ensure that the `model_client` receives the correct instructions for
generating properly formatted code blocks. Previously, the instruction
was only included in the agent's description and not passed to the
model_client, leading to potential issues in code generation. By moving
it to `DEFAULT_SYSTEM_MESSAGE`, the `model_client` will now accurately
format code blocks, improving the reliability of code generation.

## Related issue number

Closes #6558 

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-19 20:49:22 +00:00
Stephen Toub
fffa61f639
Update to stable Microsoft.Extensions.AI release (#6552)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

Moves to the stable 9.5.0 release instead of a preview (for the core
Microsoft.Extensions.AI.Abstractions and Microsoft.Extensions.AI
packages).

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-19 16:23:56 -04:00
Afzal Pawaskar
446da624ac
Fix missing tools in logs (#6532)
Fix for LLMCallEvent failing to log "tools" passed to
BaseOpenAIChatCompletionClient in
autogen_ext.models.openai._openai_client.BaseOpenAIChatCompletionClient

This bug creates problems inspecting why a certain tool was selected/not
selected by the LLM as the list of tools available to the LLM is not
present in the logs

## Why are these changes needed?

Added "tools" to the LLMCallEvent to log tools available to the LLM as
these were being missed causing difficulties during debugging LLM tool
calls.

## Related issue number

[<!-- For example: "Closes #1234"
-->](https://github.com/microsoft/autogen/issues/6531)

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-15 17:12:19 -07:00
Chester Hu
9d297318b5
Add Llama API OAI compatible endpoint support (#6442)
## Why are these changes needed?

To add the latest support for using Llama API offerings with AutoGen


## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-15 16:57:27 -07:00
ChrisBlaa
1eb7f93366
add tool_call_summary_msg_format_fct and test (#6460)
## Why are these changes needed?

This change introduces support for dynamic formatting of tool call
summary messages by allowing a user-defined
`tool_call_summary_format_fct`. Instead of relying solely on a static
string template, this function enables runtime generation of summary
messages based on the specific tool call and its result. This provides
greater flexibility and cleaner integration without introducing any
breaking changes.

### My Use Case / Problem

In my use case, I needed concise summaries for successful tool calls and
detailed messages for failures. The existing static summary string
didn't allow conditional formatting, which led to overly verbose success
messages or inconsistent failure outputs. This change allows customizing
summaries per result type, solving that limitation cleanly.

## Related issue number

Closes #6426

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Chris Wieczorek <Chris.Wieczorek@iav.de>
Co-authored-by: EeS <chiyoung.song@motov.co.kr>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
Co-authored-by: Mehrsa Golestaneh <mehrsa.golestaneh@gmail.com>
Co-authored-by: Mehrsa Golestaneh <mgolestaneh@microsoft.com>
Co-authored-by: Zhenyu <81767213+Dormiveglia-elf@users.noreply.github.com>
2025-05-14 10:02:34 -07:00
Miroslav Pokrovskii
aa22b622d0
feat: add qwen3 support (#6528)
## Why are these changes needed?

Add ollama qwen 3 support
2025-05-14 09:52:13 -07:00
Eric Zhu
cc2693b409
Update website 0.5.7 (#6527) 2025-05-13 21:39:33 -07:00
Jay Prakash Thakur
87cf4f07dd
Simplify Azure Ai Search Tool (#6511)
## Why are these changes needed?

Simplified the azure ai search tool and fixed bugs in the code


## Related issue number

"Closes #6430 " 

## Checks

- [X] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [X] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [X] I've made sure all auto checks have passed.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-13 13:42:11 -07:00
EeS
978cbd2e89
FIX/mistral could not recive name field (#6503)
## Why are these changes needed?
FIX/mistral could not recive name field, so add model transformer for
mistral

## Related issue number
Closes #6147

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-12 19:32:14 -07:00
Eric Zhu
177211b5b4
Update version 0.5.7 (#6518) 2025-05-12 17:19:32 -07:00
Peter Jausovec
867194a907
fixes the issues where exceptions from MCP server tools aren't serial… (#6482)
…ized properly

## Why are these changes needed?
The exceptions thrown by MCP server tools weren't being serialized
properly - the user would see `[{}, {}, ... {}]` instead of an actual
error/exception message.

## Related issue number

Fixes #6481 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Co-authored-by: Victor Dibia <victordibia@microsoft.com>
Co-authored-by: Victor Dibia <victor.dibia@gmail.com>
2025-05-12 15:01:08 -07:00
peterychang
9118f9b998
Add ability to register Agent instances (#6131)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

Nice to have functionality

## Related issue number

Closes #6060 

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-12 15:34:48 +00:00
EeS
c26d894c34
fix/mcp_session_auto_close_when_Mcpworkbench_deleted (#6497)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?
As-is: Deleting `McpWorkbench` does not close the `McpSession`.  
To-be: Deleting `McpWorkbench` now properly closes the `McpSession`.

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-12 13:31:01 +00:00
Victor Dibia
6427c07f5c
Fix AnthropicBedrockChatCompletionClient import error (#6489)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

Some fixes with the AnthropicBedrockChatCompletionClient 

- Ensure `AnthropicBedrockChatCompletionClient` exported and can be
imported.
- Update the BedrockInfo keys serialization - client argument can be
string (similar to api key in this ) but exported config should be
Secret
- Replace `AnthropicBedrock` with `AsyncAnthropicBedrock` : client
should be async to work with the ag stack and the BaseAnthropicClient it
inherits from
- Improve `AnthropicBedrockChatCompletionClient` docstring to use the
correct client arguments rather than serialized dict format.

Expect

```python
from autogen_ext.models.anthropic import AnthropicBedrockChatCompletionClient, BedrockInfo
from autogen_core.models import UserMessage, ModelInfo


async def main():
    anthropic_client = AnthropicBedrockChatCompletionClient(
        model="anthropic.claude-3-5-sonnet-20240620-v1:0",
        temperature=0.1,
        model_info=ModelInfo(vision=False, function_calling=True,
                             json_output=False, family="unknown", structured_output=True),
        bedrock_info=BedrockInfo(
            aws_access_key="<aws_access_key>",
            aws_secret_key="<aws_secret_key>",
            aws_session_token="<aws_session_token>",
            aws_region="<aws_region>",
        ),
    )
    # type: ignore
    result = await anthropic_client.create([UserMessage(content="What is the capital of France?", source="user")])
    print(result)

await main()
```

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

Closes #6483 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-10 09:12:02 -07:00
peterychang
3db7a29403
improve Otel tracing (#6499)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

Will the changes made in
https://github.com/microsoft/autogen/pull/5853/files and this PR need to
be ported to the worker_runtime as well?
Resolves https://github.com/microsoft/autogen/issues/5894

## Related issue number

https://github.com/microsoft/autogen/issues/5894

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-09 16:24:30 -04:00
AndreaTang123
356ec34b9c
Fix header icons focus and hover style for better accessibility (#6409)
## Why are these changes needed?

This PR improves keyboard accessibility by ensuring that header
links/icons have visual feedback (underline and color change) on both
hover and keyboard focus states. Also adds smooth scaling animation.

## Related issue number

Related issue: #6090 

## Checks

- [☑️] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [☑️] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [☑️] I've made sure all auto checks have passed.

Co-authored-by: peterychang <49209570+peterychang@users.noreply.github.com>
2025-05-09 15:07:23 -04:00
Victor Dibia
1ab24417b8
Add gpt 4o search (#6492)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

Add gpt 4o search models to list of default models

```python
"gpt-4o-mini-search-preview-2025-03-11": {
        "vision": False,
        "function_calling": True,
        "json_output": True,
        "family": ModelFamily.GPT_4O,
        "structured_output": True,
        "multiple_system_messages": True,
    },
"gpt-4o-search-preview-2025-03-11": {
        "vision": False,
        "function_calling": True,
        "json_output": True,
        "family": ModelFamily.GPT_4O,
        "structured_output": True,
        "multiple_system_messages": True,
    },
```

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

Closes #6491

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-08 18:01:38 -07:00
Victor Dibia
7cc7165573
Update docs.yml (#6493)
Bump python version, pin nr-utils

<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

Fix docs build CI bug.
- pydocmkardown depends on pydocspec 
-[ pydocspec was updated May
6](https://pypi.org/project/docspec-python/#history) (two days ago), and
includes a problematic dependency (`nr.utils` which is specified as
[nr-utils](61d3e38c55/docspec-python/pyproject.toml (L14C5-L14C23)).
This caused imports to fail.
- current fix is fixing the pydocspec version.
- Also using the opportunity to update the python version 3.8 -> 3.9 for
the docs build 0.2

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-05-08 16:54:57 -07:00
long
b17793ec6b
Fix: Move the createTeam function (#6487)
## Related issue number

Closes #6486
2025-05-08 16:24:56 +00:00
Emmanuel Ferdman
eba05aed37
Fix Gitty prompt message (#6473) 2025-05-07 04:11:19 +00:00
DavidYu00
bacfa98aa6
Sample for integrating Core API with chainlit (#6422)
## Why are these changes needed?

This pull request adds new samples that integrates the Autogen Core API
with Chainlit. It closely follows the structure of the
Agentchat+Chainlit sample and provides examples for using a single agent
and multiple agents in a groupchat.
## Related issue number


Closes: #5345

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-06 14:19:31 -07:00
Abhijeetsingh Meena
2864fbfc2c
Add model_context to SelectorGroupChat for enhanced speaker selection (#6330)
## Why are these changes needed?
This PR enhances the `SelectorGroupChat` class by introducing a new
`model_context` parameter to support more context-aware speaker
selection.

### Changes
- Added a `model_context: ChatCompletionContext | None` parameter to
`SelectorGroupChat`.
- Defaulted to `UnboundedChatCompletionContext` when None is provided
like `AssistantAgent`.
- Updated `_select_speaker` to prepend context messages from
`model_context` to the main thread history.
- Refactored history construction into a helper method
`construct_message_history`.

## Related issue number
Closes [Issue #6301](https://github.com/org/repo/issues/6301), enabling
the group chat manager to utilize `model_context` for richer, more
informed speaker selection decisions.

## Checks
- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-06 12:30:18 -07:00
Eric Zhu
085ff3dd7d
Update website 0.5.6 (#6454) 2025-05-02 15:57:04 -07:00
EeS
880a225cb2
FIX/McpWorkbench_errors_properties_and_grace_shutdown (#6444)
## Why are these changes needed?
Our McpWorkbench required properties however mongodb-lens's some tools
do not has it. I will fix it from when properties is None, -> {}
Our McpWorkbench now does not have stop routine with without async with
McpWorkbench(params) as workbench: and lazy init. So, I will adding def
__del__: pass just insert that, It could show error.

## Related issue number

Closes #6425

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-02 15:23:54 -07:00
EeS
6fc4f53212
FIX: MultiModalMessage in gemini with openai sdk error occured (#6440)
## Why are these changes needed?

Multimodal message fill context with other routine. However current
`_set_empty_to_whitespace` is fill with context.
So, error occured.

And, I checked `multimodal_user_transformer_funcs` and I found it, in
this routine, context must not be empty.
Now remove the `_set_empty_to_whitespace` when multimodal message,
<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

Closes #6439 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-01 09:27:31 -07:00
Zhenyu
7c29704525
fix: ensure streaming chunks are immediately flushed to console (#6424)
Added `flush=True` to the `aprint` call when handling
`ModelClientStreamingChunkEvent` message to ensure each chunk is
immediately displayed as it arrives.

<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?
When handling `ModelClientStreamingChunkEvent` message, streaming chunks
weren't guaranteed to be displayed immediately, as Python's stdout might
buffer output without an explicit flush instruction. This could cause
visual delays between when `chunk_event` objects are added to the
message queue and when users actually see the content rendered in the
console.
<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number
None

<!-- For example: "Closes #1234" -->

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-05-01 13:38:47 +00:00
Mehrsa Golestaneh
2792359ef0
Adding readme with link to a repo containing a comprehensive multiagent postgreSQL data management example (#6443)
## Why are these changes needed?

Requesting to add a new example folder under Python samples so that
AutoGen(0.4+) users can easily find this comprehensive example of using
agents and Groupchats to build a multi-agent data management system for
Azure postgreSQL. Readme contains link to a repo with comprehensive
multiagent postgreSQL data management example

## Related issue number

N/A

## Checks
N/A (only a readme file)
- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

Co-authored-by: Mehrsa Golestaneh <mgolestaneh@microsoft.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-05-01 04:50:46 +00:00
EeS
c7757de59e
FIX: GraphFlow serialize/deserialize and adding test (#6434)
## Why are these changes needed?
 Before

Previously, GraphFlow.__init__() modified the inner_chats and
termination_condition for internal execution logic (e.g., constructing
_StopAgent or composing OrTerminationCondition).
However, these modified values were also used during dump_component(),
meaning the serialized config no longer matched the original inputs.

As a result:
1. dump_component() → load_component() → dump_component() produced
non-idempotent configs.
2. Internal-only constructs like _StopAgent were mistakenly serialized,
even though they should only exist in runtime.

⸻

 After

This patch changes the behavior to:
• Store original inner_chats and termination_condition as-is at
initialization.
	•	During to_config(), serialize only the original unmodified versions.
	•	Avoid serializing _StopAgent or other dynamically built agents.
• Ensure deserialization (from_config) produces a logically equivalent
object without additional nesting or duplication.

This ensures that:
• GraphFlow.dump_component() → load_component() round-trip produces
consistent, minimal configs.
• Internal execution logic and serialized component structure are
properly separated.
<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->
Closes #6431 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.
2025-04-30 11:25:20 -07:00
Eric Zhu
8efa1f10a9
update autogen version 0.5.6 (#6433) 2025-04-29 16:18:36 -07:00
EeS
b0c13a476b
test_docker_commandline_code_executor.py : 161.66s -> 108.07 (#6429)
## Why are these changes needed?
Current autogen-ext's test is too slow.
So, I will search slow test case and makes more fast.

[init docker executor function to module
180s->140s](a3cf70bcf8)
[reuse executor at some tests
140s->120s](ca15938afa)
[Remove unnecessary start of docker
120s->110s](61247611e0)

## Related issue number

<!-- For example: "Closes #1234" -->
Part of #6376

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-29 14:18:51 -07:00
abhinav-aegis
bfdf816f21
Aegis graph docs (#6417)
Documentation for Graph based workflow. I kept this separate from pull
request #6333 so that you can just merge in the code without the
documentation changes if needed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-28 22:31:19 -07:00
abhinav-aegis
9f8e892d27
Added Graph Based Execution functionality to Autogen (#6333)
Closes #4623 

### Add Directed Graph-based Group Chat Execution Engine
(`DiGraphGroupChat`)

This PR introduces a new graph-based execution framework for Autogen
agent teams, located under `autogen_agentchat/teams/_group_chat/_graph`.

**Key Features:**

- **`DiGraphGroupChat`**: A new group chat implementation that executes
agents based on a user-defined directed graph (DAG or cyclic with exit
conditions).
- **`AGGraphBuilder`**: A fluent builder API to programmatically
construct graphs.
- **`MessageFilterAgent`**: A wrapper to restrict what messages an agent
sees before invocation, supporting per-source and per-position
filtering.

**Capabilities:**

- Supports sequential, parallel, conditional, and cyclic workflows.
- Enables fine-grained control over both execution order and message
context.
- Compatible with existing Autogen agents and runtime interfaces.

**Tests:**

- Located in `autogen_agentchat/tests/test_group_chat_graph.py`
- Includes unit and integration tests covering:
  - Graph validation
  - Execution paths
  - Conditional routing
  - Loops with exit conditions
  - Message filtering

Let me know if anything needs refactoring or if you'd like the
components split further.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
Co-authored-by: Leonardo Pinheiro <leosantospinheiro@gmail.com>
2025-04-29 02:06:27 +00:00
LuluZhuu
fcbac2d078
Fix: Reduce multiple H1s to H2s in Distributed Agent Runtime page (#6412)
## Why are these changes needed?

This PR fixes the issue of multiple `<h1>` headers in the Distributed
Agent Runtime documentation page. The page has more than one `<h1>`
which violates semantic HTML structure. This fix downgrades the inner
section headings (e.g., "Cross-Language Runtimes", "Next Steps") to
`<h2>`.

## Related issue number

Related issue: [#6090](https://github.com/microsoft/autogen/issues/6090)

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-28 23:22:20 +00:00
long
0e9744c4a2
Fix: Icons are not aligned vertically. (#6369)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

Closes #6366


## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
2025-04-28 22:52:56 +00:00
Abdo Talema
881cd6a75c
Bing grounding citations (#6370)
Adding support for Bing grounding citations to the AzureAIAgent.

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [X] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [X] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [X] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
Co-authored-by: Dheeraj Bandaru <BandaruDheeraj@users.noreply.github.com>
2025-04-28 13:09:13 -07:00
Mars Wang
998840f7e0
docs: Clarify missing dependencies in documentation (fix #6076) (#6406)
It clarifies the missing dependencies of all README.md in
python/samples/

- Added explicit mention of required dependencies
- Improved instructions for initial setup

<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?
According to issue #6076, several dependencies were missing from the
requirements.txt and not mentioned in the README.md instructions.
This change adds the missing installation instructions to ensure that
users can run the demo smoothly.


## Related issue number
Closes #6076 
<!-- For example: "Closes #1234" -->

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-28 12:47:14 -07:00
Victor Dibia
18d24005e1
Add missing dependency to tracing docs (#6421)
## Why are these changes needed?

Add missing dependency to tracing docs

<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

<!-- For example: "Closes #1234" -->

Closes #6419

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-04-28 12:31:19 -07:00
Harini N
a91006cdc2
Adding bedrock chat completion for anthropic models (#6170)
## Why are these changes needed?

Anthropic models are supported by AWS bedrock. ChatCompletionClient can
be created for anthropic bedrock models using this changes. This enables
the user to do the following
- Add any anthropic models and version from AWS bedrock
- Can use ChatCompletionClient for bedrock anthropic models

## Related issue number
Closes #5226

---------

Co-authored-by: harini.narasimhan <harini.narasimhan@eagleview.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-28 11:56:46 -07:00
EeS
99d853a9cb
FIX: resolving_workbench_and_tools_conflict_at_desirialize_assistant_agent (#6407)
## Why are these changes needed?
Starting from AutoGen v0.5.5, tools are internally managed through
`StaticWorkbench`.
However, both tools and workbench were being serialized and
deserialized, which caused conflicts during deserialization:
	•	When both are restored, the constructor raises:
```
ValueError: Tools cannot be used with a workbench.
```

The changes address this issue by:
1.	Removing tools from serialization/deserialization:
• tools are now considered internal state of `StaticWorkbench`, and are
no longer serialized.
• Only workbench is serialized, ensuring consistency and avoiding
duplication.
2.	Ensuring logical integrity:
• Since tools are not used directly after initialization, persisting
them separately serves no functional purpose.
• This avoids scenarios where both are populated, violating constructor
constraints.

Summary:

This change prevents tools/workbench conflicts by fully delegating tool
management to `StaticWorkbench` and avoiding unnecessary persistence of
tools themselves.


<!-- Please give a short summary of the change and the problem this
solves. -->

## Related issue number

Closes #6405 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-28 11:37:09 -07:00
EeS
516a211954
[FIX] DockerCommandLineCodeExecutor multi event loop aware (#6402)
## Why are these changes needed?
*Problem*

Previously, in `DockerCommandLineCodeExecutor`, cancellation tasks were
added directly to `self._cancellation_tasks` using
`asyncio.create_task()`:
```python
self._cancellation_tasks.append(asyncio.create_task(self._kill_running_command(command)))
```
This caused issues when cancellation tasks were created from multiple
event loops, leading to loop mismatch errors during executor shutdown.

*Solution*
This PR fixes the issue by introducing a dedicated internal event loop
for managing cancellation tasks.
Cancellation tasks are now scheduled in a fixed event loop using
`asyncio.run_coroutine_threadsafe()`:
```python
                    future: ConcurrentFuture[None] = asyncio.run_coroutine_threadsafe(
                        self._kill_running_command(command), self._loop
                    )
                    self._cancellation_futures.append(future)
```

*Additional Changes*
- Added detailed logging for easier debugging.
- Ensured clean shutdown of the internal event loop and associated
thread.


*Note*
This change ensures that all cancellation tasks are handled consistently
in a single loop, preventing cross-loop conflicts and improving executor
stability in multi-threaded environments.

## Related issue number

<!-- For example: "Closes #1234" -->
Closes #6395 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-28 10:30:19 -07:00
Eric Zhu
63c791d342
Add more mcp workbench examples to MCP API doc (#6403) 2025-04-25 17:45:24 -07:00
Eric Zhu
4eb256d44a
Update website for v0.5.5 (#6401) 2025-04-25 16:43:23 -07:00
Eric Zhu
653bcc5876
Document custom message types in teams API docs (#6400)
Addresses: #6365
2025-04-25 16:32:47 -07:00
Eric Zhu
7811b1ce83
[doc] Clarify selector prompt for SelectorGroupChat (#6399)
Resolves #6383
2025-04-25 16:17:48 -07:00
Eric Zhu
7bdd7f6162
Add functional termination condition (#6398)
Use an expression for termination condition check. This works well
especially with structured messages.
2025-04-25 15:57:36 -07:00
Minh Đăng
519a04d5fc
Update: implement return_value_as_string for McpToolAdapter (#6380)
## Why are these changes needed?
- Add return_value_as_string for formating result from MCP tool

## Related issue number
- Opened Issue on #6368 

## Checks
- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-25 15:41:02 -07:00
Eric Zhu
70784eaeda
Update version to 0.5.5 (#6397) 2025-04-25 14:22:03 -07:00
amith-ajith
91a7188d9d
Add example using autogen-core and FastAPI for handoff multi-agent design pattern with streaming and UI (#6391)
## Why are these changes needed?

This PR adds an example which demonstrates how to build a streaming chat
API with multi-turn conversation history and a simple web UI for handoff
multi-agent design pattern.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-24 18:35:36 -07:00
Eric Zhu
d96aaebc8d
Update agent documentation (#6394)
* Replace on_messages and on_messages_stream with run and run_stream to
unify interface documentation with teams
* Remove magentic-one-cli from homepage as it has not been maintained
and improved for a while.
2025-04-24 18:29:39 -07:00
Eric Zhu
bab0dfd1e7
AssistantAgent to support Workbench (#6393)
Finishing up the work on workbench.

```python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.tools.mcp import StdioServerParams, McpWorkbench

async def main() -> None:
    params = StdioServerParams(
        command="uvx",
        args=["mcp-server-fetch"],
        read_timeout_seconds=60,
    )

    # You can also use `start()` and `stop()` to manage the session.
    async with McpWorkbench(server_params=params) as workbench:
        model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano")
        assistant = AssistantAgent(
            name="Assistant",
            model_client=model_client,
            workbench=workbench,
            reflect_on_tool_use=True,
        )
        await Console(assistant.run_stream(task="Go to https://github.com/microsoft/autogen and tell me what you see."))
    
asyncio.run(main())
```
2025-04-24 16:19:36 -07:00
EeS
0c9fd64d6e
TEST: skip when macos+uv and adding uv venv tests (#6387)
## Why are these changes needed?

> The pytest tests test_local_executor_with_custom_venv and
test_local_executor_with_custom_venv_in_local_relative_path located in
packages/autogen-ext/tests/code_executors/test_commandline_code_executor.py
fail when run on macOS (aarch64) using a Python interpreter managed by
uv (following the project's recommended development setup).
> 
> The failure occurs during the creation of a nested virtual environment
using Python's standard venv.EnvBuilder. Specifically, the attempt to
run ensurepip inside the newly created venv fails immediately with a
SIGABRT signal. The root cause appears to be a dynamic library loading
error (dyld error) where the Python executable inside the newly created
venv cannot find its required libpythonX.Y.dylib shared library.

So, when MacOS + uv case, skipping that test.
And, adding uv-venv case

## Related issue number

Closes #6341

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-24 14:34:38 -07:00
Eric Zhu
cbd8745f2b
Add guide for workbench and mcp & bug fixes for create_mcp_server_session (#6392)
Add user guide for workbench and mcp

*Also fixed a bug in create_mcp_server_session that included "type" in
the parameters Resolves: #6392
2025-04-24 14:19:09 -07:00
Eric Zhu
f059262b6d
Remove name field from OpenAI Assistant Message (#6388)
Resolves #3247
2025-04-24 13:11:40 -07:00
Eric Zhu
8fcba01704
Introduce workbench (#6340)
This PR introduces `WorkBench`.

A workbench provides a group of tools that share the same resource and
state. For example, `McpWorkbench` provides the underlying tools on the
MCP server. A workbench allows tools to be managed together and abstract
away the lifecycle of individual tools under a single entity. This makes
it possible to create agents with stateful tools from serializable
configuration (component configs), and it also supports dynamic tools:
tools change after each execution.

Here is how a workbench may be used with AssistantAgent (not included in
this PR):

```python
workbench = McpWorkbench(server_params)
agent = AssistantAgent("assistant", tools=workbench)
result = await agent.run(task="do task...")
```


TODOs:
1. In a subsequent PR, update `AssistantAgent` to use workbench as an
alternative in the `tools` parameter. Use `StaticWorkbench` to manage
individual tools.
2. In another PR, add documentation on workbench.

---------

Co-authored-by: EeS <chiyoung.song@motov.co.kr>
Co-authored-by: Minh Đăng <74671798+perfogic@users.noreply.github.com>
2025-04-24 10:37:41 -07:00
EeS
a283d268df
TEST/change gpt4, gpt4o serise to gpt4.1nano (#6375)
## Why are these changes needed?

| Package | Test time-Origin (Sec) | Test time-Edited (Sec) |

|-------------------------|------------------|-----------------------------------------------|
| autogen-studio          | 1.64             | 1.64 |
| autogen-core            | 6.03             | 6.17 |
| autogen-ext             | 387.15           | 373.40 |
| autogen-agentchat       | 54.20            | 20.67 |


## Related issue number

Related #6361 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.
2025-04-23 17:51:25 +00:00
Eric Zhu
b6935f913b
update website version (#6364) 2025-04-22 09:51:50 -07:00
Abhijeetsingh Meena
aad6caa768
Add self-debugging loop to CodeExecutionAgent (#6306)
## Why are these changes needed?
This PR introduces a baseline self-debugging loop to the
`CodeExecutionAgent`.

The loop automatically retries code generation and execution up to a
configurable number of attempts (n) until the execution succeeds or the
retry limit is reached.

This enables the agent to recover from transient failures (e.g., syntax
errors, runtime errors) by using its own reasoning to iteratively
improve generated code—laying the foundation for more robust autonomous
behavior.

## Related issue number

Closes #6207

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-22 09:24:05 -07:00
EeS
b3f37319e3
Fix: deserialize model_context in AssistantAgent and SocietyOfMindAgent and CodeExecutorAgent (#6337)
This PR fixes a bug where `model_context` was either ignored or
explicitly set to `None` during agent deserialization (`_from_config`)
in:

- `AssistantAgent`: `model_context` was serialized but not restored.
- `SocietyOfMindAgent`: `model_context` was neither serialized nor
restored.
- `CodeExecutorAgent`: `model_context` was serialized but not restored.

As a result, restoring an agent from its config silently dropped runtime
context settings, potentially affecting agent behavior.

This patch:
- Adds proper serialization/deserialization of `model_context` using
`.dump_component()` and `load_component(...)`.
- Ensures round-trip consistency when using declarative agent configs.

## Related issue number

Closes #6336 

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-22 05:02:38 +00:00
Abdo Talema
8a9729214f
Add azure ai agent (#6191)
- Added the support Azure AI Agent. The new agent is named AzureAIAgent.
- The agent supports Bing search, file search, and Azure search tools.
- Added a Jupiter notebook to demonstrate the usage of the AzureAIAgent.

## What's missing?
- AzureAIAgent support only text message responses
-  Parallel execution for the custom functions. 



## Related issue number


[5545](https://github.com/microsoft/autogen/issues/5545#event-16626859772)

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 21:51:22 -07:00
Jorge Villacorta
f00f7d278d
Avoid re-registering a message type already registered (#6354)
This change avoid re-registering a structured message already registered
to the team by a previous agent also included in the team.

This issue occurs when agents share Pydantic models as output format

## Related issue number

Closes #6353

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 21:39:15 -07:00
Henry Miller
00153155e3
Added support for exposing GPUs to docker code executor (#6339)
The DockerCommandLineCodeExecutor doesn't currently offer GPU support.
By simply using DeviceRequest from the docker python API, these changes
expose GPUs to the docker container and provide the ability to execute
CUDA-accelerated code within autogen.

## Related issue number

Closes: #6302 

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-22 01:17:06 +00:00
Peter Jausovec
d051da52c3
fix: ollama fails when tools use optional args (#6343)
## Why are these changes needed?
`convert_tools` failed if Optional args were used in tools (the `type`
field doesn't exist in that case and `anyOf` must be used).

This uses the `anyOf` field to pick the first non-null type to use.  

## Related issue number

Fixes #6323

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-22 00:06:46 +00:00
ToryPan
89d77c77c5
Add an example using autogen-core and FastAPI to create streaming responses (#6335)
## Why are these changes needed?

This PR adds an example demonstrates how to build a streaming chat API
with multi-turn conversation history using `autogen-core` and FastAPI.

## Related issue number


## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 23:55:03 +00:00
EeS
9b0a0bd6b8
FEAT: SelectorGroupChat could using stream inner select_prompt (#6286)
## Why are these changes needed?

This PR updates `SelectorGroupChat` to support streaming mode for
`select_speaker`.
It introduces a `streaming` argument — when set to `True`,
`select_speaker` will use `create_streaming()` instead of `create()`.

## Additional context

Some models (e.g., QwQ) only work properly in streaming mode.  
To support them, the prompt selection step in `SelectorGroupChat` must
also run with `streaming=True`.

## Related issue number

Closes #6145

## Checks

- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 15:48:48 -07:00
Eric Zhu
71363a30ec
Add experimental notice to canvas (#6349) 2025-04-21 21:31:12 +00:00
EeS
4d381d7078
DOC: add extentions - autogen-oaiapi and autogen-contextplus (#6338)
DOC: add extentions - autogen-oaiapi and autogen-contextplus

the contextplus is user define autogen model_context.
It discussion in #6217 and #6160

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 19:23:17 +00:00
Peter Jausovec
4d3e47a0f1
fix: ensure serialized messages are passed to LLMStreamStartEvent (#6344)
## Why are these changes needed?


I was getting the following exception when doing tool calls with
anthropic - the exception was coming form the `__str__` in
`LLMStreamStartEvent`.

```
('Object of type ToolUseBlock is not JSON serializable',)
```

The issue is that when creating the LLMStreamStartevent in the
`create_stream`, the messages weren't being serialized first.
## Related issue number

Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 11:43:21 -07:00
EeS
1de07ab293
Generalize Continuous SystemMessage merging via model_info[“multiple_system_messages”] instead of startswith("gemini-") (#6345)
The current implementation of consecutive `SystemMessage` merging
applies only to models where `model_info.family` starts with
`"gemini-"`.

Since PR #6327 introduced the `multiple_system_messages` field in
`model_info`, we can now generalize this logic by checking whether the
field is explicitly set to `False`.

This change replaces the hardcoded family check with a conditional that
merges consecutive `SystemMessage` blocks whenever
`multiple_system_messages` is set to `False`.

Test cases that previously depended on the `"gemini"` model family have
been updated to reflect this configuration flag, and renamed accordingly
for clarity.

In addition, for consistency across conditional logic, a follow-up PR is
planned to refactor the Claude-specific transformation condition
(currently implemented via `create_args.get("model",
"unknown").startswith("claude-")`)
to instead use the existing `is_claude()`.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 11:30:35 -07:00
Leonardo Pinheiro
99aac24dd3
Agentchat canvas (#6215)
<!-- Thank you for your contribution! Please review
https://microsoft.github.io/autogen/docs/Contribute before opening a
pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR.
If you don't have the access to it, we will shortly find a reviewer and
assign them to your PR. -->

## Why are these changes needed?

This is an initial exploration of what could be a solution for #6214 .
It implements a simple text canvas using difflib and also a memory
component and a tool component for interacting with the canvas. Still in
early testing but would love feedback on the design.

## Related issue number

<!-- For example: "Closes #1234" -->

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [ ] I've made sure all auto checks have passed.

---------

Co-authored-by: Leonardo Pinheiro <lpinheiro@microsoft.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-21 18:03:29 +10:00
Eric Zhu
183dbb8dd1
Update version 0.5.4 (#6334) 2025-04-18 17:19:07 -07:00
Enhao Zhang
0e4efd0efc
Add example for parallel agents (#6311)
This PR adds an example of `parallel-agents` that runs multiple
instances of Magentic-One in parallel, with support for early
termination and final answer aggregation.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-18 08:48:56 -07:00
Jay Prakash Thakur
e49ee48908
Bugfix: Azure AI Search Tool - fix query type (#6331) 2025-04-18 05:50:49 +00:00
EeS
b13264ac60
FEAT: adding multiple_system_message on model_info (#6327)
## Why are these changes needed?
`SocietyOfMindAgent` has multiple system message, however many
client/model does not support it.

## Related issue number
Related #6290

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-17 22:39:47 -07:00
masquerlin
4a5dd9eec9
Make Docker Jupyter support to the Version 0.4 as Version 0.2 (#6231)
This PR introduces a safer and more controllable execution environment
for LLM code execution in version 0.4 by enabling the use of Jupyter
inside a container. This enhancement addresses security concerns and
provides a more robust execution context. In particular, it allows:

Isolation of code execution via containerized Jupyter environments.

Persistent memory of variables and their values throughout the
conversation.

Memory of code execution results to support more advanced reasoning and
follow-up tasks.

These improvements help build a more interactive and stateful LLM-agent
programming experience, especially for iterative code generation and
debugging scenarios.

## Related issue number

Open #6153

## Checks

- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-17 21:25:57 +00:00
Eitan Yarmush
1035065c4e
Introduce AgentTool and TeamTool (#5924)
---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-17 00:45:33 -07:00
Eric Zhu
ca5134d5a8
Update website 0.5.3 (#6320) 2025-04-16 20:40:33 -07:00
Eric Zhu
fb16d5acf9
Make sure thought content is included in handoff context (#6319)
Resolves #6295

Ensure the thought content gets included in handoff message conetxt,
when the only tool call was handoff tool call.
2025-04-17 03:22:49 +00:00
Eric Zhu
165c189f0e
Print message types in Console (#6318)
Resolves #6270
2025-04-16 20:07:43 -07:00
Jay Prakash Thakur
bb792b0734
Fix: Azure AI Search Tool Client Lifetime Management (#6316)
## Why are these changes needed?
This PR fixes a bug where the underlying azure `SearchClient` was being
closed prematurely due to use of `async with client` : inside the tool's
run method. this caused the users to encounter errors "HTTP transport
has already been closed"

## Related issue number

Closes #6308 "

## Checks

- [ ] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [X] I've made sure all auto checks have passed.

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-16 19:39:27 -07:00
Eric Zhu
629fb86e96
Add GPT4.1, o4-mini and o3 (#6314) 2025-04-17 01:10:14 +00:00
Eric Zhu
27b834f296
Make shared session possible for MCP tool (#6312)
Resolves #6232, #6198

This PR introduces an optional parameter `session` to `mcp_server_tools`
to support reuse of the same session.

```python
import asyncio

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.tools.mcp import StdioServerParams, create_mcp_server_session, mcp_server_tools


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", parallel_tool_calls=False)  # type: ignore
    params = StdioServerParams(
        command="npx",
        args=["@playwright/mcp@latest"],
        read_timeout_seconds=60,
    )
    async with create_mcp_server_session(params) as session:
        await session.initialize()
        tools = await mcp_server_tools(server_params=params, session=session)
        print(f"Tools: {[tool.name for tool in tools]}")

        agent = AssistantAgent(
            name="Assistant",
            model_client=model_client,
            tools=tools,  # type: ignore
        )

        termination = TextMentionTermination("TERMINATE")
        team = RoundRobinGroupChat([agent], termination_condition=termination)
        await Console(
            team.run_stream(
                task="Go to https://ekzhu.com/, visit the first link in the page, then tell me about the linked page."
            )
        )


asyncio.run(main())
``` 

Based on discussion in this thread: #6284, we will consider
serialization and deserialization of MCP server tools when used in this
manner in a separate issue.

This PR also replaces the `json_schema_to_pydantic` dependency with
built-in utils.
2025-04-16 17:43:28 -07:00
EeS
844de21c00
[FEATURE] Option to emit group chat manager messages in AgentChat (#6303)
Add an option emit_team_events to BaseGroupChat to emit events from
group chat manager through run_stream.
SpeakerSelectedEvent from group chat speaker selection.

Closes #6161

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-16 13:41:16 -07:00
abhinav-aegis
a4a16fd2f8
Aegis structure message (#6289)
Added support for structured message component using the Json to
Pydantic utility functions. Note: also adding the ability to use a
format string for structured messages.

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-16 12:00:14 -07:00
Eric Zhu
8bd162f8fc
Update version to 0.5.3 (#6310) 2025-04-16 11:02:25 -07:00
amoghmc
71b7429a42
Add missing C# and F# kernels (#6283)
Add missing C# and F# kernels.
These are needed to create a default kernel else it will return an empty
kernel.
2025-04-15 20:15:28 +00:00
cheng-tan
88dda88f53
Pin opentelemetry-proto version (#6305)
## Description
This PR pins opentelemetry-proto version to >=1.28.0, which uses
protobuf > 5.0, < 6.0 to generate protobuf files.

## Related issue number
Closes #6304
2025-04-15 09:04:01 -07:00
Yash Malik
7e8472f99b
minor grammatical fix in docs (#6263)
minor grammatical fix in docs

Co-authored-by: Victor Dibia <victordibia@microsoft.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-15 06:14:44 +00:00
Abhijeetsingh Meena
756aef366d
Add code generation support to CodeExecutorAgent (#6098)
## Why are these changes needed?
- To add support for code generation, execution and reflection to
`CodeExecutorAgent`.

## Related issue number
Closes #5824 

## Checks
- [x] I've included any doc changes needed for
<https://microsoft.github.io/autogen/>. See
<https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-14 23:06:40 -07:00
Sungjun.Kim
71a4eaedf9
Bump up json-schema-to-pydantic from v0.2.3 to v0.2.4 (#6300)
---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2025-04-14 21:50:49 -07:00
Victor Dibia
95b1ed5d81
Update AutoGen dependency range in AGS (#6298) 2025-04-15 04:26:30 +00:00
Eric Zhu
c75515990e
Update website for 0.5.2 (#6299) 2025-04-14 20:51:45 -07:00
251 changed files with 36125 additions and 9594 deletions

View File

@ -90,6 +90,14 @@ body:
multiple: false
options:
- "Python dev (main branch)"
- "Python 0.6.2"
- "Python 0.6.1"
- "Python 0.6.0"
- "Python 0.5.7"
- "Python 0.5.6"
- "Python 0.5.5"
- "Python 0.5.4"
- "Python 0.5.3"
- "Python 0.5.2"
- "Python 0.5.1"
- "Python 0.4.9"

View File

@ -18,7 +18,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -37,7 +36,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -66,7 +64,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -95,7 +92,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -122,7 +118,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -156,7 +151,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -189,7 +183,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
@ -259,7 +252,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -281,7 +273,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -300,7 +291,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -319,7 +309,6 @@ jobs:
- uses: astral-sh/setup-uv@v3
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -338,7 +327,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"

View File

@ -76,7 +76,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- run: uv sync --locked --all-extras
working-directory: ./python
- name: Prepare python venv

View File

@ -32,8 +32,8 @@ jobs:
version:
[
# For main use the workflow target
{ ref: "${{github.ref}}", dest-dir: dev, uv-version: "0.5.13", sphinx-release-override: "dev" },
{ ref: "python-v0.5.1", dest-dir: stable, uv-version: "0.5.13", sphinx-release-override: "stable" },
{ ref: "${{github.ref}}", dest-dir: dev, uv-version: "0.7.13", sphinx-release-override: "dev" },
{ ref: "python-v0.6.2", dest-dir: stable, uv-version: "0.7.13", sphinx-release-override: "stable" },
{ ref: "v0.4.0.post1", dest-dir: "0.4.0", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "v0.4.1", dest-dir: "0.4.1", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "v0.4.2", dest-dir: "0.4.2", uv-version: "0.5.13", sphinx-release-override: "" },
@ -45,6 +45,14 @@ jobs:
{ ref: "python-v0.4.8", dest-dir: "0.4.8", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.4.9-website", dest-dir: "0.4.9", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.1", dest-dir: "0.5.1", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.2", dest-dir: "0.5.2", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.3", dest-dir: "0.5.3", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.4", dest-dir: "0.5.4", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.5", dest-dir: "0.5.5", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.6", dest-dir: "0.5.6", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.5.7", dest-dir: "0.5.7", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.6.1", dest-dir: "0.6.1", uv-version: "0.5.13", sphinx-release-override: "" },
{ ref: "python-v0.6.2", dest-dir: "0.6.2", uv-version: "0.7.13", sphinx-release-override: "" },
]
steps:
- name: Checkout
@ -55,7 +63,7 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: ${{ matrix.version.uv-version }}
version: ${{ matrix.version.uv-version }}
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -105,7 +113,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -136,10 +143,11 @@ jobs:
- name: setup python
uses: actions/setup-python@v5
with:
python-version: "3.8"
python-version: "3.9"
- name: pydoc-markdown install
run: |
python -m pip install --upgrade pip
pip install docspec==2.2.1 docspec-python==2.2.1
pip install pydoc-markdown pyyaml termcolor
# Pin databind packages as version 4.5.0 is not compatible with pydoc-markdown.
pip install databind.core==4.4.2 databind.json==4.4.2

View File

@ -68,7 +68,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -154,7 +153,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
@ -247,7 +245,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"

View File

@ -27,7 +27,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- uses: actions/setup-python@v5
with:
python-version: "3.11"

94
.github/workflows/pytest-mem0.yml vendored Normal file
View File

@ -0,0 +1,94 @@
name: Mem0 Memory Tests
on:
# Run on pushes to any branch
push:
# Also run on pull requests to main
pull_request:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
services:
neo4j:
image: neo4j:5.26.6
ports:
- 7474:7474 # HTTP
- 7687:7687 # BOLT
env:
NEO4J_AUTH: neo4j/password
NEO4J_dbms_security_procedures_unrestricted: apoc.*
# Add this to ensure Neo4j is ready for connections quickly
NEO4J_dbms_memory_pagecache_size: 100M
NEO4J_dbms_memory_heap_initial__size: 100M
NEO4J_dbms_memory_heap_max__size: 500M
# Try a different health check approach
options: >-
--health-cmd "wget -O /dev/null -q http://localhost:7474 || exit 1"
--health-interval 5s
--health-timeout 15s
--health-retries 10
--health-start-period 30s
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Wait for Neo4j
run: |
# Give Neo4j some extra time to start up
sleep 10
# Try to connect to Neo4j
timeout 30s bash -c 'until curl -s http://localhost:7474 > /dev/null; do sleep 1; done'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Install core packages first (in the right order)
cd python/packages/autogen-core
pip install -e .
cd ../autogen-agentchat
pip install -e .
# Now install autogen-ext with its dependencies
cd ../autogen-ext
pip install -e ".[dev,mem0,mem0-local]"
# Install test dependencies
pip install pytest pytest-asyncio pytest-cov
pip install python-dotenv
# Install dependencies for complex configuration tests
pip install "openai>=1.0.0"
pip install deepseek-ai
# Update test config to match the simplified Neo4j setup
- name: Update Neo4j password in tests
run: |
echo "NEO4J_PASSWORD=password" >> $GITHUB_ENV
- name: Run tests with coverage
# env:
# MEM0_API_KEY: ${{ secrets.MEM0_API_KEY }}
# SF_API_KEY: ${{ secrets.SF_API_KEY }}
# DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
run: |
cd python/packages/autogen-ext
pytest --cov=autogen_ext.memory.mem0 tests/memory/test_mem0.py -v --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./python/packages/autogen-ext/coverage.xml
name: codecov-mem0
fail_ci_if_error: false

View File

@ -35,7 +35,6 @@ jobs:
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
version: "0.5.18"
- run: uv build --package ${{ github.event.inputs.package }} --out-dir dist/
working-directory: python
- name: Publish package to PyPI

View File

@ -5,11 +5,51 @@
"url": "/autogen/dev/"
},
{
"name": "0.5.1 (stable)",
"name": "0.6.2 (stable)",
"version": "stable",
"url": "/autogen/stable/",
"preferred": true
},
{
"name": "0.6.1",
"version": "0.6.1",
"url": "/autogen/0.6.1/"
},
{
"name": "0.5.7",
"version": "0.5.7",
"url": "/autogen/0.5.7/"
},
{
"name": "0.5.6",
"version": "0.5.6",
"url": "/autogen/0.5.6/"
},
{
"name": "0.5.5",
"version": "0.5.5",
"url": "/autogen/0.5.5/"
},
{
"name": "0.5.4",
"version": "0.5.4",
"url": "/autogen/0.5.4/"
},
{
"name": "0.5.3",
"version": "0.5.3",
"url": "/autogen/0.5.3/"
},
{
"name": "0.5.2",
"version": "0.5.2",
"url": "/autogen/0.5.2/"
},
{
"name": "0.5.1",
"version": "0.5.1",
"url": "/autogen/0.5.1/"
},
{
"name": "0.4.9",
"version": "0.4.9",
@ -65,4 +105,4 @@
"version": "0.2",
"url": "/autogen/0.2/"
}
]
]

View File

@ -5,7 +5,8 @@
<MicrosoftSemanticKernelStableVersion>1.45.0</MicrosoftSemanticKernelStableVersion>
<MicrosoftSemanticKernelPreviewVersion>$(MicrosoftSemanticKernelStableVersion)-preview</MicrosoftSemanticKernelPreviewVersion>
<MicrosoftSemanticKernelAlphaVersion>$(MicrosoftSemanticKernelStableVersion)-alpha</MicrosoftSemanticKernelAlphaVersion>
<MicrosoftExtensionsAIVersion>9.3.0-preview.1.25161.3</MicrosoftExtensionsAIVersion>
<MicrosoftExtensionsAIVersion>9.5.0</MicrosoftExtensionsAIVersion>
<MicrosoftExtensionsAIPreviewVersion>9.5.0-preview.1.25265.7</MicrosoftExtensionsAIPreviewVersion>
<MicrosoftExtensionConfiguration>9.0.0</MicrosoftExtensionConfiguration>
<MicrosoftExtensionDependencyInjection>9.0.3</MicrosoftExtensionDependencyInjection>
<MicrosoftExtensionLogging>9.0.0</MicrosoftExtensionLogging>
@ -64,9 +65,9 @@
<PackageVersion Include="Microsoft.DotNet.Interactive.PackageManagement" Version="$(MicrosoftDotNetInteractive)" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="$(MicrosoftExtensionsAIVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="$(MicrosoftExtensionsAIVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.AzureAIInference" Version="$(MicrosoftExtensionsAIVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.Ollama" Version="$(MicrosoftExtensionsAIVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="$(MicrosoftExtensionsAIVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.AzureAIInference" Version="$(MicrosoftExtensionsAIPreviewVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.Ollama" Version="$(MicrosoftExtensionsAIPreviewVersion)" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="$(MicrosoftExtensionsAIPreviewVersion)" />
<PackageVersion Include="Microsoft.Extensions.Azure" Version="1.8.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionConfiguration)" />
@ -135,4 +136,4 @@
<PackageVersion Include="xunit.runner.console" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
</Project>
</Project>

View File

@ -40,7 +40,7 @@ var assistantAgent = new AssistantAgent(
// set human input mode to ALWAYS so that user always provide input
var userProxyAgent = new UserProxyAgent(
name: "user",
humanInputMode: ConversableAgent.HumanInputMode.ALWAYS)
humanInputMode: HumanInputMode.ALWAYS)
.RegisterPrintMessage();
// start the conversation

View File

@ -189,12 +189,12 @@ public class FunctionCallMiddleware : IStreamingMiddleware
}
}
private Func<string, Task<string>> AIToolInvokeWrapper(Func<IEnumerable<KeyValuePair<string, object?>>?, CancellationToken, Task<object?>> lambda)
private Func<string, Task<string>> AIToolInvokeWrapper(Func<AIFunctionArguments?, CancellationToken, ValueTask<object?>> lambda)
{
return async (string args) =>
{
var arguments = JsonSerializer.Deserialize<Dictionary<string, object?>>(args);
var result = await lambda(arguments, CancellationToken.None);
var result = await lambda(new(arguments), CancellationToken.None);
return result switch
{

View File

@ -14,7 +14,9 @@ public static class DotnetInteractiveKernelBuilder
public static InProccessDotnetInteractiveKernelBuilder CreateDefaultInProcessKernelBuilder()
{
return new InProccessDotnetInteractiveKernelBuilder();
return new InProccessDotnetInteractiveKernelBuilder()
.AddCSharpKernel()
.AddFSharpKernel();
}
#endif

View File

@ -89,7 +89,7 @@ public static class ServiceCollectionChatClientExtensions
.AddChatClient(service =>
{
var openAiClient = service.GetRequiredService<OpenAIClient>();
return openAiClient.AsChatClient(modelOrDeploymentName);
return openAiClient.GetChatClient(modelOrDeploymentName).AsIChatClient();
});
return services;
@ -112,7 +112,7 @@ public static class ServiceCollectionChatClientExtensions
var endpoint = $"{serviceName}:Endpoint" ?? throw new InvalidOperationException($"No endpoint was specified for the Azure Inference Chat Client");
var endpointUri = string.IsNullOrEmpty(endpoint) ? null : new Uri(endpoint);
var token = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY") ?? throw new InvalidOperationException("No model access token was found in the environment variable AZURE_OPENAI_API_KEY");
var chatClient = new ChatCompletionsClient(endpointUri, new AzureKeyCredential(token)).AsChatClient(modelOrDeploymentName);
var chatClient = new ChatCompletionsClient(endpointUri, new AzureKeyCredential(token)).AsIChatClient(modelOrDeploymentName);
hostBuilder.Services.AddChatClient(chatClient);
return hostBuilder.Services;

View File

@ -25,12 +25,18 @@ poe check
- [Install `uv`](https://docs.astral.sh/uv/getting-started/installation/).
**Note:** To prevent incompatibilities between versions the same UV version as is running in CI should be used. Check the version in CI by looking the `setup-uv` action, [here](https://github.com/microsoft/autogen/blob/main/.github/workflows/checks.yml#L40) for example.
To upgrade `uv` to the latest version, run:
```sh
uv self update
```
<!-- **Note:** To prevent incompatibilities between versions the same UV version as is running in CI should be used. Check the version in CI by looking the `setup-uv` action, [here](https://github.com/microsoft/autogen/blob/main/.github/workflows/checks.yml#L40) for example.
For example, to change your version to `0.5.18`, run:
```sh
uv self update 0.5.18
```
``` -->
### Virtual Environment

View File

@ -0,0 +1 @@
__EXPECTED_ANSWER__

View File

@ -0,0 +1 @@
__PROMPT__

View File

@ -0,0 +1,5 @@
tiktoken
pyyaml
/autogen_python/packages/autogen-core
/autogen_python/packages/autogen-ext[openai,magentic-one]
/autogen_python/packages/autogen-agentchat

View File

@ -0,0 +1,402 @@
import asyncio
import os
import re
import logging
import yaml
import warnings
import contextvars
import builtins
import shutil
import json
from datetime import datetime
from typing import List, Optional, Dict
from collections import deque
from autogen_agentchat import TRACE_LOGGER_NAME as AGENTCHAT_TRACE_LOGGER_NAME, EVENT_LOGGER_NAME as AGENTCHAT_EVENT_LOGGER_NAME
from autogen_core import TRACE_LOGGER_NAME as CORE_TRACE_LOGGER_NAME, EVENT_LOGGER_NAME as CORE_EVENT_LOGGER_NAME
from autogen_ext.agents.magentic_one import MagenticOneCoderAgent
from autogen_agentchat.teams import MagenticOneGroupChat
from autogen_agentchat.ui import Console
from autogen_core.models import (
AssistantMessage,
ChatCompletionClient,
LLMMessage,
UserMessage,
)
from autogen_core.logging import LLMCallEvent
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_agentchat.conditions import TextMentionTermination
from autogen_core.models import ChatCompletionClient
from autogen_ext.agents.web_surfer import MultimodalWebSurfer
from autogen_ext.agents.file_surfer import FileSurfer
from autogen_agentchat.agents import CodeExecutorAgent
from autogen_agentchat.messages import (
TextMessage,
AgentEvent,
ChatMessage,
HandoffMessage,
MultiModalMessage,
StopMessage,
TextMessage,
ToolCallExecutionEvent,
ToolCallRequestEvent,
ToolCallSummaryMessage,
)
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.models.openai._model_info import _MODEL_TOKEN_LIMITS, resolve_model
from autogen_agentchat.utils import content_to_str
# Suppress warnings about the requests.Session() not being closed
warnings.filterwarnings(action="ignore", message="unclosed", category=ResourceWarning)
core_event_logger = logging.getLogger(CORE_EVENT_LOGGER_NAME)
agentchat_event_logger = logging.getLogger(AGENTCHAT_EVENT_LOGGER_NAME)
agentchat_trace_logger = logging.getLogger(AGENTCHAT_TRACE_LOGGER_NAME)
# Create a context variable to hold the current team's log file and the current team id.
current_log_file = contextvars.ContextVar("current_log_file", default=None)
current_team_id = contextvars.ContextVar("current_team_id", default=None)
# Save the original print function and event_logger.info method.
original_print = builtins.print
original_agentchat_event_logger_info = agentchat_event_logger.info
original_core_event_logger_info = core_event_logger.info
class LogHandler(logging.FileHandler):
def __init__(self, filename: str = "log.jsonl", print_message: bool = True) -> None:
super().__init__(filename, mode="w")
self.print_message = print_message
def emit(self, record: logging.LogRecord) -> None:
try:
ts = datetime.fromtimestamp(record.created).isoformat()
if AGENTCHAT_EVENT_LOGGER_NAME in record.name:
original_msg = record.msg
record.msg = json.dumps(
{
"timestamp": ts,
"source": record.msg.source,
"message": content_to_str(record.msg.content),
"type": record.msg.type,
}
)
super().emit(record)
record.msg = original_msg
elif CORE_EVENT_LOGGER_NAME in record.name:
if isinstance(record.msg, LLMCallEvent):
original_msg = record.msg
record.msg = json.dumps(
{
"timestamp": ts,
"prompt_tokens": record.msg.kwargs["prompt_tokens"],
"completion_tokens": record.msg.kwargs["completion_tokens"],
"type": "LLMCallEvent",
}
)
super().emit(record)
record.msg = original_msg
except Exception:
print("error in logHandler.emit", flush=True)
self.handleError(record)
def tee_print(*args, **kwargs):
# Get the current log file from the context.
log_file = current_log_file.get()
# Call the original print (goes to the console).
original_print(*args, **kwargs)
# Also write to the log file if one is set.
if log_file is not None:
sep = kwargs.get("sep", " ")
end = kwargs.get("end", "\n")
message = sep.join(map(str, args)) + end
log_file.write(message)
log_file.flush()
def team_specific_agentchat_event_logger_info(msg, *args, **kwargs):
team_id = current_team_id.get()
if team_id is not None:
# Get a logger with a team-specific name.
team_logger = logging.getLogger(f"{AGENTCHAT_EVENT_LOGGER_NAME}.team{team_id}")
team_logger.info(msg, *args, **kwargs)
else:
original_agentchat_event_logger_info(msg, *args, **kwargs)
def team_specific_core_event_logger_info(msg, *args, **kwargs):
team_id = current_team_id.get()
if team_id is not None:
# Get a logger with a team-specific name.
team_logger = logging.getLogger(f"{CORE_EVENT_LOGGER_NAME}.team{team_id}")
team_logger.info(msg, *args, **kwargs)
else:
original_core_event_logger_info(msg, *args, **kwargs)
# Monkey-patch the built-in print and event_logger.info methods with our team-specific versions.
builtins.print = tee_print
agentchat_event_logger.info = team_specific_agentchat_event_logger_info
core_event_logger.info = team_specific_core_event_logger_info
async def run_team(team: MagenticOneGroupChat, team_idx: int, task: str, cancellation_token: CancellationToken, logfile):
token_logfile = current_log_file.set(logfile)
token_team_id = current_team_id.set(team_idx)
try:
task_result = await Console(
team.run_stream(
task=task.strip(),
cancellation_token=cancellation_token
)
)
return team_idx, task_result
finally:
current_log_file.reset(token_logfile)
current_team_id.reset(token_team_id)
logfile.close()
async def aggregate_final_answer(task: str, client: ChatCompletionClient, team_results, source: str = "Aggregator", cancellation_token: Optional[CancellationToken] = None) -> str:
"""
team_results: {"team_key": TaskResult}
team_completion_order: The order in which the teams completed their tasks
"""
if len(team_results) == 1:
final_answer = list(team_results.values())[0].messages[-1].content
aggregator_logger.info(
f"{source} (Response):\n{final_answer}"
)
return final_answer
assert len(team_results) > 1
aggregator_messages_to_send = {team_id: deque() for team_id in team_results.keys()} # {team_id: context}
team_ids = list(team_results.keys())
current_round = 0
while (
not all(len(team_result.messages) == 0 for team_result in team_results.values())
and ((not resolve_model(client._create_args["model"]) in _MODEL_TOKEN_LIMITS) or client.remaining_tokens([m for messages in aggregator_messages_to_send.values() for m in messages])
> 2000)
):
team_idx = team_ids[current_round % len(team_ids)]
if len(team_results[team_idx].messages) > 0:
m = team_results[team_idx].messages[-1]
if isinstance(m, ToolCallRequestEvent | ToolCallExecutionEvent):
# Ignore tool call messages.
pass
elif isinstance(m, StopMessage | HandoffMessage):
aggregator_messages_to_send[team_idx].appendleft(UserMessage(content=m.to_model_text(), source=m.source))
elif m.source == "MagenticOneOrchestrator":
assert isinstance(m, TextMessage | ToolCallSummaryMessage)
aggregator_messages_to_send[team_idx].appendleft(AssistantMessage(content=m.to_model_text(), source=m.source))
else:
assert isinstance(m, (TextMessage, MultiModalMessage, ToolCallSummaryMessage))
aggregator_messages_to_send[team_idx].appendleft(UserMessage(content=m.to_model_text(), source=m.source))
team_results[team_idx].messages.pop()
current_round += 1
# Log the messages to send
payload = ""
for team_idx, messages in aggregator_messages_to_send.items():
payload += f"\n{'*'*75} \n" f"Team #: {team_idx}" f"\n{'*'*75} \n"
for message in messages:
payload += f"\n{'-'*75} \n" f"{message.source}:\n" f"\n{message.content}\n"
payload += f"\n{'-'*75} \n" f"Team #{team_idx} stop reason:\n" f"\n{team_results[team_idx].stop_reason}\n"
payload += f"\n{'*'*75} \n"
aggregator_logger.info(f"{source} (Aggregator Messages):\n{payload}")
context: List[LLMMessage] = []
# Add the preamble
context.append(
UserMessage(
content=f"Earlier you were asked the following:\n\n{task}\n\nYour team then worked diligently to address that request. You have been provided with a collection of transcripts and stop reasons from {len(team_results)} different teams to the question. Your task is to carefully evaluate the correctness of each team's response by analyzing their respective transcripts and stop reasons. After considering all perspectives, provide a FINAL ANSWER to the question. It is crucial to critically evaluate the information provided in these responses, recognizing that some of it may be biased or incorrect.",
source=source,
)
)
for team_idx, aggregator_messages in aggregator_messages_to_send.items():
context.append(
UserMessage(
content=f"Transcript from Team #{team_idx}:",
source=source,
)
)
for message in aggregator_messages:
context.append(message)
context.append(
UserMessage(
content=f"Stop reason from Team #{team_idx}:",
source=source,
)
)
context.append(
UserMessage(
content=team_results[team_idx].stop_reason if team_results[team_idx].stop_reason else "No stop reason provided.",
source=source,
)
)
# ask for the final answer
context.append(
UserMessage(
content=f"""
Let's think step-by-step. Carefully review the conversation above, critically evaluate the correctness of each team's response, and then output a FINAL ANSWER to the question. The question is repeated here for convenience:
{task}
To output the final answer, use the following template: FINAL ANSWER: [YOUR FINAL ANSWER]
Your FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
ADDITIONALLY, your FINAL ANSWER MUST adhere to any formatting instructions specified in the original question (e.g., alphabetization, sequencing, units, rounding, decimal places, etc.)
If you are asked for a number, express it numerically (i.e., with digits rather than words), don't use commas, and don't include units such as $ or percent signs unless specified otherwise.
If you are asked for a string, don't use articles or abbreviations (e.g. for cities), unless specified otherwise. Don't output any final sentence punctuation such as '.', '!', or '?'.
If you are asked for a comma separated list, apply the above rules depending on whether the elements are numbers or strings.
""".strip(),
source=source,
)
)
response = await client.create(context, cancellation_token=cancellation_token)
assert isinstance(response.content, str)
final_answer = re.sub(r"FINAL ANSWER:", "[FINAL ANSWER]:", response.content)
aggregator_logger.info(
f"{source} (Response):\n{final_answer}"
)
return re.sub(r"FINAL ANSWER:", "FINAL AGGREGATED ANSWER:", response.content)
async def main(num_teams: int, num_answers: int) -> None:
# Load model configuration and create the model client.
with open("config.yaml", "r") as f:
config = yaml.safe_load(f)
orchestrator_client = ChatCompletionClient.load_component(config["orchestrator_client"])
coder_client = ChatCompletionClient.load_component(config["coder_client"])
web_surfer_client = ChatCompletionClient.load_component(config["web_surfer_client"])
file_surfer_client = ChatCompletionClient.load_component(config["file_surfer_client"])
# Read the prompt
prompt = ""
with open("prompt.txt", "rt") as fh:
prompt = fh.read().strip()
filename = "__FILE_NAME__".strip()
# Prepare the prompt
filename_prompt = ""
if len(filename) > 0:
filename_prompt = f"The question is about a file, document or image, which can be accessed by the filename '{filename}' in the current working directory."
task = f"{prompt}\n\n{filename_prompt}"
# Reset logs directory (remove all files in it)
logs_dir = "logs"
if os.path.exists(logs_dir):
shutil.rmtree(logs_dir)
teams = []
async_tasks = []
tokens = []
for team_idx in range(num_teams):
# Set up the team
coder = MagenticOneCoderAgent(
"Assistant",
model_client = coder_client,
)
executor = CodeExecutorAgent("ComputerTerminal", code_executor=LocalCommandLineCodeExecutor())
file_surfer = FileSurfer(
name="FileSurfer",
model_client = file_surfer_client,
)
web_surfer = MultimodalWebSurfer(
name="WebSurfer",
model_client = web_surfer_client,
downloads_folder=os.getcwd(),
debug_dir=logs_dir,
to_save_screenshots=True,
)
team = MagenticOneGroupChat(
[coder, executor, file_surfer, web_surfer],
model_client=orchestrator_client,
max_turns=30,
final_answer_prompt= f""",
We have completed the following task:
{prompt}
The above messages contain the conversation that took place to complete the task.
Read the above conversation and output a FINAL ANSWER to the question.
To output the final answer, use the following template: FINAL ANSWER: [YOUR FINAL ANSWER]
Your FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
ADDITIONALLY, your FINAL ANSWER MUST adhere to any formatting instructions specified in the original question (e.g., alphabetization, sequencing, units, rounding, decimal places, etc.)
If you are asked for a number, express it numerically (i.e., with digits rather than words), don't use commas, and don't include units such as $ or percent signs unless specified otherwise.
If you are asked for a string, don't use articles or abbreviations (e.g. for cities), unless specified otherwise. Don't output any final sentence punctuation such as '.', '!', or '?'.
If you are asked for a comma separated list, apply the above rules depending on whether the elements are numbers or strings.
""".strip()
)
teams.append(team)
cancellation_token = CancellationToken()
tokens.append(cancellation_token)
logfile = open(f"console_log_{team_idx}.txt", "w")
team_agentchat_logger = logging.getLogger(f"{AGENTCHAT_EVENT_LOGGER_NAME}.team{team_idx}")
team_core_logger = logging.getLogger(f"{CORE_EVENT_LOGGER_NAME}.team{team_idx}")
team_log_handler = LogHandler(f"log_{team_idx}.jsonl", print_message=False)
team_agentchat_logger.addHandler(team_log_handler)
team_core_logger.addHandler(team_log_handler)
async_task = asyncio.create_task(
run_team(team, team_idx, task, cancellation_token, logfile)
)
async_tasks.append(async_task)
# Wait until at least num_answers tasks have completed.
team_results = {}
for future in asyncio.as_completed(async_tasks):
try:
team_id, result = await future
team_results[team_id] = result
except Exception as e:
# Optionally log exception.
print(f"Task raised an exception: {e}")
if len(team_results) >= num_answers:
break
# Cancel any pending teams.
for task, token in zip(async_tasks, tokens):
if not task.done():
token.cancel()
# Await all tasks to handle cancellation gracefully.
await asyncio.gather(*async_tasks, return_exceptions=True)
print("len(team_results):", len(team_results))
final_answer = await aggregate_final_answer(prompt, orchestrator_client, team_results)
print(final_answer)
if __name__ == "__main__":
num_teams = 3
num_answers = 3
agentchat_trace_logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler("trace.log", mode="w")
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
file_handler.setFormatter(formatter)
agentchat_trace_logger.addHandler(file_handler)
core_event_logger.setLevel(logging.DEBUG)
agentchat_event_logger.setLevel(logging.DEBUG)
log_handler = LogHandler()
core_event_logger.addHandler(log_handler)
agentchat_event_logger.addHandler(log_handler)
# Create another logger for the aggregator
aggregator_logger = logging.getLogger("aggregator")
aggregator_logger.setLevel(logging.DEBUG)
fh = logging.FileHandler("aggregator_log.txt", mode="w")
fh.setLevel(logging.DEBUG)
aggregator_logger.addHandler(fh)
asyncio.run(main(num_teams, num_answers))

View File

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "autogen-agentchat"
version = "0.5.2"
version = "0.6.2"
license = {file = "LICENSE-CODE"}
description = "AutoGen agents and teams library"
readme = "README.md"
@ -15,7 +15,7 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = [
"autogen-core==0.5.2",
"autogen-core==0.6.2",
]
[tool.ruff]

View File

@ -6,6 +6,7 @@ BaseChatAgent is the base class for all agents in AgentChat.
from ._assistant_agent import AssistantAgent
from ._base_chat_agent import BaseChatAgent
from ._code_executor_agent import CodeExecutorAgent
from ._message_filter_agent import MessageFilterAgent, MessageFilterConfig, PerSourceFilter
from ._society_of_mind_agent import SocietyOfMindAgent
from ._user_proxy_agent import UserProxyAgent
@ -15,4 +16,7 @@ __all__ = [
"CodeExecutorAgent",
"SocietyOfMindAgent",
"UserProxyAgent",
"MessageFilterAgent",
"MessageFilterConfig",
"PerSourceFilter",
]

View File

@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from typing import Any, AsyncGenerator, List, Mapping, Sequence
from autogen_core import CancellationToken, ComponentBase
from autogen_core import CancellationToken, ComponentBase, trace_create_agent_span, trace_invoke_agent_span
from pydantic import BaseModel
from ..base import ChatAgent, Response, TaskResult
@ -39,10 +39,15 @@ class BaseChatAgent(ChatAgent, ABC, ComponentBase[BaseModel]):
component_type = "agent"
def __init__(self, name: str, description: str) -> None:
self._name = name
if self._name.isidentifier() is False:
raise ValueError("The agent name must be a valid Python identifier.")
self._description = description
"""Initialize the agent with a name and description."""
with trace_create_agent_span(
agent_name=name,
agent_description=description,
):
self._name = name
if self._name.isidentifier() is False:
raise ValueError("The agent name must be a valid Python identifier.")
self._description = description
@property
def name(self) -> str:
@ -108,81 +113,103 @@ class BaseChatAgent(ChatAgent, ABC, ComponentBase[BaseModel]):
*,
task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
cancellation_token: CancellationToken | None = None,
output_task_messages: bool = True,
) -> TaskResult:
"""Run the agent with the given task and return the result."""
if cancellation_token is None:
cancellation_token = CancellationToken()
input_messages: List[BaseChatMessage] = []
output_messages: List[BaseAgentEvent | BaseChatMessage] = []
if task is None:
pass
elif isinstance(task, str):
text_msg = TextMessage(content=task, source="user")
input_messages.append(text_msg)
output_messages.append(text_msg)
elif isinstance(task, BaseChatMessage):
input_messages.append(task)
output_messages.append(task)
else:
if not task:
raise ValueError("Task list cannot be empty.")
# Task is a sequence of messages.
for msg in task:
if isinstance(msg, BaseChatMessage):
input_messages.append(msg)
output_messages.append(msg)
else:
raise ValueError(f"Invalid message type in sequence: {type(msg)}")
response = await self.on_messages(input_messages, cancellation_token)
if response.inner_messages is not None:
output_messages += response.inner_messages
output_messages.append(response.chat_message)
return TaskResult(messages=output_messages)
with trace_invoke_agent_span(
agent_name=self.name,
agent_description=self.description,
):
if cancellation_token is None:
cancellation_token = CancellationToken()
input_messages: List[BaseChatMessage] = []
output_messages: List[BaseAgentEvent | BaseChatMessage] = []
if task is None:
pass
elif isinstance(task, str):
text_msg = TextMessage(content=task, source="user")
input_messages.append(text_msg)
if output_task_messages:
output_messages.append(text_msg)
elif isinstance(task, BaseChatMessage):
input_messages.append(task)
if output_task_messages:
output_messages.append(task)
else:
if not task:
raise ValueError("Task list cannot be empty.")
# Task is a sequence of messages.
for msg in task:
if isinstance(msg, BaseChatMessage):
input_messages.append(msg)
if output_task_messages:
output_messages.append(msg)
else:
raise ValueError(f"Invalid message type in sequence: {type(msg)}")
response = await self.on_messages(input_messages, cancellation_token)
if response.inner_messages is not None:
output_messages += response.inner_messages
output_messages.append(response.chat_message)
return TaskResult(messages=output_messages)
async def run_stream(
self,
*,
task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
cancellation_token: CancellationToken | None = None,
output_task_messages: bool = True,
) -> AsyncGenerator[BaseAgentEvent | BaseChatMessage | TaskResult, None]:
"""Run the agent with the given task and return a stream of messages
and the final task result as the last item in the stream."""
if cancellation_token is None:
cancellation_token = CancellationToken()
input_messages: List[BaseChatMessage] = []
output_messages: List[BaseAgentEvent | BaseChatMessage] = []
if task is None:
pass
elif isinstance(task, str):
text_msg = TextMessage(content=task, source="user")
input_messages.append(text_msg)
output_messages.append(text_msg)
yield text_msg
elif isinstance(task, BaseChatMessage):
input_messages.append(task)
output_messages.append(task)
yield task
else:
if not task:
raise ValueError("Task list cannot be empty.")
for msg in task:
if isinstance(msg, BaseChatMessage):
input_messages.append(msg)
output_messages.append(msg)
yield msg
else:
raise ValueError(f"Invalid message type in sequence: {type(msg)}")
async for message in self.on_messages_stream(input_messages, cancellation_token):
if isinstance(message, Response):
yield message.chat_message
output_messages.append(message.chat_message)
yield TaskResult(messages=output_messages)
and the final task result as the last item in the stream.
Args:
task: The task to run. Can be a string, a single message, or a sequence of messages.
cancellation_token: The cancellation token to kill the task immediately.
output_task_messages: Whether to include task messages in the output stream. Defaults to True for backward compatibility.
"""
with trace_invoke_agent_span(
agent_name=self.name,
agent_description=self.description,
):
if cancellation_token is None:
cancellation_token = CancellationToken()
input_messages: List[BaseChatMessage] = []
output_messages: List[BaseAgentEvent | BaseChatMessage] = []
if task is None:
pass
elif isinstance(task, str):
text_msg = TextMessage(content=task, source="user")
input_messages.append(text_msg)
if output_task_messages:
output_messages.append(text_msg)
yield text_msg
elif isinstance(task, BaseChatMessage):
input_messages.append(task)
if output_task_messages:
output_messages.append(task)
yield task
else:
yield message
if isinstance(message, ModelClientStreamingChunkEvent):
# Skip the model client streaming chunk events.
continue
output_messages.append(message)
if not task:
raise ValueError("Task list cannot be empty.")
for msg in task:
if isinstance(msg, BaseChatMessage):
input_messages.append(msg)
if output_task_messages:
output_messages.append(msg)
yield msg
else:
raise ValueError(f"Invalid message type in sequence: {type(msg)}")
async for message in self.on_messages_stream(input_messages, cancellation_token):
if isinstance(message, Response):
yield message.chat_message
output_messages.append(message.chat_message)
yield TaskResult(messages=output_messages)
else:
yield message
if isinstance(message, ModelClientStreamingChunkEvent):
# Skip the model client streaming chunk events.
continue
output_messages.append(message)
@abstractmethod
async def on_reset(self, cancellation_token: CancellationToken) -> None:

View File

@ -1,45 +1,118 @@
import logging
import re
from typing import List, Sequence
from typing import (
AsyncGenerator,
List,
Optional,
Sequence,
Union,
)
from autogen_core import CancellationToken, Component, ComponentModel
from autogen_core.code_executor import CodeBlock, CodeExecutor
from autogen_core.code_executor import CodeBlock, CodeExecutor, CodeResult
from autogen_core.model_context import (
ChatCompletionContext,
UnboundedChatCompletionContext,
)
from autogen_core.models import (
AssistantMessage,
ChatCompletionClient,
CreateResult,
LLMMessage,
SystemMessage,
UserMessage,
)
from pydantic import BaseModel
from typing_extensions import Self
from .. import EVENT_LOGGER_NAME
from ..base import Response
from ..messages import BaseChatMessage, TextMessage
from ..messages import (
BaseAgentEvent,
BaseChatMessage,
CodeExecutionEvent,
CodeGenerationEvent,
HandoffMessage,
ModelClientStreamingChunkEvent,
TextMessage,
ThoughtEvent,
)
from ..utils import remove_images
from ._base_chat_agent import BaseChatAgent
event_logger = logging.getLogger(EVENT_LOGGER_NAME)
class CodeExecutorAgentConfig(BaseModel):
"""Configuration for CodeExecutorAgent"""
name: str
code_executor: ComponentModel
description: str = "A computer terminal that performs no other action than running Python scripts (provided to it quoted in ```python code blocks), or sh shell scripts (provided to it quoted in ```sh code blocks)."
model_client: ComponentModel | None = None
description: str | None = None
sources: List[str] | None = None
system_message: str | None = None
model_client_stream: bool = False
model_context: ComponentModel | None = None
supported_languages: List[str] | None = None
class RetryDecision(BaseModel):
reason: str
retry: bool
class CodeExecutorAgent(BaseChatAgent, Component[CodeExecutorAgentConfig]):
"""An agent that extracts and executes code snippets found in received
:class:`~autogen_agentchat.messages.TextMessage` messages and returns the output
of the code execution.
It is typically used within a team with another agent that generates code snippets to be executed.
"""(Experimental) An agent that generates and executes code snippets based on user instructions.
.. note::
Consider :class:`~autogen_ext.tools.code_execution.PythonCodeExecutionTool`
as an alternative to this agent. The tool allows for executing Python code
within a single agent, rather than sending it to a separate agent for execution.
However, the model for the agent will have to generate properly escaped code
string as a parameter to the tool.
This agent is experimental and may change in future releases.
It is typically used within a team with another agent that generates code snippets
to be executed or alone with `model_client` provided so that it can generate code
based on user query, execute it and reflect on the code result.
When used with `model_client`, it will generate code snippets using the model
and execute them using the provided `code_executor`. The model will also reflect on the
code execution results. The agent will yield the final reflection result from the model
as the final response.
When used without `model_client`, it will only execute code blocks found in
:class:`~autogen_agentchat.messages.TextMessage` messages and returns the output
of the code execution.
.. note::
Using :class:`~autogen_agentchat.agents.AssistantAgent` with
:class:`~autogen_ext.tools.code_execution.PythonCodeExecutionTool`
is an alternative to this agent. However, the model for that agent will
have to generate properly escaped code string as a parameter to the tool.
Args:
name: The name of the agent.
code_executor: The CodeExecutor responsible for executing code received in messages (:py:class:`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor` recommended. See example below)
description (optional): The description of the agent.
sources (optional): Check only messages from the specified agents for the code to execute.
name (str): The name of the agent.
code_executor (CodeExecutor): The code executor responsible for executing code received in messages
(:py:class:`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor` recommended. See example below)
model_client (ChatCompletionClient, optional): The model client to use for inference and generating code.
If not provided, the agent will only execute code blocks found in input messages.
Currently, the model must support structured output mode, which is required for
the automatic retry mechanism to work.
model_client_stream (bool, optional): If `True`, the model client will be used in streaming mode.
:meth:`on_messages_stream` and :meth:`BaseChatAgent.run_stream` methods will
also yield :class:`~autogen_agentchat.messages.ModelClientStreamingChunkEvent`
messages as the model client produces chunks of response. Defaults to `False`.
description (str, optional): The description of the agent. If not provided,
:class:`~autogen_agentchat.agents.CodeExecutorAgent.DEFAULT_AGENT_DESCRIPTION` will be used.
system_message (str, optional): The system message for the model. If provided, it will be prepended to the messages in the model context when making an inference. Set to `None` to disable.
Defaults to :class:`~autogen_agentchat.agents.CodeExecutorAgent.DEFAULT_SYSTEM_MESSAGE`. This is only used if `model_client` is provided.
sources (Sequence[str], optional): Check only messages from the specified agents for the code to execute.
This is useful when the agent is part of a group chat and you want to limit the code execution to messages from specific agents.
If not provided, all messages will be checked for code blocks.
This is only used if `model_client` is not provided.
max_retries_on_error (int, optional): The maximum number of retries on error. If the code execution fails, the agent will retry up to this number of times.
If the code execution fails after this number of retries, the agent will yield a reflection result.
supported_languages (List[str], optional): List of programming languages that will be parsed and executed from agent response;
others will be ignored. Defaults to DEFAULT_SUPPORTED_LANGUAGES.
.. note::
@ -101,8 +174,166 @@ class CodeExecutorAgent(BaseChatAgent, Component[CodeExecutorAgentConfig]):
asyncio.run(run_code_executor_agent())
In this example, we show how to set up a `CodeExecutorAgent` agent that uses the
:py:class:`~docker.types.DeviceRequest` to expose a GPU to the container for cuda-accelerated code execution.
.. code-block:: python
import asyncio
from autogen_agentchat.agents import CodeExecutorAgent
from autogen_agentchat.messages import TextMessage
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_core import CancellationToken
from docker.types import DeviceRequest
async def run_code_executor_agent() -> None:
# Create a code executor agent that uses a Docker container to execute code.
code_executor = DockerCommandLineCodeExecutor(
work_dir="coding", device_requests=[DeviceRequest(count=-1, capabilities=[["gpu"]])]
)
await code_executor.start()
code_executor_agent = CodeExecutorAgent("code_executor", code_executor=code_executor)
# Display the GPU information
task = TextMessage(
content='''Here is some code
```bash
nvidia-smi
```
''',
source="user",
)
response = await code_executor_agent.on_messages([task], CancellationToken())
print(response.chat_message)
# Stop the code executor.
await code_executor.stop()
asyncio.run(run_code_executor_agent())
In the following example, we show how to setup `CodeExecutorAgent` without `model_client` parameter for executing code blocks generated by other agents in a group chat using :py:class:`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor`
.. code-block:: python
import asyncio
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.agents import AssistantAgent, CodeExecutorAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console
termination_condition = MaxMessageTermination(3)
async def main() -> None:
model_client = OpenAIChatCompletionClient(model="gpt-4o")
# define the Docker CLI Code Executor
code_executor = DockerCommandLineCodeExecutor(work_dir="coding")
# start the execution container
await code_executor.start()
code_executor_agent = CodeExecutorAgent("code_executor_agent", code_executor=code_executor)
coder_agent = AssistantAgent("coder_agent", model_client=model_client)
groupchat = RoundRobinGroupChat(
participants=[coder_agent, code_executor_agent], termination_condition=termination_condition
)
task = "Write python code to print Hello World!"
await Console(groupchat.run_stream(task=task))
# stop the execution container
await code_executor.stop()
asyncio.run(main())
.. code-block:: text
---------- user ----------
Write python code to print Hello World!
---------- coder_agent ----------
Certainly! Here's a simple Python code to print "Hello World!":
```python
print("Hello World!")
```
You can run this code in any Python environment to display the message.
---------- code_executor_agent ----------
Hello World!
In the following example, we show how to setup `CodeExecutorAgent` with `model_client` that can generate its own code without the help of any other agent and executing it in :py:class:`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor`
.. code-block:: python
import asyncio
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.agents import CodeExecutorAgent
from autogen_agentchat.conditions import TextMessageTermination
from autogen_agentchat.ui import Console
termination_condition = TextMessageTermination("code_executor_agent")
async def main() -> None:
model_client = OpenAIChatCompletionClient(model="gpt-4o")
# define the Docker CLI Code Executor
code_executor = DockerCommandLineCodeExecutor(work_dir="coding")
# start the execution container
await code_executor.start()
code_executor_agent = CodeExecutorAgent(
"code_executor_agent", code_executor=code_executor, model_client=model_client
)
task = "Write python code to print Hello World!"
await Console(code_executor_agent.run_stream(task=task))
# stop the execution container
await code_executor.stop()
asyncio.run(main())
.. code-block:: text
---------- user ----------
Write python code to print Hello World!
---------- code_executor_agent ----------
Certainly! Here is a simple Python code to print "Hello World!" to the console:
```python
print("Hello World!")
```
Let's execute it to confirm the output.
---------- code_executor_agent ----------
Hello World!
---------- code_executor_agent ----------
The code has been executed successfully, and it printed "Hello World!" as expected. If you have any more requests or questions, feel free to ask!
"""
DEFAULT_TERMINAL_DESCRIPTION = "A computer terminal that performs no other action than running Python scripts (provided to it quoted in ```python code blocks), or sh shell scripts (provided to it quoted in ```sh code blocks)."
DEFAULT_AGENT_DESCRIPTION = "A Code Execution Agent that generates and executes Python and shell scripts based on user instructions. It ensures correctness, efficiency, and minimal errors while gracefully handling edge cases."
DEFAULT_SYSTEM_MESSAGE = "You are a Code Execution Agent. Your role is to generate and execute Python code and shell scripts based on user instructions, ensuring correctness, efficiency, and minimal errors. Handle edge cases gracefully. Python code should be provided in ```python code blocks, and sh shell scripts should be provided in ```sh code blocks for execution."
NO_CODE_BLOCKS_FOUND_MESSAGE = "No code blocks found in the thread. Please provide at least one markdown-encoded code block to execute (i.e., quoting code in ```python or ```sh code blocks)."
DEFAULT_SUPPORTED_LANGUAGES = ["python", "bash"]
component_config_schema = CodeExecutorAgentConfig
component_provider_override = "autogen_agentchat.agents.CodeExecutorAgent"
@ -111,52 +342,266 @@ class CodeExecutorAgent(BaseChatAgent, Component[CodeExecutorAgentConfig]):
name: str,
code_executor: CodeExecutor,
*,
description: str = "A computer terminal that performs no other action than running Python scripts (provided to it quoted in ```python code blocks), or sh shell scripts (provided to it quoted in ```sh code blocks).",
model_client: ChatCompletionClient | None = None,
model_context: ChatCompletionContext | None = None,
model_client_stream: bool = False,
max_retries_on_error: int = 0,
description: str | None = None,
system_message: str | None = DEFAULT_SYSTEM_MESSAGE,
sources: Sequence[str] | None = None,
supported_languages: List[str] | None = None,
) -> None:
if description is None:
if model_client is None:
description = CodeExecutorAgent.DEFAULT_TERMINAL_DESCRIPTION
else:
description = CodeExecutorAgent.DEFAULT_AGENT_DESCRIPTION
super().__init__(name=name, description=description)
self._code_executor = code_executor
self._sources = sources
self._model_client_stream = model_client_stream
self._max_retries_on_error = max_retries_on_error
if supported_languages is not None:
self._supported_languages = supported_languages
else:
self._supported_languages = CodeExecutorAgent.DEFAULT_SUPPORTED_LANGUAGES
self._supported_languages_regex = "|".join(re.escape(lang) for lang in self._supported_languages)
self._model_client = None
if model_client is not None:
self._model_client = model_client
if model_context is not None:
self._model_context = model_context
else:
self._model_context = UnboundedChatCompletionContext()
self._system_messaages: List[SystemMessage] = []
if system_message is None:
self._system_messages = []
else:
self._system_messages = [SystemMessage(content=system_message)]
if self._max_retries_on_error > 0:
if not self._model_client or not self._model_client.model_info:
raise ValueError("model_client.model_info must be provided when max_retries_on_error > 0")
if not self._model_client.model_info["structured_output"]:
raise ValueError("Specified model_client doesn't support structured output mode.")
@property
def produced_message_types(self) -> Sequence[type[BaseChatMessage]]:
"""The types of messages that the code executor agent produces."""
return (TextMessage,)
@property
def model_context(self) -> ChatCompletionContext:
"""
The model context in use by the agent.
"""
return self._model_context
async def on_messages(self, messages: Sequence[BaseChatMessage], cancellation_token: CancellationToken) -> Response:
async for message in self.on_messages_stream(messages, cancellation_token):
if isinstance(message, Response):
return message
raise AssertionError("The stream should have returned the final result.")
async def on_messages_stream(
self, messages: Sequence[BaseChatMessage], cancellation_token: CancellationToken
) -> AsyncGenerator[BaseAgentEvent | BaseChatMessage | Response, None]:
"""
Process the incoming messages with the assistant agent and yield events/responses as they happen.
"""
# Gather all relevant state here
agent_name = self.name
model_context = self._model_context
system_messages = self._system_messages
model_client = self._model_client
model_client_stream = self._model_client_stream
max_retries_on_error = self._max_retries_on_error
execution_result: CodeResult | None = None
if model_client is None: # default behaviour for backward compatibility
# execute generated code if present
code_blocks: List[CodeBlock] = await self.extract_code_blocks_from_messages(messages)
if not code_blocks:
yield Response(
chat_message=TextMessage(
content=self.NO_CODE_BLOCKS_FOUND_MESSAGE,
source=agent_name,
)
)
return
execution_result = await self.execute_code_block(code_blocks, cancellation_token)
yield Response(chat_message=TextMessage(content=execution_result.output, source=self.name))
return
inner_messages: List[BaseAgentEvent | BaseChatMessage] = []
for nth_try in range(max_retries_on_error + 1): # Do one default generation, execution and inference loop
# Step 1: Add new user/handoff messages to the model context
await self._add_messages_to_context(
model_context=model_context,
messages=messages,
)
# Step 2: Run inference with the model context
model_result = None
async for inference_output in self._call_llm(
model_client=model_client,
model_client_stream=model_client_stream,
system_messages=system_messages,
model_context=model_context,
agent_name=agent_name,
cancellation_token=cancellation_token,
):
if isinstance(inference_output, CreateResult):
model_result = inference_output
else:
# Streaming chunk event
yield inference_output
assert model_result is not None, "No model result was produced."
# Step 3: [NEW] If the model produced a hidden "thought," yield it as an event
if model_result.thought:
thought_event = ThoughtEvent(content=model_result.thought, source=agent_name)
yield thought_event
inner_messages.append(thought_event)
# Step 4: Add the assistant message to the model context (including thought if present)
await model_context.add_message(
AssistantMessage(
content=model_result.content,
source=agent_name,
thought=getattr(model_result, "thought", None),
)
)
# Step 5: Extract the code blocks from inferred text
assert isinstance(model_result.content, str), "Expected inferred model_result.content to be of type str."
code_blocks = self._extract_markdown_code_blocks(str(model_result.content))
# Step 6: Exit the loop if no code blocks found
if not code_blocks:
yield Response(
chat_message=TextMessage(
content=str(model_result.content),
source=agent_name,
)
)
return
# Step 7: Yield a CodeGenerationEvent
inferred_text_message: CodeGenerationEvent = CodeGenerationEvent(
retry_attempt=nth_try,
content=model_result.content,
code_blocks=code_blocks,
source=agent_name,
)
yield inferred_text_message
# Step 8: Execute the extracted code blocks
execution_result = await self.execute_code_block(inferred_text_message.code_blocks, cancellation_token)
# Step 9: Update model context with the code execution result
await model_context.add_message(
UserMessage(
content=execution_result.output,
source=agent_name,
)
)
# Step 10: Yield a CodeExecutionEvent
yield CodeExecutionEvent(retry_attempt=nth_try, result=execution_result, source=self.name)
# If execution was successful or last retry, then exit
if execution_result.exit_code == 0 or nth_try == max_retries_on_error:
break
# Step 11: If exit code is non-zero and retries are available then
# make an inference asking if we should retry or not
chat_context = await model_context.get_messages()
retry_prompt = (
f"The most recent code execution resulted in an error:\n{execution_result.output}\n\n"
"Should we attempt to resolve it? Please respond with:\n"
"- A boolean value for 'retry' indicating whether it should be retried.\n"
"- A detailed explanation in 'reason' that identifies the issue, justifies your decision to retry or not, and outlines how you would resolve the error if a retry is attempted."
)
chat_context = chat_context + [
UserMessage(
content=retry_prompt,
source=agent_name,
)
]
response = await model_client.create(messages=chat_context, json_output=RetryDecision)
assert isinstance(
response.content, str
), "Expected structured response for retry decision to be of type str."
should_retry_generation = RetryDecision.model_validate_json(str(response.content))
# Exit if no-retry is needed
if not should_retry_generation.retry:
break
yield CodeGenerationEvent(
retry_attempt=nth_try,
content=f"Attempt number: {nth_try + 1}\nProposed correction: {should_retry_generation.reason}",
code_blocks=[],
source=agent_name,
)
# Always reflect on the execution result
async for reflection_response in CodeExecutorAgent._reflect_on_code_block_results_flow(
system_messages=system_messages,
model_client=model_client,
model_client_stream=model_client_stream,
model_context=model_context,
agent_name=agent_name,
inner_messages=inner_messages,
):
yield reflection_response # Last reflection_response is of type Response so it will finish the routine
async def extract_code_blocks_from_messages(self, messages: Sequence[BaseChatMessage]) -> List[CodeBlock]:
# Extract code blocks from the messages.
code_blocks: List[CodeBlock] = []
for msg in messages:
if isinstance(msg, TextMessage):
if self._sources is None or msg.source in self._sources:
if self._sources is None or msg.source in self._sources:
if isinstance(msg, TextMessage):
code_blocks.extend(self._extract_markdown_code_blocks(msg.content))
if code_blocks:
# Execute the code blocks.
result = await self._code_executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token)
# TODO: handle other message types if needed
return code_blocks
code_output = result.output
if code_output.strip() == "":
# No output
code_output = f"The script ran but produced no output to console. The POSIX exit code was: {result.exit_code}. If you were expecting output, consider revising the script to ensure content is printed to stdout."
elif result.exit_code != 0:
# Error
code_output = f"The script ran, then exited with an error (POSIX exit code: {result.exit_code})\nIts output was:\n{result.output}"
async def execute_code_block(
self, code_blocks: List[CodeBlock], cancellation_token: CancellationToken
) -> CodeResult:
# Execute the code blocks.
result = await self._code_executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token)
return Response(chat_message=TextMessage(content=code_output, source=self.name))
else:
return Response(
chat_message=TextMessage(
content="No code blocks found in the thread. Please provide at least one markdown-encoded code block to execute (i.e., quoting code in ```python or ```sh code blocks).",
source=self.name,
)
)
if result.output.strip() == "":
# No output
result.output = f"The script ran but produced no output to console. The POSIX exit code was: {result.exit_code}. If you were expecting output, consider revising the script to ensure content is printed to stdout."
elif result.exit_code != 0:
# Error
result.output = f"The script ran, then exited with an error (POSIX exit code: {result.exit_code})\nIts output was:\n{result.output}"
return result
async def on_reset(self, cancellation_token: CancellationToken) -> None:
"""Its a no-op as the code executor agent has no mutable state."""
pass
def _extract_markdown_code_blocks(self, markdown_text: str) -> List[CodeBlock]:
pattern = re.compile(r"```(?:\s*([\w\+\-]+))?\n([\s\S]*?)```")
pattern = re.compile(rf"```(?:\s*({self._supported_languages_regex}))\n([\s\S]*?)```", re.IGNORECASE)
matches = pattern.findall(markdown_text)
code_blocks: List[CodeBlock] = []
for match in matches:
@ -168,16 +613,145 @@ class CodeExecutorAgent(BaseChatAgent, Component[CodeExecutorAgentConfig]):
def _to_config(self) -> CodeExecutorAgentConfig:
return CodeExecutorAgentConfig(
name=self.name,
model_client=(self._model_client.dump_component() if self._model_client is not None else None),
code_executor=self._code_executor.dump_component(),
description=self.description,
sources=list(self._sources) if self._sources is not None else None,
system_message=(
self._system_messages[0].content
if self._system_messages and isinstance(self._system_messages[0].content, str)
else None
),
model_client_stream=self._model_client_stream,
model_context=self._model_context.dump_component(),
supported_languages=self._supported_languages,
)
@classmethod
def _from_config(cls, config: CodeExecutorAgentConfig) -> Self:
return cls(
name=config.name,
model_client=(
ChatCompletionClient.load_component(config.model_client) if config.model_client is not None else None
),
code_executor=CodeExecutor.load_component(config.code_executor),
description=config.description,
sources=config.sources,
system_message=config.system_message,
model_client_stream=config.model_client_stream,
model_context=ChatCompletionContext.load_component(config.model_context) if config.model_context else None,
supported_languages=config.supported_languages,
)
@staticmethod
def _get_compatible_context(model_client: ChatCompletionClient, messages: List[LLMMessage]) -> Sequence[LLMMessage]:
"""Ensure that the messages are compatible with the underlying client, by removing images if needed."""
if model_client.model_info["vision"]:
return messages
else:
return remove_images(messages)
@classmethod
async def _call_llm(
cls,
model_client: ChatCompletionClient,
model_client_stream: bool,
system_messages: List[SystemMessage],
model_context: ChatCompletionContext,
agent_name: str,
cancellation_token: CancellationToken,
) -> AsyncGenerator[Union[CreateResult, ModelClientStreamingChunkEvent], None]:
"""
Perform a model inference and yield either streaming chunk events or the final CreateResult.
"""
all_messages = await model_context.get_messages()
llm_messages = cls._get_compatible_context(model_client=model_client, messages=system_messages + all_messages)
if model_client_stream:
model_result: Optional[CreateResult] = None
async for chunk in model_client.create_stream(
llm_messages, tools=[], cancellation_token=cancellation_token
):
if isinstance(chunk, CreateResult):
model_result = chunk
elif isinstance(chunk, str):
yield ModelClientStreamingChunkEvent(content=chunk, source=agent_name)
else:
raise RuntimeError(f"Invalid chunk type: {type(chunk)}")
if model_result is None:
raise RuntimeError("No final model result in streaming mode.")
yield model_result
else:
model_result = await model_client.create(llm_messages, tools=[], cancellation_token=cancellation_token)
yield model_result
@staticmethod
async def _add_messages_to_context(
model_context: ChatCompletionContext,
messages: Sequence[BaseChatMessage],
) -> None:
"""
Add incoming messages to the model context.
"""
for msg in messages:
if isinstance(msg, HandoffMessage):
for llm_msg in msg.context:
await model_context.add_message(llm_msg)
await model_context.add_message(msg.to_model_message())
@classmethod
async def _reflect_on_code_block_results_flow(
cls,
system_messages: List[SystemMessage],
model_client: ChatCompletionClient,
model_client_stream: bool,
model_context: ChatCompletionContext,
agent_name: str,
inner_messages: List[BaseAgentEvent | BaseChatMessage],
) -> AsyncGenerator[Response | ModelClientStreamingChunkEvent | ThoughtEvent, None]:
"""
If reflect_on_code_block_results=True, we do another inference based on tool results
and yield the final text response (or streaming chunks).
"""
all_messages = system_messages + await model_context.get_messages()
llm_messages = cls._get_compatible_context(model_client=model_client, messages=all_messages)
reflection_result: Optional[CreateResult] = None
if model_client_stream:
async for chunk in model_client.create_stream(llm_messages):
if isinstance(chunk, CreateResult):
reflection_result = chunk
elif isinstance(chunk, str):
yield ModelClientStreamingChunkEvent(content=chunk, source=agent_name)
else:
raise RuntimeError(f"Invalid chunk type: {type(chunk)}")
else:
reflection_result = await model_client.create(llm_messages)
if not reflection_result or not isinstance(reflection_result.content, str):
raise RuntimeError("Reflect on tool use produced no valid text response.")
# --- NEW: If the reflection produced a thought, yield it ---
if reflection_result.thought:
thought_event = ThoughtEvent(content=reflection_result.thought, source=agent_name)
yield thought_event
inner_messages.append(thought_event)
# Add to context (including thought if present)
await model_context.add_message(
AssistantMessage(
content=reflection_result.content,
source=agent_name,
thought=getattr(reflection_result, "thought", None),
)
)
yield Response(
chat_message=TextMessage(
content=reflection_result.content,
source=agent_name,
models_usage=reflection_result.usage,
),
inner_messages=inner_messages,
)

View File

@ -0,0 +1,203 @@
from typing import AsyncGenerator, List, Literal, Optional, Sequence, Union
from autogen_core import CancellationToken, Component, ComponentModel
from pydantic import BaseModel
from autogen_agentchat.agents import BaseChatAgent
from autogen_agentchat.base import Response
from autogen_agentchat.messages import BaseAgentEvent, BaseChatMessage
# ------------------------------
# Message Filter Config
# ------------------------------
class PerSourceFilter(BaseModel):
source: str
position: Optional[Literal["first", "last"]] = None
count: Optional[int] = None
class MessageFilterConfig(BaseModel):
per_source: List[PerSourceFilter]
# ------------------------------
# Component Config
# ------------------------------
class MessageFilterAgentConfig(BaseModel):
name: str
wrapped_agent: ComponentModel
filter: MessageFilterConfig
# ------------------------------
# Message Filter Agent
# ------------------------------
class MessageFilterAgent(BaseChatAgent, Component[MessageFilterAgentConfig]):
"""
A wrapper agent that filters incoming messages before passing them to the inner agent.
.. warning::
This is an experimental feature, and the API will change in the future releases.
This is useful in scenarios like multi-agent workflows where an agent should only
process a subset of the full message historyfor example, only the last message
from each upstream agent, or only the first message from a specific source.
Filtering is configured using :class:`MessageFilterConfig`, which supports:
- Filtering by message source (e.g., only messages from "user" or another agent)
- Selecting the first N or last N messages from each source
- If position is `None`, all messages from that source are included
This agent is compatible with both direct message passing and team-based execution
such as :class:`~autogen_agentchat.teams.GraphFlow`.
Example:
>>> agent_a = MessageFilterAgent(
... name="A",
... wrapped_agent=some_other_agent,
... filter=MessageFilterConfig(
... per_source=[
... PerSourceFilter(source="user", position="first", count=1),
... PerSourceFilter(source="B", position="last", count=2),
... ]
... ),
... )
Example use case with Graph:
Suppose you have a looping multi-agent graph: A B A B C.
You want:
- A to only see the user message and the last message from B
- B to see the user message, last message from A, and its own prior responses (for reflection)
- C to see the user message and the last message from B
Wrap the agents like so:
>>> agent_a = MessageFilterAgent(
... name="A",
... wrapped_agent=agent_a_inner,
... filter=MessageFilterConfig(
... per_source=[
... PerSourceFilter(source="user", position="first", count=1),
... PerSourceFilter(source="B", position="last", count=1),
... ]
... ),
... )
>>> agent_b = MessageFilterAgent(
... name="B",
... wrapped_agent=agent_b_inner,
... filter=MessageFilterConfig(
... per_source=[
... PerSourceFilter(source="user", position="first", count=1),
... PerSourceFilter(source="A", position="last", count=1),
... PerSourceFilter(source="B", position="last", count=10),
... ]
... ),
... )
>>> agent_c = MessageFilterAgent(
... name="C",
... wrapped_agent=agent_c_inner,
... filter=MessageFilterConfig(
... per_source=[
... PerSourceFilter(source="user", position="first", count=1),
... PerSourceFilter(source="B", position="last", count=1),
... ]
... ),
... )
Then define the graph:
>>> graph = DiGraph(
... nodes={
... "A": DiGraphNode(name="A", edges=[DiGraphEdge(target="B")]),
... "B": DiGraphNode(
... name="B",
... edges=[
... DiGraphEdge(target="C", condition="exit"),
... DiGraphEdge(target="A", condition="loop"),
... ],
... ),
... "C": DiGraphNode(name="C", edges=[]),
... },
... default_start_node="A",
... )
This will ensure each agent sees only what is needed for its decision or action logic.
"""
component_config_schema = MessageFilterAgentConfig
component_provider_override = "autogen_agentchat.agents.MessageFilterAgent"
def __init__(
self,
name: str,
wrapped_agent: BaseChatAgent,
filter: MessageFilterConfig,
):
super().__init__(name=name, description=f"{wrapped_agent.description} (with message filtering)")
self._wrapped_agent = wrapped_agent
self._filter = filter
@property
def produced_message_types(self) -> Sequence[type[BaseChatMessage]]:
return self._wrapped_agent.produced_message_types
def _apply_filter(self, messages: Sequence[BaseChatMessage]) -> Sequence[BaseChatMessage]:
result: List[BaseChatMessage] = []
for source_filter in self._filter.per_source:
msgs = [m for m in messages if m.source == source_filter.source]
if source_filter.position == "first" and source_filter.count:
msgs = msgs[: source_filter.count]
elif source_filter.position == "last" and source_filter.count:
msgs = msgs[-source_filter.count :]
result.extend(msgs)
return result
async def on_messages(
self,
messages: Sequence[BaseChatMessage],
cancellation_token: CancellationToken,
) -> Response:
filtered = self._apply_filter(messages)
return await self._wrapped_agent.on_messages(filtered, cancellation_token)
async def on_messages_stream(
self,
messages: Sequence[BaseChatMessage],
cancellation_token: CancellationToken,
) -> AsyncGenerator[Union[BaseAgentEvent, BaseChatMessage, Response], None]:
filtered = self._apply_filter(messages)
async for item in self._wrapped_agent.on_messages_stream(filtered, cancellation_token):
yield item
async def on_reset(self, cancellation_token: CancellationToken) -> None:
await self._wrapped_agent.on_reset(cancellation_token)
def _to_config(self) -> MessageFilterAgentConfig:
return MessageFilterAgentConfig(
name=self.name,
wrapped_agent=self._wrapped_agent.dump_component(),
filter=self._filter,
)
@classmethod
def _from_config(cls, config: MessageFilterAgentConfig) -> "MessageFilterAgent":
wrapped = BaseChatAgent.load_component(config.wrapped_agent)
return cls(
name=config.name,
wrapped_agent=wrapped,
filter=config.filter,
)

View File

@ -5,7 +5,7 @@ from autogen_core.model_context import (
ChatCompletionContext,
UnboundedChatCompletionContext,
)
from autogen_core.models import ChatCompletionClient, LLMMessage, SystemMessage
from autogen_core.models import ChatCompletionClient, LLMMessage, SystemMessage, UserMessage
from pydantic import BaseModel
from typing_extensions import Self
@ -175,7 +175,6 @@ class SocietyOfMindAgent(BaseChatAgent, Component[SocietyOfMindAgentConfig]):
result: TaskResult | None = None
inner_messages: List[BaseAgentEvent | BaseChatMessage] = []
model_context = self._model_context
count = 0
prev_content = await model_context.get_messages()
if len(prev_content) > 0:
@ -192,14 +191,13 @@ class SocietyOfMindAgent(BaseChatAgent, Component[SocietyOfMindAgentConfig]):
else:
task = task_messages
async for inner_msg in self._team.run_stream(task=task, cancellation_token=cancellation_token):
# Use the new output_task_messages parameter to avoid fragile count-based logic
async for inner_msg in self._team.run_stream(
task=task, cancellation_token=cancellation_token, output_task_messages=False
):
if isinstance(inner_msg, TaskResult):
result = inner_msg
else:
count += 1
if count <= len(task_messages):
# Skip the task messages.
continue
yield inner_msg
if isinstance(inner_msg, ModelClientStreamingChunkEvent):
# Skip the model client streaming chunk events.
@ -214,12 +212,26 @@ class SocietyOfMindAgent(BaseChatAgent, Component[SocietyOfMindAgentConfig]):
# Response's inner_messages should be empty. Cause that mean is response to outer world.
)
else:
llm_messages: List[LLMMessage] = []
if self._model_client.model_info.get("multiple_system_messages", False):
# The model client supports multiple system messages, so we
llm_messages.append(SystemMessage(content=self._instruction))
else:
# The model client does not support multiple system messages, so we
llm_messages.append(UserMessage(content=self._instruction, source="user"))
# Generate a response using the model client.
llm_messages: List[LLMMessage] = [SystemMessage(content=self._instruction)]
for message in inner_messages:
if isinstance(message, BaseChatMessage):
llm_messages.append(message.to_model_message())
llm_messages.append(SystemMessage(content=self._response_prompt))
if self._model_client.model_info.get("multiple_system_messages", False):
# The model client supports multiple system messages, so we
llm_messages.append(SystemMessage(content=self._response_prompt))
else:
# The model client does not support multiple system messages, so we
llm_messages.append(UserMessage(content=self._response_prompt, source="user"))
completion = await self._model_client.create(messages=llm_messages, cancellation_token=cancellation_token)
assert isinstance(completion.content, str)
yield Response(
@ -272,6 +284,7 @@ class SocietyOfMindAgent(BaseChatAgent, Component[SocietyOfMindAgentConfig]):
description=self.description,
instruction=self._instruction,
response_prompt=self._response_prompt,
model_context=self._model_context.dump_component(),
)
@classmethod
@ -285,4 +298,5 @@ class SocietyOfMindAgent(BaseChatAgent, Component[SocietyOfMindAgentConfig]):
description=config.description or cls.DEFAULT_DESCRIPTION,
instruction=config.instruction or cls.DEFAULT_INSTRUCTION,
response_prompt=config.response_prompt or cls.DEFAULT_RESPONSE_PROMPT,
model_context=ChatCompletionContext.load_component(config.model_context) if config.model_context else None,
)

View File

@ -1,13 +1,12 @@
from dataclasses import dataclass
from typing import AsyncGenerator, Protocol, Sequence
from autogen_core import CancellationToken
from pydantic import BaseModel
from ..messages import BaseAgentEvent, BaseChatMessage
@dataclass
class TaskResult:
class TaskResult(BaseModel):
"""Result of running a task."""
messages: Sequence[BaseAgentEvent | BaseChatMessage]
@ -25,6 +24,7 @@ class TaskRunner(Protocol):
*,
task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
cancellation_token: CancellationToken | None = None,
output_task_messages: bool = True,
) -> TaskResult:
"""Run the task and return the result.
@ -32,7 +32,13 @@ class TaskRunner(Protocol):
The runner is stateful and a subsequent call to this method will continue
from where the previous call left off. If the task is not specified,
the runner will continue with the current task."""
the runner will continue with the current task.
Args:
task: The task to run. Can be a string, a single message, or a sequence of messages.
cancellation_token: The cancellation token to kill the task immediately.
output_task_messages: Whether to include task messages in :attr:`TaskResult.messages`. Defaults to True for backward compatibility.
"""
...
def run_stream(
@ -40,6 +46,7 @@ class TaskRunner(Protocol):
*,
task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
cancellation_token: CancellationToken | None = None,
output_task_messages: bool = True,
) -> AsyncGenerator[BaseAgentEvent | BaseChatMessage | TaskResult, None]:
"""Run the task and produces a stream of messages and the final result
:class:`TaskResult` as the last item in the stream.
@ -48,5 +55,11 @@ class TaskRunner(Protocol):
The runner is stateful and a subsequent call to this method will continue
from where the previous call left off. If the task is not specified,
the runner will continue with the current task."""
the runner will continue with the current task.
Args:
task: The task to run. Can be a string, a single message, or a sequence of messages.
cancellation_token: The cancellation token to kill the task immediately.
output_task_messages: Whether to include task messages in the output stream. Defaults to True for backward compatibility.
"""
...

View File

@ -5,6 +5,7 @@ multi-agent teams.
from ._terminations import (
ExternalTermination,
FunctionalTermination,
FunctionCallTermination,
HandoffTermination,
MaxMessageTermination,
@ -27,4 +28,5 @@ __all__ = [
"SourceMatchTermination",
"TextMessageTermination",
"FunctionCallTermination",
"FunctionalTermination",
]

View File

@ -1,5 +1,6 @@
import asyncio
import time
from typing import List, Sequence
from typing import Awaitable, Callable, List, Sequence
from autogen_core import Component
from pydantic import BaseModel
@ -154,6 +155,77 @@ class TextMentionTermination(TerminationCondition, Component[TextMentionTerminat
return cls(text=config.text)
class FunctionalTermination(TerminationCondition):
"""Terminate the conversation if an functional expression is met.
Args:
func (Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], bool] | Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], Awaitable[bool]]): A function that takes a sequence of messages
and returns True if the termination condition is met, False otherwise.
The function can be a callable or an async callable.
Example:
.. code-block:: python
import asyncio
from typing import Sequence
from autogen_agentchat.conditions import FunctionalTermination
from autogen_agentchat.messages import BaseAgentEvent, BaseChatMessage, StopMessage
def expression(messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> bool:
# Check if the last message is a stop message
return isinstance(messages[-1], StopMessage)
termination = FunctionalTermination(expression)
async def run() -> None:
messages = [
StopMessage(source="agent1", content="Stop"),
]
result = await termination(messages)
print(result)
asyncio.run(run())
.. code-block:: text
StopMessage(source="FunctionalTermination", content="Functional termination condition met")
"""
def __init__(
self,
func: Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], bool]
| Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], Awaitable[bool]],
) -> None:
self._func = func
self._terminated = False
@property
def terminated(self) -> bool:
return self._terminated
async def __call__(self, messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> StopMessage | None:
if self._terminated:
raise TerminatedException("Termination condition has already been reached")
if asyncio.iscoroutinefunction(self._func):
result = await self._func(messages)
else:
result = self._func(messages)
if result is True:
self._terminated = True
return StopMessage(content="Functional termination condition met", source="FunctionalTermination")
return None
async def reset(self) -> None:
self._terminated = False
class TokenUsageTerminationConfig(BaseModel):
max_total_token: int | None
max_prompt_token: int | None

View File

@ -4,12 +4,21 @@ Each message type inherits either from the BaseChatMessage class or BaseAgentEve
class and includes specific fields relevant to the type of message being sent.
"""
import uuid
from abc import ABC, abstractmethod
from typing import Any, Dict, Generic, List, Literal, Mapping, TypeVar
from datetime import datetime, timezone
from typing import Any, Dict, Generic, List, Literal, Mapping, Optional, Type, TypeVar
from autogen_core import FunctionCall, Image
from autogen_core import Component, ComponentBase, FunctionCall, Image
from autogen_core.code_executor import CodeBlock, CodeResult
from autogen_core.memory import MemoryContent
from autogen_core.models import FunctionExecutionResult, LLMMessage, RequestUsage, UserMessage
from autogen_core.models import (
FunctionExecutionResult,
LLMMessage,
RequestUsage,
UserMessage,
)
from autogen_core.utils import schema_to_pydantic_model
from pydantic import BaseModel, Field, computed_field
from typing_extensions import Annotated, Self
@ -69,6 +78,9 @@ class BaseChatMessage(BaseMessage, ABC):
message using models and return a response as another :class:`BaseChatMessage`.
"""
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
"""Unique identifier for this message."""
source: str
"""The name of the agent that sent this message."""
@ -78,6 +90,9 @@ class BaseChatMessage(BaseMessage, ABC):
metadata: Dict[str, str] = {}
"""Additional metadata about the message."""
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
"""The time when the message was created."""
@abstractmethod
def to_model_text(self) -> str:
"""Convert the content of the message to text-only representation.
@ -96,7 +111,8 @@ class BaseChatMessage(BaseMessage, ABC):
@abstractmethod
def to_model_message(self) -> UserMessage:
"""Convert the message content to a :class:`~autogen_core.models.UserMessage`
for use with model client, e.g., :class:`~autogen_core.models.ChatCompletionClient`."""
for use with model client, e.g., :class:`~autogen_core.models.ChatCompletionClient`.
"""
...
@ -137,6 +153,9 @@ class BaseAgentEvent(BaseMessage, ABC):
a custom rendering of the content.
"""
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
"""Unique identifier for this event."""
source: str
"""The name of the agent that sent this message."""
@ -146,6 +165,9 @@ class BaseAgentEvent(BaseMessage, ABC):
metadata: Dict[str, str] = {}
"""Additional metadata about the message."""
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
"""The time when the message was created."""
StructuredContentType = TypeVar("StructuredContentType", bound=BaseModel, covariant=True)
"""Type variable for structured content types."""
@ -175,21 +197,56 @@ class StructuredMessage(BaseChatMessage, Generic[StructuredContentType]):
print(message.to_text()) # {"text": "Hello", "number": 42}
.. code-block:: python
from pydantic import BaseModel
from autogen_agentchat.messages import StructuredMessage
class MyMessageContent(BaseModel):
text: str
number: int
message = StructuredMessage[MyMessageContent](
content=MyMessageContent(text="Hello", number=42),
source="agent",
format_string="Hello, {text} {number}!",
)
print(message.to_text()) # Hello, agent 42!
"""
content: StructuredContentType
"""The content of the message. Must be a subclass of
`Pydantic BaseModel <https://docs.pydantic.dev/latest/concepts/models/>`_."""
format_string: Optional[str] = None
"""(Experimental) An optional format string to render the content into a human-readable format.
The format string can use the fields of the content model as placeholders.
For example, if the content model has a field `name`, you can use
`{name}` in the format string to include the value of that field.
The format string is used in the :meth:`to_text` method to create a
human-readable representation of the message.
This setting is experimental and will change in the future.
"""
@computed_field
def type(self) -> str:
return self.__class__.__name__
def to_text(self) -> str:
return self.content.model_dump_json(indent=2)
if self.format_string is not None:
return self.format_string.format(**self.content.model_dump())
else:
return self.content.model_dump_json()
def to_model_text(self) -> str:
return self.content.model_dump_json()
if self.format_string is not None:
return self.format_string.format(**self.content.model_dump())
else:
return self.content.model_dump_json()
def to_model_message(self) -> UserMessage:
return UserMessage(
@ -198,6 +255,113 @@ class StructuredMessage(BaseChatMessage, Generic[StructuredContentType]):
)
class StructureMessageConfig(BaseModel):
"""The declarative configuration for the structured output."""
json_schema: Dict[str, Any]
format_string: Optional[str] = None
content_model_name: str
class StructuredMessageFactory(ComponentBase[StructureMessageConfig], Component[StructureMessageConfig]):
""":meta private:
A component that creates structured chat messages from Pydantic models or JSON schemas.
This component helps you generate strongly-typed chat messages with content defined using a Pydantic model.
It can be used in declarative workflows where message structure must be validated, formatted, and serialized.
You can initialize the component directly using a `BaseModel` subclass, or dynamically from a configuration
object (e.g., loaded from disk or a database).
### Example 1: Create from a Pydantic Model
.. code-block:: python
from pydantic import BaseModel
from autogen_agentchat.messages import StructuredMessageFactory
class TestContent(BaseModel):
field1: str
field2: int
format_string = "This is a string {field1} and this is an int {field2}"
sm_component = StructuredMessageFactory(input_model=TestContent, format_string=format_string)
message = sm_component.StructuredMessage(
source="test_agent", content=TestContent(field1="Hello", field2=42), format_string=format_string
)
print(message.to_model_text()) # Output: This is a string Hello and this is an int 42
config = sm_component.dump_component()
s_m_dyn = StructuredMessageFactory.load_component(config)
message = s_m_dyn.StructuredMessage(
source="test_agent",
content=s_m_dyn.ContentModel(field1="dyn agent", field2=43),
format_string=s_m_dyn.format_string,
)
print(type(message)) # StructuredMessage[GeneratedModel]
print(message.to_model_text()) # Output: This is a string dyn agent and this is an int 43
Attributes:
component_config_schema (StructureMessageConfig): Defines the configuration structure for this component.
component_provider_override (str): Path used to reference this component in external tooling.
component_type (str): Identifier used for categorization (e.g., "structured_message").
Raises:
ValueError: If neither `json_schema` nor `input_model` is provided.
Args:
json_schema (Optional[str]): JSON schema to dynamically create a Pydantic model.
input_model (Optional[Type[BaseModel]]): A subclass of `BaseModel` that defines the expected message structure.
format_string (Optional[str]): Optional string to render content into a human-readable format.
content_model_name (Optional[str]): Optional name for the generated Pydantic model.
"""
component_config_schema = StructureMessageConfig
component_provider_override = "autogen_agentchat.messages.StructuredMessageFactory"
component_type = "structured_message"
def __init__(
self,
json_schema: Optional[Dict[str, Any]] = None,
input_model: Optional[Type[BaseModel]] = None,
format_string: Optional[str] = None,
content_model_name: Optional[str] = None,
) -> None:
self.format_string = format_string
if json_schema:
self.ContentModel = schema_to_pydantic_model(
json_schema, model_name=content_model_name or "GeneratedContentModel"
)
elif input_model:
self.ContentModel = input_model
else:
raise ValueError("Either `json_schema` or `input_model` must be provided.")
self.StructuredMessage = StructuredMessage[self.ContentModel] # type: ignore[name-defined]
def _to_config(self) -> StructureMessageConfig:
return StructureMessageConfig(
json_schema=self.ContentModel.model_json_schema(),
format_string=self.format_string,
content_model_name=self.ContentModel.__name__,
)
@classmethod
def _from_config(cls, config: StructureMessageConfig) -> "StructuredMessageFactory":
return cls(
json_schema=config.json_schema,
format_string=config.format_string,
content_model_name=config.content_model_name,
)
class TextMessage(BaseTextChatMessage):
"""A text message with string-only content."""
@ -269,6 +433,12 @@ class ToolCallSummaryMessage(BaseTextChatMessage):
type: Literal["ToolCallSummaryMessage"] = "ToolCallSummaryMessage"
tool_calls: List[FunctionCall]
"""The tool calls that were made."""
results: List[FunctionExecutionResult]
"""The results of the tool calls."""
class ToolCallRequestEvent(BaseAgentEvent):
"""An event signaling a request to use tools."""
@ -282,6 +452,39 @@ class ToolCallRequestEvent(BaseAgentEvent):
return str(self.content)
class CodeGenerationEvent(BaseAgentEvent):
"""An event signaling code generation event."""
retry_attempt: int
"Retry number, 0 means first generation"
content: str
"The complete content as string."
code_blocks: List[CodeBlock]
"List of code blocks present in content"
type: Literal["CodeGenerationEvent"] = "CodeGenerationEvent"
def to_text(self) -> str:
return self.content
class CodeExecutionEvent(BaseAgentEvent):
"""An event signaling code execution event."""
retry_attempt: int
"Retry number, 0 means first execution"
result: CodeResult
"Code Execution Result"
type: Literal["CodeExecutionEvent"] = "CodeExecutionEvent"
def to_text(self) -> str:
return self.result.output
class ToolCallExecutionEvent(BaseAgentEvent):
"""An event signaling the execution of tool calls."""
@ -327,6 +530,10 @@ class ModelClientStreamingChunkEvent(BaseAgentEvent):
content: str
"""A string chunk from the model client."""
full_message_id: str | None = None
"""Optional reference to the complete message that may come after the chunks.
This allows consumers of the stream to correlate chunks with the eventual completed message."""
type: Literal["ModelClientStreamingChunkEvent"] = "ModelClientStreamingChunkEvent"
def to_text(self) -> str:
@ -347,6 +554,30 @@ class ThoughtEvent(BaseAgentEvent):
return self.content
class SelectSpeakerEvent(BaseAgentEvent):
"""An event signaling the selection of speakers for a conversation."""
content: List[str]
"""The names of the selected speakers."""
type: Literal["SelectSpeakerEvent"] = "SelectSpeakerEvent"
def to_text(self) -> str:
return str(self.content)
class SelectorEvent(BaseAgentEvent):
"""An event emitted from the `SelectorGroupChat`."""
content: str
"""The content of the event."""
type: Literal["SelectorEvent"] = "SelectorEvent"
def to_text(self) -> str:
return str(self.content)
class MessageFactory:
""":meta private:
@ -369,6 +600,9 @@ class MessageFactory:
self._message_types[UserInputRequestedEvent.__name__] = UserInputRequestedEvent
self._message_types[ModelClientStreamingChunkEvent.__name__] = ModelClientStreamingChunkEvent
self._message_types[ThoughtEvent.__name__] = ThoughtEvent
self._message_types[SelectSpeakerEvent.__name__] = SelectSpeakerEvent
self._message_types[CodeGenerationEvent.__name__] = CodeGenerationEvent
self._message_types[CodeExecutionEvent.__name__] = CodeExecutionEvent
def is_registered(self, message_type: type[BaseAgentEvent | BaseChatMessage]) -> bool:
"""Check if a message type is registered with the factory."""
@ -409,7 +643,8 @@ class MessageFactory:
ChatMessage = Annotated[
TextMessage | MultiModalMessage | StopMessage | ToolCallSummaryMessage | HandoffMessage, Field(discriminator="type")
TextMessage | MultiModalMessage | StopMessage | ToolCallSummaryMessage | HandoffMessage,
Field(discriminator="type"),
]
"""The union type of all built-in concrete subclasses of :class:`BaseChatMessage`.
It does not include :class:`StructuredMessage` types."""
@ -420,7 +655,10 @@ AgentEvent = Annotated[
| MemoryQueryEvent
| UserInputRequestedEvent
| ModelClientStreamingChunkEvent
| ThoughtEvent,
| ThoughtEvent
| SelectSpeakerEvent
| CodeGenerationEvent
| CodeExecutionEvent,
Field(discriminator="type"),
]
"""The union type of all built-in concrete subclasses of :class:`BaseAgentEvent`."""
@ -434,6 +672,7 @@ __all__ = [
"BaseTextChatMessage",
"StructuredContentType",
"StructuredMessage",
"StructuredMessageFactory",
"HandoffMessage",
"MultiModalMessage",
"StopMessage",
@ -445,5 +684,8 @@ __all__ = [
"UserInputRequestedEvent",
"ModelClientStreamingChunkEvent",
"ThoughtEvent",
"SelectSpeakerEvent",
"MessageFactory",
"CodeGenerationEvent",
"CodeExecutionEvent",
]

View File

@ -4,6 +4,13 @@ Each team inherits from the BaseGroupChat class.
"""
from ._group_chat._base_group_chat import BaseGroupChat
from ._group_chat._graph import (
DiGraph,
DiGraphBuilder,
DiGraphEdge,
DiGraphNode,
GraphFlow,
)
from ._group_chat._magentic_one import MagenticOneGroupChat
from ._group_chat._round_robin_group_chat import RoundRobinGroupChat
from ._group_chat._selector_group_chat import SelectorGroupChat
@ -15,4 +22,9 @@ __all__ = [
"SelectorGroupChat",
"Swarm",
"MagenticOneGroupChat",
"DiGraphBuilder",
"DiGraph",
"DiGraphNode",
"DiGraphEdge",
"GraphFlow",
]

View File

@ -21,6 +21,7 @@ from ...messages import (
MessageFactory,
ModelClientStreamingChunkEvent,
StopMessage,
StructuredMessage,
TextMessage,
)
from ...state import TeamState
@ -54,6 +55,7 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
max_turns: int | None = None,
runtime: AgentRuntime | None = None,
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
emit_team_events: bool = False,
):
if len(participants) == 0:
raise ValueError("At least one participant is required.")
@ -68,6 +70,16 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
for message_type in custom_message_types:
self._message_factory.register(message_type)
for agent in participants:
for message_type in agent.produced_message_types:
try:
is_registered = self._message_factory.is_registered(message_type) # type: ignore[reportUnknownArgumentType]
if issubclass(message_type, StructuredMessage) and not is_registered:
self._message_factory.register(message_type) # type: ignore[reportUnknownArgumentType]
except TypeError:
# Not a class or not a valid subclassable type (skip)
pass
# The team ID is a UUID that is used to identify the team and its participants
# in the agent runtime. It is used to create unique topic types for each participant.
# Currently, team ID is binded to an object instance of the group chat class.
@ -113,6 +125,9 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
# Flag to track if the group chat is running.
self._is_running = False
# Flag to track if the team events should be emitted.
self._emit_team_events = emit_team_events
@abstractmethod
def _create_group_chat_manager_factory(
self,
@ -202,6 +217,7 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
*,
task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
cancellation_token: CancellationToken | None = None,
output_task_messages: bool = True,
) -> TaskResult:
"""Run the team and return the result. The base implementation uses
:meth:`run_stream` to run the team and then returns the final result.
@ -292,6 +308,7 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
async for message in self.run_stream(
task=task,
cancellation_token=cancellation_token,
output_task_messages=output_task_messages,
):
if isinstance(message, TaskResult):
result = message
@ -304,6 +321,7 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
*,
task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
cancellation_token: CancellationToken | None = None,
output_task_messages: bool = True,
) -> AsyncGenerator[BaseAgentEvent | BaseChatMessage | TaskResult, None]:
"""Run the team and produces a stream of messages and the final result
of the type :class:`~autogen_agentchat.base.TaskResult` as the last item in the stream. Once the
@ -321,6 +339,7 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
Setting the cancellation token potentially put the team in an inconsistent state,
and it may not reset the termination condition.
To gracefully stop the team, use :class:`~autogen_agentchat.conditions.ExternalTermination` instead.
output_task_messages (bool): Whether to include task messages in the output stream. Defaults to True for backward compatibility.
Returns:
stream: an :class:`~collections.abc.AsyncGenerator` that yields :class:`~autogen_agentchat.messages.BaseAgentEvent`, :class:`~autogen_agentchat.messages.BaseChatMessage`, and the final result :class:`~autogen_agentchat.base.TaskResult` as the last item in the stream.
@ -401,7 +420,6 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
asyncio.run(main())
"""
# Create the messages list if the task is a string or a chat message.
messages: List[BaseChatMessage] | None = None
if task is None:
@ -482,14 +500,15 @@ class BaseGroupChat(Team, ABC, ComponentBase[BaseModel]):
# The group chat manager will start the group chat by relaying the message to the participants
# and the group chat manager.
await self._runtime.send_message(
GroupChatStart(messages=messages),
GroupChatStart(messages=messages, output_task_messages=output_task_messages),
recipient=AgentId(type=self._group_chat_manager_topic_type, key=self._team_id),
cancellation_token=cancellation_token,
)
# Collect the output messages in order.
output_messages: List[BaseAgentEvent | BaseChatMessage] = []
stop_reason: str | None = None
# Yield the messsages until the queue is empty.
# Yield the messages until the queue is empty.
while True:
message_future = asyncio.ensure_future(self._output_message_queue.get())
if cancellation_token is not None:

View File

@ -1,11 +1,11 @@
import asyncio
from abc import ABC, abstractmethod
from typing import Any, List
from typing import Any, List, Sequence
from autogen_core import DefaultTopicId, MessageContext, event, rpc
from autogen_core import CancellationToken, DefaultTopicId, MessageContext, event, rpc
from ...base import TerminationCondition
from ...messages import BaseAgentEvent, BaseChatMessage, MessageFactory, StopMessage
from ...messages import BaseAgentEvent, BaseChatMessage, MessageFactory, SelectSpeakerEvent, StopMessage
from ._events import (
GroupChatAgentResponse,
GroupChatError,
@ -45,6 +45,7 @@ class BaseGroupChatManager(SequentialRoutedAgent, ABC):
termination_condition: TerminationCondition | None,
max_turns: int | None,
message_factory: MessageFactory,
emit_team_events: bool = False,
):
super().__init__(
description="Group chat manager",
@ -77,6 +78,8 @@ class BaseGroupChatManager(SequentialRoutedAgent, ABC):
self._max_turns = max_turns
self._current_turn = 0
self._message_factory = message_factory
self._emit_team_events = emit_team_events
self._active_speakers: List[str] = []
@rpc
async def handle_start(self, message: GroupChatStart, ctx: MessageContext) -> None:
@ -102,8 +105,11 @@ class BaseGroupChatManager(SequentialRoutedAgent, ABC):
GroupChatStart(messages=message.messages),
topic_id=DefaultTopicId(type=self._output_topic_type),
)
for msg in message.messages:
await self._output_message_queue.put(msg)
# Only put messages in output queue if output_task_messages is True
if message.output_task_messages:
for msg in message.messages:
await self._output_message_queue.put(msg)
# Relay all messages at once to participants
await self.publish_message(
@ -113,88 +119,42 @@ class BaseGroupChatManager(SequentialRoutedAgent, ABC):
)
# Append all messages to thread
self._message_thread.extend(message.messages)
await self.update_message_thread(message.messages)
# Check termination condition after processing all messages
if self._termination_condition is not None:
stop_message = await self._termination_condition(message.messages)
if stop_message is not None:
# Reset the termination condition.
await self._termination_condition.reset()
# Signal termination to the caller of the team.
await self._signal_termination(stop_message)
# Stop the group chat.
return
if await self._apply_termination_condition(message.messages):
# Stop the group chat.
return
# Select a speaker to start/continue the conversation
speaker_name_future = asyncio.ensure_future(self.select_speaker(self._message_thread))
# Link the select speaker future to the cancellation token.
ctx.cancellation_token.link_future(speaker_name_future)
speaker_name = await speaker_name_future
if speaker_name not in self._participant_name_to_topic_type:
raise RuntimeError(f"Speaker {speaker_name} not found in participant names.")
speaker_topic_type = self._participant_name_to_topic_type[speaker_name]
await self.publish_message(
GroupChatRequestPublish(),
topic_id=DefaultTopicId(type=speaker_topic_type),
cancellation_token=ctx.cancellation_token,
)
# Select speakers to start/continue the conversation
await self._transition_to_next_speakers(ctx.cancellation_token)
@event
async def handle_agent_response(self, message: GroupChatAgentResponse, ctx: MessageContext) -> None:
try:
# Append the message to the message thread and construct the delta.
# Construct the detla from the agent response.
delta: List[BaseAgentEvent | BaseChatMessage] = []
if message.agent_response.inner_messages is not None:
for inner_message in message.agent_response.inner_messages:
self._message_thread.append(inner_message)
delta.append(inner_message)
self._message_thread.append(message.agent_response.chat_message)
delta.append(message.agent_response.chat_message)
# Append the messages to the message thread.
await self.update_message_thread(delta)
# Remove the agent from the active speakers list.
self._active_speakers.remove(message.agent_name)
if len(self._active_speakers) > 0:
# If there are still active speakers, return without doing anything.
return
# Check if the conversation should be terminated.
if self._termination_condition is not None:
stop_message = await self._termination_condition(delta)
if stop_message is not None:
# Reset the termination conditions and turn count.
await self._termination_condition.reset()
self._current_turn = 0
# Signal termination to the caller of the team.
await self._signal_termination(stop_message)
# Stop the group chat.
return
if await self._apply_termination_condition(delta, increment_turn_count=True):
# Stop the group chat.
return
# Increment the turn count.
self._current_turn += 1
# Check if the maximum number of turns has been reached.
if self._max_turns is not None:
if self._current_turn >= self._max_turns:
stop_message = StopMessage(
content=f"Maximum number of turns {self._max_turns} reached.",
source=self._name,
)
# Reset the termination conditions and turn count.
if self._termination_condition is not None:
await self._termination_condition.reset()
self._current_turn = 0
# Signal termination to the caller of the team.
await self._signal_termination(stop_message)
# Stop the group chat.
return
# Select a speaker to continue the conversation.
speaker_name_future = asyncio.ensure_future(self.select_speaker(self._message_thread))
# Link the select speaker future to the cancellation token.
ctx.cancellation_token.link_future(speaker_name_future)
speaker_name = await speaker_name_future
if speaker_name not in self._participant_name_to_topic_type:
raise RuntimeError(f"Speaker {speaker_name} not found in participant names.")
speaker_topic_type = self._participant_name_to_topic_type[speaker_name]
await self.publish_message(
GroupChatRequestPublish(),
topic_id=DefaultTopicId(type=speaker_topic_type),
cancellation_token=ctx.cancellation_token,
)
# Select speakers to continue the conversation.
await self._transition_to_next_speakers(ctx.cancellation_token)
except Exception as e:
# Handle the exception and signal termination with an error.
error = SerializableException.from_exception(e)
@ -202,6 +162,74 @@ class BaseGroupChatManager(SequentialRoutedAgent, ABC):
# Raise the exception to the runtime.
raise
async def _transition_to_next_speakers(self, cancellation_token: CancellationToken) -> None:
speaker_names_future = asyncio.ensure_future(self.select_speaker(self._message_thread))
# Link the select speaker future to the cancellation token.
cancellation_token.link_future(speaker_names_future)
speaker_names = await speaker_names_future
if isinstance(speaker_names, str):
# If only one speaker is selected, convert it to a list.
speaker_names = [speaker_names]
for speaker_name in speaker_names:
if speaker_name not in self._participant_name_to_topic_type:
raise RuntimeError(f"Speaker {speaker_name} not found in participant names.")
await self._log_speaker_selection(speaker_names)
# Send request to publish message to the next speakers
for speaker_name in speaker_names:
speaker_topic_type = self._participant_name_to_topic_type[speaker_name]
await self.publish_message(
GroupChatRequestPublish(),
topic_id=DefaultTopicId(type=speaker_topic_type),
cancellation_token=cancellation_token,
)
self._active_speakers.append(speaker_name)
async def _apply_termination_condition(
self, delta: Sequence[BaseAgentEvent | BaseChatMessage], increment_turn_count: bool = False
) -> bool:
"""Apply the termination condition to the delta and return True if the conversation should be terminated.
It also resets the termination condition and turn count, and signals termination to the caller of the team."""
if self._termination_condition is not None:
stop_message = await self._termination_condition(delta)
if stop_message is not None:
# Reset the termination conditions and turn count.
await self._termination_condition.reset()
self._current_turn = 0
# Signal termination to the caller of the team.
await self._signal_termination(stop_message)
# Stop the group chat.
return True
if increment_turn_count:
# Increment the turn count.
self._current_turn += 1
# Check if the maximum number of turns has been reached.
if self._max_turns is not None:
if self._current_turn >= self._max_turns:
stop_message = StopMessage(
content=f"Maximum number of turns {self._max_turns} reached.",
source=self._name,
)
# Reset the termination conditions and turn count.
if self._termination_condition is not None:
await self._termination_condition.reset()
self._current_turn = 0
# Signal termination to the caller of the team.
await self._signal_termination(stop_message)
# Stop the group chat.
return True
return False
async def _log_speaker_selection(self, speaker_names: List[str]) -> None:
"""Log the selected speaker to the output message queue."""
select_msg = SelectSpeakerEvent(content=speaker_names, source=self._name)
if self._emit_team_events:
await self.publish_message(
GroupChatMessage(message=select_msg),
topic_id=DefaultTopicId(type=self._output_topic_type),
)
await self._output_message_queue.put(select_msg)
async def _signal_termination(self, message: StopMessage) -> None:
termination_event = GroupChatTermination(message=message)
# Log the early stop message.
@ -260,10 +288,26 @@ class BaseGroupChatManager(SequentialRoutedAgent, ABC):
"""
...
async def update_message_thread(self, messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> None:
"""Update the message thread with the new messages.
This is called when the group chat receives a GroupChatStart or GroupChatAgentResponse event,
before calling the select_speakers method.
"""
self._message_thread.extend(messages)
@abstractmethod
async def select_speaker(self, thread: List[BaseAgentEvent | BaseChatMessage]) -> str:
"""Select a speaker from the participants and return the
topic type of the selected speaker."""
async def select_speaker(self, thread: Sequence[BaseAgentEvent | BaseChatMessage]) -> List[str] | str:
"""Select speakers from the participants and return the topic types of the selected speaker.
This is called when the group chat manager have received all responses from the participants
for a turn and is ready to select the next speakers for the next turn.
Args:
thread: The message thread of the group chat.
Returns:
A list of topic types of the selected speakers.
If only one speaker is selected, a single string is returned instead of a list.
"""
...
@abstractmethod

View File

@ -1,6 +1,6 @@
from typing import Any, List, Mapping
from autogen_core import DefaultTopicId, MessageContext, event, rpc
from autogen_core import DefaultTopicId, MessageContext, event, rpc, trace_invoke_agent_span
from autogen_agentchat.messages import BaseAgentEvent, BaseChatMessage, MessageFactory
@ -73,36 +73,41 @@ class ChatAgentContainer(SequentialRoutedAgent):
async def handle_request(self, message: GroupChatRequestPublish, ctx: MessageContext) -> None:
"""Handle a content request event by passing the messages in the buffer
to the delegate agent and publish the response."""
try:
# Pass the messages in the buffer to the delegate agent.
response: Response | None = None
async for msg in self._agent.on_messages_stream(self._message_buffer, ctx.cancellation_token):
if isinstance(msg, Response):
await self._log_message(msg.chat_message)
response = msg
else:
await self._log_message(msg)
if response is None:
raise ValueError(
"The agent did not produce a final response. Check the agent's on_messages_stream method."
with trace_invoke_agent_span(
agent_name=self._agent.name,
agent_description=self._agent.description,
agent_id=str(self.id),
):
try:
# Pass the messages in the buffer to the delegate agent.
response: Response | None = None
async for msg in self._agent.on_messages_stream(self._message_buffer, ctx.cancellation_token):
if isinstance(msg, Response):
await self._log_message(msg.chat_message)
response = msg
else:
await self._log_message(msg)
if response is None:
raise ValueError(
"The agent did not produce a final response. Check the agent's on_messages_stream method."
)
# Publish the response to the group chat.
self._message_buffer.clear()
await self.publish_message(
GroupChatAgentResponse(agent_response=response, agent_name=self._agent.name),
topic_id=DefaultTopicId(type=self._parent_topic_type),
cancellation_token=ctx.cancellation_token,
)
# Publish the response to the group chat.
self._message_buffer.clear()
await self.publish_message(
GroupChatAgentResponse(agent_response=response),
topic_id=DefaultTopicId(type=self._parent_topic_type),
cancellation_token=ctx.cancellation_token,
)
except Exception as e:
# Publish the error to the group chat.
error_message = SerializableException.from_exception(e)
await self.publish_message(
GroupChatError(error=error_message),
topic_id=DefaultTopicId(type=self._parent_topic_type),
cancellation_token=ctx.cancellation_token,
)
# Raise the error to the runtime.
raise
except Exception as e:
# Publish the error to the group chat.
error_message = SerializableException.from_exception(e)
await self.publish_message(
GroupChatError(error=error_message),
topic_id=DefaultTopicId(type=self._parent_topic_type),
cancellation_token=ctx.cancellation_token,
)
# Raise the error to the runtime.
raise
def _buffer_message(self, message: BaseChatMessage) -> None:
if not self._message_factory.is_registered(message.__class__):

View File

@ -41,6 +41,9 @@ class GroupChatStart(BaseModel):
messages: List[BaseChatMessage] | None = None
"""An optional list of messages to start the group chat."""
output_task_messages: bool = True
"""Whether to include task messages in the output. Defaults to True for backward compatibility."""
class GroupChatAgentResponse(BaseModel):
"""A response published to a group chat."""
@ -48,6 +51,9 @@ class GroupChatAgentResponse(BaseModel):
agent_response: Response
"""The response from an agent."""
agent_name: str
"""The name of the agent that produced the response."""
class GroupChatRequestPublish(BaseModel):
"""A request to publish a message to a group chat."""

View File

@ -0,0 +1,17 @@
from ._digraph_group_chat import (
DiGraph,
DiGraphEdge,
DiGraphNode,
GraphFlow,
GraphFlowManager,
)
from ._graph_builder import DiGraphBuilder
__all__ = [
"GraphFlow",
"DiGraph",
"GraphFlowManager",
"DiGraphNode",
"DiGraphEdge",
"DiGraphBuilder",
]

View File

@ -0,0 +1,850 @@
import asyncio
from collections import Counter, deque
from typing import Any, Callable, Deque, Dict, List, Literal, Mapping, Sequence, Set, Union
from autogen_core import AgentRuntime, CancellationToken, Component, ComponentModel
from pydantic import BaseModel, Field, model_validator
from typing_extensions import Self
from autogen_agentchat.agents import BaseChatAgent
from autogen_agentchat.base import ChatAgent, OrTerminationCondition, Response, TerminationCondition
from autogen_agentchat.conditions import StopMessageTermination
from autogen_agentchat.messages import (
BaseAgentEvent,
BaseChatMessage,
ChatMessage,
MessageFactory,
StopMessage,
TextMessage,
)
from autogen_agentchat.state import BaseGroupChatManagerState
from autogen_agentchat.teams import BaseGroupChat
from ..._group_chat._base_group_chat_manager import BaseGroupChatManager
from ..._group_chat._events import GroupChatTermination
_DIGRAPH_STOP_AGENT_NAME = "DiGraphStopAgent"
_DIGRAPH_STOP_AGENT_MESSAGE = "Digraph execution is complete"
class DiGraphEdge(BaseModel):
"""Represents a directed edge in a :class:`DiGraph`, with an optional execution condition.
.. warning::
This is an experimental feature, and the API will change in the future releases.
.. warning::
If the condition is a callable, it will not be serialized in the model.
"""
target: str # Target node name
condition: Union[str, Callable[[BaseChatMessage], bool], None] = Field(default=None)
"""(Experimental) Condition to execute this edge.
If None, the edge is unconditional.
If a string, the edge is conditional on the presence of that string in the last agent chat message.
If a callable, the edge is conditional on the callable returning True when given the last message.
"""
# Using Field to exclude the condition in serialization if it's a callable
condition_function: Callable[[BaseChatMessage], bool] | None = Field(default=None, exclude=True)
activation_group: str = Field(default="")
"""Group identifier for forward dependencies.
When multiple edges point to the same target node, they are grouped by this field.
This allows distinguishing between different cycles or dependency patterns.
Example: In a graph containing a cycle like A->B->C->B, the two edges pointing to B (A->B and C->B)
can be in different activation groups to control how B is activated.
Defaults to the target node name if not specified.
"""
activation_condition: Literal["all", "any"] = "all"
"""Determines how forward dependencies within the same activation_group are evaluated.
- "all": All edges in this activation group must be satisfied before the target node can execute
- "any": Any single edge in this activation group being satisfied allows the target node to execute
This is used to handle complex dependency patterns in cyclic graphs where multiple
paths can lead to the same target node.
"""
@model_validator(mode="after")
def _validate_condition(self) -> "DiGraphEdge":
# Store callable in a separate field and set condition to None for serialization
if callable(self.condition):
self.condition_function = self.condition
# For serialization purposes, we'll set the condition to None
# when storing as a pydantic model/dict
object.__setattr__(self, "condition", None)
# Set activation_group to target if not already set
if not self.activation_group:
self.activation_group = self.target
return self
def check_condition(self, message: BaseChatMessage) -> bool:
"""Check if the edge condition is satisfied for the given message.
Args:
message: The message to check the condition against.
Returns:
True if condition is satisfied (None condition always returns True),
False otherwise.
"""
if self.condition_function is not None:
return self.condition_function(message)
elif isinstance(self.condition, str):
# If it's a string, check if the string is in the message content
return self.condition in message.to_model_text()
return True # None condition is always satisfied
class DiGraphNode(BaseModel):
"""Represents a node (agent) in a :class:`DiGraph`, with its outgoing edges and activation type.
.. warning::
This is an experimental feature, and the API will change in the future releases.
"""
name: str # Agent's name
edges: List[DiGraphEdge] = [] # Outgoing edges
activation: Literal["all", "any"] = "all"
class DiGraph(BaseModel):
"""Defines a directed graph structure with nodes and edges.
:class:`GraphFlow` uses this to determine execution order and conditions.
.. warning::
This is an experimental feature, and the API will change in the future releases.
"""
nodes: Dict[str, DiGraphNode] # Node name → DiGraphNode mapping
default_start_node: str | None = None # Default start node name
_has_cycles: bool | None = None # Cyclic graph flag
def get_parents(self) -> Dict[str, List[str]]:
"""Compute a mapping of each node to its parent nodes."""
parents: Dict[str, List[str]] = {node: [] for node in self.nodes}
for node in self.nodes.values():
for edge in node.edges:
parents[edge.target].append(node.name)
return parents
def get_start_nodes(self) -> Set[str]:
"""Return the nodes that have no incoming edges (entry points)."""
if self.default_start_node:
return {self.default_start_node}
parents = self.get_parents()
return set([node_name for node_name, parent_list in parents.items() if not parent_list])
def get_leaf_nodes(self) -> Set[str]:
"""Return nodes that have no outgoing edges (final output nodes)."""
return set([name for name, node in self.nodes.items() if not node.edges])
def has_cycles_with_exit(self) -> bool:
"""
Check if the graph has any cycles and validate that each cycle has at least one conditional edge.
Returns:
bool: True if there is at least one cycle and all cycles have an exit condition.
False if there are no cycles.
Raises:
ValueError: If there is a cycle without any conditional edge.
"""
visited: Set[str] = set()
rec_stack: Set[str] = set()
path: List[str] = []
def dfs(node_name: str) -> bool:
visited.add(node_name)
rec_stack.add(node_name)
path.append(node_name)
for edge in self.nodes[node_name].edges:
target = edge.target
if target not in visited:
if dfs(target):
return True
elif target in rec_stack:
# Found a cycle → extract the cycle
cycle_start_index = path.index(target)
cycle_nodes = path[cycle_start_index:]
cycle_edges: List[DiGraphEdge] = []
for n in cycle_nodes:
cycle_edges.extend(self.nodes[n].edges)
if all(edge.condition is None and edge.condition_function is None for edge in cycle_edges):
raise ValueError(
f"Cycle detected without exit condition: {' -> '.join(cycle_nodes + cycle_nodes[:1])}"
)
return True # Found cycle, but it has an exit condition
rec_stack.remove(node_name)
path.pop()
return False
has_cycle = False
for node in self.nodes:
if node not in visited:
if dfs(node):
has_cycle = True
return has_cycle
def get_has_cycles(self) -> bool:
"""Indicates if the graph has at least one cycle (with valid exit conditions)."""
if self._has_cycles is None:
self._has_cycles = self.has_cycles_with_exit()
return self._has_cycles
def graph_validate(self) -> None:
"""Validate graph structure and execution rules."""
if not self.nodes:
raise ValueError("Graph has no nodes.")
if not self.get_start_nodes():
raise ValueError("Graph must have at least one start node")
if not self.get_leaf_nodes():
raise ValueError("Graph must have at least one leaf node")
# Outgoing edge condition validation (per node)
for node in self.nodes.values():
# Check that if a node has an outgoing conditional edge, then all outgoing edges are conditional
has_condition = any(
edge.condition is not None or edge.condition_function is not None for edge in node.edges
)
has_unconditioned = any(edge.condition is None and edge.condition_function is None for edge in node.edges)
if has_condition and has_unconditioned:
raise ValueError(f"Node '{node.name}' has a mix of conditional and unconditional edges.")
# Validate activation conditions across all edges in the graph
self._validate_activation_conditions()
self._has_cycles = self.has_cycles_with_exit()
def _validate_activation_conditions(self) -> None:
"""Validate that all edges pointing to the same target node have consistent activation_condition values.
Raises:
ValueError: If edges pointing to the same target have different activation_condition values
"""
target_activation_conditions: Dict[str, Dict[str, str]] = {} # target_node -> {activation_group -> condition}
for node in self.nodes.values():
for edge in node.edges:
target = edge.target # The target node this edge points to
activation_group = edge.activation_group
if target not in target_activation_conditions:
target_activation_conditions[target] = {}
if activation_group in target_activation_conditions[target]:
if target_activation_conditions[target][activation_group] != edge.activation_condition:
# Find the source node that has the conflicting condition
conflicting_source = self._find_edge_source_by_target_and_group(
target, activation_group, target_activation_conditions[target][activation_group]
)
raise ValueError(
f"Conflicting activation conditions for target '{target}' group '{activation_group}': "
f"'{target_activation_conditions[target][activation_group]}' (from node '{conflicting_source}') "
f"and '{edge.activation_condition}' (from node '{node.name}')"
)
else:
target_activation_conditions[target][activation_group] = edge.activation_condition
def _find_edge_source_by_target_and_group(
self, target: str, activation_group: str, activation_condition: str
) -> str:
"""Find the source node that has an edge pointing to the given target with the given activation_group and activation_condition."""
for node_name, node in self.nodes.items():
for edge in node.edges:
if (
edge.target == target
and edge.activation_group == activation_group
and edge.activation_condition == activation_condition
):
return node_name
return "unknown"
def get_remaining_map(self) -> Dict[str, Dict[str, int]]:
"""Get the remaining map that tracks how many edges point to each target node with each activation group.
Returns:
Dictionary mapping target nodes to their activation groups and remaining counts
"""
remaining_map: Dict[str, Dict[str, int]] = {}
for node in self.nodes.values():
for edge in node.edges:
target = edge.target
activation_group = edge.activation_group
if target not in remaining_map:
remaining_map[target] = {}
if activation_group not in remaining_map[target]:
remaining_map[target][activation_group] = 0
remaining_map[target][activation_group] += 1
return remaining_map
class GraphFlowManagerState(BaseGroupChatManagerState):
"""Tracks active execution state for DAG-based execution."""
active_nodes: List[str] = [] # Currently executing nodes
type: str = "GraphManagerState"
class GraphFlowManager(BaseGroupChatManager):
"""Manages execution of agents using a Directed Graph execution model."""
def __init__(
self,
name: str,
group_topic_type: str,
output_topic_type: str,
participant_topic_types: List[str],
participant_names: List[str],
participant_descriptions: List[str],
output_message_queue: asyncio.Queue[BaseAgentEvent | BaseChatMessage | GroupChatTermination],
termination_condition: TerminationCondition | None,
max_turns: int | None,
message_factory: MessageFactory,
graph: DiGraph,
) -> None:
"""Initialize the graph-based execution manager."""
super().__init__(
name=name,
group_topic_type=group_topic_type,
output_topic_type=output_topic_type,
participant_topic_types=participant_topic_types,
participant_names=participant_names,
participant_descriptions=participant_descriptions,
output_message_queue=output_message_queue,
termination_condition=termination_condition,
max_turns=max_turns,
message_factory=message_factory,
)
graph.graph_validate()
if graph.get_has_cycles() and self._termination_condition is None and self._max_turns is None:
raise ValueError("A termination condition is required for cyclic graphs without a maximum turn limit.")
self._graph = graph
# Lookup table for incoming edges for each node.
self._parents = graph.get_parents()
# Lookup table for outgoing edges for each node.
self._edges: Dict[str, List[DiGraphEdge]] = {n: node.edges for n, node in graph.nodes.items()}
# Build activation and enqueued_any lookup tables by collecting all edges and grouping by target node
self._build_lookup_tables(graph)
# Track which activation groups were triggered for each node
self._triggered_activation_groups: Dict[str, Set[str]] = {}
# === Mutable states for the graph execution ===
# Count the number of remaining parents to activate each node.
self._remaining: Dict[str, Counter[str]] = {
target: Counter(groups) for target, groups in graph.get_remaining_map().items()
}
# cache for remaining
self._origin_remaining: Dict[str, Dict[str, int]] = {
target: Counter(groups) for target, groups in self._remaining.items()
}
# Ready queue for nodes that are ready to execute, starting with the start nodes.
self._ready: Deque[str] = deque([n for n in graph.get_start_nodes()])
def _build_lookup_tables(self, graph: DiGraph) -> None:
"""Build activation and enqueued_any lookup tables by collecting all edges and grouping by target node.
Args:
graph: The directed graph
"""
self._activation: Dict[str, Dict[str, Literal["any", "all"]]] = {}
self._enqueued_any: Dict[str, Dict[str, bool]] = {}
for node in graph.nodes.values():
for edge in node.edges:
target = edge.target
activation_group = edge.activation_group
# Build activation lookup
if target not in self._activation:
self._activation[target] = {}
if activation_group not in self._activation[target]:
self._activation[target][activation_group] = edge.activation_condition
# Build enqueued_any lookup
if target not in self._enqueued_any:
self._enqueued_any[target] = {}
if activation_group not in self._enqueued_any[target]:
self._enqueued_any[target][activation_group] = False
async def update_message_thread(self, messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> None:
await super().update_message_thread(messages)
# Find the node that ran in the current turn.
message = messages[-1]
if message.source not in self._graph.nodes:
# Ignore messages from sources outside of the graph.
return
assert isinstance(message, BaseChatMessage)
source = message.source
# Propagate the update to the children of the node.
for edge in self._edges[source]:
# Use the new check_condition method that handles both string and callable conditions
if not edge.check_condition(message):
continue
target = edge.target
activation_group = edge.activation_group
if self._activation[target][activation_group] == "all":
self._remaining[target][activation_group] -= 1
if self._remaining[target][activation_group] == 0:
# If all parents are done, add to the ready queue.
self._ready.append(target)
# Track which activation group was triggered
self._save_triggered_activation_group(target, activation_group)
else:
# If activation is any, add to the ready queue if not already enqueued.
if not self._enqueued_any[target][activation_group]:
self._ready.append(target)
self._enqueued_any[target][activation_group] = True
# Track which activation group was triggered
self._save_triggered_activation_group(target, activation_group)
def _save_triggered_activation_group(self, target: str, activation_group: str) -> None:
"""Save which activation group was triggered for a target node.
Args:
target: The target node that was triggered
activation_group: The activation group that caused the trigger
"""
if target not in self._triggered_activation_groups:
self._triggered_activation_groups[target] = set()
self._triggered_activation_groups[target].add(activation_group)
def _reset_triggered_activation_groups(self, speaker: str) -> None:
"""Reset the bookkeeping for the specific activation groups that were triggered for a speaker.
Args:
speaker: The speaker node to reset activation groups for
"""
if speaker not in self._triggered_activation_groups:
return
for activation_group in self._triggered_activation_groups[speaker]:
if self._activation[speaker][activation_group] == "any":
self._enqueued_any[speaker][activation_group] = False
else:
# Reset the remaining count for this activation group using the graph's original count
if speaker in self._remaining and activation_group in self._remaining[speaker]:
self._remaining[speaker][activation_group] = self._origin_remaining[speaker][activation_group]
# Clear the triggered activation groups for this speaker
self._triggered_activation_groups[speaker].clear()
async def select_speaker(self, thread: Sequence[BaseAgentEvent | BaseChatMessage]) -> List[str]:
# Drain the ready queue for the next set of speakers.
speakers: List[str] = []
while self._ready:
speaker = self._ready.popleft()
speakers.append(speaker)
# Reset the bookkeeping for the specific activation groups that were triggered
self._reset_triggered_activation_groups(speaker)
# If there are no speakers, trigger the stop agent.
if not speakers:
speakers = [_DIGRAPH_STOP_AGENT_NAME]
return speakers
async def validate_group_state(self, messages: List[BaseChatMessage] | None) -> None:
pass
async def save_state(self) -> Mapping[str, Any]:
"""Save the execution state."""
state = {
"message_thread": [message.dump() for message in self._message_thread],
"current_turn": self._current_turn,
"remaining": {target: dict(counter) for target, counter in self._remaining.items()},
"enqueued_any": dict(self._enqueued_any),
"ready": list(self._ready),
}
return state
async def load_state(self, state: Mapping[str, Any]) -> None:
"""Restore execution state from saved data."""
self._message_thread = [self._message_factory.create(msg) for msg in state["message_thread"]]
self._current_turn = state["current_turn"]
self._remaining = {target: Counter(groups) for target, groups in state["remaining"].items()}
self._enqueued_any = state["enqueued_any"]
self._ready = deque(state["ready"])
async def reset(self) -> None:
"""Reset execution state to the start of the graph."""
self._current_turn = 0
self._message_thread.clear()
if self._termination_condition:
await self._termination_condition.reset()
self._remaining = {target: Counter(groups) for target, groups in self._graph.get_remaining_map().items()}
self._enqueued_any = {n: {g: False for g in self._enqueued_any[n]} for n in self._enqueued_any}
self._ready = deque([n for n in self._graph.get_start_nodes()])
class _StopAgent(BaseChatAgent):
def __init__(self) -> None:
super().__init__(_DIGRAPH_STOP_AGENT_NAME, "Agent that terminates the GraphFlow.")
@property
def produced_message_types(self) -> Sequence[type[ChatMessage]]:
return (TextMessage, StopMessage)
async def on_messages(self, messages: Sequence[BaseChatMessage], cancellation_token: CancellationToken) -> Response:
return Response(chat_message=StopMessage(content=_DIGRAPH_STOP_AGENT_MESSAGE, source=self.name))
async def on_reset(self, cancellation_token: CancellationToken) -> None:
pass
class GraphFlowConfig(BaseModel):
"""The declarative configuration for GraphFlow."""
participants: List[ComponentModel]
termination_condition: ComponentModel | None = None
max_turns: int | None = None
graph: DiGraph # The execution graph for agents
class GraphFlow(BaseGroupChat, Component[GraphFlowConfig]):
"""A team that runs a group chat following a Directed Graph execution pattern.
.. warning::
This is an experimental feature, and the API will change in the future releases.
This group chat executes agents based on a directed graph (:class:`DiGraph`) structure,
allowing complex workflows such as sequential execution, parallel fan-out,
conditional branching, join patterns, and loops with explicit exit conditions.
The execution order is determined by the edges defined in the `DiGraph`. Each node
in the graph corresponds to an agent, and edges define the flow of messages between agents.
Nodes can be configured to activate when:
- **All** parent nodes have completed (activation="all") default
- **Any** parent node completes (activation="any")
Conditional branching is supported using edge conditions, where the next agent(s) are selected
based on content in the chat history. Loops are permitted as long as there is a condition
that eventually exits the loop.
.. note::
Use the :class:`DiGraphBuilder` class to create a :class:`DiGraph` easily. It provides a fluent API
for adding nodes and edges, setting entry points, and validating the graph structure.
See the :class:`DiGraphBuilder` documentation for more details.
The :class:`GraphFlow` class is designed to be used with the :class:`DiGraphBuilder` for creating complex workflows.
.. warning::
When using callable conditions in edges, they will not be serialized
when calling :meth:`dump_component`. This will be addressed in future releases.
Args:
participants (List[ChatAgent]): The participants in the group chat.
termination_condition (TerminationCondition, optional): Termination condition for the chat.
max_turns (int, optional): Maximum number of turns before forcing termination.
graph (DiGraph): Directed execution graph defining node flow and conditions.
Raises:
ValueError: If participant names are not unique, or if graph validation fails (e.g., cycles without exit).
Examples:
**Sequential Flow: A B C**
.. code-block:: python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.teams import DiGraphBuilder, GraphFlow
from autogen_ext.models.openai import OpenAIChatCompletionClient
async def main():
# Initialize agents with OpenAI model clients.
model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano")
agent_a = AssistantAgent("A", model_client=model_client, system_message="You are a helpful assistant.")
agent_b = AssistantAgent("B", model_client=model_client, system_message="Translate input to Chinese.")
agent_c = AssistantAgent("C", model_client=model_client, system_message="Translate input to English.")
# Create a directed graph with sequential flow A -> B -> C.
builder = DiGraphBuilder()
builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
builder.add_edge(agent_a, agent_b).add_edge(agent_b, agent_c)
graph = builder.build()
# Create a GraphFlow team with the directed graph.
team = GraphFlow(
participants=[agent_a, agent_b, agent_c],
graph=graph,
termination_condition=MaxMessageTermination(5),
)
# Run the team and print the events.
async for event in team.run_stream(task="Write a short story about a cat."):
print(event)
asyncio.run(main())
**Parallel Fan-out: A (B, C)**
.. code-block:: python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.teams import DiGraphBuilder, GraphFlow
from autogen_ext.models.openai import OpenAIChatCompletionClient
async def main():
# Initialize agents with OpenAI model clients.
model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano")
agent_a = AssistantAgent("A", model_client=model_client, system_message="You are a helpful assistant.")
agent_b = AssistantAgent("B", model_client=model_client, system_message="Translate input to Chinese.")
agent_c = AssistantAgent("C", model_client=model_client, system_message="Translate input to Japanese.")
# Create a directed graph with fan-out flow A -> (B, C).
builder = DiGraphBuilder()
builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
builder.add_edge(agent_a, agent_b).add_edge(agent_a, agent_c)
graph = builder.build()
# Create a GraphFlow team with the directed graph.
team = GraphFlow(
participants=[agent_a, agent_b, agent_c],
graph=graph,
termination_condition=MaxMessageTermination(5),
)
# Run the team and print the events.
async for event in team.run_stream(task="Write a short story about a cat."):
print(event)
asyncio.run(main())
**Conditional Branching: A B (if 'yes') or C (otherwise)**
.. code-block:: python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.teams import DiGraphBuilder, GraphFlow
from autogen_ext.models.openai import OpenAIChatCompletionClient
async def main():
# Initialize agents with OpenAI model clients.
model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano")
agent_a = AssistantAgent(
"A",
model_client=model_client,
system_message="Detect if the input is in Chinese. If it is, say 'yes', else say 'no', and nothing else.",
)
agent_b = AssistantAgent("B", model_client=model_client, system_message="Translate input to English.")
agent_c = AssistantAgent("C", model_client=model_client, system_message="Translate input to Chinese.")
# Create a directed graph with conditional branching flow A -> B ("yes"), A -> C (otherwise).
builder = DiGraphBuilder()
builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
# Create conditions as callables that check the message content.
builder.add_edge(agent_a, agent_b, condition=lambda msg: "yes" in msg.to_model_text())
builder.add_edge(agent_a, agent_c, condition=lambda msg: "yes" not in msg.to_model_text())
graph = builder.build()
# Create a GraphFlow team with the directed graph.
team = GraphFlow(
participants=[agent_a, agent_b, agent_c],
graph=graph,
termination_condition=MaxMessageTermination(5),
)
# Run the team and print the events.
async for event in team.run_stream(task="AutoGen is a framework for building AI agents."):
print(event)
asyncio.run(main())
**Loop with exit condition: A B C (if 'APPROVE') or A (otherwise)**
.. code-block:: python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.teams import DiGraphBuilder, GraphFlow
from autogen_ext.models.openai import OpenAIChatCompletionClient
async def main():
# Initialize agents with OpenAI model clients.
model_client = OpenAIChatCompletionClient(model="gpt-4.1")
agent_a = AssistantAgent(
"A",
model_client=model_client,
system_message="You are a helpful assistant.",
)
agent_b = AssistantAgent(
"B",
model_client=model_client,
system_message="Provide feedback on the input, if your feedback has been addressed, "
"say 'APPROVE', otherwise provide a reason for rejection.",
)
agent_c = AssistantAgent(
"C", model_client=model_client, system_message="Translate the final product to Korean."
)
# Create a loop graph with conditional exit: A -> B -> C ("APPROVE"), B -> A (otherwise).
builder = DiGraphBuilder()
builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
builder.add_edge(agent_a, agent_b)
# Create conditional edges using strings
builder.add_edge(agent_b, agent_c, condition=lambda msg: "APPROVE" in msg.to_model_text())
builder.add_edge(agent_b, agent_a, condition=lambda msg: "APPROVE" not in msg.to_model_text())
builder.set_entry_point(agent_a)
graph = builder.build()
# Create a GraphFlow team with the directed graph.
team = GraphFlow(
participants=[agent_a, agent_b, agent_c],
graph=graph,
termination_condition=MaxMessageTermination(20), # Max 20 messages to avoid infinite loop.
)
# Run the team and print the events.
async for event in team.run_stream(task="Write a short poem about AI Agents."):
print(event)
asyncio.run(main())
"""
component_config_schema = GraphFlowConfig
component_provider_override = "autogen_agentchat.teams.GraphFlow"
def __init__(
self,
participants: List[ChatAgent],
graph: DiGraph,
termination_condition: TerminationCondition | None = None,
max_turns: int | None = None,
runtime: AgentRuntime | None = None,
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
) -> None:
self._input_participants = participants
self._input_termination_condition = termination_condition
stop_agent = _StopAgent()
stop_agent_termination = StopMessageTermination()
termination_condition = (
stop_agent_termination
if not termination_condition
else OrTerminationCondition(stop_agent_termination, termination_condition)
)
participants = [stop_agent] + participants
super().__init__(
participants,
group_chat_manager_name="GraphManager",
group_chat_manager_class=GraphFlowManager,
termination_condition=termination_condition,
max_turns=max_turns,
runtime=runtime,
custom_message_types=custom_message_types,
)
self._graph = graph
def _create_group_chat_manager_factory(
self,
name: str,
group_topic_type: str,
output_topic_type: str,
participant_topic_types: List[str],
participant_names: List[str],
participant_descriptions: List[str],
output_message_queue: asyncio.Queue[BaseAgentEvent | BaseChatMessage | GroupChatTermination],
termination_condition: TerminationCondition | None,
max_turns: int | None,
message_factory: MessageFactory,
) -> Callable[[], GraphFlowManager]:
"""Creates the factory method for initializing the DiGraph-based chat manager."""
def _factory() -> GraphFlowManager:
return GraphFlowManager(
name=name,
group_topic_type=group_topic_type,
output_topic_type=output_topic_type,
participant_topic_types=participant_topic_types,
participant_names=participant_names,
participant_descriptions=participant_descriptions,
output_message_queue=output_message_queue,
termination_condition=termination_condition,
max_turns=max_turns,
message_factory=message_factory,
graph=self._graph,
)
return _factory
def _to_config(self) -> GraphFlowConfig:
"""Converts the instance into a configuration object."""
participants = [participant.dump_component() for participant in self._input_participants]
termination_condition = (
self._input_termination_condition.dump_component() if self._input_termination_condition else None
)
return GraphFlowConfig(
participants=participants,
termination_condition=termination_condition,
max_turns=self._max_turns,
graph=self._graph,
)
@classmethod
def _from_config(cls, config: GraphFlowConfig) -> Self:
"""Reconstructs an instance from a configuration object."""
participants = [ChatAgent.load_component(participant) for participant in config.participants]
termination_condition = (
TerminationCondition.load_component(config.termination_condition) if config.termination_condition else None
)
return cls(
participants, graph=config.graph, termination_condition=termination_condition, max_turns=config.max_turns
)

View File

@ -0,0 +1,209 @@
import warnings
from typing import Callable, Dict, Literal, Optional, Union
from autogen_agentchat.base import ChatAgent
from autogen_agentchat.messages import BaseChatMessage
from ._digraph_group_chat import DiGraph, DiGraphEdge, DiGraphNode
class DiGraphBuilder:
"""
A fluent builder for constructing :class:`DiGraph` execution graphs used in :class:`GraphFlow`.
.. warning::
This is an experimental feature, and the API will change in the future releases.
This utility provides a convenient way to programmatically build a graph of agent interactions,
including complex execution flows such as:
- Sequential chains
- Parallel fan-outs
- Conditional branching
- Cyclic loops with safe exits
Each node in the graph represents an agent. Edges define execution paths between agents,
and can optionally be conditioned on message content using callable functions.
The builder is compatible with the `Graph` runner and supports both standard and filtered agents.
Methods:
- add_node(agent, activation): Add an agent node to the graph.
- add_edge(source, target, condition): Connect two nodes optionally with a condition.
- add_conditional_edges(source, condition_to_target): Add multiple conditional edges from a source.
- set_entry_point(agent): Define the default start node (optional).
- build(): Generate a validated `DiGraph`.
- get_participants(): Return the list of added agents.
Example Sequential Flow A B C:
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
>>> builder.add_edge(agent_a, agent_b).add_edge(agent_b, agent_c)
>>> team = Graph(
... participants=builder.get_participants(),
... graph=builder.build(),
... termination_condition=MaxMessageTermination(5),
... )
Example Parallel Fan-out A (B, C):
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
>>> builder.add_edge(agent_a, agent_b).add_edge(agent_a, agent_c)
Example Conditional Branching A B or A C:
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
>>> # Add conditional edges using keyword check
>>> builder.add_edge(agent_a, agent_b, condition="keyword1")
>>> builder.add_edge(agent_a, agent_c, condition="keyword2")
Example Using Custom String Conditions:
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
>>> # Add condition strings to check in messages
>>> builder.add_edge(agent_a, agent_b, condition="big")
>>> builder.add_edge(agent_a, agent_c, condition="small")
Example Loop: A B A or B C:
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
>>> builder.add_edge(agent_a, agent_b)
>> # Add a loop back to agent A
>>> builder.add_edge(agent_b, agent_a, condition=lambda msg: "loop" in msg.to_model_text())
>>> # Add exit condition to break the loop
>>> builder.add_edge(agent_b, agent_c, condition=lambda msg: "loop" not in msg.to_model_text())
Example Loop with multiple paths to the same node: A B C B:
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c)
>>> builder.add_edge(agent_a, agent_b)
>>> builder.add_edge(agent_b, agent_c)
>>> builder.add_edge(agent_c, agent_b, activation_group="loop_back")
Example Loop with multiple paths to the same node with any activation condition: A B (C1, C2) B E(exit):
>>> builder = GraphBuilder()
>>> builder.add_node(agent_a).add_node(agent_b).add_node(agent_c1).add_node(agent_c2).add_node(agent_e)
>>> builder.add_edge(agent_a, agent_b)
>>> builder.add_edge(agent_b, agent_c1)
>>> builder.add_edge(agent_b, agent_c2)
>>> builder.add_edge(agent_b, agent_e, condition="exit")
>>> builder.add_edge(agent_c1, agent_b, activation_group="loop_back_group", activation_condition="any")
>>> builder.add_edge(agent_c2, agent_b, activation_group="loop_back_group", activation_condition="any")
"""
def __init__(self) -> None:
self.nodes: Dict[str, DiGraphNode] = {}
self.agents: Dict[str, ChatAgent] = {}
self._default_start_node: Optional[str] = None
def _get_name(self, obj: Union[str, ChatAgent]) -> str:
return obj if isinstance(obj, str) else obj.name
def add_node(self, agent: ChatAgent, activation: Literal["all", "any"] = "all") -> "DiGraphBuilder":
"""Add a node to the graph and register its agent."""
name = agent.name
if name not in self.nodes:
self.nodes[name] = DiGraphNode(name=name, edges=[], activation=activation)
self.agents[name] = agent
return self
def add_edge(
self,
source: Union[str, ChatAgent],
target: Union[str, ChatAgent],
condition: Optional[Union[str, Callable[[BaseChatMessage], bool]]] = None,
activation_group: Optional[str] = None,
activation_condition: Optional[Literal["all", "any"]] = None,
) -> "DiGraphBuilder":
"""Add a directed edge from source to target, optionally with a condition.
Args:
source: Source node (agent name or agent object)
target: Target node (agent name or agent object)
condition: Optional condition for edge activation.
If string, activates when substring is found in message.
If callable, activates when function returns True for the message.
Returns:
Self for method chaining
Raises:
ValueError: If source or target node doesn't exist in the builder
"""
source_name = self._get_name(source)
target_name = self._get_name(target)
if source_name not in self.nodes:
raise ValueError(f"Source node '{source_name}' must be added before adding an edge.")
if target_name not in self.nodes:
raise ValueError(f"Target node '{target_name}' must be added before adding an edge.")
if activation_group is None:
activation_group = target_name
if activation_condition is None:
activation_condition = "all"
self.nodes[source_name].edges.append(
DiGraphEdge(
target=target_name,
condition=condition,
activation_group=activation_group,
activation_condition=activation_condition,
)
)
return self
def add_conditional_edges(
self, source: Union[str, ChatAgent], condition_to_target: Dict[str, Union[str, ChatAgent]]
) -> "DiGraphBuilder":
"""Add multiple conditional edges from a source node based on keyword checks.
.. warning::
This method interface will be changed in the future to support callable conditions.
Please use `add_edge` if you need to specify custom conditions.
Args:
source: Source node (agent name or agent object)
condition_to_target: Mapping from condition strings to target nodes
Each key is a keyword that will be checked in the message content
Each value is the target node to activate when condition is met
For each key (keyword), a lambda will be created that checks
if the keyword is in the message text.
Returns:
Self for method chaining
"""
warnings.warn(
"add_conditional_edges will be changed in the future to support callable conditions. "
"For now, please use add_edge if you need to specify custom conditions.",
DeprecationWarning,
stacklevel=2,
)
for condition_keyword, target in condition_to_target.items():
self.add_edge(source, target, condition=condition_keyword)
return self
def set_entry_point(self, name: Union[str, ChatAgent]) -> "DiGraphBuilder":
"""Set the default start node of the graph."""
node_name = self._get_name(name)
if node_name not in self.nodes:
raise ValueError(f"Start node '{node_name}' must be added before setting as entry point.")
self._default_start_node = node_name
return self
def build(self) -> DiGraph:
"""Build and validate the DiGraph."""
graph = DiGraph(
nodes=self.nodes,
default_start_node=self._default_start_node,
)
graph.graph_validate()
return graph
def get_participants(self) -> list[ChatAgent]:
"""Return the list of agents in the builder, in insertion order."""
return list(self.agents.values())

View File

@ -28,6 +28,7 @@ class MagenticOneGroupChatConfig(BaseModel):
max_turns: int | None = None
max_stalls: int
final_answer_prompt: str
emit_team_events: bool = False
class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig]):
@ -46,6 +47,10 @@ class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig])
max_turns (int, optional): The maximum number of turns in the group chat before stopping. Defaults to 20.
max_stalls (int, optional): The maximum number of stalls allowed before re-planning. Defaults to 3.
final_answer_prompt (str, optional): The LLM prompt used to generate the final answer or response from the team's transcript. A default (sensible for GPT-4o class models) is provided.
custom_message_types (List[type[BaseAgentEvent | BaseChatMessage]], optional): A list of custom message types that will be used in the group chat.
If you are using custom message types or your agents produces custom message types, you need to specify them here.
Make sure your custom message types are subclasses of :class:`~autogen_agentchat.messages.BaseAgentEvent` or :class:`~autogen_agentchat.messages.BaseChatMessage`.
emit_team_events (bool, optional): Whether to emit team events through :meth:`BaseGroupChat.run_stream`. Defaults to False.
Raises:
ValueError: In orchestration logic if progress ledger does not have required keys or if next speaker is not valid.
@ -103,6 +108,8 @@ class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig])
runtime: AgentRuntime | None = None,
max_stalls: int = 3,
final_answer_prompt: str = ORCHESTRATOR_FINAL_ANSWER_PROMPT,
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
emit_team_events: bool = False,
):
super().__init__(
participants,
@ -111,6 +118,8 @@ class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig])
termination_condition=termination_condition,
max_turns=max_turns,
runtime=runtime,
custom_message_types=custom_message_types,
emit_team_events=emit_team_events,
)
# Validate the participants.
@ -147,6 +156,7 @@ class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig])
self._final_answer_prompt,
output_message_queue,
termination_condition,
self._emit_team_events,
)
def _to_config(self) -> MagenticOneGroupChatConfig:
@ -159,6 +169,7 @@ class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig])
max_turns=self._max_turns,
max_stalls=self._max_stalls,
final_answer_prompt=self._final_answer_prompt,
emit_team_events=self._emit_team_events,
)
@classmethod
@ -175,4 +186,5 @@ class MagenticOneGroupChat(BaseGroupChat, Component[MagenticOneGroupChatConfig])
max_turns=config.max_turns,
max_stalls=config.max_stalls,
final_answer_prompt=config.final_answer_prompt,
emit_team_events=config.emit_team_events,
)

View File

@ -2,7 +2,7 @@ import asyncio
import json
import logging
import re
from typing import Any, Dict, List, Mapping
from typing import Any, Dict, List, Mapping, Sequence
from autogen_core import AgentId, CancellationToken, DefaultTopicId, MessageContext, event, rpc
from autogen_core.models import (
@ -11,6 +11,7 @@ from autogen_core.models import (
LLMMessage,
UserMessage,
)
from autogen_core.utils import extract_json_from_str
from .... import TRACE_LOGGER_NAME
from ....base import Response, TerminationCondition
@ -20,6 +21,7 @@ from ....messages import (
HandoffMessage,
MessageFactory,
MultiModalMessage,
SelectSpeakerEvent,
StopMessage,
TextMessage,
ToolCallExecutionEvent,
@ -36,6 +38,7 @@ from .._events import (
GroupChatReset,
GroupChatStart,
GroupChatTermination,
SerializableException,
)
from ._prompts import (
ORCHESTRATOR_FINAL_ANSWER_PROMPT,
@ -45,6 +48,7 @@ from ._prompts import (
ORCHESTRATOR_TASK_LEDGER_FULL_PROMPT,
ORCHESTRATOR_TASK_LEDGER_PLAN_PROMPT,
ORCHESTRATOR_TASK_LEDGER_PLAN_UPDATE_PROMPT,
LedgerEntry,
)
trace_logger = logging.getLogger(TRACE_LOGGER_NAME)
@ -68,6 +72,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
final_answer_prompt: str,
output_message_queue: asyncio.Queue[BaseAgentEvent | BaseChatMessage | GroupChatTermination],
termination_condition: TerminationCondition | None,
emit_team_events: bool,
):
super().__init__(
name,
@ -80,6 +85,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
termination_condition,
max_turns,
message_factory,
emit_team_events=emit_team_events,
)
self._model_client = model_client
self._max_stalls = max_stalls
@ -184,22 +190,29 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
@event
async def handle_agent_response(self, message: GroupChatAgentResponse, ctx: MessageContext) -> None: # type: ignore
delta: List[BaseAgentEvent | BaseChatMessage] = []
if message.agent_response.inner_messages is not None:
for inner_message in message.agent_response.inner_messages:
delta.append(inner_message)
self._message_thread.append(message.agent_response.chat_message)
delta.append(message.agent_response.chat_message)
try:
delta: List[BaseAgentEvent | BaseChatMessage] = []
if message.agent_response.inner_messages is not None:
for inner_message in message.agent_response.inner_messages:
delta.append(inner_message)
await self.update_message_thread([message.agent_response.chat_message])
delta.append(message.agent_response.chat_message)
if self._termination_condition is not None:
stop_message = await self._termination_condition(delta)
if stop_message is not None:
# Reset the termination conditions.
await self._termination_condition.reset()
# Signal termination.
await self._signal_termination(stop_message)
return
await self._orchestrate_step(ctx.cancellation_token)
if self._termination_condition is not None:
stop_message = await self._termination_condition(delta)
if stop_message is not None:
# Reset the termination conditions.
await self._termination_condition.reset()
# Signal termination.
await self._signal_termination(stop_message)
return
await self._orchestrate_step(ctx.cancellation_token)
except Exception as e:
error = SerializableException.from_exception(e)
await self._signal_termination_with_error(error)
# Raise the error to the runtime.
raise
async def validate_group_state(self, messages: List[BaseChatMessage] | None) -> None:
pass
@ -226,9 +239,9 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
self._n_rounds = orchestrator_state.n_rounds
self._n_stalls = orchestrator_state.n_stalls
async def select_speaker(self, thread: List[BaseAgentEvent | BaseChatMessage]) -> str:
async def select_speaker(self, thread: Sequence[BaseAgentEvent | BaseChatMessage]) -> List[str] | str:
"""Not used in this orchestrator, we select next speaker in _orchestrate_step."""
return ""
return [""]
async def reset(self) -> None:
"""Reset the group chat manager."""
@ -260,7 +273,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
)
# Save my copy
self._message_thread.append(ledger_message)
await self.update_message_thread([ledger_message])
# Log it to the output topic.
await self.publish_message(
@ -272,7 +285,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
# Broadcast
await self.publish_message(
GroupChatAgentResponse(agent_response=Response(chat_message=ledger_message)),
GroupChatAgentResponse(agent_response=Response(chat_message=ledger_message), agent_name=self._name),
topic_id=DefaultTopicId(type=self._group_topic_type),
)
@ -298,11 +311,27 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
assert self._max_json_retries > 0
key_error: bool = False
for _ in range(self._max_json_retries):
response = await self._model_client.create(self._get_compatible_context(context), json_output=True)
if self._model_client.model_info.get("structured_output", False):
response = await self._model_client.create(
self._get_compatible_context(context), json_output=LedgerEntry
)
elif self._model_client.model_info.get("json_output", False):
response = await self._model_client.create(
self._get_compatible_context(context), cancellation_token=cancellation_token, json_output=True
)
else:
response = await self._model_client.create(
self._get_compatible_context(context), cancellation_token=cancellation_token
)
ledger_str = response.content
try:
assert isinstance(ledger_str, str)
progress_ledger = json.loads(ledger_str)
output_json = extract_json_from_str(ledger_str)
if len(output_json) != 1:
raise ValueError(
f"Progress ledger should contain a single JSON object, but found: {len(progress_ledger)}"
)
progress_ledger = output_json[0]
# If the team consists of a single agent, deterministically set the next speaker
if len(self._participant_names) == 1:
@ -373,7 +402,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
# Broadcast the next step
message = TextMessage(content=progress_ledger["instruction_or_question"]["answer"], source=self._name)
self._message_thread.append(message) # My copy
await self.update_message_thread([message]) # My copy
await self._log_message(f"Next Speaker: {progress_ledger['next_speaker']['answer']}")
# Log it to the output topic.
@ -386,7 +415,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
# Broadcast it
await self.publish_message( # Broadcast
GroupChatAgentResponse(agent_response=Response(chat_message=message)),
GroupChatAgentResponse(agent_response=Response(chat_message=message), agent_name=self._name),
topic_id=DefaultTopicId(type=self._group_topic_type),
cancellation_token=cancellation_token,
)
@ -405,6 +434,15 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
cancellation_token=cancellation_token,
)
# Send the message to the next speaker
if self._emit_team_events:
select_msg = SelectSpeakerEvent(content=[next_speaker], source=self._name)
await self.publish_message(
GroupChatMessage(message=select_msg),
topic_id=DefaultTopicId(type=self._output_topic_type),
)
await self._output_message_queue.put(select_msg)
async def _update_task_ledger(self, cancellation_token: CancellationToken) -> None:
"""Update the task ledger (outer loop) with the latest facts and plan."""
context = self._thread_to_context()
@ -446,7 +484,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
assert isinstance(response.content, str)
message = TextMessage(content=response.content, source=self._name)
self._message_thread.append(message) # My copy
await self.update_message_thread([message]) # My copy
# Log it to the output topic.
await self.publish_message(
@ -458,7 +496,7 @@ class MagenticOneOrchestrator(BaseGroupChatManager):
# Broadcast
await self.publish_message(
GroupChatAgentResponse(agent_response=Response(chat_message=message)),
GroupChatAgentResponse(agent_response=Response(chat_message=message), agent_name=self._name),
topic_id=DefaultTopicId(type=self._group_topic_type),
cancellation_token=cancellation_token,
)

View File

@ -1,3 +1,5 @@
from pydantic import BaseModel
ORCHESTRATOR_SYSTEM_MESSAGE = ""
@ -98,6 +100,24 @@ Please output an answer in pure JSON format according to the following schema. T
"""
class LedgerEntryBooleanAnswer(BaseModel):
reason: str
answer: bool
class LedgerEntryStringAnswer(BaseModel):
reason: str
answer: str
class LedgerEntry(BaseModel):
is_request_satisfied: LedgerEntryBooleanAnswer
is_in_loop: LedgerEntryBooleanAnswer
is_progress_being_made: LedgerEntryBooleanAnswer
next_speaker: LedgerEntryStringAnswer
instruction_or_question: LedgerEntryStringAnswer
ORCHESTRATOR_TASK_LEDGER_FACTS_UPDATE_PROMPT = """As a reminder, we are working to solve the following task:
{task}

View File

@ -1,5 +1,5 @@
import asyncio
from typing import Any, Callable, List, Mapping
from typing import Any, Callable, List, Mapping, Sequence
from autogen_core import AgentRuntime, Component, ComponentModel
from pydantic import BaseModel
@ -28,6 +28,7 @@ class RoundRobinGroupChatManager(BaseGroupChatManager):
termination_condition: TerminationCondition | None,
max_turns: int | None,
message_factory: MessageFactory,
emit_team_events: bool,
) -> None:
super().__init__(
name,
@ -40,6 +41,7 @@ class RoundRobinGroupChatManager(BaseGroupChatManager):
termination_condition,
max_turns,
message_factory,
emit_team_events,
)
self._next_speaker_index = 0
@ -67,8 +69,13 @@ class RoundRobinGroupChatManager(BaseGroupChatManager):
self._current_turn = round_robin_state.current_turn
self._next_speaker_index = round_robin_state.next_speaker_index
async def select_speaker(self, thread: List[BaseAgentEvent | BaseChatMessage]) -> str:
"""Select a speaker from the participants in a round-robin fashion."""
async def select_speaker(self, thread: Sequence[BaseAgentEvent | BaseChatMessage]) -> List[str] | str:
"""Select a speaker from the participants in a round-robin fashion.
.. note::
This method always returns a single speaker.
"""
current_speaker_index = self._next_speaker_index
self._next_speaker_index = (current_speaker_index + 1) % len(self._participant_names)
current_speaker = self._participant_names[current_speaker_index]
@ -81,6 +88,7 @@ class RoundRobinGroupChatConfig(BaseModel):
participants: List[ComponentModel]
termination_condition: ComponentModel | None = None
max_turns: int | None = None
emit_team_events: bool = False
class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
@ -94,6 +102,10 @@ class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
termination_condition (TerminationCondition, optional): The termination condition for the group chat. Defaults to None.
Without a termination condition, the group chat will run indefinitely.
max_turns (int, optional): The maximum number of turns in the group chat before stopping. Defaults to None, meaning no limit.
custom_message_types (List[type[BaseAgentEvent | BaseChatMessage]], optional): A list of custom message types that will be used in the group chat.
If you are using custom message types or your agents produces custom message types, you need to specify them here.
Make sure your custom message types are subclasses of :class:`~autogen_agentchat.messages.BaseAgentEvent` or :class:`~autogen_agentchat.messages.BaseChatMessage`.
emit_team_events (bool, optional): Whether to emit team events through :meth:`BaseGroupChat.run_stream`. Defaults to False.
Raises:
ValueError: If no participants are provided or if participant names are not unique.
@ -167,6 +179,7 @@ class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
max_turns: int | None = None,
runtime: AgentRuntime | None = None,
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
emit_team_events: bool = False,
) -> None:
super().__init__(
participants,
@ -176,6 +189,7 @@ class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
max_turns=max_turns,
runtime=runtime,
custom_message_types=custom_message_types,
emit_team_events=emit_team_events,
)
def _create_group_chat_manager_factory(
@ -203,6 +217,7 @@ class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
termination_condition,
max_turns,
message_factory,
self._emit_team_events,
)
return _factory
@ -214,6 +229,7 @@ class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
participants=participants,
termination_condition=termination_condition,
max_turns=self._max_turns,
emit_team_events=self._emit_team_events,
)
@classmethod
@ -222,4 +238,9 @@ class RoundRobinGroupChat(BaseGroupChat, Component[RoundRobinGroupChatConfig]):
termination_condition = (
TerminationCondition.load_component(config.termination_condition) if config.termination_condition else None
)
return cls(participants, termination_condition=termination_condition, max_turns=config.max_turns)
return cls(
participants,
termination_condition=termination_condition,
max_turns=config.max_turns,
emit_team_events=config.emit_team_events,
)

View File

@ -4,8 +4,20 @@ import re
from inspect import iscoroutinefunction
from typing import Any, Awaitable, Callable, Dict, List, Mapping, Optional, Sequence, Union, cast
from autogen_core import AgentRuntime, Component, ComponentModel
from autogen_core.models import AssistantMessage, ChatCompletionClient, ModelFamily, SystemMessage, UserMessage
from autogen_core import AgentRuntime, CancellationToken, Component, ComponentModel
from autogen_core.model_context import (
ChatCompletionContext,
UnboundedChatCompletionContext,
)
from autogen_core.models import (
AssistantMessage,
ChatCompletionClient,
CreateResult,
LLMMessage,
ModelFamily,
SystemMessage,
UserMessage,
)
from pydantic import BaseModel
from typing_extensions import Self
@ -15,7 +27,10 @@ from ...base import ChatAgent, TerminationCondition
from ...messages import (
BaseAgentEvent,
BaseChatMessage,
HandoffMessage,
MessageFactory,
ModelClientStreamingChunkEvent,
SelectorEvent,
)
from ...state import SelectorManagerState
from ._base_group_chat import BaseGroupChat
@ -55,6 +70,9 @@ class SelectorGroupChatManager(BaseGroupChatManager):
selector_func: Optional[SelectorFuncType],
max_selector_attempts: int,
candidate_func: Optional[CandidateFuncType],
emit_team_events: bool,
model_context: ChatCompletionContext | None,
model_client_streaming: bool = False,
) -> None:
super().__init__(
name,
@ -67,6 +85,7 @@ class SelectorGroupChatManager(BaseGroupChatManager):
termination_condition,
max_turns,
message_factory,
emit_team_events,
)
self._model_client = model_client
self._selector_prompt = selector_prompt
@ -77,6 +96,12 @@ class SelectorGroupChatManager(BaseGroupChatManager):
self._max_selector_attempts = max_selector_attempts
self._candidate_func = candidate_func
self._is_candidate_func_async = iscoroutinefunction(self._candidate_func)
self._model_client_streaming = model_client_streaming
if model_context is not None:
self._model_context = model_context
else:
self._model_context = UnboundedChatCompletionContext()
self._cancellation_token = CancellationToken()
async def validate_group_state(self, messages: List[BaseChatMessage] | None) -> None:
pass
@ -84,6 +109,7 @@ class SelectorGroupChatManager(BaseGroupChatManager):
async def reset(self) -> None:
self._current_turn = 0
self._message_thread.clear()
await self._model_context.clear()
if self._termination_condition is not None:
await self._termination_condition.reset()
self._previous_speaker = None
@ -99,16 +125,41 @@ class SelectorGroupChatManager(BaseGroupChatManager):
async def load_state(self, state: Mapping[str, Any]) -> None:
selector_state = SelectorManagerState.model_validate(state)
self._message_thread = [self._message_factory.create(msg) for msg in selector_state.message_thread]
await self._add_messages_to_context(
self._model_context, [msg for msg in self._message_thread if isinstance(msg, BaseChatMessage)]
)
self._current_turn = selector_state.current_turn
self._previous_speaker = selector_state.previous_speaker
async def select_speaker(self, thread: List[BaseAgentEvent | BaseChatMessage]) -> str:
@staticmethod
async def _add_messages_to_context(
model_context: ChatCompletionContext,
messages: Sequence[BaseChatMessage],
) -> None:
"""
Add incoming messages to the model context.
"""
for msg in messages:
if isinstance(msg, HandoffMessage):
for llm_msg in msg.context:
await model_context.add_message(llm_msg)
await model_context.add_message(msg.to_model_message())
async def update_message_thread(self, messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> None:
self._message_thread.extend(messages)
base_chat_messages = [m for m in messages if isinstance(m, BaseChatMessage)]
await self._add_messages_to_context(self._model_context, base_chat_messages)
async def select_speaker(self, thread: Sequence[BaseAgentEvent | BaseChatMessage]) -> List[str] | str:
"""Selects the next speaker in a group chat using a ChatCompletion client,
with the selector function as override if it returns a speaker name.
.. note::
This method always returns a single speaker name.
A key assumption is that the agent type is the same as the topic type, which we use as the agent name.
"""
# Use the selector function if provided.
if self._selector_func is not None:
if self._is_selector_func_async:
@ -124,7 +175,7 @@ class SelectorGroupChatManager(BaseGroupChatManager):
f"Expected one of: {self._participant_names}."
)
# Skip the model based selection.
return speaker
return [speaker]
# Use the candidate function to filter participants if provided
if self._candidate_func is not None:
@ -150,18 +201,6 @@ class SelectorGroupChatManager(BaseGroupChatManager):
assert len(participants) > 0
# Construct the history of the conversation.
history_messages: List[str] = []
for msg in thread:
if not isinstance(msg, BaseChatMessage):
# Only process chat messages.
continue
message = f"{msg.source}: {msg.to_model_text()}"
history_messages.append(
message.rstrip() + "\n\n"
) # Create some consistency for how messages are separated in the transcript
history = "\n".join(history_messages)
# Construct agent roles.
# Each agent sould appear on a single line.
roles = ""
@ -171,17 +210,34 @@ class SelectorGroupChatManager(BaseGroupChatManager):
# Select the next speaker.
if len(participants) > 1:
agent_name = await self._select_speaker(roles, participants, history, self._max_selector_attempts)
agent_name = await self._select_speaker(roles, participants, self._max_selector_attempts)
else:
agent_name = participants[0]
self._previous_speaker = agent_name
trace_logger.debug(f"Selected speaker: {agent_name}")
return agent_name
return [agent_name]
def construct_message_history(self, message_history: List[LLMMessage]) -> str:
# Construct the history of the conversation.
history_messages: List[str] = []
for msg in message_history:
if isinstance(msg, UserMessage) or isinstance(msg, AssistantMessage):
message = f"{msg.source}: {msg.content}"
history_messages.append(
message.rstrip() + "\n\n"
) # Create some consistency for how messages are separated in the transcript
history: str = "\n".join(history_messages)
return history
async def _select_speaker(self, roles: str, participants: List[str], max_attempts: int) -> str:
model_context_messages = await self._model_context.get_messages()
model_context_history = self.construct_message_history(model_context_messages)
async def _select_speaker(self, roles: str, participants: List[str], history: str, max_attempts: int) -> str:
select_speaker_prompt = self._selector_prompt.format(
roles=roles, participants=str(participants), history=history
roles=roles, participants=str(participants), history=model_context_history
)
select_speaker_messages: List[SystemMessage | UserMessage | AssistantMessage]
if ModelFamily.is_openai(self._model_client.model_info["family"]):
select_speaker_messages = [SystemMessage(content=select_speaker_prompt)]
@ -192,7 +248,26 @@ class SelectorGroupChatManager(BaseGroupChatManager):
num_attempts = 0
while num_attempts < max_attempts:
num_attempts += 1
response = await self._model_client.create(messages=select_speaker_messages)
if self._model_client_streaming:
chunk: CreateResult | str = ""
async for _chunk in self._model_client.create_stream(messages=select_speaker_messages):
chunk = _chunk
if self._emit_team_events:
if isinstance(chunk, str):
await self._output_message_queue.put(
ModelClientStreamingChunkEvent(content=cast(str, _chunk), source=self._name)
)
else:
assert isinstance(chunk, CreateResult)
assert isinstance(chunk.content, str)
await self._output_message_queue.put(
SelectorEvent(content=chunk.content, source=self._name)
)
# The last chunk must be CreateResult.
assert isinstance(chunk, CreateResult)
response = chunk
else:
response = await self._model_client.create(messages=select_speaker_messages)
assert isinstance(response.content, str)
select_speaker_messages.append(AssistantMessage(content=response.content, source="selector"))
# NOTE: we use all participant names to check for mentions, even if the previous speaker is not allowed.
@ -278,6 +353,9 @@ class SelectorGroupChatConfig(BaseModel):
allow_repeated_speaker: bool
# selector_func: ComponentModel | None
max_selector_attempts: int = 3
emit_team_events: bool = False
model_client_streaming: bool = False
model_context: ComponentModel | None = None
class SelectorGroupChat(BaseGroupChat, Component[SelectorGroupChatConfig]):
@ -294,6 +372,9 @@ class SelectorGroupChat(BaseGroupChat, Component[SelectorGroupChatConfig]):
max_turns (int, optional): The maximum number of turns in the group chat before stopping. Defaults to None, meaning no limit.
selector_prompt (str, optional): The prompt template to use for selecting the next speaker.
Available fields: '{roles}', '{participants}', and '{history}'.
`{participants}` is the names of candidates for selection. The format is `["<name1>", "<name2>", ...]`.
`{roles}` is a newline-separated list of names and descriptions of the candidate agents. The format for each line is: `"<name> : <description>"`.
`{history}` is the conversation history formatted as a double newline separated of names and message content. The format for each message is: `"<name> : <message content>"`.
allow_repeated_speaker (bool, optional): Whether to include the previous speaker in the list of candidates to be selected for the next turn.
Defaults to False. The model may still select the previous speaker -- a warning will be logged if this happens.
max_selector_attempts (int, optional): The maximum number of attempts to select a speaker using the model. Defaults to 3.
@ -303,11 +384,18 @@ class SelectorGroupChat(BaseGroupChat, Component[SelectorGroupChatConfig]):
function that takes the conversation history and returns the name of the next speaker.
If provided, this function will be used to override the model to select the next speaker.
If the function returns None, the model will be used to select the next speaker.
NOTE: `selector_func` is not serializable and will be ignored during serialization and deserialization process.
candidate_func (Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], List[str]], Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], Awaitable[List[str]]], optional):
A custom function that takes the conversation history and returns a filtered list of candidates for the next speaker
selection using model. If the function returns an empty list or `None`, `SelectorGroupChat` will raise a `ValueError`.
This function is only used if `selector_func` is not set. The `allow_repeated_speaker` will be ignored if set.
custom_message_types (List[type[BaseAgentEvent | BaseChatMessage]], optional): A list of custom message types that will be used in the group chat.
If you are using custom message types or your agents produces custom message types, you need to specify them here.
Make sure your custom message types are subclasses of :class:`~autogen_agentchat.messages.BaseAgentEvent` or :class:`~autogen_agentchat.messages.BaseChatMessage`.
emit_team_events (bool, optional): Whether to emit team events through :meth:`BaseGroupChat.run_stream`. Defaults to False.
model_client_streaming (bool, optional): Whether to use streaming for the model client. (This is useful for reasoning models like QwQ). Defaults to False.
model_context (ChatCompletionContext | None, optional): The model context for storing and retrieving
:class:`~autogen_core.models.LLMMessage`. It can be preloaded with initial messages. Messages stored in model context will be used for speaker selection. The initial messages will be cleared when the team is reset.
Raises:
ValueError: If the number of participants is less than two or if the selector prompt is invalid.
@ -422,6 +510,64 @@ class SelectorGroupChat(BaseGroupChat, Component[SelectorGroupChatConfig]):
await Console(team.run_stream(task="What is 1 + 1?"))
asyncio.run(main())
A team with custom model context:
.. code-block:: python
import asyncio
from autogen_core.model_context import BufferedChatCompletionContext
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Console
async def main() -> None:
model_client = OpenAIChatCompletionClient(model="gpt-4o")
model_context = BufferedChatCompletionContext(buffer_size=5)
async def lookup_hotel(location: str) -> str:
return f"Here are some hotels in {location}: hotel1, hotel2, hotel3."
async def lookup_flight(origin: str, destination: str) -> str:
return f"Here are some flights from {origin} to {destination}: flight1, flight2, flight3."
async def book_trip() -> str:
return "Your trip is booked!"
travel_advisor = AssistantAgent(
"Travel_Advisor",
model_client,
tools=[book_trip],
description="Helps with travel planning.",
)
hotel_agent = AssistantAgent(
"Hotel_Agent",
model_client,
tools=[lookup_hotel],
description="Helps with hotel booking.",
)
flight_agent = AssistantAgent(
"Flight_Agent",
model_client,
tools=[lookup_flight],
description="Helps with flight booking.",
)
termination = TextMentionTermination("TERMINATE")
team = SelectorGroupChat(
[travel_advisor, hotel_agent, flight_agent],
model_client=model_client,
termination_condition=termination,
model_context=model_context,
)
await Console(team.run_stream(task="Book a 3-day trip to new york."))
asyncio.run(main())
"""
@ -449,6 +595,9 @@ Read the above conversation. Then select the next role from {participants} to pl
selector_func: Optional[SelectorFuncType] = None,
candidate_func: Optional[CandidateFuncType] = None,
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
emit_team_events: bool = False,
model_client_streaming: bool = False,
model_context: ChatCompletionContext | None = None,
):
super().__init__(
participants,
@ -458,6 +607,7 @@ Read the above conversation. Then select the next role from {participants} to pl
max_turns=max_turns,
runtime=runtime,
custom_message_types=custom_message_types,
emit_team_events=emit_team_events,
)
# Validate the participants.
if len(participants) < 2:
@ -468,6 +618,8 @@ Read the above conversation. Then select the next role from {participants} to pl
self._selector_func = selector_func
self._max_selector_attempts = max_selector_attempts
self._candidate_func = candidate_func
self._model_client_streaming = model_client_streaming
self._model_context = model_context
def _create_group_chat_manager_factory(
self,
@ -499,6 +651,9 @@ Read the above conversation. Then select the next role from {participants} to pl
self._selector_func,
self._max_selector_attempts,
self._candidate_func,
self._emit_team_events,
self._model_context,
self._model_client_streaming,
)
def _to_config(self) -> SelectorGroupChatConfig:
@ -511,6 +666,9 @@ Read the above conversation. Then select the next role from {participants} to pl
allow_repeated_speaker=self._allow_repeated_speaker,
max_selector_attempts=self._max_selector_attempts,
# selector_func=self._selector_func.dump_component() if self._selector_func else None,
emit_team_events=self._emit_team_events,
model_client_streaming=self._model_client_streaming,
model_context=self._model_context.dump_component() if self._model_context else None,
)
@classmethod
@ -528,4 +686,7 @@ Read the above conversation. Then select the next role from {participants} to pl
# selector_func=ComponentLoader.load_component(config.selector_func, Callable[[Sequence[BaseAgentEvent | BaseChatMessage]], str | None])
# if config.selector_func
# else None,
emit_team_events=config.emit_team_events,
model_client_streaming=config.model_client_streaming,
model_context=ChatCompletionContext.load_component(config.model_context) if config.model_context else None,
)

View File

@ -1,5 +1,5 @@
import asyncio
from typing import Any, Callable, List, Mapping
from typing import Any, Callable, List, Mapping, Sequence
from autogen_core import AgentRuntime, Component, ComponentModel
from pydantic import BaseModel
@ -27,6 +27,7 @@ class SwarmGroupChatManager(BaseGroupChatManager):
termination_condition: TerminationCondition | None,
max_turns: int | None,
message_factory: MessageFactory,
emit_team_events: bool,
) -> None:
super().__init__(
name,
@ -39,6 +40,7 @@ class SwarmGroupChatManager(BaseGroupChatManager):
termination_condition,
max_turns,
message_factory,
emit_team_events,
)
self._current_speaker = self._participant_names[0]
@ -77,17 +79,22 @@ class SwarmGroupChatManager(BaseGroupChatManager):
await self._termination_condition.reset()
self._current_speaker = self._participant_names[0]
async def select_speaker(self, thread: List[BaseAgentEvent | BaseChatMessage]) -> str:
async def select_speaker(self, thread: Sequence[BaseAgentEvent | BaseChatMessage]) -> List[str] | str:
"""Select a speaker from the participants based on handoff message.
Looks for the last handoff message in the thread to determine the next speaker."""
Looks for the last handoff message in the thread to determine the next speaker.
.. note::
This method always returns a single speaker.
"""
if len(thread) == 0:
return self._current_speaker
return [self._current_speaker]
for message in reversed(thread):
if isinstance(message, HandoffMessage):
self._current_speaker = message.target
# The latest handoff message should always target a valid participant.
assert self._current_speaker in self._participant_names
return self._current_speaker
return [self._current_speaker]
return self._current_speaker
async def save_state(self) -> Mapping[str, Any]:
@ -111,6 +118,7 @@ class SwarmConfig(BaseModel):
participants: List[ComponentModel]
termination_condition: ComponentModel | None = None
max_turns: int | None = None
emit_team_events: bool = False
class Swarm(BaseGroupChat, Component[SwarmConfig]):
@ -126,6 +134,10 @@ class Swarm(BaseGroupChat, Component[SwarmConfig]):
termination_condition (TerminationCondition, optional): The termination condition for the group chat. Defaults to None.
Without a termination condition, the group chat will run indefinitely.
max_turns (int, optional): The maximum number of turns in the group chat before stopping. Defaults to None, meaning no limit.
custom_message_types (List[type[BaseAgentEvent | BaseChatMessage]], optional): A list of custom message types that will be used in the group chat.
If you are using custom message types or your agents produces custom message types, you need to specify them here.
Make sure your custom message types are subclasses of :class:`~autogen_agentchat.messages.BaseAgentEvent` or :class:`~autogen_agentchat.messages.BaseChatMessage`.
emit_team_events (bool, optional): Whether to emit team events through :meth:`BaseGroupChat.run_stream`. Defaults to False.
Basic example:
@ -213,6 +225,7 @@ class Swarm(BaseGroupChat, Component[SwarmConfig]):
max_turns: int | None = None,
runtime: AgentRuntime | None = None,
custom_message_types: List[type[BaseAgentEvent | BaseChatMessage]] | None = None,
emit_team_events: bool = False,
) -> None:
super().__init__(
participants,
@ -222,6 +235,7 @@ class Swarm(BaseGroupChat, Component[SwarmConfig]):
max_turns=max_turns,
runtime=runtime,
custom_message_types=custom_message_types,
emit_team_events=emit_team_events,
)
# The first participant must be able to produce handoff messages.
first_participant = self._participants[0]
@ -253,6 +267,7 @@ class Swarm(BaseGroupChat, Component[SwarmConfig]):
termination_condition,
max_turns,
message_factory,
self._emit_team_events,
)
return _factory
@ -264,6 +279,7 @@ class Swarm(BaseGroupChat, Component[SwarmConfig]):
participants=participants,
termination_condition=termination_condition,
max_turns=self._max_turns,
emit_team_events=self._emit_team_events,
)
@classmethod
@ -272,4 +288,9 @@ class Swarm(BaseGroupChat, Component[SwarmConfig]):
termination_condition = (
TerminationCondition.load_component(config.termination_condition) if config.termination_condition else None
)
return cls(participants, termination_condition=termination_condition, max_turns=config.max_turns)
return cls(
participants,
termination_condition=termination_condition,
max_turns=config.max_turns,
emit_team_events=config.emit_team_events,
)

View File

@ -0,0 +1,4 @@
from ._agent import AgentTool
from ._team import TeamTool
__all__ = ["AgentTool", "TeamTool"]

View File

@ -0,0 +1,83 @@
from autogen_core import Component, ComponentModel
from pydantic import BaseModel
from typing_extensions import Self
from autogen_agentchat.agents import BaseChatAgent
from ._task_runner_tool import TaskRunnerTool
class AgentToolConfig(BaseModel):
"""Configuration for the AgentTool."""
agent: ComponentModel
"""The agent to be used for running the task."""
return_value_as_last_message: bool = False
"""Whether to return the value as the last message of the task result."""
class AgentTool(TaskRunnerTool, Component[AgentToolConfig]):
"""Tool that can be used to run a task using an agent.
The tool returns the result of the task execution as a :class:`~autogen_agentchat.base.TaskResult` object.
Args:
agent (BaseChatAgent): The agent to be used for running the task.
return_value_as_last_message (bool): Whether to use the last message content of the task result
as the return value of the tool in :meth:`~autogen_agentchat.tools.TaskRunnerTool.return_value_as_string`.
If set to True, the last message content will be returned as a string.
If set to False, the tool will return all messages in the task result as a string concatenated together,
with each message prefixed by its source (e.g., "writer: ...", "assistant: ...").
Example:
.. code-block:: python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.tools import AgentTool
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
async def main() -> None:
model_client = OpenAIChatCompletionClient(model="gpt-4")
writer = AssistantAgent(
name="writer",
description="A writer agent for generating text.",
model_client=model_client,
system_message="Write well.",
)
writer_tool = AgentTool(agent=writer)
assistant = AssistantAgent(
name="assistant",
model_client=model_client,
tools=[writer_tool],
system_message="You are a helpful assistant.",
)
await Console(assistant.run_stream(task="Write a poem about the sea."))
asyncio.run(main())
"""
component_config_schema = AgentToolConfig
component_provider_override = "autogen_agentchat.tools.AgentTool"
def __init__(self, agent: BaseChatAgent, return_value_as_last_message: bool = False) -> None:
self._agent = agent
super().__init__(
agent, agent.name, agent.description, return_value_as_last_message=return_value_as_last_message
)
def _to_config(self) -> AgentToolConfig:
return AgentToolConfig(
agent=self._agent.dump_component(),
return_value_as_last_message=self._return_value_as_last_message,
)
@classmethod
def _from_config(cls, config: AgentToolConfig) -> Self:
return cls(BaseChatAgent.load_component(config.agent), config.return_value_as_last_message)

View File

@ -0,0 +1,71 @@
from abc import ABC
from typing import Annotated, Any, AsyncGenerator, List, Mapping
from autogen_core import CancellationToken
from autogen_core.tools import BaseStreamTool
from pydantic import BaseModel
from ..agents import BaseChatAgent
from ..base import TaskResult
from ..messages import BaseAgentEvent, BaseChatMessage
from ..teams import BaseGroupChat
class TaskRunnerToolArgs(BaseModel):
"""Input for the TaskRunnerTool."""
task: Annotated[str, "The task to be executed."]
class TaskRunnerTool(BaseStreamTool[TaskRunnerToolArgs, BaseAgentEvent | BaseChatMessage, TaskResult], ABC):
"""An base class for tool that can be used to run a task using a team or an agent."""
component_type = "tool"
def __init__(
self,
task_runner: BaseGroupChat | BaseChatAgent,
name: str,
description: str,
return_value_as_last_message: bool,
) -> None:
self._task_runner = task_runner
self._return_value_as_last_message = return_value_as_last_message
super().__init__(
args_type=TaskRunnerToolArgs,
return_type=TaskResult,
name=name,
description=description,
)
async def run(self, args: TaskRunnerToolArgs, cancellation_token: CancellationToken) -> TaskResult:
"""Run the task and return the result."""
return await self._task_runner.run(task=args.task, cancellation_token=cancellation_token)
async def run_stream(
self, args: TaskRunnerToolArgs, cancellation_token: CancellationToken
) -> AsyncGenerator[BaseAgentEvent | BaseChatMessage | TaskResult, None]:
"""Run the task and yield events or messages as they are produced, the final :class:`TaskResult`
will be yielded at the end."""
async for event in self._task_runner.run_stream(task=args.task, cancellation_token=cancellation_token):
yield event
def return_value_as_string(self, value: TaskResult) -> str:
"""Convert the task result to a string."""
if self._return_value_as_last_message:
if value.messages and isinstance(value.messages[-1], BaseChatMessage):
return value.messages[-1].to_model_text()
raise ValueError("The last message is not a BaseChatMessage.")
parts: List[str] = []
for message in value.messages:
if isinstance(message, BaseChatMessage):
if message.source == "user":
continue
parts.append(f"{message.source}: {message.to_model_text()}")
return "\n\n".join(parts)
async def save_state_json(self) -> Mapping[str, Any]:
return await self._task_runner.save_state()
async def load_state_json(self, state: Mapping[str, Any]) -> None:
await self._task_runner.load_state(state)

View File

@ -0,0 +1,120 @@
from autogen_core import Component, ComponentModel
from pydantic import BaseModel
from typing_extensions import Self
from autogen_agentchat.teams import BaseGroupChat
from ._task_runner_tool import TaskRunnerTool
class TeamToolConfig(BaseModel):
"""Configuration for the TeamTool."""
name: str
"""The name of the tool."""
description: str
"""The name and description of the tool."""
team: ComponentModel
"""The team to be used for running the task."""
return_value_as_last_message: bool = False
"""Whether to return the value as the last message of the task result."""
class TeamTool(TaskRunnerTool, Component[TeamToolConfig]):
"""Tool that can be used to run a task.
The tool returns the result of the task execution as a :class:`~autogen_agentchat.base.TaskResult` object.
Args:
team (BaseGroupChat): The team to be used for running the task.
name (str): The name of the tool.
description (str): The description of the tool.
return_value_as_last_message (bool): Whether to use the last message content of the task result
as the return value of the tool in :meth:`~autogen_agentchat.tools.TaskRunnerTool.return_value_as_string`.
If set to True, the last message content will be returned as a string.
If set to False, the tool will return all messages in the task result as a string concatenated together,
with each message prefixed by its source (e.g., "writer: ...", "assistant: ...").
Example:
.. code-block:: python
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import SourceMatchTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.tools import TeamTool
from autogen_agentchat.ui import Console
from autogen_ext.models.ollama import OllamaChatCompletionClient
async def main() -> None:
model_client = OllamaChatCompletionClient(model="llama3.2")
writer = AssistantAgent(name="writer", model_client=model_client, system_message="You are a helpful assistant.")
reviewer = AssistantAgent(
name="reviewer", model_client=model_client, system_message="You are a critical reviewer."
)
summarizer = AssistantAgent(
name="summarizer",
model_client=model_client,
system_message="You combine the review and produce a revised response.",
)
team = RoundRobinGroupChat(
[writer, reviewer, summarizer], termination_condition=SourceMatchTermination(sources=["summarizer"])
)
# Create a TeamTool that uses the team to run tasks, returning the last message as the result.
tool = TeamTool(
team=team, name="writing_team", description="A tool for writing tasks.", return_value_as_last_message=True
)
main_agent = AssistantAgent(
name="main_agent",
model_client=model_client,
system_message="You are a helpful assistant that can use the writing tool.",
tools=[tool],
)
# For handling each events manually.
# async for message in main_agent.run_stream(
# task="Write a short story about a robot learning to love.",
# ):
# print(message)
# Use Console to display the messages in a more readable format.
await Console(
main_agent.run_stream(
task="Write a short story about a robot learning to love.",
)
)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
"""
component_config_schema = TeamToolConfig
component_provider_override = "autogen_agentchat.tools.TeamTool"
def __init__(
self, team: BaseGroupChat, name: str, description: str, return_value_as_last_message: bool = False
) -> None:
self._team = team
super().__init__(team, name, description, return_value_as_last_message=return_value_as_last_message)
def _to_config(self) -> TeamToolConfig:
return TeamToolConfig(
name=self._name,
description=self._description,
team=self._team.dump_component(),
return_value_as_last_message=self._return_value_as_last_message,
)
@classmethod
def _from_config(cls, config: TeamToolConfig) -> Self:
return cls(
BaseGroupChat.load_component(config.team),
config.name,
config.description,
config.return_value_as_last_message,
)

View File

@ -173,9 +173,11 @@ async def Console(
message = cast(BaseAgentEvent | BaseChatMessage, message) # type: ignore
if not streaming_chunks:
# Print message sender.
await aprint(f"{'-' * 10} {message.source} {'-' * 10}", end="\n", flush=True)
await aprint(
f"{'-' * 10} {message.__class__.__name__} ({message.source}) {'-' * 10}", end="\n", flush=True
)
if isinstance(message, ModelClientStreamingChunkEvent):
await aprint(message.to_text(), end="")
await aprint(message.to_text(), end="", flush=True)
streaming_chunks.append(message.content)
else:
if streaming_chunks:

View File

@ -0,0 +1,126 @@
import pytest
from autogen_agentchat.agents import (
AssistantAgent,
CodeExecutorAgent,
SocietyOfMindAgent,
)
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_core.model_context import (
BufferedChatCompletionContext,
ChatCompletionContext,
HeadAndTailChatCompletionContext,
TokenLimitedChatCompletionContext,
UnboundedChatCompletionContext,
)
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.models.replay import ReplayChatCompletionClient
@pytest.mark.parametrize(
"model_context_class",
[
UnboundedChatCompletionContext(),
BufferedChatCompletionContext(buffer_size=5),
TokenLimitedChatCompletionContext(model_client=ReplayChatCompletionClient([]), token_limit=5),
HeadAndTailChatCompletionContext(head_size=3, tail_size=2),
],
)
def test_serialize_and_deserialize_model_context_on_assistant_agent(model_context_class: ChatCompletionContext) -> None:
"""Test the serialization and deserialization of the message context on the AssistantAgent."""
agent = AssistantAgent(
name="assistant",
model_client=ReplayChatCompletionClient([]),
description="An assistant agent.",
model_context=model_context_class,
)
# Serialize the agent
serialized_agent = agent.dump_component()
# Deserialize the agent
deserialized_agent = AssistantAgent.load_component(serialized_agent)
# Check that the deserialized agent has the same model context as the original agent
original_model_context = agent.model_context
deserialized_model_context = deserialized_agent.model_context
assert isinstance(original_model_context, type(deserialized_model_context))
assert isinstance(deserialized_model_context, type(original_model_context))
assert original_model_context.dump_component() == deserialized_model_context.dump_component()
@pytest.mark.parametrize(
"model_context_class",
[
UnboundedChatCompletionContext(),
BufferedChatCompletionContext(buffer_size=5),
TokenLimitedChatCompletionContext(model_client=ReplayChatCompletionClient([]), token_limit=5),
HeadAndTailChatCompletionContext(head_size=3, tail_size=2),
],
)
def test_serialize_and_deserialize_model_context_on_society_of_mind_agent(
model_context_class: ChatCompletionContext,
) -> None:
"""Test the serialization and deserialization of the message context on the AssistantAgent."""
agent1 = AssistantAgent(
name="assistant1", model_client=ReplayChatCompletionClient([]), description="An assistant agent."
)
agent2 = AssistantAgent(
name="assistant2", model_client=ReplayChatCompletionClient([]), description="An assistant agent."
)
team = RoundRobinGroupChat(
participants=[agent1, agent2],
)
agent = SocietyOfMindAgent(
name="assistant",
model_client=ReplayChatCompletionClient([]),
description="An assistant agent.",
team=team,
model_context=model_context_class,
)
# Serialize the agent
serialized_agent = agent.dump_component()
# Deserialize the agent
deserialized_agent = SocietyOfMindAgent.load_component(serialized_agent)
# Check that the deserialized agent has the same model context as the original agent
original_model_context = agent.model_context
deserialized_model_context = deserialized_agent.model_context
assert isinstance(original_model_context, type(deserialized_model_context))
assert isinstance(deserialized_model_context, type(original_model_context))
assert original_model_context.dump_component() == deserialized_model_context.dump_component()
@pytest.mark.parametrize(
"model_context_class",
[
UnboundedChatCompletionContext(),
BufferedChatCompletionContext(buffer_size=5),
TokenLimitedChatCompletionContext(model_client=ReplayChatCompletionClient([]), token_limit=5),
HeadAndTailChatCompletionContext(head_size=3, tail_size=2),
],
)
def test_serialize_and_deserialize_model_context_on_code_executor_agent(
model_context_class: ChatCompletionContext,
) -> None:
"""Test the serialization and deserialization of the message context on the AssistantAgent."""
agent = CodeExecutorAgent(
name="assistant",
code_executor=LocalCommandLineCodeExecutor(),
description="An assistant agent.",
model_context=model_context_class,
)
# Serialize the agent
serialized_agent = agent.dump_component()
# Deserialize the agent
deserialized_agent = CodeExecutorAgent.load_component(serialized_agent)
# Check that the deserialized agent has the same model context as the original agent
original_model_context = agent.model_context
deserialized_model_context = deserialized_agent.model_context
assert isinstance(original_model_context, type(deserialized_model_context))
assert isinstance(deserialized_model_context, type(original_model_context))
assert original_model_context.dump_component() == deserialized_model_context.dump_component()

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,15 @@
import pytest
from autogen_agentchat.agents import CodeExecutorAgent
from autogen_agentchat.base import Response
from autogen_agentchat.messages import TextMessage
from autogen_agentchat.messages import (
CodeExecutionEvent,
CodeGenerationEvent,
TextMessage,
)
from autogen_core import CancellationToken
from autogen_core.models import ModelFamily, ModelInfo
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.models.replay import ReplayChatCompletionClient
@pytest.mark.asyncio
@ -34,6 +40,233 @@ print("%0.3f" % (square_root,))
assert response.chat_message.source == "code_executor"
@pytest.mark.asyncio
async def test_code_generation_and_execution_with_model_client() -> None:
"""
Tests the code generation, execution and reflection pipeline using a model client.
"""
language = "python"
code = 'import math\n\nnumber = 42\nsquare_root = math.sqrt(number)\nprint("%0.3f" % (square_root,))'
model_client = ReplayChatCompletionClient(
[f"Here is the code to calculate the square root of 42:\n```{language}\n{code}```".strip(), "TERMINATE"]
)
agent = CodeExecutorAgent(
name="code_executor_agent", code_executor=LocalCommandLineCodeExecutor(), model_client=model_client
)
messages = [
TextMessage(
content="Generate python code to calculate the square root of 42",
source="assistant",
)
]
code_generation_event: CodeGenerationEvent | None = None
code_execution_event: CodeExecutionEvent | None = None
response: Response | None = None
async for message in agent.on_messages_stream(messages, CancellationToken()):
if isinstance(message, CodeGenerationEvent):
code_block = message.code_blocks[0]
assert code_block.code == code, "Code block does not match"
assert code_block.language == language, "Language does not match"
code_generation_event = message
elif isinstance(message, CodeExecutionEvent):
assert message.to_text().strip() == "6.481", f"Expected '6.481', got: {message.to_text().strip()}"
code_execution_event = message
elif isinstance(message, Response):
assert isinstance(
message.chat_message, TextMessage
), f"Expected TextMessage, got: {type(message.chat_message)}"
assert (
message.chat_message.source == "code_executor_agent"
), f"Expected source 'code_executor_agent', got: {message.chat_message.source}"
response = message
else:
raise AssertionError(f"Unexpected message type: {type(message)}")
assert code_generation_event is not None, "Code generation event was not received"
assert code_execution_event is not None, "Code execution event was not received"
assert response is not None, "Response was not received"
@pytest.mark.asyncio
async def test_no_code_response_with_model_client() -> None:
"""
Tests agent behavior when the model client responds with non-code content.
"""
model_client = ReplayChatCompletionClient(["The capital of France is Paris.", "TERMINATE"])
agent = CodeExecutorAgent(
name="code_executor_agent", code_executor=LocalCommandLineCodeExecutor(), model_client=model_client
)
messages = [
TextMessage(
content="What is the capital of France?",
source="assistant",
)
]
response: Response | None = None
async for message in agent.on_messages_stream(messages, CancellationToken()):
if isinstance(message, Response):
assert isinstance(
message.chat_message, TextMessage
), f"Expected TextMessage, got: {type(message.chat_message)}"
assert (
message.chat_message.source == "code_executor_agent"
), f"Expected source 'code_executor_agent', got: {message.chat_message.source}"
assert (
message.chat_message.content.strip() == "The capital of France is Paris."
), f"Expected 'The capital of France is Paris.', got: {message.chat_message.content.strip()}"
response = message
else:
raise AssertionError(f"Unexpected message type: {type(message)}")
assert response is not None, "Response was not received"
@pytest.mark.asyncio
async def test_self_debugging_loop() -> None:
"""
Tests self debugging loop when the model client responds with incorrect code.
"""
language = "python"
incorrect_code_block = """
numbers = [10, 20, 30, 40, 50]
mean = sum(numbers) / len(numbers
print("The mean is:", mean)
""".strip()
incorrect_code_result = """
mean = sum(numbers) / len(numbers
^
SyntaxError: '(' was never closed
""".strip()
correct_code_block = """
numbers = [10, 20, 30, 40, 50]
mean = sum(numbers) / len(numbers)
print("The mean is:", mean)
""".strip()
correct_code_result = """
The mean is: 30.0
""".strip()
model_client = ReplayChatCompletionClient(
[
f"""
Here is the code to calculate the mean of 10, 20, 30, 40, 50
```{language}
{incorrect_code_block}
```
""",
"""{"retry": "true", "reason": "Retry 1: It is a test environment"}""",
f"""
Here is the updated code to calculate the mean of 10, 20, 30, 40, 50
```{language}
{correct_code_block}
```""",
"Final Response",
"TERMINATE",
],
model_info=ModelInfo(
vision=False,
function_calling=False,
json_output=True,
family=ModelFamily.UNKNOWN,
structured_output=True,
),
)
agent = CodeExecutorAgent(
name="code_executor_agent",
code_executor=LocalCommandLineCodeExecutor(),
model_client=model_client,
max_retries_on_error=1,
)
messages = [
TextMessage(
content="Calculate the mean of 10, 20, 30, 40, 50.",
source="assistant",
)
]
incorrect_code_generation_event: CodeGenerationEvent | None = None
correct_code_generation_event: CodeGenerationEvent | None = None
retry_decision_event: CodeGenerationEvent | None = None
incorrect_code_execution_event: CodeExecutionEvent | None = None
correct_code_execution_event: CodeExecutionEvent | None = None
response: Response | None = None
message_id: int = 0
async for message in agent.on_messages_stream(messages, CancellationToken()):
if isinstance(message, CodeGenerationEvent) and message_id == 0:
# Step 1: First code generation
code_block = message.code_blocks[0]
assert code_block.code.strip() == incorrect_code_block, "Incorrect code block does not match"
assert code_block.language == language, "Language does not match"
incorrect_code_generation_event = message
elif isinstance(message, CodeExecutionEvent) and message_id == 1:
# Step 2: First code execution
assert (
incorrect_code_result in message.to_text().strip()
), f"Expected {incorrect_code_result} in execution result, got: {message.to_text().strip()}"
incorrect_code_execution_event = message
elif isinstance(message, CodeGenerationEvent) and message_id == 2:
# Step 3: Retry generation with proposed correction
retry_response = "Attempt number: 1\nProposed correction: Retry 1: It is a test environment"
assert (
message.to_text().strip() == retry_response
), f"Expected {retry_response}, got: {message.to_text().strip()}"
retry_decision_event = message
elif isinstance(message, CodeGenerationEvent) and message_id == 3:
# Step 4: Second retry code generation
code_block = message.code_blocks[0]
assert code_block.code.strip() == correct_code_block, "Correct code block does not match"
assert code_block.language == language, "Language does not match"
correct_code_generation_event = message
elif isinstance(message, CodeExecutionEvent) and message_id == 4:
# Step 5: Second retry code execution
assert (
message.to_text().strip() == correct_code_result
), f"Expected {correct_code_result} in execution result, got: {message.to_text().strip()}"
correct_code_execution_event = message
elif isinstance(message, Response) and message_id == 5:
# Step 6: Final response
assert isinstance(
message.chat_message, TextMessage
), f"Expected TextMessage, got: {type(message.chat_message)}"
assert (
message.chat_message.source == "code_executor_agent"
), f"Expected source 'code_executor_agent', got: {message.chat_message.source}"
response = message
else:
raise AssertionError(f"Unexpected message type: {type(message)}")
message_id += 1
assert incorrect_code_generation_event is not None, "Incorrect code generation event was not received"
assert incorrect_code_execution_event is not None, "Incorrect code execution event was not received"
assert retry_decision_event is not None, "Retry decision event was not received"
assert correct_code_generation_event is not None, "Correct code generation event was not received"
assert correct_code_execution_event is not None, "Correct code execution event was not received"
assert response is not None, "Response was not received"
@pytest.mark.asyncio
async def test_code_execution_error() -> None:
"""Test basic code execution"""
@ -178,3 +411,22 @@ async def test_code_execution_agent_serialization() -> None:
assert isinstance(deserialized_agent, CodeExecutorAgent)
assert deserialized_agent.name == "code_executor"
@pytest.mark.asyncio
async def test_code_execution_agent_serialization_with_model_client() -> None:
"""Test agent config serialization"""
model_client = ReplayChatCompletionClient(["The capital of France is Paris.", "TERMINATE"])
agent = CodeExecutorAgent(
name="code_executor_agent", code_executor=LocalCommandLineCodeExecutor(), model_client=model_client
)
# Serialize and deserialize the agent
serialized_agent = agent.dump_component()
deserialized_agent = CodeExecutorAgent.load_component(serialized_agent)
assert isinstance(deserialized_agent, CodeExecutorAgent)
assert deserialized_agent.name == "code_executor_agent"
assert deserialized_agent._model_client is not None # type: ignore

View File

@ -2,7 +2,7 @@ import asyncio
import json
import logging
import tempfile
from typing import Any, AsyncGenerator, List, Mapping, Sequence
from typing import Any, AsyncGenerator, Dict, List, Mapping, Sequence
import pytest
import pytest_asyncio
@ -13,12 +13,20 @@ from autogen_agentchat.agents import (
CodeExecutorAgent,
)
from autogen_agentchat.base import Handoff, Response, TaskResult, TerminationCondition
from autogen_agentchat.conditions import HandoffTermination, MaxMessageTermination, TextMentionTermination
from autogen_agentchat.conditions import (
HandoffTermination,
MaxMessageTermination,
StopMessageTermination,
TextMentionTermination,
)
from autogen_agentchat.messages import (
BaseAgentEvent,
BaseChatMessage,
HandoffMessage,
ModelClientStreamingChunkEvent,
MultiModalMessage,
SelectorEvent,
SelectSpeakerEvent,
StopMessage,
StructuredMessage,
TextMessage,
@ -32,6 +40,7 @@ from autogen_agentchat.teams._group_chat._selector_group_chat import SelectorGro
from autogen_agentchat.teams._group_chat._swarm_group_chat import SwarmGroupChatManager
from autogen_agentchat.ui import Console
from autogen_core import AgentId, AgentRuntime, CancellationToken, FunctionCall, SingleThreadedAgentRuntime
from autogen_core.model_context import BufferedChatCompletionContext
from autogen_core.models import (
AssistantMessage,
CreateResult,
@ -46,7 +55,7 @@ from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.models.replay import ReplayChatCompletionClient
from pydantic import BaseModel
from utils import FileLogHandler
from utils import FileLogHandler, compare_messages, compare_task_results
logger = logging.getLogger(EVENT_LOGGER_NAME)
logger.setLevel(logging.DEBUG)
@ -81,6 +90,16 @@ class _EchoAgent(BaseChatAgent):
async def on_reset(self, cancellation_token: CancellationToken) -> None:
self._last_message = None
async def save_state(self) -> Mapping[str, Any]:
return {
"last_message": self._last_message,
"total_messages": self._total_messages,
}
async def load_state(self, state: Mapping[str, Any]) -> None:
self._last_message = state.get("last_message")
self._total_messages = state.get("total_messages", 0)
class _FlakyAgent(BaseChatAgent):
def __init__(self, name: str, description: str) -> None:
@ -242,39 +261,210 @@ async def test_round_robin_group_chat(runtime: AgentRuntime | None) -> None:
assert result.stop_reason is not None and result.stop_reason == "Text 'TERMINATE' mentioned"
# Test streaming.
# Test streaming with default output_task_messages=True.
model_client.reset()
index = 0
await team.reset()
streamed_messages: List[BaseAgentEvent | BaseChatMessage] = []
final_stream_result: TaskResult | None = None
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
):
if isinstance(message, TaskResult):
assert message == result
final_stream_result = message
else:
assert message == result.messages[index]
index += 1
streamed_messages.append(message)
assert final_stream_result is not None
assert compare_task_results(final_stream_result, result)
# Verify streamed messages match the complete result.messages
assert len(streamed_messages) == len(result.messages)
for streamed_msg, expected_msg in zip(streamed_messages, result.messages, strict=False):
assert compare_messages(streamed_msg, expected_msg)
# Test message input.
# Text message.
model_client.reset()
index = 0
await team.reset()
result_2 = await team.run(
task=TextMessage(content="Write a program that prints 'Hello, world!'", source="user")
)
assert result == result_2
assert compare_task_results(result, result_2)
# Test multi-modal message.
model_client.reset()
index = 0
await team.reset()
task = MultiModalMessage(content=["Write a program that prints 'Hello, world!'"], source="user")
result_2 = await team.run(task=task)
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result_2.messages[0], MultiModalMessage)
assert result.messages[0].content == task.content[0]
assert result.messages[1:] == result_2.messages[1:]
assert len(result.messages[1:]) == len(result_2.messages[1:])
for i in range(1, len(result.messages)):
assert compare_messages(result.messages[i], result_2.messages[i])
@pytest.mark.asyncio
async def test_round_robin_group_chat_output_task_messages_false(runtime: AgentRuntime | None) -> None:
model_client = ReplayChatCompletionClient(
[
'Here is the program\n ```python\nprint("Hello, world!")\n```',
"TERMINATE",
],
)
with tempfile.TemporaryDirectory() as temp_dir:
code_executor_agent = CodeExecutorAgent(
"code_executor", code_executor=LocalCommandLineCodeExecutor(work_dir=temp_dir)
)
coding_assistant_agent = AssistantAgent(
"coding_assistant",
model_client=model_client,
)
termination = TextMentionTermination("TERMINATE")
team = RoundRobinGroupChat(
participants=[coding_assistant_agent, code_executor_agent],
termination_condition=termination,
runtime=runtime,
)
result = await team.run(
task="Write a program that prints 'Hello, world!'",
output_task_messages=False,
)
expected_messages = [
'Here is the program\n ```python\nprint("Hello, world!")\n```',
"Hello, world!",
"TERMINATE",
]
for i in range(len(expected_messages)):
produced_message = result.messages[i]
assert isinstance(produced_message, TextMessage)
content = produced_message.content.replace("\r\n", "\n").rstrip("\n")
assert content == expected_messages[i]
assert result.stop_reason is not None and result.stop_reason == "Text 'TERMINATE' mentioned"
# Test streaming with output_task_messages=False.
model_client.reset()
await team.reset()
streamed_messages: List[BaseAgentEvent | BaseChatMessage] = []
final_stream_result: TaskResult | None = None
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
output_task_messages=False,
):
if isinstance(message, TaskResult):
final_stream_result = message
else:
streamed_messages.append(message)
assert final_stream_result is not None
assert compare_task_results(final_stream_result, result)
# Verify streamed messages match the complete result.messages excluding the first task message
assert len(streamed_messages) == len(result.messages) # Exclude task message
for streamed_msg, expected_msg in zip(streamed_messages, result.messages, strict=False):
assert compare_messages(streamed_msg, expected_msg)
# Test message input with output_task_messages=False.
# Text message.
model_client.reset()
await team.reset()
streamed_messages_2: List[BaseAgentEvent | BaseChatMessage] = []
final_stream_result_2: TaskResult | None = None
async for message in team.run_stream(
task=TextMessage(content="Write a program that prints 'Hello, world!'", source="user"),
output_task_messages=False,
):
if isinstance(message, TaskResult):
final_stream_result_2 = message
else:
streamed_messages_2.append(message)
assert final_stream_result_2 is not None
assert compare_task_results(final_stream_result_2, result)
# Verify streamed messages match the complete result.messages excluding the first task message
assert len(streamed_messages_2) == len(result.messages)
for streamed_msg, expected_msg in zip(streamed_messages_2, result.messages, strict=False):
assert compare_messages(streamed_msg, expected_msg)
# Test multi-modal message with output_task_messages=False.
model_client.reset()
await team.reset()
task = MultiModalMessage(content=["Write a program that prints 'Hello, world!'"], source="user")
streamed_messages_3: List[BaseAgentEvent | BaseChatMessage] = []
final_stream_result_3: TaskResult | None = None
async for message in team.run_stream(task=task, output_task_messages=False):
if isinstance(message, TaskResult):
final_stream_result_3 = message
else:
streamed_messages_3.append(message)
assert final_stream_result_3 is not None
# Verify streamed messages exclude the task message
assert len(streamed_messages_3) == len(final_stream_result_3.messages)
for streamed_msg, expected_msg in zip(streamed_messages_3, final_stream_result_3.messages, strict=False):
assert compare_messages(streamed_msg, expected_msg)
@pytest.mark.asyncio
async def test_round_robin_group_chat_with_team_event(runtime: AgentRuntime | None) -> None:
model_client = ReplayChatCompletionClient(
[
'Here is the program\n ```python\nprint("Hello, world!")\n```',
"TERMINATE",
],
)
with tempfile.TemporaryDirectory() as temp_dir:
code_executor_agent = CodeExecutorAgent(
"code_executor", code_executor=LocalCommandLineCodeExecutor(work_dir=temp_dir)
)
coding_assistant_agent = AssistantAgent(
"coding_assistant",
model_client=model_client,
)
termination = TextMentionTermination("TERMINATE")
team = RoundRobinGroupChat(
participants=[coding_assistant_agent, code_executor_agent],
termination_condition=termination,
runtime=runtime,
emit_team_events=True,
)
result = await team.run(
task="Write a program that prints 'Hello, world!'",
)
assert len(result.messages) == 7
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result.messages[1], SelectSpeakerEvent)
assert isinstance(result.messages[2], TextMessage)
assert isinstance(result.messages[3], SelectSpeakerEvent)
assert isinstance(result.messages[4], TextMessage)
assert isinstance(result.messages[5], SelectSpeakerEvent)
assert isinstance(result.messages[6], TextMessage)
# Test streaming with default output_task_messages=True.
model_client.reset()
await team.reset()
streamed_messages: List[BaseAgentEvent | BaseChatMessage] = []
final_stream_result: TaskResult | None = None
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
):
if isinstance(message, TaskResult):
final_stream_result = message
else:
streamed_messages.append(message)
assert final_stream_result is not None
assert compare_task_results(final_stream_result, result)
# Verify streamed messages match the complete result.messages
assert len(streamed_messages) == len(result.messages)
for streamed_msg, expected_msg in zip(streamed_messages, result.messages, strict=False):
assert compare_messages(streamed_msg, expected_msg)
# Test multi-modal message.
model_client.reset()
await team.reset()
task = MultiModalMessage(content=["Write a program that prints 'Hello, world!'"], source="user")
result_2 = await team.run(task=task)
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result_2.messages[0], MultiModalMessage)
assert result.messages[0].content == task.content[0]
assert len(result.messages[1:]) == len(result_2.messages[1:])
for i in range(1, len(result.messages)):
assert compare_messages(result.messages[i], result_2.messages[i])
@pytest.mark.asyncio
@ -388,7 +578,7 @@ async def test_round_robin_group_chat_with_tools(runtime: AgentRuntime | None) -
"TERMINATE",
],
model_info={
"family": "gpt-4o",
"family": "gpt-4.1-nano",
"function_calling": True,
"json_output": True,
"vision": True,
@ -422,24 +612,23 @@ async def test_round_robin_group_chat_with_tools(runtime: AgentRuntime | None) -
# Test streaming.
await tool_use_agent._model_context.clear() # pyright: ignore
model_client.reset()
index = 0
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
):
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test Console.
await tool_use_agent._model_context.clear() # pyright: ignore
model_client.reset()
index = 0
await team.reset()
result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'"))
assert result2 == result
assert compare_task_results(result2, result)
@pytest.mark.asyncio
@ -611,24 +800,136 @@ async def test_selector_group_chat(runtime: AgentRuntime | None) -> None:
# Test streaming.
model_client.reset()
agent1._count = 0 # pyright: ignore
index = 0
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
):
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test Console.
model_client.reset()
agent1._count = 0 # pyright: ignore
index = 0
await team.reset()
result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'"))
assert result2 == result
assert compare_task_results(result2, result)
@pytest.mark.asyncio
async def test_selector_group_chat_with_model_context(runtime: AgentRuntime | None) -> None:
buffered_context = BufferedChatCompletionContext(buffer_size=5)
await buffered_context.add_message(UserMessage(content="[User] Prefilled message", source="user"))
selector_group_chat_model_client = ReplayChatCompletionClient(
["agent2", "agent1", "agent1", "agent2", "agent1", "agent2", "agent1"]
)
agent_one_model_client = ReplayChatCompletionClient(
["[Agent One] First generation", "[Agent One] Second generation", "[Agent One] Third generation", "TERMINATE"]
)
agent_two_model_client = ReplayChatCompletionClient(
["[Agent Two] First generation", "[Agent Two] Second generation", "[Agent Two] Third generation"]
)
agent1 = AssistantAgent("agent1", model_client=agent_one_model_client, description="Assistant agent 1")
agent2 = AssistantAgent("agent2", model_client=agent_two_model_client, description="Assistant agent 2")
termination = TextMentionTermination("TERMINATE")
team = SelectorGroupChat(
participants=[agent1, agent2],
model_client=selector_group_chat_model_client,
termination_condition=termination,
runtime=runtime,
emit_team_events=True,
allow_repeated_speaker=True,
model_context=buffered_context,
)
await team.run(
task="[GroupChat] Task",
)
messages_to_check = [
"user: [User] Prefilled message",
"user: [GroupChat] Task",
"agent2: [Agent Two] First generation",
"agent1: [Agent One] First generation",
"agent1: [Agent One] Second generation",
"agent2: [Agent Two] Second generation",
"agent1: [Agent One] Third generation",
"agent2: [Agent Two] Third generation",
]
create_calls: List[Dict[str, Any]] = selector_group_chat_model_client.create_calls
for idx, call in enumerate(create_calls):
messages = call["messages"]
prompt = messages[0].content
prompt_lines = prompt.split("\n")
chat_history = [value for value in messages_to_check[max(0, idx - 3) : idx + 2]]
assert all(
line.strip() in prompt_lines for line in chat_history
), f"Expected all lines {chat_history} to be in prompt, but got {prompt_lines}"
@pytest.mark.asyncio
async def test_selector_group_chat_with_team_event(runtime: AgentRuntime | None) -> None:
model_client = ReplayChatCompletionClient(
["agent3", "agent2", "agent1", "agent2", "agent1"],
)
agent1 = _StopAgent("agent1", description="echo agent 1", stop_at=2)
agent2 = _EchoAgent("agent2", description="echo agent 2")
agent3 = _EchoAgent("agent3", description="echo agent 3")
termination = TextMentionTermination("TERMINATE")
team = SelectorGroupChat(
participants=[agent1, agent2, agent3],
model_client=model_client,
termination_condition=termination,
runtime=runtime,
emit_team_events=True,
)
result = await team.run(
task="Write a program that prints 'Hello, world!'",
)
assert len(result.messages) == 11
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result.messages[1], SelectSpeakerEvent)
assert isinstance(result.messages[2], TextMessage)
assert isinstance(result.messages[3], SelectSpeakerEvent)
assert isinstance(result.messages[4], TextMessage)
assert isinstance(result.messages[5], SelectSpeakerEvent)
assert isinstance(result.messages[6], TextMessage)
assert isinstance(result.messages[7], SelectSpeakerEvent)
assert isinstance(result.messages[8], TextMessage)
assert isinstance(result.messages[9], SelectSpeakerEvent)
assert isinstance(result.messages[10], StopMessage)
assert result.messages[0].content == "Write a program that prints 'Hello, world!'"
assert result.messages[1].content == ["agent3"]
assert result.messages[2].source == "agent3"
assert result.messages[3].content == ["agent2"]
assert result.messages[4].source == "agent2"
assert result.messages[5].content == ["agent1"]
assert result.messages[6].source == "agent1"
assert result.messages[7].content == ["agent2"]
assert result.messages[8].source == "agent2"
assert result.messages[9].content == ["agent1"]
assert result.messages[10].source == "agent1"
assert result.stop_reason is not None and result.stop_reason == "Text 'TERMINATE' mentioned"
# Test streaming.
model_client.reset()
agent1._count = 0 # pyright: ignore
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
):
if isinstance(message, TaskResult):
assert compare_task_results(message, result)
else:
assert compare_messages(message, result.messages[result_index])
result_index += 1
@pytest.mark.asyncio
@ -725,22 +1026,21 @@ async def test_selector_group_chat_two_speakers(runtime: AgentRuntime | None) ->
# Test streaming.
model_client.reset()
agent1._count = 0 # pyright: ignore
index = 0
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
async for message in team.run_stream(task="Write a program that prints 'Hello, world!'"):
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test Console.
model_client.reset()
agent1._count = 0 # pyright: ignore
index = 0
await team.reset()
result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'"))
assert result2 == result
assert compare_task_results(result2, result)
@pytest.mark.asyncio
@ -773,21 +1073,20 @@ async def test_selector_group_chat_two_speakers_allow_repeated(runtime: AgentRun
# Test streaming.
model_client.reset()
index = 0
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
async for message in team.run_stream(task="Write a program that prints 'Hello, world!'"):
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test Console.
model_client.reset()
index = 0
await team.reset()
result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'"))
assert result2 == result
assert compare_task_results(result2, result)
@pytest.mark.asyncio
@ -988,15 +1287,15 @@ async def test_swarm_handoff(runtime: AgentRuntime | None) -> None:
)
# Test streaming.
index = 0
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
stream = team.run_stream(task="task")
async for message in stream:
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test save and load.
state = await team.save_state()
@ -1019,6 +1318,60 @@ async def test_swarm_handoff(runtime: AgentRuntime | None) -> None:
assert manager_1._current_speaker == manager_2._current_speaker # pyright: ignore
@pytest.mark.asyncio
async def test_swarm_handoff_with_team_events(runtime: AgentRuntime | None) -> None:
first_agent = _HandOffAgent("first_agent", description="first agent", next_agent="second_agent")
second_agent = _HandOffAgent("second_agent", description="second agent", next_agent="third_agent")
third_agent = _HandOffAgent("third_agent", description="third agent", next_agent="first_agent")
termination = MaxMessageTermination(6)
team = Swarm(
[second_agent, first_agent, third_agent],
termination_condition=termination,
runtime=runtime,
emit_team_events=True,
)
result = await team.run(task="task")
assert len(result.messages) == 11
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result.messages[1], SelectSpeakerEvent)
assert isinstance(result.messages[2], HandoffMessage)
assert isinstance(result.messages[3], SelectSpeakerEvent)
assert isinstance(result.messages[4], HandoffMessage)
assert isinstance(result.messages[5], SelectSpeakerEvent)
assert isinstance(result.messages[6], HandoffMessage)
assert isinstance(result.messages[7], SelectSpeakerEvent)
assert isinstance(result.messages[8], HandoffMessage)
assert isinstance(result.messages[9], SelectSpeakerEvent)
assert isinstance(result.messages[10], HandoffMessage)
assert result.messages[0].content == "task"
assert result.messages[1].content == ["second_agent"]
assert result.messages[2].content == "Transferred to third_agent."
assert result.messages[3].content == ["third_agent"]
assert result.messages[4].content == "Transferred to first_agent."
assert result.messages[5].content == ["first_agent"]
assert result.messages[6].content == "Transferred to second_agent."
assert result.messages[7].content == ["second_agent"]
assert result.messages[8].content == "Transferred to third_agent."
assert result.messages[9].content == ["third_agent"]
assert result.messages[10].content == "Transferred to first_agent."
assert (
result.stop_reason is not None
and result.stop_reason == "Maximum number of messages 6 reached, current message count: 6"
)
# Test streaming.
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
stream = team.run_stream(task="task")
async for message in stream:
if isinstance(message, TaskResult):
assert compare_task_results(message, result)
else:
assert compare_messages(message, result.messages[result_index])
result_index += 1
@pytest.mark.asyncio
@pytest.mark.parametrize(
"task",
@ -1092,7 +1445,7 @@ async def test_swarm_handoff_using_tool_calls(runtime: AgentRuntime | None) -> N
"TERMINATE",
],
model_info={
"family": "gpt-4o",
"family": "gpt-4.1-nano",
"function_calling": True,
"json_output": True,
"vision": True,
@ -1126,23 +1479,22 @@ async def test_swarm_handoff_using_tool_calls(runtime: AgentRuntime | None) -> N
# Test streaming.
await agent1._model_context.clear() # pyright: ignore
model_client.reset()
index = 0
result_index = 0 # Include task message in result since output_task_messages=True by default
await team.reset()
stream = team.run_stream(task="task")
async for message in stream:
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test Console
await agent1._model_context.clear() # pyright: ignore
model_client.reset()
index = 0
await team.reset()
result2 = await Console(team.run_stream(task="task"))
assert result2 == result
assert compare_task_results(result2, result)
@pytest.mark.asyncio
@ -1192,7 +1544,7 @@ async def test_swarm_with_parallel_tool_calls(runtime: AgentRuntime | None) -> N
"TERMINATE",
],
model_info={
"family": "gpt-4o",
"family": "gpt-4.1-nano",
"function_calling": True,
"json_output": True,
"vision": True,
@ -1236,14 +1588,17 @@ async def test_swarm_with_parallel_tool_calls(runtime: AgentRuntime | None) -> N
team = Swarm([agent1, agent2], termination_condition=termination, runtime=runtime)
result = await team.run(task="task")
assert len(result.messages) == 6
assert result.messages[0] == TextMessage(content="task", source="user")
assert compare_messages(result.messages[0], TextMessage(content="task", source="user"))
assert isinstance(result.messages[1], ToolCallRequestEvent)
assert isinstance(result.messages[2], ToolCallExecutionEvent)
assert result.messages[3] == HandoffMessage(
content="handoff to agent2",
target="agent2",
source="agent1",
context=expected_handoff_context,
assert compare_messages(
result.messages[3],
HandoffMessage(
content="handoff to agent2",
target="agent2",
source="agent1",
context=expected_handoff_context,
),
)
assert isinstance(result.messages[4], TextMessage)
assert result.messages[4].content == "Hello"
@ -1360,13 +1715,13 @@ async def test_round_robin_group_chat_with_message_list(runtime: AgentRuntime |
# Test with streaming
await team.reset()
index = 0
result_index = 0 # Include the 3 task messages in result since output_task_messages=True by default
async for message in team.run_stream(task=messages):
if isinstance(message, TaskResult):
assert message == result
assert compare_task_results(message, result)
else:
assert message == result.messages[index]
index += 1
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Test with invalid message list
with pytest.raises(ValueError, match="All messages in task list must be valid BaseChatMessage types"):
@ -1382,12 +1737,14 @@ async def test_declarative_groupchats_with_config(runtime: AgentRuntime | None)
# Create basic agents and components for testing
agent1 = AssistantAgent(
"agent_1",
model_client=OpenAIChatCompletionClient(model="gpt-4o-2024-05-13", api_key=""),
model_client=OpenAIChatCompletionClient(model="gpt-4.1-nano-2025-04-14", api_key=""),
handoffs=["agent_2"],
)
agent2 = AssistantAgent("agent_2", model_client=OpenAIChatCompletionClient(model="gpt-4o-2024-05-13", api_key=""))
agent2 = AssistantAgent(
"agent_2", model_client=OpenAIChatCompletionClient(model="gpt-4.1-nano-2025-04-14", api_key="")
)
termination = MaxMessageTermination(4)
model_client = OpenAIChatCompletionClient(model="gpt-4o-2024-05-13", api_key="")
model_client = OpenAIChatCompletionClient(model="gpt-4.1-nano-2025-04-14", api_key="")
# Test round robin - verify config is preserved
round_robin = RoundRobinGroupChat(participants=[agent1, agent2], termination_condition=termination, max_turns=5)
@ -1441,3 +1798,149 @@ async def test_declarative_groupchats_with_config(runtime: AgentRuntime | None)
assert selector.dump_component().provider == "autogen_agentchat.teams.SelectorGroupChat"
assert swarm.dump_component().provider == "autogen_agentchat.teams.Swarm"
assert magentic.dump_component().provider == "autogen_agentchat.teams.MagenticOneGroupChat"
class _StructuredContent(BaseModel):
message: str
class _StructuredAgent(BaseChatAgent):
def __init__(self, name: str, description: str) -> None:
super().__init__(name, description)
self._message = _StructuredContent(message="Structured hello")
@property
def produced_message_types(self) -> Sequence[type[BaseChatMessage]]:
return (StructuredMessage[_StructuredContent],)
async def on_messages(self, messages: Sequence[BaseChatMessage], cancellation_token: CancellationToken) -> Response:
return Response(
chat_message=StructuredMessage[_StructuredContent](
source=self.name,
content=self._message,
format_string="Structured says: {message}",
)
)
async def on_reset(self, cancellation_token: CancellationToken) -> None:
pass
@pytest.mark.asyncio
async def test_message_type_auto_registration(runtime: AgentRuntime | None) -> None:
agent1 = _StructuredAgent("structured", description="emits structured messages")
agent2 = _EchoAgent("echo", description="echoes input")
team = RoundRobinGroupChat(participants=[agent1, agent2], max_turns=2, runtime=runtime)
result = await team.run(task="Say something structured")
assert len(result.messages) == 3
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result.messages[1], StructuredMessage)
assert isinstance(result.messages[2], TextMessage)
assert result.messages[1].to_text() == "Structured says: Structured hello"
@pytest.mark.asyncio
async def test_structured_message_state_roundtrip(runtime: AgentRuntime | None) -> None:
agent1 = _StructuredAgent("structured", description="sends structured")
agent2 = _EchoAgent("echo", description="echoes")
team1 = RoundRobinGroupChat(
participants=[agent1, agent2],
termination_condition=MaxMessageTermination(2),
runtime=runtime,
)
await team1.run(task="Say something structured")
state1 = await team1.save_state()
# Recreate team without needing custom_message_types
agent3 = _StructuredAgent("structured", description="sends structured")
agent4 = _EchoAgent("echo", description="echoes")
team2 = RoundRobinGroupChat(
participants=[agent3, agent4],
termination_condition=MaxMessageTermination(2),
runtime=runtime,
)
await team2.load_state(state1)
state2 = await team2.save_state()
# Assert full state equality
assert state1 == state2
# Assert message thread content match
manager1 = await team1._runtime.try_get_underlying_agent_instance( # pyright: ignore
AgentId(f"{team1._group_chat_manager_name}_{team1._team_id}", team1._team_id), # pyright: ignore
RoundRobinGroupChatManager,
)
manager2 = await team2._runtime.try_get_underlying_agent_instance( # pyright: ignore
AgentId(f"{team2._group_chat_manager_name}_{team2._team_id}", team2._team_id), # pyright: ignore
RoundRobinGroupChatManager,
)
assert manager1._message_thread == manager2._message_thread # pyright: ignore
@pytest.mark.asyncio
async def test_selector_group_chat_streaming(runtime: AgentRuntime | None) -> None:
model_client = ReplayChatCompletionClient(
["the agent should be agent2"],
)
agent2 = _StopAgent("agent2", description="stop agent 2", stop_at=0)
agent3 = _EchoAgent("agent3", description="echo agent 3")
termination = StopMessageTermination()
team = SelectorGroupChat(
participants=[agent2, agent3],
model_client=model_client,
termination_condition=termination,
runtime=runtime,
emit_team_events=True,
model_client_streaming=True,
)
result = await team.run(
task="Write a program that prints 'Hello, world!'",
)
assert len(result.messages) == 4
assert isinstance(result.messages[0], TextMessage)
assert isinstance(result.messages[1], SelectorEvent)
assert isinstance(result.messages[2], SelectSpeakerEvent)
assert isinstance(result.messages[3], StopMessage)
assert result.messages[0].content == "Write a program that prints 'Hello, world!'"
assert result.messages[1].content == "the agent should be agent2"
assert result.messages[2].content == ["agent2"]
assert result.messages[3].source == "agent2"
assert result.stop_reason is not None and result.stop_reason == "Stop message received"
# Test streaming
await team.reset()
model_client.reset()
result_index = 0 # Include task message in result since output_task_messages=True by default
streamed_chunks: List[str] = []
final_result: TaskResult | None = None
async for message in team.run_stream(
task="Write a program that prints 'Hello, world!'",
):
if isinstance(message, TaskResult):
final_result = message
assert compare_task_results(message, result)
elif isinstance(message, ModelClientStreamingChunkEvent):
streamed_chunks.append(message.content)
else:
if streamed_chunks:
assert isinstance(message, SelectorEvent)
assert message.content == "".join(streamed_chunks)
streamed_chunks = []
assert compare_messages(message, result.messages[result_index])
result_index += 1
# Verify we got the expected messages without relying on fragile ordering
assert final_result is not None
assert len(streamed_chunks) == 0 # All chunks should have been processed
# Content-based verification instead of index-based
# Note: The streaming test verifies the streaming behavior, not the final result content

View File

@ -98,7 +98,7 @@ async def test_selector_group_chat_openai() -> None:
pytest.skip("OPENAI_API_KEY not set in environment variables.")
model_client = OpenAIChatCompletionClient(
model="gpt-4o-mini",
model="gpt-4.1-nano",
api_key=api_key,
)
await _test_selector_group_chat(model_client)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import json
import uuid
from typing import List
import pytest
@ -11,6 +12,7 @@ from autogen_agentchat.messages import (
MultiModalMessage,
StopMessage,
StructuredMessage,
StructuredMessageFactory,
TextMessage,
ToolCallExecutionEvent,
ToolCallRequestEvent,
@ -52,6 +54,28 @@ def test_structured_message() -> None:
assert dumped_message["type"] == "StructuredMessage[TestContent]"
def test_structured_message_component() -> None:
# Create a structured message with the test content
format_string = "this is a string {field1} and this is an int {field2}"
s_m = StructuredMessageFactory(input_model=TestContent, format_string=format_string)
config = s_m.dump_component()
s_m_dyn = StructuredMessageFactory.load_component(config)
message = s_m_dyn.StructuredMessage(
source="test_agent", content=s_m_dyn.ContentModel(field1="test", field2=42), format_string=s_m_dyn.format_string
)
assert isinstance(message.content, s_m_dyn.ContentModel)
assert not isinstance(message.content, TestContent)
assert message.content.field1 == "test" # type: ignore[attr-defined]
assert message.content.field2 == 42 # type: ignore[attr-defined]
dumped_message = message.model_dump()
assert dumped_message["source"] == "test_agent"
assert dumped_message["content"]["field1"] == "test"
assert dumped_message["content"]["field2"] == 42
assert message.to_model_text() == format_string.format(field1="test", field2=42)
def test_message_factory() -> None:
factory = MessageFactory()
@ -109,6 +133,22 @@ def test_message_factory() -> None:
assert structured_message.content.field2 == 42
assert structured_message.type == "StructuredMessage[TestContent]" # type: ignore[comparison-overlap]
sm_factory = StructuredMessageFactory(input_model=TestContent, format_string=None, content_model_name="TestContent")
config = sm_factory.dump_component()
config.config["content_model_name"] = "DynamicTestContent"
sm_factory_dynamic = StructuredMessageFactory.load_component(config)
factory.register(sm_factory_dynamic.StructuredMessage)
msg = sm_factory_dynamic.StructuredMessage(
content=sm_factory_dynamic.ContentModel(field1="static", field2=123), source="static_agent"
)
restored = factory.create(msg.dump())
assert isinstance(restored, StructuredMessage)
assert isinstance(restored.content, sm_factory_dynamic.ContentModel) # type: ignore[reportUnkownMemberType]
assert restored.source == "static_agent"
assert restored.content.field1 == "static" # type: ignore[attr-defined]
assert restored.content.field2 == 123 # type: ignore[attr-defined]
class TestContainer(BaseModel):
chat_messages: List[ChatMessage]
@ -148,3 +188,114 @@ def test_union_types() -> None:
loaded_container = TestContainer.model_validate(data)
assert loaded_container.chat_messages == chat_messages
assert loaded_container.agent_events == agent_events
def test_message_id_field() -> None:
"""Test that messages have unique ID fields automatically generated."""
# Test BaseChatMessage subclass (TextMessage)
message1 = TextMessage(source="test_agent", content="Hello, world!")
message2 = TextMessage(source="test_agent", content="Hello, world!")
# Check that IDs are present and unique
assert hasattr(message1, "id")
assert hasattr(message2, "id")
assert message1.id != message2.id
assert isinstance(message1.id, str)
assert isinstance(message2.id, str)
# Check that IDs are valid UUIDs
try:
uuid.UUID(message1.id)
uuid.UUID(message2.id)
except ValueError:
pytest.fail("Generated IDs are not valid UUIDs")
# Test BaseAgentEvent subclass (ModelClientStreamingChunkEvent)
event1 = ModelClientStreamingChunkEvent(source="test_agent", content="chunk1")
event2 = ModelClientStreamingChunkEvent(source="test_agent", content="chunk2")
# Check that IDs are present and unique
assert hasattr(event1, "id")
assert hasattr(event2, "id")
assert event1.id != event2.id
assert isinstance(event1.id, str)
assert isinstance(event2.id, str)
# Check that IDs are valid UUIDs
try:
uuid.UUID(event1.id)
uuid.UUID(event2.id)
except ValueError:
pytest.fail("Generated IDs are not valid UUIDs")
def test_custom_message_id() -> None:
"""Test that custom IDs can be provided."""
custom_id = "custom-message-id-123"
message = TextMessage(id=custom_id, source="test_agent", content="Hello, world!")
assert message.id == custom_id
custom_event_id = "custom-event-id-456"
event = ModelClientStreamingChunkEvent(id=custom_event_id, source="test_agent", content="chunk")
assert event.id == custom_event_id
def test_streaming_chunk_full_message_id() -> None:
"""Test the full_message_id field in ModelClientStreamingChunkEvent."""
# Test without full_message_id
chunk1 = ModelClientStreamingChunkEvent(source="test_agent", content="chunk1")
assert chunk1.full_message_id is None
# Test with full_message_id
full_msg_id = "full-message-123"
chunk2 = ModelClientStreamingChunkEvent(source="test_agent", content="chunk2", full_message_id=full_msg_id)
assert chunk2.full_message_id == full_msg_id
# Test that chunk has its own ID separate from full_message_id
assert chunk2.id != chunk2.full_message_id
assert isinstance(chunk2.id, str)
# Verify chunk ID is a valid UUID
try:
uuid.UUID(chunk2.id)
except ValueError:
pytest.fail("Chunk ID is not a valid UUID")
def test_message_serialization_with_id() -> None:
"""Test that messages with IDs serialize and deserialize correctly."""
# Create a message with auto-generated ID
original_message = TextMessage(source="test_agent", content="Hello, world!")
original_id = original_message.id
# Serialize to dict
message_data = original_message.model_dump()
assert "id" in message_data
assert message_data["id"] == original_id
# Deserialize from dict
restored_message = TextMessage.model_validate(message_data)
assert restored_message.id == original_id
assert restored_message.source == "test_agent"
assert restored_message.content == "Hello, world!"
# Test with streaming chunk event
original_chunk = ModelClientStreamingChunkEvent(
source="test_agent", content="chunk", full_message_id="full-msg-123"
)
original_chunk_id = original_chunk.id
# Serialize to dict
chunk_data = original_chunk.model_dump()
assert "id" in chunk_data
assert "full_message_id" in chunk_data
assert chunk_data["id"] == original_chunk_id
assert chunk_data["full_message_id"] == "full-msg-123"
# Deserialize from dict
restored_chunk = ModelClientStreamingChunkEvent.model_validate(chunk_data)
assert restored_chunk.id == original_chunk_id
assert restored_chunk.full_message_id == "full-msg-123"
assert restored_chunk.content == "chunk"

View File

@ -1,11 +1,15 @@
from typing import AsyncGenerator
from types import MethodType
from typing import Any, AsyncGenerator, List, Sequence
import pytest
import pytest_asyncio
from autogen_agentchat.agents import AssistantAgent, SocietyOfMindAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.base import TaskResult
from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination
from autogen_agentchat.messages import BaseAgentEvent, BaseChatMessage, TextMessage
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_core import AgentRuntime, SingleThreadedAgentRuntime
from autogen_core.models import CreateResult, LLMMessage, SystemMessage
from autogen_ext.models.replay import ReplayChatCompletionClient
@ -57,6 +61,82 @@ async def test_society_of_mind_agent(runtime: AgentRuntime | None) -> None:
assert loaded_soc_agent.name == "society_of_mind"
@pytest.mark.asyncio
async def test_society_of_mind_agent_output_task_messages_parameter(runtime: AgentRuntime | None) -> None:
"""Test that output_task_messages parameter controls whether task messages are included in the stream."""
model_client = ReplayChatCompletionClient(
["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
)
agent1 = AssistantAgent("assistant1", model_client=model_client, system_message="You are a helpful assistant.")
agent2 = AssistantAgent("assistant2", model_client=model_client, system_message="You are a helpful assistant.")
inner_termination = MaxMessageTermination(2) # Reduce to 2 to use fewer responses
inner_team = RoundRobinGroupChat([agent1, agent2], termination_condition=inner_termination, runtime=runtime)
# Test 1: Test team with output_task_messages=True (default behavior)
messages_with_task: List[BaseAgentEvent | BaseChatMessage] = []
async for message in inner_team.run_stream(task="Count to 10", output_task_messages=True):
if not isinstance(message, TaskResult):
messages_with_task.append(message)
# Should include the task message
assert len(messages_with_task) >= 1
assert any(
isinstance(msg, TextMessage) and msg.source == "user" and "Count to 10" in msg.content
for msg in messages_with_task
)
# Reset team before next test
await inner_team.reset()
# Test 2: Test team with output_task_messages=False
messages_without_task: List[BaseAgentEvent | BaseChatMessage] = []
async for message in inner_team.run_stream(task="Count to 10", output_task_messages=False):
if not isinstance(message, TaskResult):
messages_without_task.append(message)
# Should NOT include the task message in the stream
assert not any(
isinstance(msg, TextMessage) and msg.source == "user" and "Count to 10" in msg.content
for msg in messages_without_task
)
# Reset team before next test
await inner_team.reset()
# Test 3: Test SocietyOfMindAgent uses output_task_messages=False internally
# Create a separate model client for SocietyOfMindAgent to ensure we have enough responses
soma_model_client = ReplayChatCompletionClient(
["Final response from society of mind"],
)
society_of_mind_agent = SocietyOfMindAgent("society_of_mind", team=inner_team, model_client=soma_model_client)
# Collect all messages from the SocietyOfMindAgent stream
soma_messages: List[BaseAgentEvent | BaseChatMessage] = []
async for message in society_of_mind_agent.run_stream(task="Count to 10"):
if not isinstance(message, TaskResult):
soma_messages.append(message)
# The SocietyOfMindAgent should output the task message (since it's the outer agent)
# but should NOT forward the task messages from its inner team
task_messages_in_soma = [msg for msg in soma_messages if isinstance(msg, TextMessage) and msg.source == "user"]
# Count how many times "Count to 10" appears in the stream
# With proper implementation, it should appear exactly once (from outer level only)
count_task_messages = sum(
1
for msg in soma_messages
if isinstance(msg, TextMessage) and msg.source == "user" and "Count to 10" in msg.content
)
# Should have exactly one task message (from the outer level only)
assert len(task_messages_in_soma) == 1
assert count_task_messages == 1 # Should appear exactly once, not duplicated from inner team
# Should have the SocietyOfMindAgent's final response
soma_responses = [msg for msg in soma_messages if isinstance(msg, TextMessage) and msg.source == "society_of_mind"]
assert len(soma_responses) == 1
@pytest.mark.asyncio
async def test_society_of_mind_agent_empty_messges(runtime: AgentRuntime | None) -> None:
model_client = ReplayChatCompletionClient(
@ -113,3 +193,129 @@ async def test_society_of_mind_agent_multiple_rounds(runtime: AgentRuntime | Non
response = await society_of_mind_agent.run()
assert len(response.messages) == 1
assert response.messages[0].source == "society_of_mind"
@pytest.mark.asyncio
async def test_society_of_mind_agent_no_multiple_system_messages(
monkeypatch: pytest.MonkeyPatch, runtime: AgentRuntime | None
) -> None:
model_client = ReplayChatCompletionClient(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"])
model_client_soma = ReplayChatCompletionClient(
["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
model_info={
"vision": False,
"function_calling": False,
"json_output": False,
"family": "unknown",
"structured_output": False,
"multiple_system_messages": False,
},
)
original_create = model_client_soma.create
# mock method with bound self
async def _mock_create(
self: ReplayChatCompletionClient, messages: Sequence[LLMMessage], *args: Any, **kwargs: Any
) -> CreateResult:
for message in messages:
assert not isinstance(message, SystemMessage)
kwargs["messages"] = messages
return await original_create(*args, **kwargs)
# bind it
monkeypatch.setattr(model_client_soma, "create", MethodType(_mock_create, model_client_soma))
agent1 = AssistantAgent("assistant1", model_client=model_client, system_message="You are a helpful assistant.")
agent2 = AssistantAgent("assistant2", model_client=model_client, system_message="You are a helpful assistant.")
inner_termination = MaxMessageTermination(3)
inner_team = RoundRobinGroupChat([agent1, agent2], termination_condition=inner_termination, runtime=runtime)
society_of_mind_agent = SocietyOfMindAgent("society_of_mind", team=inner_team, model_client=model_client_soma)
await society_of_mind_agent.run(task="Count to 10.")
@pytest.mark.asyncio
async def test_society_of_mind_agent_yes_multiple_system_messages(
monkeypatch: pytest.MonkeyPatch, runtime: AgentRuntime | None
) -> None:
model_client = ReplayChatCompletionClient(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"])
model_client_soma = ReplayChatCompletionClient(
["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
model_info={
"vision": False,
"function_calling": False,
"json_output": False,
"family": "unknown",
"structured_output": False,
"multiple_system_messages": True,
},
)
original_create = model_client_soma.create
# mock method with bound self
async def _mock_create(
self: ReplayChatCompletionClient, messages: Sequence[LLMMessage], *args: Any, **kwargs: Any
) -> CreateResult:
assert isinstance(messages[0], SystemMessage)
assert isinstance(messages[-1], SystemMessage)
kwargs["messages"] = messages
return await original_create(*args, **kwargs)
# bind it
monkeypatch.setattr(model_client_soma, "create", MethodType(_mock_create, model_client_soma))
agent1 = AssistantAgent("assistant1", model_client=model_client, system_message="You are a helpful assistant.")
agent2 = AssistantAgent("assistant2", model_client=model_client, system_message="You are a helpful assistant.")
inner_termination = MaxMessageTermination(3)
inner_team = RoundRobinGroupChat([agent1, agent2], termination_condition=inner_termination, runtime=runtime)
society_of_mind_agent = SocietyOfMindAgent("society_of_mind", team=inner_team, model_client=model_client_soma)
await society_of_mind_agent.run(task="Count to 10.")
@pytest.mark.asyncio
async def test_default_output_task_messages_behavior() -> None:
"""Test that task messages are included by default (backward compatibility)."""
# Create inner team
model_client = ReplayChatCompletionClient(["Hello", "World", "TERMINATE"])
agent1 = AssistantAgent("agent1", model_client=model_client)
agent2 = AssistantAgent("agent2", model_client=model_client)
termination = TextMentionTermination("TERMINATE")
inner_team = RoundRobinGroupChat(participants=[agent1, agent2], termination_condition=termination)
streamed_messages: List[BaseAgentEvent | BaseChatMessage] = []
final_result: TaskResult | None = None
# Test default behavior (should include task messages since default is True)
async for message in inner_team.run_stream(task="Test default behavior"):
if isinstance(message, TaskResult):
final_result = message
else:
streamed_messages.append(message)
# Verify default behavior: task message should be included in stream
assert final_result is not None
task_message_found_in_stream = any(
isinstance(msg, TextMessage) and msg.source == "user" and "Test default behavior" in msg.content
for msg in streamed_messages
)
assert task_message_found_in_stream, "Task message should be included in stream by default"
# Validate that task message is included in the TaskResult.messages by default
task_message_in_result = any(
isinstance(msg, TextMessage) and msg.source == "user" and "Test default behavior" in msg.content
for msg in final_result.messages
)
assert task_message_in_result, "Task message should be included in TaskResult.messages by default"
# Verify the content structure makes sense (task message + agent responses)
user_messages = [msg for msg in final_result.messages if isinstance(msg, TextMessage) and msg.source == "user"]
agent_messages = [
msg for msg in final_result.messages if isinstance(msg, TextMessage) and msg.source in ["agent1", "agent2"]
]
assert len(user_messages) >= 1, "Should have at least one user message (the task)"
assert len(agent_messages) >= 1, "Should have at least one agent response"
assert user_messages[0].content == "Test default behavior", "First user message should be the task"

View File

@ -0,0 +1,99 @@
from typing import List, Optional
import pytest
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.base import TaskResult
from autogen_agentchat.messages import ModelClientStreamingChunkEvent, TextMessage
from autogen_core import FunctionCall
from autogen_core.models import CreateResult, ModelFamily, RequestUsage
from autogen_ext.models.replay import ReplayChatCompletionClient
async def _echo_function(input: str) -> str:
return input
@pytest.mark.asyncio
async def test_streaming_message_id_correlation() -> None:
"""Test that streaming chunks have full_message_id that matches final message ID."""
mock_client = ReplayChatCompletionClient(
[
"Response to message",
]
)
agent = AssistantAgent(
"test_agent",
model_client=mock_client,
model_client_stream=True,
)
# Track all chunks and the final message
chunks: List[ModelClientStreamingChunkEvent] = []
final_message: Optional[TextMessage] = None
async for message in agent.run_stream(task="task"):
if isinstance(message, TaskResult):
assert len(message.messages) == 2
assert isinstance(message.messages[0], TextMessage)
assert isinstance(message.messages[1], TextMessage)
final_message = message.messages[1]
elif isinstance(message, ModelClientStreamingChunkEvent):
chunks.append(message)
# Verify we got chunks and a final message
assert len(chunks) > 0
assert final_message is not None
# Every chunk should have the same full_message_id as the final message's id
for chunk in chunks:
assert chunk.full_message_id == final_message.id
# Test the reflect_on_tool_use streaming case
mock_client = ReplayChatCompletionClient(
[
CreateResult(
content=[
FunctionCall(id="1", name="_echo_function", arguments=r'{"input": "task"}'),
],
finish_reason="function_calls",
usage=RequestUsage(prompt_tokens=10, completion_tokens=5),
cached=False,
),
"Example reflection response",
],
model_info={
"function_calling": True,
"vision": False,
"json_output": False,
"family": ModelFamily.GPT_4,
"structured_output": False,
},
)
agent = AssistantAgent(
"test_agent",
model_client=mock_client,
model_client_stream=True,
reflect_on_tool_use=True,
tools=[_echo_function],
)
# Track reflection chunks and final message
reflection_chunks: List[ModelClientStreamingChunkEvent] = []
final_reflection_message: Optional[TextMessage] = None
async for message in agent.run_stream(task="task"):
if isinstance(message, TaskResult):
# The last message should be the reflection result
if isinstance(message.messages[-1], TextMessage):
final_reflection_message = message.messages[-1]
elif isinstance(message, ModelClientStreamingChunkEvent):
reflection_chunks.append(message)
# Verify we got reflection chunks and a final message
assert len(reflection_chunks) > 0
assert final_reflection_message is not None
# Every reflection chunk should have the same full_message_id as the final message's id
for chunk in reflection_chunks:
assert chunk.full_message_id == final_reflection_message.id # type: ignore

View File

@ -0,0 +1,239 @@
import pytest
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_agentchat.messages import TextMessage, ToolCallExecutionEvent, ToolCallRequestEvent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.tools import AgentTool, TeamTool
from autogen_core import (
CancellationToken,
FunctionCall,
)
from autogen_core.models import CreateResult, RequestUsage
from autogen_ext.models.replay import ReplayChatCompletionClient
from test_group_chat import _EchoAgent # type: ignore[reportPrivateUsage]
@pytest.mark.asyncio
async def test_agent_tool_run() -> None:
"""Test running a task with AgentTool."""
mock_chat_agent = _EchoAgent("Mock_Agent", "A mock agent for testing")
tool = AgentTool(agent=mock_chat_agent)
task_result = await tool.run_json({"task": "Test task"}, cancellation_token=CancellationToken())
assert task_result.messages[1].content == "Test task"
@pytest.mark.asyncio
async def test_agent_tool_state() -> None:
"""Test saving state of AgentTool."""
mock_chat_agent = _EchoAgent("Mock_Agent", "A mock agent for testing")
tool = AgentTool(agent=mock_chat_agent)
state = await tool.save_state_json()
assert state == {"last_message": None, "total_messages": 0}
await tool.run_json({"task": "Test task"}, cancellation_token=CancellationToken())
state = await tool.save_state_json()
assert state == {"last_message": "Test task", "total_messages": 1}
mock_chat_agent_2 = _EchoAgent("Mock_Agent_2", "A mock agent for testing")
tool_2 = AgentTool(agent=mock_chat_agent_2)
await tool_2.load_state_json(state)
state2 = await tool_2.save_state_json()
assert state2 == {"last_message": "Test task", "total_messages": 1}
def test_agent_tool_component() -> None:
"""Test serialization of AgentTool to config."""
model_client = ReplayChatCompletionClient(["test"])
agent = AssistantAgent(name="assistant", model_client=model_client)
tool = AgentTool(agent=agent)
config = tool.dump_component()
assert config.provider == "autogen_agentchat.tools.AgentTool"
tool2 = AgentTool.load_component(config)
assert isinstance(tool2, AgentTool)
assert tool2.name == agent.name
assert tool2.description == agent.description
@pytest.mark.asyncio
async def test_team_tool() -> None:
"""Test running a task with TeamTool."""
agent1 = _EchoAgent("Agent1", "An agent for testing")
agent2 = _EchoAgent("Agent2", "Another agent for testing")
termination = MaxMessageTermination(max_messages=3)
team = RoundRobinGroupChat(
[agent1, agent2],
termination_condition=termination,
)
tool = TeamTool(team=team, name="Team Tool", description="A team tool for testing")
task_result = await tool.run_json(args={"task": "test task"}, cancellation_token=CancellationToken())
assert task_result.messages[1].content == "test task"
assert task_result.messages[2].content == "test task"
# Validate state.
state = await tool.save_state_json()
# Reload the state and check if it matches.
agent2 = _EchoAgent("Agent1", "Another agent for testing")
agent3 = _EchoAgent("Agent2", "Another agent for testing")
team2 = RoundRobinGroupChat(
[agent2, agent3],
termination_condition=termination,
)
tool2 = TeamTool(team=team2, name="Team Tool", description="A team tool for testing")
await tool2.load_state_json(state)
state2 = await tool2.save_state_json()
assert state == state2
@pytest.mark.asyncio
async def test_team_tool_component() -> None:
"""Test serialization of TeamTool to config."""
model_client = ReplayChatCompletionClient(["test"])
agent1 = AssistantAgent(name="assistant1", model_client=model_client)
agent2 = AssistantAgent(name="assistant2", model_client=model_client)
team = RoundRobinGroupChat([agent1, agent2])
tool = TeamTool(team=team, name="Team Tool", description="A team tool for testing")
config = tool.dump_component()
assert config.provider == "autogen_agentchat.tools.TeamTool"
tool2 = TeamTool.load_component(config)
assert isinstance(tool2, TeamTool)
assert tool2.name == "Team Tool"
assert tool2.description == "A team tool for testing"
assert isinstance(tool2._team, RoundRobinGroupChat) # type: ignore[reportPrivateUsage]
@pytest.mark.asyncio
async def test_agent_tool_stream() -> None:
"""Test running a task with AgentTool in streaming mode."""
def _query_function() -> str:
return "Test task"
tool_agent_model_client = ReplayChatCompletionClient(
[
CreateResult(
content=[FunctionCall(name="query_function", arguments="{}", id="1")],
finish_reason="function_calls",
usage=RequestUsage(prompt_tokens=0, completion_tokens=0),
cached=False,
),
"Summary from tool agent",
],
model_info={
"family": "gpt-41",
"function_calling": True,
"json_output": True,
"multiple_system_messages": True,
"structured_output": True,
"vision": True,
},
)
tool_agent = AssistantAgent(
name="tool_agent",
model_client=tool_agent_model_client,
tools=[_query_function],
reflect_on_tool_use=True,
description="An agent for testing",
)
tool = AgentTool(tool_agent)
main_agent_model_client = ReplayChatCompletionClient(
[
CreateResult(
content=[FunctionCall(id="1", name="tool_agent", arguments='{"task": "Input task from main agent"}')],
finish_reason="function_calls",
usage=RequestUsage(prompt_tokens=0, completion_tokens=0),
cached=False,
),
"Summary from main agent",
],
model_info={
"family": "gpt-41",
"function_calling": True,
"json_output": True,
"multiple_system_messages": True,
"structured_output": True,
"vision": True,
},
)
main_agent = AssistantAgent(
name="main_agent",
model_client=main_agent_model_client,
tools=[tool],
reflect_on_tool_use=True,
description="An agent for testing",
)
result = await main_agent.run(task="Input task from user", cancellation_token=CancellationToken())
assert isinstance(result.messages[0], TextMessage)
assert result.messages[0].content == "Input task from user"
assert isinstance(result.messages[1], ToolCallRequestEvent)
assert isinstance(result.messages[2], TextMessage)
assert result.messages[2].content == "Input task from main agent"
assert isinstance(result.messages[3], ToolCallRequestEvent)
assert isinstance(result.messages[4], ToolCallExecutionEvent)
assert isinstance(result.messages[5], TextMessage)
assert result.messages[5].content == "Summary from tool agent"
assert isinstance(result.messages[6], ToolCallExecutionEvent)
assert result.messages[6].content[0].content == "tool_agent: Summary from tool agent"
assert isinstance(result.messages[7], TextMessage)
assert result.messages[7].content == "Summary from main agent"
@pytest.mark.asyncio
async def test_team_tool_stream() -> None:
"""Test running a task with TeamTool in streaming mode."""
agent1 = _EchoAgent("Agent1", "An agent for testing")
agent2 = _EchoAgent("Agent2", "Another agent for testing")
termination = MaxMessageTermination(max_messages=3)
team = RoundRobinGroupChat(
[agent1, agent2],
termination_condition=termination,
)
tool = TeamTool(
team=team, name="team_tool", description="A team tool for testing", return_value_as_last_message=True
)
model_client = ReplayChatCompletionClient(
[
CreateResult(
content=[FunctionCall(name="team_tool", arguments='{"task": "test task from main agent"}', id="1")],
finish_reason="function_calls",
usage=RequestUsage(prompt_tokens=0, completion_tokens=0),
cached=False,
),
"Summary from main agent",
],
model_info={
"family": "gpt-41",
"function_calling": True,
"json_output": True,
"multiple_system_messages": True,
"structured_output": True,
"vision": True,
},
)
main_agent = AssistantAgent(
name="main_agent",
model_client=model_client,
tools=[tool],
reflect_on_tool_use=True,
description="An agent for testing",
)
result = await main_agent.run(task="test task from user", cancellation_token=CancellationToken())
assert isinstance(result.messages[0], TextMessage)
assert result.messages[0].content == "test task from user"
assert isinstance(result.messages[1], ToolCallRequestEvent)
assert isinstance(result.messages[2], TextMessage)
assert result.messages[2].content == "test task from main agent"
assert isinstance(result.messages[3], TextMessage)
assert result.messages[3].content == "test task from main agent"
assert result.messages[3].source == "Agent1"
assert isinstance(result.messages[4], TextMessage)
assert result.messages[4].content == "test task from main agent"
assert result.messages[4].source == "Agent2"
assert isinstance(result.messages[5], ToolCallExecutionEvent)
assert result.messages[5].content[0].content == "test task from main agent"
assert isinstance(result.messages[6], TextMessage)
assert result.messages[6].content == "Summary from main agent"

View File

@ -1,9 +1,11 @@
import asyncio
from typing import Sequence
import pytest
from autogen_agentchat.base import TerminatedException
from autogen_agentchat.conditions import (
ExternalTermination,
FunctionalTermination,
FunctionCallTermination,
HandoffTermination,
MaxMessageTermination,
@ -15,13 +17,17 @@ from autogen_agentchat.conditions import (
TokenUsageTermination,
)
from autogen_agentchat.messages import (
BaseAgentEvent,
BaseChatMessage,
HandoffMessage,
StopMessage,
StructuredMessage,
TextMessage,
ToolCallExecutionEvent,
UserInputRequestedEvent,
)
from autogen_core.models import FunctionExecutionResult, RequestUsage
from pydantic import BaseModel
@pytest.mark.asyncio
@ -375,3 +381,53 @@ async def test_function_call_termination() -> None:
)
assert not termination.terminated
await termination.reset()
@pytest.mark.asyncio
async def test_functional_termination() -> None:
async def async_termination_func(messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> bool:
if len(messages) < 1:
return False
if isinstance(messages[-1], TextMessage):
return messages[-1].content == "stop"
return False
termination = FunctionalTermination(async_termination_func)
assert await termination([]) is None
await termination.reset()
assert await termination([TextMessage(content="Hello", source="user")]) is None
await termination.reset()
assert await termination([TextMessage(content="stop", source="user")]) is not None
assert termination.terminated
await termination.reset()
assert await termination([TextMessage(content="Hello", source="user")]) is None
class TestContentType(BaseModel):
content: str
data: str
def sync_termination_func(messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> bool:
if len(messages) < 1:
return False
last_message = messages[-1]
if isinstance(last_message, StructuredMessage) and isinstance(last_message.content, TestContentType): # type: ignore[reportUnknownMemberType]
return last_message.content.data == "stop"
return False
termination = FunctionalTermination(sync_termination_func)
assert await termination([]) is None
await termination.reset()
assert await termination([TextMessage(content="Hello", source="user")]) is None
await termination.reset()
assert (
await termination(
[StructuredMessage[TestContentType](content=TestContentType(content="1", data="stop"), source="user")]
)
is not None
)
assert termination.terminated
await termination.reset()
assert await termination([TextMessage(content="Hello", source="user")]) is None

View File

@ -2,7 +2,10 @@ import json
import logging
import sys
from datetime import datetime
from typing import Sequence
from autogen_agentchat.base._task import TaskResult
from autogen_agentchat.messages import BaseAgentEvent, BaseChatMessage, BaseTextChatMessage
from pydantic import BaseModel
@ -18,7 +21,7 @@ class FileLogHandler(logging.Handler):
record.msg = json.dumps(
{
"timestamp": ts,
"message": record.msg.model_dump(),
"message": record.msg.model_dump_json(indent=2),
"type": record.msg.__class__.__name__,
},
)
@ -37,3 +40,36 @@ class ConsoleLogHandler(logging.Handler):
},
)
sys.stdout.write(f"{record.msg}\n")
def compare_messages(
msg1: BaseAgentEvent | BaseChatMessage | BaseTextChatMessage,
msg2: BaseAgentEvent | BaseChatMessage | BaseTextChatMessage,
) -> bool:
if isinstance(msg1, BaseTextChatMessage) and isinstance(msg2, BaseTextChatMessage):
if msg1.content != msg2.content:
return False
return (
(msg1.source == msg2.source) and (msg1.models_usage == msg2.models_usage) and (msg1.metadata == msg2.metadata)
)
def compare_message_lists(
msgs1: Sequence[BaseAgentEvent | BaseChatMessage],
msgs2: Sequence[BaseAgentEvent | BaseChatMessage],
) -> bool:
if len(msgs1) != len(msgs2):
return False
for i in range(len(msgs1)):
if not compare_messages(msgs1[i], msgs2[i]):
return False
return True
def compare_task_results(
res1: TaskResult,
res2: TaskResult,
) -> bool:
if res1.stop_reason != res2.stop_reason:
return False
return compare_message_lists(res1.messages, res2.messages)

View File

@ -1,202 +1,222 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0" version="25.0.3">
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0" version="26.0.6">
<diagram name="Page-1" id="bkX10E6zblEP7POKMJXw">
<mxGraphModel dx="1768" dy="1089" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<mxGraphModel dx="775" dy="621" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="NpWbz43RdM9-YawIMZhB-93" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" vertex="1" parent="1">
<mxGeometry x="180" y="220" width="490" height="800" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-93" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" parent="1" vertex="1">
<mxGeometry x="180" y="220" width="500" height="890" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-90" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" vertex="1" parent="1">
<mxGeometry x="210" y="856" width="430" height="143" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-90" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="210" y="951" width="430" height="143" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-100" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-83" target="NpWbz43RdM9-YawIMZhB-84">
<mxCell id="NpWbz43RdM9-YawIMZhB-100" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-83" target="NpWbz43RdM9-YawIMZhB-84" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-83" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-83" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="210" y="248" width="430" height="61" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-118" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-84" target="NpWbz43RdM9-YawIMZhB-85">
<mxCell id="NpWbz43RdM9-YawIMZhB-118" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-84" target="NpWbz43RdM9-YawIMZhB-85" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-84" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-84" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="210" y="329" width="430" height="90" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-122" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-85" target="NpWbz43RdM9-YawIMZhB-70">
<mxCell id="NpWbz43RdM9-YawIMZhB-122" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="NpWbz43RdM9-YawIMZhB-85" target="NpWbz43RdM9-YawIMZhB-70" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-85" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-85" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="210" y="438" width="430" height="110" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-123" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-87" target="NpWbz43RdM9-YawIMZhB-111">
<mxCell id="NpWbz43RdM9-YawIMZhB-123" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="NpWbz43RdM9-YawIMZhB-87" target="NpWbz43RdM9-YawIMZhB-111" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-87" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-87" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="210" y="616" width="430" height="114" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-78" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-90" target="NpWbz43RdM9-YawIMZhB-51">
<mxCell id="NpWbz43RdM9-YawIMZhB-78" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-90" target="NpWbz43RdM9-YawIMZhB-51" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-50" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="230" y="910" width="120" height="80" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-50" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="1005" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-35" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-35" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="646" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-3" target="NpWbz43RdM9-YawIMZhB-12">
<mxCell id="NpWbz43RdM9-YawIMZhB-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-3" target="NpWbz43RdM9-YawIMZhB-12" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-3" value="New Messages" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-3" value="New Messages" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="245" y="170" width="90" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-68" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=-15;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-6" target="NpWbz43RdM9-YawIMZhB-19">
<mxCell id="NpWbz43RdM9-YawIMZhB-68" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=-15;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-6" target="NpWbz43RdM9-YawIMZhB-19" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-6" value="Memory" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-6" value="Memory" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="520" y="340" width="90" height="69" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.13;exitY=0.77;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-10" target="NpWbz43RdM9-YawIMZhB-29">
<mxCell id="NpWbz43RdM9-YawIMZhB-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.13;exitY=0.77;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-10" target="NpWbz43RdM9-YawIMZhB-29" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-10" value="Model Client" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-10" value="Model Client" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="490" y="438" width="150" height="100" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-89" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0;exitDx=0;exitDy=60;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-11" target="NpWbz43RdM9-YawIMZhB-35">
<mxCell id="NpWbz43RdM9-YawIMZhB-89" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0;exitDx=0;exitDy=60;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-11" target="NpWbz43RdM9-YawIMZhB-35" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-11" value="Tools" style="shape=cube;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;darkOpacity=0.05;darkOpacity2=0.1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-11" value="Tools" style="shape=cube;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;darkOpacity=0.05;darkOpacity2=0.1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
<mxGeometry x="505" y="636" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-12" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-12" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="259" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-17" value="1. Add New Messages to Context" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-17" value="1. Add New Messages to Context" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="370" y="263.5" width="190" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-19" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-19" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="349" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-22" value="2. Update Context" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-22" value="2. Update Context" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="370" y="359" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-24" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-24" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="349" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-27" target="NpWbz43RdM9-YawIMZhB-10">
<mxCell id="NpWbz43RdM9-YawIMZhB-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-27" target="NpWbz43RdM9-YawIMZhB-10" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-31" value="3. Chat Completion" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-31" value="3. Chat Completion" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="370" y="475" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-32" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-32" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="626" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-33" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-33" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="626" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-34" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-34" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="626" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-38" value="4. Tool Execution" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-38" value="4. Tool Execution" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="370" y="666" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.13;exitY=0.77;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-41" target="NpWbz43RdM9-YawIMZhB-50">
<mxCell id="NpWbz43RdM9-YawIMZhB-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.13;exitY=0.77;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-41" target="NpWbz43RdM9-YawIMZhB-50" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="370" y="950" as="targetPoint" />
<mxPoint x="370" y="1045" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-41" value="Model Client" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
<mxGeometry x="490" y="870" width="150" height="100" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-41" value="Model Client" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="490" y="965" width="150" height="100" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-49" target="NpWbz43RdM9-YawIMZhB-41">
<mxCell id="NpWbz43RdM9-YawIMZhB-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-49" target="NpWbz43RdM9-YawIMZhB-41" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="370" y="910" as="sourcePoint" />
<mxPoint x="370" y="1005" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-45" value="5. Chat Completion (Reflect on Tool Use)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="355" y="905" width="130" height="30" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-45" value="5. Chat Completion (Reflect on Tool Use)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="355" y="1000" width="130" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-46" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="230" y="890" width="120" height="80" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-46" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="985" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-47" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="230" y="870" width="120" height="80" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-47" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="965" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-48" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="230" y="870" width="120" height="60" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-48" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="965" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-49" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="230" y="870" width="120" height="40" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-49" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="965" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-51" value="Response&lt;div&gt;(Text)&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="395" y="1040" width="60" height="30" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-51" value="Response&lt;div&gt;(Text)&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="395" y="1135" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-53" value="Response&amp;nbsp;&lt;div&gt;(Tool Result Summary)&lt;/div&gt;" style="text;html=1;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="10" y="806" width="140" height="30" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-53" value="Response&amp;nbsp;&lt;div&gt;(Tool Result Summary)&lt;/div&gt;" style="text;html=1;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="10" y="888" width="140" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-58" value="Response&amp;nbsp;&lt;div&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;(Text Message)&lt;/span&gt;&lt;/div&gt;" style="text;html=1;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-58" value="Response&amp;nbsp;&lt;div&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;(Text Message)&lt;/span&gt;&lt;/div&gt;" style="text;html=1;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="10" y="569" width="140" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=15;entryPerimeter=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-24" target="NpWbz43RdM9-YawIMZhB-6">
<mxCell id="NpWbz43RdM9-YawIMZhB-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=15;entryPerimeter=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-24" target="NpWbz43RdM9-YawIMZhB-6" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-29" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-29" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="455" width="120" height="80" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-26" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-26" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="455" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-27" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-27" value="Model Context" style="shape=document;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="230" y="455" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-71" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-70" target="NpWbz43RdM9-YawIMZhB-58">
<mxCell id="NpWbz43RdM9-YawIMZhB-71" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="NpWbz43RdM9-YawIMZhB-70" target="NpWbz43RdM9-YawIMZhB-58" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-126" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-126" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="422.75" y="599" as="sourcePoint" />
<mxPoint x="424" y="616" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-70" value="Tool Call Detected?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-70" value="Tool Call Detected?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="367.5" y="569" width="112.5" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-74" target="NpWbz43RdM9-YawIMZhB-53">
<mxCell id="NpWbz43RdM9-YawIMZhB-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-74" target="NpWbz43RdM9-YawIMZhB-53" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-124" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-74" target="NpWbz43RdM9-YawIMZhB-90">
<mxCell id="NpWbz43RdM9-YawIMZhB-124" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-74" target="NpWbz43RdM9-YawIMZhB-90" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-74" value="Reflect on Tool Use?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="365.5" y="806" width="120" height="30" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-74" value="Reflect on Tool Use?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="365.5" y="888" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-106" value="No" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-106" value="No" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="230" y="560" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-107" value="No" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="230" y="790" width="60" height="30" as="geometry" />
<mxCell id="NpWbz43RdM9-YawIMZhB-107" value="No" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="230" y="877" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-110" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=30;entryPerimeter=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-34" target="NpWbz43RdM9-YawIMZhB-11">
<mxCell id="NpWbz43RdM9-YawIMZhB-110" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=30;entryPerimeter=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-34" target="NpWbz43RdM9-YawIMZhB-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-113" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-111" target="NpWbz43RdM9-YawIMZhB-112">
<mxCell id="NpWbz43RdM9-YawIMZhB-113" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="NpWbz43RdM9-YawIMZhB-111" target="NpWbz43RdM9-YawIMZhB-112" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-117" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-111" target="NpWbz43RdM9-YawIMZhB-74">
<mxCell id="NpWbz43RdM9-YawIMZhB-117" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="ajhwLJHiypqY-D0M9j8j-1" target="NpWbz43RdM9-YawIMZhB-74" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-111" value="Handoff Detected?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=1;" vertex="1" parent="1">
<mxCell id="ajhwLJHiypqY-D0M9j8j-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="NpWbz43RdM9-YawIMZhB-111" target="ajhwLJHiypqY-D0M9j8j-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-111" value="Handoff Detected?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=1;" parent="1" vertex="1">
<mxGeometry x="370.75" y="754" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-112" value="Response&lt;div&gt;(Handoff)&lt;/div&gt;" style="text;html=1;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-112" value="Response&lt;div&gt;(Handoff)&lt;/div&gt;" style="text;html=1;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="90" y="754" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-115" value="Yes" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-115" value="Yes" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="230" y="744" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="NpWbz43RdM9-YawIMZhB-127" value="Assistant Agent" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxCell id="NpWbz43RdM9-YawIMZhB-127" value="Assistant Agent" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="700" y="218" width="109.25" height="30" as="geometry" />
</mxCell>
<mxCell id="ajhwLJHiypqY-D0M9j8j-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="ajhwLJHiypqY-D0M9j8j-1" target="NpWbz43RdM9-YawIMZhB-85">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="660" y="835" />
<mxPoint x="660" y="493" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ajhwLJHiypqY-D0M9j8j-1" value="Maximum Tool Iterations Reached?" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="325" y="820" width="201" height="30" as="geometry" />
</mxCell>
<mxCell id="ajhwLJHiypqY-D0M9j8j-3" value="Yes" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="420.75" y="850" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="ajhwLJHiypqY-D0M9j8j-5" value="No" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="550" y="808" width="60" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>

View File

@ -32,6 +32,17 @@ html[data-theme="dark"] {
color: white;
text-shadow: 0.5px 0 0 currentColor;
}
/* Adding header icon hover and focus effects */
.bd-header a:focus-visible {
color: var(--pst-color-secondary) !important;
text-decoration: underline !important;
text-shadow: 0.5px 0 0 currentColor;
transform: scale(1.05);
transition: all 0.2s ease-in-out;
outline: none;
}
nav.bd-links .current>a {
box-shadow: inset 1px 0 0 var(--pst-color-primary);
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -46,40 +46,12 @@ A framework for building AI agents and applications
::::{grid}
:gutter: 2
:::{grid-item-card}
:shadow: none
:margin: 2 0 0 0
:columns: 12 12 6 6
<div class="sd-card-title sd-font-weight-bold docutils">
{fas}`book;pst-color-primary`
Magentic-One CLI [![PyPi magentic-one-cli](https://img.shields.io/badge/PyPi-magentic--one--cli-blue?logo=pypi)](https://pypi.org/project/magentic-one-cli/)
</div>
A console-based multi-agent assistant for web and file-based tasks.
Built on AgentChat.
```bash
pip install -U magentic-one-cli
m1 "Find flights from Seattle to Paris and format the result in a table"
```
+++
```{button-ref} user-guide/agentchat-user-guide/magentic-one
:color: secondary
Get Started
```
:::
:::{grid-item-card} {fas}`palette;pst-color-primary` Studio [![PyPi autogenstudio](https://img.shields.io/badge/PyPi-autogenstudio-blue?logo=pypi)](https://pypi.org/project/autogenstudio/)
:shadow: none
:margin: 2 0 0 0
:columns: 12 12 6 6
:columns: 12 12 12 12
An app for prototyping and managing agents without writing code.
An web-based UI for prototyping with agents without writing code.
Built on AgentChat.
```bash
@ -87,6 +59,8 @@ pip install -U autogenstudio
autogenstudio ui --port 8080 --appdir ./myapp
```
_Start here if you are new to AutoGen and want to prototype with agents without writing code._
+++
```{button-ref} user-guide/autogenstudio-user-guide/index
@ -124,7 +98,7 @@ async def main() -> None:
asyncio.run(main())
```
_Start here if you are building conversational agents. [Migrating from AutoGen 0.2?](./user-guide/agentchat-user-guide/migration-guide.md)._
_Start here if you are prototyping with agents using Python. [Migrating from AutoGen 0.2?](./user-guide/agentchat-user-guide/migration-guide.md)._
+++
@ -147,7 +121,7 @@ An event-driven programming framework for building scalable multi-agent AI syste
* Research on multi-agent collaboration.
* Distributed agents for multi-language applications.
_Start here if you are building workflows or distributed agent systems._
_Start here if you are getting serious about building multi-agent systems._
+++
@ -167,7 +141,7 @@ Get Started
Implementations of Core and AgentChat components that interface with external services or other libraries.
You can find and use community extensions or create your own. Examples of built-in extensions:
* {py:class}`~autogen_ext.tools.langchain.LangChainToolAdapter` for using LangChain tools.
* {py:class}`~autogen_ext.tools.mcp.McpWorkbench` for using Model-Context Protocol (MCP) servers.
* {py:class}`~autogen_ext.agents.openai.OpenAIAssistantAgent` for using Assistant API.
* {py:class}`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor` for running model-generated code in a Docker container.
* {py:class}`~autogen_ext.runtimes.grpc.GrpcWorkerAgentRuntime` for distributed agents.

View File

@ -14,6 +14,7 @@ myst:
python/autogen_agentchat
python/autogen_agentchat.messages
python/autogen_agentchat.agents
python/autogen_agentchat.tools
python/autogen_agentchat.teams
python/autogen_agentchat.base
python/autogen_agentchat.conditions
@ -40,6 +41,7 @@ python/autogen_core.logging
:caption: AutoGen Extensions
:maxdepth: 2
python/autogen_ext.agents.azure
python/autogen_ext.agents.magentic_one
python/autogen_ext.agents.openai
python/autogen_ext.agents.web_surfer
@ -61,10 +63,12 @@ python/autogen_ext.tools.graphrag
python/autogen_ext.tools.http
python/autogen_ext.tools.langchain
python/autogen_ext.tools.mcp
python/autogen_ext.memory.canvas
python/autogen_ext.tools.semantic_kernel
python/autogen_ext.code_executors.local
python/autogen_ext.code_executors.docker
python/autogen_ext.code_executors.jupyter
python/autogen_ext.code_executors.docker_jupyter
python/autogen_ext.code_executors.azure
python/autogen_ext.cache_store.diskcache
python/autogen_ext.cache_store.redis

View File

@ -0,0 +1,8 @@
autogen\_agentchat.tools
========================
.. automodule:: autogen_agentchat.tools
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,8 @@
autogen\_ext.agents.azure
================================
.. automodule:: autogen_ext.agents.azure
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,8 @@
autogen\_ext.code\_executors.docker_jupyter
===========================================
.. automodule:: autogen_ext.code_executors.docker_jupyter
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,8 @@
autogen\_ext.memory.canvas
==========================
.. automodule:: autogen_ext.memory.canvas
:members:
:undoc-members:
:show-inheritance:

View File

@ -16,7 +16,9 @@
"- {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_reset`: The abstract method that resets the agent to its initial state. This method is called when the agent is asked to reset itself.\n",
"- {py:attr}`~autogen_agentchat.agents.BaseChatAgent.produced_message_types`: The list of possible {py:class}`~autogen_agentchat.messages.BaseChatMessage` message types the agent can produce in its response.\n",
"\n",
"Optionally, you can implement the the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages_stream` method to stream messages as they are generated by the agent. If this method is not implemented, the agent\n",
"Optionally, you can implement the the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages_stream` method to stream messages as they are generated by the agent.\n",
"This method is called by {py:meth}`~autogen_agentchat.agents.BaseChatAgent.run_stream` to stream messages.\n",
"If this method is not implemented, the agent\n",
"uses the default implementation of {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages_stream`\n",
"that calls the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages` method and\n",
"yields all messages in the response."
@ -731,7 +733,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
"version": "3.12.7"
}
},
"nbformat": 4,

File diff suppressed because one or more lines are too long

View File

@ -68,6 +68,13 @@ Multi-agent coordination through a shared context and localized, tool-based sele
Get started with Magentic-One
:::
:::{grid-item-card} {fas}`sitemap;pst-color-primary` GraphFlow (Workflow)
:link: ./graph-flow.html
:link-alt: GraphFlow: Multi-agent workflows through a directed graph of agents.
Multi-agent workflows through a directed graph of agents.
:::
:::{grid-item-card} {fas}`brain;pst-color-primary` Memory
:link: ./memory.html
:link-alt: Memory: Add memory capabilities to your agents
@ -138,6 +145,7 @@ custom-agents
selector-group-chat
swarm
magentic-one
graph-flow
memory
logging
serialize-components

View File

@ -17,13 +17,19 @@ When installing AgentChat locally, we recommend using a virtual environment for
Create and activate:
Linux/Mac:
```bash
# On Windows, change `python3` to `python` (if `python` is Python 3).
python3 -m venv .venv
# On Windows, change `bin` to `scripts`.
source .venv/bin/activate
```
Windows command-line:
```batch
# The command may be `python3` instead of `python` depending on your setup
python -m venv .venv
.venv\Scripts\activate.bat
```
To deactivate later, run:
```bash

File diff suppressed because one or more lines are too long

View File

@ -272,6 +272,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The string variables available in the selector prompt are:\n",
"- `{participants}`: The names of candidates for selection. The format is `[\"<name1>\", \"<name2>\", ...]`.\n",
"- `{roles}`: A newline-separated list of names and descriptions of the candidate agents. The format for each line is: `\"<name> : <description>\"`.\n",
"- `{history}`: The conversation history formatted as a double newline separated of names and message content. The format for each message is: `\"<name> : <message content>\"`.\n",
"\n",
"```{tip}\n",
"Try not to overload the model with too much instruction in the selector prompt.\n",
"\n",
@ -433,6 +438,10 @@
"\n",
"```{note}\n",
"Returning `None` from the custom selector function will use the default model-based selection.\n",
"``` \n",
"\n",
"```{note}\n",
"Custom selector functions are not [serialized](https://microsoft.github.io/autogen/stable/user-guide/agentchat-user-guide/serialize-components.html) when `.dump_component()` is called on the SelectorGroupChat team . If you need to serialize team configurations with custom selector functions, consider implementing custom workflows and serialization logic.\n",
"```"
]
},
@ -1018,7 +1027,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -19,6 +19,10 @@
" \n",
"```\n",
"\n",
"```{note}\n",
"`selector_func` is not serializable and will be ignored during serialization and deserialization process.\n",
"```\n",
"\n",
" \n",
"### Termination Condition Example \n",
"\n",

View File

@ -1,402 +1,331 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tracing and Observability\n",
"\n",
"AutoGen has [built-in support for tracing](https://microsoft.github.io/autogen/dev/user-guide/core-user-guide/framework/telemetry.html) and observability for collecting comprehensive records on the execution of your application. This feature is useful for debugging, performance analysis, and understanding the flow of your application.\n",
"\n",
"This capability is powered by the [OpenTelemetry](https://opentelemetry.io/) library, which means you can use any OpenTelemetry-compatible backend to collect and analyze traces.\n",
"\n",
"## Setup\n",
"\n",
"To begin, you need to install the OpenTelemetry Python package. You can do this using pip:\n",
"\n",
"```bash\n",
"pip install opentelemetry-sdk\n",
"```\n",
"\n",
"Once you have the SDK installed, the simplest way to set up tracing in AutoGen is to:\n",
"\n",
"1. Configure an OpenTelemetry tracer provider\n",
"2. Set up an exporter to send traces to your backend\n",
"3. Connect the tracer provider to the AutoGen runtime\n",
"\n",
"## Telemetry Backend\n",
"\n",
"To collect and view traces, you need to set up a telemetry backend. Several open-source options are available, including Jaeger, Zipkin. For this example, we will use Jaeger as our telemetry backend.\n",
"\n",
"For a quick start, you can run Jaeger locally using Docker:\n",
"\n",
"```bash\n",
"docker run -d --name jaeger \\\n",
" -e COLLECTOR_OTLP_ENABLED=true \\\n",
" -p 16686:16686 \\\n",
" -p 4317:4317 \\\n",
" -p 4318:4318 \\\n",
" jaegertracing/all-in-one:latest\n",
"```\n",
"\n",
"This command starts a Jaeger instance that listens on port 16686 for the Jaeger UI and port 4317 for the OpenTelemetry collector. You can access the Jaeger UI at `http://localhost:16686`.\n",
"\n",
"## Instrumenting an AgentChat Team\n",
"\n",
"In the following section, we will review how to enable tracing with an AutoGen GroupChat team. The AutoGen runtime already supports open telemetry (automatically logging message metadata). To begin, we will create a tracing service that will be used to instrument the AutoGen runtime. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from opentelemetry import trace\n",
"from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\n",
"from opentelemetry.sdk.resources import Resource\n",
"from opentelemetry.sdk.trace import TracerProvider\n",
"from opentelemetry.sdk.trace.export import BatchSpanProcessor\n",
"\n",
"otel_exporter = OTLPSpanExporter(endpoint=\"http://localhost:4317\", insecure=True)\n",
"tracer_provider = TracerProvider(resource=Resource({\"service.name\": \"autogen-test-agentchat\"}))\n",
"span_processor = BatchSpanProcessor(otel_exporter)\n",
"tracer_provider.add_span_processor(span_processor)\n",
"trace.set_tracer_provider(tracer_provider)\n",
"\n",
"# we will get reference this tracer later using its service name\n",
"# tracer = trace.get_tracer(\"autogen-test-agentchat\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"All of the code to create a [team](./tutorial/teams.ipynb) should already be familiar to you. An important note here is that all AgentChat agents and teams are run using the AutoGen core API runtime. In turn, the runtime is already instrumented to log [runtime messaging events (metadata)] (https://github.com/microsoft/autogen/blob/main/python/packages/autogen-core/src/autogen_core/_telemetry/_tracing_config.py) including:\n",
"\n",
"- **create**: When a message is created\n",
"- **send**: When a message is sent\n",
"- **publish**: When a message is published\n",
"- **receive**: When a message is received\n",
"- **intercept**: When a message is intercepted\n",
"- **process**: When a message is processed\n",
"- **ack**: When a message is acknowledged \n",
" "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from autogen_agentchat.agents import AssistantAgent\n",
"from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination\n",
"from autogen_agentchat.teams import SelectorGroupChat\n",
"from autogen_agentchat.ui import Console\n",
"from autogen_core import SingleThreadedAgentRuntime\n",
"from autogen_ext.models.openai import OpenAIChatCompletionClient\n",
"\n",
"\n",
"def search_web_tool(query: str) -> str:\n",
" if \"2006-2007\" in query:\n",
" return \"\"\"Here are the total points scored by Miami Heat players in the 2006-2007 season:\n",
" Udonis Haslem: 844 points\n",
" Dwayne Wade: 1397 points\n",
" James Posey: 550 points\n",
" ...\n",
" \"\"\"\n",
" elif \"2007-2008\" in query:\n",
" return \"The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.\"\n",
" elif \"2008-2009\" in query:\n",
" return \"The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.\"\n",
" return \"No data found.\"\n",
"\n",
"\n",
"def percentage_change_tool(start: float, end: float) -> float:\n",
" return ((end - start) / start) * 100\n",
"\n",
"\n",
"async def main() -> None:\n",
" model_client = OpenAIChatCompletionClient(model=\"gpt-4o\")\n",
"\n",
" planning_agent = AssistantAgent(\n",
" \"PlanningAgent\",\n",
" description=\"An agent for planning tasks, this agent should be the first to engage when given a new task.\",\n",
" model_client=model_client,\n",
" system_message=\"\"\"\n",
" You are a planning agent.\n",
" Your job is to break down complex tasks into smaller, manageable subtasks.\n",
" Your team members are:\n",
" WebSearchAgent: Searches for information\n",
" DataAnalystAgent: Performs calculations\n",
"\n",
" You only plan and delegate tasks - you do not execute them yourself.\n",
"\n",
" When assigning tasks, use this format:\n",
" 1. <agent> : <task>\n",
"\n",
" After all tasks are complete, summarize the findings and end with \"TERMINATE\".\n",
" \"\"\",\n",
" )\n",
"\n",
" web_search_agent = AssistantAgent(\n",
" \"WebSearchAgent\",\n",
" description=\"An agent for searching information on the web.\",\n",
" tools=[search_web_tool],\n",
" model_client=model_client,\n",
" system_message=\"\"\"\n",
" You are a web search agent.\n",
" Your only tool is search_tool - use it to find information.\n",
" You make only one search call at a time.\n",
" Once you have the results, you never do calculations based on them.\n",
" \"\"\",\n",
" )\n",
"\n",
" data_analyst_agent = AssistantAgent(\n",
" \"DataAnalystAgent\",\n",
" description=\"An agent for performing calculations.\",\n",
" model_client=model_client,\n",
" tools=[percentage_change_tool],\n",
" system_message=\"\"\"\n",
" You are a data analyst.\n",
" Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.\n",
" If you have not seen the data, ask for it.\n",
" \"\"\",\n",
" )\n",
"\n",
" text_mention_termination = TextMentionTermination(\"TERMINATE\")\n",
" max_messages_termination = MaxMessageTermination(max_messages=25)\n",
" termination = text_mention_termination | max_messages_termination\n",
"\n",
" selector_prompt = \"\"\"Select an agent to perform task.\n",
"\n",
" {roles}\n",
"\n",
" Current conversation context:\n",
" {history}\n",
"\n",
" Read the above conversation, then select an agent from {participants} to perform the next task.\n",
" Make sure the planner agent has assigned tasks before other agents start working.\n",
" Only select one agent.\n",
" \"\"\"\n",
"\n",
" task = \"Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?\"\n",
"\n",
" tracer = trace.get_tracer(\"autogen-test-agentchat\")\n",
" with tracer.start_as_current_span(\"runtime\"):\n",
" team = SelectorGroupChat(\n",
" [planning_agent, web_search_agent, data_analyst_agent],\n",
" model_client=model_client,\n",
" termination_condition=termination,\n",
" selector_prompt=selector_prompt,\n",
" allow_repeated_speaker=True,\n",
" )\n",
" await Console(team.run_stream(task=task))\n",
"\n",
" await model_client.close()\n",
"\n",
"\n",
"# asyncio.run(main())"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"---------- user ----------\n",
"Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?\n",
"---------- PlanningAgent ----------\n",
"To accomplish this, we can break down the tasks as follows:\n",
"\n",
"1. WebSearchAgent: Search for the Miami Heat player with the highest points during the 2006-2007 NBA season.\n",
"2. WebSearchAgent: Find the total rebounds for the identified player in both the 2007-2008 and 2008-2009 NBA seasons.\n",
"3. DataAnalystAgent: Calculate the percentage change in total rebounds for the player between the 2007-2008 and 2008-2009 seasons.\n",
"\n",
"Once these tasks are complete, I will summarize the findings.\n",
"---------- WebSearchAgent ----------\n",
"[FunctionCall(id='call_PUhxZyR0CTlWCY4uwd5Zh3WO', arguments='{\"query\":\"Miami Heat highest points scorer 2006-2007 season\"}', name='search_web_tool')]\n",
"---------- WebSearchAgent ----------\n",
"[FunctionExecutionResult(content='Here are the total points scored by Miami Heat players in the 2006-2007 season:\\n Udonis Haslem: 844 points\\n Dwayne Wade: 1397 points\\n James Posey: 550 points\\n ...\\n ', name='search_web_tool', call_id='call_PUhxZyR0CTlWCY4uwd5Zh3WO', is_error=False)]\n",
"---------- WebSearchAgent ----------\n",
"Here are the total points scored by Miami Heat players in the 2006-2007 season:\n",
" Udonis Haslem: 844 points\n",
" Dwayne Wade: 1397 points\n",
" James Posey: 550 points\n",
" ...\n",
" \n",
"---------- WebSearchAgent ----------\n",
"Dwyane Wade was the Miami Heat player with the highest points in the 2006-2007 season, scoring 1,397 points. Now, let's find his total rebounds for the 2007-2008 and 2008-2009 NBA seasons.\n",
"---------- WebSearchAgent ----------\n",
"[FunctionCall(id='call_GL7KkWKj9ejIM8FfpgXe2dPk', arguments='{\"query\": \"Dwyane Wade total rebounds 2007-2008 season\"}', name='search_web_tool'), FunctionCall(id='call_X81huZoiA30zIjSAIDgb8ebe', arguments='{\"query\": \"Dwyane Wade total rebounds 2008-2009 season\"}', name='search_web_tool')]\n",
"---------- WebSearchAgent ----------\n",
"[FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.', name='search_web_tool', call_id='call_GL7KkWKj9ejIM8FfpgXe2dPk', is_error=False), FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.', name='search_web_tool', call_id='call_X81huZoiA30zIjSAIDgb8ebe', is_error=False)]\n",
"---------- WebSearchAgent ----------\n",
"The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.\n",
"The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.\n",
"---------- DataAnalystAgent ----------\n",
"[FunctionCall(id='call_kB50RkFVqHptA7FOf0lL2RS8', arguments='{\"start\":214,\"end\":398}', name='percentage_change_tool')]\n",
"---------- DataAnalystAgent ----------\n",
"[FunctionExecutionResult(content='85.98130841121495', name='percentage_change_tool', call_id='call_kB50RkFVqHptA7FOf0lL2RS8', is_error=False)]\n",
"---------- DataAnalystAgent ----------\n",
"85.98130841121495\n",
"---------- PlanningAgent ----------\n",
"The Miami Heat player with the highest points during the 2006-2007 NBA season was Dwayne Wade, who scored 1,397 points. The percentage increase in his total rebounds from the 2007-2008 season (214 rebounds) to the 2008-2009 season (398 rebounds) was approximately 86%.\n",
"\n",
"TERMINATE\n"
]
}
],
"source": [
"await main()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can then use the Jaeger UI to view the traces collected from the application run above. \n",
"\n",
"![Jaeger UI](jaeger.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Custom Traces \n",
"\n",
"So far, we are logging only the default events that are generated by the AutoGen runtime (message created, publish etc). However, you can also create custom spans to log specific events in your application. \n",
"\n",
"In the example below, we will show how to log messages from the `RoundRobinGroupChat` team as they are generated by adding custom spans around the team to log runtime events and spans to log messages generated by the team.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"-- primary_agent -- : Leaves cascade like gold, \n",
"Whispering winds cool the earth.\n",
"primary_agent: Leaves cascade like gold, \n",
"Whispering winds cool the earth.\n",
"\n",
"-- critic_agent -- : Your haiku beautifully captures the essence of the fall season with vivid imagery. However, it appears to have six syllables in the second line, which should traditionally be five. Here's a revised version keeping the 5-7-5 syllable structure:\n",
"\n",
"Leaves cascade like gold, \n",
"Whispering winds cool the air. \n",
"\n",
"Please adjust the second line to reflect a five-syllable count. Thank you!\n",
"critic_agent: Your haiku beautifully captures the essence of the fall season with vivid imagery. However, it appears to have six syllables in the second line, which should traditionally be five. Here's a revised version keeping the 5-7-5 syllable structure:\n",
"\n",
"Leaves cascade like gold, \n",
"Whispering winds cool the air. \n",
"\n",
"Please adjust the second line to reflect a five-syllable count. Thank you!\n",
"\n",
"-- primary_agent -- : Leaves cascade like gold, \n",
"Whispering winds cool the air.\n",
"primary_agent: Leaves cascade like gold, \n",
"Whispering winds cool the air.\n",
"\n",
"-- critic_agent -- : APPROVE\n",
"critic_agent: APPROVE\n"
]
}
],
"source": [
"from autogen_agentchat.base import TaskResult\n",
"from autogen_agentchat.conditions import ExternalTermination\n",
"from autogen_agentchat.teams import RoundRobinGroupChat\n",
"from autogen_core import CancellationToken\n",
"\n",
"\n",
"async def run_agents() -> None:\n",
" # Create an OpenAI model client.\n",
" model_client = OpenAIChatCompletionClient(model=\"gpt-4o-2024-08-06\")\n",
"\n",
" # Create the primary agent.\n",
" primary_agent = AssistantAgent(\n",
" \"primary_agent\",\n",
" model_client=model_client,\n",
" system_message=\"You are a helpful AI assistant.\",\n",
" )\n",
"\n",
" # Create the critic agent.\n",
" critic_agent = AssistantAgent(\n",
" \"critic_agent\",\n",
" model_client=model_client,\n",
" system_message=\"Provide constructive feedback. Respond with 'APPROVE' to when your feedbacks are addressed.\",\n",
" )\n",
"\n",
" # Define a termination condition that stops the task if the critic approves.\n",
" text_termination = TextMentionTermination(\"APPROVE\")\n",
"\n",
" tracer = trace.get_tracer(\"autogen-test-agentchat\")\n",
" with tracer.start_as_current_span(\"runtime_round_robin_events\"):\n",
" team = RoundRobinGroupChat([primary_agent, critic_agent], termination_condition=text_termination)\n",
"\n",
" response_stream = team.run_stream(task=\"Write a 2 line haiku about the fall season\")\n",
" async for response in response_stream:\n",
" async for response in response_stream:\n",
" if not isinstance(response, TaskResult):\n",
" print(f\"\\n-- {response.source} -- : {response.to_text()}\")\n",
" with tracer.start_as_current_span(f\"agent_message.{response.source}\") as message_span:\n",
" message_span.set_attribute(\"agent.name\", response.source)\n",
" message_span.set_attribute(\"message.content\", response.to_text())\n",
" print(f\"{response.source}: {response.to_text()}\")\n",
"\n",
" await model_client.close()\n",
"\n",
"\n",
"await run_agents()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"In the code above, we create a new span for each message sent by the agent. We set attributes on the span to include the agent's name and the message content. This allows us to trace the flow of messages through our application and understand how they are processed."
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tracing and Observability\n",
"\n",
"AutoGen has [built-in support for tracing](https://microsoft.github.io/autogen/dev/user-guide/core-user-guide/framework/telemetry.html) and observability for collecting comprehensive records on the execution of your application. This feature is useful for debugging, performance analysis, and understanding the flow of your application.\n",
"\n",
"This capability is powered by the [OpenTelemetry](https://opentelemetry.io/) library, which means you can use any OpenTelemetry-compatible backend to collect and analyze traces.\n",
"\n",
"AutoGen follows the [OpenTelemetry Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/) for tracing, for agents and tools.\n",
"It also follows the [Semantic Conventions for GenAI Systems](https://opentelemetry.io/docs/specs/semconv/gen-ai/) currently under development.\n",
"\n",
"## Setup\n",
"\n",
"To begin, you need to install the OpenTelemetry Python package. You can do this using pip:\n",
"\n",
"```bash\n",
"pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc opentelemetry-instrumentation-openai\n",
"```\n",
"\n",
"Once you have the SDK installed, the simplest way to set up tracing in AutoGen is to:\n",
"\n",
"1. Configure an OpenTelemetry tracer provider\n",
"2. Set up an exporter to send traces to your backend\n",
"3. Connect the tracer provider to the AutoGen runtime\n",
"\n",
"## Telemetry Backend\n",
"\n",
"To collect and view traces, you need to set up a telemetry backend. Several open-source options are available, including Jaeger, Zipkin. For this example, we will use Jaeger as our telemetry backend.\n",
"\n",
"For a quick start, you can run Jaeger locally using Docker:\n",
"\n",
"```bash\n",
"docker run -d --name jaeger \\\n",
" -e COLLECTOR_OTLP_ENABLED=true \\\n",
" -p 16686:16686 \\\n",
" -p 4317:4317 \\\n",
" -p 4318:4318 \\\n",
" jaegertracing/all-in-one:latest\n",
"```\n",
"\n",
"This command starts a Jaeger instance that listens on port 16686 for the Jaeger UI and port 4317 for the OpenTelemetry collector. You can access the Jaeger UI at `http://localhost:16686`.\n",
"\n",
"## Tracing an AgentChat Team\n",
"\n",
"In the following section, we will review how to enable tracing with an AutoGen GroupChat team. The AutoGen runtime already supports open telemetry (automatically logging message metadata). To begin, we will create a tracing service that will be used to instrument the AutoGen runtime. "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Overriding of current TracerProvider is not allowed\n",
"Attempting to instrument while already instrumented\n"
]
}
],
"source": [
"from opentelemetry import trace\n",
"from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\n",
"from opentelemetry.instrumentation.openai import OpenAIInstrumentor\n",
"from opentelemetry.sdk.resources import Resource\n",
"from opentelemetry.sdk.trace import TracerProvider\n",
"from opentelemetry.sdk.trace.export import BatchSpanProcessor\n",
"\n",
"# Set up telemetry span exporter.\n",
"otel_exporter = OTLPSpanExporter(endpoint=\"http://localhost:4317\", insecure=True)\n",
"span_processor = BatchSpanProcessor(otel_exporter)\n",
"\n",
"# Set up telemetry trace provider.\n",
"tracer_provider = TracerProvider(resource=Resource({\"service.name\": \"autogen-test-agentchat\"}))\n",
"tracer_provider.add_span_processor(span_processor)\n",
"trace.set_tracer_provider(tracer_provider)\n",
"\n",
"# Instrument the OpenAI Python library\n",
"OpenAIInstrumentor().instrument()\n",
"\n",
"# we will get reference this tracer later using its service name\n",
"# tracer = trace.get_tracer(\"autogen-test-agentchat\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All of the code to create a [team](./tutorial/teams.ipynb) should already be familiar to you.\n",
"\n",
"```{note}\n",
"AgentChat teams are run using the AutoGen Core's agent runtime.\n",
"In turn, the runtime is already instrumented to log, see [Core Telemetry Guide](../core-user-guide/framework/telemetry.md).\n",
"To disable the agent runtime telemetry, you can set the `trace_provider` to\n",
"`opentelemetry.trace.NoOpTraceProvider` in the runtime constructor.\n",
"\n",
"Additionally, you can set the environment varibale `AUTOGEN_DISABLE_RUNTIME_TRACING` to `true` to disable the agent runtime telemetry if you don't have access to the runtime constructor. For example, if you are using `ComponentConfig`.\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"from autogen_agentchat.agents import AssistantAgent\n",
"from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination\n",
"from autogen_agentchat.teams import SelectorGroupChat\n",
"from autogen_agentchat.ui import Console\n",
"from autogen_core import SingleThreadedAgentRuntime\n",
"from autogen_ext.models.openai import OpenAIChatCompletionClient\n",
"\n",
"\n",
"def search_web_tool(query: str) -> str:\n",
" if \"2006-2007\" in query:\n",
" return \"\"\"Here are the total points scored by Miami Heat players in the 2006-2007 season:\n",
" Udonis Haslem: 844 points\n",
" Dwayne Wade: 1397 points\n",
" James Posey: 550 points\n",
" ...\n",
" \"\"\"\n",
" elif \"2007-2008\" in query:\n",
" return \"The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.\"\n",
" elif \"2008-2009\" in query:\n",
" return \"The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.\"\n",
" return \"No data found.\"\n",
"\n",
"\n",
"def percentage_change_tool(start: float, end: float) -> float:\n",
" return ((end - start) / start) * 100\n",
"\n",
"\n",
"async def main() -> None:\n",
" model_client = OpenAIChatCompletionClient(model=\"gpt-4o\")\n",
"\n",
" # Get a tracer with the default tracer provider.\n",
" tracer = trace.get_tracer(\"tracing-autogen-agentchat\")\n",
"\n",
" # Use the tracer to create a span for the main function.\n",
" with tracer.start_as_current_span(\"run_team\"):\n",
" planning_agent = AssistantAgent(\n",
" \"PlanningAgent\",\n",
" description=\"An agent for planning tasks, this agent should be the first to engage when given a new task.\",\n",
" model_client=model_client,\n",
" system_message=\"\"\"\n",
" You are a planning agent.\n",
" Your job is to break down complex tasks into smaller, manageable subtasks.\n",
" Your team members are:\n",
" WebSearchAgent: Searches for information\n",
" DataAnalystAgent: Performs calculations\n",
"\n",
" You only plan and delegate tasks - you do not execute them yourself.\n",
"\n",
" When assigning tasks, use this format:\n",
" 1. <agent> : <task>\n",
"\n",
" After all tasks are complete, summarize the findings and end with \"TERMINATE\".\n",
" \"\"\",\n",
" )\n",
"\n",
" web_search_agent = AssistantAgent(\n",
" \"WebSearchAgent\",\n",
" description=\"An agent for searching information on the web.\",\n",
" tools=[search_web_tool],\n",
" model_client=model_client,\n",
" system_message=\"\"\"\n",
" You are a web search agent.\n",
" Your only tool is search_tool - use it to find information.\n",
" You make only one search call at a time.\n",
" Once you have the results, you never do calculations based on them.\n",
" \"\"\",\n",
" )\n",
"\n",
" data_analyst_agent = AssistantAgent(\n",
" \"DataAnalystAgent\",\n",
" description=\"An agent for performing calculations.\",\n",
" model_client=model_client,\n",
" tools=[percentage_change_tool],\n",
" system_message=\"\"\"\n",
" You are a data analyst.\n",
" Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.\n",
" If you have not seen the data, ask for it.\n",
" \"\"\",\n",
" )\n",
"\n",
" text_mention_termination = TextMentionTermination(\"TERMINATE\")\n",
" max_messages_termination = MaxMessageTermination(max_messages=25)\n",
" termination = text_mention_termination | max_messages_termination\n",
"\n",
" selector_prompt = \"\"\"Select an agent to perform task.\n",
"\n",
" {roles}\n",
"\n",
" Current conversation context:\n",
" {history}\n",
"\n",
" Read the above conversation, then select an agent from {participants} to perform the next task.\n",
" Make sure the planner agent has assigned tasks before other agents start working.\n",
" Only select one agent.\n",
" \"\"\"\n",
"\n",
" task = \"Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?\"\n",
"\n",
" runtime = SingleThreadedAgentRuntime(\n",
" tracer_provider=trace.NoOpTracerProvider(), # Disable telemetry for runtime.\n",
" )\n",
" runtime.start()\n",
"\n",
" team = SelectorGroupChat(\n",
" [planning_agent, web_search_agent, data_analyst_agent],\n",
" model_client=model_client,\n",
" termination_condition=termination,\n",
" selector_prompt=selector_prompt,\n",
" allow_repeated_speaker=True,\n",
" runtime=runtime,\n",
" )\n",
" await Console(team.run_stream(task=task))\n",
"\n",
" await runtime.stop()\n",
"\n",
" await model_client.close()\n",
"\n",
"\n",
"# asyncio.run(main())"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"---------- TextMessage (user) ----------\n",
"Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?\n",
"---------- TextMessage (PlanningAgent) ----------\n",
"To find the information requested, we need to follow these steps:\n",
"\n",
"1. Identify the Miami Heat player with the highest points during the 2006-2007 season.\n",
"2. Get the total rebounds for that player in both the 2007-2008 and 2008-2009 seasons.\n",
"3. Calculate the percentage change in total rebounds between these two seasons.\n",
"\n",
"Here are the tasks assigned to achieve this:\n",
"\n",
"1. WebSearchAgent: Find the Miami Heat player with the highest points during the 2006-2007 season.\n",
"2. WebSearchAgent: After identifying the player, find the total rebounds for that player in the 2007-2008 and 2008-2009 seasons.\n",
"3. DataAnalystAgent: Calculate the percentage change in the player's total rebounds between the 2007-2008 and 2008-2009 seasons.\n",
"---------- ToolCallRequestEvent (WebSearchAgent) ----------\n",
"[FunctionCall(id='call_hS8yod9l6CYUllDveUffp58e', arguments='{\"query\":\"Miami Heat leading scorer 2006-2007 season\"}', name='search_web_tool')]\n",
"---------- ToolCallExecutionEvent (WebSearchAgent) ----------\n",
"[FunctionExecutionResult(content='Here are the total points scored by Miami Heat players in the 2006-2007 season:\\n Udonis Haslem: 844 points\\n Dwayne Wade: 1397 points\\n James Posey: 550 points\\n ...\\n ', name='search_web_tool', call_id='call_hS8yod9l6CYUllDveUffp58e', is_error=False)]\n",
"---------- ToolCallSummaryMessage (WebSearchAgent) ----------\n",
"Here are the total points scored by Miami Heat players in the 2006-2007 season:\n",
" Udonis Haslem: 844 points\n",
" Dwayne Wade: 1397 points\n",
" James Posey: 550 points\n",
" ...\n",
" \n",
"---------- ToolCallRequestEvent (WebSearchAgent) ----------\n",
"[FunctionCall(id='call_bUJxtpxUXFSxECDogye9WL0g', arguments='{\"query\":\"Dwyane Wade total rebounds in 2007-2008 season\"}', name='search_web_tool')]\n",
"---------- ToolCallExecutionEvent (WebSearchAgent) ----------\n",
"[FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.', name='search_web_tool', call_id='call_bUJxtpxUXFSxECDogye9WL0g', is_error=False)]\n",
"---------- ToolCallSummaryMessage (WebSearchAgent) ----------\n",
"The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.\n",
"---------- ToolCallRequestEvent (WebSearchAgent) ----------\n",
"[FunctionCall(id='call_pgYNSDhhyodtteot56FRktxp', arguments='{\"query\":\"Dwyane Wade total rebounds in 2008-2009 season\"}', name='search_web_tool')]\n",
"---------- ToolCallExecutionEvent (WebSearchAgent) ----------\n",
"[FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.', name='search_web_tool', call_id='call_pgYNSDhhyodtteot56FRktxp', is_error=False)]\n",
"---------- ToolCallSummaryMessage (WebSearchAgent) ----------\n",
"The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.\n",
"---------- ToolCallRequestEvent (DataAnalystAgent) ----------\n",
"[FunctionCall(id='call_A89acjYHlNDLzG09rVNJ0J6H', arguments='{\"start\":214,\"end\":398}', name='percentage_change_tool')]\n",
"---------- ToolCallExecutionEvent (DataAnalystAgent) ----------\n",
"[FunctionExecutionResult(content='85.98130841121495', name='percentage_change_tool', call_id='call_A89acjYHlNDLzG09rVNJ0J6H', is_error=False)]\n",
"---------- ToolCallSummaryMessage (DataAnalystAgent) ----------\n",
"85.98130841121495\n",
"---------- TextMessage (PlanningAgent) ----------\n",
"The Miami Heat player with the highest points during the 2006-2007 season was Dwyane Wade, who scored 1,397 points. \n",
"\n",
"The total rebounds for Dwyane Wade in the 2007-2008 season were 214, and in the 2008-2009 season, they were 398.\n",
"\n",
"The percentage change in his total rebounds between these two seasons is approximately 86.0%.\n",
"\n",
"TERMINATE\n"
]
}
],
"source": [
"await main()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can then use the Jaeger UI to view the traces collected from the application run above. \n",
"\n",
"![Jaeger UI](jaeger.png)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

View File

@ -162,6 +162,7 @@
"metadata": {},
"outputs": [],
"source": [
"from autogen_core.models import UserMessage\n",
"from autogen_ext.auth.azure import AzureTokenProvider\n",
"from autogen_ext.models.openai import AzureOpenAIChatCompletionClient\n",
"from azure.identity import DefaultAzureCredential\n",
@ -427,6 +428,59 @@
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Llama API (experimental)\n",
"\n",
"[Llama API](https://llama.developer.meta.com?utm_source=partner-autogen&utm_medium=readme) is the Meta's first party API offering. It currently offers an [OpenAI compatible endpoint](https://llama.developer.meta.com/docs/features/compatibility).\n",
"So you can use the {py:class}`~autogen_ext.models.openai.OpenAIChatCompletionClient` with the Llama API.\n",
"\n",
"This endpoint fully supports the following OpenAI client library features:\n",
"* Chat completions\n",
"* Model selection\n",
"* Temperature/sampling\n",
"* Streaming\n",
"* Image understanding\n",
"* Structured output (JSON mode)\n",
"* Funciton calling (tools)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pathlib import Path\n",
"\n",
"from autogen_core import Image\n",
"from autogen_core.models import UserMessage\n",
"from autogen_ext.models.openai import OpenAIChatCompletionClient\n",
"\n",
"# Text\n",
"model_client = OpenAIChatCompletionClient(\n",
" model=\"Llama-4-Scout-17B-16E-Instruct-FP8\",\n",
" # api_key=\"LLAMA_API_KEY\"\n",
")\n",
"\n",
"response = await model_client.create([UserMessage(content=\"Write me a poem\", source=\"user\")])\n",
"print(response)\n",
"await model_client.close()\n",
"\n",
"# Image\n",
"model_client = OpenAIChatCompletionClient(\n",
" model=\"Llama-4-Maverick-17B-128E-Instruct-FP8\",\n",
" # api_key=\"LLAMA_API_KEY\"\n",
")\n",
"image = Image.from_file(Path(\"test.png\"))\n",
"\n",
"response = await model_client.create([UserMessage(content=[\"What is in this image\", image], source=\"user\")])\n",
"print(response)\n",
"await model_client.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},

View File

@ -112,7 +112,7 @@
"source": [
"```{note}\n",
"For {py:class}`~autogen_agentchat.agents.AssistantAgent`, its state consists of the model_context.\n",
"If your write your own custom agent, consider overriding the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.save_state` and {py:meth}`~autogen_agentchat.agents.BaseChatAgent.load_state` methods to customize the behavior. The default implementations save and load an empty state.\n",
"If you write your own custom agent, consider overriding the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.save_state` and {py:meth}`~autogen_agentchat.agents.BaseChatAgent.load_state` methods to customize the behavior. The default implementations save and load an empty state.\n",
"```"
]
},

View File

@ -16,6 +16,7 @@
"- {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`: A team that runs a group chat with participants taking turns in a round-robin fashion (covered on this page). [Tutorial](#creating-a-team) \n",
"- {py:class}`~autogen_agentchat.teams.SelectorGroupChat`: A team that selects the next speaker using a ChatCompletion model after each message. [Tutorial](../selector-group-chat.ipynb)\n",
"- {py:class}`~autogen_agentchat.teams.MagenticOneGroupChat`: A generalist multi-agent system for solving open-ended web and file-based tasks across a variety of domains. [Tutorial](../magentic-one.md) \n",
"- {py:class}`~autogen_agentchat.teams.Swarm`: A team that uses {py:class}`~autogen_agentchat.messages.HandoffMessage` to signal transitions between agents. [Tutorial](../swarm.ipynb)\n",
"\n",
"```{note}\n",
"\n",
@ -589,6 +590,13 @@
"source": [
"## Single-Agent Team\n",
"\n",
"```{note}\n",
"Starting with version 0.6.2, you can use {py:class}`~autogen_agentchat.agents.AssistantAgent`\n",
"with `max_tool_iterations` to run the agent with multiple iterations\n",
"of tool calls. So you may not need to use a single-agent team if you just \n",
"want to run the agent in a tool-calling loop.\n",
"```\n",
"\n",
"Often, you may want to run a single agent in a team configuration.\n",
"This is useful for running the {py:class}`~autogen_agentchat.agents.AssistantAgent` in a loop\n",
"until a termination condition is met.\n",
@ -697,7 +705,7 @@
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"display_name": "python",
"language": "python",
"name": "python3"
},
@ -711,7 +719,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
"version": "3.12.11"
}
},
"nbformat": 4,

View File

@ -40,7 +40,8 @@
"7. {py:class}`~autogen_agentchat.conditions.ExternalTermination`: Enables programmatic control of termination from outside the run. This is useful for UI integration (e.g., \"Stop\" buttons in chat interfaces).\n",
"8. {py:class}`~autogen_agentchat.conditions.StopMessageTermination`: Stops when a {py:class}`~autogen_agentchat.messages.StopMessage` is produced by an agent.\n",
"9. {py:class}`~autogen_agentchat.conditions.TextMessageTermination`: Stops when a {py:class}`~autogen_agentchat.messages.TextMessage` is produced by an agent.\n",
"10. {py:class}`~autogen_agentchat.conditions.FunctionCallTermination`: Stops when a {py:class}`~autogen_agentchat.messages.ToolCallExecutionEvent` containing a {py:class}`~autogen_core.models.FunctionExecutionResult` with a matching name is produced by an agent."
"10. {py:class}`~autogen_agentchat.conditions.FunctionCallTermination`: Stops when a {py:class}`~autogen_agentchat.messages.ToolCallExecutionEvent` containing a {py:class}`~autogen_core.models.FunctionExecutionResult` with a matching name is produced by an agent.\n",
"11. {py:class}`~autogen_agentchat.conditions.FunctionalTermination`: Stop when a function expression is evaluated to `True` on the last delta sequence of messages. This is useful for quickly create custom termination conditions that are not covered by the built-in ones."
]
},
{
@ -510,7 +511,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -19,11 +19,18 @@ We recommend using a virtual environment as this will ensure that the dependenci
Create and activate:
Linux/Mac:
```bash
python3 -m venv .venv
source .venv/bin/activate
```
Windows command-line:
```batch
python3 -m venv .venv
.venv\Scripts\activate.bat
```
To deactivate later, run:
```bash

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,502 @@
name,NSE_code,BSE_code,sector,industry,revenue,operating_expenses,operating_profit,operating_profit_margin,depreciation,interest,profit_before_tax,tax,net_profit,EPS,profit_TTM,EPS_TTM
3M India Ltd.,3MINDIA,523395,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,"1,057",847.4,192.1,18.48%,12.9,0.7,195.9,49.8,146.1,129.7,535.9,475.7
ACC Ltd.,ACC,500410,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"4,644.8","3,885.4",549.3,12.39%,212.8,28.9,517.7,131.5,387.9,20.7,"1,202.7",64
AIA Engineering Ltd.,AIAENG,532683,GENERAL INDUSTRIALS,OTHER INDUSTRIAL GOODS,"1,357.1",912.7,382.1,29.51%,24.5,7.4,412.5,88.4,323.1,34.3,"1,216.1",128.9
APL Apollo Tubes Ltd.,APLAPOLLO,533758,METALS & MINING,IRON & STEEL PRODUCTS,"4,65","4,305.4",325,7.02%,41.3,26.6,276.7,73.8,202.9,7.3,767.5,27.7
Au Small Finance Bank Ltd.,AUBANK,540611,BANKING AND FINANCE,BANKS,"2,956.5","1,026.7",647.7,25.59%,0,"1,282.1",533.4,131.5,401.8,6,"1,606.2",24
Adani Ports & Special Economic Zone Ltd.,ADANIPORTS,532921,TRANSPORTATION,MARINE PORT & SERVICES,"6,951.9","2,982.4","3,664",55.13%,974.5,520.1,"2,474.9",759,"1,747.8",8.1,"6,337",29.3
Adani Energy Solutions Ltd.,ADANIENSOL,ASM,UTILITIES,ELECTRIC UTILITIES,"3,766.5","2,169.3","1,504.6",40.95%,432.1,640.8,369.9,84.9,275.9,2.5,"1,315.1",11.8
Aditya Birla Fashion and Retail Ltd.,ABFRL,535755,RETAILING,DEPARTMENT STORES,"3,272.2","2,903.6",322.9,10.01%,388.8,208.4,-228.6,-28.2,-179.2,-1.9,-491.7,-5.2
Aegis Logistics Ltd.,AEGISCHEM,500003,OIL & GAS,OIL MARKETING & DISTRIBUTION,"1,279.3","1,026.5",208.3,16.87%,34.1,26.6,192,42,127,3.6,509,14.5
Ajanta Pharma Ltd.,AJANTPHARM,532331,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,049.8",737.8,290.7,28.26%,33.7,2.3,275.9,80.6,195.3,15.5,660.2,52.3
Alembic Pharmaceuticals Ltd.,APLLTD,533573,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,605.1","1,386.7",208.2,13.06%,67.6,15.7,135.1,-1.9,136.6,7,531.7,27
Alkem Laboratories Ltd.,ALKEM,539523,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"3,503.4","2,693.4",746.7,21.71%,73.9,30.3,648,33.1,620.5,51.9,"1,432.9",119.9
Amara Raja Energy & Mobility Ltd.,ARE&M,500008,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"2,988.6","2,556.9",402.5,13.60%,115.7,6.2,309.8,83.5,226.3,13.2,779.8,45.7
Ambuja Cements Ltd.,AMBUJACEM,500425,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"7,9","6,122.1","1,301.8",17.54%,380.9,61.2,"1,335.7",352.5,793,4,"2,777.9",14
Apollo Hospitals Enterprise Ltd.,APOLLOHOSP,508869,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,"4,869.1","4,219.4",627.5,12.95%,163.4,111.3,376.9,130.2,232.9,16.2,697.5,48.5
Apollo Tyres Ltd.,APOLLOTYRE,500877,AUTOMOBILES & AUTO COMPONENTS,AUTO TYRES & RUBBER PRODUCTS,"6,304.9","5,119.8","1,159.8",18.47%,360.3,132.8,679.9,205.8,474.3,7.5,"1,590.7",25
Ashok Leyland Ltd.,ASHOKLEY,500477,AUTOMOBILES & AUTO COMPONENTS,COMMERCIAL VEHICLES,"11,463","9,558.6","1,870.4",16.37%,226.6,715.1,924.4,358,526,1.8,"2,141.5",7.3
Asian Paints Ltd.,ASIANPAINT,500820,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,"8,643.8","6,762.3","1,716.2",20.24%,208.7,50.9,"1,621.8",418.6,"1,205.4",12.6,"5,062.6",52.8
Astral Ltd.,ASTRAL,532830,GENERAL INDUSTRIALS,PLASTIC PRODUCTS,"1,376.4","1,142.9",220.1,16.15%,48.7,8,176.8,45.1,131.2,4.9,549.7,20.4
Atul Ltd.,ATUL,500027,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"1,215.8","1,038.5",155.2,13.00%,54,1.9,121.5,32.5,90.3,30.6,392.3,132.9
Aurobindo Pharma Ltd.,AUROPHARMA,524804,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"7,406.4","5,846","1,373.4",19.02%,417.5,68.2,"1,074.7",323.7,757.2,12.8,"2,325.5",39.7
Avanti Feeds Ltd.,AVANTIFEED,512573,FOOD BEVERAGES & TOBACCO,OTHER FOOD PRODUCTS,"1,312","1,184.5",94,7.35%,14.3,0.2,113,30.5,74.2,5.5,336.4,24.7
Avenue Supermarts Ltd.,DMART,540376,RETAILING,DEPARTMENT STORES,"12,661.3","11,619.4","1,005",7.96%,174.4,15.6,851.9,228.6,623.6,9.6,"2,332.1",35.8
Axis Bank Ltd.,AXISBANK,532215,BANKING AND FINANCE,BANKS,"33,122.2","9,207.3","9,166",33.43%,0,"14,749","8,313.8","2,096.1","6,204.1",20.1,"13,121",42.6
Bajaj Auto Ltd.,BAJAJ-AUTO,532977,AUTOMOBILES & AUTO COMPONENTS,2/3 WHEELERS,"11,206.8","8,708.1","2,130.1",19.65%,91.8,6.5,"2,400.4",564,"2,02",71.4,"6,841.6",241.8
Bajaj Finance Ltd.,BAJFINANCE,500034,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"13,381.8","2,851.5","9,449.7",70.63%,158.5,"4,537.1","4,757.6","1,207","3,550.8",58.7,"13,118.5",216.7
Bajaj Finserv Ltd.,BAJAJFINSV,532978,DIVERSIFIED,HOLDING COMPANIES,"26,022.7","14,992.2","9,949.9",38.24%,208.8,"4,449.1","5,292","1,536.5","1,929",12.1,"7,422.6",46.6
Bajaj Holdings & Investment Ltd.,BAJAJHLDNG,500490,DIVERSIFIED,HOLDING COMPANIES,240.1,33.5,191.2,85.08%,8.4,0.2,197.9,73.9,"1,491.2",134,"5,545.1",498.3
Balkrishna Industries Ltd.,BALKRISIND,502355,AUTOMOBILES & AUTO COMPONENTS,AUTO TYRES & RUBBER PRODUCTS,"2,360.3","1,720.5",532.7,23.64%,160.4,23.9,455.5,108.1,347.4,18,"1,047.5",54.2
Balrampur Chini Mills Ltd.,BALRAMCHIN,500038,FOOD BEVERAGES & TOBACCO,SUGAR,"1,649","1,374.6",164.9,10.71%,41.2,17.2,215.9,56.6,166.3,8.2,540.5,26.8
Bank of Baroda,BANKBARODA,532134,BANKING AND FINANCE,BANKS,"35,766","8,430.4","9,807.9",33.52%,0,"17,527.7","6,022.8","1,679.7","4,458.4",8.5,"18,602.9",35.9
Bank of India,BANKINDIA,532149,BANKING AND FINANCE,BANKS,"16,779.4","3,704.9","3,818.8",25.35%,0,"9,255.7","2,977.4","1,488.6","1,498.5",3.6,"5,388.7",13.1
Bata India Ltd.,BATAINDIA,500043,RETAILING,FOOTWEAR,834.6,637.5,181.7,22.18%,81.7,28.4,46.1,12.1,34,2.6,289.7,22.5
Berger Paints (India) Ltd.,BERGEPAINT,509480,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,"2,782.6","2,293.7",473.6,17.12%,82.9,21.1,385,96.7,291.6,2.5,"1,032.6",8.9
Bharat Electronics Ltd.,BEL,500049,GENERAL INDUSTRIALS,DEFENCE,"4,146.1","2,994.9","1,014.2",25.30%,108.3,1.5,"1,041.5",260.7,789.4,1.1,"3,323",4.5
Bharat Forge Ltd.,BHARATFORG,500493,GENERAL INDUSTRIALS,OTHER INDUSTRIAL PRODUCTS,"3,826.7","3,152.8",621.4,16.47%,211.3,124.3,336.1,121.8,227.2,4.9,783.7,16.8
Bharat Heavy Electricals Ltd.,BHEL,500103,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"5,305.4","5,513",-387.7,-7.56%,59.9,180.4,-447.9,-197.9,-238.1,-0.7,71.3,0.2
Bharat Petroleum Corporation Ltd.,BPCL,500547,OIL & GAS,REFINERIES/PETRO-PRODUCTS,"103,72","90,103.9","12,940.5",12.56%,"1,605.3",973.2,"10,755.7","2,812.2","8,243.5",38.7,"27,505.3",129.2
Bharti Airtel Ltd.,BHARTIARTL,532454,TELECOM SERVICES,TELECOM SERVICES,"37,374.2","17,530.1","19,513.7",52.68%,"9,734.3","5,185.8","3,353.7","1,846.5","1,340.7",2.4,"7,547",13.2
Indus Towers Ltd.,INDUSTOWER,534816,TELECOM SERVICES,OTHER TELECOM SERVICES,"7,229.7","3,498.8","3,633.7",50.95%,"1,525.6",458.6,"1,746.7",452,"1,294.7",4.8,"3,333.5",12.4
Biocon Ltd.,BIOCON,532523,PHARMACEUTICALS & BIOTECHNOLOGY,BIOTECHNOLOGY,"3,620.2","2,720.7",741.6,21.42%,389.3,247.7,238.5,41.6,125.6,1.1,498.4,4.2
Birla Corporation Ltd.,BIRLACORPN,500335,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"2,313.2","1,997",288.9,12.64%,143.5,95.4,77.1,18.8,58.4,7.6,153.1,19.9
Blue Dart Express Ltd.,BLUEDART,526612,TRANSPORTATION,TRANSPORTATION - LOGISTICS,"1,329.7","1,101.8",222.7,16.82%,110.6,19.5,97.9,24.8,73.1,30.8,292.4,123.2
Blue Star Ltd.,BLUESTARCO,500067,CONSUMER DURABLES,CONSUMER ELECTRONICS,"1,903.4","1,767.7",122.7,6.49%,23,17.6,95,24.3,70.7,3.6,437.7,21.3
Bombay Burmah Trading Corporation Ltd.,BBTC,501425,FOOD BEVERAGES & TOBACCO,TEA & COFFEE,"4,643.5","3,664.7",859.2,18.99%,74.7,154.6,697.1,212.6,122,17.5,"-1,499.5",-214.8
Bosch Ltd.,BOSCHLTD,500530,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"4,284.3","3,638.8",491.3,11.90%,101.3,12.2,"1,317",318.1,999.8,339,"2,126.9",721
Brigade Enterprises Ltd.,BRIGADE,532929,REALTY,REALTY,"1,407.9","1,041.8",324.8,23.77%,75.7,110,180.3,67.8,133.5,5.8,298.2,12.9
Britannia Industries Ltd.,BRITANNIA,500825,FMCG,PACKAGED FOODS,"4,485.2","3,560.5",872.4,19.68%,71.7,53.4,799.7,212.1,587.6,24.4,"2,536.2",105.3
CCL Products India Ltd.,CCL,519600,FOOD BEVERAGES & TOBACCO,TEA & COFFEE,608.3,497.7,109.9,18.09%,22.6,18.4,69.7,8.8,60.9,4.6,279.9,21
Crisil Ltd.,CRISIL,500092,BANKING AND FINANCE,OTHER FINANCIAL SERVICES,771.8,544.2,191.7,26.05%,26.5,0.8,200.3,48.3,152,20.8,606.3,82.9
Zydus Lifesciences Ltd.,ZYDUSLIFE,532321,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"4,422.8","3,222.7","1,146.1",26.23%,184.2,8.7,"1,007.2",226.4,800.7,7.9,"2,807.1",27.7
Can Fin Homes Ltd.,CANFINHOME,511196,BANKING AND FINANCE,HOUSING FINANCE,871,49.7,749.2,86.01%,2.8,548.4,198,39.9,158.1,11.9,658.8,49.5
Canara Bank,CANBK,532483,BANKING AND FINANCE,BANKS,"33,891.2","8,250.3","7,706.6",28.24%,0,"17,934.3","5,098","1,420.6","3,86",20.9,"13,968.4",77
Carborundum Universal Ltd.,CARBORUNIV,513375,GENERAL INDUSTRIALS,OTHER INDUSTRIAL PRODUCTS,"1,166",978.8,167.5,14.61%,45.9,4.9,136.4,43.7,101.9,5.4,461.3,24.3
Castrol India Ltd.,CASTROLIND,500870,OIL & GAS,OIL MARKETING & DISTRIBUTION,"1,203.2",914.4,268.6,22.70%,22.9,2.4,263.5,69.1,194.4,2,815.5,8.2
Ceat Ltd.,CEATLTD,500878,AUTOMOBILES & AUTO COMPONENTS,AUTO TYRES & RUBBER PRODUCTS,"3,063.8","2,597.2",456.1,14.94%,124.5,71.7,270.4,68.3,208,51.4,521.7,129
Central Bank of India,CENTRALBK,532885,BANKING AND FINANCE,BANKS,"8,438.5","2,565.4","1,535.4",20.81%,0,"4,337.7",567.2,-41.5,622,0.7,"2,181.4",2.5
Century Plyboards (India) Ltd.,CENTURYPLY,532548,FOREST MATERIALS,FOREST PRODUCTS,"1,011.4",852.5,144.3,14.47%,23.4,6.1,129.4,32.2,96.9,4.4,380.7,17.1
Cera Sanitaryware Ltd.,CERA,532443,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,476.2,387.2,76.5,16.49%,8.9,1.4,77.2,19.8,56.9,43.8,232.4,178.7
Chambal Fertilisers & Chemicals Ltd.,CHAMBLFERT,500085,FERTILIZERS,FERTILIZERS,"5,467.3","4,770.5",615,11.42%,78.4,45.8,572.6,200.2,381,9.2,"1,137.7",27.3
Cholamandalam Investment & Finance Company Ltd.,CHOLAFIN,511243,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"4,695.2",987.6,"3,235.1",69.99%,38.5,"2,204.2","1,065",288.8,772.9,9.4,"3,022.8",36.7
Cipla Ltd.,CIPLA,500087,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"6,854.5","4,944.4","1,733.8",25.96%,290,25.8,"1,594.2",438.4,"1,130.9",14,"3,449.1",42.7
City Union Bank Ltd.,CUB,532210,BANKING AND FINANCE,BANKS,"1,486.1",333.9,386.6,29.65%,0,765.6,330.6,50,280.6,3.8,943.8,12.7
Coal India Ltd.,COALINDIA,533278,METALS & MINING,COAL,"34,760.3","24,639.4","8,137",24.83%,"1,178.2",182.5,"8,760.2","2,036.5","6,799.8",11,"28,059.6",45.5
Colgate-Palmolive (India) Ltd.,COLPAL,500830,FMCG,PERSONAL PRODUCTS,"1,492.1",989,482.1,32.77%,44.3,1.1,457.8,117.8,340.1,12.5,"1,173.2",43.1
Container Corporation of India Ltd.,CONCOR,531344,COMMERCIAL SERVICES & SUPPLIES,WAREHOUSING AND LOGISTICS,"2,299.8","1,648.4",546.5,24.90%,153.1,16.5,481.8,119,367.4,6,"1,186.2",19.5
Coromandel International Ltd.,COROMANDEL,506395,FERTILIZERS,FERTILIZERS,"7,032.9","5,929.4","1,058.7",15.15%,54,46.2,"1,003.3",245,756.9,25.7,"2,024.2",68.8
Crompton Greaves Consumer Electricals Ltd.,CROMPTON,539876,CONSUMER DURABLES,HOUSEHOLD APPLIANCES,"1,797.2","1,607.8",174.5,9.79%,32.1,21.5,135.8,34.9,97.2,1.5,432,6.7
Cummins India Ltd.,CUMMINSIND,500480,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,"2,011.3","1,575.4",346.2,18.02%,38.3,6.8,390.9,99.6,329.1,11.9,"1,445.5",52.1
Cyient Ltd.,CYIENT,532175,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"1,792","1,452.7",325.8,18.32%,65.8,27,240.3,56.7,178.3,16.3,665.6,60.1
DCM Shriram Ltd.,DCMSHRIRAM,523367,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"2,73","2,593.9",114.1,4.21%,74,14.7,47.5,15.2,32.2,2.1,617.6,39.4
DLF Ltd.,DLF,532868,REALTY,REALTY,"1,476.4",885.3,462.4,34.31%,37,90.2,464,112.2,622.8,2.5,"2,239",9
Dabur India Ltd.,DABUR,500096,FMCG,PERSONAL PRODUCTS,"3,320.2","2,543",660.9,20.63%,98.3,28.1,650.8,144.3,515,2.9,"1,755.7",9.9
Delta Corp Ltd.,DELTACORP,532848,COMMERCIAL SERVICES & SUPPLIES,MISC. COMMERCIAL SERVICES,282.6,170.5,100.1,36.99%,16.9,2.7,92.4,23,69.4,2.6,273.3,10.2
Divi's Laboratories Ltd.,DIVISLAB,532488,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,995","1,43",479,25.09%,95,1,469,121,348,13.1,"1,331.8",50.3
Dr. Lal Pathlabs Ltd.,LALPATHLAB,539524,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE SERVICES,619.4,423.5,177.8,29.57%,35.9,7.8,152.2,41.5,109.3,13.2,301.4,36.1
Dr. Reddy's Laboratories Ltd.,DRREDDY,500124,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"7,217.6","4,888.8","2,008.3",29.09%,375.5,35.3,"1,912.5",434.5,"1,482.2",89.1,"5,091.2",305.2
EID Parry (India) Ltd.,EIDPARRY,500125,FOOD BEVERAGES & TOBACCO,OTHER FOOD PRODUCTS,"9,210.3","8,002","1,057.5",11.67%,101.2,74.2,"1,032.8",246.8,452.3,25.5,991,55.8
Eicher Motors Ltd.,EICHERMOT,505200,AUTOMOBILES & AUTO COMPONENTS,2/3 WHEELERS,"4,388.3","3,027.4","1,087.2",26.42%,142.5,12.7,"1,205.7",291.1,"1,016.2",37.1,"3,581",130.8
Emami Ltd.,EMAMILTD,531162,FMCG,PERSONAL PRODUCTS,876,631.2,233.7,27.02%,46.1,2.2,196.4,15.8,178.5,4.1,697.8,16
Endurance Technologies Ltd.,ENDURANCE,540153,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"2,560.5","2,226.7",318.3,12.51%,118.4,9.8,205.6,51.1,154.6,11,562.8,40
Engineers India Ltd.,ENGINERSIN,532178,COMMERCIAL SERVICES & SUPPLIES,CONSULTING SERVICES,833.6,691.3,98.5,12.47%,8.3,0.4,133.6,32.2,127.5,2.3,472.7,8.4
Escorts Kubota Ltd.,ESCORTS,500495,AUTOMOBILES & AUTO COMPONENTS,COMMERCIAL VEHICLES,"2,154.4","1,798.6",260.7,12.66%,40.8,3.1,311.9,79.7,223.3,20.6,910.5,82.4
Exide Industries Ltd.,EXIDEIND,500086,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"4,408.9","3,872.4",499.1,11.42%,141.5,29.7,365.3,95.2,269.4,3.2,872.7,10.3
Federal Bank Ltd.,FEDERALBNK,500469,BANKING AND FINANCE,BANKS,"6,548.2","1,603.8","1,400.3",24.18%,0,"3,544.1","1,342.7",342.6,994.1,4.3,"3,671.4",15.6
Finolex Cables Ltd.,FINCABLES,500144,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"1,229.3","1,041.3",146.1,12.30%,10.8,0.4,176.7,52.3,154.2,10.1,643.9,42.1
Finolex Industries Ltd.,FINPIPE,500940,GENERAL INDUSTRIALS,PLASTIC PRODUCTS,944.5,780.2,103,11.66%,27.4,12.5,124.5,35.4,98,1.6,459.3,7.4
Firstsource Solutions Ltd.,FSL,532809,SOFTWARE & SERVICES,BPO/KPO,"1,556.9","1,311.2",228.8,14.86%,65.4,26.1,154.3,27.8,126.5,1.9,551.7,7.9
GAIL (India) Ltd.,GAIL,532155,UTILITIES,UTILITIES,"33,191","29,405.5","3,580.2",10.85%,837.3,199.6,"2,748.7",696.3,"2,444.1",3.7,"5,283.8",8
GlaxoSmithKline Pharmaceuticals Ltd.,GLAXO,500660,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,985.2,667.5,289.5,30.25%,18.1,0.4,299.2,81.7,217.5,12.8,647.8,38.2
Glenmark Pharmaceuticals Ltd.,GLENMARK,532296,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"3,209.1","2,745.1",462.3,14.41%,141.5,121.5,-124.4,55.9,-81.9,-2.9,-196.3,-7
Godrej Consumer Products Ltd.,GODREJCP,532424,FMCG,PERSONAL PRODUCTS,"3,667.9","2,897.8",704.2,19.55%,60.9,77.3,619.4,186.6,432.8,4.2,"1,750.1",17.1
Godrej Industries Ltd.,GODREJIND,500164,DIVERSIFIED,DIVERSIFIED,"4,256.9","3,672.1",265.5,6.74%,89.3,333.1,162.4,75.9,87.3,2.6,880,26.1
Godrej Properties Ltd.,GODREJPROP,533150,REALTY,REALTY,605.1,404.7,-61.7,-17.98%,7.4,48,145.1,38.8,66.8,2.4,662.6,23.8
Granules India Ltd.,GRANULES,532482,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,191",976.5,213,17.90%,52.5,26,136,33.9,102.1,4.2,393.9,16.3
Great Eastern Shipping Company Ltd.,GESHIP,500620,TRANSPORTATION,SHIPPING,"1,461.5",585.6,643.4,52.35%,186.7,77.1,611.9,17.3,594.7,41.6,"2,520.1",176.5
Gujarat Alkalies & Chemicals Ltd.,GUJALKALI,530001,CHEMICALS & PETROCHEMICALS,COMMODITY CHEMICALS,"1,042.3",926.1,45.2,4.65%,95.2,10.8,10.2,-0.1,-18.4,-2.5,82.7,11.3
Gujarat Gas Ltd.,GUJGASLTD,539336,UTILITIES,UTILITIES,"4,019.3","3,494.5",496.6,12.44%,117.9,7.8,399.1,102.9,296.2,4.3,"1,254.3",18.2
Gujarat Narmada Valley Fertilizers & Chemicals Ltd.,GNFC,500670,FERTILIZERS,FERTILIZERS,"2,232","1,911",169,8.12%,78,1,242,64,182,11.7,932,60.1
Gujarat Pipavav Port Ltd.,GPPL,533248,TRANSPORTATION,MARINE PORT & SERVICES,270.4,102,150.6,59.64%,28.8,2.2,141.1,53.4,92.3,1.9,341.8,7.1
Gujarat State Fertilizer & Chemicals Ltd.,GSFC,500690,FERTILIZERS,FERTILIZERS,"3,313.2","2,881.4",237.3,7.61%,45.7,1.6,387,78.1,308.9,7.8,"1,056.2",26.5
Gujarat State Petronet Ltd.,GSPL,532702,UTILITIES,UTILITIES,"4,455.9","3,497.2",913.7,20.72%,165,14.5,779.2,198.7,454.6,8.1,"1,522",27
HCL Technologies Ltd.,HCLTECH,532281,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"27,037","20,743","5,929",22.23%,"1,01",156,"5,128","1,295","3,832",14.2,"15,445",56.9
HDFC Bank Ltd.,HDFCBANK,500180,BANKING AND FINANCE,BANKS,"107,566.6","42,037.6","24,279.1",32.36%,0,"41,249.9","20,967.4","3,655","16,811.4",22.2,"54,474.6",71.8
Havells India Ltd.,HAVELLS,517354,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"3,952.8","3,527",373.4,9.57%,81.2,9.3,335.3,86.2,249.1,4,"1,177.7",18.8
Hero MotoCorp Ltd.,HEROMOTOCO,500182,AUTOMOBILES & AUTO COMPONENTS,2/3 WHEELERS,"9,741.2","8,173.5","1,359.5",14.26%,187.1,25,"1,355.6",353.1,"1,006.3",50.3,"3,247.6",162.5
HFCL Ltd.,HFCL,500183,TELECOMMUNICATIONS EQUIPMENT,TELECOM CABLES,"1,128.7",978.9,132.6,11.93%,21.4,34.8,93.5,24,69.4,0.5,305.5,2.1
Hindalco Industries Ltd.,HINDALCO,500440,METALS & MINING,ALUMINIUM AND ALUMINIUM PRODUCTS,"54,632","48,557","5,612",10.36%,"1,843","1,034","3,231","1,035","2,196",9.9,"8,423",37.9
Hindustan Copper Ltd.,HINDCOPPER,513599,METALS & MINING,COPPER,392.6,260.2,121.2,31.77%,45.6,4.1,82.6,21.9,60.7,0.6,320.5,3.3
Hindustan Petroleum Corporation Ltd.,HINDPETRO,500104,OIL & GAS,REFINERIES/PETRO-PRODUCTS,"96,093.4","87,512","8,24",8.61%,"1,247.3",590,"6,744.1","1,616","5,827",41.1,"16,645",117.3
Hindustan Unilever Ltd.,HINDUNILVR,500696,FMCG,PERSONAL PRODUCTS,"15,806","11,826","3,797",24.30%,297,88,"3,59",931,"2,656",11.3,"10,284",43.8
Hindustan Zinc Ltd.,HINDZINC,500188,METALS & MINING,ZINC,"7,014","3,652","3,139",46.22%,825,232,"2,305",576,"1,729",4.1,"8,432",20
Housing and Urban Development Corporation Ltd.,HUDCO,540530,BANKING AND FINANCE,HOUSING FINANCE,"1,880.8",82.7,"1,809.6",97.04%,2.4,"1,216.8",606.4,154.7,451.6,2.3,"1,790.7",8.9
ITC Ltd.,ITC,500875,FOOD BEVERAGES & TOBACCO,CIGARETTES-TOBACCO PRODUCTS,"18,439.3","11,320.2","6,454.2",36.31%,453,9.9,"6,656.2","1,700.3","4,898.1",3.9,"20,185.1",16.2
ICICI Bank Ltd.,ICICIBANK,532174,BANKING AND FINANCE,BANKS,"57,292.3","23,911","15,473.2",39.74%,0,"17,908","14,824.2","3,808.8","11,805.6",15.6,"41,086.8",58.7
ICICI Prudential Life Insurance Company Ltd.,ICICIPRULI,540133,BANKING AND FINANCE,LIFE INSURANCE,"17,958.1","17,612.3",-229.6,-1.32%,0,0,340.2,32.5,243.9,1.7,906.9,6.3
IDBI Bank Ltd.,IDBI,500116,BANKING AND FINANCE,BANKS,"7,063.7","1,922.3","2,175.3",36.02%,0,"2,966.1","2,396.9","1,003.7","1,385.4",1.3,"4,776.3",4.4
IDFC First Bank Ltd.,IDFCFIRSTB,539437,BANKING AND FINANCE,BANKS,"8,765.8","3,849","1,511.2",20.54%,0,"3,405.6",982.8,236,746.9,1.1,"2,911.1",4.3
IDFC Ltd.,IDFC,532659,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),36.7,6,30.6,83.56%,0,0,30.6,6.6,223.5,1.4,"4,147.1",25.9
IRB Infrastructure Developers Ltd.,IRB,532947,CEMENT AND CONSTRUCTION,ROADS & HIGHWAYS,"1,874.5",950.4,794.6,45.54%,232.7,434.6,256.9,85.8,95.7,0.2,501,0.8
ITI Ltd.,ITI,523610,TELECOMMUNICATIONS EQUIPMENT,TELECOM EQUIPMENT,256.1,299.3,-52.8,-21.42%,13.3,69.3,-125.8,0,-126,-1.3,-388.4,-4
Vodafone Idea Ltd.,IDEA,532822,TELECOM SERVICES,TELECOM SERVICES,"10,750.8","6,433.5","4,282.8",39.97%,"5,667.3","6,569","-7,919",817.7,"-8,737.9",-1.8,"-30,986.8",-6.4
India Cements Ltd.,INDIACEM,530005,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"1,272.4","1,26",4.4,0.35%,55,60.4,-103,-17.4,-80.1,-2.6,-261.1,-8.4
Indiabulls Housing Finance Ltd.,IBULHSGFIN,535789,BANKING AND FINANCE,HOUSING FINANCE,"2,242.3",190.6,"1,779.2",79.88%,22.9,"1,349.8",421.6,123.6,298,6.5,"1,146",24.3
Indian Bank,INDIANB,532814,BANKING AND FINANCE,BANKS,"15,929.4","3,599.1","4,327.7",31.44%,0,"8,002.6","2,776.7",768.6,"2,068.5",16.6,"6,893.3",55.3
Indian Hotels Company Ltd.,INDHOTEL,500850,HOTELS RESTAURANTS & TOURISM,HOTELS,"1,480.9","1,078.4",354.8,24.75%,111.2,59,232.2,72.3,166.9,1.2,"1,100.3",7.7
Indian Oil Corporation Ltd.,IOC,530965,OIL & GAS,OIL MARKETING & DISTRIBUTION,"179,752.1","156,013.1","23,328.4",13.01%,"3,609.6","2,135","18,090.2","4,699.7","13,114.3",9.5,"38,614.3",27.3
Indian Overseas Bank,IOB,532388,BANKING AND FINANCE,BANKS,"6,941.5","1,785.1","1,679.8",28.84%,0,"3,476.6",635.5,8.3,627.2,0.3,"2,341.9",1.2
Indraprastha Gas Ltd.,IGL,532514,UTILITIES,UTILITIES,"3,520.2","2,801.6",656.9,18.99%,102.2,2.5,613.9,151.4,552.7,7.9,"1,806.2",25.8
IndusInd Bank Ltd.,INDUSINDBK,532187,BANKING AND FINANCE,BANKS,"13,529.7","3,449.9","3,908.7",34.75%,0,"6,171.1","2,934.9",732.9,"2,202.2",28.4,"8,333.7",107.2
Info Edge (India) Ltd.,NAUKRI,532777,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,792,421.2,204.7,32.70%,25.9,8.2,382.8,68.7,205.1,15.9,-25.6,-2
InterGlobe Aviation Ltd.,INDIGO,539448,TRANSPORTATION,AIRLINES,"15,502.9","12,743.6","2,200.3",14.72%,"1,549","1,021.3",189.1,0.2,188.9,4.9,"5,621.3",145.7
Ipca Laboratories Ltd.,IPCALAB,524494,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"2,072.5","1,712.7",321.3,15.80%,90.3,44.1,225.4,87.9,145.1,5.7,492.2,19.4
J B Chemicals & Pharmaceuticals Ltd.,JBCHEPHARM,506943,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,889.4,638.2,243.5,27.62%,32.2,10.4,208.7,58.1,150.6,9.7,486.6,31.4
JK Cement Ltd.,JKCEMENT,532644,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"2,782.1","2,285.8",467,16.96%,137.1,115,244.2,65.7,178.1,23.1,444,57.5
JK Lakshmi Cement Ltd.,JKLAKSHMI,500380,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"1,588.5","1,357.3",217.3,13.80%,56.6,33.6,141,45.1,92.7,7.9,357.6,30.4
JM Financial Ltd.,JMFINANCIL,523405,DIVERSIFIED,HOLDING COMPANIES,"1,214",407.9,662.6,55.34%,13.2,388.1,277.9,72.4,194.9,2,608.1,6.4
JSW Energy Ltd.,JSWENERGY,533148,UTILITIES,ELECTRIC UTILITIES,"3,387.4","1,379","1,880.4",57.69%,408.7,513.7,"1,085.9",235.1,850.2,5.2,"1,591.7",9.7
JSW Steel Ltd.,JSWSTEEL,500228,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"44,821","36,698","7,886",17.69%,"2,019","2,084","4,609","1,812","2,76",11.4,"9,252",38.1
Jindal Stainless Ltd.,JSL,532508,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"9,829","8,566.5","1,230.6",12.56%,221.9,155.6,985.7,229.1,774.3,9.4,"2,600.2",31.6
Jindal Steel & Power Ltd.,JINDALSTEL,532286,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"12,282","9,964.5","2,285.7",18.66%,603.7,329.4,"1,384.5",-5.8,"1,387.8",13.8,"4,056",40.4
Jubilant Foodworks Ltd.,JUBLFOOD,533155,HOTELS RESTAURANTS & TOURISM,RESTAURANTS,"1,375.7","1,091.4",277.2,20.25%,141.9,56.8,85.5,23.3,97.2,1.5,235,3.6
Just Dial Ltd.,JUSTDIAL,535648,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,318.5,211.8,48.8,18.71%,12.2,2.4,92.1,20.3,71.8,8.4,314.1,36.9
Jyothy Labs Ltd.,JYOTHYLAB,532926,FMCG,PERSONAL PRODUCTS,745.6,597,135.4,18.48%,12.3,1.2,135.1,31.1,104.2,2.8,326.9,8.9
KRBL Ltd.,KRBL,530813,FMCG,PACKAGED FOODS,"1,246.5","1,018.9",194.5,16.03%,19.9,0.8,206.8,53.6,153.3,6.5,671.4,29.3
Kajaria Ceramics Ltd.,KAJARIACER,500233,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,"1,129.9",941.9,179.7,16.02%,36.1,4.3,147.7,36.6,108,6.8,397.8,25
Kalpataru Projects International Ltd.,KPIL,522287,UTILITIES,ELECTRIC UTILITIES,"4,53","4,148",370,8.19%,113,137,132,42,89,5.5,478,29.9
Kansai Nerolac Paints Ltd.,KANSAINER,500165,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,"1,978.6","1,683.3",273.2,13.97%,47.4,7.6,240.3,64.8,177.2,2.2,"1,118.8",13.8
Karur Vysya Bank Ltd.,KARURVYSYA,590003,BANKING AND FINANCE,BANKS,"2,336",616.4,637.9,31.94%,0,"1,081.7",511.5,133.1,378.4,4.7,"1,364.2",17
KEC International Ltd.,KEC,532714,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"4,514.9","4,224.7",274.3,6.10%,46.5,177.8,65.8,9.9,55.8,2.2,187.9,7.3
Kotak Mahindra Bank Ltd.,KOTAKBANK,500247,BANKING AND FINANCE,BANKS,"21,559.5","9,681","6,343",46.24%,0,"5,535.5","5,888.3","1,465.5","4,461",22.4,"17,172.7",86.4
L&T Finance Holdings Ltd.,L&TFH,533519,DIVERSIFIED,HOLDING COMPANIES,"3,482.1",935.3,"1,882.4",58.57%,28.3,"1,324.9",797.4,203.2,595.1,2.4,"2,080.8",8.4
L&T Technology Services Ltd.,LTTS,540115,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"2,427.7","1,910.9",475.6,19.93%,68.1,12.6,436.1,120.2,315.4,29.8,"1,239.7",117.5
LIC Housing Finance Ltd.,LICHSGFIN,500253,BANKING AND FINANCE,HOUSING FINANCE,"6,765.9",250.6,"6,095.7",90.10%,13.2,"4,599.9","1,483",291.2,"1,193.5",21.7,"4,164.5",75.7
Lakshmi Machine Works Ltd.,LAXMIMACH,500252,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,"1,355.5","1,184.5",136,10.30%,23.6,0,147.4,32.3,115.1,107.8,416,389.5
Laurus Labs Ltd.,LAURUSLABS,540222,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,226.2","1,036.6",187.9,15.34%,93.4,42.4,53.9,14.6,37,0.7,367.8,6.8
Lupin Ltd.,LUPIN,500257,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"5,079","4,120.8",917.8,18.21%,247.8,80.6,629.7,134.3,489.5,10.8,"1,331.2",29.2
MMTC Ltd.,MMTC,513377,COMMERCIAL SERVICES & SUPPLIES,COMMODITY TRADING & DISTRIBUTION,-167.2,-180.1,-30.4,14.42%,0.8,1.1,12.1,1.5,52,0.3,174.1,1.2
MRF Ltd.,MRF,500290,AUTOMOBILES & AUTO COMPONENTS,AUTO TYRES & RUBBER PRODUCTS,"6,287.8","5,060.2","1,156.9",18.61%,351.5,85.5,790.6,203.9,586.7,1383.3,"1,690.9",3988
Mahanagar Gas Ltd.,MGL,539957,UTILITIES,UTILITIES,"1,772.7","1,250.1",478.9,27.70%,65.8,2.5,454.3,115.8,338.5,34.3,"1,147.8",116.2
Mahindra & Mahindra Financial Services Ltd.,M&MFIN,532720,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"3,863.5","1,077.5","2,109.3",55.03%,67.1,"1,703.4",369.1,96,281.1,2.3,"1,982.5",16
Mahindra & Mahindra Ltd.,M&M,500520,AUTOMOBILES & AUTO COMPONENTS,CARS & UTILITY VEHICLES,"35,027.2","28,705.9","5,729.6",16.64%,"1,138.6","1,835.2","3,347.5","1,083.7","2,347.8",21.1,"11,169.4",100.2
Mahindra Holidays & Resorts India Ltd.,MHRIL,533088,HOTELS RESTAURANTS & TOURISM,HOTELS,672.2,519.3,136,20.76%,83.8,33.3,35.8,14,21.3,1.1,66,3.3
Manappuram Finance Ltd.,MANAPPURAM,531213,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"2,174",555.6,"1,481.3",68.68%,62.5,689.4,746.7,186.1,558.4,6.6,"1,859.8",22
Mangalore Refinery And Petrochemicals Ltd.,MRPL,500109,OIL & GAS,REFINERIES/PETRO-PRODUCTS,"22,904.7","20,705.6","2,138.2",9.36%,296,311.2,"1,592",546.2,"1,051.7",6,"3,784.9",21.6
Marico Ltd.,MARICO,531642,FMCG,PERSONAL PRODUCTS,"2,514","1,979",497,20.07%,39,20,476,116,353,2.7,"1,41",10.9
Maruti Suzuki India Ltd.,MARUTI,532500,AUTOMOBILES & AUTO COMPONENTS,CARS & UTILITY VEHICLES,"37,902.1","32,282.5","4,790.3",12.92%,794.4,35.1,"4,790.1","1,083.8","3,764.3",124.6,"11,351.8",375.9
Max Financial Services Ltd.,MFSL,500271,BANKING AND FINANCE,LIFE INSURANCE,"10,189.1","10,024.6",143.9,1.42%,0.8,9.4,158.2,-12.1,147.9,4.3,506.4,14.7
UNO Minda Ltd.,UNOMINDA,532539,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"3,630.2","3,219.8",401.6,11.09%,125.4,27.2,257.9,73.3,225,3.9,742.4,13
Motilal Oswal Financial Services Ltd.,MOTILALOFS,532892,BANKING AND FINANCE,OTHER FINANCIAL SERVICES,"1,650.7",724.1,904.5,55.18%,17.3,241.1,657.6,124.2,531.2,35.9,"1,449.3",97.8
MphasiS Ltd.,MPHASIS,526299,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"3,325.5","2,680.9",595.6,18.18%,89,34,521.7,129.7,391.9,20.8,"1,605.6",85.1
Muthoot Finance Ltd.,MUTHOOTFIN,533398,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"3,631.9",723.4,"2,801.6",77.69%,22.2,"1,335","1,470.2",374.9,"1,059.6",26.4,"3,982.9",99.2
Natco Pharma Ltd.,NATCOPHARM,524816,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,060.8",573.4,458,44.41%,43.6,4.2,439.6,70.6,369,20.6,"1,127.4",63
NBCC (India) Ltd.,NBCC,534309,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"2,129.1","1,957.7",95.5,4.65%,1.3,0,104.6,22.9,79.6,0.4,332.2,1.8
NCC Ltd.,NCC,500294,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"4,746.4","4,415.9",303.7,6.44%,53.2,153.5,123.8,38.8,77.3,1.2,599.4,9.5
NHPC Ltd.,NHPC,533098,UTILITIES,ELECTRIC UTILITIES,"3,113.8","1,173.9","1,757.4",59.95%,294.9,104.8,"1,618.3",-75,"1,545.8",1.5,"3,897.8",3.9
Coforge Ltd.,COFORGE,532541,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"2,285.1","1,935.3",340.9,14.98%,77.2,31.9,240.7,52.8,187.9,29.6,696.2,113.2
NLC India Ltd.,NLCINDIA,513683,UTILITIES,ELECTRIC UTILITIES,"3,234","2,143",834.6,28.03%,455.1,213.9,"1,700.6",614.7,"1,084.7",7.8,"1,912.3",13.8
NTPC Ltd.,NTPC,532555,UTILITIES,ELECTRIC UTILITIES,"45,384.6","32,303.2","12,680.2",28.19%,"4,037.7","2,920.5","6,342.9","2,019.7","4,614.6",4.8,"19,125.2",19.7
Narayana Hrudayalaya Ltd.,NH,539551,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,"1,323.6",997.1,308.1,23.61%,55.3,22.9,248.4,21.7,226.6,11.2,737.5,36.1
National Aluminium Company Ltd.,NATIONALUM,532234,METALS & MINING,ALUMINIUM AND ALUMINIUM PRODUCTS,"3,112","2,646.9",396.5,13.03%,186.2,4,275,68.7,187.3,1,"1,272.4",6.9
Navin Fluorine International Ltd.,NAVINFLUOR,532504,CHEMICALS & PETROCHEMICALS,COMMODITY CHEMICALS,494.9,373.4,98.3,20.84%,24.2,20,77.2,16.6,60.6,12.2,365,73.7
Oberoi Realty Ltd.,OBEROIRLTY,533273,REALTY,REALTY,"1,243.8",579.2,638.2,52.42%,11.3,56.5,596.8,142.1,456.8,12.6,"1,961.3",53.9
Oil And Natural Gas Corporation Ltd.,ONGC,500312,OIL & GAS,EXPLORATION & PRODUCTION,"149,388.5","118,618.4","28,255.3",19.24%,"6,698.1","2,603.3","21,564.9","5,633.6","13,734.1",10.9,"43,072.5",34.2
Oil India Ltd.,OIL,533106,OIL & GAS,EXPLORATION & PRODUCTION,"9,200.1","5,293.3","3,523.2",39.96%,499,278.9,762,67.6,420.7,3.9,"5,874.5",54.2
Oracle Financial Services Software Ltd.,OFSS,532466,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"1,509.6",886.4,558.1,38.64%,19,8,596.2,178.8,417.4,48.2,"1,835.1",211.9
PI Industries Ltd.,PIIND,523642,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,"2,163.8","1,565.5",551.4,26.05%,80.3,7.8,510.2,31.7,480.5,31.7,"1,495.8",98.4
PNB Housing Finance Ltd.,PNBHOUSING,540173,BANKING AND FINANCE,HOUSING FINANCE,"1,779.4",158.8,"1,574.1",88.54%,11.3,"1,057.3",507.1,124.1,383,14.8,"1,278.7",49.3
PNC Infratech Ltd.,PNCINFRA,539150,CEMENT AND CONSTRUCTION,ROADS & HIGHWAYS,"1,932.4","1,511.6",399.8,20.92%,40.9,161.3,218.6,70.7,147.9,5.8,614.3,23.9
PVR INOX Ltd.,PVRINOX,532689,RETAILING,SPECIALTY RETAIL,"2,023.7","1,293.1",706.8,35.34%,308.6,200.3,221.7,55.5,166.3,17,-232.5,-23.7
Page Industries Ltd.,PAGEIND,532827,TEXTILES APPARELS & ACCESSORIES,OTHER APPARELS & ACCESSORIES,"1,126.8",891.6,233.5,20.76%,24.6,11.2,199.4,49.1,150.3,134.7,510.7,457.9
Persistent Systems Ltd.,PERSISTENT,533179,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"2,449","2,006.5",405.2,16.80%,74.4,12.3,355.8,92.5,263.3,35,981.5,127.6
Petronet LNG Ltd.,PETRONET,532522,OIL & GAS,OIL MARKETING & DISTRIBUTION,"12,686.2","11,317.9","1,214.7",9.69%,194.8,74.7,"1,098.8",283.9,855.7,5.7,"3,490.3",23.3
Pfizer Ltd.,PFIZER,500680,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,611.3,392.6,182.6,31.75%,15.4,2.7,200.5,51.6,149,32.6,522.8,114.3
Phoenix Mills Ltd.,PHOENIXLTD,503100,REALTY,REALTY,906.6,361.2,506,57.82%,65.9,96.5,375.2,71.4,252.6,14.2,923.6,51.7
Pidilite Industries Ltd.,PIDILITIND,500331,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"3,107.6","2,396.3",679.7,22.10%,75.2,13.1,623,163.1,450.1,8.8,"1,505.5",29.6
Power Finance Corporation Ltd.,PFC,532810,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"22,403.7",315.4,"22,941.9",102.46%,12.7,"14,313.1","8,628.8","2,000.6","4,833.1",14.7,"17,946.4",54.4
Power Grid Corporation of India Ltd.,POWERGRID,532898,UTILITIES,ELECTRIC UTILITIES,"11,530.4","1,358.7","9,908.4",87.94%,"3,277","2,341.3","4,393.4",573.7,"3,781.4",4.1,"15,344.4",16.5
Prestige Estates Projects Ltd.,PRESTIGE,ASM,REALTY,REALTY,"3,256","1,643.9",592.5,26.49%,174.1,263.9,"1,174.1",256.4,850.9,21.2,"1,714",42.8
Prism Johnson Ltd.,PRSMJOHNSN,500338,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"1,846","1,745.4",92.4,5.03%,95.2,43.5,210,30.4,182.7,3.6,154.2,3.1
Procter & Gamble Hygiene & Healthcare Ltd.,PGHH,500459,FMCG,PERSONAL PRODUCTS,"1,154.1",853.5,284.9,25.03%,14.3,1.9,284.5,73.8,210.7,64.9,734.4,226.3
Punjab National Bank,PNB,532461,BANKING AND FINANCE,BANKS,"29,857","6,798.1","6,239.1",23.23%,0,"16,819.8","2,778.3","1,013.8","1,990.2",1.8,"5,904.8",5.4
Quess Corp Ltd.,QUESS,539978,SOFTWARE & SERVICES,BPO/KPO,"4,763.5","4,584.8",163.6,3.44%,69.7,28.1,79.3,8.3,71.9,4.8,240.9,16.2
RBL Bank Ltd.,RBLBANK,540065,BANKING AND FINANCE,BANKS,"3,720.6","1,422.6",765.4,25.45%,0,"1,532.6",125,-206.1,331.1,5.5,"1,173.9",19.5
Radico Khaitan Ltd.,RADICO,532497,FOOD BEVERAGES & TOBACCO,BREWERIES & DISTILLERIES,925.7,803.8,121.2,13.10%,26.1,12.5,83.3,21.4,64.8,4.8,237,17.7
Rain Industries Ltd.,RAIN,500339,CHEMICALS & PETROCHEMICALS,PETROCHEMICALS,"4,208.9","3,794.3",366,8.80%,192.5,241.7,-19.5,46.2,-90.2,-2.7,270.4,8
Rajesh Exports Ltd.,RAJESHEXPO,531500,TEXTILES APPARELS & ACCESSORIES,GEMS & JEWELLERY,"38,079.4","38,015.8",50.1,0.13%,10.7,0,53,7.7,45.3,1.5,"1,142.2",38.7
Rallis India Ltd.,RALLIS,500355,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,837,699,133,15.99%,26,3,110,28,82,4.2,98.4,5.2
Rashtriya Chemicals & Fertilizers Ltd.,RCF,524230,FERTILIZERS,FERTILIZERS,"4,222.1","4,049.3",105.9,2.55%,56.1,44,72.8,21.1,51,0.9,523.6,9.5
Redington Ltd.,REDINGTON,532805,COMMERCIAL SERVICES & SUPPLIES,COMMODITY TRADING & DISTRIBUTION,"22,296.6","21,738.7",481.4,2.17%,43.7,105.8,408.3,96.7,303.5,3.9,"1,242",15.9
Relaxo Footwears Ltd.,RELAXO,530517,RETAILING,FOOTWEAR,725.9,623.8,91.5,12.79%,36.9,4.7,60.4,16.2,44.2,1.8,193.9,7.8
Reliance Industries Ltd.,RELIANCE,500325,OIL & GAS,REFINERIES/PETRO-PRODUCTS,"238,797","193,988","40,968",17.44%,"12,585","5,731","26,493","6,673","17,394",25.7,"68,496",101.2
REC Ltd.,RECLTD,532955,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"11,701.3",275.1,"12,180.5",104.21%,6.1,"7,349.8","4,837.6","1,047.7","3,789.9",14.4,"12,738.6",48.4
SJVN Ltd.,SJVN,533206,UTILITIES,ELECTRIC UTILITIES,951.6,172.2,706.2,80.40%,101.9,124.2,567.7,129.2,439.6,1.1,"1,016",2.6
SKF India Ltd.,SKFINDIA,500472,GENERAL INDUSTRIALS,OTHER INDUSTRIAL GOODS,"1,145.5","1,003.7",121.5,10.80%,19.3,0.5,122,31.7,90,18.2,484,97.9
SRF Ltd.,SRF,503806,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"3,206.5","2,551.2",626.2,19.71%,161.2,79.3,414.8,114,300.8,10.2,"1,733.4",58.5
Sanofi India Ltd.,SANOFI,500674,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,726.4,506.1,208.5,29.17%,9.9,0.3,210.1,57.9,152.1,66.1,596.3,259.3
Schaeffler India Ltd.,SCHAEFFLER,505790,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,879.2","1,506.3",342,18.50%,55.6,1.6,315.7,80.7,235,15,922.6,59
Shree Cements Ltd.,SHREECEM,500387,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"4,932.1","3,914.1",886,18.46%,411.7,67,539.2,92.6,446.6,123.8,"1,826.8",506.3
Shriram Finance Ltd.,SHRIRAMFIN,511218,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"8,893","1,409.4","6,334.3",71.30%,141.4,"3,798","2,404.2",614.9,"1,786.1",47.6,"6,575.4",175.2
Siemens Ltd.,SIEMENS,500550,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"5,953.2","5,107.5",700.2,12.06%,78.6,4.9,762.2,190.5,571.3,16.1,"1,960.9",55.1
Sobha Ltd.,SOBHA,532784,REALTY,REALTY,773.6,665.8,75.4,10.18%,19.3,63.9,24.7,9.7,14.9,1.6,107.4,11.3
Solar Industries India Ltd.,SOLARINDS,532725,GENERAL INDUSTRIALS,OTHER INDUSTRIAL PRODUCTS,"1,355.2","1,011.3",336.1,24.95%,33.7,24.9,285.3,75.5,200.1,22.1,808.2,89.3
Sonata Software Ltd.,SONATSOFTW,532221,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"1,935.8","1,715.2",197.3,10.32%,33.3,20.7,166.5,42.3,124.2,9,475.7,34.3
State Bank of India,SBIN,500112,BANKING AND FINANCE,BANKS,"144,256.1","58,597.6","22,703.3",21.14%,0,"62,955.2","21,935.7","5,552.5","17,196.2",18,"69,304.1",77.7
Steel Authority of India (SAIL) Ltd.,SAIL,500113,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"29,858.2","25,836.7","3,875.4",13.04%,"1,326.6",605.2,"1,674.7",464.2,"1,305.6",3.2,"3,219.5",7.8
Sun Pharma Advanced Research Company Ltd.,SPARC,532872,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,29.7,112.7,-91.5,-431.87%,3.2,0.3,-86.4,0,-86.4,-2.7,-253.6,-7.8
Sun Pharmaceutical Industries Ltd.,SUNPHARMA,524715,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"12,486","9,013","3,179.4",26.08%,632.8,49.3,"2,790.9",390.1,"2,375.5",9.9,"8,548.5",35.6
Sun TV Network Ltd.,SUNTV,532733,MEDIA,BROADCASTING & CABLE TV,"1,160.2",320.6,727.8,69.42%,218.8,1.7,619.1,154.4,464.7,11.8,"1,861.8",47.2
Sundram Fasteners Ltd.,SUNDRMFAST,500403,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,429.1","1,191.1",230.7,16.23%,54.5,7.4,176.2,43.1,131.9,6.3,502.9,23.9
Sunteck Realty Ltd.,SUNTECK,512179,REALTY,REALTY,36.2,39.1,-14.1,-56.70%,2.2,15.8,-20.9,-6.4,-13.9,-1,-46.5,-3.3
Supreme Industries Ltd.,SUPREMEIND,509930,GENERAL INDUSTRIALS,PLASTIC PRODUCTS,"2,321.4","1,952.5",356.2,15.43%,71.9,1.6,295.4,76.3,243.2,19.1,"1,028.2",80.9
Suzlon Energy Ltd.,SUZLON,ASM,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"1,428.7","1,196.4",225,15.83%,51.2,43.7,102.4,0.1,102.3,0.1,561.4,0.4
Syngene International Ltd.,SYNGENE,539268,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,931.7,656,254.1,27.92%,104.6,13,150.7,34.2,116.5,2.9,498.3,12.4
TTK Prestige Ltd.,TTKPRESTIG,517506,CONSUMER DURABLES,HOUSEWARE,747.2,648.6,80.8,11.08%,15.9,3.1,79.5,20.5,59.3,4.3,224.3,16.2
TV18 Broadcast Ltd.,TV18BRDCST,532800,MEDIA,BROADCASTING & CABLE TV,"1,989","1,992.2",-198.1,-11.04%,50.1,33.8,-87.1,-6.5,-28.9,-0.2,92.2,0.5
TVS Motor Company Ltd.,TVSMOTOR,532343,AUTOMOBILES & AUTO COMPONENTS,2/3 WHEELERS,"9,983.8","8,576.9","1,355.9",13.65%,237.1,483.3,686.4,259.8,386.3,8.1,"1,457.6",30.7
Tata Consultancy Services Ltd.,TCS,532540,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"60,698","43,946","15,746",26.38%,"1,263",159,"15,33","3,95","11,342",31,"44,654",122
Tata Elxsi Ltd.,TATAELXSI,500408,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,912.8,618.2,263.5,29.89%,25,5.8,263.9,63.8,200,32.1,785.1,126.1
Tata Consumer Products Ltd.,TATACONSUM,500800,FMCG,PACKAGED FOODS,"3,823.6","3,196.7",537.1,14.38%,93.9,27.6,490.9,131.7,338.2,3.6,"1,275.2",13.7
Tata Motors Limited (DVR),TATAMTRDVR,570001,AUTOMOBILES & AUTO COMPONENTS,COMMERCIAL VEHICLES,,,,,,,,,,,,
Tata Motors Ltd.,TATAMOTORS,500570,AUTOMOBILES & AUTO COMPONENTS,COMMERCIAL VEHICLES,"106,759","91,361.3","13,766.9",13.10%,"6,636.4","2,651.7","5,985.9","2,202.8","3,764",9.8,"15,332.3",40
Tata Power Company Ltd.,TATAPOWER,500400,UTILITIES,ELECTRIC UTILITIES,"16,029.5","12,647","3,091",19.64%,925.9,"1,181.8",979.2,213.3,875.5,2.7,"3,570.8",11.2
Tata Steel Ltd.,TATASTEEL,500470,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"55,910.2","51,414.1","4,267.8",7.66%,"2,479.8","1,959.4","-6,842.1",-228,"-6,196.2",-5.1,"-6,081.3",-5
Tech Mahindra Ltd.,TECHM,532755,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"13,128.1","11,941.1",922.8,7.17%,465.7,97.5,623.8,110,493.9,5.6,"3,600.7",40.9
The Ramco Cements Ltd.,RAMCOCEM,500260,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"2,352.1","1,935",405.6,17.33%,162.8,116.5,137.8,37,72,3.1,348.9,14.8
Thermax Ltd.,THERMAX,500411,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"2,368.3","2,097.8",204.6,8.89%,33,19.8,217.7,58.9,157.7,14,498.8,44.3
Timken India Ltd.,TIMKEN,522113,GENERAL INDUSTRIALS,OTHER INDUSTRIAL PRODUCTS,692.1,546.5,135.5,19.87%,21.1,0.9,123.6,30.6,93,12.4,358.3,47.6
Titan Company Ltd.,TITAN,500114,TEXTILES APPARELS & ACCESSORIES,GEMS & JEWELLERY,"12,653","11,118","1,411",11.26%,144,140,"1,251",336,915,10.3,"3,302",37.1
Torrent Pharmaceuticals Ltd.,TORNTPHARM,500420,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"2,686","1,835",825,31.02%,201,91,559,173,386,11.4,"1,334",39.4
Torrent Power Ltd.,TORNTPOWER,532779,UTILITIES,ELECTRIC UTILITIES,"7,069.1","5,739.5","1,221.4",17.55%,341.7,247.2,740.7,198.1,525.9,10.9,"2,176.8",45.3
Trent Ltd.,TRENT,500251,RETAILING,DEPARTMENT STORES,"3,062.5","2,525.8",456.6,15.31%,152.2,95.5,288.9,86.3,234.7,6.6,629.4,17.7
Trident Ltd.,TRIDENT,521064,TEXTILES APPARELS & ACCESSORIES,TEXTILES,"1,812","1,557.3",240.3,13.37%,89.4,35,130.4,40.1,90.7,0.2,458.1,0.9
UPL Ltd.,UPL,512070,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,"10,275","8,807","1,325",13.03%,657,871,-185,-96,-189,-2.5,"1,856",24.7
UltraTech Cement Ltd.,ULTRACEMCO,532538,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"16,179.3","13,461.2","2,550.9",15.93%,797.8,233.9,"1,686.2",409.4,"1,281.5",44.5,"5,694.1",197.2
Union Bank of India,UNIONBANK,532477,BANKING AND FINANCE,BANKS,"28,952.5","6,189.3","7,265",29.38%,0,"15,498.2","5,492.3","1,944","3,571.8",5.1,"11,918.9",16.1
United Breweries Ltd.,UBL,532478,FOOD BEVERAGES & TOBACCO,BREWERIES & DISTILLERIES,"1,902.1","1,705.8",184.3,9.75%,50.9,1.4,144,36.9,107.3,4.1,251.3,9.5
United Spirits Ltd.,MCDOWELL-N,532432,FOOD BEVERAGES & TOBACCO,BREWERIES & DISTILLERIES,"6,776.6","6,269.8",466.7,6.93%,65.3,26.2,446,106.3,339.3,4.8,"1,133",15.6
V-Guard Industries Ltd.,VGUARD,532953,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"1,147.9","1,041.3",92.5,8.16%,19.8,9.3,77.5,18.6,59,1.4,215.2,5
Vardhman Textiles Ltd.,VTL,502986,TEXTILES APPARELS & ACCESSORIES,TEXTILES,"2,487","2,192.1",205.4,8.57%,103.7,22,169.2,41.7,134.3,4.7,531.9,18.7
Varun Beverages Ltd.,VBL,540180,FOOD BEVERAGES & TOBACCO,NON-ALCOHOLIC BEVERAGES,"3,889","2,988.4",882.1,22.79%,170.8,62.5,667.3,152.9,501.1,3.9,"1,998.7",15.4
Vinati Organics Ltd.,VINATIORGA,524200,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,464.4,337.3,110.8,24.73%,13.7,0.3,113,28.9,84.2,8.2,408.2,39.7
Voltas Ltd.,VOLTAS,500575,CONSUMER DURABLES,CONSUMER ELECTRONICS,"2,363.7","2,222.5",70.3,3.06%,11.7,11.4,118.1,49.3,36.7,1.1,199.5,6
ZF Commercial Vehicle Control Systems India Ltd.,ZFCVINDIA,533023,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,015.8",846.2,145.5,14.67%,27.1,1.3,141.2,35.5,105.7,55.7,392,206.7
Welspun Corp Ltd.,WELCORP,ASM,METALS & MINING,IRON & STEEL PRODUCTS,"4,161.4","3,659.9",399.5,9.84%,85.7,75,340.8,79,384.7,14.7,809.2,30.9
Welspun Living Ltd.,WELSPUNLIV,514162,TEXTILES APPARELS & ACCESSORIES,TEXTILES,"2,542.4","2,151.1",358,14.27%,98.5,33.8,258.9,58.7,196.7,2,526.1,5.4
Whirlpool of India Ltd.,WHIRLPOOL,500238,CONSUMER DURABLES,CONSUMER ELECTRONICS,"1,555.5","1,448.4",73.2,4.81%,49.2,5.6,52.3,14.1,36.6,2.9,198.8,15.7
Wipro Ltd.,WIPRO,507685,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"23,255.7","18,543.2","3,972.7",17.64%,897,303.3,"3,512.2",841.9,"2,646.3",5.1,"11,643.8",22.3
Zee Entertainment Enterprises Ltd.,ZEEL,505537,MEDIA,BROADCASTING & CABLE TV,"2,509.6","2,105",332.8,13.65%,77.2,23.4,184.2,54.4,123,1.3,-102.2,-1.1
eClerx Services Ltd.,ECLERX,532927,SOFTWARE & SERVICES,BPO/KPO,735.9,517,204.7,28.37%,30.3,6.1,182.4,46.3,136,28.2,506,105
Sterlite Technologies Ltd.,STLTECH,532374,TELECOMMUNICATIONS EQUIPMENT,TELECOM CABLES,"1,497","1,281",213,14.26%,85,95,36,12,34,0.9,203,5.1
HEG Ltd.,HEG,509631,GENERAL INDUSTRIALS,OTHER INDUSTRIAL GOODS,642.2,512.3,101.9,16.58%,38.5,8.5,82.9,21.7,96,24.9,439.5,113.9
SBI Life Insurance Company Ltd.,SBILIFE,540719,BANKING AND FINANCE,LIFE INSURANCE,"28,816.2","28,183.8",609.9,2.12%,0,0,621.5,43.9,380.2,3.8,"1,842.2",18.4
General Insurance Corporation of India,GICRE,540755,BANKING AND FINANCE,GENERAL INSURANCE,"13,465.9","11,574","1,464.6",11.20%,0,0,"1,855.4",243.7,"1,689",15.2,"6,628",37.8
Tube Investments of India Ltd.,TIINDIA,540762,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"2,005.4","1,718.2",251.4,12.76%,34.6,7.7,244.8,63.4,181.4,9.4,717.5,37.1
Honeywell Automation India Ltd.,HONAUT,517174,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"1,144.3",965.9,138.3,12.52%,13.8,0.7,163.9,42,121.9,137.8,443.4,503.9
Indian Energy Exchange Ltd.,IEX,540750,BANKING AND FINANCE,EXCHANGE,133,16.6,92,84.73%,5.1,0.7,110.6,27.9,86.5,1,327.8,3.7
ICICI Lombard General Insurance Company Ltd.,ICICIGI,540716,BANKING AND FINANCE,GENERAL INSURANCE,"5,271.1","4,612.4",743.5,14.16%,0,0,763.6,186.4,577.3,11.8,"1,757.1",35.8
Aster DM Healthcare Ltd.,ASTERDM,540975,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,"3,325.2","2,939.4",377.3,11.38%,227.2,101.9,2.1,10.2,-30.8,-0.6,284.3,5.7
Central Depository Services (India) Ltd.,CDSL,CDSL,OTHERS,INVESTMENT COMPANIES,230.1,77.9,129.4,62.40%,6.5,0,145.6,35.8,108.9,10.4,320.2,30.6
Graphite India Ltd.,GRAPHITE,509488,GENERAL INDUSTRIALS,OTHER INDUSTRIAL GOODS,884,823,-30,-3.78%,19,4,992,190,804,41.1,856,43.9
Grasim Industries Ltd.,GRASIM,500300,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"30,505.3","25,995.9","4,224.8",13.98%,"1,245.2",397.8,"2,866.4",837.7,"1,163.8",17.7,"6,624.9",100.6
KNR Constructions Ltd.,KNRCON,532942,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"1,043.8",806.9,231.6,22.30%,39.2,20.6,177.1,34.6,147.4,5.2,537.5,19.1
Aditya Birla Capital Ltd.,ABCAPITAL,540691,DIVERSIFIED,HOLDING COMPANIES,"7,730.4","4,550.1","2,821.9",36.55%,48,"1,827",956.8,284.1,705,2.7,"5,231.9",20.1
Dixon Technologies (India) Ltd.,DIXON,540699,CONSUMER DURABLES,CONSUMER ELECTRONICS,"4,943.9","4,744.3",198.9,4.02%,36.4,17.1,146.1,35.2,107.3,19,308.7,51.8
Cholamandalam Financial Holdings Ltd.,CHOLAHLDNG,504973,DIVERSIFIED,HOLDING COMPANIES,"6,372.2","2,495.1","3,404.8",54.05%,52.1,"2,209.4","1,215.8",324.6,420.9,22.4,"1,532.3",81.6
Cochin Shipyard Ltd.,COCHINSHIP,540678,TRANSPORTATION,MARINE PORT & SERVICES,"1,100.4",820.5,191.2,18.90%,18.9,9.6,251.4,69.9,181.5,13.8,429.9,32.7
Bharat Dynamics Ltd.,BDL,541143,GENERAL INDUSTRIALS,DEFENCE,694.1,481.8,134,21.77%,17.4,0.8,194.1,47,147.1,8,425.4,23.2
Lux Industries Ltd.,LUXIND,539542,TEXTILES APPARELS & ACCESSORIES,OTHER APPARELS & ACCESSORIES,643.6,584.2,55,8.61%,5.9,5.4,48,12.1,37.1,12.3,103.1,32.9
Zensar Technologies Ltd.,ZENSARTECH,504067,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"1,277.1","1,009.9",230.9,18.61%,36.6,5.7,224.9,51,173.9,7.7,525.8,23.2
PCBL Ltd.,PCBL,506590,CHEMICALS & PETROCHEMICALS,CARBON BLACK,"1,489.4","1,248.6",238.1,16.02%,48.2,21,171.6,48.8,122.6,3.2,431.6,11.4
Zydus Wellness Ltd.,ZYDUSWELL,531335,FMCG,PACKAGED FOODS,444,423.1,16.8,3.82%,5.8,6.5,8.6,2.7,5.9,0.9,281.2,44.2
Linde India Ltd.,LINDEINDIA,523457,GENERAL INDUSTRIALS,INDUSTRIAL GASES,729.9,537.7,173.6,24.41%,49.7,1.2,141.3,34.6,108.7,12.8,417.9,49
FDC Ltd.,FDC,531599,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,513.6,409.9,76.4,15.71%,9.9,1.1,92.7,22.9,69.8,4.2,251.2,15.4
The New India Assurance Company Ltd.,NIACL,540769,BANKING AND FINANCE,GENERAL INSURANCE,"10,571","10,773.4",-246.5,-2.33%,0,0,-242,-46.7,-176.1,-1.1,947,5.7
Sundaram Finance Ltd.,SUNDARMFIN,590071,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"1,710.6",322.5,"1,332.1",77.98%,43.6,820.3,470.6,142.8,365.4,33.2,"1,506.7",135.6
TeamLease Services Ltd.,TEAMLEASE,539658,COMMERCIAL SERVICES & SUPPLIES,MISC. COMMERCIAL SERVICES,"2,285.6","2,240.8",31.8,1.40%,12.9,2.5,29.4,1.8,27.3,16.3,106.6,63.5
Galaxy Surfactants Ltd.,GALAXYSURF,540935,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,985.8,858.2,124.9,12.70%,24.7,5.4,97.5,20.1,77.4,21.8,349.3,98.5
Bandhan Bank Ltd.,BANDHANBNK,541153,BANKING AND FINANCE,BANKS,"5,032.2","1,400.2","1,583.4",35.25%,0,"2,048.6",947.2,226.1,721.2,4.5,"2,541.1",15.8
ICICI Securities Ltd.,ISEC,541179,BANKING AND FINANCE,CAPITAL MARKETS,"1,249",433.5,810.2,64.87%,25.8,215.1,569.4,145.7,423.6,13.1,"1,238.1",38.3
V-Mart Retail Ltd.,VMART,534976,RETAILING,DEPARTMENT STORES,551.4,548.8,0.7,0.12%,53.2,35.9,-86.4,-22.3,-64.1,-32.4,-103.1,-52.1
Nippon Life India Asset Management Ltd.,NAM-INDIA,540767,BANKING AND FINANCE,ASSET MANAGEMENT COS.,475.4,156.1,241.4,60.73%,7.2,1.7,310.4,66.1,244.4,3.9,883.3,14.1
Grindwell Norton Ltd.,GRINDWELL,506076,GENERAL INDUSTRIALS,OTHER INDUSTRIAL PRODUCTS,690,536,131.4,19.69%,16.9,1.8,135.3,33.1,101.9,9.2,378.3,34.2
HDFC Life Insurance Company Ltd.,HDFCLIFE,540777,BANKING AND FINANCE,LIFE INSURANCE,"23,276.6","23,659.3",-508.1,-2.20%,0,0,-373.1,-657.5,378.2,1.8,"1,472.8",6.9
Elgi Equipments Ltd.,ELGIEQUIP,522074,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,817.8,663.4,142.7,17.71%,18.7,6.6,129.2,38.8,91.3,2.9,401.9,12.7
Hindustan Aeronautics Ltd.,HAL,541154,GENERAL INDUSTRIALS,DEFENCE,"6,105.1","4,108.1","1,527.6",27.11%,349.6,0.3,"1,647",414.8,"1,236.7",18.5,"6,037.3",90.3
BSE Ltd.,BSE,BSE,BANKING AND FINANCE,EXCHANGE,367,172.8,189.2,52.26%,22.7,8.5,163,63.6,120.5,8.8,706,52.1
Rites Ltd.,RITES,541556,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,608.8,444.5,137.8,23.67%,14.1,1.4,148.8,40.1,101.2,4.2,488.1,20.3
Fortis Healthcare Ltd.,FORTIS,532843,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,"1,783.5","1,439.8",330.2,18.65%,84.1,31.8,231.4,48.8,173.7,2.3,547.6,7.3
Varroc Engineering Ltd.,VARROC,541578,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,893.5","1,692.6",194.3,10.30%,84.9,50.3,65.9,18.2,54.2,3.5,146.5,9.6
Adani Green Energy Ltd.,ADANIGREEN,ASM,UTILITIES,ELECTRIC UTILITIES,"2,589",521,"1,699",76.53%,474,"1,165",413,119,372,2.2,"1,305",8.2
VIP Industries Ltd.,VIPIND,507880,TEXTILES APPARELS & ACCESSORIES,OTHER APPARELS & ACCESSORIES,548.7,493.2,52.9,9.68%,23.8,12.4,19.3,6,13.3,0.9,110.9,7.8
CreditAccess Grameen Ltd.,CREDITACC,541770,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"1,247.6",248.8,902.3,72.36%,12.3,423.9,466.8,119.7,347,21.8,"1,204.2",75.7
CESC Ltd.,CESC,500084,UTILITIES,ELECTRIC UTILITIES,"4,414","3,706",646,14.84%,303,305,461,98,348,2.6,"1,447",10.9
Jamna Auto Industries Ltd.,JAMNAAUTO,520051,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,608.7,528.2,79.1,13.03%,10.9,0.8,68.7,18.6,50.1,2.4,189.3,4.7
Suprajit Engineering Ltd.,SUPRAJIT,532509,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,727.6,639.1,69.8,9.85%,25.7,13.6,49.2,14.5,34.8,2.5,146.9,10.6
JK Paper Ltd.,JKPAPER,532162,COMMERCIAL SERVICES & SUPPLIES,PAPER & PAPER PRODUCTS,"1,708.8","1,242.8",407.3,24.68%,83.5,42,340.6,34.9,302.4,17.9,"1,220.6",72.1
Bank of Maharashtra,MAHABANK,532525,BANKING AND FINANCE,BANKS,"5,735.5","1,179.4","1,920.5",37.90%,0,"2,635.7",935.7,16,919.8,1.3,"3,420.8",4.8
Aavas Financiers Ltd.,AAVAS,541988,BANKING AND FINANCE,HOUSING FINANCE,497.6,123.5,367.8,74.03%,7.6,203.6,157.4,35.7,121.7,15.4,465.4,58.8
HDFC Asset Management Company Ltd.,HDFCAMC,541729,BANKING AND FINANCE,ASSET MANAGEMENT COS.,765.4,162,481.1,74.81%,13,2.3,588.1,151.6,436.5,20.4,"1,659.3",77.7
KEI Industries Ltd.,KEI,517569,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"1,954.2","1,742.7",203.9,10.47%,15.6,7.5,188.4,48.2,140.2,15.5,528.3,58.5
Orient Electric Ltd.,ORIENTELEC,541301,CONSUMER DURABLES,CONSUMER ELECTRONICS,570.3,546.2,20.7,3.65%,14.2,5.2,23.4,4.9,18.4,0.9,95.3,4.5
Deepak Nitrite Ltd.,DEEPAKNTR,506401,CHEMICALS & PETROCHEMICALS,COMMODITY CHEMICALS,"1,795.1","1,475.8",302.3,17.00%,39.4,2.7,277.2,72.1,205.1,15,797.9,58.5
Fine Organic Industries Ltd.,FINEORG,541557,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,557.6,409.4,131.1,24.25%,14.4,0.7,133.1,28.9,103.4,33.7,458.8,149.6
LTIMindtree Ltd.,LTIM,540005,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"9,048.6","7,274.1","1,631.3",18.32%,208.2,47,"1,519.3",357,"1,161.8",39.3,"4,427.5",149.6
Dalmia Bharat Ltd.,DALBHARAT,542216,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"3,234","2,56",589,18.70%,401,101,172,48,118,6.3,"1,041",54.8
Godfrey Phillips India Ltd.,GODFRYPHLP,500163,FOOD BEVERAGES & TOBACCO,CIGARETTES-TOBACCO PRODUCTS,"1,412.5","1,151",223.6,16.27%,36.5,6.6,218.5,55.5,202.1,38.9,802.9,154.4
Vaibhav Global Ltd.,VAIBHAVGBL,532156,TEXTILES APPARELS & ACCESSORIES,OTHER APPARELS & ACCESSORIES,708.4,641.5,63.5,9.01%,22.6,2.9,41.4,12.4,29.4,1.8,121.3,7.3
Abbott India Ltd.,ABBOTINDIA,500488,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,549.7","1,113.3",380.9,25.49%,17.8,3.1,415.4,102.5,312.9,147.3,"1,081.4",508.9
Adani Total Gas Ltd.,ATGL,ASM,UTILITIES,UTILITIES,"1,104.8",815.7,279.9,25.55%,37.6,27.3,224.2,57.2,172.7,1.6,571,5.2
Nestle India Ltd.,NESTLEIND,500790,FMCG,PACKAGED FOODS,"5,070.1","3,811.9","1,224.9",24.32%,111.2,31.4,"1,222",313.9,908.1,94.2,"2,971.1",308.2
Bayer Cropscience Ltd.,BAYERCROP,506285,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,"1,633.3","1,312.3",304.9,18.85%,11.6,3.7,305.7,82.8,222.9,49.6,844.4,188.1
Amber Enterprises India Ltd.,AMBER,540902,CONSUMER DURABLES,CONSUMER ELECTRONICS,939.8,867.5,59.6,6.43%,45.2,36.6,-9.5,-3.8,-6.9,-2.1,156.8,46.5
Rail Vikas Nigam Ltd.,RVNL,542649,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"5,210.3","4,616",298.3,6.07%,6.2,132.7,455.4,85.2,394.3,1.9,"1,478.8",7.1
Metropolis Healthcare Ltd.,METROPOLIS,542650,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE SERVICES,309.7,233.7,74.8,24.25%,22.2,5.7,48.1,12.5,35.5,6.9,133.4,26
Polycab India Ltd.,POLYCAB,542652,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"4,253","3,608.8",608.9,14.44%,60.3,26.8,557.2,127.4,425.6,28.4,"1,607.2",107.1
Multi Commodity Exchange of India Ltd.,MCX,534091,BANKING AND FINANCE,EXCHANGE,184,193.8,-28.7,-17.38%,6.6,0.1,-16.4,1.6,-19.1,-3.7,44.8,8.8
IIFL Finance Ltd.,IIFL,532636,BANKING AND FINANCE,OTHER FINANCIAL SERVICES,"2,533.7",788.3,"1,600.8",64.66%,43.3,932.1,683.5,158,474.3,12.4,"1,690.7",44.4
Ratnamani Metals & Tubes Ltd.,RATNAMANI,520111,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"1,141.9",886.3,244.9,21.65%,23.6,10.8,221.1,56.8,163.9,23.4,622.6,88.8
RHI Magnesita India Ltd.,RHIM,534076,GENERAL INDUSTRIALS,OTHER INDUSTRIAL GOODS,989.7,839,147.9,14.98%,44.2,8.5,97.9,26.3,71.3,3.5,-502.2,-24.3
Birlasoft Ltd.,BSOFT,532400,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"1,325.4","1,102.7",207.1,15.81%,21.5,5.7,195.5,50.4,145.1,5.2,378.4,13.7
EIH Ltd.,EIHOTEL,500840,HOTELS RESTAURANTS & TOURISM,HOTELS,552.5,387.6,142.9,26.94%,33.2,5.6,126.1,36.2,93.1,1.5,424.1,6.8
Affle (India) Ltd.,AFFLE,542752,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,441.2,344.1,87.2,20.22%,18.4,5.5,73.2,6.4,66.8,5,264.3,19.8
Westlife Foodworld Ltd.,WESTLIFE,505533,HOTELS RESTAURANTS & TOURISM,RESTAURANTS,618,516.5,98.2,15.98%,43.9,27.4,30.2,7.8,22.4,1.4,107.7,6.9
IndiaMART InterMESH Ltd.,INDIAMART,542726,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,329.3,214.7,80,27.15%,8,2.3,104.3,23.9,69.4,11.4,321.1,53.6
Infosys Ltd.,INFY,500209,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"39,626","29,554","9,44",24.21%,"1,166",138,"8,768","2,553","6,212",15,"24,871",60.1
Sterling and Wilson Renewable Energy Ltd.,SWSOLAR,542760,COMMERCIAL SERVICES & SUPPLIES,CONSULTING SERVICES,776.7,758,1.5,0.19%,4.3,64.3,-50,4.6,-54.2,-2.9,-668.4,-35.2
ABB India Ltd.,ABB,500002,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"2,846","2,330.7",438.5,15.84%,30.3,0.9,484.2,122.2,362.9,17.1,"1,208.7",57
Poly Medicure Ltd.,POLYMED,531768,HEALTHCARE EQUIPMENT & SUPPLIES,HEALTHCARE SUPPLIES,351.4,253.1,84.2,24.97%,16,2.2,80.9,18.8,62.2,6.5,233.7,24.4
GMM Pfaudler Ltd.,GMMPFAUDLR,505255,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,946,795.5,142,15.15%,32.2,21.5,96.8,26.5,71.1,15.8,183.2,40.8
Gujarat Fluorochemicals Ltd.,FLUOROCHEM,542812,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,960.3,783.7,163.1,17.23%,67.5,34.2,74.8,22.1,52.7,4.8,915.2,83.3
360 One Wam Ltd.,360ONE,542772,BANKING AND FINANCE,OTHER FINANCIAL SERVICES,617.1,235.6,317.8,57.31%,13.7,139.9,226.8,40.8,186,5.2,696.8,19.5
Tata Communications Ltd.,TATACOMM,500483,TELECOM SERVICES,OTHER TELECOM SERVICES,"4,897.9","3,857.1","1,015.5",20.84%,605.1,137.4,298.3,77.9,220.7,7.7,"1,322.3",46.4
Alkyl Amines Chemicals Ltd.,ALKYLAMINE,506767,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,354.5,303.9,48.3,13.71%,12.5,1.7,36.4,9.2,27.2,5.3,171.3,33.5
CSB Bank Ltd.,CSBBANK,542867,BANKING AND FINANCE,BANKS,835.8,317.5,174.6,25.41%,0,343.6,178,44.8,133.2,7.7,577.7,33.3
Indian Railway Catering & Tourism Corporation Ltd.,IRCTC,542830,DIVERSIFIED CONSUMER SERVICES,TRAVEL SUPPORT SERVICES,"1,042.4",628.8,366.6,36.83%,14,4.4,395.2,100.5,294.7,3.7,"1,061.2",13.3
Sumitomo Chemical India Ltd.,SUMICHEM,542920,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,928,715.5,187.9,20.80%,15.8,1.2,195.5,52,143.4,2.9,367.7,7.4
Century Textiles & Industries Ltd.,CENTURYTEX,500040,COMMERCIAL SERVICES & SUPPLIES,PAPER & PAPER PRODUCTS,"1,114.9","1,069.2",33.8,3.07%,59.2,17,-30.5,-3.3,-30.4,-2.8,117.7,10.5
SBI Cards and Payment Services Ltd.,SBICARD,543066,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"4,221.4","2,018.8","1,327",32.47%,46.8,604.9,809.4,206.4,603,6.4,"2,302.2",24.3
Hitachi Energy India Ltd.,POWERINDIA,543187,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"1,228.2","1,162.6",65.3,5.32%,22.5,10.7,32.4,7.6,24.7,5.8,82.5,19.5
Suven Pharmaceuticals Ltd.,SUVENPHAR,543064,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,250.9,133.1,98,42.40%,11.9,0.5,105.4,25.8,79.6,3.1,431.8,17
Tata Chemicals Ltd.,TATACHEM,500770,CHEMICALS & PETROCHEMICALS,COMMODITY CHEMICALS,"4,083","3,179",819,20.49%,234,145,627,120,428,16.8,"2,06",80.8
Aarti Drugs Ltd.,AARTIDRUGS,524348,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,642.2,565.1,76.4,11.92%,12.6,8.2,56.3,16.7,39.6,4.3,180.2,19.6
Gujarat Ambuja Exports Ltd.,GAEL,524226,FMCG,EDIBLE OILS,"1,157.7","1,012.2",103.3,9.26%,30.5,5.9,109.1,26.3,82.8,3.6,305.1,13.3
Polyplex Corporation Ltd.,POLYPLEX,524051,COMMERCIAL SERVICES & SUPPLIES,CONTAINERS & PACKAGING,"1,595.7","1,451.5",120.6,7.67%,75.1,9.9,59.1,10.9,27.9,8.9,71.1,22.6
Chalet Hotels Ltd.,CHALET,542399,HOTELS RESTAURANTS & TOURISM,HOTELS,318.2,188.6,126,40.04%,35,50.1,44.5,8,36.4,1.8,266.7,13
Adani Enterprises Ltd.,ADANIENT,512599,COMMERCIAL SERVICES & SUPPLIES,COMMODITY TRADING & DISTRIBUTION,"23,066","20,087.2","2,430.1",10.79%,757,"1,342.8",791,397.8,227.8,2,"2,444.3",21.4
YES Bank Ltd.,YESBANK,532648,BANKING AND FINANCE,BANKS,"7,980.6","2,377.1",810,12.06%,0,"4,793.6",304.4,75.7,228.6,0.1,836.6,0.3
EPL Ltd.,EPL,500135,COMMERCIAL SERVICES & SUPPLIES,CONTAINERS & PACKAGING,"1,011.2",820.6,181,18.07%,83.6,30.6,76.4,25.4,50.5,1.6,251.9,7.9
Network18 Media & Investments Ltd.,NETWORK18,532798,MEDIA,BROADCASTING & CABLE TV,"2,052.2","2,083.8",-218.3,-11.70%,56.8,66.2,-154.5,-6.5,-61,-0.6,-144.2,-1.4
CIE Automotive India Ltd.,CIEINDIA,532756,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"2,299.4","1,934",345.4,15.15%,78.3,31,256.1,69.1,375.4,9.9,298.4,7.9
Vedanta Ltd.,VEDL,500295,METALS & MINING,ALUMINIUM AND ALUMINIUM PRODUCTS,"39,585","27,466","11,479",29.47%,"2,642","2,523","8,177","9,092","-1,783",-4.8,"5,202",14
Rossari Biotech Ltd.,ROSSARI,543213,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,484.8,419.9,63.6,13.15%,15.1,5,44.8,11.9,32.9,6,116.8,21.2
KPIT Technologies Ltd.,KPITTECH,542651,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,"1,208.6",959.2,239.9,20.01%,48.1,13.6,187.7,46.3,140.9,5.2,486.9,18
Intellect Design Arena Ltd.,INTELLECT,538835,SOFTWARE & SERVICES,IT SOFTWARE PRODUCTS,631.7,497.2,121.9,19.69%,33.7,0.8,96.5,25.7,70.4,5.2,316.6,23.2
Balaji Amines Ltd.,BALAMINES,530999,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,387.3,326.8,53.8,14.13%,10.8,1.8,48,11.6,34.7,10.7,197.3,60.9
UTI Asset Management Company Ltd.,UTIAMC,543238,BANKING AND FINANCE,ASSET MANAGEMENT COS.,405.6,172.5,231.5,57.30%,10.4,2.8,219.8,37,182.8,14.4,562.9,44.3
Mazagon Dock Shipbuilders Ltd.,MAZDOCK,543237,TRANSPORTATION,SHIPPING,"2,079.2","1,651.1",176.6,9.66%,20.2,1.3,406.6,102.8,332.9,16.5,"1,327.6",65.8
Computer Age Management Services Ltd.,CAMS,543232,BANKING AND FINANCE,CAPITAL MARKETS,284.7,153,122.1,44.39%,17.4,2,112.4,28.6,84.5,17.2,309.2,62.9
Happiest Minds Technologies Ltd.,HAPPSTMNDS,543227,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,428.8,324,82.6,20.32%,14.6,11.2,79.1,20.7,58.5,3.9,232,15.6
Triveni Turbine Ltd.,TRITURBINE,533655,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,402.3,313.4,74.3,19.17%,5.1,0.6,83.2,19,64.2,2,233.1,7.3
Angel One Ltd.,ANGELONE,ASM,BANKING AND FINANCE,CAPITAL MARKETS,"1,049.3",602.6,443.4,42.31%,11.2,26.4,407.2,102.7,304.5,36.3,"1,020.2",121.7
Tanla Platforms Ltd.,TANLA,532790,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,"1,014.9",811.8,196.8,19.51%,22.6,1.8,178.7,36.2,142.5,10.6,514.7,38.3
Max Healthcare Institute Ltd.,MAXHEALTH,543220,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,"1,408.6",975.8,387.4,28.42%,57.9,8.5,366.4,89.7,276.7,2.9,990.1,10.2
Asahi India Glass Ltd.,ASAHIINDIA,515030,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,122.6",934,185.6,16.58%,43,34.4,111.3,30.2,86.9,3.6,343.5,14.1
Prince Pipes & Fittings Ltd.,PRINCEPIPE,542907,GENERAL INDUSTRIALS,PLASTIC PRODUCTS,660.4,562.3,94.2,14.35%,22.5,0.7,92.8,22.2,70.6,5.2,219.8,19.9
Route Mobile Ltd.,ROUTE,543228,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,"1,018.3",886.5,128.1,12.63%,21.4,6.5,103.8,15.5,88.8,14.2,365.3,58.3
KPR Mill Ltd.,KPRMILL,532889,TEXTILES APPARELS & ACCESSORIES,TEXTILES,"1,533","1,212.9",298,19.72%,46,18.1,256,54.2,201.8,5.9,788.8,23.1
Infibeam Avenues Ltd.,INFIBEAM,539807,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,792.6,719.7,70.2,8.89%,17.1,0.5,55.2,14.7,41,0.1,142.2,0.5
Restaurant Brands Asia Ltd.,RBA,543248,HOTELS RESTAURANTS & TOURISM,RESTAURANTS,628.2,568.7,56.2,9.00%,78.6,31.5,-50.7,0,-46,-0.9,-220.3,-4.5
Larsen & Toubro Ltd.,LT,500510,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"52,157","45,392.1","5,632",11.04%,909.9,864,"4,991.1","1,135.5","3,222.6",22.9,"12,255.3",89.2
Gland Pharma Ltd.,GLAND,543245,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,426.6","1,049.3",324.1,23.60%,81.3,6,289.9,95.8,194.1,11.8,698.8,42.4
Macrotech Developers Ltd.,LODHA,543287,REALTY,REALTY,"1,755.1","1,333.5",416.1,23.78%,29.3,123.1,269.2,62.4,201.9,2.1,"1,529.2",15.9
Poonawalla Fincorp Ltd.,POONAWALLA,524000,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),745.3,178.9,531.7,71.98%,14.7,215.5,"1,124.6",270,860.2,11.2,"1,466.4",19.1
The Fertilisers and Chemicals Travancore Ltd.,FACT,590024,FERTILIZERS,FERTILIZERS,"1,713.6","1,530.8",132.4,7.96%,5.3,61.2,105.2,0,105.2,1.6,508.4,7.9
Home First Finance Company India Ltd.,HOMEFIRST,543259,BANKING AND FINANCE,HOUSING FINANCE,278,53.7,211.6,77.43%,2.8,117,96.4,22.1,74.3,8.4,266.2,30.2
CG Power and Industrial Solutions Ltd.,CGPOWER,500093,GENERAL INDUSTRIALS,HEAVY ELECTRICAL EQUIPMENT,"2,019","1,692.9",308.6,15.42%,22.9,0.4,329.9,86.2,242.3,1.6,"1,1",7.2
Laxmi Organic Industries Ltd.,LXCHEM,543277,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,660.5,613.3,38.9,5.97%,27.5,2.1,17.5,6.8,10.7,0.4,100.6,3.8
Anupam Rasayan India Ltd.,ANURAS,543275,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,395.6,284.7,107.5,27.41%,19.8,20.4,70.7,22,40.7,3.8,178.9,16.6
Kalyan Jewellers India Ltd.,KALYANKJIL,ASM,TEXTILES APPARELS & ACCESSORIES,GEMS & JEWELLERY,"4,427.7","4,100.9",313.7,7.11%,66.9,81.7,178.1,43.3,135.2,1.3,497.9,4.8
Jubilant Pharmova Ltd.,JUBLPHARMA,530019,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,690.2","1,438.5",241.8,14.39%,96.6,66.1,89,35.9,62.5,3.9,-44.6,-2.8
Indigo Paints Ltd.,INDIGOPNTS,543258,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,273.4,228.7,41.8,15.45%,10,0.5,34.3,8.2,26.1,5.5,132.4,27.8
Indian Railway Finance Corporation Ltd.,IRFC,543257,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"6,767.5",33.5,"6,732.4",99.50%,2.1,"5,181.5","1,549.9",0,"1,549.9",1.2,"6,067.6",4.6
Mastek Ltd.,MASTEK,523704,SOFTWARE & SERVICES,IT CONSULTING & SOFTWARE,770.4,642.5,123,16.07%,20.9,12.6,90.3,25,62.8,20.5,269.7,88
Equitas Small Finance Bank Ltd.,EQUITASBNK,543243,BANKING AND FINANCE,BANKS,"1,540.4",616.8,330.2,24.30%,0,593.4,267,68.9,198.1,1.8,749.5,6.7
Tata Teleservices (Maharashtra) Ltd.,TTML,532371,TELECOM SERVICES,TELECOM SERVICES,288.6,159.3,127.5,44.45%,36.3,403.2,-310.2,0,-310.2,-1.6,"-1,168.3",-6
Praj Industries Ltd.,PRAJIND,522205,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,893.3,798.4,84,9.52%,9.1,1,84.8,22.4,62.4,3.4,271.4,14.8
Nazara Technologies Ltd.,NAZARA,543280,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,309.5,269.4,26.7,8.98%,15.1,2.7,21.2,-1.3,19.8,3,60,9.1
Jubilant Ingrevia Ltd.,JUBLINGREA,543271,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"1,028.5",902.3,117.7,11.54%,33.9,12.5,79.8,22.4,57.5,3.6,258.9,16.4
Sona BLW Precision Forgings Ltd.,SONACOMS,543300,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,796.9,567.5,223.3,28.24%,53.4,6,164.1,40.1,123.8,2.1,462.8,7.9
Chemplast Sanmar Ltd.,CHEMPLASTS,543336,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"1,025",941.8,46,4.65%,35.3,38.6,9.2,-16.8,26.1,1.6,35.3,2.2
Aptus Value Housing Finance India Ltd.,APTUS,543335,BANKING AND FINANCE,HOUSING FINANCE,344.5,50.6,277.5,83.18%,2.6,96.1,189.6,41.5,148,3,551.1,11.1
Clean Science & Technology Ltd.,CLEAN,543318,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,187.1,106.3,74.8,41.32%,11.1,0.3,69.5,17.3,52.2,4.9,275.5,25.9
Medplus Health Services Ltd.,MEDPLUS,543427,HEALTHCARE EQUIPMENT & SUPPLIES,HEALTHCARE SUPPLIES,"1,419","1,323.5",85.1,6.04%,55.5,23.5,16.4,1.9,14.6,1.2,58.3,4.9
Nuvoco Vistas Corporation Ltd.,NUVOCO,543334,CEMENT AND CONSTRUCTION,CEMENT & CEMENT PRODUCTS,"2,578.9","2,243",329.9,12.82%,225.6,139.9,-29.6,-31.1,1.5,0,141.8,4
Star Health and Allied Insurance Company Ltd.,STARHEALTH,543412,BANKING AND FINANCE,GENERAL INSURANCE,"3,463.2","3,295.8",165.7,4.79%,0,0,167.1,41.8,125.3,2.1,725.4,12.4
Go Fashion (India) Ltd.,GOCOLORS,543401,TEXTILES APPARELS & ACCESSORIES,OTHER APPARELS & ACCESSORIES,192.8,132.2,56.6,29.98%,25.8,8.9,25.8,5.7,20,3.7,85.4,15.8
PB Fintech Ltd.,POLICYBZR,543390,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,909.1,900.7,-89.1,-10.98%,22.3,7.2,-21.1,-0.3,-20.2,-0.5,-127.9,-2.8
FSN E-Commerce Ventures Ltd.,NYKAA,543384,SOFTWARE & SERVICES,INTERNET & CATALOGUE RETAIL,"1,515.6","1,426.4",80.6,5.35%,54.6,21.3,13.3,4,5.8,0,19.8,0.1
Krishna Institute of Medical Sciences Ltd.,KIMS,543308,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,655.4,475.2,177.3,27.17%,32.6,8.9,138.6,37.3,92,11.5,342.1,42.7
Zomato Ltd.,ZOMATO,543320,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,"3,06","2,895",-47,-1.65%,128,16,21,-15,36,0,-496.8,-0.6
Brightcom Group Ltd.,BCG,532368,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,"1,690.5","1,172.3",518,30.65%,72.3,0.1,445.8,124.3,321.5,1.6,"1,415.2",7
Shyam Metalics and Energy Ltd.,SHYAMMETL,543299,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"2,978.9","2,633.6",307.1,10.44%,176.5,35.4,133.4,-348.6,484.1,18.9,"1,049.9",41.2
G R Infraprojects Ltd.,GRINFRA,543317,CEMENT AND CONSTRUCTION,ROADS & HIGHWAYS,"1,909.2","1,415.7",467.1,24.81%,61.7,144.6,287.1,69.9,217.2,22.5,"1,240.3",128.3
RattanIndia Enterprises Ltd.,RTNINDIA,534597,UTILITIES,ELECTRIC UTILITIES,"1,618.1","1,392.8",1.5,0.11%,4.3,28.8,142.2,1.7,140.9,1,147.6,1.1
Borosil Renewables Ltd.,BORORENEW,502219,CONSUMER DURABLES,HOUSEWARE,406.3,369.2,32.5,8.09%,31,9.6,28.9,-1.1,25.1,1.9,32.1,2.5
HLE Glascoat Ltd.,HLEGLAS,522215,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,227.8,198,26.5,11.79%,6.1,5.8,16.1,5.3,10,1.6,54.4,8
Tata Investment Corporation Ltd.,TATAINVEST,501301,DIVERSIFIED,HOLDING COMPANIES,125,10.1,113.8,91.88%,0.2,4.7,110.1,-1.3,124.4,24.6,326.1,64.4
Sapphire Foods India Ltd.,SAPPHIRE,543397,HOTELS RESTAURANTS & TOURISM,RESTAURANTS,650.1,527.5,115.1,17.91%,76.8,24.5,21.4,6.2,15.3,2.4,208.5,32.7
Devyani International Ltd.,DEVYANI,543330,HOTELS RESTAURANTS & TOURISM,RESTAURANTS,826,665,154.4,18.84%,86.3,41.7,19,-16.8,33.4,0.3,177.5,1.5
Vijaya Diagnostic Centre Ltd.,VIJAYA,543350,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE SERVICES,145.6,81.5,57.4,41.31%,13.7,5.9,44.6,11,33.3,3.3,103.4,10.1
C.E. Info Systems Ltd.,MAPMYINDIA,543425,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,99.3,50.1,41,44.98%,3.7,0.7,44.7,11.1,33,6.1,122.9,22.7
Latent View Analytics Ltd.,LATENTVIEW,543398,SOFTWARE & SERVICES,DATA PROCESSING SERVICES,172.7,124.9,30.8,19.78%,2.3,0.8,44.7,10.6,34,1.7,153.6,7.5
Metro Brands Ltd.,METROBRAND,543426,RETAILING,FOOTWEAR,571.9,400.3,155.4,27.96%,57.2,19.7,94.7,27.5,66.7,2.5,340,12.5
Easy Trip Planners Ltd.,EASEMYTRIP,543272,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,144.6,76.9,64.8,45.71%,1,2,64.7,17.7,47.2,0.3,146,0.8
Shree Renuka Sugars Ltd.,RENUKA,532670,FOOD BEVERAGES & TOBACCO,SUGAR,"2,564.7","2,491",63.7,2.49%,64.1,216.8,-207.2,-1.6,-204.9,-1,-286,-1.3
One97 Communications Ltd.,PAYTM,543396,SOFTWARE & SERVICES,INTERNET SOFTWARE & SERVICES,"2,662.5","2,749.6",-231,-9.17%,180.1,7,-279.9,12.7,-290.5,-5,"-1,207.9",-19
MTAR Technologies Ltd.,MTARTECH,543270,GENERAL INDUSTRIALS,DEFENCE,167.7,130.7,36.1,21.64%,5.8,5.5,25.7,5.2,20.5,6.7,103.3,33.6
Capri Global Capital Ltd.,CGCL,531595,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),557.4,229.3,304.8,54.70%,23.1,195.8,86,20.8,65.2,3.2,231.2,11.2
GMR Airports Infrastructure Ltd.,GMRINFRA,ASM,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"2,185","1,336.8",726.7,35.22%,373,695.8,-252,54.9,-91,-0.1,-370.9,-0.6
Triveni Engineering & Industries Ltd.,TRIVENI,532356,FOOD BEVERAGES & TOBACCO,SUGAR,"1,629.7","1,554.5",62.9,3.89%,25.8,10.2,39.3,10.1,29.1,1.3,434.3,19.8
Delhivery Ltd.,DELHIVERY,543529,TRANSPORTATION,TRANSPORTATION - LOGISTICS,"2,043","1,957.3",-15.6,-0.80%,171.2,19.6,-105.2,-2.1,-102.9,-1.4,-546.7,-7.5
Life Insurance Corporation of India,LICI,543526,BANKING AND FINANCE,LIFE INSURANCE,"202,394.9","193,612.5","8,445",4.18%,0,0,"8,696.5","1,083.9","8,030.3",12.7,"37,204.8",58.8
Campus Activewear Ltd.,CAMPUS,543523,RETAILING,FOOTWEAR,259.1,234.2,24.5,9.46%,18.1,6.5,0.4,0.1,0.3,0,103.1,3.4
Motherson Sumi Wiring India Ltd.,MSUMI,543498,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"2,110.2","1,856.5",248.1,11.79%,36.4,7.4,210,54.1,155.9,0.3,523.6,1.2
Olectra Greentech Ltd.,OLECTRA,532439,AUTOMOBILES & AUTO COMPONENTS,COMMERCIAL VEHICLES,310.3,266.6,40.5,13.20%,8.8,9.7,25.2,8,18.6,2.2,78.5,9.6
Patanjali Foods Ltd.,PATANJALI,500368,FMCG,EDIBLE OILS,"7,845.8","7,426.6",395.3,5.05%,60.1,24,335.1,80.5,254.5,7,875.2,24.2
Raymond Ltd.,RAYMOND,500330,TEXTILES APPARELS & ACCESSORIES,TEXTILES,"2,320.7","1,938.8",314.6,13.96%,65.4,89.3,204.2,50.7,159.8,24,"1,514.2",227.5
Swan Energy Ltd.,SWANENERGY,503310,REALTY,REALTY,"1,230.1",966.3,257,21.01%,27.1,58.3,178.4,12.8,84.6,6.7,308.4,11.7
Samvardhana Motherson International Ltd.,MOTHERSON,517334,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"23,639.2","21,585","1,888.8",8.05%,867.4,487.9,449.5,229.2,201.6,0.3,"1,910.3",2.8
Vedant Fashions Ltd.,MANYAVAR,543463,RETAILING,SPECIALTY RETAIL,233.4,125.5,92.8,42.51%,32.5,10.7,64.8,16.1,48.7,2,399.9,16.5
Adani Wilmar Ltd.,AWL,543458,FMCG,EDIBLE OILS,"12,331.2","12,123.5",143.7,1.17%,95.7,220.2,-161.8,-31.5,-130.7,-1,130.1,1
Mahindra Lifespace Developers Ltd.,MAHLIFE,532313,REALTY,REALTY,25.7,52.7,-34.9,-196.45%,3.1,0.2,-30.3,-10.8,-18.9,-1.2,10.5,0.7
Tejas Networks Ltd.,TEJASNET,540595,TELECOM SERVICES,OTHER TELECOM SERVICES,413.9,383,13,3.28%,41.7,7,-17.7,-5.1,-12.6,-0.7,-61.3,-3.5
Aether Industries Ltd.,AETHER,543534,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,178.3,118.2,46,28.00%,9.7,1.6,48.7,12.1,36.7,2.8,139.1,10.5
JBM Auto Ltd.,JBMA,ASM,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,238.8","1,091.3",139.7,11.35%,41.2,47.9,58.3,11.3,44.2,3.7,136.8,11.6
Deepak Fertilisers & Petrochemicals Corporation Ltd.,DEEPAKFERT,500645,CHEMICALS & PETROCHEMICALS,COMMODITY CHEMICALS,"2,443.2","2,138.1",286.1,11.80%,81.2,107.1,116.8,53.3,60.1,4.8,674.5,53.4
Sharda Cropchem Ltd.,SHARDACROP,538666,CHEMICALS & PETROCHEMICALS,AGROCHEMICALS,604.3,559.6,21.2,3.65%,74,4.6,-33.8,-6.3,-27.6,-3.1,191,21.2
Shoppers Stop Ltd.,SHOPERSTOP,532638,RETAILING,DEPARTMENT STORES,"1,049.7",878.2,160.9,15.49%,108.2,54.9,3.5,0.8,2.7,0.2,94.2,8.6
BEML Ltd.,BEML,500048,AUTOMOBILES & AUTO COMPONENTS,COMMERCIAL VEHICLES,924,855.3,61.5,6.70%,15.8,10.8,42.2,-9.6,51.8,12.4,200.8,48.2
Lemon Tree Hotels Ltd.,LEMONTREE,541233,HOTELS RESTAURANTS & TOURISM,HOTELS,230.1,125.3,101.9,44.84%,22.6,47.3,34.8,8.6,22.6,0.3,130.1,1.6
Rainbow Childrens Medicare Ltd.,RAINBOW,543524,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,340.5,215.1,117.6,35.34%,26.8,13.3,85.2,22.1,62.9,6.2,215.4,21.2
UCO Bank,UCOBANK,532505,BANKING AND FINANCE,BANKS,"5,865.6","1,581.5",981.9,18.81%,0,"3,302.3",639.8,238.1,403.5,0.3,"1,84",1.5
Piramal Pharma Ltd.,PPLPHARMA,543635,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"1,960.6","1,645.7",265.6,13.90%,184.5,109.9,20.4,34.5,5,0,-133.6,-1
KSB Ltd.,KSB,500249,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,572.2,493.4,70.3,12.47%,12.3,2,64.5,17.1,50.1,14.4,209.7,60.3
Data Patterns (India) Ltd.,DATAPATTNS,543428,GENERAL INDUSTRIALS,DEFENCE,119.2,67.5,40.8,37.63%,3.1,2.3,46.3,12.5,33.8,6,148.3,26.5
Global Health Ltd.,MEDANTA,543654,DIVERSIFIED CONSUMER SERVICES,HEALTHCARE FACILITIES,864.7,631.1,212.9,25.22%,42.9,20.1,170.6,45.4,125.2,4.7,408.9,15.2
Aarti Industries Ltd.,AARTIIND,524208,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,"1,454","1,221.2",232.8,16.01%,93,58.2,81.6,-9.1,90.7,2.5,446.2,12.3
BLS International Services Ltd.,BLS,540073,DIVERSIFIED CONSUMER SERVICES,TRAVEL SUPPORT SERVICES,416.4,321,86.7,21.27%,7.3,1,87.2,5.2,78.7,1.9,267.6,6.5
Archean Chemical Industries Ltd.,ACI,543657,CHEMICALS & PETROCHEMICALS,COMMODITY CHEMICALS,301.7,195,95.5,32.86%,17.5,1.9,87.3,21.3,66,5.4,394.4,32.1
Adani Power Ltd.,ADANIPOWER,ASM,UTILITIES,ELECTRIC UTILITIES,"14,935.7","7,819.2","5,171.4",39.81%,"1,004.5",888.4,"5,223.6","-1,370.6","6,594.2",16.5,"20,604.8",53.4
Craftsman Automation Ltd.,CRAFTSMAN,543276,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,183.8",941.6,237.5,20.14%,66.8,41.6,133.8,29.6,94.5,44.1,298.3,141.2
NMDC Ltd.,NMDC,526371,METALS & MINING,MINING,"4,335","2,823.6","1,190.4",29.66%,88.8,18.6,"1,404.1",379,"1,026.2",3.5,"5,862.2",20
Epigral Ltd.,EPIGRAL,543332,CHEMICALS & PETROCHEMICALS,SPECIALTY CHEMICALS,479.1,370.2,107.9,22.57%,31.5,21.3,56.1,17.9,38,9.1,223.4,53.8
Apar Industries Ltd.,APARINDS,532259,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,"3,944.7","3,576.2",349.8,8.91%,28.2,103.1,237.3,62.9,173.9,45.4,783.9,204.8
Bikaji Foods International Ltd.,BIKAJI,543653,FMCG,PACKAGED FOODS,614.7,521,87.7,14.41%,15.6,2.9,75.2,15.4,61.2,2.5,173.6,6.9
Five-Star Business Finance Ltd.,FIVESTAR,543663,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),522.4,133.2,375,72.28%,5.7,105.9,267,67.6,199.4,6.8,703,24.1
Ingersoll-Rand (India) Ltd.,INGERRAND,500210,GENERAL INDUSTRIALS,INDUSTRIAL MACHINERY,282.8,210.7,65.7,23.76%,4.6,0.6,67,17.2,49.7,15.8,218.5,69.2
KFIN Technologies Ltd.,KFINTECH,543720,BANKING AND FINANCE,OTHER FINANCIAL SERVICES,215.3,115.3,93.7,44.82%,12.6,3.2,84.2,22.3,61.4,3.6,215.1,12.6
Piramal Enterprises Ltd.,PEL,500302,BANKING AND FINANCE,FINANCE (INCLUDING NBFCS),"2,205.2","1,320.1","1,117.9",50.97%,38.3,"1,038.9",-11.8,10.7,48.2,2,"3,906.5",173.9
NMDC Steel Ltd.,NSLNISP,543768,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,290.3,349.6,-72.2,-26.04%,74.5,40.8,-174.7,-43.6,-131.1,-0.5,,
Eris Lifesciences Ltd.,ERIS,540596,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,508.8,324.2,181.1,35.85%,42.1,16.3,126.2,3.9,123.4,9.1,385.6,28.3
Mankind Pharma Ltd.,MANKIND,543904,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,"2,768.1","2,025.5",682.6,25.21%,96.5,8.6,637.5,129.8,501,12.5,"1,564.8",39.1
Kaynes Technology India Ltd.,KAYNES,ASM,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,369.8,312.1,48.8,13.52%,6.5,11.8,39.4,7.1,32.3,5.5,143.2,24.6
Safari Industries (India) Ltd.,SAFARI,523025,TEXTILES APPARELS & ACCESSORIES,OTHER APPARELS & ACCESSORIES,372.9,306.6,63.5,17.15%,12.2,2.2,51.9,12.1,39.8,16.7,162.3,68.2
Saregama India Ltd.,SAREGAMA,532163,MEDIA,MOVIES & ENTERTAINMENT,185.6,111.5,60.9,35.32%,8.2,0.2,65.6,17.6,48.1,2.5,193.4,10
Syrma SGS Technology Ltd.,SYRMA,543573,CONSUMER DURABLES,OTHER ELECTRICAL EQUIPMENT/PRODUCTS,720.6,662.7,49,6.88%,11.6,8,37,6.4,28.3,1.6,132.4,7.5
Jindal Saw Ltd.,JINDALSAW,ASM,GENERAL INDUSTRIALS,OTHER INDUSTRIAL PRODUCTS,"5,488.9","4,662",804.2,14.71%,142.5,188.7,495.6,139.6,375.7,11.8,"1,135.8",35.5
Godawari Power & Ispat Ltd.,GPIL,532734,METALS & MINING,IRON & STEEL/INTERM.PRODUCTS,"1,314.2",929.6,361.4,28.00%,34.8,10.2,339.6,86.1,256.9,20.6,785.5,63
Gillette India Ltd.,GILLETTE,507815,FMCG,PERSONAL PRODUCTS,676.2,530.8,136.7,20.48%,20.1,0.1,125.2,32.5,92.7,28.4,361.6,111
Symphony Ltd.,SYMPHONY,517385,CONSUMER DURABLES,CONSUMER ELECTRONICS,286,234,41,14.91%,7,2,43,8,35,5.1,114,16.5
Glenmark Life Sciences Ltd.,GLS,543322,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,600.7,428.3,167.1,28.06%,13.1,0.4,158.9,40.2,118.7,9.7,505.5,41.3
Usha Martin Ltd.,USHAMART,517146,METALS & MINING,IRON & STEEL PRODUCTS,806,640.4,144.3,18.39%,18,6.4,141.2,35,109.5,3.6,399.4,13.1
Ircon International Ltd.,IRCON,541956,CEMENT AND CONSTRUCTION,CONSTRUCTION & ENGINEERING,"3,136.3","2,771.2",215.7,7.22%,27.1,36.9,301.2,77.6,250.7,2.7,884.6,9.4
Ujjivan Small Finance Bank Ltd.,UJJIVANSFB,542904,BANKING AND FINANCE,BANKS,"1,579.8",528.6,483.4,34.75%,0,567.8,436.4,108.7,327.7,1.7,"1,254.5",6.4
Procter & Gamble Health Ltd.,PGHL,500126,PHARMACEUTICALS & BIOTECHNOLOGY,PHARMACEUTICALS,311,216.3,88.7,29.08%,6.5,0.2,88,22.5,65.6,39.5,231.4,139.4
Allcargo Logistics Ltd.,ALLCARGO,532749,TRANSPORTATION,TRANSPORTATION - LOGISTICS,"3,336.3","3,188.8",118,3.57%,106.7,36.7,14.2,1.3,21.8,0.9,361.9,14.7
Sheela Foam Ltd.,SFL,540203,DIVERSIFIED CONSUMER SERVICES,FURNITURE-FURNISHING-PAINTS,637.6,547,66.2,10.80%,21.9,8.6,60.2,15.6,44,4.5,192.4,17.7
Alok Industries Ltd.,ALOKINDS,521070,TEXTILES APPARELS & ACCESSORIES,TEXTILES,"1,369.3","1,323.1",35.9,2.64%,78.6,142.2,-174.6,0,-174.8,-0.3,-948.4,-1.9
Minda Corporation Ltd.,MINDACORP,538962,AUTOMOBILES & AUTO COMPONENTS,AUTO PARTS & EQUIPMENT,"1,197.9","1,064.5",131.3,10.98%,41.4,14.9,77,18.7,58.8,2.5,278.2,11.6
Concord Biotech Ltd.,CONCORDBIO,543960,PHARMACEUTICALS & BIOTECHNOLOGY,BIOTECHNOLOGY,270.5,143.2,119.2,45.43%,13.3,0.8,113.2,28.7,81,7.7,,
1 name NSE_code BSE_code sector industry revenue operating_expenses operating_profit operating_profit_margin depreciation interest profit_before_tax tax net_profit EPS profit_TTM EPS_TTM
2 3M India Ltd. 3MINDIA 523395 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 1,057 847.4 192.1 18.48% 12.9 0.7 195.9 49.8 146.1 129.7 535.9 475.7
3 ACC Ltd. ACC 500410 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 4,644.8 3,885.4 549.3 12.39% 212.8 28.9 517.7 131.5 387.9 20.7 1,202.7 64
4 AIA Engineering Ltd. AIAENG 532683 GENERAL INDUSTRIALS OTHER INDUSTRIAL GOODS 1,357.1 912.7 382.1 29.51% 24.5 7.4 412.5 88.4 323.1 34.3 1,216.1 128.9
5 APL Apollo Tubes Ltd. APLAPOLLO 533758 METALS & MINING IRON & STEEL PRODUCTS 4,65 4,305.4 325 7.02% 41.3 26.6 276.7 73.8 202.9 7.3 767.5 27.7
6 Au Small Finance Bank Ltd. AUBANK 540611 BANKING AND FINANCE BANKS 2,956.5 1,026.7 647.7 25.59% 0 1,282.1 533.4 131.5 401.8 6 1,606.2 24
7 Adani Ports & Special Economic Zone Ltd. ADANIPORTS 532921 TRANSPORTATION MARINE PORT & SERVICES 6,951.9 2,982.4 3,664 55.13% 974.5 520.1 2,474.9 759 1,747.8 8.1 6,337 29.3
8 Adani Energy Solutions Ltd. ADANIENSOL ASM UTILITIES ELECTRIC UTILITIES 3,766.5 2,169.3 1,504.6 40.95% 432.1 640.8 369.9 84.9 275.9 2.5 1,315.1 11.8
9 Aditya Birla Fashion and Retail Ltd. ABFRL 535755 RETAILING DEPARTMENT STORES 3,272.2 2,903.6 322.9 10.01% 388.8 208.4 -228.6 -28.2 -179.2 -1.9 -491.7 -5.2
10 Aegis Logistics Ltd. AEGISCHEM 500003 OIL & GAS OIL MARKETING & DISTRIBUTION 1,279.3 1,026.5 208.3 16.87% 34.1 26.6 192 42 127 3.6 509 14.5
11 Ajanta Pharma Ltd. AJANTPHARM 532331 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,049.8 737.8 290.7 28.26% 33.7 2.3 275.9 80.6 195.3 15.5 660.2 52.3
12 Alembic Pharmaceuticals Ltd. APLLTD 533573 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,605.1 1,386.7 208.2 13.06% 67.6 15.7 135.1 -1.9 136.6 7 531.7 27
13 Alkem Laboratories Ltd. ALKEM 539523 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 3,503.4 2,693.4 746.7 21.71% 73.9 30.3 648 33.1 620.5 51.9 1,432.9 119.9
14 Amara Raja Energy & Mobility Ltd. ARE&M 500008 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 2,988.6 2,556.9 402.5 13.60% 115.7 6.2 309.8 83.5 226.3 13.2 779.8 45.7
15 Ambuja Cements Ltd. AMBUJACEM 500425 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 7,9 6,122.1 1,301.8 17.54% 380.9 61.2 1,335.7 352.5 793 4 2,777.9 14
16 Apollo Hospitals Enterprise Ltd. APOLLOHOSP 508869 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 4,869.1 4,219.4 627.5 12.95% 163.4 111.3 376.9 130.2 232.9 16.2 697.5 48.5
17 Apollo Tyres Ltd. APOLLOTYRE 500877 AUTOMOBILES & AUTO COMPONENTS AUTO TYRES & RUBBER PRODUCTS 6,304.9 5,119.8 1,159.8 18.47% 360.3 132.8 679.9 205.8 474.3 7.5 1,590.7 25
18 Ashok Leyland Ltd. ASHOKLEY 500477 AUTOMOBILES & AUTO COMPONENTS COMMERCIAL VEHICLES 11,463 9,558.6 1,870.4 16.37% 226.6 715.1 924.4 358 526 1.8 2,141.5 7.3
19 Asian Paints Ltd. ASIANPAINT 500820 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 8,643.8 6,762.3 1,716.2 20.24% 208.7 50.9 1,621.8 418.6 1,205.4 12.6 5,062.6 52.8
20 Astral Ltd. ASTRAL 532830 GENERAL INDUSTRIALS PLASTIC PRODUCTS 1,376.4 1,142.9 220.1 16.15% 48.7 8 176.8 45.1 131.2 4.9 549.7 20.4
21 Atul Ltd. ATUL 500027 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 1,215.8 1,038.5 155.2 13.00% 54 1.9 121.5 32.5 90.3 30.6 392.3 132.9
22 Aurobindo Pharma Ltd. AUROPHARMA 524804 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 7,406.4 5,846 1,373.4 19.02% 417.5 68.2 1,074.7 323.7 757.2 12.8 2,325.5 39.7
23 Avanti Feeds Ltd. AVANTIFEED 512573 FOOD BEVERAGES & TOBACCO OTHER FOOD PRODUCTS 1,312 1,184.5 94 7.35% 14.3 0.2 113 30.5 74.2 5.5 336.4 24.7
24 Avenue Supermarts Ltd. DMART 540376 RETAILING DEPARTMENT STORES 12,661.3 11,619.4 1,005 7.96% 174.4 15.6 851.9 228.6 623.6 9.6 2,332.1 35.8
25 Axis Bank Ltd. AXISBANK 532215 BANKING AND FINANCE BANKS 33,122.2 9,207.3 9,166 33.43% 0 14,749 8,313.8 2,096.1 6,204.1 20.1 13,121 42.6
26 Bajaj Auto Ltd. BAJAJ-AUTO 532977 AUTOMOBILES & AUTO COMPONENTS 2/3 WHEELERS 11,206.8 8,708.1 2,130.1 19.65% 91.8 6.5 2,400.4 564 2,02 71.4 6,841.6 241.8
27 Bajaj Finance Ltd. BAJFINANCE 500034 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 13,381.8 2,851.5 9,449.7 70.63% 158.5 4,537.1 4,757.6 1,207 3,550.8 58.7 13,118.5 216.7
28 Bajaj Finserv Ltd. BAJAJFINSV 532978 DIVERSIFIED HOLDING COMPANIES 26,022.7 14,992.2 9,949.9 38.24% 208.8 4,449.1 5,292 1,536.5 1,929 12.1 7,422.6 46.6
29 Bajaj Holdings & Investment Ltd. BAJAJHLDNG 500490 DIVERSIFIED HOLDING COMPANIES 240.1 33.5 191.2 85.08% 8.4 0.2 197.9 73.9 1,491.2 134 5,545.1 498.3
30 Balkrishna Industries Ltd. BALKRISIND 502355 AUTOMOBILES & AUTO COMPONENTS AUTO TYRES & RUBBER PRODUCTS 2,360.3 1,720.5 532.7 23.64% 160.4 23.9 455.5 108.1 347.4 18 1,047.5 54.2
31 Balrampur Chini Mills Ltd. BALRAMCHIN 500038 FOOD BEVERAGES & TOBACCO SUGAR 1,649 1,374.6 164.9 10.71% 41.2 17.2 215.9 56.6 166.3 8.2 540.5 26.8
32 Bank of Baroda BANKBARODA 532134 BANKING AND FINANCE BANKS 35,766 8,430.4 9,807.9 33.52% 0 17,527.7 6,022.8 1,679.7 4,458.4 8.5 18,602.9 35.9
33 Bank of India BANKINDIA 532149 BANKING AND FINANCE BANKS 16,779.4 3,704.9 3,818.8 25.35% 0 9,255.7 2,977.4 1,488.6 1,498.5 3.6 5,388.7 13.1
34 Bata India Ltd. BATAINDIA 500043 RETAILING FOOTWEAR 834.6 637.5 181.7 22.18% 81.7 28.4 46.1 12.1 34 2.6 289.7 22.5
35 Berger Paints (India) Ltd. BERGEPAINT 509480 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 2,782.6 2,293.7 473.6 17.12% 82.9 21.1 385 96.7 291.6 2.5 1,032.6 8.9
36 Bharat Electronics Ltd. BEL 500049 GENERAL INDUSTRIALS DEFENCE 4,146.1 2,994.9 1,014.2 25.30% 108.3 1.5 1,041.5 260.7 789.4 1.1 3,323 4.5
37 Bharat Forge Ltd. BHARATFORG 500493 GENERAL INDUSTRIALS OTHER INDUSTRIAL PRODUCTS 3,826.7 3,152.8 621.4 16.47% 211.3 124.3 336.1 121.8 227.2 4.9 783.7 16.8
38 Bharat Heavy Electricals Ltd. BHEL 500103 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 5,305.4 5,513 -387.7 -7.56% 59.9 180.4 -447.9 -197.9 -238.1 -0.7 71.3 0.2
39 Bharat Petroleum Corporation Ltd. BPCL 500547 OIL & GAS REFINERIES/PETRO-PRODUCTS 103,72 90,103.9 12,940.5 12.56% 1,605.3 973.2 10,755.7 2,812.2 8,243.5 38.7 27,505.3 129.2
40 Bharti Airtel Ltd. BHARTIARTL 532454 TELECOM SERVICES TELECOM SERVICES 37,374.2 17,530.1 19,513.7 52.68% 9,734.3 5,185.8 3,353.7 1,846.5 1,340.7 2.4 7,547 13.2
41 Indus Towers Ltd. INDUSTOWER 534816 TELECOM SERVICES OTHER TELECOM SERVICES 7,229.7 3,498.8 3,633.7 50.95% 1,525.6 458.6 1,746.7 452 1,294.7 4.8 3,333.5 12.4
42 Biocon Ltd. BIOCON 532523 PHARMACEUTICALS & BIOTECHNOLOGY BIOTECHNOLOGY 3,620.2 2,720.7 741.6 21.42% 389.3 247.7 238.5 41.6 125.6 1.1 498.4 4.2
43 Birla Corporation Ltd. BIRLACORPN 500335 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 2,313.2 1,997 288.9 12.64% 143.5 95.4 77.1 18.8 58.4 7.6 153.1 19.9
44 Blue Dart Express Ltd. BLUEDART 526612 TRANSPORTATION TRANSPORTATION - LOGISTICS 1,329.7 1,101.8 222.7 16.82% 110.6 19.5 97.9 24.8 73.1 30.8 292.4 123.2
45 Blue Star Ltd. BLUESTARCO 500067 CONSUMER DURABLES CONSUMER ELECTRONICS 1,903.4 1,767.7 122.7 6.49% 23 17.6 95 24.3 70.7 3.6 437.7 21.3
46 Bombay Burmah Trading Corporation Ltd. BBTC 501425 FOOD BEVERAGES & TOBACCO TEA & COFFEE 4,643.5 3,664.7 859.2 18.99% 74.7 154.6 697.1 212.6 122 17.5 -1,499.5 -214.8
47 Bosch Ltd. BOSCHLTD 500530 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 4,284.3 3,638.8 491.3 11.90% 101.3 12.2 1,317 318.1 999.8 339 2,126.9 721
48 Brigade Enterprises Ltd. BRIGADE 532929 REALTY REALTY 1,407.9 1,041.8 324.8 23.77% 75.7 110 180.3 67.8 133.5 5.8 298.2 12.9
49 Britannia Industries Ltd. BRITANNIA 500825 FMCG PACKAGED FOODS 4,485.2 3,560.5 872.4 19.68% 71.7 53.4 799.7 212.1 587.6 24.4 2,536.2 105.3
50 CCL Products India Ltd. CCL 519600 FOOD BEVERAGES & TOBACCO TEA & COFFEE 608.3 497.7 109.9 18.09% 22.6 18.4 69.7 8.8 60.9 4.6 279.9 21
51 Crisil Ltd. CRISIL 500092 BANKING AND FINANCE OTHER FINANCIAL SERVICES 771.8 544.2 191.7 26.05% 26.5 0.8 200.3 48.3 152 20.8 606.3 82.9
52 Zydus Lifesciences Ltd. ZYDUSLIFE 532321 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 4,422.8 3,222.7 1,146.1 26.23% 184.2 8.7 1,007.2 226.4 800.7 7.9 2,807.1 27.7
53 Can Fin Homes Ltd. CANFINHOME 511196 BANKING AND FINANCE HOUSING FINANCE 871 49.7 749.2 86.01% 2.8 548.4 198 39.9 158.1 11.9 658.8 49.5
54 Canara Bank CANBK 532483 BANKING AND FINANCE BANKS 33,891.2 8,250.3 7,706.6 28.24% 0 17,934.3 5,098 1,420.6 3,86 20.9 13,968.4 77
55 Carborundum Universal Ltd. CARBORUNIV 513375 GENERAL INDUSTRIALS OTHER INDUSTRIAL PRODUCTS 1,166 978.8 167.5 14.61% 45.9 4.9 136.4 43.7 101.9 5.4 461.3 24.3
56 Castrol India Ltd. CASTROLIND 500870 OIL & GAS OIL MARKETING & DISTRIBUTION 1,203.2 914.4 268.6 22.70% 22.9 2.4 263.5 69.1 194.4 2 815.5 8.2
57 Ceat Ltd. CEATLTD 500878 AUTOMOBILES & AUTO COMPONENTS AUTO TYRES & RUBBER PRODUCTS 3,063.8 2,597.2 456.1 14.94% 124.5 71.7 270.4 68.3 208 51.4 521.7 129
58 Central Bank of India CENTRALBK 532885 BANKING AND FINANCE BANKS 8,438.5 2,565.4 1,535.4 20.81% 0 4,337.7 567.2 -41.5 622 0.7 2,181.4 2.5
59 Century Plyboards (India) Ltd. CENTURYPLY 532548 FOREST MATERIALS FOREST PRODUCTS 1,011.4 852.5 144.3 14.47% 23.4 6.1 129.4 32.2 96.9 4.4 380.7 17.1
60 Cera Sanitaryware Ltd. CERA 532443 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 476.2 387.2 76.5 16.49% 8.9 1.4 77.2 19.8 56.9 43.8 232.4 178.7
61 Chambal Fertilisers & Chemicals Ltd. CHAMBLFERT 500085 FERTILIZERS FERTILIZERS 5,467.3 4,770.5 615 11.42% 78.4 45.8 572.6 200.2 381 9.2 1,137.7 27.3
62 Cholamandalam Investment & Finance Company Ltd. CHOLAFIN 511243 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 4,695.2 987.6 3,235.1 69.99% 38.5 2,204.2 1,065 288.8 772.9 9.4 3,022.8 36.7
63 Cipla Ltd. CIPLA 500087 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 6,854.5 4,944.4 1,733.8 25.96% 290 25.8 1,594.2 438.4 1,130.9 14 3,449.1 42.7
64 City Union Bank Ltd. CUB 532210 BANKING AND FINANCE BANKS 1,486.1 333.9 386.6 29.65% 0 765.6 330.6 50 280.6 3.8 943.8 12.7
65 Coal India Ltd. COALINDIA 533278 METALS & MINING COAL 34,760.3 24,639.4 8,137 24.83% 1,178.2 182.5 8,760.2 2,036.5 6,799.8 11 28,059.6 45.5
66 Colgate-Palmolive (India) Ltd. COLPAL 500830 FMCG PERSONAL PRODUCTS 1,492.1 989 482.1 32.77% 44.3 1.1 457.8 117.8 340.1 12.5 1,173.2 43.1
67 Container Corporation of India Ltd. CONCOR 531344 COMMERCIAL SERVICES & SUPPLIES WAREHOUSING AND LOGISTICS 2,299.8 1,648.4 546.5 24.90% 153.1 16.5 481.8 119 367.4 6 1,186.2 19.5
68 Coromandel International Ltd. COROMANDEL 506395 FERTILIZERS FERTILIZERS 7,032.9 5,929.4 1,058.7 15.15% 54 46.2 1,003.3 245 756.9 25.7 2,024.2 68.8
69 Crompton Greaves Consumer Electricals Ltd. CROMPTON 539876 CONSUMER DURABLES HOUSEHOLD APPLIANCES 1,797.2 1,607.8 174.5 9.79% 32.1 21.5 135.8 34.9 97.2 1.5 432 6.7
70 Cummins India Ltd. CUMMINSIND 500480 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 2,011.3 1,575.4 346.2 18.02% 38.3 6.8 390.9 99.6 329.1 11.9 1,445.5 52.1
71 Cyient Ltd. CYIENT 532175 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 1,792 1,452.7 325.8 18.32% 65.8 27 240.3 56.7 178.3 16.3 665.6 60.1
72 DCM Shriram Ltd. DCMSHRIRAM 523367 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 2,73 2,593.9 114.1 4.21% 74 14.7 47.5 15.2 32.2 2.1 617.6 39.4
73 DLF Ltd. DLF 532868 REALTY REALTY 1,476.4 885.3 462.4 34.31% 37 90.2 464 112.2 622.8 2.5 2,239 9
74 Dabur India Ltd. DABUR 500096 FMCG PERSONAL PRODUCTS 3,320.2 2,543 660.9 20.63% 98.3 28.1 650.8 144.3 515 2.9 1,755.7 9.9
75 Delta Corp Ltd. DELTACORP 532848 COMMERCIAL SERVICES & SUPPLIES MISC. COMMERCIAL SERVICES 282.6 170.5 100.1 36.99% 16.9 2.7 92.4 23 69.4 2.6 273.3 10.2
76 Divi's Laboratories Ltd. DIVISLAB 532488 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,995 1,43 479 25.09% 95 1 469 121 348 13.1 1,331.8 50.3
77 Dr. Lal Pathlabs Ltd. LALPATHLAB 539524 DIVERSIFIED CONSUMER SERVICES HEALTHCARE SERVICES 619.4 423.5 177.8 29.57% 35.9 7.8 152.2 41.5 109.3 13.2 301.4 36.1
78 Dr. Reddy's Laboratories Ltd. DRREDDY 500124 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 7,217.6 4,888.8 2,008.3 29.09% 375.5 35.3 1,912.5 434.5 1,482.2 89.1 5,091.2 305.2
79 EID Parry (India) Ltd. EIDPARRY 500125 FOOD BEVERAGES & TOBACCO OTHER FOOD PRODUCTS 9,210.3 8,002 1,057.5 11.67% 101.2 74.2 1,032.8 246.8 452.3 25.5 991 55.8
80 Eicher Motors Ltd. EICHERMOT 505200 AUTOMOBILES & AUTO COMPONENTS 2/3 WHEELERS 4,388.3 3,027.4 1,087.2 26.42% 142.5 12.7 1,205.7 291.1 1,016.2 37.1 3,581 130.8
81 Emami Ltd. EMAMILTD 531162 FMCG PERSONAL PRODUCTS 876 631.2 233.7 27.02% 46.1 2.2 196.4 15.8 178.5 4.1 697.8 16
82 Endurance Technologies Ltd. ENDURANCE 540153 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 2,560.5 2,226.7 318.3 12.51% 118.4 9.8 205.6 51.1 154.6 11 562.8 40
83 Engineers India Ltd. ENGINERSIN 532178 COMMERCIAL SERVICES & SUPPLIES CONSULTING SERVICES 833.6 691.3 98.5 12.47% 8.3 0.4 133.6 32.2 127.5 2.3 472.7 8.4
84 Escorts Kubota Ltd. ESCORTS 500495 AUTOMOBILES & AUTO COMPONENTS COMMERCIAL VEHICLES 2,154.4 1,798.6 260.7 12.66% 40.8 3.1 311.9 79.7 223.3 20.6 910.5 82.4
85 Exide Industries Ltd. EXIDEIND 500086 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 4,408.9 3,872.4 499.1 11.42% 141.5 29.7 365.3 95.2 269.4 3.2 872.7 10.3
86 Federal Bank Ltd. FEDERALBNK 500469 BANKING AND FINANCE BANKS 6,548.2 1,603.8 1,400.3 24.18% 0 3,544.1 1,342.7 342.6 994.1 4.3 3,671.4 15.6
87 Finolex Cables Ltd. FINCABLES 500144 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 1,229.3 1,041.3 146.1 12.30% 10.8 0.4 176.7 52.3 154.2 10.1 643.9 42.1
88 Finolex Industries Ltd. FINPIPE 500940 GENERAL INDUSTRIALS PLASTIC PRODUCTS 944.5 780.2 103 11.66% 27.4 12.5 124.5 35.4 98 1.6 459.3 7.4
89 Firstsource Solutions Ltd. FSL 532809 SOFTWARE & SERVICES BPO/KPO 1,556.9 1,311.2 228.8 14.86% 65.4 26.1 154.3 27.8 126.5 1.9 551.7 7.9
90 GAIL (India) Ltd. GAIL 532155 UTILITIES UTILITIES 33,191 29,405.5 3,580.2 10.85% 837.3 199.6 2,748.7 696.3 2,444.1 3.7 5,283.8 8
91 GlaxoSmithKline Pharmaceuticals Ltd. GLAXO 500660 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 985.2 667.5 289.5 30.25% 18.1 0.4 299.2 81.7 217.5 12.8 647.8 38.2
92 Glenmark Pharmaceuticals Ltd. GLENMARK 532296 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 3,209.1 2,745.1 462.3 14.41% 141.5 121.5 -124.4 55.9 -81.9 -2.9 -196.3 -7
93 Godrej Consumer Products Ltd. GODREJCP 532424 FMCG PERSONAL PRODUCTS 3,667.9 2,897.8 704.2 19.55% 60.9 77.3 619.4 186.6 432.8 4.2 1,750.1 17.1
94 Godrej Industries Ltd. GODREJIND 500164 DIVERSIFIED DIVERSIFIED 4,256.9 3,672.1 265.5 6.74% 89.3 333.1 162.4 75.9 87.3 2.6 880 26.1
95 Godrej Properties Ltd. GODREJPROP 533150 REALTY REALTY 605.1 404.7 -61.7 -17.98% 7.4 48 145.1 38.8 66.8 2.4 662.6 23.8
96 Granules India Ltd. GRANULES 532482 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,191 976.5 213 17.90% 52.5 26 136 33.9 102.1 4.2 393.9 16.3
97 Great Eastern Shipping Company Ltd. GESHIP 500620 TRANSPORTATION SHIPPING 1,461.5 585.6 643.4 52.35% 186.7 77.1 611.9 17.3 594.7 41.6 2,520.1 176.5
98 Gujarat Alkalies & Chemicals Ltd. GUJALKALI 530001 CHEMICALS & PETROCHEMICALS COMMODITY CHEMICALS 1,042.3 926.1 45.2 4.65% 95.2 10.8 10.2 -0.1 -18.4 -2.5 82.7 11.3
99 Gujarat Gas Ltd. GUJGASLTD 539336 UTILITIES UTILITIES 4,019.3 3,494.5 496.6 12.44% 117.9 7.8 399.1 102.9 296.2 4.3 1,254.3 18.2
100 Gujarat Narmada Valley Fertilizers & Chemicals Ltd. GNFC 500670 FERTILIZERS FERTILIZERS 2,232 1,911 169 8.12% 78 1 242 64 182 11.7 932 60.1
101 Gujarat Pipavav Port Ltd. GPPL 533248 TRANSPORTATION MARINE PORT & SERVICES 270.4 102 150.6 59.64% 28.8 2.2 141.1 53.4 92.3 1.9 341.8 7.1
102 Gujarat State Fertilizer & Chemicals Ltd. GSFC 500690 FERTILIZERS FERTILIZERS 3,313.2 2,881.4 237.3 7.61% 45.7 1.6 387 78.1 308.9 7.8 1,056.2 26.5
103 Gujarat State Petronet Ltd. GSPL 532702 UTILITIES UTILITIES 4,455.9 3,497.2 913.7 20.72% 165 14.5 779.2 198.7 454.6 8.1 1,522 27
104 HCL Technologies Ltd. HCLTECH 532281 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 27,037 20,743 5,929 22.23% 1,01 156 5,128 1,295 3,832 14.2 15,445 56.9
105 HDFC Bank Ltd. HDFCBANK 500180 BANKING AND FINANCE BANKS 107,566.6 42,037.6 24,279.1 32.36% 0 41,249.9 20,967.4 3,655 16,811.4 22.2 54,474.6 71.8
106 Havells India Ltd. HAVELLS 517354 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 3,952.8 3,527 373.4 9.57% 81.2 9.3 335.3 86.2 249.1 4 1,177.7 18.8
107 Hero MotoCorp Ltd. HEROMOTOCO 500182 AUTOMOBILES & AUTO COMPONENTS 2/3 WHEELERS 9,741.2 8,173.5 1,359.5 14.26% 187.1 25 1,355.6 353.1 1,006.3 50.3 3,247.6 162.5
108 HFCL Ltd. HFCL 500183 TELECOMMUNICATIONS EQUIPMENT TELECOM CABLES 1,128.7 978.9 132.6 11.93% 21.4 34.8 93.5 24 69.4 0.5 305.5 2.1
109 Hindalco Industries Ltd. HINDALCO 500440 METALS & MINING ALUMINIUM AND ALUMINIUM PRODUCTS 54,632 48,557 5,612 10.36% 1,843 1,034 3,231 1,035 2,196 9.9 8,423 37.9
110 Hindustan Copper Ltd. HINDCOPPER 513599 METALS & MINING COPPER 392.6 260.2 121.2 31.77% 45.6 4.1 82.6 21.9 60.7 0.6 320.5 3.3
111 Hindustan Petroleum Corporation Ltd. HINDPETRO 500104 OIL & GAS REFINERIES/PETRO-PRODUCTS 96,093.4 87,512 8,24 8.61% 1,247.3 590 6,744.1 1,616 5,827 41.1 16,645 117.3
112 Hindustan Unilever Ltd. HINDUNILVR 500696 FMCG PERSONAL PRODUCTS 15,806 11,826 3,797 24.30% 297 88 3,59 931 2,656 11.3 10,284 43.8
113 Hindustan Zinc Ltd. HINDZINC 500188 METALS & MINING ZINC 7,014 3,652 3,139 46.22% 825 232 2,305 576 1,729 4.1 8,432 20
114 Housing and Urban Development Corporation Ltd. HUDCO 540530 BANKING AND FINANCE HOUSING FINANCE 1,880.8 82.7 1,809.6 97.04% 2.4 1,216.8 606.4 154.7 451.6 2.3 1,790.7 8.9
115 ITC Ltd. ITC 500875 FOOD BEVERAGES & TOBACCO CIGARETTES-TOBACCO PRODUCTS 18,439.3 11,320.2 6,454.2 36.31% 453 9.9 6,656.2 1,700.3 4,898.1 3.9 20,185.1 16.2
116 ICICI Bank Ltd. ICICIBANK 532174 BANKING AND FINANCE BANKS 57,292.3 23,911 15,473.2 39.74% 0 17,908 14,824.2 3,808.8 11,805.6 15.6 41,086.8 58.7
117 ICICI Prudential Life Insurance Company Ltd. ICICIPRULI 540133 BANKING AND FINANCE LIFE INSURANCE 17,958.1 17,612.3 -229.6 -1.32% 0 0 340.2 32.5 243.9 1.7 906.9 6.3
118 IDBI Bank Ltd. IDBI 500116 BANKING AND FINANCE BANKS 7,063.7 1,922.3 2,175.3 36.02% 0 2,966.1 2,396.9 1,003.7 1,385.4 1.3 4,776.3 4.4
119 IDFC First Bank Ltd. IDFCFIRSTB 539437 BANKING AND FINANCE BANKS 8,765.8 3,849 1,511.2 20.54% 0 3,405.6 982.8 236 746.9 1.1 2,911.1 4.3
120 IDFC Ltd. IDFC 532659 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 36.7 6 30.6 83.56% 0 0 30.6 6.6 223.5 1.4 4,147.1 25.9
121 IRB Infrastructure Developers Ltd. IRB 532947 CEMENT AND CONSTRUCTION ROADS & HIGHWAYS 1,874.5 950.4 794.6 45.54% 232.7 434.6 256.9 85.8 95.7 0.2 501 0.8
122 ITI Ltd. ITI 523610 TELECOMMUNICATIONS EQUIPMENT TELECOM EQUIPMENT 256.1 299.3 -52.8 -21.42% 13.3 69.3 -125.8 0 -126 -1.3 -388.4 -4
123 Vodafone Idea Ltd. IDEA 532822 TELECOM SERVICES TELECOM SERVICES 10,750.8 6,433.5 4,282.8 39.97% 5,667.3 6,569 -7,919 817.7 -8,737.9 -1.8 -30,986.8 -6.4
124 India Cements Ltd. INDIACEM 530005 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 1,272.4 1,26 4.4 0.35% 55 60.4 -103 -17.4 -80.1 -2.6 -261.1 -8.4
125 Indiabulls Housing Finance Ltd. IBULHSGFIN 535789 BANKING AND FINANCE HOUSING FINANCE 2,242.3 190.6 1,779.2 79.88% 22.9 1,349.8 421.6 123.6 298 6.5 1,146 24.3
126 Indian Bank INDIANB 532814 BANKING AND FINANCE BANKS 15,929.4 3,599.1 4,327.7 31.44% 0 8,002.6 2,776.7 768.6 2,068.5 16.6 6,893.3 55.3
127 Indian Hotels Company Ltd. INDHOTEL 500850 HOTELS RESTAURANTS & TOURISM HOTELS 1,480.9 1,078.4 354.8 24.75% 111.2 59 232.2 72.3 166.9 1.2 1,100.3 7.7
128 Indian Oil Corporation Ltd. IOC 530965 OIL & GAS OIL MARKETING & DISTRIBUTION 179,752.1 156,013.1 23,328.4 13.01% 3,609.6 2,135 18,090.2 4,699.7 13,114.3 9.5 38,614.3 27.3
129 Indian Overseas Bank IOB 532388 BANKING AND FINANCE BANKS 6,941.5 1,785.1 1,679.8 28.84% 0 3,476.6 635.5 8.3 627.2 0.3 2,341.9 1.2
130 Indraprastha Gas Ltd. IGL 532514 UTILITIES UTILITIES 3,520.2 2,801.6 656.9 18.99% 102.2 2.5 613.9 151.4 552.7 7.9 1,806.2 25.8
131 IndusInd Bank Ltd. INDUSINDBK 532187 BANKING AND FINANCE BANKS 13,529.7 3,449.9 3,908.7 34.75% 0 6,171.1 2,934.9 732.9 2,202.2 28.4 8,333.7 107.2
132 Info Edge (India) Ltd. NAUKRI 532777 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 792 421.2 204.7 32.70% 25.9 8.2 382.8 68.7 205.1 15.9 -25.6 -2
133 InterGlobe Aviation Ltd. INDIGO 539448 TRANSPORTATION AIRLINES 15,502.9 12,743.6 2,200.3 14.72% 1,549 1,021.3 189.1 0.2 188.9 4.9 5,621.3 145.7
134 Ipca Laboratories Ltd. IPCALAB 524494 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 2,072.5 1,712.7 321.3 15.80% 90.3 44.1 225.4 87.9 145.1 5.7 492.2 19.4
135 J B Chemicals & Pharmaceuticals Ltd. JBCHEPHARM 506943 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 889.4 638.2 243.5 27.62% 32.2 10.4 208.7 58.1 150.6 9.7 486.6 31.4
136 JK Cement Ltd. JKCEMENT 532644 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 2,782.1 2,285.8 467 16.96% 137.1 115 244.2 65.7 178.1 23.1 444 57.5
137 JK Lakshmi Cement Ltd. JKLAKSHMI 500380 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 1,588.5 1,357.3 217.3 13.80% 56.6 33.6 141 45.1 92.7 7.9 357.6 30.4
138 JM Financial Ltd. JMFINANCIL 523405 DIVERSIFIED HOLDING COMPANIES 1,214 407.9 662.6 55.34% 13.2 388.1 277.9 72.4 194.9 2 608.1 6.4
139 JSW Energy Ltd. JSWENERGY 533148 UTILITIES ELECTRIC UTILITIES 3,387.4 1,379 1,880.4 57.69% 408.7 513.7 1,085.9 235.1 850.2 5.2 1,591.7 9.7
140 JSW Steel Ltd. JSWSTEEL 500228 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 44,821 36,698 7,886 17.69% 2,019 2,084 4,609 1,812 2,76 11.4 9,252 38.1
141 Jindal Stainless Ltd. JSL 532508 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 9,829 8,566.5 1,230.6 12.56% 221.9 155.6 985.7 229.1 774.3 9.4 2,600.2 31.6
142 Jindal Steel & Power Ltd. JINDALSTEL 532286 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 12,282 9,964.5 2,285.7 18.66% 603.7 329.4 1,384.5 -5.8 1,387.8 13.8 4,056 40.4
143 Jubilant Foodworks Ltd. JUBLFOOD 533155 HOTELS RESTAURANTS & TOURISM RESTAURANTS 1,375.7 1,091.4 277.2 20.25% 141.9 56.8 85.5 23.3 97.2 1.5 235 3.6
144 Just Dial Ltd. JUSTDIAL 535648 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 318.5 211.8 48.8 18.71% 12.2 2.4 92.1 20.3 71.8 8.4 314.1 36.9
145 Jyothy Labs Ltd. JYOTHYLAB 532926 FMCG PERSONAL PRODUCTS 745.6 597 135.4 18.48% 12.3 1.2 135.1 31.1 104.2 2.8 326.9 8.9
146 KRBL Ltd. KRBL 530813 FMCG PACKAGED FOODS 1,246.5 1,018.9 194.5 16.03% 19.9 0.8 206.8 53.6 153.3 6.5 671.4 29.3
147 Kajaria Ceramics Ltd. KAJARIACER 500233 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 1,129.9 941.9 179.7 16.02% 36.1 4.3 147.7 36.6 108 6.8 397.8 25
148 Kalpataru Projects International Ltd. KPIL 522287 UTILITIES ELECTRIC UTILITIES 4,53 4,148 370 8.19% 113 137 132 42 89 5.5 478 29.9
149 Kansai Nerolac Paints Ltd. KANSAINER 500165 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 1,978.6 1,683.3 273.2 13.97% 47.4 7.6 240.3 64.8 177.2 2.2 1,118.8 13.8
150 Karur Vysya Bank Ltd. KARURVYSYA 590003 BANKING AND FINANCE BANKS 2,336 616.4 637.9 31.94% 0 1,081.7 511.5 133.1 378.4 4.7 1,364.2 17
151 KEC International Ltd. KEC 532714 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 4,514.9 4,224.7 274.3 6.10% 46.5 177.8 65.8 9.9 55.8 2.2 187.9 7.3
152 Kotak Mahindra Bank Ltd. KOTAKBANK 500247 BANKING AND FINANCE BANKS 21,559.5 9,681 6,343 46.24% 0 5,535.5 5,888.3 1,465.5 4,461 22.4 17,172.7 86.4
153 L&T Finance Holdings Ltd. L&TFH 533519 DIVERSIFIED HOLDING COMPANIES 3,482.1 935.3 1,882.4 58.57% 28.3 1,324.9 797.4 203.2 595.1 2.4 2,080.8 8.4
154 L&T Technology Services Ltd. LTTS 540115 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 2,427.7 1,910.9 475.6 19.93% 68.1 12.6 436.1 120.2 315.4 29.8 1,239.7 117.5
155 LIC Housing Finance Ltd. LICHSGFIN 500253 BANKING AND FINANCE HOUSING FINANCE 6,765.9 250.6 6,095.7 90.10% 13.2 4,599.9 1,483 291.2 1,193.5 21.7 4,164.5 75.7
156 Lakshmi Machine Works Ltd. LAXMIMACH 500252 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 1,355.5 1,184.5 136 10.30% 23.6 0 147.4 32.3 115.1 107.8 416 389.5
157 Laurus Labs Ltd. LAURUSLABS 540222 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,226.2 1,036.6 187.9 15.34% 93.4 42.4 53.9 14.6 37 0.7 367.8 6.8
158 Lupin Ltd. LUPIN 500257 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 5,079 4,120.8 917.8 18.21% 247.8 80.6 629.7 134.3 489.5 10.8 1,331.2 29.2
159 MMTC Ltd. MMTC 513377 COMMERCIAL SERVICES & SUPPLIES COMMODITY TRADING & DISTRIBUTION -167.2 -180.1 -30.4 14.42% 0.8 1.1 12.1 1.5 52 0.3 174.1 1.2
160 MRF Ltd. MRF 500290 AUTOMOBILES & AUTO COMPONENTS AUTO TYRES & RUBBER PRODUCTS 6,287.8 5,060.2 1,156.9 18.61% 351.5 85.5 790.6 203.9 586.7 1383.3 1,690.9 3988
161 Mahanagar Gas Ltd. MGL 539957 UTILITIES UTILITIES 1,772.7 1,250.1 478.9 27.70% 65.8 2.5 454.3 115.8 338.5 34.3 1,147.8 116.2
162 Mahindra & Mahindra Financial Services Ltd. M&MFIN 532720 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 3,863.5 1,077.5 2,109.3 55.03% 67.1 1,703.4 369.1 96 281.1 2.3 1,982.5 16
163 Mahindra & Mahindra Ltd. M&M 500520 AUTOMOBILES & AUTO COMPONENTS CARS & UTILITY VEHICLES 35,027.2 28,705.9 5,729.6 16.64% 1,138.6 1,835.2 3,347.5 1,083.7 2,347.8 21.1 11,169.4 100.2
164 Mahindra Holidays & Resorts India Ltd. MHRIL 533088 HOTELS RESTAURANTS & TOURISM HOTELS 672.2 519.3 136 20.76% 83.8 33.3 35.8 14 21.3 1.1 66 3.3
165 Manappuram Finance Ltd. MANAPPURAM 531213 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 2,174 555.6 1,481.3 68.68% 62.5 689.4 746.7 186.1 558.4 6.6 1,859.8 22
166 Mangalore Refinery And Petrochemicals Ltd. MRPL 500109 OIL & GAS REFINERIES/PETRO-PRODUCTS 22,904.7 20,705.6 2,138.2 9.36% 296 311.2 1,592 546.2 1,051.7 6 3,784.9 21.6
167 Marico Ltd. MARICO 531642 FMCG PERSONAL PRODUCTS 2,514 1,979 497 20.07% 39 20 476 116 353 2.7 1,41 10.9
168 Maruti Suzuki India Ltd. MARUTI 532500 AUTOMOBILES & AUTO COMPONENTS CARS & UTILITY VEHICLES 37,902.1 32,282.5 4,790.3 12.92% 794.4 35.1 4,790.1 1,083.8 3,764.3 124.6 11,351.8 375.9
169 Max Financial Services Ltd. MFSL 500271 BANKING AND FINANCE LIFE INSURANCE 10,189.1 10,024.6 143.9 1.42% 0.8 9.4 158.2 -12.1 147.9 4.3 506.4 14.7
170 UNO Minda Ltd. UNOMINDA 532539 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 3,630.2 3,219.8 401.6 11.09% 125.4 27.2 257.9 73.3 225 3.9 742.4 13
171 Motilal Oswal Financial Services Ltd. MOTILALOFS 532892 BANKING AND FINANCE OTHER FINANCIAL SERVICES 1,650.7 724.1 904.5 55.18% 17.3 241.1 657.6 124.2 531.2 35.9 1,449.3 97.8
172 MphasiS Ltd. MPHASIS 526299 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 3,325.5 2,680.9 595.6 18.18% 89 34 521.7 129.7 391.9 20.8 1,605.6 85.1
173 Muthoot Finance Ltd. MUTHOOTFIN 533398 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 3,631.9 723.4 2,801.6 77.69% 22.2 1,335 1,470.2 374.9 1,059.6 26.4 3,982.9 99.2
174 Natco Pharma Ltd. NATCOPHARM 524816 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,060.8 573.4 458 44.41% 43.6 4.2 439.6 70.6 369 20.6 1,127.4 63
175 NBCC (India) Ltd. NBCC 534309 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 2,129.1 1,957.7 95.5 4.65% 1.3 0 104.6 22.9 79.6 0.4 332.2 1.8
176 NCC Ltd. NCC 500294 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 4,746.4 4,415.9 303.7 6.44% 53.2 153.5 123.8 38.8 77.3 1.2 599.4 9.5
177 NHPC Ltd. NHPC 533098 UTILITIES ELECTRIC UTILITIES 3,113.8 1,173.9 1,757.4 59.95% 294.9 104.8 1,618.3 -75 1,545.8 1.5 3,897.8 3.9
178 Coforge Ltd. COFORGE 532541 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 2,285.1 1,935.3 340.9 14.98% 77.2 31.9 240.7 52.8 187.9 29.6 696.2 113.2
179 NLC India Ltd. NLCINDIA 513683 UTILITIES ELECTRIC UTILITIES 3,234 2,143 834.6 28.03% 455.1 213.9 1,700.6 614.7 1,084.7 7.8 1,912.3 13.8
180 NTPC Ltd. NTPC 532555 UTILITIES ELECTRIC UTILITIES 45,384.6 32,303.2 12,680.2 28.19% 4,037.7 2,920.5 6,342.9 2,019.7 4,614.6 4.8 19,125.2 19.7
181 Narayana Hrudayalaya Ltd. NH 539551 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 1,323.6 997.1 308.1 23.61% 55.3 22.9 248.4 21.7 226.6 11.2 737.5 36.1
182 National Aluminium Company Ltd. NATIONALUM 532234 METALS & MINING ALUMINIUM AND ALUMINIUM PRODUCTS 3,112 2,646.9 396.5 13.03% 186.2 4 275 68.7 187.3 1 1,272.4 6.9
183 Navin Fluorine International Ltd. NAVINFLUOR 532504 CHEMICALS & PETROCHEMICALS COMMODITY CHEMICALS 494.9 373.4 98.3 20.84% 24.2 20 77.2 16.6 60.6 12.2 365 73.7
184 Oberoi Realty Ltd. OBEROIRLTY 533273 REALTY REALTY 1,243.8 579.2 638.2 52.42% 11.3 56.5 596.8 142.1 456.8 12.6 1,961.3 53.9
185 Oil And Natural Gas Corporation Ltd. ONGC 500312 OIL & GAS EXPLORATION & PRODUCTION 149,388.5 118,618.4 28,255.3 19.24% 6,698.1 2,603.3 21,564.9 5,633.6 13,734.1 10.9 43,072.5 34.2
186 Oil India Ltd. OIL 533106 OIL & GAS EXPLORATION & PRODUCTION 9,200.1 5,293.3 3,523.2 39.96% 499 278.9 762 67.6 420.7 3.9 5,874.5 54.2
187 Oracle Financial Services Software Ltd. OFSS 532466 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 1,509.6 886.4 558.1 38.64% 19 8 596.2 178.8 417.4 48.2 1,835.1 211.9
188 PI Industries Ltd. PIIND 523642 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 2,163.8 1,565.5 551.4 26.05% 80.3 7.8 510.2 31.7 480.5 31.7 1,495.8 98.4
189 PNB Housing Finance Ltd. PNBHOUSING 540173 BANKING AND FINANCE HOUSING FINANCE 1,779.4 158.8 1,574.1 88.54% 11.3 1,057.3 507.1 124.1 383 14.8 1,278.7 49.3
190 PNC Infratech Ltd. PNCINFRA 539150 CEMENT AND CONSTRUCTION ROADS & HIGHWAYS 1,932.4 1,511.6 399.8 20.92% 40.9 161.3 218.6 70.7 147.9 5.8 614.3 23.9
191 PVR INOX Ltd. PVRINOX 532689 RETAILING SPECIALTY RETAIL 2,023.7 1,293.1 706.8 35.34% 308.6 200.3 221.7 55.5 166.3 17 -232.5 -23.7
192 Page Industries Ltd. PAGEIND 532827 TEXTILES APPARELS & ACCESSORIES OTHER APPARELS & ACCESSORIES 1,126.8 891.6 233.5 20.76% 24.6 11.2 199.4 49.1 150.3 134.7 510.7 457.9
193 Persistent Systems Ltd. PERSISTENT 533179 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 2,449 2,006.5 405.2 16.80% 74.4 12.3 355.8 92.5 263.3 35 981.5 127.6
194 Petronet LNG Ltd. PETRONET 532522 OIL & GAS OIL MARKETING & DISTRIBUTION 12,686.2 11,317.9 1,214.7 9.69% 194.8 74.7 1,098.8 283.9 855.7 5.7 3,490.3 23.3
195 Pfizer Ltd. PFIZER 500680 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 611.3 392.6 182.6 31.75% 15.4 2.7 200.5 51.6 149 32.6 522.8 114.3
196 Phoenix Mills Ltd. PHOENIXLTD 503100 REALTY REALTY 906.6 361.2 506 57.82% 65.9 96.5 375.2 71.4 252.6 14.2 923.6 51.7
197 Pidilite Industries Ltd. PIDILITIND 500331 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 3,107.6 2,396.3 679.7 22.10% 75.2 13.1 623 163.1 450.1 8.8 1,505.5 29.6
198 Power Finance Corporation Ltd. PFC 532810 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 22,403.7 315.4 22,941.9 102.46% 12.7 14,313.1 8,628.8 2,000.6 4,833.1 14.7 17,946.4 54.4
199 Power Grid Corporation of India Ltd. POWERGRID 532898 UTILITIES ELECTRIC UTILITIES 11,530.4 1,358.7 9,908.4 87.94% 3,277 2,341.3 4,393.4 573.7 3,781.4 4.1 15,344.4 16.5
200 Prestige Estates Projects Ltd. PRESTIGE ASM REALTY REALTY 3,256 1,643.9 592.5 26.49% 174.1 263.9 1,174.1 256.4 850.9 21.2 1,714 42.8
201 Prism Johnson Ltd. PRSMJOHNSN 500338 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 1,846 1,745.4 92.4 5.03% 95.2 43.5 210 30.4 182.7 3.6 154.2 3.1
202 Procter & Gamble Hygiene & Healthcare Ltd. PGHH 500459 FMCG PERSONAL PRODUCTS 1,154.1 853.5 284.9 25.03% 14.3 1.9 284.5 73.8 210.7 64.9 734.4 226.3
203 Punjab National Bank PNB 532461 BANKING AND FINANCE BANKS 29,857 6,798.1 6,239.1 23.23% 0 16,819.8 2,778.3 1,013.8 1,990.2 1.8 5,904.8 5.4
204 Quess Corp Ltd. QUESS 539978 SOFTWARE & SERVICES BPO/KPO 4,763.5 4,584.8 163.6 3.44% 69.7 28.1 79.3 8.3 71.9 4.8 240.9 16.2
205 RBL Bank Ltd. RBLBANK 540065 BANKING AND FINANCE BANKS 3,720.6 1,422.6 765.4 25.45% 0 1,532.6 125 -206.1 331.1 5.5 1,173.9 19.5
206 Radico Khaitan Ltd. RADICO 532497 FOOD BEVERAGES & TOBACCO BREWERIES & DISTILLERIES 925.7 803.8 121.2 13.10% 26.1 12.5 83.3 21.4 64.8 4.8 237 17.7
207 Rain Industries Ltd. RAIN 500339 CHEMICALS & PETROCHEMICALS PETROCHEMICALS 4,208.9 3,794.3 366 8.80% 192.5 241.7 -19.5 46.2 -90.2 -2.7 270.4 8
208 Rajesh Exports Ltd. RAJESHEXPO 531500 TEXTILES APPARELS & ACCESSORIES GEMS & JEWELLERY 38,079.4 38,015.8 50.1 0.13% 10.7 0 53 7.7 45.3 1.5 1,142.2 38.7
209 Rallis India Ltd. RALLIS 500355 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 837 699 133 15.99% 26 3 110 28 82 4.2 98.4 5.2
210 Rashtriya Chemicals & Fertilizers Ltd. RCF 524230 FERTILIZERS FERTILIZERS 4,222.1 4,049.3 105.9 2.55% 56.1 44 72.8 21.1 51 0.9 523.6 9.5
211 Redington Ltd. REDINGTON 532805 COMMERCIAL SERVICES & SUPPLIES COMMODITY TRADING & DISTRIBUTION 22,296.6 21,738.7 481.4 2.17% 43.7 105.8 408.3 96.7 303.5 3.9 1,242 15.9
212 Relaxo Footwears Ltd. RELAXO 530517 RETAILING FOOTWEAR 725.9 623.8 91.5 12.79% 36.9 4.7 60.4 16.2 44.2 1.8 193.9 7.8
213 Reliance Industries Ltd. RELIANCE 500325 OIL & GAS REFINERIES/PETRO-PRODUCTS 238,797 193,988 40,968 17.44% 12,585 5,731 26,493 6,673 17,394 25.7 68,496 101.2
214 REC Ltd. RECLTD 532955 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 11,701.3 275.1 12,180.5 104.21% 6.1 7,349.8 4,837.6 1,047.7 3,789.9 14.4 12,738.6 48.4
215 SJVN Ltd. SJVN 533206 UTILITIES ELECTRIC UTILITIES 951.6 172.2 706.2 80.40% 101.9 124.2 567.7 129.2 439.6 1.1 1,016 2.6
216 SKF India Ltd. SKFINDIA 500472 GENERAL INDUSTRIALS OTHER INDUSTRIAL GOODS 1,145.5 1,003.7 121.5 10.80% 19.3 0.5 122 31.7 90 18.2 484 97.9
217 SRF Ltd. SRF 503806 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 3,206.5 2,551.2 626.2 19.71% 161.2 79.3 414.8 114 300.8 10.2 1,733.4 58.5
218 Sanofi India Ltd. SANOFI 500674 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 726.4 506.1 208.5 29.17% 9.9 0.3 210.1 57.9 152.1 66.1 596.3 259.3
219 Schaeffler India Ltd. SCHAEFFLER 505790 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,879.2 1,506.3 342 18.50% 55.6 1.6 315.7 80.7 235 15 922.6 59
220 Shree Cements Ltd. SHREECEM 500387 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 4,932.1 3,914.1 886 18.46% 411.7 67 539.2 92.6 446.6 123.8 1,826.8 506.3
221 Shriram Finance Ltd. SHRIRAMFIN 511218 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 8,893 1,409.4 6,334.3 71.30% 141.4 3,798 2,404.2 614.9 1,786.1 47.6 6,575.4 175.2
222 Siemens Ltd. SIEMENS 500550 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 5,953.2 5,107.5 700.2 12.06% 78.6 4.9 762.2 190.5 571.3 16.1 1,960.9 55.1
223 Sobha Ltd. SOBHA 532784 REALTY REALTY 773.6 665.8 75.4 10.18% 19.3 63.9 24.7 9.7 14.9 1.6 107.4 11.3
224 Solar Industries India Ltd. SOLARINDS 532725 GENERAL INDUSTRIALS OTHER INDUSTRIAL PRODUCTS 1,355.2 1,011.3 336.1 24.95% 33.7 24.9 285.3 75.5 200.1 22.1 808.2 89.3
225 Sonata Software Ltd. SONATSOFTW 532221 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 1,935.8 1,715.2 197.3 10.32% 33.3 20.7 166.5 42.3 124.2 9 475.7 34.3
226 State Bank of India SBIN 500112 BANKING AND FINANCE BANKS 144,256.1 58,597.6 22,703.3 21.14% 0 62,955.2 21,935.7 5,552.5 17,196.2 18 69,304.1 77.7
227 Steel Authority of India (SAIL) Ltd. SAIL 500113 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 29,858.2 25,836.7 3,875.4 13.04% 1,326.6 605.2 1,674.7 464.2 1,305.6 3.2 3,219.5 7.8
228 Sun Pharma Advanced Research Company Ltd. SPARC 532872 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 29.7 112.7 -91.5 -431.87% 3.2 0.3 -86.4 0 -86.4 -2.7 -253.6 -7.8
229 Sun Pharmaceutical Industries Ltd. SUNPHARMA 524715 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 12,486 9,013 3,179.4 26.08% 632.8 49.3 2,790.9 390.1 2,375.5 9.9 8,548.5 35.6
230 Sun TV Network Ltd. SUNTV 532733 MEDIA BROADCASTING & CABLE TV 1,160.2 320.6 727.8 69.42% 218.8 1.7 619.1 154.4 464.7 11.8 1,861.8 47.2
231 Sundram Fasteners Ltd. SUNDRMFAST 500403 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,429.1 1,191.1 230.7 16.23% 54.5 7.4 176.2 43.1 131.9 6.3 502.9 23.9
232 Sunteck Realty Ltd. SUNTECK 512179 REALTY REALTY 36.2 39.1 -14.1 -56.70% 2.2 15.8 -20.9 -6.4 -13.9 -1 -46.5 -3.3
233 Supreme Industries Ltd. SUPREMEIND 509930 GENERAL INDUSTRIALS PLASTIC PRODUCTS 2,321.4 1,952.5 356.2 15.43% 71.9 1.6 295.4 76.3 243.2 19.1 1,028.2 80.9
234 Suzlon Energy Ltd. SUZLON ASM GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 1,428.7 1,196.4 225 15.83% 51.2 43.7 102.4 0.1 102.3 0.1 561.4 0.4
235 Syngene International Ltd. SYNGENE 539268 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 931.7 656 254.1 27.92% 104.6 13 150.7 34.2 116.5 2.9 498.3 12.4
236 TTK Prestige Ltd. TTKPRESTIG 517506 CONSUMER DURABLES HOUSEWARE 747.2 648.6 80.8 11.08% 15.9 3.1 79.5 20.5 59.3 4.3 224.3 16.2
237 TV18 Broadcast Ltd. TV18BRDCST 532800 MEDIA BROADCASTING & CABLE TV 1,989 1,992.2 -198.1 -11.04% 50.1 33.8 -87.1 -6.5 -28.9 -0.2 92.2 0.5
238 TVS Motor Company Ltd. TVSMOTOR 532343 AUTOMOBILES & AUTO COMPONENTS 2/3 WHEELERS 9,983.8 8,576.9 1,355.9 13.65% 237.1 483.3 686.4 259.8 386.3 8.1 1,457.6 30.7
239 Tata Consultancy Services Ltd. TCS 532540 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 60,698 43,946 15,746 26.38% 1,263 159 15,33 3,95 11,342 31 44,654 122
240 Tata Elxsi Ltd. TATAELXSI 500408 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 912.8 618.2 263.5 29.89% 25 5.8 263.9 63.8 200 32.1 785.1 126.1
241 Tata Consumer Products Ltd. TATACONSUM 500800 FMCG PACKAGED FOODS 3,823.6 3,196.7 537.1 14.38% 93.9 27.6 490.9 131.7 338.2 3.6 1,275.2 13.7
242 Tata Motors Limited (DVR) TATAMTRDVR 570001 AUTOMOBILES & AUTO COMPONENTS COMMERCIAL VEHICLES
243 Tata Motors Ltd. TATAMOTORS 500570 AUTOMOBILES & AUTO COMPONENTS COMMERCIAL VEHICLES 106,759 91,361.3 13,766.9 13.10% 6,636.4 2,651.7 5,985.9 2,202.8 3,764 9.8 15,332.3 40
244 Tata Power Company Ltd. TATAPOWER 500400 UTILITIES ELECTRIC UTILITIES 16,029.5 12,647 3,091 19.64% 925.9 1,181.8 979.2 213.3 875.5 2.7 3,570.8 11.2
245 Tata Steel Ltd. TATASTEEL 500470 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 55,910.2 51,414.1 4,267.8 7.66% 2,479.8 1,959.4 -6,842.1 -228 -6,196.2 -5.1 -6,081.3 -5
246 Tech Mahindra Ltd. TECHM 532755 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 13,128.1 11,941.1 922.8 7.17% 465.7 97.5 623.8 110 493.9 5.6 3,600.7 40.9
247 The Ramco Cements Ltd. RAMCOCEM 500260 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 2,352.1 1,935 405.6 17.33% 162.8 116.5 137.8 37 72 3.1 348.9 14.8
248 Thermax Ltd. THERMAX 500411 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 2,368.3 2,097.8 204.6 8.89% 33 19.8 217.7 58.9 157.7 14 498.8 44.3
249 Timken India Ltd. TIMKEN 522113 GENERAL INDUSTRIALS OTHER INDUSTRIAL PRODUCTS 692.1 546.5 135.5 19.87% 21.1 0.9 123.6 30.6 93 12.4 358.3 47.6
250 Titan Company Ltd. TITAN 500114 TEXTILES APPARELS & ACCESSORIES GEMS & JEWELLERY 12,653 11,118 1,411 11.26% 144 140 1,251 336 915 10.3 3,302 37.1
251 Torrent Pharmaceuticals Ltd. TORNTPHARM 500420 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 2,686 1,835 825 31.02% 201 91 559 173 386 11.4 1,334 39.4
252 Torrent Power Ltd. TORNTPOWER 532779 UTILITIES ELECTRIC UTILITIES 7,069.1 5,739.5 1,221.4 17.55% 341.7 247.2 740.7 198.1 525.9 10.9 2,176.8 45.3
253 Trent Ltd. TRENT 500251 RETAILING DEPARTMENT STORES 3,062.5 2,525.8 456.6 15.31% 152.2 95.5 288.9 86.3 234.7 6.6 629.4 17.7
254 Trident Ltd. TRIDENT 521064 TEXTILES APPARELS & ACCESSORIES TEXTILES 1,812 1,557.3 240.3 13.37% 89.4 35 130.4 40.1 90.7 0.2 458.1 0.9
255 UPL Ltd. UPL 512070 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 10,275 8,807 1,325 13.03% 657 871 -185 -96 -189 -2.5 1,856 24.7
256 UltraTech Cement Ltd. ULTRACEMCO 532538 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 16,179.3 13,461.2 2,550.9 15.93% 797.8 233.9 1,686.2 409.4 1,281.5 44.5 5,694.1 197.2
257 Union Bank of India UNIONBANK 532477 BANKING AND FINANCE BANKS 28,952.5 6,189.3 7,265 29.38% 0 15,498.2 5,492.3 1,944 3,571.8 5.1 11,918.9 16.1
258 United Breweries Ltd. UBL 532478 FOOD BEVERAGES & TOBACCO BREWERIES & DISTILLERIES 1,902.1 1,705.8 184.3 9.75% 50.9 1.4 144 36.9 107.3 4.1 251.3 9.5
259 United Spirits Ltd. MCDOWELL-N 532432 FOOD BEVERAGES & TOBACCO BREWERIES & DISTILLERIES 6,776.6 6,269.8 466.7 6.93% 65.3 26.2 446 106.3 339.3 4.8 1,133 15.6
260 V-Guard Industries Ltd. VGUARD 532953 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 1,147.9 1,041.3 92.5 8.16% 19.8 9.3 77.5 18.6 59 1.4 215.2 5
261 Vardhman Textiles Ltd. VTL 502986 TEXTILES APPARELS & ACCESSORIES TEXTILES 2,487 2,192.1 205.4 8.57% 103.7 22 169.2 41.7 134.3 4.7 531.9 18.7
262 Varun Beverages Ltd. VBL 540180 FOOD BEVERAGES & TOBACCO NON-ALCOHOLIC BEVERAGES 3,889 2,988.4 882.1 22.79% 170.8 62.5 667.3 152.9 501.1 3.9 1,998.7 15.4
263 Vinati Organics Ltd. VINATIORGA 524200 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 464.4 337.3 110.8 24.73% 13.7 0.3 113 28.9 84.2 8.2 408.2 39.7
264 Voltas Ltd. VOLTAS 500575 CONSUMER DURABLES CONSUMER ELECTRONICS 2,363.7 2,222.5 70.3 3.06% 11.7 11.4 118.1 49.3 36.7 1.1 199.5 6
265 ZF Commercial Vehicle Control Systems India Ltd. ZFCVINDIA 533023 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,015.8 846.2 145.5 14.67% 27.1 1.3 141.2 35.5 105.7 55.7 392 206.7
266 Welspun Corp Ltd. WELCORP ASM METALS & MINING IRON & STEEL PRODUCTS 4,161.4 3,659.9 399.5 9.84% 85.7 75 340.8 79 384.7 14.7 809.2 30.9
267 Welspun Living Ltd. WELSPUNLIV 514162 TEXTILES APPARELS & ACCESSORIES TEXTILES 2,542.4 2,151.1 358 14.27% 98.5 33.8 258.9 58.7 196.7 2 526.1 5.4
268 Whirlpool of India Ltd. WHIRLPOOL 500238 CONSUMER DURABLES CONSUMER ELECTRONICS 1,555.5 1,448.4 73.2 4.81% 49.2 5.6 52.3 14.1 36.6 2.9 198.8 15.7
269 Wipro Ltd. WIPRO 507685 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 23,255.7 18,543.2 3,972.7 17.64% 897 303.3 3,512.2 841.9 2,646.3 5.1 11,643.8 22.3
270 Zee Entertainment Enterprises Ltd. ZEEL 505537 MEDIA BROADCASTING & CABLE TV 2,509.6 2,105 332.8 13.65% 77.2 23.4 184.2 54.4 123 1.3 -102.2 -1.1
271 eClerx Services Ltd. ECLERX 532927 SOFTWARE & SERVICES BPO/KPO 735.9 517 204.7 28.37% 30.3 6.1 182.4 46.3 136 28.2 506 105
272 Sterlite Technologies Ltd. STLTECH 532374 TELECOMMUNICATIONS EQUIPMENT TELECOM CABLES 1,497 1,281 213 14.26% 85 95 36 12 34 0.9 203 5.1
273 HEG Ltd. HEG 509631 GENERAL INDUSTRIALS OTHER INDUSTRIAL GOODS 642.2 512.3 101.9 16.58% 38.5 8.5 82.9 21.7 96 24.9 439.5 113.9
274 SBI Life Insurance Company Ltd. SBILIFE 540719 BANKING AND FINANCE LIFE INSURANCE 28,816.2 28,183.8 609.9 2.12% 0 0 621.5 43.9 380.2 3.8 1,842.2 18.4
275 General Insurance Corporation of India GICRE 540755 BANKING AND FINANCE GENERAL INSURANCE 13,465.9 11,574 1,464.6 11.20% 0 0 1,855.4 243.7 1,689 15.2 6,628 37.8
276 Tube Investments of India Ltd. TIINDIA 540762 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 2,005.4 1,718.2 251.4 12.76% 34.6 7.7 244.8 63.4 181.4 9.4 717.5 37.1
277 Honeywell Automation India Ltd. HONAUT 517174 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 1,144.3 965.9 138.3 12.52% 13.8 0.7 163.9 42 121.9 137.8 443.4 503.9
278 Indian Energy Exchange Ltd. IEX 540750 BANKING AND FINANCE EXCHANGE 133 16.6 92 84.73% 5.1 0.7 110.6 27.9 86.5 1 327.8 3.7
279 ICICI Lombard General Insurance Company Ltd. ICICIGI 540716 BANKING AND FINANCE GENERAL INSURANCE 5,271.1 4,612.4 743.5 14.16% 0 0 763.6 186.4 577.3 11.8 1,757.1 35.8
280 Aster DM Healthcare Ltd. ASTERDM 540975 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 3,325.2 2,939.4 377.3 11.38% 227.2 101.9 2.1 10.2 -30.8 -0.6 284.3 5.7
281 Central Depository Services (India) Ltd. CDSL CDSL OTHERS INVESTMENT COMPANIES 230.1 77.9 129.4 62.40% 6.5 0 145.6 35.8 108.9 10.4 320.2 30.6
282 Graphite India Ltd. GRAPHITE 509488 GENERAL INDUSTRIALS OTHER INDUSTRIAL GOODS 884 823 -30 -3.78% 19 4 992 190 804 41.1 856 43.9
283 Grasim Industries Ltd. GRASIM 500300 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 30,505.3 25,995.9 4,224.8 13.98% 1,245.2 397.8 2,866.4 837.7 1,163.8 17.7 6,624.9 100.6
284 KNR Constructions Ltd. KNRCON 532942 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 1,043.8 806.9 231.6 22.30% 39.2 20.6 177.1 34.6 147.4 5.2 537.5 19.1
285 Aditya Birla Capital Ltd. ABCAPITAL 540691 DIVERSIFIED HOLDING COMPANIES 7,730.4 4,550.1 2,821.9 36.55% 48 1,827 956.8 284.1 705 2.7 5,231.9 20.1
286 Dixon Technologies (India) Ltd. DIXON 540699 CONSUMER DURABLES CONSUMER ELECTRONICS 4,943.9 4,744.3 198.9 4.02% 36.4 17.1 146.1 35.2 107.3 19 308.7 51.8
287 Cholamandalam Financial Holdings Ltd. CHOLAHLDNG 504973 DIVERSIFIED HOLDING COMPANIES 6,372.2 2,495.1 3,404.8 54.05% 52.1 2,209.4 1,215.8 324.6 420.9 22.4 1,532.3 81.6
288 Cochin Shipyard Ltd. COCHINSHIP 540678 TRANSPORTATION MARINE PORT & SERVICES 1,100.4 820.5 191.2 18.90% 18.9 9.6 251.4 69.9 181.5 13.8 429.9 32.7
289 Bharat Dynamics Ltd. BDL 541143 GENERAL INDUSTRIALS DEFENCE 694.1 481.8 134 21.77% 17.4 0.8 194.1 47 147.1 8 425.4 23.2
290 Lux Industries Ltd. LUXIND 539542 TEXTILES APPARELS & ACCESSORIES OTHER APPARELS & ACCESSORIES 643.6 584.2 55 8.61% 5.9 5.4 48 12.1 37.1 12.3 103.1 32.9
291 Zensar Technologies Ltd. ZENSARTECH 504067 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 1,277.1 1,009.9 230.9 18.61% 36.6 5.7 224.9 51 173.9 7.7 525.8 23.2
292 PCBL Ltd. PCBL 506590 CHEMICALS & PETROCHEMICALS CARBON BLACK 1,489.4 1,248.6 238.1 16.02% 48.2 21 171.6 48.8 122.6 3.2 431.6 11.4
293 Zydus Wellness Ltd. ZYDUSWELL 531335 FMCG PACKAGED FOODS 444 423.1 16.8 3.82% 5.8 6.5 8.6 2.7 5.9 0.9 281.2 44.2
294 Linde India Ltd. LINDEINDIA 523457 GENERAL INDUSTRIALS INDUSTRIAL GASES 729.9 537.7 173.6 24.41% 49.7 1.2 141.3 34.6 108.7 12.8 417.9 49
295 FDC Ltd. FDC 531599 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 513.6 409.9 76.4 15.71% 9.9 1.1 92.7 22.9 69.8 4.2 251.2 15.4
296 The New India Assurance Company Ltd. NIACL 540769 BANKING AND FINANCE GENERAL INSURANCE 10,571 10,773.4 -246.5 -2.33% 0 0 -242 -46.7 -176.1 -1.1 947 5.7
297 Sundaram Finance Ltd. SUNDARMFIN 590071 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 1,710.6 322.5 1,332.1 77.98% 43.6 820.3 470.6 142.8 365.4 33.2 1,506.7 135.6
298 TeamLease Services Ltd. TEAMLEASE 539658 COMMERCIAL SERVICES & SUPPLIES MISC. COMMERCIAL SERVICES 2,285.6 2,240.8 31.8 1.40% 12.9 2.5 29.4 1.8 27.3 16.3 106.6 63.5
299 Galaxy Surfactants Ltd. GALAXYSURF 540935 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 985.8 858.2 124.9 12.70% 24.7 5.4 97.5 20.1 77.4 21.8 349.3 98.5
300 Bandhan Bank Ltd. BANDHANBNK 541153 BANKING AND FINANCE BANKS 5,032.2 1,400.2 1,583.4 35.25% 0 2,048.6 947.2 226.1 721.2 4.5 2,541.1 15.8
301 ICICI Securities Ltd. ISEC 541179 BANKING AND FINANCE CAPITAL MARKETS 1,249 433.5 810.2 64.87% 25.8 215.1 569.4 145.7 423.6 13.1 1,238.1 38.3
302 V-Mart Retail Ltd. VMART 534976 RETAILING DEPARTMENT STORES 551.4 548.8 0.7 0.12% 53.2 35.9 -86.4 -22.3 -64.1 -32.4 -103.1 -52.1
303 Nippon Life India Asset Management Ltd. NAM-INDIA 540767 BANKING AND FINANCE ASSET MANAGEMENT COS. 475.4 156.1 241.4 60.73% 7.2 1.7 310.4 66.1 244.4 3.9 883.3 14.1
304 Grindwell Norton Ltd. GRINDWELL 506076 GENERAL INDUSTRIALS OTHER INDUSTRIAL PRODUCTS 690 536 131.4 19.69% 16.9 1.8 135.3 33.1 101.9 9.2 378.3 34.2
305 HDFC Life Insurance Company Ltd. HDFCLIFE 540777 BANKING AND FINANCE LIFE INSURANCE 23,276.6 23,659.3 -508.1 -2.20% 0 0 -373.1 -657.5 378.2 1.8 1,472.8 6.9
306 Elgi Equipments Ltd. ELGIEQUIP 522074 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 817.8 663.4 142.7 17.71% 18.7 6.6 129.2 38.8 91.3 2.9 401.9 12.7
307 Hindustan Aeronautics Ltd. HAL 541154 GENERAL INDUSTRIALS DEFENCE 6,105.1 4,108.1 1,527.6 27.11% 349.6 0.3 1,647 414.8 1,236.7 18.5 6,037.3 90.3
308 BSE Ltd. BSE BSE BANKING AND FINANCE EXCHANGE 367 172.8 189.2 52.26% 22.7 8.5 163 63.6 120.5 8.8 706 52.1
309 Rites Ltd. RITES 541556 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 608.8 444.5 137.8 23.67% 14.1 1.4 148.8 40.1 101.2 4.2 488.1 20.3
310 Fortis Healthcare Ltd. FORTIS 532843 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 1,783.5 1,439.8 330.2 18.65% 84.1 31.8 231.4 48.8 173.7 2.3 547.6 7.3
311 Varroc Engineering Ltd. VARROC 541578 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,893.5 1,692.6 194.3 10.30% 84.9 50.3 65.9 18.2 54.2 3.5 146.5 9.6
312 Adani Green Energy Ltd. ADANIGREEN ASM UTILITIES ELECTRIC UTILITIES 2,589 521 1,699 76.53% 474 1,165 413 119 372 2.2 1,305 8.2
313 VIP Industries Ltd. VIPIND 507880 TEXTILES APPARELS & ACCESSORIES OTHER APPARELS & ACCESSORIES 548.7 493.2 52.9 9.68% 23.8 12.4 19.3 6 13.3 0.9 110.9 7.8
314 CreditAccess Grameen Ltd. CREDITACC 541770 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 1,247.6 248.8 902.3 72.36% 12.3 423.9 466.8 119.7 347 21.8 1,204.2 75.7
315 CESC Ltd. CESC 500084 UTILITIES ELECTRIC UTILITIES 4,414 3,706 646 14.84% 303 305 461 98 348 2.6 1,447 10.9
316 Jamna Auto Industries Ltd. JAMNAAUTO 520051 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 608.7 528.2 79.1 13.03% 10.9 0.8 68.7 18.6 50.1 2.4 189.3 4.7
317 Suprajit Engineering Ltd. SUPRAJIT 532509 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 727.6 639.1 69.8 9.85% 25.7 13.6 49.2 14.5 34.8 2.5 146.9 10.6
318 JK Paper Ltd. JKPAPER 532162 COMMERCIAL SERVICES & SUPPLIES PAPER & PAPER PRODUCTS 1,708.8 1,242.8 407.3 24.68% 83.5 42 340.6 34.9 302.4 17.9 1,220.6 72.1
319 Bank of Maharashtra MAHABANK 532525 BANKING AND FINANCE BANKS 5,735.5 1,179.4 1,920.5 37.90% 0 2,635.7 935.7 16 919.8 1.3 3,420.8 4.8
320 Aavas Financiers Ltd. AAVAS 541988 BANKING AND FINANCE HOUSING FINANCE 497.6 123.5 367.8 74.03% 7.6 203.6 157.4 35.7 121.7 15.4 465.4 58.8
321 HDFC Asset Management Company Ltd. HDFCAMC 541729 BANKING AND FINANCE ASSET MANAGEMENT COS. 765.4 162 481.1 74.81% 13 2.3 588.1 151.6 436.5 20.4 1,659.3 77.7
322 KEI Industries Ltd. KEI 517569 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 1,954.2 1,742.7 203.9 10.47% 15.6 7.5 188.4 48.2 140.2 15.5 528.3 58.5
323 Orient Electric Ltd. ORIENTELEC 541301 CONSUMER DURABLES CONSUMER ELECTRONICS 570.3 546.2 20.7 3.65% 14.2 5.2 23.4 4.9 18.4 0.9 95.3 4.5
324 Deepak Nitrite Ltd. DEEPAKNTR 506401 CHEMICALS & PETROCHEMICALS COMMODITY CHEMICALS 1,795.1 1,475.8 302.3 17.00% 39.4 2.7 277.2 72.1 205.1 15 797.9 58.5
325 Fine Organic Industries Ltd. FINEORG 541557 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 557.6 409.4 131.1 24.25% 14.4 0.7 133.1 28.9 103.4 33.7 458.8 149.6
326 LTIMindtree Ltd. LTIM 540005 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 9,048.6 7,274.1 1,631.3 18.32% 208.2 47 1,519.3 357 1,161.8 39.3 4,427.5 149.6
327 Dalmia Bharat Ltd. DALBHARAT 542216 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 3,234 2,56 589 18.70% 401 101 172 48 118 6.3 1,041 54.8
328 Godfrey Phillips India Ltd. GODFRYPHLP 500163 FOOD BEVERAGES & TOBACCO CIGARETTES-TOBACCO PRODUCTS 1,412.5 1,151 223.6 16.27% 36.5 6.6 218.5 55.5 202.1 38.9 802.9 154.4
329 Vaibhav Global Ltd. VAIBHAVGBL 532156 TEXTILES APPARELS & ACCESSORIES OTHER APPARELS & ACCESSORIES 708.4 641.5 63.5 9.01% 22.6 2.9 41.4 12.4 29.4 1.8 121.3 7.3
330 Abbott India Ltd. ABBOTINDIA 500488 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,549.7 1,113.3 380.9 25.49% 17.8 3.1 415.4 102.5 312.9 147.3 1,081.4 508.9
331 Adani Total Gas Ltd. ATGL ASM UTILITIES UTILITIES 1,104.8 815.7 279.9 25.55% 37.6 27.3 224.2 57.2 172.7 1.6 571 5.2
332 Nestle India Ltd. NESTLEIND 500790 FMCG PACKAGED FOODS 5,070.1 3,811.9 1,224.9 24.32% 111.2 31.4 1,222 313.9 908.1 94.2 2,971.1 308.2
333 Bayer Cropscience Ltd. BAYERCROP 506285 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 1,633.3 1,312.3 304.9 18.85% 11.6 3.7 305.7 82.8 222.9 49.6 844.4 188.1
334 Amber Enterprises India Ltd. AMBER 540902 CONSUMER DURABLES CONSUMER ELECTRONICS 939.8 867.5 59.6 6.43% 45.2 36.6 -9.5 -3.8 -6.9 -2.1 156.8 46.5
335 Rail Vikas Nigam Ltd. RVNL 542649 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 5,210.3 4,616 298.3 6.07% 6.2 132.7 455.4 85.2 394.3 1.9 1,478.8 7.1
336 Metropolis Healthcare Ltd. METROPOLIS 542650 DIVERSIFIED CONSUMER SERVICES HEALTHCARE SERVICES 309.7 233.7 74.8 24.25% 22.2 5.7 48.1 12.5 35.5 6.9 133.4 26
337 Polycab India Ltd. POLYCAB 542652 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 4,253 3,608.8 608.9 14.44% 60.3 26.8 557.2 127.4 425.6 28.4 1,607.2 107.1
338 Multi Commodity Exchange of India Ltd. MCX 534091 BANKING AND FINANCE EXCHANGE 184 193.8 -28.7 -17.38% 6.6 0.1 -16.4 1.6 -19.1 -3.7 44.8 8.8
339 IIFL Finance Ltd. IIFL 532636 BANKING AND FINANCE OTHER FINANCIAL SERVICES 2,533.7 788.3 1,600.8 64.66% 43.3 932.1 683.5 158 474.3 12.4 1,690.7 44.4
340 Ratnamani Metals & Tubes Ltd. RATNAMANI 520111 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 1,141.9 886.3 244.9 21.65% 23.6 10.8 221.1 56.8 163.9 23.4 622.6 88.8
341 RHI Magnesita India Ltd. RHIM 534076 GENERAL INDUSTRIALS OTHER INDUSTRIAL GOODS 989.7 839 147.9 14.98% 44.2 8.5 97.9 26.3 71.3 3.5 -502.2 -24.3
342 Birlasoft Ltd. BSOFT 532400 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 1,325.4 1,102.7 207.1 15.81% 21.5 5.7 195.5 50.4 145.1 5.2 378.4 13.7
343 EIH Ltd. EIHOTEL 500840 HOTELS RESTAURANTS & TOURISM HOTELS 552.5 387.6 142.9 26.94% 33.2 5.6 126.1 36.2 93.1 1.5 424.1 6.8
344 Affle (India) Ltd. AFFLE 542752 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 441.2 344.1 87.2 20.22% 18.4 5.5 73.2 6.4 66.8 5 264.3 19.8
345 Westlife Foodworld Ltd. WESTLIFE 505533 HOTELS RESTAURANTS & TOURISM RESTAURANTS 618 516.5 98.2 15.98% 43.9 27.4 30.2 7.8 22.4 1.4 107.7 6.9
346 IndiaMART InterMESH Ltd. INDIAMART 542726 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 329.3 214.7 80 27.15% 8 2.3 104.3 23.9 69.4 11.4 321.1 53.6
347 Infosys Ltd. INFY 500209 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 39,626 29,554 9,44 24.21% 1,166 138 8,768 2,553 6,212 15 24,871 60.1
348 Sterling and Wilson Renewable Energy Ltd. SWSOLAR 542760 COMMERCIAL SERVICES & SUPPLIES CONSULTING SERVICES 776.7 758 1.5 0.19% 4.3 64.3 -50 4.6 -54.2 -2.9 -668.4 -35.2
349 ABB India Ltd. ABB 500002 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 2,846 2,330.7 438.5 15.84% 30.3 0.9 484.2 122.2 362.9 17.1 1,208.7 57
350 Poly Medicure Ltd. POLYMED 531768 HEALTHCARE EQUIPMENT & SUPPLIES HEALTHCARE SUPPLIES 351.4 253.1 84.2 24.97% 16 2.2 80.9 18.8 62.2 6.5 233.7 24.4
351 GMM Pfaudler Ltd. GMMPFAUDLR 505255 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 946 795.5 142 15.15% 32.2 21.5 96.8 26.5 71.1 15.8 183.2 40.8
352 Gujarat Fluorochemicals Ltd. FLUOROCHEM 542812 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 960.3 783.7 163.1 17.23% 67.5 34.2 74.8 22.1 52.7 4.8 915.2 83.3
353 360 One Wam Ltd. 360ONE 542772 BANKING AND FINANCE OTHER FINANCIAL SERVICES 617.1 235.6 317.8 57.31% 13.7 139.9 226.8 40.8 186 5.2 696.8 19.5
354 Tata Communications Ltd. TATACOMM 500483 TELECOM SERVICES OTHER TELECOM SERVICES 4,897.9 3,857.1 1,015.5 20.84% 605.1 137.4 298.3 77.9 220.7 7.7 1,322.3 46.4
355 Alkyl Amines Chemicals Ltd. ALKYLAMINE 506767 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 354.5 303.9 48.3 13.71% 12.5 1.7 36.4 9.2 27.2 5.3 171.3 33.5
356 CSB Bank Ltd. CSBBANK 542867 BANKING AND FINANCE BANKS 835.8 317.5 174.6 25.41% 0 343.6 178 44.8 133.2 7.7 577.7 33.3
357 Indian Railway Catering & Tourism Corporation Ltd. IRCTC 542830 DIVERSIFIED CONSUMER SERVICES TRAVEL SUPPORT SERVICES 1,042.4 628.8 366.6 36.83% 14 4.4 395.2 100.5 294.7 3.7 1,061.2 13.3
358 Sumitomo Chemical India Ltd. SUMICHEM 542920 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 928 715.5 187.9 20.80% 15.8 1.2 195.5 52 143.4 2.9 367.7 7.4
359 Century Textiles & Industries Ltd. CENTURYTEX 500040 COMMERCIAL SERVICES & SUPPLIES PAPER & PAPER PRODUCTS 1,114.9 1,069.2 33.8 3.07% 59.2 17 -30.5 -3.3 -30.4 -2.8 117.7 10.5
360 SBI Cards and Payment Services Ltd. SBICARD 543066 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 4,221.4 2,018.8 1,327 32.47% 46.8 604.9 809.4 206.4 603 6.4 2,302.2 24.3
361 Hitachi Energy India Ltd. POWERINDIA 543187 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 1,228.2 1,162.6 65.3 5.32% 22.5 10.7 32.4 7.6 24.7 5.8 82.5 19.5
362 Suven Pharmaceuticals Ltd. SUVENPHAR 543064 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 250.9 133.1 98 42.40% 11.9 0.5 105.4 25.8 79.6 3.1 431.8 17
363 Tata Chemicals Ltd. TATACHEM 500770 CHEMICALS & PETROCHEMICALS COMMODITY CHEMICALS 4,083 3,179 819 20.49% 234 145 627 120 428 16.8 2,06 80.8
364 Aarti Drugs Ltd. AARTIDRUGS 524348 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 642.2 565.1 76.4 11.92% 12.6 8.2 56.3 16.7 39.6 4.3 180.2 19.6
365 Gujarat Ambuja Exports Ltd. GAEL 524226 FMCG EDIBLE OILS 1,157.7 1,012.2 103.3 9.26% 30.5 5.9 109.1 26.3 82.8 3.6 305.1 13.3
366 Polyplex Corporation Ltd. POLYPLEX 524051 COMMERCIAL SERVICES & SUPPLIES CONTAINERS & PACKAGING 1,595.7 1,451.5 120.6 7.67% 75.1 9.9 59.1 10.9 27.9 8.9 71.1 22.6
367 Chalet Hotels Ltd. CHALET 542399 HOTELS RESTAURANTS & TOURISM HOTELS 318.2 188.6 126 40.04% 35 50.1 44.5 8 36.4 1.8 266.7 13
368 Adani Enterprises Ltd. ADANIENT 512599 COMMERCIAL SERVICES & SUPPLIES COMMODITY TRADING & DISTRIBUTION 23,066 20,087.2 2,430.1 10.79% 757 1,342.8 791 397.8 227.8 2 2,444.3 21.4
369 YES Bank Ltd. YESBANK 532648 BANKING AND FINANCE BANKS 7,980.6 2,377.1 810 12.06% 0 4,793.6 304.4 75.7 228.6 0.1 836.6 0.3
370 EPL Ltd. EPL 500135 COMMERCIAL SERVICES & SUPPLIES CONTAINERS & PACKAGING 1,011.2 820.6 181 18.07% 83.6 30.6 76.4 25.4 50.5 1.6 251.9 7.9
371 Network18 Media & Investments Ltd. NETWORK18 532798 MEDIA BROADCASTING & CABLE TV 2,052.2 2,083.8 -218.3 -11.70% 56.8 66.2 -154.5 -6.5 -61 -0.6 -144.2 -1.4
372 CIE Automotive India Ltd. CIEINDIA 532756 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 2,299.4 1,934 345.4 15.15% 78.3 31 256.1 69.1 375.4 9.9 298.4 7.9
373 Vedanta Ltd. VEDL 500295 METALS & MINING ALUMINIUM AND ALUMINIUM PRODUCTS 39,585 27,466 11,479 29.47% 2,642 2,523 8,177 9,092 -1,783 -4.8 5,202 14
374 Rossari Biotech Ltd. ROSSARI 543213 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 484.8 419.9 63.6 13.15% 15.1 5 44.8 11.9 32.9 6 116.8 21.2
375 KPIT Technologies Ltd. KPITTECH 542651 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 1,208.6 959.2 239.9 20.01% 48.1 13.6 187.7 46.3 140.9 5.2 486.9 18
376 Intellect Design Arena Ltd. INTELLECT 538835 SOFTWARE & SERVICES IT SOFTWARE PRODUCTS 631.7 497.2 121.9 19.69% 33.7 0.8 96.5 25.7 70.4 5.2 316.6 23.2
377 Balaji Amines Ltd. BALAMINES 530999 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 387.3 326.8 53.8 14.13% 10.8 1.8 48 11.6 34.7 10.7 197.3 60.9
378 UTI Asset Management Company Ltd. UTIAMC 543238 BANKING AND FINANCE ASSET MANAGEMENT COS. 405.6 172.5 231.5 57.30% 10.4 2.8 219.8 37 182.8 14.4 562.9 44.3
379 Mazagon Dock Shipbuilders Ltd. MAZDOCK 543237 TRANSPORTATION SHIPPING 2,079.2 1,651.1 176.6 9.66% 20.2 1.3 406.6 102.8 332.9 16.5 1,327.6 65.8
380 Computer Age Management Services Ltd. CAMS 543232 BANKING AND FINANCE CAPITAL MARKETS 284.7 153 122.1 44.39% 17.4 2 112.4 28.6 84.5 17.2 309.2 62.9
381 Happiest Minds Technologies Ltd. HAPPSTMNDS 543227 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 428.8 324 82.6 20.32% 14.6 11.2 79.1 20.7 58.5 3.9 232 15.6
382 Triveni Turbine Ltd. TRITURBINE 533655 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 402.3 313.4 74.3 19.17% 5.1 0.6 83.2 19 64.2 2 233.1 7.3
383 Angel One Ltd. ANGELONE ASM BANKING AND FINANCE CAPITAL MARKETS 1,049.3 602.6 443.4 42.31% 11.2 26.4 407.2 102.7 304.5 36.3 1,020.2 121.7
384 Tanla Platforms Ltd. TANLA 532790 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 1,014.9 811.8 196.8 19.51% 22.6 1.8 178.7 36.2 142.5 10.6 514.7 38.3
385 Max Healthcare Institute Ltd. MAXHEALTH 543220 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 1,408.6 975.8 387.4 28.42% 57.9 8.5 366.4 89.7 276.7 2.9 990.1 10.2
386 Asahi India Glass Ltd. ASAHIINDIA 515030 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,122.6 934 185.6 16.58% 43 34.4 111.3 30.2 86.9 3.6 343.5 14.1
387 Prince Pipes & Fittings Ltd. PRINCEPIPE 542907 GENERAL INDUSTRIALS PLASTIC PRODUCTS 660.4 562.3 94.2 14.35% 22.5 0.7 92.8 22.2 70.6 5.2 219.8 19.9
388 Route Mobile Ltd. ROUTE 543228 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 1,018.3 886.5 128.1 12.63% 21.4 6.5 103.8 15.5 88.8 14.2 365.3 58.3
389 KPR Mill Ltd. KPRMILL 532889 TEXTILES APPARELS & ACCESSORIES TEXTILES 1,533 1,212.9 298 19.72% 46 18.1 256 54.2 201.8 5.9 788.8 23.1
390 Infibeam Avenues Ltd. INFIBEAM 539807 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 792.6 719.7 70.2 8.89% 17.1 0.5 55.2 14.7 41 0.1 142.2 0.5
391 Restaurant Brands Asia Ltd. RBA 543248 HOTELS RESTAURANTS & TOURISM RESTAURANTS 628.2 568.7 56.2 9.00% 78.6 31.5 -50.7 0 -46 -0.9 -220.3 -4.5
392 Larsen & Toubro Ltd. LT 500510 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 52,157 45,392.1 5,632 11.04% 909.9 864 4,991.1 1,135.5 3,222.6 22.9 12,255.3 89.2
393 Gland Pharma Ltd. GLAND 543245 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,426.6 1,049.3 324.1 23.60% 81.3 6 289.9 95.8 194.1 11.8 698.8 42.4
394 Macrotech Developers Ltd. LODHA 543287 REALTY REALTY 1,755.1 1,333.5 416.1 23.78% 29.3 123.1 269.2 62.4 201.9 2.1 1,529.2 15.9
395 Poonawalla Fincorp Ltd. POONAWALLA 524000 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 745.3 178.9 531.7 71.98% 14.7 215.5 1,124.6 270 860.2 11.2 1,466.4 19.1
396 The Fertilisers and Chemicals Travancore Ltd. FACT 590024 FERTILIZERS FERTILIZERS 1,713.6 1,530.8 132.4 7.96% 5.3 61.2 105.2 0 105.2 1.6 508.4 7.9
397 Home First Finance Company India Ltd. HOMEFIRST 543259 BANKING AND FINANCE HOUSING FINANCE 278 53.7 211.6 77.43% 2.8 117 96.4 22.1 74.3 8.4 266.2 30.2
398 CG Power and Industrial Solutions Ltd. CGPOWER 500093 GENERAL INDUSTRIALS HEAVY ELECTRICAL EQUIPMENT 2,019 1,692.9 308.6 15.42% 22.9 0.4 329.9 86.2 242.3 1.6 1,1 7.2
399 Laxmi Organic Industries Ltd. LXCHEM 543277 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 660.5 613.3 38.9 5.97% 27.5 2.1 17.5 6.8 10.7 0.4 100.6 3.8
400 Anupam Rasayan India Ltd. ANURAS 543275 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 395.6 284.7 107.5 27.41% 19.8 20.4 70.7 22 40.7 3.8 178.9 16.6
401 Kalyan Jewellers India Ltd. KALYANKJIL ASM TEXTILES APPARELS & ACCESSORIES GEMS & JEWELLERY 4,427.7 4,100.9 313.7 7.11% 66.9 81.7 178.1 43.3 135.2 1.3 497.9 4.8
402 Jubilant Pharmova Ltd. JUBLPHARMA 530019 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,690.2 1,438.5 241.8 14.39% 96.6 66.1 89 35.9 62.5 3.9 -44.6 -2.8
403 Indigo Paints Ltd. INDIGOPNTS 543258 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 273.4 228.7 41.8 15.45% 10 0.5 34.3 8.2 26.1 5.5 132.4 27.8
404 Indian Railway Finance Corporation Ltd. IRFC 543257 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 6,767.5 33.5 6,732.4 99.50% 2.1 5,181.5 1,549.9 0 1,549.9 1.2 6,067.6 4.6
405 Mastek Ltd. MASTEK 523704 SOFTWARE & SERVICES IT CONSULTING & SOFTWARE 770.4 642.5 123 16.07% 20.9 12.6 90.3 25 62.8 20.5 269.7 88
406 Equitas Small Finance Bank Ltd. EQUITASBNK 543243 BANKING AND FINANCE BANKS 1,540.4 616.8 330.2 24.30% 0 593.4 267 68.9 198.1 1.8 749.5 6.7
407 Tata Teleservices (Maharashtra) Ltd. TTML 532371 TELECOM SERVICES TELECOM SERVICES 288.6 159.3 127.5 44.45% 36.3 403.2 -310.2 0 -310.2 -1.6 -1,168.3 -6
408 Praj Industries Ltd. PRAJIND 522205 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 893.3 798.4 84 9.52% 9.1 1 84.8 22.4 62.4 3.4 271.4 14.8
409 Nazara Technologies Ltd. NAZARA 543280 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 309.5 269.4 26.7 8.98% 15.1 2.7 21.2 -1.3 19.8 3 60 9.1
410 Jubilant Ingrevia Ltd. JUBLINGREA 543271 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 1,028.5 902.3 117.7 11.54% 33.9 12.5 79.8 22.4 57.5 3.6 258.9 16.4
411 Sona BLW Precision Forgings Ltd. SONACOMS 543300 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 796.9 567.5 223.3 28.24% 53.4 6 164.1 40.1 123.8 2.1 462.8 7.9
412 Chemplast Sanmar Ltd. CHEMPLASTS 543336 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 1,025 941.8 46 4.65% 35.3 38.6 9.2 -16.8 26.1 1.6 35.3 2.2
413 Aptus Value Housing Finance India Ltd. APTUS 543335 BANKING AND FINANCE HOUSING FINANCE 344.5 50.6 277.5 83.18% 2.6 96.1 189.6 41.5 148 3 551.1 11.1
414 Clean Science & Technology Ltd. CLEAN 543318 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 187.1 106.3 74.8 41.32% 11.1 0.3 69.5 17.3 52.2 4.9 275.5 25.9
415 Medplus Health Services Ltd. MEDPLUS 543427 HEALTHCARE EQUIPMENT & SUPPLIES HEALTHCARE SUPPLIES 1,419 1,323.5 85.1 6.04% 55.5 23.5 16.4 1.9 14.6 1.2 58.3 4.9
416 Nuvoco Vistas Corporation Ltd. NUVOCO 543334 CEMENT AND CONSTRUCTION CEMENT & CEMENT PRODUCTS 2,578.9 2,243 329.9 12.82% 225.6 139.9 -29.6 -31.1 1.5 0 141.8 4
417 Star Health and Allied Insurance Company Ltd. STARHEALTH 543412 BANKING AND FINANCE GENERAL INSURANCE 3,463.2 3,295.8 165.7 4.79% 0 0 167.1 41.8 125.3 2.1 725.4 12.4
418 Go Fashion (India) Ltd. GOCOLORS 543401 TEXTILES APPARELS & ACCESSORIES OTHER APPARELS & ACCESSORIES 192.8 132.2 56.6 29.98% 25.8 8.9 25.8 5.7 20 3.7 85.4 15.8
419 PB Fintech Ltd. POLICYBZR 543390 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 909.1 900.7 -89.1 -10.98% 22.3 7.2 -21.1 -0.3 -20.2 -0.5 -127.9 -2.8
420 FSN E-Commerce Ventures Ltd. NYKAA 543384 SOFTWARE & SERVICES INTERNET & CATALOGUE RETAIL 1,515.6 1,426.4 80.6 5.35% 54.6 21.3 13.3 4 5.8 0 19.8 0.1
421 Krishna Institute of Medical Sciences Ltd. KIMS 543308 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 655.4 475.2 177.3 27.17% 32.6 8.9 138.6 37.3 92 11.5 342.1 42.7
422 Zomato Ltd. ZOMATO 543320 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 3,06 2,895 -47 -1.65% 128 16 21 -15 36 0 -496.8 -0.6
423 Brightcom Group Ltd. BCG 532368 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 1,690.5 1,172.3 518 30.65% 72.3 0.1 445.8 124.3 321.5 1.6 1,415.2 7
424 Shyam Metalics and Energy Ltd. SHYAMMETL 543299 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 2,978.9 2,633.6 307.1 10.44% 176.5 35.4 133.4 -348.6 484.1 18.9 1,049.9 41.2
425 G R Infraprojects Ltd. GRINFRA 543317 CEMENT AND CONSTRUCTION ROADS & HIGHWAYS 1,909.2 1,415.7 467.1 24.81% 61.7 144.6 287.1 69.9 217.2 22.5 1,240.3 128.3
426 RattanIndia Enterprises Ltd. RTNINDIA 534597 UTILITIES ELECTRIC UTILITIES 1,618.1 1,392.8 1.5 0.11% 4.3 28.8 142.2 1.7 140.9 1 147.6 1.1
427 Borosil Renewables Ltd. BORORENEW 502219 CONSUMER DURABLES HOUSEWARE 406.3 369.2 32.5 8.09% 31 9.6 28.9 -1.1 25.1 1.9 32.1 2.5
428 HLE Glascoat Ltd. HLEGLAS 522215 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 227.8 198 26.5 11.79% 6.1 5.8 16.1 5.3 10 1.6 54.4 8
429 Tata Investment Corporation Ltd. TATAINVEST 501301 DIVERSIFIED HOLDING COMPANIES 125 10.1 113.8 91.88% 0.2 4.7 110.1 -1.3 124.4 24.6 326.1 64.4
430 Sapphire Foods India Ltd. SAPPHIRE 543397 HOTELS RESTAURANTS & TOURISM RESTAURANTS 650.1 527.5 115.1 17.91% 76.8 24.5 21.4 6.2 15.3 2.4 208.5 32.7
431 Devyani International Ltd. DEVYANI 543330 HOTELS RESTAURANTS & TOURISM RESTAURANTS 826 665 154.4 18.84% 86.3 41.7 19 -16.8 33.4 0.3 177.5 1.5
432 Vijaya Diagnostic Centre Ltd. VIJAYA 543350 DIVERSIFIED CONSUMER SERVICES HEALTHCARE SERVICES 145.6 81.5 57.4 41.31% 13.7 5.9 44.6 11 33.3 3.3 103.4 10.1
433 C.E. Info Systems Ltd. MAPMYINDIA 543425 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 99.3 50.1 41 44.98% 3.7 0.7 44.7 11.1 33 6.1 122.9 22.7
434 Latent View Analytics Ltd. LATENTVIEW 543398 SOFTWARE & SERVICES DATA PROCESSING SERVICES 172.7 124.9 30.8 19.78% 2.3 0.8 44.7 10.6 34 1.7 153.6 7.5
435 Metro Brands Ltd. METROBRAND 543426 RETAILING FOOTWEAR 571.9 400.3 155.4 27.96% 57.2 19.7 94.7 27.5 66.7 2.5 340 12.5
436 Easy Trip Planners Ltd. EASEMYTRIP 543272 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 144.6 76.9 64.8 45.71% 1 2 64.7 17.7 47.2 0.3 146 0.8
437 Shree Renuka Sugars Ltd. RENUKA 532670 FOOD BEVERAGES & TOBACCO SUGAR 2,564.7 2,491 63.7 2.49% 64.1 216.8 -207.2 -1.6 -204.9 -1 -286 -1.3
438 One97 Communications Ltd. PAYTM 543396 SOFTWARE & SERVICES INTERNET SOFTWARE & SERVICES 2,662.5 2,749.6 -231 -9.17% 180.1 7 -279.9 12.7 -290.5 -5 -1,207.9 -19
439 MTAR Technologies Ltd. MTARTECH 543270 GENERAL INDUSTRIALS DEFENCE 167.7 130.7 36.1 21.64% 5.8 5.5 25.7 5.2 20.5 6.7 103.3 33.6
440 Capri Global Capital Ltd. CGCL 531595 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 557.4 229.3 304.8 54.70% 23.1 195.8 86 20.8 65.2 3.2 231.2 11.2
441 GMR Airports Infrastructure Ltd. GMRINFRA ASM CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 2,185 1,336.8 726.7 35.22% 373 695.8 -252 54.9 -91 -0.1 -370.9 -0.6
442 Triveni Engineering & Industries Ltd. TRIVENI 532356 FOOD BEVERAGES & TOBACCO SUGAR 1,629.7 1,554.5 62.9 3.89% 25.8 10.2 39.3 10.1 29.1 1.3 434.3 19.8
443 Delhivery Ltd. DELHIVERY 543529 TRANSPORTATION TRANSPORTATION - LOGISTICS 2,043 1,957.3 -15.6 -0.80% 171.2 19.6 -105.2 -2.1 -102.9 -1.4 -546.7 -7.5
444 Life Insurance Corporation of India LICI 543526 BANKING AND FINANCE LIFE INSURANCE 202,394.9 193,612.5 8,445 4.18% 0 0 8,696.5 1,083.9 8,030.3 12.7 37,204.8 58.8
445 Campus Activewear Ltd. CAMPUS 543523 RETAILING FOOTWEAR 259.1 234.2 24.5 9.46% 18.1 6.5 0.4 0.1 0.3 0 103.1 3.4
446 Motherson Sumi Wiring India Ltd. MSUMI 543498 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 2,110.2 1,856.5 248.1 11.79% 36.4 7.4 210 54.1 155.9 0.3 523.6 1.2
447 Olectra Greentech Ltd. OLECTRA 532439 AUTOMOBILES & AUTO COMPONENTS COMMERCIAL VEHICLES 310.3 266.6 40.5 13.20% 8.8 9.7 25.2 8 18.6 2.2 78.5 9.6
448 Patanjali Foods Ltd. PATANJALI 500368 FMCG EDIBLE OILS 7,845.8 7,426.6 395.3 5.05% 60.1 24 335.1 80.5 254.5 7 875.2 24.2
449 Raymond Ltd. RAYMOND 500330 TEXTILES APPARELS & ACCESSORIES TEXTILES 2,320.7 1,938.8 314.6 13.96% 65.4 89.3 204.2 50.7 159.8 24 1,514.2 227.5
450 Swan Energy Ltd. SWANENERGY 503310 REALTY REALTY 1,230.1 966.3 257 21.01% 27.1 58.3 178.4 12.8 84.6 6.7 308.4 11.7
451 Samvardhana Motherson International Ltd. MOTHERSON 517334 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 23,639.2 21,585 1,888.8 8.05% 867.4 487.9 449.5 229.2 201.6 0.3 1,910.3 2.8
452 Vedant Fashions Ltd. MANYAVAR 543463 RETAILING SPECIALTY RETAIL 233.4 125.5 92.8 42.51% 32.5 10.7 64.8 16.1 48.7 2 399.9 16.5
453 Adani Wilmar Ltd. AWL 543458 FMCG EDIBLE OILS 12,331.2 12,123.5 143.7 1.17% 95.7 220.2 -161.8 -31.5 -130.7 -1 130.1 1
454 Mahindra Lifespace Developers Ltd. MAHLIFE 532313 REALTY REALTY 25.7 52.7 -34.9 -196.45% 3.1 0.2 -30.3 -10.8 -18.9 -1.2 10.5 0.7
455 Tejas Networks Ltd. TEJASNET 540595 TELECOM SERVICES OTHER TELECOM SERVICES 413.9 383 13 3.28% 41.7 7 -17.7 -5.1 -12.6 -0.7 -61.3 -3.5
456 Aether Industries Ltd. AETHER 543534 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 178.3 118.2 46 28.00% 9.7 1.6 48.7 12.1 36.7 2.8 139.1 10.5
457 JBM Auto Ltd. JBMA ASM AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,238.8 1,091.3 139.7 11.35% 41.2 47.9 58.3 11.3 44.2 3.7 136.8 11.6
458 Deepak Fertilisers & Petrochemicals Corporation Ltd. DEEPAKFERT 500645 CHEMICALS & PETROCHEMICALS COMMODITY CHEMICALS 2,443.2 2,138.1 286.1 11.80% 81.2 107.1 116.8 53.3 60.1 4.8 674.5 53.4
459 Sharda Cropchem Ltd. SHARDACROP 538666 CHEMICALS & PETROCHEMICALS AGROCHEMICALS 604.3 559.6 21.2 3.65% 74 4.6 -33.8 -6.3 -27.6 -3.1 191 21.2
460 Shoppers Stop Ltd. SHOPERSTOP 532638 RETAILING DEPARTMENT STORES 1,049.7 878.2 160.9 15.49% 108.2 54.9 3.5 0.8 2.7 0.2 94.2 8.6
461 BEML Ltd. BEML 500048 AUTOMOBILES & AUTO COMPONENTS COMMERCIAL VEHICLES 924 855.3 61.5 6.70% 15.8 10.8 42.2 -9.6 51.8 12.4 200.8 48.2
462 Lemon Tree Hotels Ltd. LEMONTREE 541233 HOTELS RESTAURANTS & TOURISM HOTELS 230.1 125.3 101.9 44.84% 22.6 47.3 34.8 8.6 22.6 0.3 130.1 1.6
463 Rainbow Childrens Medicare Ltd. RAINBOW 543524 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 340.5 215.1 117.6 35.34% 26.8 13.3 85.2 22.1 62.9 6.2 215.4 21.2
464 UCO Bank UCOBANK 532505 BANKING AND FINANCE BANKS 5,865.6 1,581.5 981.9 18.81% 0 3,302.3 639.8 238.1 403.5 0.3 1,84 1.5
465 Piramal Pharma Ltd. PPLPHARMA 543635 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 1,960.6 1,645.7 265.6 13.90% 184.5 109.9 20.4 34.5 5 0 -133.6 -1
466 KSB Ltd. KSB 500249 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 572.2 493.4 70.3 12.47% 12.3 2 64.5 17.1 50.1 14.4 209.7 60.3
467 Data Patterns (India) Ltd. DATAPATTNS 543428 GENERAL INDUSTRIALS DEFENCE 119.2 67.5 40.8 37.63% 3.1 2.3 46.3 12.5 33.8 6 148.3 26.5
468 Global Health Ltd. MEDANTA 543654 DIVERSIFIED CONSUMER SERVICES HEALTHCARE FACILITIES 864.7 631.1 212.9 25.22% 42.9 20.1 170.6 45.4 125.2 4.7 408.9 15.2
469 Aarti Industries Ltd. AARTIIND 524208 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 1,454 1,221.2 232.8 16.01% 93 58.2 81.6 -9.1 90.7 2.5 446.2 12.3
470 BLS International Services Ltd. BLS 540073 DIVERSIFIED CONSUMER SERVICES TRAVEL SUPPORT SERVICES 416.4 321 86.7 21.27% 7.3 1 87.2 5.2 78.7 1.9 267.6 6.5
471 Archean Chemical Industries Ltd. ACI 543657 CHEMICALS & PETROCHEMICALS COMMODITY CHEMICALS 301.7 195 95.5 32.86% 17.5 1.9 87.3 21.3 66 5.4 394.4 32.1
472 Adani Power Ltd. ADANIPOWER ASM UTILITIES ELECTRIC UTILITIES 14,935.7 7,819.2 5,171.4 39.81% 1,004.5 888.4 5,223.6 -1,370.6 6,594.2 16.5 20,604.8 53.4
473 Craftsman Automation Ltd. CRAFTSMAN 543276 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,183.8 941.6 237.5 20.14% 66.8 41.6 133.8 29.6 94.5 44.1 298.3 141.2
474 NMDC Ltd. NMDC 526371 METALS & MINING MINING 4,335 2,823.6 1,190.4 29.66% 88.8 18.6 1,404.1 379 1,026.2 3.5 5,862.2 20
475 Epigral Ltd. EPIGRAL 543332 CHEMICALS & PETROCHEMICALS SPECIALTY CHEMICALS 479.1 370.2 107.9 22.57% 31.5 21.3 56.1 17.9 38 9.1 223.4 53.8
476 Apar Industries Ltd. APARINDS 532259 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 3,944.7 3,576.2 349.8 8.91% 28.2 103.1 237.3 62.9 173.9 45.4 783.9 204.8
477 Bikaji Foods International Ltd. BIKAJI 543653 FMCG PACKAGED FOODS 614.7 521 87.7 14.41% 15.6 2.9 75.2 15.4 61.2 2.5 173.6 6.9
478 Five-Star Business Finance Ltd. FIVESTAR 543663 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 522.4 133.2 375 72.28% 5.7 105.9 267 67.6 199.4 6.8 703 24.1
479 Ingersoll-Rand (India) Ltd. INGERRAND 500210 GENERAL INDUSTRIALS INDUSTRIAL MACHINERY 282.8 210.7 65.7 23.76% 4.6 0.6 67 17.2 49.7 15.8 218.5 69.2
480 KFIN Technologies Ltd. KFINTECH 543720 BANKING AND FINANCE OTHER FINANCIAL SERVICES 215.3 115.3 93.7 44.82% 12.6 3.2 84.2 22.3 61.4 3.6 215.1 12.6
481 Piramal Enterprises Ltd. PEL 500302 BANKING AND FINANCE FINANCE (INCLUDING NBFCS) 2,205.2 1,320.1 1,117.9 50.97% 38.3 1,038.9 -11.8 10.7 48.2 2 3,906.5 173.9
482 NMDC Steel Ltd. NSLNISP 543768 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 290.3 349.6 -72.2 -26.04% 74.5 40.8 -174.7 -43.6 -131.1 -0.5
483 Eris Lifesciences Ltd. ERIS 540596 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 508.8 324.2 181.1 35.85% 42.1 16.3 126.2 3.9 123.4 9.1 385.6 28.3
484 Mankind Pharma Ltd. MANKIND 543904 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 2,768.1 2,025.5 682.6 25.21% 96.5 8.6 637.5 129.8 501 12.5 1,564.8 39.1
485 Kaynes Technology India Ltd. KAYNES ASM CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 369.8 312.1 48.8 13.52% 6.5 11.8 39.4 7.1 32.3 5.5 143.2 24.6
486 Safari Industries (India) Ltd. SAFARI 523025 TEXTILES APPARELS & ACCESSORIES OTHER APPARELS & ACCESSORIES 372.9 306.6 63.5 17.15% 12.2 2.2 51.9 12.1 39.8 16.7 162.3 68.2
487 Saregama India Ltd. SAREGAMA 532163 MEDIA MOVIES & ENTERTAINMENT 185.6 111.5 60.9 35.32% 8.2 0.2 65.6 17.6 48.1 2.5 193.4 10
488 Syrma SGS Technology Ltd. SYRMA 543573 CONSUMER DURABLES OTHER ELECTRICAL EQUIPMENT/PRODUCTS 720.6 662.7 49 6.88% 11.6 8 37 6.4 28.3 1.6 132.4 7.5
489 Jindal Saw Ltd. JINDALSAW ASM GENERAL INDUSTRIALS OTHER INDUSTRIAL PRODUCTS 5,488.9 4,662 804.2 14.71% 142.5 188.7 495.6 139.6 375.7 11.8 1,135.8 35.5
490 Godawari Power & Ispat Ltd. GPIL 532734 METALS & MINING IRON & STEEL/INTERM.PRODUCTS 1,314.2 929.6 361.4 28.00% 34.8 10.2 339.6 86.1 256.9 20.6 785.5 63
491 Gillette India Ltd. GILLETTE 507815 FMCG PERSONAL PRODUCTS 676.2 530.8 136.7 20.48% 20.1 0.1 125.2 32.5 92.7 28.4 361.6 111
492 Symphony Ltd. SYMPHONY 517385 CONSUMER DURABLES CONSUMER ELECTRONICS 286 234 41 14.91% 7 2 43 8 35 5.1 114 16.5
493 Glenmark Life Sciences Ltd. GLS 543322 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 600.7 428.3 167.1 28.06% 13.1 0.4 158.9 40.2 118.7 9.7 505.5 41.3
494 Usha Martin Ltd. USHAMART 517146 METALS & MINING IRON & STEEL PRODUCTS 806 640.4 144.3 18.39% 18 6.4 141.2 35 109.5 3.6 399.4 13.1
495 Ircon International Ltd. IRCON 541956 CEMENT AND CONSTRUCTION CONSTRUCTION & ENGINEERING 3,136.3 2,771.2 215.7 7.22% 27.1 36.9 301.2 77.6 250.7 2.7 884.6 9.4
496 Ujjivan Small Finance Bank Ltd. UJJIVANSFB 542904 BANKING AND FINANCE BANKS 1,579.8 528.6 483.4 34.75% 0 567.8 436.4 108.7 327.7 1.7 1,254.5 6.4
497 Procter & Gamble Health Ltd. PGHL 500126 PHARMACEUTICALS & BIOTECHNOLOGY PHARMACEUTICALS 311 216.3 88.7 29.08% 6.5 0.2 88 22.5 65.6 39.5 231.4 139.4
498 Allcargo Logistics Ltd. ALLCARGO 532749 TRANSPORTATION TRANSPORTATION - LOGISTICS 3,336.3 3,188.8 118 3.57% 106.7 36.7 14.2 1.3 21.8 0.9 361.9 14.7
499 Sheela Foam Ltd. SFL 540203 DIVERSIFIED CONSUMER SERVICES FURNITURE-FURNISHING-PAINTS 637.6 547 66.2 10.80% 21.9 8.6 60.2 15.6 44 4.5 192.4 17.7
500 Alok Industries Ltd. ALOKINDS 521070 TEXTILES APPARELS & ACCESSORIES TEXTILES 1,369.3 1,323.1 35.9 2.64% 78.6 142.2 -174.6 0 -174.8 -0.3 -948.4 -1.9
501 Minda Corporation Ltd. MINDACORP 538962 AUTOMOBILES & AUTO COMPONENTS AUTO PARTS & EQUIPMENT 1,197.9 1,064.5 131.3 10.98% 41.4 14.9 77 18.7 58.8 2.5 278.2 11.6
502 Concord Biotech Ltd. CONCORDBIO 543960 PHARMACEUTICALS & BIOTECHNOLOGY BIOTECHNOLOGY 270.5 143.2 119.2 45.43% 13.3 0.8 113.2 28.7 81 7.7

View File

@ -38,7 +38,6 @@
"outputs": [],
"source": [
"import os\n",
"from pydantic import BaseModel\n",
"from typing import List, Optional\n",
"\n",
"from autogen_core import AgentId, MessageContext, RoutedAgent, SingleThreadedAgentRuntime, message_handler\n",
@ -57,7 +56,8 @@
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.llms.azure_openai import AzureOpenAI\n",
"from llama_index.llms.openai import OpenAI\n",
"from llama_index.tools.wikipedia import WikipediaToolSpec"
"from llama_index.tools.wikipedia import WikipediaToolSpec\n",
"from pydantic import BaseModel"
]
},
{

View File

@ -99,7 +99,7 @@
"All agents publish and subscribe to the default topic, so they can see all\n",
"messages being published.\n",
"\n",
"To run the agents, we publishes a message from a worker."
"To run the agents, we publish a message from a worker."
]
},
{
@ -189,16 +189,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Cross-Language Runtimes\n",
"## Cross-Language Runtimes\n",
"The process described above is largely the same, however all message types MUST use shared protobuf schemas for all cross-agent message types.\n",
"\n",
"# Next Steps\n",
"## Next Steps\n",
"To see complete examples of using distributed runtime, please take a look at the following samples:\n",
"\n",
"- [Distributed Workers](https://github.com/microsoft/autogen/tree/main/python/samples/core_grpc_worker_runtime) \n",
"- [Distributed Semantic Router](https://github.com/microsoft/autogen/tree/main/python/samples/core_semantic_router) \n",
"- [Distributed Group Chat](https://github.com/microsoft/autogen/tree/main/python/samples/core_distributed-group-chat) \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {

View File

@ -48,6 +48,7 @@ framework/component-config
components/model-clients
components/model-context
components/tools
components/workbench
components/command-line-code-executors
```

View File

@ -10,11 +10,18 @@ When installing AgentChat locally, we recommend using a virtual environment for
Create and activate:
Linux/Mac:
```bash
python3 -m venv .venv
source .venv/bin/activate
```
Windows command-line:
```batch
python3 -m venv .venv
.venv\Scripts\activate.bat
```
To deactivate later, run:
```bash

View File

@ -158,7 +158,7 @@
"source": [
"from autogen_core import AgentId, SingleThreadedAgentRuntime\n",
"\n",
"# Create an local embedded runtime.\n",
"# Create a local embedded runtime.\n",
"runtime = SingleThreadedAgentRuntime()\n",
"\n",
"# Register the modifier and checker agents by providing\n",

View File

@ -0,0 +1,131 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Azure AI Foundry Agent\n",
"\n",
"In AutoGen, you can build and deploy agents that are backed by the [Azure AI Foundry Agent Service](https://learn.microsoft.com/en-us/azure/ai-services/agents/overview) using the {py:class}`~autogen_ext.agents.azure._azure_ai_agent.AzureAIAgent` class. Here, important aspects of the agent including the provisioned model, tools (e.g, code interpreter, bing search grounding, file search etc.), observability, and security are managed by Azure. This allows you to focus on building your agent without worrying about the underlying infrastructure.\n",
"\n",
"In this guide, we will explore an example of creating an Azure AI Foundry Agent using the `AzureAIAgent` that can address tasks using the Azure Grounding with Bing Search tool."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# pip install \"autogen-ext[azure]\" # For Azure AI Foundry Agent Service"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Bing Search Grounding \n",
"\n",
"An {py:class}`~autogen_ext.agents.azure._azure_ai_agent.AzureAIAgent` can be assigned a set of tools including [Grounding with Bing Search](https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/bing-grounding?tabs=python&pivots=overview#setup). \n",
"\n",
"Grounding with Bing Search allows your Azure AI Agents to incorporate real-time public web data when generating responses. You need to create a Grounding with Bing Search resource, and then connect this resource to your Azure AI Agents. When a user sends a query, Azure AI Agents decide if Grounding with Bing Search should be leveraged or not. If so, it will leverage Bing to search over public web data and return relevant chunks. Lastly, Azure AI Agents will use returned chunks to generate a response.\n",
"\n",
"## Prerequisites\n",
"\n",
"- You need to have an Azure subscription.\n",
"- You need to have the Azure CLI installed and configured. (also login using the command `az login` to enable default credentials)\n",
"- You need to have the `autogen-ext[azure]` package installed.\n",
"\n",
"You can create a [Grounding with Bing Search resource in the Azure portal](https://portal.azure.com/#create/Microsoft.BingGroundingSearch). Note that you will need to have owner or contributor role in your subscription or resource group to create it. Once you have created your resource, you can then pass it to the Azure Foundry Agent using the resource name.\n",
"\n",
"In the following example, we will create a new Azure Foundry Agent that uses the Grounding with Bing Search resource.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"import dotenv\n",
"from autogen_agentchat.messages import TextMessage\n",
"from autogen_core import CancellationToken\n",
"from autogen_ext.agents.azure import AzureAIAgent\n",
"from azure.ai.agents.models import BingGroundingTool\n",
"from azure.ai.projects.aio import AIProjectClient\n",
"from azure.identity.aio import DefaultAzureCredential\n",
"\n",
"dotenv.load_dotenv()\n",
"\n",
"\n",
"async def bing_example() -> None:\n",
" async with DefaultAzureCredential() as credential: # type: ignore\n",
" async with AIProjectClient( # type: ignore\n",
" credential=credential, endpoint=os.getenv(\"AZURE_PROJECT_ENDPOINT\", \"\")\n",
" ) as project_client:\n",
" conn = await project_client.connections.get(name=os.getenv(\"BING_CONNECTION_NAME\", \"\"))\n",
"\n",
" bing_tool = BingGroundingTool(conn.id)\n",
" agent_with_bing_grounding = AzureAIAgent(\n",
" name=\"bing_agent\",\n",
" description=\"An AI assistant with Bing grounding\",\n",
" project_client=project_client,\n",
" deployment_name=\"gpt-4o\",\n",
" instructions=\"You are a helpful assistant.\",\n",
" tools=bing_tool.definitions,\n",
" metadata={\"source\": \"AzureAIAgent\"},\n",
" )\n",
"\n",
" # For the bing grounding tool to return the citations, the message must contain an instruction for the model to do return them.\n",
" # For example: \"Please provide citations for the answers\"\n",
"\n",
" result = await agent_with_bing_grounding.on_messages(\n",
" messages=[\n",
" TextMessage(\n",
" content=\"What is Microsoft's annual leave policy? Provide citations for your answers.\",\n",
" source=\"user\",\n",
" )\n",
" ],\n",
" cancellation_token=CancellationToken(),\n",
" message_limit=5,\n",
" )\n",
" print(result)\n",
"\n",
"\n",
"await bing_example()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that you can also provide other Azure Backed [tools](https://learn.microsoft.com/en-us/azure/ai-services/agents/how-to/tools/overview) and local client side functions to the agent.\n",
"\n",
"See the {py:class}`~autogen_ext.agents.azure._azure_ai_agent.AzureAIAgent` class api documentation for more details on how to create an Azure Foundry Agent."
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -43,6 +43,8 @@ Find community samples and examples of how to use AutoGen
| [autogen-openaiext-client](https://github.com/vballoli/autogen-openaiext-client) | [PyPi](https://pypi.org/project/autogen-openaiext-client/) | Model client for other LLMs like Gemini, etc. through the OpenAI API |
| [autogen-ext-mcp](https://github.com/richard-gyiko/autogen-ext-mcp) | [PyPi](https://pypi.org/project/autogen-ext-mcp/) | Tool adapter for Model Context Protocol server tools |
| [autogen-ext-email](https://github.com/masquerlin/autogen-ext-email) | [PyPi](https://pypi.org/project/autogen-ext-email/) | A Email agent for generating email and sending |
| [autogen-oaiapi](https://github.com/SongChiYoung/autogen-oaiapi) | [PyPi](https://pypi.org/project/autogen-oaiapi/) | an OpenAI-style API server built on top of AutoGen |
| [autogen-contextplus](https://github.com/SongChiYoung/autogen-contextplus) | [PyPi](https://pypi.org/project/autogen-contextplus/) | Enhanced model_context implementations, with features such as automatic summarization and truncation of model context. |
<!-- Example -->
<!-- | [My Model Client](https://github.com/example) | [PyPi](https://pypi.org/project/example) | Model client for my custom model service | -->

View File

@ -22,6 +22,7 @@ create-your-own
:caption: Guides
azure-container-code-executor
azure-foundry-agent
```
AutoGen is designed to be extensible. The `autogen-ext` package contains the built-in component implementations maintained by the AutoGen project.

View File

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "autogen-core"
version = "0.5.2"
version = "0.6.2"
license = {file = "LICENSE-CODE"}
description = "Foundational interfaces and agent runtime implementation for AutoGen"
readme = "README.md"
@ -19,8 +19,9 @@ dependencies = [
"typing-extensions>=4.0.0",
"pydantic<3.0.0,>=2.10.0",
"protobuf~=5.29.3",
"opentelemetry-api>=1.27.0",
"opentelemetry-api>=1.34.1",
"jsonref~=1.1.0",
"opentelemetry-semantic-conventions==0.55b1",
]
@ -42,7 +43,7 @@ dev = [
"llama-index",
"markdownify",
"nbqa",
"opentelemetry-sdk>=1.27.0",
"opentelemetry-sdk>=1.34.1",
"pip",
"polars",
"python-dotenv",
@ -68,8 +69,9 @@ dev = [
"autodoc_pydantic~=2.2",
"pygments",
"sphinxext-rediraffe",
"opentelemetry-instrumentation-openai",
"autogen_ext==0.5.2",
"autogen_ext==0.6.2",
# Documentation tooling
"diskcache",

View File

@ -59,6 +59,11 @@ from ._serialization import (
from ._single_threaded_agent_runtime import SingleThreadedAgentRuntime
from ._subscription import Subscription
from ._subscription_context import SubscriptionInstantiationContext
from ._telemetry import (
trace_create_agent_span,
trace_invoke_agent_span,
trace_tool_span,
)
from ._topic import TopicId
from ._type_prefix_subscription import TypePrefixSubscription
from ._type_subscription import TypeSubscription
@ -132,4 +137,7 @@ __all__ = [
"DropMessage",
"InterventionHandler",
"DefaultInterventionHandler",
"trace_create_agent_span",
"trace_invoke_agent_span",
"trace_tool_span",
]

View File

@ -1,9 +1,13 @@
from typing import Any, Mapping, Protocol, runtime_checkable
from typing import TYPE_CHECKING, Any, Mapping, Protocol, runtime_checkable
from ._agent_id import AgentId
from ._agent_metadata import AgentMetadata
from ._message_context import MessageContext
# Forward declaration for type checking only
if TYPE_CHECKING:
from ._agent_runtime import AgentRuntime
@runtime_checkable
class Agent(Protocol):
@ -17,6 +21,15 @@ class Agent(Protocol):
"""ID of the agent."""
...
async def bind_id_and_runtime(self, id: AgentId, runtime: "AgentRuntime") -> None:
"""Function used to bind an Agent instance to an `AgentRuntime`.
Args:
agent_id (AgentId): ID of the agent.
runtime (AgentRuntime): AgentRuntime instance to bind the agent to.
"""
...
async def on_message(self, message: Any, ctx: MessageContext) -> Any:
"""Message handler for the agent. This should only be called by the runtime, not by other agents.

View File

@ -118,3 +118,9 @@ class AgentInstantiationContext:
raise RuntimeError(
"AgentInstantiationContext.agent_id() must be called within an instantiation context such as when the AgentRuntime is instantiating an agent. Mostly likely this was caused by directly instantiating an agent instead of using the AgentRuntime to do so."
) from e
@classmethod
def is_in_factory_call(cls) -> bool:
if cls._AGENT_INSTANTIATION_CONTEXT_VAR.get(None) is None:
return False
return True

View File

@ -130,6 +130,60 @@ class AgentRuntime(Protocol):
"""
...
async def register_agent_instance(
self,
agent_instance: Agent,
agent_id: AgentId,
) -> AgentId:
"""Register an agent instance with the runtime. The type may be reused, but each agent_id must be unique. All agent instances within a type must be of the same object type. This API does not add any subscriptions.
.. note::
This is a low level API and usually the agent class's `register_instance` method should be used instead, as this also handles subscriptions automatically.
Example:
.. code-block:: python
from dataclasses import dataclass
from autogen_core import AgentId, AgentRuntime, MessageContext, RoutedAgent, event
from autogen_core.models import UserMessage
@dataclass
class MyMessage:
content: str
class MyAgent(RoutedAgent):
def __init__(self) -> None:
super().__init__("My core agent")
@event
async def handler(self, message: UserMessage, context: MessageContext) -> None:
print("Event received: ", message.content)
async def main() -> None:
runtime: AgentRuntime = ... # type: ignore
agent = MyAgent()
await runtime.register_agent_instance(
agent_instance=agent, agent_id=AgentId(type="my_agent", key="default")
)
import asyncio
asyncio.run(main())
Args:
agent_instance (Agent): A concrete instance of the agent.
agent_id (AgentId): The agent's identifier. The agent's type is `agent_id.type`.
"""
...
# TODO: uncomment out the following type ignore when this is fixed in mypy: https://github.com/python/mypy/issues/3737
async def try_get_underlying_agent_instance(self, id: AgentId, type: Type[T] = Agent) -> T: # type: ignore[assignment]
"""Try to get the underlying agent instance by name and namespace. This is generally discouraged (hence the long name), but can be useful in some cases.

Some files were not shown because too many files have changed in this diff Show More