mirror of
https://github.com/Significant-Gravitas/Auto-GPT.git
synced 2025-01-08 11:57:32 +08:00
feat(docs): OAuth docs updates based on google block changes (#8243)
* feat(frontend,backend): testing
* feat: testing
* feat(backend): it works for reading email
* feat(backend): more docs on google
* fix(frontend,backend): formatting
* feat(backend): more logigin (i know this should be debug)
* feat(backend): make real the default scopes
* feat(backend): tests and linting
* fix: code review prep
* feat: sheets block
* feat: liniting
* Update route.ts
* Update autogpt_platform/backend/backend/integrations/oauth/google.py
Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
* Update autogpt_platform/backend/backend/server/routers/integrations.py
Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
* fix: revert opener change
* feat(frontend): add back opener
required to work on mac edge
* feat(frontend): drop typing list import from gmail
* fix: code review comments
* feat: code review changes
* feat: code review changes
* fix(backend): move from asserts to checks so they don't get optimized away in the future
* fix(backend): code review changes
* fix(backend): remove google specific check
* fix: add typing
* fix: only enable google blocks when oauth is configured for google
* fix: errors are real and valid outputs always when output
* fix(backend): add provider detail for debuging scope declines
* Update autogpt_platform/frontend/src/components/integrations/credentials-input.tsx
Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
* fix(frontend): enhance with comment, typeof error isn't known so this is best way to ensure the stringifyication will work
* feat: code review change requests
* fix: linting
* fix: reduce error catching
* fix: doc messages in code
* fix: check the correct scopes object 😄
* fix: remove double (and not needed) try catch
* fix: lint
* fix: scopes
* feat: handle the default scopes better
* feat: better email objectification
* feat: process attachements
turns out an email doesn't need a body
* fix: lint
* Update google.py
* Update autogpt_platform/backend/backend/data/block.py
Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
* fix: quit trying and except failure
* Update autogpt_platform/backend/backend/server/routers/integrations.py
Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
* feat: don't allow expired states
* fix: clarify function name and purpose
* feat: code links updates
* feat: additional docs on adding a block
* fix: type hint missing which means the block won't work
* fix: linting
* fix: docs formatting
* Update issues.py
* fix: improve the naming
* fix: formatting
* Update new_blocks.md
* Update new_blocks.md
* feat: better docs on what the args mean
* feat: more details on yield
* Update new_blocks.md
* fix: remove ignore from docs build
---------
Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
Co-authored-by: Zamil Majdy <zamil.majdy@agpt.co>
This commit is contained in:
parent
2a74381ae8
commit
04473cad1e
@ -13,6 +13,7 @@ from ._auth import (
|
||||
)
|
||||
|
||||
|
||||
# --8<-- [start:GithubCommentBlockExample]
|
||||
class GithubCommentBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
credentials: GithubCredentialsInput = GithubCredentialsField("repo")
|
||||
@ -104,6 +105,9 @@ class GithubCommentBlock(Block):
|
||||
yield "error", f"Failed to post comment: {str(e)}"
|
||||
|
||||
|
||||
# --8<-- [end:GithubCommentBlockExample]
|
||||
|
||||
|
||||
class GithubMakeIssueBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
credentials: GithubCredentialsInput = GithubCredentialsField("repo")
|
||||
|
@ -6,11 +6,12 @@ from pydantic import SecretStr
|
||||
from backend.data.model import CredentialsField, CredentialsMetaInput
|
||||
from backend.util.settings import Secrets
|
||||
|
||||
# --8<-- [start:GoogleOAuthIsConfigured]
|
||||
secrets = Secrets()
|
||||
GOOGLE_OAUTH_IS_CONFIGURED = bool(
|
||||
secrets.google_client_id and secrets.google_client_secret
|
||||
)
|
||||
|
||||
# --8<-- [end:GoogleOAuthIsConfigured]
|
||||
GoogleCredentials = OAuth2Credentials
|
||||
GoogleCredentialsInput = CredentialsMetaInput[Literal["google"], Literal["oauth2"]]
|
||||
|
||||
|
@ -3,6 +3,7 @@ from .github import GitHubOAuthHandler
|
||||
from .google import GoogleOAuthHandler
|
||||
from .notion import NotionOAuthHandler
|
||||
|
||||
# --8<-- [start:HANDLERS_BY_NAMEExample]
|
||||
HANDLERS_BY_NAME: dict[str, type[BaseOAuthHandler]] = {
|
||||
handler.PROVIDER_NAME: handler
|
||||
for handler in [
|
||||
@ -11,5 +12,6 @@ HANDLERS_BY_NAME: dict[str, type[BaseOAuthHandler]] = {
|
||||
NotionOAuthHandler,
|
||||
]
|
||||
}
|
||||
# --8<-- [end:HANDLERS_BY_NAMEExample]
|
||||
|
||||
__all__ = ["HANDLERS_BY_NAME"]
|
||||
|
@ -9,26 +9,37 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseOAuthHandler(ABC):
|
||||
# --8<-- [start:BaseOAuthHandler1]
|
||||
PROVIDER_NAME: ClassVar[str]
|
||||
DEFAULT_SCOPES: ClassVar[list[str]] = []
|
||||
# --8<-- [end:BaseOAuthHandler1]
|
||||
|
||||
@abstractmethod
|
||||
# --8<-- [start:BaseOAuthHandler2]
|
||||
def __init__(self, client_id: str, client_secret: str, redirect_uri: str): ...
|
||||
|
||||
# --8<-- [end:BaseOAuthHandler2]
|
||||
|
||||
@abstractmethod
|
||||
# --8<-- [start:BaseOAuthHandler3]
|
||||
def get_login_url(self, scopes: list[str], state: str) -> str:
|
||||
# --8<-- [end:BaseOAuthHandler3]
|
||||
"""Constructs a login URL that the user can be redirected to"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
# --8<-- [start:BaseOAuthHandler4]
|
||||
def exchange_code_for_tokens(
|
||||
self, code: str, scopes: list[str]
|
||||
) -> OAuth2Credentials:
|
||||
# --8<-- [end:BaseOAuthHandler4]
|
||||
"""Exchanges the acquired authorization code from login for a set of tokens"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
# --8<-- [start:BaseOAuthHandler5]
|
||||
def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
|
||||
# --8<-- [end:BaseOAuthHandler5]
|
||||
"""Implements the token refresh mechanism"""
|
||||
...
|
||||
|
||||
|
@ -8,6 +8,7 @@ from autogpt_libs.supabase_integration_credentials_store import OAuth2Credential
|
||||
from .base import BaseOAuthHandler
|
||||
|
||||
|
||||
# --8<-- [start:GithubOAuthHandlerExample]
|
||||
class GitHubOAuthHandler(BaseOAuthHandler):
|
||||
"""
|
||||
Based on the documentation at:
|
||||
@ -119,3 +120,6 @@ class GitHubOAuthHandler(BaseOAuthHandler):
|
||||
|
||||
# Get the login (username)
|
||||
return response.json().get("login")
|
||||
|
||||
|
||||
# --8<-- [end:GithubOAuthHandlerExample]
|
||||
|
@ -14,6 +14,7 @@ from .base import BaseOAuthHandler
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# --8<-- [start:GoogleOAuthHandlerExample]
|
||||
class GoogleOAuthHandler(BaseOAuthHandler):
|
||||
"""
|
||||
Based on the documentation at https://developers.google.com/identity/protocols/oauth2/web-server
|
||||
@ -26,6 +27,7 @@ class GoogleOAuthHandler(BaseOAuthHandler):
|
||||
"https://www.googleapis.com/auth/userinfo.profile",
|
||||
"openid",
|
||||
]
|
||||
# --8<-- [end:GoogleOAuthHandlerExample]
|
||||
|
||||
def __init__(self, client_id: str, client_secret: str, redirect_uri: str):
|
||||
self.client_id = client_id
|
||||
|
@ -189,10 +189,12 @@ class Secrets(UpdateTrackingModel["Secrets"], BaseSettings):
|
||||
)
|
||||
|
||||
# OAuth server credentials for integrations
|
||||
# --8<-- [start:OAuthServerCredentialsExample]
|
||||
github_client_id: str = Field(default="", description="GitHub OAuth client ID")
|
||||
github_client_secret: str = Field(
|
||||
default="", description="GitHub OAuth client secret"
|
||||
)
|
||||
# --8<-- [end:OAuthServerCredentialsExample]
|
||||
google_client_id: str = Field(default="", description="Google OAuth client ID")
|
||||
google_client_secret: str = Field(
|
||||
default="", description="Google OAuth client secret"
|
||||
|
@ -44,11 +44,13 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
// --8<-- [start:ProviderIconsEmbed]
|
||||
const providerIcons: Record<string, React.FC<{ className?: string }>> = {
|
||||
github: FaGithub,
|
||||
google: FaGoogle,
|
||||
notion: NotionLogoIcon,
|
||||
};
|
||||
// --8<-- [end:ProviderIconsEmbed]
|
||||
|
||||
export type OAuthPopupResultMessage = { message_type: "oauth_popup_result" } & (
|
||||
| {
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
// --8<-- [start:CredentialsProviderNames]
|
||||
const CREDENTIALS_PROVIDER_NAMES = ["github", "google", "notion"] as const;
|
||||
|
||||
type CredentialsProviderName = (typeof CREDENTIALS_PROVIDER_NAMES)[number];
|
||||
@ -19,6 +20,7 @@ const providerDisplayNames: Record<CredentialsProviderName, string> = {
|
||||
google: "Google",
|
||||
notion: "Notion",
|
||||
};
|
||||
// --8<-- [end:CredentialsProviderNames]
|
||||
|
||||
type APIKeyCredentialsCreatable = Omit<
|
||||
APIKeyCredentials,
|
||||
|
@ -94,11 +94,13 @@ export type BlockIOBooleanSubSchema = BlockIOSubSchemaMeta & {
|
||||
|
||||
export type CredentialsType = "api_key" | "oauth2";
|
||||
|
||||
// --8<-- [start:BlockIOCredentialsSubSchema]
|
||||
export type BlockIOCredentialsSubSchema = BlockIOSubSchemaMeta & {
|
||||
credentials_provider: "github" | "google" | "notion";
|
||||
credentials_scopes?: string[];
|
||||
credentials_types: Array<CredentialsType>;
|
||||
};
|
||||
// --8<-- [end:BlockIOCredentialsSubSchema]
|
||||
|
||||
export type BlockIONullSubSchema = BlockIOSubSchemaMeta & {
|
||||
type: "null";
|
||||
|
@ -105,7 +105,7 @@ Follow these steps to create and test a new block:
|
||||
- **Try block**: Contains the main logic to fetch and process the Wikipedia summary.
|
||||
- **API request**: Send a GET request to the Wikipedia API.
|
||||
- **Error handling**: Handle various exceptions that might occur during the API request and data processing.
|
||||
- **Yield**: Use `yield` to output the results.
|
||||
- **Yield**: Use `yield` to output the results. Prefer to output one result object at a time. If you are calling a function that returns a list, you can yield each item in the list separately. You can also yield the whole list as well, but do both rather than yielding the list. For example: If you were writing a block that outputs emails, you'd yield each email as a separate result object, but you could also yield the whole list as an additional single result object.
|
||||
|
||||
### Blocks with authentication
|
||||
|
||||
@ -115,6 +115,7 @@ for a service that we already have OAuth2 support for.
|
||||
|
||||
Implementing the block itself is relatively simple. On top of the instructions above,
|
||||
you're going to add a `credentials` parameter to the `Input` model and the `run` method:
|
||||
|
||||
```python
|
||||
from autogpt_libs.supabase_integration_credentials_store.types import (
|
||||
APIKeyCredentials,
|
||||
@ -129,10 +130,11 @@ from backend.data.model import CredentialsField
|
||||
# API Key auth:
|
||||
class BlockWithAPIKeyAuth(Block):
|
||||
class Input(BlockSchema):
|
||||
credentials = CredentialsField(
|
||||
# Note that the type hint below is require or you will get a type error.
|
||||
# The first argument is the provider name, the second is the credential type.
|
||||
credentials: CredentialsMetaInput[Literal['github'], Literal['api_key']] = CredentialsField(
|
||||
provider="github",
|
||||
supported_credential_types={"api_key"},
|
||||
required_scopes={"repo"},
|
||||
description="The GitHub integration can be used with "
|
||||
"any API key with sufficient permissions for the blocks it is used on.",
|
||||
)
|
||||
@ -151,7 +153,9 @@ class BlockWithAPIKeyAuth(Block):
|
||||
# OAuth:
|
||||
class BlockWithOAuth(Block):
|
||||
class Input(BlockSchema):
|
||||
credentials = CredentialsField(
|
||||
# Note that the type hint below is require or you will get a type error.
|
||||
# The first argument is the provider name, the second is the credential type.
|
||||
credentials: CredentialsMetaInput[Literal['github'], Literal['oauth2']] = CredentialsField(
|
||||
provider="github",
|
||||
supported_credential_types={"oauth2"},
|
||||
required_scopes={"repo"},
|
||||
@ -172,7 +176,9 @@ class BlockWithOAuth(Block):
|
||||
# API Key auth + OAuth:
|
||||
class BlockWithAPIKeyAndOAuth(Block):
|
||||
class Input(BlockSchema):
|
||||
credentials = CredentialsField(
|
||||
# Note that the type hint below is require or you will get a type error.
|
||||
# The first argument is the provider name, the second is the credential type.
|
||||
credentials: CredentialsMetaInput[Literal['github'], Literal['api_key', 'oauth2']] = CredentialsField(
|
||||
provider="github",
|
||||
supported_credential_types={"api_key", "oauth2"},
|
||||
required_scopes={"repo"},
|
||||
@ -191,10 +197,12 @@ class BlockWithAPIKeyAndOAuth(Block):
|
||||
) -> BlockOutput:
|
||||
...
|
||||
```
|
||||
|
||||
The credentials will be automagically injected by the executor in the back end.
|
||||
|
||||
The `APIKeyCredentials` and `OAuth2Credentials` models are defined [here](https://github.com/Significant-Gravitas/AutoGPT/blob/master/rnd/autogpt_libs/autogpt_libs/supabase_integration_credentials_store/types.py).
|
||||
To use them in e.g. an API request, you can either access the token directly:
|
||||
|
||||
```python
|
||||
# credentials: APIKeyCredentials
|
||||
response = requests.post(
|
||||
@ -212,7 +220,9 @@ response = requests.post(
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
or use the shortcut `credentials.bearer()`:
|
||||
|
||||
```python
|
||||
# credentials: APIKeyCredentials | OAuth2Credentials
|
||||
response = requests.post(
|
||||
@ -227,25 +237,84 @@ To add support for a new OAuth2-authenticated service, you'll need to add an `OA
|
||||
All our existing handlers and the base class can be found [here][OAuth2 handlers].
|
||||
|
||||
Every handler must implement the following parts of the [`BaseOAuthHandler`] interface:
|
||||
- `PROVIDER_NAME`
|
||||
- `__init__(client_id, client_secret, redirect_uri)`
|
||||
- `get_login_url(scopes, state)`
|
||||
- `exchange_code_for_tokens(code)`
|
||||
- `_refresh_tokens(credentials)`
|
||||
|
||||
```python title="autogpt_platform/backend/backend/integrations/oauth/base.py"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/base.py:BaseOAuthHandler1"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/base.py:BaseOAuthHandler2"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/base.py:BaseOAuthHandler3"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/base.py:BaseOAuthHandler4"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/base.py:BaseOAuthHandler5"
|
||||
```
|
||||
|
||||
As you can see, this is modeled after the standard OAuth2 flow.
|
||||
|
||||
Aside from implementing the `OAuthHandler` itself, adding a handler into the system requires two more things:
|
||||
- Adding the handler class to `HANDLERS_BY_NAME` [here](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/backend/backend/integrations/oauth/__init__.py)
|
||||
- Adding `{provider}_client_id` and `{provider}_client_secret` to the application's `Secrets` [here](https://github.com/Significant-Gravitas/AutoGPT/blob/e3f35d79c7e9fc6ee0cabefcb73e0fad15a0ce2d/autogpt_platform/backend/backend/util/settings.py#L132)
|
||||
|
||||
- Adding the handler class to `HANDLERS_BY_NAME` under [`integrations/oauth/__init__.py`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/backend/backend/integrations/oauth/__init__.py)
|
||||
|
||||
```python title="autogpt_platform/backend/backend/integrations/oauth/__init__.py"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/__init__.py:HANDLERS_BY_NAMEExample"
|
||||
```
|
||||
|
||||
- Adding `{provider}_client_id` and `{provider}_client_secret` to the application's `Secrets` under [`util/settings.py`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/backend/backend/util/settings.py)
|
||||
|
||||
```python title="autogpt_platform/backend/backend/util/settings.py"
|
||||
--8<-- "autogpt_platform/backend/backend/util/settings.py:OAuthServerCredentialsExample"
|
||||
```
|
||||
|
||||
[OAuth2 handlers]: https://github.com/Significant-Gravitas/AutoGPT/tree/master/autogpt_platform/backend/backend/integrations/oauth
|
||||
[`BaseOAuthHandler`]: https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/backend/backend/integrations/oauth/base.py
|
||||
|
||||
#### Adding to the frontend
|
||||
|
||||
You will need to add the provider (api or oauth) to the `CredentialsInput` component in [`frontend/src/components/integrations/credentials-input.tsx`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/frontend/src/components/integrations/credentials-input.tsx).
|
||||
|
||||
```ts title="frontend/src/components/integrations/credentials-input.tsx"
|
||||
--8<-- "autogpt_platform/frontend/src/components/integrations/credentials-input.tsx:ProviderIconsEmbed"
|
||||
```
|
||||
|
||||
You will also need to add the provider to the `CredentialsProvider` component in [`frontend/src/components/integrations/credentials-provider.tsx`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx).
|
||||
|
||||
```ts title="frontend/src/components/integrations/credentials-provider.tsx"
|
||||
--8<-- "autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx:CredentialsProviderNames"
|
||||
```
|
||||
|
||||
Finally you will need to add the provider to the `CredentialsType` enum in [`frontend/src/lib/autogpt-server-api/types.ts`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts).
|
||||
|
||||
```ts title="frontend/src/lib/autogpt-server-api/types.ts"
|
||||
--8<-- "autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts:BlockIOCredentialsSubSchema"
|
||||
```
|
||||
|
||||
#### Example: GitHub integration
|
||||
|
||||
- GitHub blocks with API key + OAuth2 support: [`blocks/github`](https://github.com/Significant-Gravitas/AutoGPT/tree/master/autogpt_platform/backend/backend/blocks/github/)
|
||||
|
||||
```python title="blocks/github/issues.py"
|
||||
--8<-- "autogpt_platform/backend/backend/blocks/github/issues.py:GithubCommentBlockExample"
|
||||
```
|
||||
|
||||
- GitHub OAuth2 handler: [`integrations/oauth/github.py`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/backend/backend/integrations/oauth/github.py)
|
||||
|
||||
```python title="blocks/github/github.py"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/github.py:GithubOAuthHandlerExample"
|
||||
```
|
||||
|
||||
#### Example: Google integration
|
||||
|
||||
- Google OAuth2 handler: [`integrations/oauth/google.py`](https://github.com/Significant-Gravitas/AutoGPT/blob/master/autogpt_platform/backend/backend/integrations/oauth/google.py)
|
||||
|
||||
```python title="integrations/oauth/google.py"
|
||||
--8<-- "autogpt_platform/backend/backend/integrations/oauth/google.py:GoogleOAuthHandlerExample"
|
||||
```
|
||||
|
||||
You can see that google has defined a `DEFAULT_SCOPES` variable, this is used to set the scopes that are requested no matter what the user asks for.
|
||||
|
||||
```python title="blocks/google/_auth.py"
|
||||
--8<-- "autogpt_platform/backend/backend/blocks/google/_auth.py:GoogleOAuthIsConfigured"
|
||||
```
|
||||
|
||||
You can also see that `GOOGLE_OAUTH_IS_CONFIGURED` is used to disable the blocks that require OAuth if the oauth is not configured. This is in the `__init__` method of each block. This is because there is no api key fallback for google blocks so we need to make sure that the oauth is configured before we allow the user to use the blocks.
|
||||
|
||||
## Key Points to Remember
|
||||
|
||||
- **Unique ID**: Give your block a unique ID in the **init** method.
|
||||
@ -276,6 +345,7 @@ This approach allows us to test the block's logic comprehensively without relyin
|
||||
1. **Provide realistic test_input**: Ensure your test input covers typical use cases.
|
||||
|
||||
2. **Define appropriate test_output**:
|
||||
|
||||
- For deterministic outputs, use specific expected values.
|
||||
- For non-deterministic outputs or when only the type matters, use Python types (e.g., `str`, `int`, `dict`).
|
||||
- You can mix specific values and types, e.g., `("key1", str), ("key2", 42)`.
|
||||
@ -292,14 +362,14 @@ By following these steps, you can create new blocks that extend the functionalit
|
||||
|
||||
## Blocks we want to see
|
||||
|
||||
Below is a list of blocks that we would like to see implemented in the AutoGPT Agent Server. If you're interested in contributing, feel free to pick one of these blocks or suggest your own by editing [docs/content/server/new_blocks.md](https://github.com/Significant-Gravitas/AutoGPT/edit/master/docs/content/server/new_blocks.md) and opening a pull request.
|
||||
Below is a list of blocks that we would like to see implemented in the AutoGPT Agent Server. If you're interested in contributing, feel free to pick one of these blocks or chose your own.
|
||||
|
||||
If you would like to implement one of these blocks, open a pull request and we will start the review process.
|
||||
|
||||
### Consumer Services/Platforms
|
||||
|
||||
- Google sheets - Read/Append [Read in Progress](https://github.com/Significant-Gravitas/AutoGPT/pull/7521)
|
||||
- Email - Read/Send with Gmail, Outlook, Yahoo, Proton, etc
|
||||
- Google sheets - [~~Read/Append~~](https://github.com/Significant-Gravitas/AutoGPT/pull/8236)
|
||||
- Email - Read/Send with [~~Gmail~~](https://github.com/Significant-Gravitas/AutoGPT/pull/8236), Outlook, Yahoo, Proton, etc
|
||||
- Calendar - Read/Write with Google Calendar, Outlook Calendar, etc
|
||||
- Home Assistant - Call Service, Get Status
|
||||
- Dominos - Order Pizza, Track Order
|
||||
@ -346,7 +416,6 @@ If you would like to implement one of these blocks, open a pull request and we w
|
||||
|
||||
## Agent Templates we want to see
|
||||
|
||||
|
||||
### Data/Information
|
||||
|
||||
- Summarize top news of today, of this week, this month via Apple News or other large media outlets BBC, TechCrunch, hackernews, etc
|
||||
|
@ -136,8 +136,9 @@ markdown_extensions:
|
||||
- pymdownx.mark
|
||||
- pymdownx.smartsymbols
|
||||
- pymdownx.snippets:
|
||||
auto_append:
|
||||
- includes/abbreviations.md
|
||||
base_path: ['.','../']
|
||||
check_paths: true
|
||||
dedent_subsections: true
|
||||
- pymdownx.superfences:
|
||||
custom_fences:
|
||||
- name: mermaid
|
||||
|
@ -3,4 +3,3 @@
|
||||
[build]
|
||||
publish = "public/"
|
||||
command = "mkdocs build -d public"
|
||||
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../CONTRIBUTING.md ../CODE_OF_CONDUCT.md"
|
||||
|
Loading…
Reference in New Issue
Block a user