Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add code generation support to CodeExecutorAgent #6098

Open
wants to merge 29 commits into
base: main
Choose a base branch
from

Conversation

Ethan0456
Copy link
Contributor

Why are these changes needed?

  • To add support for code generation, execution and reflection to CodeExecutorAgent.

Related issue number

Closes #5824

Checks

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
@Ethan0456
Copy link
Contributor Author

Hi @ekzhu,

I’ve pushed an initial draft PR with the basic LLM inference functionality implemented. The code is still in a rough state as I didn’t have much time to polish it today, but I’ll be refining it further in the coming iterations.

Copy link
Collaborator

@ekzhu ekzhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! it is in the right direction.

- `model_client` is now optional. When not provided, the code executor will execute other agent code from chat messages.
- If `model_client` is provided, only the code suggested by the executor will be executed and the output will be returned right after the Code Generation.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Changed the default system message from a generic AI assistant system
message to one that explicitly defines the agent’s role in generating
and executing python code with a focus on correctness and efficiency.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
- Added default terminal and agent descriptions.
- Updated description handling to assign dynamically if None.
- Moved default system_message to a constant

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
…` methods for `ChatMessage` objects

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
…ck that tests `model_client`

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
- Reflection is optional and works when `reflect_on_code_block_results=True`.
- Modified `execute_code_block` to return a `TextMessage` for better control over the reflection workflow.
- When reflection is disabled, the execution result will be wrapped in a `Response` object and yielded.
- When reflection is enabled, the execution result is yielded as a `TextMessage`, followed by the code execution
  reflection, which ultimately returns a `Response` object, terminating the routine.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
@Ethan0456
Copy link
Contributor Author

Hi @ekzhu,

I’ve implemented a prototype baseline for the reflection feature, completing the reasoning, execution, and reflection pipeline. Please let me know your thoughts — I’d appreciate any suggestions!

Copy link
Collaborator

@ekzhu ekzhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks pretty good.

Could you update the API docs with two usage examples to show different scenarios. One without model client and one with model client. Include the output for each in the doc as well.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
- Expanded the docstrings in the `CodeExecutorAgent` class to cover new features, including configuration examples with and without a model client.
- Updated class description and parameters to reflect recent additions.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
@Ethan0456
Copy link
Contributor Author

Could you update the API docs with two usage examples to show different scenarios. One without model client and one with model client. Include the output for each in the doc as well.

Done!

Commit: 9fd093e

Added API Docs for both the scenarios.

@ekzhu
Copy link
Collaborator

ekzhu commented Mar 31, 2025

I rebased this PR to the latest changes in the main branch. I also made a small change to the default setting of system_message so that it has a default and can be turned off by setting it to None. I also updated the API doc.

Copy link
Collaborator

@ekzhu ekzhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can move this PR out of Draft stage now.

@Ethan0456
Copy link
Contributor Author

Hi @ekzhu,

Apologies for the oversight. I missed updating that section of the API documentation and forgot to account for the fact that with this approach, the system_message can never be None.

@Ethan0456 Ethan0456 marked this pull request as ready for review March 31, 2025 05:25
…n result in model context

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
…D_MESSAGE constant

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
@Ethan0456 Ethan0456 force-pushed the feature/enable-code-gen-in-code-exec-agent branch from cb78371 to 2f874ef Compare April 2, 2025 14:17
@Ethan0456 Ethan0456 changed the title [DRAFT] Add code generation support to CodeExecutorAgent Add code generation support to CodeExecutorAgent Apr 2, 2025
Copy link
Collaborator

@ekzhu ekzhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have played with this setup for a number of tasks. I think there are some immediate next steps:

  1. New message types CodeGenerationEvent, CodeExecutionEvent instead of the TextMessage used for inner messages. Introduce additional fields like CodeGenerationEvent.code_blocks, CodeExecutionEvent.result. See autogen_agentchat.messges.
  2. Automatic debugging loop until code result is not an error.

let me know if you want to work on these as separate PRs or keep iterating on this one for now.

I see the tests are still broken.

ekzhu and others added 3 commits April 2, 2025 15:16
- Replaced the usage of `TextMessage` with new message types `CodeGenerationEvent` and `CodeExecutionEvent` for yielding code generation and execution results.
- Updated `execute_code_block` method to return `CodeExecutionEvent` instead of `TextMessage`.
- Adjusted message factory to register and support the new event types.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
@Ethan0456
Copy link
Contributor Author

Hi @ekzhu,

Thanks for the suggestions! I’ve pushed a new commit that introduces CodeGenerationEvent and CodeExecutionEvent. For the .code_blocks attribute, I wasn’t entirely sure of the best approach, so I implemented it as a .get_code_blocks method, but I’m open to feedback if this isn’t the most appropriate solution.

Now, the inner messages are yielded as CodeGenerationEvent and CodeExecutionEvent, but the final response is still returned as a TextMessage because the Response object requires a BaseChatMessage.

Regarding the automatic debugging loop to handle errors in code results, I find this feature really interesting and would love to work on it. I’m happy to create a separate PR for that one.

As for the broken tests, I will prioritize fixing them as soon as I have some time.

Let me know if you have any feedback on the recent commit!

def to_model_text(self) -> str:
return self.content

def to_model_message(self) -> AssistantMessage:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not include to_model_text and to_model_message in the CodeExecutionEvent and CodeGenerationEvent. As these are events for observability and termination purpose. Only BaseChatMessage are going to other agents' model context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

50dd722

Removed these two methods from both the Event types.


type: Literal["CodeGenerationEvent"] = "CodeGenerationEvent"

def get_code_blocks(self) -> List[CodeBlock]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_code_blocks and _extract_markdown_code_blocks should stay in CodeExecutionAgent.

Instead, it should include a field code_blocks: List[CodeBlock] which gets assigned by the CodeExecutionAgent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

26a1491

Removed get_code_blocks and _extract_markdown_code_blocks from CodeExecutorAgent.
And code_blocks attributes is filled from CodeExecutorAgent.

class CodeExecutionEvent(BaseAgentEvent):
type: Literal["CodeExecutionEvent"] = "CodeExecutionEvent"
result: str

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the result field should be CodeResult type:

result: CodeResult.

Copy link
Contributor Author

@Ethan0456 Ethan0456 Apr 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

8ea9f03

I have a few doubts to confirm for this commit:

  1. I am utilizing code_execution.result.output attribute to add execution result to model_context, because it was not accepting CodeExecutionEvent. Is it correct?
  2. Still yielding execution result as TextMessage.
  3. Is returning exit_code=-1 valid when there is not code blocks in generation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am utilizing code_execution.result.output attribute to add execution result to model_context, because it was not accepting CodeExecutionEvent. Is it correct?

Yes.

Still yielding execution result as TextMessage.

The final Response still contains the TextMessage. Intermediate execution result should be yielded as CodeExecutionEvent.

Is returning exit_code=-1 valid when there is not code blocks in generation.

No. If there is no code in the generation, there shouldn't be CodeGenerationEvent or CodeExecutionEvent -- it should go straight to final Response.

@ekzhu
Copy link
Collaborator

ekzhu commented Apr 4, 2025

Regarding the automatic debugging loop to handle errors in code results, I find this feature really interesting and would love to work on it. I’m happy to create a separate PR for that one.

Great, created a separate issue: #6207. You can comment on that issue.

Ethan0456 and others added 4 commits April 5, 2025 21:48
…ationEvent` and `CodeExecutionEvent`

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
- Removed `get_code_blocks` and `_extract_markdown_code_blocks` methods from `CodeGenerationEvent`.
- Added a new field `code_blocks: List[CodeBlock]` to CodeGenerationEvent.
- Updated `CodeExecutionAgent` to assign `code_blocks` directly to the `CodeGenerationEvent`.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
- Refactored `CodeExecutionEvent` to use `CodeResult` instead of a string for the `result` field.
- Updated handling of code execution results in `on_messages_stream` and `execute_code_block` to ensure proper usage of `CodeResult`.

