airbyte-agent-asana 0.19.27__py3-none-any.whl → 0.19.41__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of airbyte-agent-asana might be problematic. Click here for more details.
- airbyte_agent_asana/__init__.py +6 -6
- airbyte_agent_asana/_vendored/connector_sdk/auth_strategies.py +2 -5
- airbyte_agent_asana/_vendored/connector_sdk/auth_template.py +1 -1
- airbyte_agent_asana/_vendored/connector_sdk/cloud_utils/client.py +26 -26
- airbyte_agent_asana/_vendored/connector_sdk/connector_model_loader.py +11 -4
- airbyte_agent_asana/_vendored/connector_sdk/constants.py +1 -1
- airbyte_agent_asana/_vendored/connector_sdk/executor/hosted_executor.py +10 -11
- airbyte_agent_asana/_vendored/connector_sdk/executor/local_executor.py +94 -25
- airbyte_agent_asana/_vendored/connector_sdk/extensions.py +43 -5
- airbyte_agent_asana/_vendored/connector_sdk/http/response.py +2 -0
- airbyte_agent_asana/_vendored/connector_sdk/introspection.py +262 -0
- airbyte_agent_asana/_vendored/connector_sdk/logging/logger.py +9 -9
- airbyte_agent_asana/_vendored/connector_sdk/logging/types.py +10 -10
- airbyte_agent_asana/_vendored/connector_sdk/observability/config.py +179 -0
- airbyte_agent_asana/_vendored/connector_sdk/observability/models.py +6 -6
- airbyte_agent_asana/_vendored/connector_sdk/observability/session.py +41 -32
- airbyte_agent_asana/_vendored/connector_sdk/performance/metrics.py +3 -3
- airbyte_agent_asana/_vendored/connector_sdk/schema/base.py +17 -17
- airbyte_agent_asana/_vendored/connector_sdk/schema/components.py +59 -58
- airbyte_agent_asana/_vendored/connector_sdk/schema/extensions.py +9 -9
- airbyte_agent_asana/_vendored/connector_sdk/schema/operations.py +32 -32
- airbyte_agent_asana/_vendored/connector_sdk/schema/security.py +44 -34
- airbyte_agent_asana/_vendored/connector_sdk/secrets.py +2 -2
- airbyte_agent_asana/_vendored/connector_sdk/telemetry/events.py +9 -8
- airbyte_agent_asana/_vendored/connector_sdk/telemetry/tracker.py +9 -5
- airbyte_agent_asana/_vendored/connector_sdk/types.py +7 -3
- airbyte_agent_asana/connector.py +88 -3
- airbyte_agent_asana/connector_model.py +6 -0
- airbyte_agent_asana/models.py +29 -29
- airbyte_agent_asana/types.py +1 -1
- {airbyte_agent_asana-0.19.27.dist-info → airbyte_agent_asana-0.19.41.dist-info}/METADATA +11 -11
- {airbyte_agent_asana-0.19.27.dist-info → airbyte_agent_asana-0.19.41.dist-info}/RECORD +33 -31
- {airbyte_agent_asana-0.19.27.dist-info → airbyte_agent_asana-0.19.41.dist-info}/WHEEL +0 -0
|
@@ -6,7 +6,7 @@ References:
|
|
|
6
6
|
- https://spec.openapis.org/oas/v3.1.0#oauth-flows-object
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from typing import Any, Dict, List, Literal
|
|
9
|
+
from typing import Any, Dict, List, Literal
|
|
10
10
|
|
|
11
11
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
12
12
|
|
|
@@ -20,9 +20,9 @@ class OAuth2Flow(BaseModel):
|
|
|
20
20
|
|
|
21
21
|
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
22
22
|
|
|
23
|
-
authorization_url:
|
|
24
|
-
token_url:
|
|
25
|
-
refresh_url:
|
|
23
|
+
authorization_url: str | None = Field(None, alias="authorizationUrl")
|
|
24
|
+
token_url: str | None = Field(None, alias="tokenUrl")
|
|
25
|
+
refresh_url: str | None = Field(None, alias="refreshUrl")
|
|
26
26
|
scopes: Dict[str, str] = Field(default_factory=dict)
|
|
27
27
|
|
|
28
28
|
|
|
@@ -35,10 +35,10 @@ class OAuth2Flows(BaseModel):
|
|
|
35
35
|
|
|
36
36
|
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
37
37
|
|
|
38
|
-
implicit:
|
|
39
|
-
password:
|
|
40
|
-
client_credentials:
|
|
41
|
-
authorization_code:
|
|
38
|
+
implicit: OAuth2Flow | None = None
|
|
39
|
+
password: OAuth2Flow | None = None
|
|
40
|
+
client_credentials: OAuth2Flow | None = Field(None, alias="clientCredentials")
|
|
41
|
+
authorization_code: OAuth2Flow | None = Field(None, alias="authorizationCode")
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
class AuthConfigFieldSpec(BaseModel):
|
|
@@ -51,12 +51,12 @@ class AuthConfigFieldSpec(BaseModel):
|
|
|
51
51
|
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
52
52
|
|
|
53
53
|
type: Literal["string", "integer", "boolean", "number"] = "string"
|
|
54
|
-
title:
|
|
55
|
-
description:
|
|
56
|
-
format:
|
|
57
|
-
pattern:
|
|
54
|
+
title: str | None = None
|
|
55
|
+
description: str | None = None
|
|
56
|
+
format: str | None = None # e.g., "email", "uri"
|
|
57
|
+
pattern: str | None = None # Regex validation
|
|
58
58
|
airbyte_secret: bool = Field(False, alias="airbyte_secret")
|
|
59
|
-
default:
|
|
59
|
+
default: Any | None = None
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
class AuthConfigOption(BaseModel):
|
|
@@ -68,8 +68,8 @@ class AuthConfigOption(BaseModel):
|
|
|
68
68
|
|
|
69
69
|
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
70
70
|
|
|
71
|
-
title:
|
|
72
|
-
description:
|
|
71
|
+
title: str | None = None
|
|
72
|
+
description: str | None = None
|
|
73
73
|
type: Literal["object"] = "object"
|
|
74
74
|
required: List[str] = Field(default_factory=list)
|
|
75
75
|
properties: Dict[str, AuthConfigFieldSpec] = Field(default_factory=dict)
|
|
@@ -77,6 +77,10 @@ class AuthConfigOption(BaseModel):
|
|
|
77
77
|
default_factory=dict,
|
|
78
78
|
description="Mapping from auth parameters (e.g., 'username', 'password', 'token') to template strings using ${field} syntax",
|
|
79
79
|
)
|
|
80
|
+
replication_auth_key_mapping: Dict[str, str] | None = Field(
|
|
81
|
+
None,
|
|
82
|
+
description="Mapping from source config paths (e.g., 'credentials.api_key') to auth config keys for direct connectors",
|
|
83
|
+
)
|
|
80
84
|
|
|
81
85
|
|
|
82
86
|
class AirbyteAuthConfig(BaseModel):
|
|
@@ -92,15 +96,21 @@ class AirbyteAuthConfig(BaseModel):
|
|
|
92
96
|
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
93
97
|
|
|
94
98
|
# Single option fields
|
|
95
|
-
title:
|
|
96
|
-
description:
|
|
97
|
-
type:
|
|
98
|
-
required:
|
|
99
|
-
properties:
|
|
100
|
-
auth_mapping:
|
|
99
|
+
title: str | None = None
|
|
100
|
+
description: str | None = None
|
|
101
|
+
type: Literal["object"] | None = None
|
|
102
|
+
required: List[str] | None = None
|
|
103
|
+
properties: Dict[str, AuthConfigFieldSpec] | None = None
|
|
104
|
+
auth_mapping: Dict[str, str] | None = None
|
|
105
|
+
|
|
106
|
+
# Replication connector auth mapping
|
|
107
|
+
replication_auth_key_mapping: Dict[str, str] | None = Field(
|
|
108
|
+
None,
|
|
109
|
+
description="Mapping from source config paths (e.g., 'credentials.api_key') to auth config keys for direct connectors",
|
|
110
|
+
)
|
|
101
111
|
|
|
102
112
|
# Multiple options (oneOf)
|
|
103
|
-
one_of:
|
|
113
|
+
one_of: List[AuthConfigOption] | None = Field(None, alias="oneOf")
|
|
104
114
|
|
|
105
115
|
@model_validator(mode="after")
|
|
106
116
|
def validate_config_structure(self) -> "AirbyteAuthConfig":
|
|
@@ -151,27 +161,27 @@ class SecurityScheme(BaseModel):
|
|
|
151
161
|
|
|
152
162
|
# Standard OpenAPI fields
|
|
153
163
|
type: Literal["apiKey", "http", "oauth2", "openIdConnect"]
|
|
154
|
-
description:
|
|
164
|
+
description: str | None = None
|
|
155
165
|
|
|
156
166
|
# apiKey specific
|
|
157
|
-
name:
|
|
158
|
-
in_:
|
|
167
|
+
name: str | None = None
|
|
168
|
+
in_: Literal["query", "header", "cookie"] | None = Field(None, alias="in")
|
|
159
169
|
|
|
160
170
|
# http specific
|
|
161
|
-
scheme:
|
|
162
|
-
bearer_format:
|
|
171
|
+
scheme: str | None = None # e.g., "basic", "bearer", "digest"
|
|
172
|
+
bearer_format: str | None = Field(None, alias="bearerFormat")
|
|
163
173
|
|
|
164
174
|
# oauth2 specific
|
|
165
|
-
flows:
|
|
175
|
+
flows: OAuth2Flows | None = None
|
|
166
176
|
|
|
167
177
|
# openIdConnect specific
|
|
168
|
-
open_id_connect_url:
|
|
178
|
+
open_id_connect_url: str | None = Field(None, alias="openIdConnectUrl")
|
|
169
179
|
|
|
170
180
|
# Airbyte extensions
|
|
171
|
-
x_token_path:
|
|
172
|
-
x_token_refresh:
|
|
173
|
-
x_airbyte_auth_config:
|
|
174
|
-
x_airbyte_token_extract:
|
|
181
|
+
x_token_path: str | None = Field(None, alias="x-airbyte-token-path")
|
|
182
|
+
x_token_refresh: Dict[str, Any] | None = Field(None, alias="x-airbyte-token-refresh")
|
|
183
|
+
x_airbyte_auth_config: AirbyteAuthConfig | None = Field(None, alias="x-airbyte-auth-config")
|
|
184
|
+
x_airbyte_token_extract: List[str] | None = Field(
|
|
175
185
|
None,
|
|
176
186
|
alias="x-airbyte-token-extract",
|
|
177
187
|
description="List of fields to extract from OAuth2 token responses and use as server variables",
|
|
@@ -179,7 +189,7 @@ class SecurityScheme(BaseModel):
|
|
|
179
189
|
|
|
180
190
|
@field_validator("x_airbyte_token_extract", mode="after")
|
|
181
191
|
@classmethod
|
|
182
|
-
def validate_token_extract(cls, v:
|
|
192
|
+
def validate_token_extract(cls, v: List[str] | None) -> List[str] | None:
|
|
183
193
|
"""Validate x-airbyte-token-extract has no duplicates."""
|
|
184
194
|
if v is not None:
|
|
185
195
|
if len(v) != len(set(v)):
|
|
@@ -14,7 +14,7 @@ Example:
|
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
16
|
import re
|
|
17
|
-
from typing import Any, Dict
|
|
17
|
+
from typing import Any, Dict
|
|
18
18
|
|
|
19
19
|
from pydantic import SecretStr
|
|
20
20
|
|
|
@@ -72,7 +72,7 @@ class SecretResolutionError(Exception):
|
|
|
72
72
|
def resolve_env_var_references(
|
|
73
73
|
secret_mappings: Dict[str, Any],
|
|
74
74
|
strict: bool = True,
|
|
75
|
-
env_vars:
|
|
75
|
+
env_vars: Dict[str, str] | None = None,
|
|
76
76
|
) -> Dict[str, str]:
|
|
77
77
|
"""Resolve environment variable references in secret values.
|
|
78
78
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Telemetry event models."""
|
|
2
2
|
|
|
3
|
-
from dataclasses import asdict, dataclass
|
|
3
|
+
from dataclasses import asdict, dataclass, field
|
|
4
4
|
from datetime import datetime
|
|
5
|
-
from typing import Any, Dict
|
|
5
|
+
from typing import Any, Dict
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@dataclass
|
|
@@ -13,6 +13,7 @@ class BaseEvent:
|
|
|
13
13
|
session_id: str
|
|
14
14
|
user_id: str
|
|
15
15
|
execution_context: str
|
|
16
|
+
is_internal_user: bool = field(default=False, kw_only=True)
|
|
16
17
|
|
|
17
18
|
def to_dict(self) -> Dict[str, Any]:
|
|
18
19
|
"""Convert event to dictionary with ISO formatted timestamp."""
|
|
@@ -29,8 +30,8 @@ class ConnectorInitEvent(BaseEvent):
|
|
|
29
30
|
python_version: str
|
|
30
31
|
os_name: str
|
|
31
32
|
os_version: str
|
|
32
|
-
public_ip:
|
|
33
|
-
connector_version:
|
|
33
|
+
public_ip: str | None = None
|
|
34
|
+
connector_version: str | None = None
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
@dataclass
|
|
@@ -41,9 +42,9 @@ class OperationEvent(BaseEvent):
|
|
|
41
42
|
entity: str
|
|
42
43
|
action: str
|
|
43
44
|
timing_ms: float
|
|
44
|
-
public_ip:
|
|
45
|
-
status_code:
|
|
46
|
-
error_type:
|
|
45
|
+
public_ip: str | None = None
|
|
46
|
+
status_code: int | None = None
|
|
47
|
+
error_type: str | None = None
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
@dataclass
|
|
@@ -55,4 +56,4 @@ class SessionEndEvent(BaseEvent):
|
|
|
55
56
|
operation_count: int
|
|
56
57
|
success_count: int
|
|
57
58
|
failure_count: int
|
|
58
|
-
public_ip:
|
|
59
|
+
public_ip: str | None = None
|
|
@@ -4,7 +4,6 @@ import logging
|
|
|
4
4
|
import platform
|
|
5
5
|
import sys
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
from ..observability import ObservabilitySession
|
|
10
9
|
|
|
@@ -20,7 +19,7 @@ class SegmentTracker:
|
|
|
20
19
|
def __init__(
|
|
21
20
|
self,
|
|
22
21
|
session: ObservabilitySession,
|
|
23
|
-
mode:
|
|
22
|
+
mode: TelemetryMode | None = None,
|
|
24
23
|
):
|
|
25
24
|
self.session = session
|
|
26
25
|
self.mode = mode or TelemetryConfig.get_mode()
|
|
@@ -31,6 +30,8 @@ class SegmentTracker:
|
|
|
31
30
|
|
|
32
31
|
if self.enabled:
|
|
33
32
|
try:
|
|
33
|
+
# NOTE: Import here intentionally - segment is an optional dependency.
|
|
34
|
+
# This allows the SDK to work without telemetry if segment is not installed.
|
|
34
35
|
import segment.analytics as analytics
|
|
35
36
|
|
|
36
37
|
analytics.write_key = SEGMENT_WRITE_KEY
|
|
@@ -47,7 +48,7 @@ class SegmentTracker:
|
|
|
47
48
|
|
|
48
49
|
def track_connector_init(
|
|
49
50
|
self,
|
|
50
|
-
connector_version:
|
|
51
|
+
connector_version: str | None = None,
|
|
51
52
|
) -> None:
|
|
52
53
|
"""Track connector initialization."""
|
|
53
54
|
if not self.enabled or not self._analytics:
|
|
@@ -59,6 +60,7 @@ class SegmentTracker:
|
|
|
59
60
|
session_id=self.session.session_id,
|
|
60
61
|
user_id=self.session.user_id,
|
|
61
62
|
execution_context=self.session.execution_context,
|
|
63
|
+
is_internal_user=self.session.is_internal_user,
|
|
62
64
|
public_ip=self.session.public_ip,
|
|
63
65
|
connector_name=self.session.connector_name,
|
|
64
66
|
connector_version=connector_version,
|
|
@@ -81,9 +83,9 @@ class SegmentTracker:
|
|
|
81
83
|
self,
|
|
82
84
|
entity: str,
|
|
83
85
|
action: str,
|
|
84
|
-
status_code:
|
|
86
|
+
status_code: int | None,
|
|
85
87
|
timing_ms: float,
|
|
86
|
-
error_type:
|
|
88
|
+
error_type: str | None = None,
|
|
87
89
|
) -> None:
|
|
88
90
|
"""Track API operation."""
|
|
89
91
|
# Always track success/failure counts (useful even when tracking is disabled)
|
|
@@ -101,6 +103,7 @@ class SegmentTracker:
|
|
|
101
103
|
session_id=self.session.session_id,
|
|
102
104
|
user_id=self.session.user_id,
|
|
103
105
|
execution_context=self.session.execution_context,
|
|
106
|
+
is_internal_user=self.session.is_internal_user,
|
|
104
107
|
public_ip=self.session.public_ip,
|
|
105
108
|
connector_name=self.session.connector_name,
|
|
106
109
|
entity=entity,
|
|
@@ -130,6 +133,7 @@ class SegmentTracker:
|
|
|
130
133
|
session_id=self.session.session_id,
|
|
131
134
|
user_id=self.session.user_id,
|
|
132
135
|
execution_context=self.session.execution_context,
|
|
136
|
+
is_internal_user=self.session.is_internal_user,
|
|
133
137
|
public_ip=self.session.public_ip,
|
|
134
138
|
connector_name=self.session.connector_name,
|
|
135
139
|
duration_seconds=self.session.duration_seconds(),
|
|
@@ -22,7 +22,7 @@ class Action(str, Enum):
|
|
|
22
22
|
UPDATE = "update"
|
|
23
23
|
DELETE = "delete"
|
|
24
24
|
LIST = "list"
|
|
25
|
-
|
|
25
|
+
API_SEARCH = "api_search"
|
|
26
26
|
DOWNLOAD = "download"
|
|
27
27
|
AUTHORIZE = "authorize"
|
|
28
28
|
|
|
@@ -140,7 +140,7 @@ class AuthConfig(BaseModel):
|
|
|
140
140
|
ValueError: If this is a multi-auth config or invalid
|
|
141
141
|
"""
|
|
142
142
|
if self.is_multi_auth():
|
|
143
|
-
raise ValueError("Cannot call get_single_option() on multi-auth config.
|
|
143
|
+
raise ValueError("Cannot call get_single_option() on multi-auth config. Use options list instead.")
|
|
144
144
|
|
|
145
145
|
if self.type is None:
|
|
146
146
|
raise ValueError("Invalid AuthConfig: neither single-auth nor multi-auth")
|
|
@@ -161,7 +161,7 @@ class EndpointDefinition(BaseModel):
|
|
|
161
161
|
path: str # e.g., /v1/customers/{id} (OpenAPI path)
|
|
162
162
|
path_override: PathOverrideConfig | None = Field(
|
|
163
163
|
None,
|
|
164
|
-
description=("Path override config from x-airbyte-path-override.
|
|
164
|
+
description=("Path override config from x-airbyte-path-override. When set, overrides the path for actual HTTP requests."),
|
|
165
165
|
)
|
|
166
166
|
action: Action | None = None # Semantic action (get, list, create, update, delete)
|
|
167
167
|
description: str | None = None
|
|
@@ -221,6 +221,10 @@ class EntityDefinition(BaseModel):
|
|
|
221
221
|
model_config = {"populate_by_name": True}
|
|
222
222
|
|
|
223
223
|
name: str
|
|
224
|
+
stream_name: str | None = Field(
|
|
225
|
+
default=None,
|
|
226
|
+
description="Airbyte stream name for cache lookup (from x-airbyte-stream-name schema extension)",
|
|
227
|
+
)
|
|
224
228
|
actions: list[Action]
|
|
225
229
|
endpoints: dict[Action, EndpointDefinition]
|
|
226
230
|
entity_schema: dict[str, Any] | None = Field(default=None, alias="schema")
|
airbyte_agent_asana/connector.py
CHANGED
|
@@ -4,14 +4,15 @@ asana connector.
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import logging
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, TypeVar, AsyncIterator, overload
|
|
8
9
|
try:
|
|
9
10
|
from typing import Literal
|
|
10
11
|
except ImportError:
|
|
11
12
|
from typing_extensions import Literal
|
|
12
13
|
|
|
13
14
|
from .connector_model import AsanaConnectorModel
|
|
14
|
-
|
|
15
|
+
from ._vendored.connector_sdk.introspection import describe_entities, generate_tool_description
|
|
15
16
|
from .types import (
|
|
16
17
|
AttachmentsDownloadParams,
|
|
17
18
|
AttachmentsGetParams,
|
|
@@ -42,7 +43,6 @@ from .types import (
|
|
|
42
43
|
WorkspacesGetParams,
|
|
43
44
|
WorkspacesListParams,
|
|
44
45
|
)
|
|
45
|
-
|
|
46
46
|
if TYPE_CHECKING:
|
|
47
47
|
from .models import AsanaAuthConfig
|
|
48
48
|
# Import specific auth config classes for multi-auth isinstance checks
|
|
@@ -80,6 +80,9 @@ from .models import (
|
|
|
80
80
|
TaskDependentsListResult,
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
+
# TypeVar for decorator type preservation
|
|
84
|
+
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
85
|
+
|
|
83
86
|
|
|
84
87
|
class AsanaConnector:
|
|
85
88
|
"""
|
|
@@ -564,6 +567,88 @@ class AsanaConnector:
|
|
|
564
567
|
# No extractors - return raw response data
|
|
565
568
|
return result.data
|
|
566
569
|
|
|
570
|
+
# ===== INTROSPECTION METHODS =====
|
|
571
|
+
|
|
572
|
+
@classmethod
|
|
573
|
+
def describe(cls, func: _F) -> _F:
|
|
574
|
+
"""
|
|
575
|
+
Decorator that populates a function's docstring with connector capabilities.
|
|
576
|
+
|
|
577
|
+
This class method can be used as a decorator to automatically generate
|
|
578
|
+
comprehensive documentation for AI tool functions.
|
|
579
|
+
|
|
580
|
+
Usage:
|
|
581
|
+
@mcp.tool()
|
|
582
|
+
@AsanaConnector.describe
|
|
583
|
+
async def execute(entity: str, action: str, params: dict):
|
|
584
|
+
'''Execute operations.'''
|
|
585
|
+
...
|
|
586
|
+
|
|
587
|
+
The decorated function's __doc__ will be updated with:
|
|
588
|
+
- Available entities and their actions
|
|
589
|
+
- Parameter signatures with required (*) and optional (?) markers
|
|
590
|
+
- Response structure documentation
|
|
591
|
+
- Example questions (if available in OpenAPI spec)
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
func: The function to decorate
|
|
595
|
+
|
|
596
|
+
Returns:
|
|
597
|
+
The same function with updated __doc__
|
|
598
|
+
"""
|
|
599
|
+
description = generate_tool_description(AsanaConnectorModel)
|
|
600
|
+
|
|
601
|
+
original_doc = func.__doc__ or ""
|
|
602
|
+
if original_doc.strip():
|
|
603
|
+
func.__doc__ = f"{original_doc.strip()}\n{description}"
|
|
604
|
+
else:
|
|
605
|
+
func.__doc__ = description
|
|
606
|
+
|
|
607
|
+
return func
|
|
608
|
+
|
|
609
|
+
def list_entities(self) -> list[dict[str, Any]]:
|
|
610
|
+
"""
|
|
611
|
+
Get structured data about available entities, actions, and parameters.
|
|
612
|
+
|
|
613
|
+
Returns a list of entity descriptions with:
|
|
614
|
+
- entity_name: Name of the entity (e.g., "contacts", "deals")
|
|
615
|
+
- description: Entity description from the first endpoint
|
|
616
|
+
- available_actions: List of actions (e.g., ["list", "get", "create"])
|
|
617
|
+
- parameters: Dict mapping action -> list of parameter dicts
|
|
618
|
+
|
|
619
|
+
Example:
|
|
620
|
+
entities = connector.list_entities()
|
|
621
|
+
for entity in entities:
|
|
622
|
+
print(f"{entity['entity_name']}: {entity['available_actions']}")
|
|
623
|
+
"""
|
|
624
|
+
return describe_entities(AsanaConnectorModel)
|
|
625
|
+
|
|
626
|
+
def entity_schema(self, entity: str) -> dict[str, Any] | None:
|
|
627
|
+
"""
|
|
628
|
+
Get the JSON schema for an entity.
|
|
629
|
+
|
|
630
|
+
Args:
|
|
631
|
+
entity: Entity name (e.g., "contacts", "companies")
|
|
632
|
+
|
|
633
|
+
Returns:
|
|
634
|
+
JSON schema dict describing the entity structure, or None if not found.
|
|
635
|
+
|
|
636
|
+
Example:
|
|
637
|
+
schema = connector.entity_schema("contacts")
|
|
638
|
+
if schema:
|
|
639
|
+
print(f"Contact properties: {list(schema.get('properties', {}).keys())}")
|
|
640
|
+
"""
|
|
641
|
+
entity_def = next(
|
|
642
|
+
(e for e in AsanaConnectorModel.entities if e.name == entity),
|
|
643
|
+
None
|
|
644
|
+
)
|
|
645
|
+
if entity_def is None:
|
|
646
|
+
logging.getLogger(__name__).warning(
|
|
647
|
+
f"Entity '{entity}' not found. Available entities: "
|
|
648
|
+
f"{[e.name for e in AsanaConnectorModel.entities]}"
|
|
649
|
+
)
|
|
650
|
+
return entity_def.entity_schema if entity_def else None
|
|
651
|
+
|
|
567
652
|
|
|
568
653
|
|
|
569
654
|
class TasksQuery:
|
|
@@ -73,6 +73,11 @@ AsanaConnectorModel: ConnectorModel = ConnectorModel(
|
|
|
73
73
|
'client_id': '${client_id}',
|
|
74
74
|
'client_secret': '${client_secret}',
|
|
75
75
|
},
|
|
76
|
+
replication_auth_key_mapping={
|
|
77
|
+
'client_id': 'client_id',
|
|
78
|
+
'client_secret': 'client_secret',
|
|
79
|
+
'refresh_token': 'refresh_token',
|
|
80
|
+
},
|
|
76
81
|
),
|
|
77
82
|
),
|
|
78
83
|
AuthOption(
|
|
@@ -91,6 +96,7 @@ AsanaConnectorModel: ConnectorModel = ConnectorModel(
|
|
|
91
96
|
),
|
|
92
97
|
},
|
|
93
98
|
auth_mapping={'token': '${token}'},
|
|
99
|
+
replication_auth_key_mapping={'personal_access_token': 'token'},
|
|
94
100
|
),
|
|
95
101
|
),
|
|
96
102
|
],
|
airbyte_agent_asana/models.py
CHANGED
|
@@ -91,84 +91,84 @@ class ProjectCompact(BaseModel):
|
|
|
91
91
|
resource_type: Union[str, Any] = Field(default=None)
|
|
92
92
|
name: Union[str, Any] = Field(default=None)
|
|
93
93
|
|
|
94
|
-
class
|
|
95
|
-
"""Nested schema for
|
|
94
|
+
class ProjectMembersItem(BaseModel):
|
|
95
|
+
"""Nested schema for Project.members_item"""
|
|
96
96
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
97
97
|
|
|
98
98
|
gid: Union[str, Any] = Field(default=None)
|
|
99
99
|
name: Union[str, Any] = Field(default=None)
|
|
100
100
|
resource_type: Union[str, Any] = Field(default=None)
|
|
101
101
|
|
|
102
|
-
class
|
|
103
|
-
"""Nested schema for
|
|
102
|
+
class ProjectWorkspace(BaseModel):
|
|
103
|
+
"""Nested schema for Project.workspace"""
|
|
104
104
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
105
105
|
|
|
106
106
|
gid: Union[str, Any] = Field(default=None)
|
|
107
107
|
name: Union[str, Any] = Field(default=None)
|
|
108
108
|
resource_type: Union[str, Any] = Field(default=None)
|
|
109
109
|
|
|
110
|
-
class
|
|
111
|
-
"""Nested schema for Project.
|
|
110
|
+
class ProjectTeam(BaseModel):
|
|
111
|
+
"""Nested schema for Project.team"""
|
|
112
112
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
113
113
|
|
|
114
114
|
gid: Union[str, Any] = Field(default=None)
|
|
115
|
-
|
|
116
|
-
color: Union[str, Any] = Field(default=None)
|
|
117
|
-
created_at: Union[str, Any] = Field(default=None)
|
|
118
|
-
created_by: Union[ProjectCurrentStatusCreatedBy, Any] = Field(default=None)
|
|
119
|
-
modified_at: Union[str, Any] = Field(default=None)
|
|
115
|
+
name: Union[str, Any] = Field(default=None)
|
|
120
116
|
resource_type: Union[str, Any] = Field(default=None)
|
|
121
|
-
text: Union[str, Any] = Field(default=None)
|
|
122
|
-
title: Union[str, Any] = Field(default=None)
|
|
123
117
|
|
|
124
|
-
class
|
|
125
|
-
"""Nested schema for Project.
|
|
118
|
+
class ProjectFollowersItem(BaseModel):
|
|
119
|
+
"""Nested schema for Project.followers_item"""
|
|
126
120
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
127
121
|
|
|
128
122
|
gid: Union[str, Any] = Field(default=None)
|
|
129
123
|
name: Union[str, Any] = Field(default=None)
|
|
130
124
|
resource_type: Union[str, Any] = Field(default=None)
|
|
131
125
|
|
|
132
|
-
class
|
|
133
|
-
"""Nested schema for
|
|
126
|
+
class ProjectCurrentStatusCreatedBy(BaseModel):
|
|
127
|
+
"""Nested schema for ProjectCurrentStatus.created_by"""
|
|
134
128
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
135
129
|
|
|
136
130
|
gid: Union[str, Any] = Field(default=None)
|
|
137
131
|
name: Union[str, Any] = Field(default=None)
|
|
138
132
|
resource_type: Union[str, Any] = Field(default=None)
|
|
139
133
|
|
|
140
|
-
class
|
|
141
|
-
"""Nested schema for
|
|
134
|
+
class ProjectCurrentStatusAuthor(BaseModel):
|
|
135
|
+
"""Nested schema for ProjectCurrentStatus.author"""
|
|
142
136
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
143
137
|
|
|
144
138
|
gid: Union[str, Any] = Field(default=None)
|
|
139
|
+
name: Union[str, Any] = Field(default=None)
|
|
145
140
|
resource_type: Union[str, Any] = Field(default=None)
|
|
146
|
-
resource_subtype: Union[str, Any] = Field(default=None)
|
|
147
|
-
title: Union[str, Any] = Field(default=None)
|
|
148
141
|
|
|
149
|
-
class
|
|
150
|
-
"""Nested schema for Project.
|
|
142
|
+
class ProjectCurrentStatus(BaseModel):
|
|
143
|
+
"""Nested schema for Project.current_status"""
|
|
151
144
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
152
145
|
|
|
153
146
|
gid: Union[str, Any] = Field(default=None)
|
|
154
|
-
|
|
147
|
+
author: Union[ProjectCurrentStatusAuthor, Any] = Field(default=None)
|
|
148
|
+
color: Union[str, Any] = Field(default=None)
|
|
149
|
+
created_at: Union[str, Any] = Field(default=None)
|
|
150
|
+
created_by: Union[ProjectCurrentStatusCreatedBy, Any] = Field(default=None)
|
|
151
|
+
modified_at: Union[str, Any] = Field(default=None)
|
|
155
152
|
resource_type: Union[str, Any] = Field(default=None)
|
|
153
|
+
text: Union[str, Any] = Field(default=None)
|
|
154
|
+
title: Union[str, Any] = Field(default=None)
|
|
156
155
|
|
|
157
|
-
class
|
|
158
|
-
"""Nested schema for Project.
|
|
156
|
+
class ProjectOwner(BaseModel):
|
|
157
|
+
"""Nested schema for Project.owner"""
|
|
159
158
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
160
159
|
|
|
161
160
|
gid: Union[str, Any] = Field(default=None)
|
|
162
161
|
name: Union[str, Any] = Field(default=None)
|
|
163
162
|
resource_type: Union[str, Any] = Field(default=None)
|
|
164
163
|
|
|
165
|
-
class
|
|
166
|
-
"""Nested schema for Project.
|
|
164
|
+
class ProjectCurrentStatusUpdate(BaseModel):
|
|
165
|
+
"""Nested schema for Project.current_status_update"""
|
|
167
166
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
168
167
|
|
|
169
168
|
gid: Union[str, Any] = Field(default=None)
|
|
170
|
-
name: Union[str, Any] = Field(default=None)
|
|
171
169
|
resource_type: Union[str, Any] = Field(default=None)
|
|
170
|
+
resource_subtype: Union[str, Any] = Field(default=None)
|
|
171
|
+
title: Union[str, Any] = Field(default=None)
|
|
172
172
|
|
|
173
173
|
class Project(BaseModel):
|
|
174
174
|
"""Full project object"""
|
airbyte_agent_asana/types.py
CHANGED
|
@@ -3,7 +3,7 @@ Type definitions for asana connector.
|
|
|
3
3
|
"""
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
# Use typing_extensions.TypedDict for Pydantic compatibility
|
|
6
|
+
# Use typing_extensions.TypedDict for Pydantic compatibility
|
|
7
7
|
try:
|
|
8
8
|
from typing_extensions import TypedDict, NotRequired
|
|
9
9
|
except ImportError:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-asana
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.41
|
|
4
4
|
Summary: Airbyte Asana Connector for AI platforms
|
|
5
5
|
Project-URL: Homepage, https://github.com/airbytehq/airbyte-embedded
|
|
6
6
|
Project-URL: Documentation, https://github.com/airbytehq/airbyte-embedded/tree/main/integrations
|
|
@@ -13,13 +13,9 @@ Classifier: Development Status :: 3 - Alpha
|
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: Other/Proprietary License
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
20
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.13
|
|
23
19
|
Requires-Dist: httpx>=0.24.0
|
|
24
20
|
Requires-Dist: jinja2>=3.0.0
|
|
25
21
|
Requires-Dist: jsonpath-ng>=1.6.1
|
|
@@ -41,12 +37,14 @@ teams, and users for project tracking, workload analysis, and productivity insig
|
|
|
41
37
|
|
|
42
38
|
## Example questions
|
|
43
39
|
|
|
40
|
+
The Asana connector is optimized to handle prompts like these.
|
|
41
|
+
|
|
44
42
|
- What tasks are assigned to me this week?
|
|
45
43
|
- List all projects in my workspace
|
|
46
44
|
- Summarize my team's workload and task completion rates
|
|
47
|
-
- Show me the tasks for the {project_name} project
|
|
48
|
-
- Who are the team members in my {team_name} team?
|
|
49
|
-
- Find all tasks related to {client_name} across my workspaces
|
|
45
|
+
- Show me the tasks for the \{project_name\} project
|
|
46
|
+
- Who are the team members in my \{team_name\} team?
|
|
47
|
+
- Find all tasks related to \{client_name\} across my workspaces
|
|
50
48
|
- Analyze the most active projects in my workspace last month
|
|
51
49
|
- Compare task completion rates between my different teams
|
|
52
50
|
- Identify overdue tasks across all my projects
|
|
@@ -54,6 +52,8 @@ teams, and users for project tracking, workload analysis, and productivity insig
|
|
|
54
52
|
|
|
55
53
|
## Unsupported questions
|
|
56
54
|
|
|
55
|
+
The Asana connector isn't currently able to handle prompts like these.
|
|
56
|
+
|
|
57
57
|
- Create a new task for [TeamMember]
|
|
58
58
|
- Update the priority of this task
|
|
59
59
|
- Delete the project [ProjectName]
|
|
@@ -139,6 +139,6 @@ For the service's official API docs, see the [Asana API reference](https://devel
|
|
|
139
139
|
|
|
140
140
|
## Version information
|
|
141
141
|
|
|
142
|
-
- **Package version:** 0.19.
|
|
142
|
+
- **Package version:** 0.19.41
|
|
143
143
|
- **Connector version:** 0.1.6
|
|
144
|
-
- **Generated with Connector SDK commit SHA:**
|
|
144
|
+
- **Generated with Connector SDK commit SHA:** a23d9e7ac2d9d416258f7a9a3b9a731782cd6bd8
|