glaip-sdk 0.0.0b99__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.
- glaip_sdk/__init__.py +52 -0
- glaip_sdk/_version.py +81 -0
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1227 -0
- glaip_sdk/branding.py +211 -0
- glaip_sdk/cli/__init__.py +9 -0
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/agent_config.py +78 -0
- glaip_sdk/cli/auth.py +705 -0
- glaip_sdk/cli/commands/__init__.py +5 -0
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents/__init__.py +119 -0
- glaip_sdk/cli/commands/agents/_common.py +561 -0
- glaip_sdk/cli/commands/agents/create.py +151 -0
- glaip_sdk/cli/commands/agents/delete.py +64 -0
- glaip_sdk/cli/commands/agents/get.py +89 -0
- glaip_sdk/cli/commands/agents/list.py +129 -0
- glaip_sdk/cli/commands/agents/run.py +264 -0
- glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
- glaip_sdk/cli/commands/agents/update.py +112 -0
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +895 -0
- glaip_sdk/cli/commands/mcps/__init__.py +94 -0
- glaip_sdk/cli/commands/mcps/_common.py +459 -0
- glaip_sdk/cli/commands/mcps/connect.py +82 -0
- glaip_sdk/cli/commands/mcps/create.py +152 -0
- glaip_sdk/cli/commands/mcps/delete.py +73 -0
- glaip_sdk/cli/commands/mcps/get.py +212 -0
- glaip_sdk/cli/commands/mcps/list.py +69 -0
- glaip_sdk/cli/commands/mcps/tools.py +235 -0
- glaip_sdk/cli/commands/mcps/update.py +190 -0
- glaip_sdk/cli/commands/models.py +67 -0
- glaip_sdk/cli/commands/shared/__init__.py +21 -0
- glaip_sdk/cli/commands/shared/formatters.py +91 -0
- glaip_sdk/cli/commands/tools/__init__.py +69 -0
- glaip_sdk/cli/commands/tools/_common.py +80 -0
- glaip_sdk/cli/commands/tools/create.py +228 -0
- glaip_sdk/cli/commands/tools/delete.py +61 -0
- glaip_sdk/cli/commands/tools/get.py +103 -0
- glaip_sdk/cli/commands/tools/list.py +69 -0
- glaip_sdk/cli/commands/tools/script.py +49 -0
- glaip_sdk/cli/commands/tools/update.py +102 -0
- glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
- glaip_sdk/cli/commands/transcripts/_common.py +9 -0
- glaip_sdk/cli/commands/transcripts/clear.py +5 -0
- glaip_sdk/cli/commands/transcripts/detail.py +5 -0
- glaip_sdk/cli/commands/transcripts_original.py +756 -0
- glaip_sdk/cli/commands/update.py +192 -0
- glaip_sdk/cli/config.py +95 -0
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +150 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +851 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +355 -0
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +112 -0
- glaip_sdk/cli/main.py +686 -0
- glaip_sdk/cli/masking.py +136 -0
- glaip_sdk/cli/mcp_validators.py +287 -0
- glaip_sdk/cli/pager.py +266 -0
- glaip_sdk/cli/parsers/__init__.py +7 -0
- glaip_sdk/cli/parsers/json_input.py +177 -0
- glaip_sdk/cli/resolution.py +68 -0
- glaip_sdk/cli/rich_helpers.py +27 -0
- glaip_sdk/cli/slash/__init__.py +15 -0
- glaip_sdk/cli/slash/accounts_controller.py +580 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +285 -0
- glaip_sdk/cli/slash/prompt.py +256 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +1724 -0
- glaip_sdk/cli/slash/tui/__init__.py +34 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +88 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +933 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/clipboard.py +147 -0
- glaip_sdk/cli/slash/tui/context.py +59 -0
- glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/slash/tui/terminal.py +402 -0
- glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
- glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
- glaip_sdk/cli/slash/tui/theme/manager.py +86 -0
- glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
- glaip_sdk/cli/slash/tui/toast.py +123 -0
- glaip_sdk/cli/transcript/__init__.py +31 -0
- glaip_sdk/cli/transcript/cache.py +536 -0
- glaip_sdk/cli/transcript/capture.py +329 -0
- glaip_sdk/cli/transcript/export.py +38 -0
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/launcher.py +77 -0
- glaip_sdk/cli/transcript/viewer.py +374 -0
- glaip_sdk/cli/update_notifier.py +369 -0
- glaip_sdk/cli/validators.py +238 -0
- glaip_sdk/client/__init__.py +12 -0
- glaip_sdk/client/_schedule_payloads.py +89 -0
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +1353 -0
- glaip_sdk/client/base.py +502 -0
- glaip_sdk/client/main.py +253 -0
- glaip_sdk/client/mcps.py +401 -0
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/payloads/agent/requests.py +495 -0
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/run_rendering.py +747 -0
- glaip_sdk/client/schedules.py +439 -0
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +690 -0
- glaip_sdk/client/validators.py +198 -0
- glaip_sdk/config/constants.py +52 -0
- glaip_sdk/exceptions.py +113 -0
- glaip_sdk/hitl/__init__.py +15 -0
- glaip_sdk/hitl/local.py +151 -0
- glaip_sdk/icons.py +25 -0
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +107 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +117 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/schedule.py +224 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +7 -0
- glaip_sdk/payload_schemas/agent.py +85 -0
- glaip_sdk/registry/__init__.py +55 -0
- glaip_sdk/registry/agent.py +164 -0
- glaip_sdk/registry/base.py +139 -0
- glaip_sdk/registry/mcp.py +253 -0
- glaip_sdk/registry/tool.py +393 -0
- glaip_sdk/rich_components.py +125 -0
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +112 -0
- glaip_sdk/runner/langgraph.py +870 -0
- glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +95 -0
- glaip_sdk/runner/tool_adapter/__init__.py +18 -0
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +219 -0
- glaip_sdk/schedules/__init__.py +22 -0
- glaip_sdk/schedules/base.py +291 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +466 -0
- glaip_sdk/utils/__init__.py +86 -0
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/agent_config.py +194 -0
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +486 -0
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +135 -0
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +61 -0
- glaip_sdk/utils/import_export.py +168 -0
- glaip_sdk/utils/import_resolver.py +530 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -0
- glaip_sdk/utils/rendering/formatting.py +264 -0
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/layout/panels.py +156 -0
- glaip_sdk/utils/rendering/layout/progress.py +202 -0
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +85 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +55 -0
- glaip_sdk/utils/rendering/renderer/base.py +1082 -0
- glaip_sdk/utils/rendering/renderer/config.py +27 -0
- glaip_sdk/utils/rendering/renderer/console.py +55 -0
- glaip_sdk/utils/rendering/renderer/debug.py +178 -0
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +202 -0
- glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/toggle.py +182 -0
- glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
- glaip_sdk/utils/rendering/state.py +204 -0
- glaip_sdk/utils/rendering/step_tree_state.py +100 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/steps/event_processor.py +778 -0
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/steps/manager.py +387 -0
- glaip_sdk/utils/rendering/timing.py +36 -0
- glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
- glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
- glaip_sdk/utils/resource_refs.py +195 -0
- glaip_sdk/utils/run_renderer.py +41 -0
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +424 -0
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- glaip_sdk/utils/validation.py +264 -0
- glaip_sdk-0.0.0b99.dist-info/METADATA +239 -0
- glaip_sdk-0.0.0b99.dist-info/RECORD +207 -0
- glaip_sdk-0.0.0b99.dist-info/WHEEL +5 -0
- glaip_sdk-0.0.0b99.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.0.0b99.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Helpers for local tool output storage setup.
|
|
2
|
+
|
|
3
|
+
This module bridges agent_config.tool_output_sharing to ToolOutputManager
|
|
4
|
+
for local execution without modifying aip-agents.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Fachriza Adhiatma (fachriza.d.adhiatma@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from gllm_core.utils import LoggerManager
|
|
16
|
+
|
|
17
|
+
logger = LoggerManager().get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_tool_output_manager(agent_name: str, agent_config: dict[str, Any]) -> Any | None:
|
|
21
|
+
"""Build a ToolOutputManager for local tool output sharing.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
agent_name: Name of the agent whose tool outputs will be stored.
|
|
25
|
+
agent_config: Agent configuration that may enable tool output sharing and contain task_id.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
A ToolOutputManager instance when tool output sharing is enabled and
|
|
29
|
+
dependencies are available, otherwise ``None``.
|
|
30
|
+
"""
|
|
31
|
+
tool_output_sharing_enabled = agent_config.get("tool_output_sharing", False)
|
|
32
|
+
if not tool_output_sharing_enabled:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
from aip_agents.storage.clients.minio_client import MinioConfig, MinioObjectStorage # noqa: PLC0415
|
|
37
|
+
from aip_agents.storage.providers.memory import InMemoryStorageProvider # noqa: PLC0415
|
|
38
|
+
from aip_agents.storage.providers.object_storage import ObjectStorageProvider # noqa: PLC0415
|
|
39
|
+
from aip_agents.utils.langgraph.tool_output_management import ( # noqa: PLC0415
|
|
40
|
+
ToolOutputConfig,
|
|
41
|
+
ToolOutputManager,
|
|
42
|
+
)
|
|
43
|
+
except ImportError:
|
|
44
|
+
logger.warning("Tool output sharing requested but aip-agents is unavailable; skipping.")
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
task_id = agent_config.get("task_id")
|
|
48
|
+
|
|
49
|
+
storage_provider = _build_tool_output_storage_provider(
|
|
50
|
+
agent_name=agent_name,
|
|
51
|
+
task_id=task_id,
|
|
52
|
+
minio_config_cls=MinioConfig,
|
|
53
|
+
minio_client_cls=MinioObjectStorage,
|
|
54
|
+
object_storage_provider_cls=ObjectStorageProvider,
|
|
55
|
+
memory_storage_provider_cls=InMemoryStorageProvider,
|
|
56
|
+
)
|
|
57
|
+
tool_output_config = _build_tool_output_config(storage_provider, ToolOutputConfig)
|
|
58
|
+
return ToolOutputManager(tool_output_config)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _build_tool_output_storage_provider(
|
|
62
|
+
agent_name: str,
|
|
63
|
+
task_id: str | None,
|
|
64
|
+
minio_config_cls: Any,
|
|
65
|
+
minio_client_cls: Any,
|
|
66
|
+
object_storage_provider_cls: Any,
|
|
67
|
+
memory_storage_provider_cls: Any,
|
|
68
|
+
) -> Any:
|
|
69
|
+
"""Create a storage provider for tool output sharing.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
agent_name: Name of the agent whose tool outputs are stored.
|
|
73
|
+
task_id: Optional task identifier for coordination context.
|
|
74
|
+
minio_config_cls: Class exposing a ``from_env`` constructor for MinIO config.
|
|
75
|
+
minio_client_cls: MinIO client class used to talk to the object store.
|
|
76
|
+
object_storage_provider_cls: Storage provider wrapping the MinIO client.
|
|
77
|
+
memory_storage_provider_cls: In-memory provider used as a fallback.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
An instance of ``object_storage_provider_cls`` when MinIO initialization
|
|
81
|
+
succeeds, otherwise an instance of ``memory_storage_provider_cls``.
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
config_obj = minio_config_cls.from_env()
|
|
85
|
+
minio_client = minio_client_cls(config=config_obj)
|
|
86
|
+
prefix = _build_tool_output_prefix(agent_name, task_id)
|
|
87
|
+
return object_storage_provider_cls(client=minio_client, prefix=prefix, use_json=False)
|
|
88
|
+
except Exception as exc:
|
|
89
|
+
logger.warning("Failed to initialize MinIO for tool outputs: %s. Using in-memory storage.", exc)
|
|
90
|
+
return memory_storage_provider_cls()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _build_tool_output_prefix(agent_name: str, task_id: str | None) -> str:
|
|
94
|
+
"""Build object storage prefix for tool outputs in local mode.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
agent_name: Name of the agent whose outputs are stored.
|
|
98
|
+
task_id: Optional task identifier for coordination context.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Object storage key prefix dedicated to the provided agent.
|
|
102
|
+
"""
|
|
103
|
+
if task_id:
|
|
104
|
+
return f"tool-outputs/tasks/{task_id}/agents/{agent_name}/"
|
|
105
|
+
return f"tool-outputs/agents/{agent_name}/"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _build_tool_output_config(storage_provider: Any, config_cls: Any) -> Any:
|
|
109
|
+
"""Build ToolOutputConfig using env vars, with safe defaults.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
storage_provider: Provider that will persist tool outputs.
|
|
113
|
+
config_cls: Tool output configuration class to instantiate.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
A configured ``config_cls`` instance ready for ToolOutputManager use.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def safe_int_conversion(env_var: str, default: str) -> int:
|
|
120
|
+
"""Convert an environment variable to int with a fallback default.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
env_var: Environment variable name to read.
|
|
124
|
+
default: Default string value used when parsing fails.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Integer representation of the environment variable or the default.
|
|
128
|
+
"""
|
|
129
|
+
try:
|
|
130
|
+
return int(os.getenv(env_var, default))
|
|
131
|
+
except (ValueError, TypeError):
|
|
132
|
+
logger.warning("Invalid value for %s, using default: %s", env_var, default)
|
|
133
|
+
return int(default)
|
|
134
|
+
|
|
135
|
+
return config_cls(
|
|
136
|
+
max_stored_outputs=safe_int_conversion("TOOL_OUTPUT_MAX_STORED", "200"),
|
|
137
|
+
max_age_minutes=safe_int_conversion("TOOL_OUTPUT_MAX_AGE_MINUTES", str(24 * 60)),
|
|
138
|
+
cleanup_interval=safe_int_conversion("TOOL_OUTPUT_CLEANUP_INTERVAL", "50"),
|
|
139
|
+
storage_provider=storage_provider,
|
|
140
|
+
)
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""Validation utilities for resource names, timeouts, and other constraints.
|
|
2
|
+
|
|
3
|
+
This module provides pure validation functions that raise ValueError for invalid
|
|
4
|
+
inputs. CLI layer wraps these with click.ClickException for user-friendly errors.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT
|
|
15
|
+
from glaip_sdk.utils.resource_refs import validate_name_format
|
|
16
|
+
|
|
17
|
+
# Constants for validation
|
|
18
|
+
RESERVED_NAMES = ["admin", "root", "system", "api", "test", "demo"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _validate_named_resource(name: str, resource_type: str) -> str:
|
|
22
|
+
"""Shared validator that prevents reserved-name duplication."""
|
|
23
|
+
cleaned_name = validate_name_format(name, resource_type)
|
|
24
|
+
|
|
25
|
+
if cleaned_name.lower() in RESERVED_NAMES:
|
|
26
|
+
raise ValueError(f"{resource_type.capitalize()} name '{cleaned_name}' is reserved and cannot be used")
|
|
27
|
+
|
|
28
|
+
return cleaned_name
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def validate_agent_name(name: str) -> str:
|
|
32
|
+
"""Validate agent name and return cleaned version.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
name: Agent name to validate
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Cleaned agent name
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ValueError: If name is invalid
|
|
42
|
+
"""
|
|
43
|
+
return _validate_named_resource(name, "agent")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def validate_agent_instruction(instruction: str) -> str:
|
|
47
|
+
"""Validate agent instruction and return cleaned version.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
instruction: Agent instruction to validate
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Cleaned agent instruction
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ValueError: If instruction is invalid
|
|
57
|
+
"""
|
|
58
|
+
if not instruction or not instruction.strip():
|
|
59
|
+
raise ValueError("Agent instruction cannot be empty or whitespace")
|
|
60
|
+
|
|
61
|
+
cleaned_instruction = instruction.strip()
|
|
62
|
+
|
|
63
|
+
if len(cleaned_instruction) > 100000:
|
|
64
|
+
raise ValueError("Agent instruction cannot be longer than 100,000 characters")
|
|
65
|
+
|
|
66
|
+
return cleaned_instruction
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def validate_tool_name(name: str) -> str:
|
|
70
|
+
"""Validate tool name and return cleaned version.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
name: Tool name to validate
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Cleaned tool name
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ValueError: If name is invalid
|
|
80
|
+
"""
|
|
81
|
+
return _validate_named_resource(name, "tool")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def validate_mcp_name(name: str) -> str:
|
|
85
|
+
"""Validate MCP name and return cleaned version.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
name: MCP name to validate
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Cleaned MCP name
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
ValueError: If name is invalid
|
|
95
|
+
"""
|
|
96
|
+
return _validate_named_resource(name, "mcp")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def validate_timeout(timeout: int) -> int:
|
|
100
|
+
"""Validate timeout value.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
timeout: Timeout value in seconds
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Validated timeout value
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
ValueError: If timeout is invalid
|
|
110
|
+
"""
|
|
111
|
+
if timeout < 1:
|
|
112
|
+
raise ValueError("Timeout must be at least 1 second")
|
|
113
|
+
|
|
114
|
+
if timeout > 3600: # 1 hour max
|
|
115
|
+
raise ValueError("Timeout cannot be longer than 1 hour (3600 seconds)")
|
|
116
|
+
|
|
117
|
+
return timeout
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def coerce_timeout(value: Any) -> int:
|
|
121
|
+
"""Coerce timeout value to integer, handling various input types.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
value: The timeout value to coerce (int, float, str, etc.)
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Integer timeout value
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
ValueError: If value cannot be coerced to valid timeout
|
|
131
|
+
|
|
132
|
+
Examples:
|
|
133
|
+
coerce_timeout(300) -> 300
|
|
134
|
+
coerce_timeout(300.0) -> 300
|
|
135
|
+
coerce_timeout("300") -> 300
|
|
136
|
+
coerce_timeout(None) -> 300 # Uses DEFAULT_AGENT_RUN_TIMEOUT
|
|
137
|
+
"""
|
|
138
|
+
if value is None:
|
|
139
|
+
return DEFAULT_AGENT_RUN_TIMEOUT
|
|
140
|
+
elif isinstance(value, int):
|
|
141
|
+
return validate_timeout(value)
|
|
142
|
+
elif isinstance(value, float):
|
|
143
|
+
if value.is_integer():
|
|
144
|
+
return validate_timeout(int(value))
|
|
145
|
+
return validate_timeout(int(value)) # Truncate if not integer
|
|
146
|
+
elif isinstance(value, str):
|
|
147
|
+
try:
|
|
148
|
+
fval = float(value)
|
|
149
|
+
return validate_timeout(int(fval))
|
|
150
|
+
except ValueError as err:
|
|
151
|
+
raise ValueError(f"Invalid timeout value: {value}") from err
|
|
152
|
+
else:
|
|
153
|
+
try:
|
|
154
|
+
return validate_timeout(int(value))
|
|
155
|
+
except (TypeError, ValueError) as err:
|
|
156
|
+
raise ValueError(f"Invalid timeout value: {value}") from err
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def validate_file_path(file_path: str | Path, must_exist: bool = True) -> Path:
|
|
160
|
+
"""Validate file path.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
file_path: File path to validate
|
|
164
|
+
must_exist: Whether file must exist
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Path object
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
ValueError: If file path is invalid
|
|
171
|
+
"""
|
|
172
|
+
path = Path(file_path)
|
|
173
|
+
|
|
174
|
+
if must_exist and not path.exists():
|
|
175
|
+
raise ValueError(f"File does not exist: {file_path}")
|
|
176
|
+
|
|
177
|
+
if must_exist and not path.is_file():
|
|
178
|
+
raise ValueError(f"Path is not a file: {file_path}")
|
|
179
|
+
|
|
180
|
+
return path
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def validate_directory_path(dir_path: str | Path, must_exist: bool = True) -> Path:
|
|
184
|
+
"""Validate directory path.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
dir_path: Directory path to validate
|
|
188
|
+
must_exist: Whether directory must exist
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Path object
|
|
192
|
+
|
|
193
|
+
Raises:
|
|
194
|
+
ValueError: If directory path is invalid
|
|
195
|
+
"""
|
|
196
|
+
path = Path(dir_path)
|
|
197
|
+
|
|
198
|
+
if must_exist and not path.exists():
|
|
199
|
+
raise ValueError(f"Directory does not exist: {dir_path}")
|
|
200
|
+
|
|
201
|
+
if must_exist and not path.is_dir():
|
|
202
|
+
raise ValueError(f"Path is not a directory: {dir_path}")
|
|
203
|
+
|
|
204
|
+
return path
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def validate_url(url: str) -> str:
|
|
208
|
+
"""Validate URL format (HTTPS only).
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
url: URL to validate
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Validated URL
|
|
215
|
+
|
|
216
|
+
Raises:
|
|
217
|
+
ValueError: If URL is invalid
|
|
218
|
+
"""
|
|
219
|
+
url_pattern = re.compile(
|
|
220
|
+
r"^https://" # https:// only
|
|
221
|
+
r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|" # domain...
|
|
222
|
+
r"localhost|" # localhost...
|
|
223
|
+
r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip
|
|
224
|
+
r"(?::\d+)?" # optional port
|
|
225
|
+
r"(?:/?|[/?]\S+)$",
|
|
226
|
+
re.IGNORECASE,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
if not url_pattern.match(url):
|
|
230
|
+
raise ValueError("API URL must start with https:// and be a valid host.")
|
|
231
|
+
|
|
232
|
+
return url
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def validate_api_key(api_key: str) -> str:
|
|
236
|
+
"""Validate API key format.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
api_key: API key to validate
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Validated API key
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
ValueError: If API key is invalid
|
|
246
|
+
"""
|
|
247
|
+
if not api_key or not api_key.strip():
|
|
248
|
+
raise ValueError("API key cannot be empty")
|
|
249
|
+
|
|
250
|
+
cleaned_key = api_key.strip()
|
|
251
|
+
|
|
252
|
+
if len(cleaned_key) < 10:
|
|
253
|
+
raise ValueError("API key appears to be too short")
|
|
254
|
+
|
|
255
|
+
if len(cleaned_key) > 200:
|
|
256
|
+
raise ValueError("API key appears to be too long")
|
|
257
|
+
|
|
258
|
+
# Check for potentially invalid characters
|
|
259
|
+
if not re.match(r"^[a-zA-Z0-9_-]+$", cleaned_key):
|
|
260
|
+
raise ValueError(
|
|
261
|
+
"API key contains invalid characters. Only letters, numbers, hyphens, and underscores are allowed."
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return cleaned_key
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: glaip-sdk
|
|
3
|
+
Version: 0.0.0b99
|
|
4
|
+
Summary: Python SDK and CLI for GL AIP (GDP Labs AI Agent Package) - Build, run, and manage AI agents
|
|
5
|
+
Author-email: Raymond Christopher <raymond.christopher@gdplabs.id>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: <3.13,>=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: httpx>=0.28.1
|
|
10
|
+
Requires-Dist: pydantic>=2.0.0
|
|
11
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
12
|
+
Requires-Dist: python-dotenv<2.0.0,>=1.1.1
|
|
13
|
+
Requires-Dist: readchar<5.0.0,>=4.2.1
|
|
14
|
+
Requires-Dist: questionary<3.0.0,>=2.1.0
|
|
15
|
+
Requires-Dist: click<8.3.0,>=8.2.0
|
|
16
|
+
Requires-Dist: rich>=13.0.0
|
|
17
|
+
Requires-Dist: packaging>=23.2
|
|
18
|
+
Requires-Dist: textual>=0.52.0
|
|
19
|
+
Requires-Dist: gllm-core-binary>=0.1.0
|
|
20
|
+
Requires-Dist: langchain-core>=0.3.0
|
|
21
|
+
Requires-Dist: gllm-tools-binary>=0.1.3
|
|
22
|
+
Provides-Extra: local
|
|
23
|
+
Requires-Dist: aip-agents-binary[local]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
|
|
24
|
+
Provides-Extra: memory
|
|
25
|
+
Requires-Dist: aip-agents-binary[memory]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
|
|
26
|
+
Provides-Extra: privacy
|
|
27
|
+
Requires-Dist: aip-agents-binary[privacy]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-dotenv>=0.5.2; extra == "dev"
|
|
32
|
+
Requires-Dist: pre-commit>=4.3.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-xdist>=3.8.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.23.6; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-timeout>=2.3.1; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff>=0.14.0; extra == "dev"
|
|
37
|
+
|
|
38
|
+
# GL AIP β GDP Labs AI Agents Package
|
|
39
|
+
|
|
40
|
+
[](https://www.python.org/downloads/)
|
|
41
|
+
[](https://github.com/psf/black)
|
|
42
|
+
|
|
43
|
+
GL stands for **GDP Labs**βGL AIP is our AI Agents Package for building, running, and operating agents.
|
|
44
|
+
|
|
45
|
+
> **Python SDK and CLI for GL AIP - Connect, configure, and manage AI agents on the GDP Labs AI Agents Package.**
|
|
46
|
+
|
|
47
|
+
## π Quick Start
|
|
48
|
+
|
|
49
|
+
### Installation
|
|
50
|
+
|
|
51
|
+
Installing `glaip-sdk` provides both the **Python SDK** and the **`aip` CLI command** in a single package.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Using pip (recommended)
|
|
55
|
+
pip install --upgrade glaip-sdk
|
|
56
|
+
|
|
57
|
+
# Using uv (fast alternative)
|
|
58
|
+
uv tool install glaip-sdk
|
|
59
|
+
|
|
60
|
+
# Using pipx (CLI-focused, isolated environment)
|
|
61
|
+
pipx install glaip-sdk
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Requirements**: Python 3.11 or 3.12
|
|
65
|
+
|
|
66
|
+
**Updating**: The `aip` CLI automatically detects your installation method and uses the correct update command:
|
|
67
|
+
|
|
68
|
+
- If installed via `pip`: Uses `pip install --upgrade glaip-sdk`
|
|
69
|
+
- If installed via `uv tool install`: Uses `uv tool install --upgrade glaip-sdk`
|
|
70
|
+
- You can also update manually using the same command you used to install
|
|
71
|
+
|
|
72
|
+
## π Hello World - Python SDK
|
|
73
|
+
|
|
74
|
+
Perfect for building applications and integrations.
|
|
75
|
+
|
|
76
|
+
### Step 1: Environment Setup
|
|
77
|
+
|
|
78
|
+
Create a `.env` file:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# .env
|
|
82
|
+
AIP_API_URL=https://your-gl-aip-instance.com
|
|
83
|
+
AIP_API_KEY=your-api-key
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Step 2: Basic Python Script
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# hello_world.py
|
|
90
|
+
from glaip_sdk import Client
|
|
91
|
+
import os
|
|
92
|
+
from dotenv import load_dotenv
|
|
93
|
+
|
|
94
|
+
# Load environment variables
|
|
95
|
+
load_dotenv()
|
|
96
|
+
|
|
97
|
+
# Initialize client
|
|
98
|
+
client = Client()
|
|
99
|
+
|
|
100
|
+
# Create a simple agent
|
|
101
|
+
agent = client.agents.create(
|
|
102
|
+
name="hello-sdk",
|
|
103
|
+
instruction="You are a helpful assistant who responds clearly and concisely."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Run the agent
|
|
107
|
+
result = agent.run("Hello world, what's 2+2?")
|
|
108
|
+
|
|
109
|
+
print(f"Agent response: {result}")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Step 3: Run Your Script
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
python hello_world.py
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Step 4: Advanced Example with Streaming
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# streaming_example.py
|
|
122
|
+
from glaip_sdk import Client
|
|
123
|
+
import os
|
|
124
|
+
from dotenv import load_dotenv
|
|
125
|
+
|
|
126
|
+
load_dotenv()
|
|
127
|
+
client = Client()
|
|
128
|
+
|
|
129
|
+
# Create agent with streaming
|
|
130
|
+
agent = client.agents.create(
|
|
131
|
+
name="streaming-agent",
|
|
132
|
+
instruction="You are a helpful assistant. Provide detailed responses."
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Stream the response
|
|
136
|
+
print("Streaming response:")
|
|
137
|
+
client.agents.run_agent(
|
|
138
|
+
agent.id,
|
|
139
|
+
"Explain quantum computing in simple terms",
|
|
140
|
+
verbose=True,
|
|
141
|
+
)
|
|
142
|
+
print("--- Stream complete ---")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
π **SDK Success!** You're now ready to build AI-powered applications with Python.
|
|
146
|
+
|
|
147
|
+
______________________________________________________________________
|
|
148
|
+
|
|
149
|
+
## π» Hello World - CLI
|
|
150
|
+
|
|
151
|
+
Perfect for quick testing and command-line workflows.
|
|
152
|
+
|
|
153
|
+
### Step 1: Configure Connection
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Interactive setup (recommended)
|
|
157
|
+
aip configure
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Or set environment variables:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
export AIP_API_URL="https://your-gl-aip-instance.com"
|
|
164
|
+
export AIP_API_KEY="your-api-key"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Step 2: Verify Connection
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
aip status
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Step 3: Create & Run Your First Agent
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Create a simple agent
|
|
177
|
+
aip agents create --name "hello-cli" --instruction "You are a helpful assistant"
|
|
178
|
+
|
|
179
|
+
# List agents to get the ID
|
|
180
|
+
aip agents list
|
|
181
|
+
|
|
182
|
+
# Run the agent with input
|
|
183
|
+
aip agents run <AGENT_ID> --input "Hello world, what's the weather like?"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
π **CLI Success!** You're now ready to use the CLI for AI agent workflows.
|
|
187
|
+
|
|
188
|
+
## β¨ Key Features
|
|
189
|
+
|
|
190
|
+
- **π€ Agent Management**: Create, run, and orchestrate AI agents with custom instructions and streaming
|
|
191
|
+
- **π§ Language Models**: Choose from multiple AI models per agent with manual PII tag mapping
|
|
192
|
+
- **π οΈ Tool Integration**: Extend agents with custom Python tools and script management
|
|
193
|
+
- **π MCP Support**: Connect external services through Model Context Protocols with tool discovery
|
|
194
|
+
- **π Multi-Agent Patterns**: Hierarchical, parallel, sequential, router, and aggregator patterns
|
|
195
|
+
- **π» Modern CLI**: Rich terminal interface with fuzzy search and multiple output formats
|
|
196
|
+
|
|
197
|
+
## π³ Live Steps Panel
|
|
198
|
+
|
|
199
|
+
The CLI steps panel now streams a fully hierarchical tree so you can audit complex agent runs without leaving the terminal.
|
|
200
|
+
|
|
201
|
+
- Renders parent/child relationships with `βββ` connectors, even when events arrive out of order
|
|
202
|
+
- Marks running steps with spinners and duration badges sourced from SSE metadata before local fallbacks
|
|
203
|
+
- Highlights failures inline (`β reason`) and raises warning glyphs on affected delegate branches
|
|
204
|
+
- Derives deterministic βπ Thinkingβ¦β spans before/after each delegate or tool action to show scheduling gaps
|
|
205
|
+
- Flags parallel work with a dedicated glyph and argument-derived labels so simultaneous tool calls stay readable
|
|
206
|
+
- Try it locally: `poetry run python scripts/replay_steps_log.py --transcript tests/fixtures/rendering/transcripts/parallel_research.jsonl --output /tmp/parallel.log`
|
|
207
|
+
|
|
208
|
+
## π Documentation
|
|
209
|
+
|
|
210
|
+
π **[Complete Documentation](https://gdplabs.gitbook.io/gl-aip/gl-aip-sdk/overview)** - Visit our GitBook for comprehensive guides, tutorials, and API reference.
|
|
211
|
+
|
|
212
|
+
Quick links:
|
|
213
|
+
|
|
214
|
+
- **[Quick Start Guide](https://gdplabs.gitbook.io/gl-aip/gl-aip-sdk/get-started/quick-start-guide)**: Get your first agent running in 5 minutes
|
|
215
|
+
- **[Agent Management](https://gdplabs.gitbook.io/gl-aip/gl-aip-sdk/guides/agents-guide)**: Complete agent lifecycle management
|
|
216
|
+
- **[Custom Tools](https://gdplabs.gitbook.io/gl-aip/gl-aip-sdk/guides/tools-guide)**: Build and integrate custom tools
|
|
217
|
+
- **[MCP Integration](https://gdplabs.gitbook.io/gl-aip/gl-aip-sdk/guides/mcps-guide)**: Connect external services
|
|
218
|
+
- **[API Reference](https://gdplabs.gitbook.io/gl-aip/gl-aip-sdk/reference/python-sdk-reference)**: Complete SDK reference
|
|
219
|
+
|
|
220
|
+
## π§ͺ Simulate the Update Notifier
|
|
221
|
+
|
|
222
|
+
Need to verify the in-session upgrade flow without hitting PyPI or actually running `pip install`? Use the bundled helper:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
cd python/glaip-sdk
|
|
226
|
+
poetry run python scripts/mock_update_notifier.py
|
|
227
|
+
# or customize the mock payload:
|
|
228
|
+
# poetry run python scripts/mock_update_notifier.py --version 3.3.3 --marker "[nightly build]"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The script:
|
|
232
|
+
|
|
233
|
+
- Launches a SlashSession with prompt-toolkit disabled (so it runs cleanly in tests/CI).
|
|
234
|
+
- Forces the notifier to believe a newer version exists (`--version 9.9.9` by default).
|
|
235
|
+
- Appends a visible marker (default `[mock update]`) to the banner so you can prove the branding reload happened; pass `--marker ""` to skip.
|
|
236
|
+
- Auto-selects βUpdate nowβ, mocks the install step, and runs the real branding refresh logic.
|
|
237
|
+
- Resets module metadata afterwards so your environment remains untouched.
|
|
238
|
+
|
|
239
|
+
You should see the Rich banner re-render with the mocked version (and optional marker) at the end of the run.
|