-
Notifications
You must be signed in to change notification settings - Fork 178
feat: Add GitHub integration with agent_prompts and github_components #1637
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
4aba2a9
add agent_prompts and github_components
julian-risch 890ecde
rename to github_haystack
julian-risch b99ad72
remove github-haystack
julian-risch 97029b1
Merge branch 'main' into move-github-components
julian-risch af37ecd
renamed integration, added components dir
julian-risch ac4bf31
add tests, pydoc, update pyproject.toml
julian-risch 2e2202a
add workflow
julian-risch fcfec47
fmt
julian-risch 79dc7db
fmt
julian-risch cf3a2f5
lint
julian-risch f82412f
ruff
julian-risch fa9cbe3
fmt
julian-risch c4beece
lint:all
julian-risch 4a6b81b
replace StrEnum for py 3.9+ compatibility
julian-risch e77a49e
move files
julian-risch 4e49081
fix tests
julian-risch 7144176
lint
julian-risch b4a375d
fix pydoc and extend init files
julian-risch 2b8bc14
Add integration:github to labeler.yml
julian-risch 8480832
unify how we set GITHUB_TOKEN in tests
julian-risch ca977a1
fix 3 usage examples. 3 remaining
julian-risch b735b76
Merge branch 'main' into move-github-components
julian-risch e5111ed
remove empty lines from prompts
julian-risch dc08916
GitHub capitalization
julian-risch 380c212
add license header
julian-risch ea95934
all caps for prompts
julian-risch 22758e8
add GitHubFileEditorTool
julian-risch 0c4f0f0
enforce kwargs instead of positional args
julian-risch 31add35
use _get_request_headers and base_headers consistently
julian-risch 474674c
lint
julian-risch b30b21f
rename GitHubRepositoryViewer to GitHubRepoViewer
julian-risch 4f8d0d3
lint
julian-risch 4555d2a
add pipeline serialization test
julian-risch 8f4bf9f
extend pipeline to_dict test
julian-risch ec64b09
set default branch of repo viewer
julian-risch 9ae7857
lint
julian-risch d0480c2
add four more tools
julian-risch ba9b1ea
lint
julian-risch eb7a267
rename prompts
julian-risch d98d3ec
add tests for four more tools
julian-risch b8bb2ed
rename context prompt
julian-risch 8635fa5
add outputs_to_state as param to GitHubFileEditorTool
julian-risch 91ac951
add outputs_to_state as param to GitHubRepoViewerTool
julian-risch 560abfd
set default outputs_to_state for GitHubRepoViewerTool
julian-risch d754b01
extract serialize_handlers to utils; don't use mutable defaults
julian-risch 9860266
replace init_parameters with data for serde in FileEditor, RepoViewer
julian-risch 0c52ff4
add outputs_to_state to GitHubIssueCommenterTool; replace init_parame…
julian-risch 3160373
add outputs_to_state to GitHubIssueViewerTool; replace init_parameter…
julian-risch f088c18
add outputs_to_state to GitHubPRCreatorTool; replace init_parameters …
julian-risch a822bc1
move param docstrings to init methods
julian-risch f911175
use generate_qualified_class_name instead of hardcoded name
julian-risch 1ac5ba2
test with lowest supported version
julian-risch fc027f5
don't test http_client_kwargs for compatibility with Haystack 2.12
julian-risch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,46 @@ | ||
# SPDX-FileCopyrightText: 2023-present deepset GmbH <[email protected]> | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
from typing import Any, Dict, Optional | ||
from typing import Any, Callable, Dict, Optional, Union | ||
|
||
from haystack import default_from_dict, default_to_dict | ||
from haystack.tools import ComponentTool | ||
from haystack.utils import Secret, deserialize_secrets_inplace | ||
|
||
from haystack_integrations.components.connectors.github.issue_commenter import GitHubIssueCommenter | ||
from haystack_integrations.prompts.github.issue_commenter_prompt import ISSUE_COMMENTER_PROMPT, ISSUE_COMMENTER_SCHEMA | ||
from haystack_integrations.tools.github.utils import deserialize_handlers, serialize_handlers | ||
|
||
|
||
class GitHubIssueCommenterTool(ComponentTool): | ||
""" | ||
A tool for commenting on GitHub issues. | ||
|
||
:param name: Optional name for the tool. | ||
:param description: Optional description. | ||
:param parameters: Optional JSON schema defining the parameters expected by the Tool. | ||
:param github_token: GitHub personal access token for API authentication | ||
:param raise_on_failure: If True, raises exceptions on API errors | ||
:param retry_attempts: Number of retry attempts for failed requests | ||
:param outputs_to_string: | ||
Optional dictionary defining how a tool outputs should be converted into a string. | ||
If the source is provided only the specified output key is sent to the handler. | ||
If the source is omitted the whole tool result is sent to the handler. | ||
Example: { | ||
"source": "docs", "handler": format_documents | ||
} | ||
:param inputs_from_state: | ||
Optional dictionary mapping state keys to tool parameter names. | ||
Example: {"repository": "repo"} maps state's "repository" to tool's "repo" parameter. | ||
:param outputs_to_state: | ||
Optional dictionary defining how tool outputs map to keys within state as well as optional handlers. | ||
If the source is provided only the specified output key is sent to the handler. | ||
Example: { | ||
"documents": {"source": "docs", "handler": custom_handler} | ||
} | ||
If the source is omitted the whole tool result is sent to the handler. | ||
Example: { | ||
"documents": {"handler": custom_handler} | ||
} | ||
""" | ||
|
||
def __init__( | ||
|
@@ -25,13 +52,19 @@ def __init__( | |
github_token: Secret = Secret.from_env_var("GITHUB_TOKEN"), | ||
raise_on_failure: bool = True, | ||
retry_attempts: int = 2, | ||
outputs_to_string: Optional[Dict[str, Union[str, Callable[[Any], str]]]] = None, | ||
inputs_from_state: Optional[Dict[str, str]] = None, | ||
outputs_to_state: Optional[Dict[str, Dict[str, Union[str, Callable]]]] = None, | ||
): | ||
self.name = name | ||
self.description = description | ||
self.parameters = parameters | ||
self.github_token = github_token | ||
self.raise_on_failure = raise_on_failure | ||
self.retry_attempts = retry_attempts | ||
self.outputs_to_string = outputs_to_string | ||
self.inputs_from_state = inputs_from_state | ||
self.outputs_to_state = outputs_to_state | ||
|
||
issue_commenter = GitHubIssueCommenter( | ||
github_token=github_token, | ||
|
@@ -43,6 +76,9 @@ def __init__( | |
name=name, | ||
description=description, | ||
parameters=parameters, | ||
outputs_to_string=outputs_to_string, | ||
inputs_from_state=inputs_from_state, | ||
outputs_to_state=outputs_to_state, | ||
) | ||
|
||
def to_dict(self) -> Dict[str, Any]: | ||
|
@@ -52,15 +88,23 @@ def to_dict(self) -> Dict[str, Any]: | |
:returns: | ||
Dictionary with serialized data. | ||
""" | ||
return default_to_dict( | ||
self, | ||
name=self.name, | ||
description=self.description, | ||
parameters=self.parameters, | ||
github_token=self.github_token.to_dict() if self.github_token else None, | ||
raise_on_failure=self.raise_on_failure, | ||
retry_attempts=self.retry_attempts, | ||
) | ||
serialized = { | ||
"name": self.name, | ||
"description": self.description, | ||
"parameters": self.parameters, | ||
"github_token": self.github_token.to_dict() if self.github_token else None, | ||
"raise_on_failure": self.raise_on_failure, | ||
"retry_attempts": self.retry_attempts, | ||
"outputs_to_string": self.outputs_to_string, | ||
"inputs_from_state": self.inputs_from_state, | ||
"outputs_to_state": self.outputs_to_state, | ||
} | ||
|
||
serialize_handlers(serialized, self.outputs_to_state, self.outputs_to_string) | ||
return { | ||
"type": "haystack_integrations.tools.github.issue_commenter_tool.GitHubIssueCommenterTool", | ||
julian-risch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"data": serialized, | ||
} | ||
|
||
@classmethod | ||
def from_dict(cls, data: Dict[str, Any]) -> "GitHubIssueCommenterTool": | ||
|
@@ -72,5 +116,7 @@ def from_dict(cls, data: Dict[str, Any]) -> "GitHubIssueCommenterTool": | |
:returns: | ||
Deserialized tool. | ||
""" | ||
deserialize_secrets_inplace(data["init_parameters"], keys=["github_token"]) | ||
return default_from_dict(cls, data) | ||
inner_data = data["data"] | ||
deserialize_secrets_inplace(inner_data, keys=["github_token"]) | ||
deserialize_handlers(inner_data) | ||
return cls(**inner_data) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do realize this is a bit confusing in our tools, but it seems that if we define a
__init__
then these docstrings are put under the__init__
def. If there is no__init__
defined like inTool
then we put it in the class description.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, of course! Do you think we should a usage example here then (in addition to moving the param docstrings to the init)? I realized that's missing too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah if it's not too much to ask, a usage example would be great!