Signed-off-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
)

# execute generated code if present
execution_result = await self.execute_code_block([inferred_text_message], cancellation_token)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's yield the CodeGenerationEvent before the code execution. This way the event is more realtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no code in the generation, we shouldn't be emitting CodeGenerationEvent, it should go straight to final response.

So we will need to sepearate code extraction from code execution.

ekzhu and others added 2 commits April 5, 2025 21:21
)

# execute generated code if present
execution_result = await self.execute_code_block([inferred_text_message], cancellation_token)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no code in the generation, we shouldn't be emitting CodeGenerationEvent, it should go straight to final response.

So we will need to sepearate code extraction from code execution.

class CodeExecutionEvent(BaseAgentEvent):
type: Literal["CodeExecutionEvent"] = "CodeExecutionEvent"
result: str

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am utilizing code_execution.result.output attribute to add execution result to model_context, because it was not accepting CodeExecutionEvent. Is it correct?

Yes.

Still yielding execution result as TextMessage.

The final Response still contains the TextMessage. Intermediate execution result should be yielded as CodeExecutionEvent.

Is returning exit_code=-1 valid when there is not code blocks in generation.

No. If there is no code in the generation, there shouldn't be CodeGenerationEvent or CodeExecutionEvent -- it should go straight to final Response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enable CodeExecutorAgent to generate its own code and executing it.
2 participants