glaip-sdk 0.6.12__py3-none-any.whl → 0.6.15__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 +42 -5
- {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.15.dist-info}/METADATA +32 -37
- glaip_sdk-0.6.15.dist-info/RECORD +12 -0
- {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.15.dist-info}/WHEEL +2 -1
- glaip_sdk-0.6.15.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.6.15.dist-info/top_level.txt +1 -0
- glaip_sdk/agents/__init__.py +0 -27
- glaip_sdk/agents/base.py +0 -1191
- glaip_sdk/cli/__init__.py +0 -9
- glaip_sdk/cli/account_store.py +0 -540
- glaip_sdk/cli/agent_config.py +0 -78
- glaip_sdk/cli/auth.py +0 -699
- glaip_sdk/cli/commands/__init__.py +0 -5
- glaip_sdk/cli/commands/accounts.py +0 -746
- glaip_sdk/cli/commands/agents.py +0 -1509
- glaip_sdk/cli/commands/common_config.py +0 -101
- glaip_sdk/cli/commands/configure.py +0 -896
- glaip_sdk/cli/commands/mcps.py +0 -1356
- glaip_sdk/cli/commands/models.py +0 -69
- glaip_sdk/cli/commands/tools.py +0 -576
- glaip_sdk/cli/commands/transcripts.py +0 -755
- glaip_sdk/cli/commands/update.py +0 -61
- glaip_sdk/cli/config.py +0 -95
- glaip_sdk/cli/constants.py +0 -38
- glaip_sdk/cli/context.py +0 -150
- glaip_sdk/cli/core/__init__.py +0 -79
- glaip_sdk/cli/core/context.py +0 -124
- glaip_sdk/cli/core/output.py +0 -846
- glaip_sdk/cli/core/prompting.py +0 -649
- glaip_sdk/cli/core/rendering.py +0 -187
- glaip_sdk/cli/display.py +0 -355
- glaip_sdk/cli/hints.py +0 -57
- glaip_sdk/cli/io.py +0 -112
- glaip_sdk/cli/main.py +0 -604
- glaip_sdk/cli/masking.py +0 -136
- glaip_sdk/cli/mcp_validators.py +0 -287
- glaip_sdk/cli/pager.py +0 -266
- glaip_sdk/cli/parsers/__init__.py +0 -7
- glaip_sdk/cli/parsers/json_input.py +0 -177
- glaip_sdk/cli/resolution.py +0 -67
- glaip_sdk/cli/rich_helpers.py +0 -27
- glaip_sdk/cli/slash/__init__.py +0 -15
- glaip_sdk/cli/slash/accounts_controller.py +0 -578
- glaip_sdk/cli/slash/accounts_shared.py +0 -75
- glaip_sdk/cli/slash/agent_session.py +0 -285
- glaip_sdk/cli/slash/prompt.py +0 -256
- glaip_sdk/cli/slash/remote_runs_controller.py +0 -566
- glaip_sdk/cli/slash/session.py +0 -1708
- glaip_sdk/cli/slash/tui/__init__.py +0 -9
- glaip_sdk/cli/slash/tui/accounts_app.py +0 -876
- glaip_sdk/cli/slash/tui/background_tasks.py +0 -72
- glaip_sdk/cli/slash/tui/loading.py +0 -58
- glaip_sdk/cli/slash/tui/remote_runs_app.py +0 -628
- glaip_sdk/cli/transcript/__init__.py +0 -31
- glaip_sdk/cli/transcript/cache.py +0 -536
- glaip_sdk/cli/transcript/capture.py +0 -329
- glaip_sdk/cli/transcript/export.py +0 -38
- glaip_sdk/cli/transcript/history.py +0 -815
- glaip_sdk/cli/transcript/launcher.py +0 -77
- glaip_sdk/cli/transcript/viewer.py +0 -374
- glaip_sdk/cli/update_notifier.py +0 -290
- glaip_sdk/cli/utils.py +0 -263
- glaip_sdk/cli/validators.py +0 -238
- glaip_sdk/client/__init__.py +0 -11
- glaip_sdk/client/_agent_payloads.py +0 -520
- glaip_sdk/client/agent_runs.py +0 -147
- glaip_sdk/client/agents.py +0 -1335
- glaip_sdk/client/base.py +0 -502
- glaip_sdk/client/main.py +0 -249
- glaip_sdk/client/mcps.py +0 -370
- glaip_sdk/client/run_rendering.py +0 -700
- glaip_sdk/client/shared.py +0 -21
- glaip_sdk/client/tools.py +0 -661
- glaip_sdk/client/validators.py +0 -198
- glaip_sdk/config/constants.py +0 -52
- glaip_sdk/mcps/__init__.py +0 -21
- glaip_sdk/mcps/base.py +0 -345
- glaip_sdk/models/__init__.py +0 -90
- glaip_sdk/models/agent.py +0 -47
- glaip_sdk/models/agent_runs.py +0 -116
- glaip_sdk/models/common.py +0 -42
- glaip_sdk/models/mcp.py +0 -33
- glaip_sdk/models/tool.py +0 -33
- glaip_sdk/payload_schemas/__init__.py +0 -7
- glaip_sdk/payload_schemas/agent.py +0 -85
- glaip_sdk/registry/__init__.py +0 -55
- glaip_sdk/registry/agent.py +0 -164
- glaip_sdk/registry/base.py +0 -139
- glaip_sdk/registry/mcp.py +0 -253
- glaip_sdk/registry/tool.py +0 -232
- glaip_sdk/runner/__init__.py +0 -59
- glaip_sdk/runner/base.py +0 -84
- glaip_sdk/runner/deps.py +0 -115
- glaip_sdk/runner/langgraph.py +0 -782
- glaip_sdk/runner/mcp_adapter/__init__.py +0 -13
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +0 -43
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +0 -257
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +0 -95
- glaip_sdk/runner/tool_adapter/__init__.py +0 -18
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +0 -44
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +0 -219
- glaip_sdk/tools/__init__.py +0 -22
- glaip_sdk/tools/base.py +0 -435
- glaip_sdk/utils/__init__.py +0 -86
- glaip_sdk/utils/a2a/__init__.py +0 -34
- glaip_sdk/utils/a2a/event_processor.py +0 -188
- glaip_sdk/utils/agent_config.py +0 -194
- glaip_sdk/utils/bundler.py +0 -267
- glaip_sdk/utils/client.py +0 -111
- glaip_sdk/utils/client_utils.py +0 -486
- glaip_sdk/utils/datetime_helpers.py +0 -58
- glaip_sdk/utils/discovery.py +0 -78
- glaip_sdk/utils/display.py +0 -135
- glaip_sdk/utils/export.py +0 -143
- glaip_sdk/utils/general.py +0 -61
- glaip_sdk/utils/import_export.py +0 -168
- glaip_sdk/utils/import_resolver.py +0 -492
- glaip_sdk/utils/instructions.py +0 -101
- glaip_sdk/utils/rendering/__init__.py +0 -115
- glaip_sdk/utils/rendering/formatting.py +0 -264
- glaip_sdk/utils/rendering/layout/__init__.py +0 -64
- glaip_sdk/utils/rendering/layout/panels.py +0 -156
- glaip_sdk/utils/rendering/layout/progress.py +0 -202
- glaip_sdk/utils/rendering/layout/summary.py +0 -74
- glaip_sdk/utils/rendering/layout/transcript.py +0 -606
- glaip_sdk/utils/rendering/models.py +0 -85
- glaip_sdk/utils/rendering/renderer/__init__.py +0 -55
- glaip_sdk/utils/rendering/renderer/base.py +0 -1024
- glaip_sdk/utils/rendering/renderer/config.py +0 -27
- glaip_sdk/utils/rendering/renderer/console.py +0 -55
- glaip_sdk/utils/rendering/renderer/debug.py +0 -178
- glaip_sdk/utils/rendering/renderer/factory.py +0 -138
- glaip_sdk/utils/rendering/renderer/stream.py +0 -202
- glaip_sdk/utils/rendering/renderer/summary_window.py +0 -79
- glaip_sdk/utils/rendering/renderer/thinking.py +0 -273
- glaip_sdk/utils/rendering/renderer/toggle.py +0 -182
- glaip_sdk/utils/rendering/renderer/tool_panels.py +0 -442
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +0 -162
- glaip_sdk/utils/rendering/state.py +0 -204
- glaip_sdk/utils/rendering/step_tree_state.py +0 -100
- glaip_sdk/utils/rendering/steps/__init__.py +0 -34
- glaip_sdk/utils/rendering/steps/event_processor.py +0 -778
- glaip_sdk/utils/rendering/steps/format.py +0 -176
- glaip_sdk/utils/rendering/steps/manager.py +0 -387
- glaip_sdk/utils/rendering/timing.py +0 -36
- glaip_sdk/utils/rendering/viewer/__init__.py +0 -21
- glaip_sdk/utils/rendering/viewer/presenter.py +0 -184
- glaip_sdk/utils/resource_refs.py +0 -195
- glaip_sdk/utils/run_renderer.py +0 -41
- glaip_sdk/utils/runtime_config.py +0 -425
- glaip_sdk/utils/serialization.py +0 -424
- glaip_sdk/utils/sync.py +0 -142
- glaip_sdk/utils/tool_detection.py +0 -33
- glaip_sdk/utils/validation.py +0 -264
- glaip_sdk-0.6.12.dist-info/RECORD +0 -159
- glaip_sdk-0.6.12.dist-info/entry_points.txt +0 -3
glaip_sdk/utils/discovery.py
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"""Agent and tool discovery functions.
|
|
2
|
-
|
|
3
|
-
This module provides functions for finding agents and tools
|
|
4
|
-
from the GLAIP backend.
|
|
5
|
-
|
|
6
|
-
Authors:
|
|
7
|
-
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
from typing import TYPE_CHECKING
|
|
13
|
-
|
|
14
|
-
from gllm_core.utils import LoggerManager
|
|
15
|
-
|
|
16
|
-
if TYPE_CHECKING:
|
|
17
|
-
from glaip_sdk.agents import Agent
|
|
18
|
-
from glaip_sdk.tools import Tool
|
|
19
|
-
|
|
20
|
-
logger = LoggerManager().get_logger(__name__)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def find_agent(name: str) -> Agent | None:
|
|
24
|
-
"""Find an agent by name using GLAIP SDK.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
name: The name of the agent to find.
|
|
28
|
-
|
|
29
|
-
Returns:
|
|
30
|
-
The agent if found, None otherwise.
|
|
31
|
-
|
|
32
|
-
Example:
|
|
33
|
-
>>> from glaip_sdk.utils.discovery import find_agent
|
|
34
|
-
>>> agent = find_agent("weather_reporter")
|
|
35
|
-
>>> if agent:
|
|
36
|
-
... print(f"Found agent: {agent.name}")
|
|
37
|
-
"""
|
|
38
|
-
from glaip_sdk.utils.client import get_client # noqa: PLC0415
|
|
39
|
-
|
|
40
|
-
client = get_client()
|
|
41
|
-
try:
|
|
42
|
-
agents = client.list_agents()
|
|
43
|
-
for agent in agents:
|
|
44
|
-
if agent.name == name:
|
|
45
|
-
return agent
|
|
46
|
-
return None
|
|
47
|
-
except Exception as e:
|
|
48
|
-
logger.error("Error finding agent '%s': %s", name, e)
|
|
49
|
-
return None
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def find_tool(name: str) -> Tool | None:
|
|
53
|
-
"""Find a tool by name using GLAIP SDK.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
name: The name of the tool to find.
|
|
57
|
-
|
|
58
|
-
Returns:
|
|
59
|
-
The tool if found, None otherwise.
|
|
60
|
-
|
|
61
|
-
Example:
|
|
62
|
-
>>> from glaip_sdk.utils.discovery import find_tool
|
|
63
|
-
>>> tool = find_tool("weather_api")
|
|
64
|
-
>>> if tool:
|
|
65
|
-
... print(f"Found tool: {tool.name}")
|
|
66
|
-
"""
|
|
67
|
-
from glaip_sdk.utils.client import get_client # noqa: PLC0415
|
|
68
|
-
|
|
69
|
-
client = get_client()
|
|
70
|
-
try:
|
|
71
|
-
tools = client.find_tools(name)
|
|
72
|
-
for tool in tools:
|
|
73
|
-
if tool.name == name:
|
|
74
|
-
return tool
|
|
75
|
-
return None
|
|
76
|
-
except Exception as e:
|
|
77
|
-
logger.error("Error finding tool '%s': %s", name, e)
|
|
78
|
-
return None
|
glaip_sdk/utils/display.py
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"""Rich display utilities for enhanced output.
|
|
2
|
-
|
|
3
|
-
Authors:
|
|
4
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from importlib import import_module
|
|
10
|
-
from typing import TYPE_CHECKING, Any
|
|
11
|
-
|
|
12
|
-
from glaip_sdk.branding import SUCCESS, SUCCESS_STYLE
|
|
13
|
-
from glaip_sdk.icons import ICON_AGENT
|
|
14
|
-
|
|
15
|
-
if TYPE_CHECKING: # pragma: no cover - import-time typing helpers
|
|
16
|
-
from rich.console import Console
|
|
17
|
-
from rich.text import Text
|
|
18
|
-
|
|
19
|
-
from glaip_sdk.rich_components import AIPanel
|
|
20
|
-
else: # pragma: no cover - runtime fallback for type checking
|
|
21
|
-
AIPanel = Any # type: ignore[assignment]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _check_rich_available() -> bool:
|
|
25
|
-
"""Return True when core Rich display dependencies are importable."""
|
|
26
|
-
try:
|
|
27
|
-
__import__("rich.console")
|
|
28
|
-
__import__("rich.text")
|
|
29
|
-
__import__("glaip_sdk.rich_components")
|
|
30
|
-
except Exception:
|
|
31
|
-
return False
|
|
32
|
-
return True
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
RICH_AVAILABLE = _check_rich_available()
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _create_console() -> Console:
|
|
39
|
-
"""Return a Console instance with lazy import to ease mocking."""
|
|
40
|
-
if not RICH_AVAILABLE: # pragma: no cover - defensive guard
|
|
41
|
-
raise RuntimeError("Rich Console is not available")
|
|
42
|
-
console_module = import_module("rich.console")
|
|
43
|
-
return console_module.Console()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _create_text(*args: Any, **kwargs: Any) -> Text:
|
|
47
|
-
"""Return a Text instance with lazy import to ease mocking."""
|
|
48
|
-
if not RICH_AVAILABLE: # pragma: no cover - defensive guard
|
|
49
|
-
raise RuntimeError("Rich Text is not available")
|
|
50
|
-
text_module = import_module("rich.text")
|
|
51
|
-
return text_module.Text(*args, **kwargs)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _create_panel(*args: Any, **kwargs: Any) -> AIPanel:
|
|
55
|
-
"""Return an AIPPanel instance with lazy import to ease mocking."""
|
|
56
|
-
if not RICH_AVAILABLE: # pragma: no cover - defensive guard
|
|
57
|
-
raise RuntimeError("AIPPanel is not available")
|
|
58
|
-
components = import_module("glaip_sdk.rich_components")
|
|
59
|
-
return components.AIPPanel(*args, **kwargs)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def print_agent_output(output: str, title: str = "Agent Output") -> None:
|
|
63
|
-
"""Print agent output with rich formatting.
|
|
64
|
-
|
|
65
|
-
Args:
|
|
66
|
-
output: The agent's response text
|
|
67
|
-
title: Title for the output panel
|
|
68
|
-
"""
|
|
69
|
-
if RICH_AVAILABLE:
|
|
70
|
-
console = _create_console()
|
|
71
|
-
panel = _create_panel(
|
|
72
|
-
_create_text(output, style=SUCCESS),
|
|
73
|
-
title=title,
|
|
74
|
-
border_style=SUCCESS,
|
|
75
|
-
)
|
|
76
|
-
console.print(panel)
|
|
77
|
-
else:
|
|
78
|
-
print(f"\n=== {title} ===")
|
|
79
|
-
print(output)
|
|
80
|
-
print("=" * (len(title) + 8))
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def print_agent_created(agent: Any, title: str = f"{ICON_AGENT} Agent Created") -> None:
|
|
84
|
-
"""Print agent creation success with rich formatting.
|
|
85
|
-
|
|
86
|
-
Args:
|
|
87
|
-
agent: The created agent object
|
|
88
|
-
title: Title for the output panel
|
|
89
|
-
"""
|
|
90
|
-
if RICH_AVAILABLE:
|
|
91
|
-
console = _create_console()
|
|
92
|
-
panel = _create_panel(
|
|
93
|
-
f"[{SUCCESS_STYLE}]✅ Agent '{agent.name}' created successfully![/]\n\n"
|
|
94
|
-
f"ID: {agent.id}\n"
|
|
95
|
-
f"Model: {getattr(agent, 'model', 'N/A')}\n"
|
|
96
|
-
f"Type: {getattr(agent, 'type', 'config')}\n"
|
|
97
|
-
f"Framework: {getattr(agent, 'framework', 'langchain')}\n"
|
|
98
|
-
f"Version: {getattr(agent, 'version', '1.0')}",
|
|
99
|
-
title=title,
|
|
100
|
-
border_style=SUCCESS,
|
|
101
|
-
)
|
|
102
|
-
console.print(panel)
|
|
103
|
-
else:
|
|
104
|
-
print(f"✅ Agent '{agent.name}' created successfully!")
|
|
105
|
-
print(f"ID: {agent.id}")
|
|
106
|
-
print(f"Model: {getattr(agent, 'model', 'N/A')}")
|
|
107
|
-
print(f"Type: {getattr(agent, 'type', 'config')}")
|
|
108
|
-
print(f"Framework: {getattr(agent, 'framework', 'langchain')}")
|
|
109
|
-
print(f"Version: {getattr(agent, 'version', '1.0')}")
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def print_agent_updated(agent: Any) -> None:
|
|
113
|
-
"""Print agent update success with rich formatting.
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
agent: The updated agent object
|
|
117
|
-
"""
|
|
118
|
-
if RICH_AVAILABLE:
|
|
119
|
-
console = _create_console()
|
|
120
|
-
console.print(f"[{SUCCESS_STYLE}]✅ Agent '{agent.name}' updated successfully[/]")
|
|
121
|
-
else:
|
|
122
|
-
print(f"✅ Agent '{agent.name}' updated successfully")
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def print_agent_deleted(agent_id: str) -> None:
|
|
126
|
-
"""Print agent deletion success with rich formatting.
|
|
127
|
-
|
|
128
|
-
Args:
|
|
129
|
-
agent_id: The deleted agent's ID
|
|
130
|
-
"""
|
|
131
|
-
if RICH_AVAILABLE:
|
|
132
|
-
console = _create_console()
|
|
133
|
-
console.print(f"[{SUCCESS_STYLE}]✅ Agent deleted successfully (ID: {agent_id})[/]")
|
|
134
|
-
else:
|
|
135
|
-
print(f"✅ Agent deleted successfully (ID: {agent_id})")
|
glaip_sdk/utils/export.py
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Export utilities for remote agent run transcripts.
|
|
3
|
-
|
|
4
|
-
Authors:
|
|
5
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import json
|
|
9
|
-
from datetime import datetime
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
12
|
-
|
|
13
|
-
from glaip_sdk.models.agent_runs import RunWithOutput, RunOutputChunk
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def export_remote_transcript_jsonl(
|
|
17
|
-
run: RunWithOutput,
|
|
18
|
-
destination: Path,
|
|
19
|
-
*,
|
|
20
|
-
overwrite: bool = False,
|
|
21
|
-
agent_name: str | None = None,
|
|
22
|
-
model: str | None = None,
|
|
23
|
-
) -> Path:
|
|
24
|
-
"""Export a remote run transcript to JSONL format compatible with local transcript viewers.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
run: RunWithOutput instance to export
|
|
28
|
-
destination: Target file path for JSONL export
|
|
29
|
-
overwrite: Whether to overwrite existing file
|
|
30
|
-
agent_name: Optional agent name for metadata
|
|
31
|
-
model: Optional model name for metadata (extracted from run.config if not provided)
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
Path to the exported file
|
|
35
|
-
|
|
36
|
-
Raises:
|
|
37
|
-
FileExistsError: If destination exists and overwrite is False
|
|
38
|
-
OSError: If file cannot be written
|
|
39
|
-
"""
|
|
40
|
-
if destination.exists() and not overwrite:
|
|
41
|
-
raise FileExistsError(f"File already exists: {destination}")
|
|
42
|
-
|
|
43
|
-
# Ensure parent directory exists
|
|
44
|
-
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
45
|
-
|
|
46
|
-
model_name = model or _extract_model(run)
|
|
47
|
-
final_output_text = _extract_final_output(run.output) or ""
|
|
48
|
-
|
|
49
|
-
meta_payload = _build_meta_payload(run, agent_name, model_name)
|
|
50
|
-
meta_record = _build_meta_record(run, agent_name, model_name, final_output_text, meta_payload)
|
|
51
|
-
|
|
52
|
-
_write_jsonl_file(destination, meta_record, run.output)
|
|
53
|
-
|
|
54
|
-
return destination
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _build_meta_payload(run: RunWithOutput, agent_name: str | None, model_name: str | None) -> dict[str, Any]:
|
|
58
|
-
"""Build the meta payload dictionary."""
|
|
59
|
-
return {
|
|
60
|
-
"agent_name": agent_name,
|
|
61
|
-
"model": model_name,
|
|
62
|
-
"input_message": run.input,
|
|
63
|
-
"status": run.status,
|
|
64
|
-
"run_type": run.run_type,
|
|
65
|
-
"schedule_id": str(run.schedule_id) if run.schedule_id else None,
|
|
66
|
-
"config": run.config or {},
|
|
67
|
-
"created_at": run.created_at.isoformat() if run.created_at else None,
|
|
68
|
-
"updated_at": run.updated_at.isoformat() if run.updated_at else None,
|
|
69
|
-
"event_count": len(run.output),
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _build_meta_record(
|
|
74
|
-
run: RunWithOutput,
|
|
75
|
-
agent_name: str | None,
|
|
76
|
-
model_name: str | None,
|
|
77
|
-
final_output_text: str,
|
|
78
|
-
meta_payload: dict[str, Any],
|
|
79
|
-
) -> dict[str, Any]:
|
|
80
|
-
"""Build the meta record dictionary."""
|
|
81
|
-
return {
|
|
82
|
-
"type": "meta",
|
|
83
|
-
"run_id": str(run.id),
|
|
84
|
-
"agent_id": str(run.agent_id),
|
|
85
|
-
"agent_name": agent_name,
|
|
86
|
-
"model": model_name,
|
|
87
|
-
"created_at": run.created_at.isoformat() if run.created_at else None,
|
|
88
|
-
"default_output": final_output_text,
|
|
89
|
-
"final_output": final_output_text,
|
|
90
|
-
"server_run_id": str(run.id),
|
|
91
|
-
"started_at": run.started_at.isoformat() if run.started_at else None,
|
|
92
|
-
"finished_at": run.completed_at.isoformat() if run.completed_at else None,
|
|
93
|
-
"meta": meta_payload,
|
|
94
|
-
"source": "remote_history",
|
|
95
|
-
# Back-compat fields used by older tooling
|
|
96
|
-
"run_type": run.run_type,
|
|
97
|
-
"schedule_id": str(run.schedule_id) if run.schedule_id else None,
|
|
98
|
-
"status": run.status,
|
|
99
|
-
"input": run.input,
|
|
100
|
-
"config": run.config or {},
|
|
101
|
-
"updated_at": run.updated_at.isoformat() if run.updated_at else None,
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def _write_jsonl_file(destination: Path, meta_record: dict[str, Any], events: list[RunOutputChunk]) -> None:
|
|
106
|
-
"""Write the JSONL file with meta and event records."""
|
|
107
|
-
records: list[dict[str, Any]] = [meta_record]
|
|
108
|
-
records.extend({"type": "event", "event": event} for event in events)
|
|
109
|
-
|
|
110
|
-
with destination.open("w", encoding="utf-8") as fh:
|
|
111
|
-
for idx, record in enumerate(records):
|
|
112
|
-
json.dump(record, fh, ensure_ascii=False, indent=2, default=_json_default)
|
|
113
|
-
fh.write("\n")
|
|
114
|
-
if idx != len(records) - 1:
|
|
115
|
-
fh.write("\n")
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def _extract_model(run: RunWithOutput) -> str | None:
|
|
119
|
-
"""Best-effort extraction of the model name from run metadata."""
|
|
120
|
-
config = run.config or {}
|
|
121
|
-
if isinstance(config, dict):
|
|
122
|
-
model = config.get("model") or config.get("llm", {}).get("model")
|
|
123
|
-
if isinstance(model, str):
|
|
124
|
-
return model
|
|
125
|
-
return None
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def _extract_final_output(events: list[RunOutputChunk]) -> str | None:
|
|
129
|
-
"""Return the final response content from the event stream."""
|
|
130
|
-
for chunk in reversed(events):
|
|
131
|
-
content = chunk.get("content")
|
|
132
|
-
if not content:
|
|
133
|
-
continue
|
|
134
|
-
if chunk.get("event_type") == "final_response" or chunk.get("final"):
|
|
135
|
-
return str(content)
|
|
136
|
-
return None
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def _json_default(obj: Any) -> Any:
|
|
140
|
-
"""JSON serializer for datetime objects."""
|
|
141
|
-
if isinstance(obj, datetime):
|
|
142
|
-
return obj.isoformat()
|
|
143
|
-
raise TypeError(f"Type {type(obj)} not serializable")
|
glaip_sdk/utils/general.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"""General utility functions for AIP SDK.
|
|
2
|
-
|
|
3
|
-
Authors:
|
|
4
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from collections.abc import Iterable, Iterator
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
from typing import Any
|
|
10
|
-
|
|
11
|
-
import click
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def format_file_size(size_bytes: int) -> str:
|
|
15
|
-
"""Format file size in human readable format.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
size_bytes: Size in bytes
|
|
19
|
-
|
|
20
|
-
Returns:
|
|
21
|
-
Human readable size string (e.g., "1.5 MB")
|
|
22
|
-
"""
|
|
23
|
-
for unit in ["B", "KB", "MB", "GB"]:
|
|
24
|
-
if size_bytes < 1024.0:
|
|
25
|
-
return f"{size_bytes:.1f} {unit}"
|
|
26
|
-
size_bytes /= 1024.0
|
|
27
|
-
return f"{size_bytes:.1f} TB"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def format_datetime(dt: datetime | str | None) -> str:
|
|
31
|
-
"""Format datetime object to readable string.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
dt: Datetime object or string to format
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
Formatted datetime string or "N/A" if None
|
|
38
|
-
"""
|
|
39
|
-
if isinstance(dt, datetime):
|
|
40
|
-
return dt.strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
41
|
-
elif dt is None:
|
|
42
|
-
return "N/A"
|
|
43
|
-
return str(dt)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def progress_bar(iterable: Iterable[Any], description: str = "Processing") -> Iterator[Any]:
|
|
47
|
-
"""Simple progress bar using click.
|
|
48
|
-
|
|
49
|
-
Args:
|
|
50
|
-
iterable: Iterable to process
|
|
51
|
-
description: Progress description
|
|
52
|
-
|
|
53
|
-
Yields:
|
|
54
|
-
Items from iterable with progress display
|
|
55
|
-
"""
|
|
56
|
-
try:
|
|
57
|
-
with click.progressbar(iterable, label=description) as bar:
|
|
58
|
-
yield from bar
|
|
59
|
-
except ImportError:
|
|
60
|
-
# Fallback if click not available
|
|
61
|
-
yield from iterable
|
glaip_sdk/utils/import_export.py
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
"""Import/export utilities for schema transforms and data merging.
|
|
2
|
-
|
|
3
|
-
This module provides functions for converting between export and import formats,
|
|
4
|
-
merging imported data with CLI arguments, and handling relationship flattening.
|
|
5
|
-
|
|
6
|
-
Authors:
|
|
7
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from typing import Any
|
|
11
|
-
|
|
12
|
-
from glaip_sdk.utils.resource_refs import _extract_id_from_item
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def extract_ids_from_export(items: list[Any]) -> list[str]:
|
|
16
|
-
"""Extract IDs from export format (list of dicts with id/name fields).
|
|
17
|
-
|
|
18
|
-
This function is similar to `extract_ids` in `resource_refs.py` but differs in behavior:
|
|
19
|
-
- This function SKIPS items without IDs (doesn't convert to string)
|
|
20
|
-
- `extract_ids` converts items without IDs to strings as fallback
|
|
21
|
-
|
|
22
|
-
This difference is intentional: export format should only include actual IDs,
|
|
23
|
-
while general resource reference extraction may need fallback string conversion.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
items: List of items (dicts with id/name or strings)
|
|
27
|
-
|
|
28
|
-
Returns:
|
|
29
|
-
List of extracted IDs (only items with actual IDs)
|
|
30
|
-
|
|
31
|
-
Examples:
|
|
32
|
-
extract_ids_from_export([{"id": "123", "name": "tool"}]) -> ["123"]
|
|
33
|
-
extract_ids_from_export(["123", "456"]) -> ["123", "456"]
|
|
34
|
-
extract_ids_from_export([{"name": "tool"}, "123"]) -> ["123"] # Skip items without ID
|
|
35
|
-
"""
|
|
36
|
-
if not items:
|
|
37
|
-
return []
|
|
38
|
-
|
|
39
|
-
ids = []
|
|
40
|
-
for item in items:
|
|
41
|
-
extracted = _extract_id_from_item(item, skip_missing=True)
|
|
42
|
-
if extracted is not None:
|
|
43
|
-
ids.append(extracted)
|
|
44
|
-
|
|
45
|
-
return ids
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def convert_export_to_import_format(
|
|
49
|
-
data: dict[str, Any],
|
|
50
|
-
) -> dict[str, Any]:
|
|
51
|
-
"""Convert export format to import-compatible format (extract IDs from objects).
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
data: Export format data with full objects
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
Import format data with extracted IDs
|
|
58
|
-
|
|
59
|
-
Notes:
|
|
60
|
-
- Converts tools/agents from dict objects to ID lists
|
|
61
|
-
- Preserves all other data unchanged
|
|
62
|
-
"""
|
|
63
|
-
import_data = data.copy()
|
|
64
|
-
|
|
65
|
-
for key in ["tools", "agents", "mcps"]:
|
|
66
|
-
if key in import_data and isinstance(import_data[key], list):
|
|
67
|
-
import_data[key] = extract_ids_from_export(import_data[key])
|
|
68
|
-
|
|
69
|
-
return import_data
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _get_default_array_fields() -> list[str]:
|
|
73
|
-
"""Get default array fields that should be merged."""
|
|
74
|
-
return ["tools", "agents", "mcps"]
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def _should_use_cli_value(cli_value: Any) -> bool:
|
|
78
|
-
"""Check if CLI value should be used."""
|
|
79
|
-
return cli_value is not None and (not isinstance(cli_value, (list, tuple)) or len(cli_value) > 0)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _handle_array_field_merge(key: str, cli_value: Any, import_data: dict[str, Any]) -> Any:
|
|
83
|
-
"""Handle merging of array fields."""
|
|
84
|
-
import_value = import_data[key]
|
|
85
|
-
if isinstance(import_value, list):
|
|
86
|
-
return list(cli_value) + import_value
|
|
87
|
-
else:
|
|
88
|
-
return cli_value
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def _merge_cli_values_with_import(
|
|
92
|
-
merged: dict[str, Any],
|
|
93
|
-
cli_args: dict[str, Any],
|
|
94
|
-
import_data: dict[str, Any],
|
|
95
|
-
array_fields: list[str],
|
|
96
|
-
) -> None:
|
|
97
|
-
"""Merge CLI values into merged dict."""
|
|
98
|
-
for key, cli_value in cli_args.items():
|
|
99
|
-
if _should_use_cli_value(cli_value):
|
|
100
|
-
# CLI value takes precedence (for non-empty values)
|
|
101
|
-
if key in array_fields and key in import_data:
|
|
102
|
-
# For array fields, combine CLI and imported values
|
|
103
|
-
merged[key] = _handle_array_field_merge(key, cli_value, import_data)
|
|
104
|
-
else:
|
|
105
|
-
merged[key] = cli_value
|
|
106
|
-
elif key in import_data:
|
|
107
|
-
# Use imported value if no CLI value
|
|
108
|
-
merged[key] = import_data[key]
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def _add_import_only_fields(merged: dict[str, Any], import_data: dict[str, Any]) -> None:
|
|
112
|
-
"""Add fields that exist only in import data."""
|
|
113
|
-
for key, import_value in import_data.items():
|
|
114
|
-
if key not in merged:
|
|
115
|
-
merged[key] = import_value
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def merge_import_with_cli_args(
|
|
119
|
-
import_data: dict[str, Any],
|
|
120
|
-
cli_args: dict[str, Any],
|
|
121
|
-
array_fields: list[str] = None,
|
|
122
|
-
) -> dict[str, Any]:
|
|
123
|
-
"""Merge imported data with CLI arguments, preferring CLI args.
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
import_data: Data loaded from import file
|
|
127
|
-
cli_args: Arguments passed via CLI
|
|
128
|
-
array_fields: Fields that should be combined (merged) rather than replaced
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
Merged data dictionary
|
|
132
|
-
|
|
133
|
-
Notes:
|
|
134
|
-
- CLI arguments take precedence over imported data
|
|
135
|
-
- Array fields (tools, agents, mcps) are combined rather than replaced
|
|
136
|
-
- Empty arrays/lists are treated as None (no override)
|
|
137
|
-
"""
|
|
138
|
-
if array_fields is None:
|
|
139
|
-
array_fields = _get_default_array_fields()
|
|
140
|
-
|
|
141
|
-
merged = {}
|
|
142
|
-
_merge_cli_values_with_import(merged, cli_args, import_data, array_fields)
|
|
143
|
-
_add_import_only_fields(merged, import_data)
|
|
144
|
-
|
|
145
|
-
return merged
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def flatten_relationships_for_import(
|
|
149
|
-
data: dict[str, Any], fields: tuple[str, ...] = ("tools", "agents")
|
|
150
|
-
) -> dict[str, Any]:
|
|
151
|
-
"""Flatten relationship fields for import format.
|
|
152
|
-
|
|
153
|
-
This is an alias for convert_export_to_import_format with configurable fields.
|
|
154
|
-
|
|
155
|
-
Args:
|
|
156
|
-
data: Export format data with full objects
|
|
157
|
-
fields: Tuple of field names to flatten to IDs
|
|
158
|
-
|
|
159
|
-
Returns:
|
|
160
|
-
Import format data with specified fields flattened to IDs
|
|
161
|
-
"""
|
|
162
|
-
import_data = data.copy()
|
|
163
|
-
|
|
164
|
-
for field in fields:
|
|
165
|
-
if field in import_data and isinstance(import_data[field], list):
|
|
166
|
-
import_data[field] = extract_ids_from_export(import_data[field])
|
|
167
|
-
|
|
168
|
-
return import_data
|