glaip-sdk 0.1.0__py3-none-any.whl → 0.6.10__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 +5 -2
- glaip_sdk/_version.py +10 -3
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1191 -0
- glaip_sdk/branding.py +15 -6
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/agent_config.py +2 -6
- glaip_sdk/cli/auth.py +265 -45
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +251 -173
- glaip_sdk/cli/commands/common_config.py +101 -0
- glaip_sdk/cli/commands/configure.py +735 -143
- glaip_sdk/cli/commands/mcps.py +266 -134
- glaip_sdk/cli/commands/models.py +13 -9
- glaip_sdk/cli/commands/tools.py +67 -88
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/commands/update.py +3 -8
- glaip_sdk/cli/config.py +49 -7
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +8 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +846 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +45 -32
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +14 -17
- glaip_sdk/cli/main.py +232 -143
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/mcp_validators.py +5 -15
- glaip_sdk/cli/pager.py +12 -19
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/parsers/json_input.py +11 -22
- glaip_sdk/cli/resolution.py +3 -9
- glaip_sdk/cli/rich_helpers.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +578 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +65 -29
- glaip_sdk/cli/slash/prompt.py +24 -10
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +807 -225
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +86 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +876 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +258 -60
- glaip_sdk/cli/transcript/capture.py +72 -21
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/launcher.py +1 -3
- glaip_sdk/cli/transcript/viewer.py +79 -499
- glaip_sdk/cli/update_notifier.py +177 -24
- glaip_sdk/cli/utils.py +242 -1308
- glaip_sdk/cli/validators.py +16 -18
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_agent_payloads.py +53 -37
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +320 -92
- glaip_sdk/client/base.py +78 -35
- glaip_sdk/client/main.py +19 -10
- glaip_sdk/client/mcps.py +123 -15
- glaip_sdk/client/run_rendering.py +136 -101
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +163 -34
- glaip_sdk/client/validators.py +20 -48
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/exceptions.py +1 -3
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +90 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +116 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/payload_schemas/agent.py +1 -3
- 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 +232 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +115 -0
- glaip_sdk/runner/langgraph.py +706 -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/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +58 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/agent_config.py +4 -14
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +46 -28
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +25 -21
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +1 -36
- glaip_sdk/utils/import_export.py +15 -16
- glaip_sdk/utils/import_resolver.py +492 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +7 -35
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +10 -3
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +73 -12
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +3 -6
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -49
- glaip_sdk/utils/rendering/renderer/base.py +258 -1577
- glaip_sdk/utils/rendering/renderer/config.py +1 -5
- glaip_sdk/utils/rendering/renderer/debug.py +30 -34
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +10 -51
- 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 +1 -3
- 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 +1 -3
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +76 -517
- 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 +29 -26
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +32 -46
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/validation.py +20 -28
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.6.10.dist-info}/METADATA +42 -4
- glaip_sdk-0.6.10.dist-info/RECORD +159 -0
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.6.10.dist-info}/WHEEL +1 -1
- glaip_sdk/models.py +0 -259
- glaip_sdk-0.1.0.dist-info/RECORD +0 -82
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.6.10.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
11
|
from collections.abc import Mapping
|
|
12
|
+
from copy import deepcopy
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from typing import Any
|
|
14
15
|
|
|
@@ -18,6 +19,7 @@ from rich.console import Console
|
|
|
18
19
|
from glaip_sdk.branding import (
|
|
19
20
|
ACCENT_STYLE,
|
|
20
21
|
ERROR_STYLE,
|
|
22
|
+
HINT_PREFIX_STYLE,
|
|
21
23
|
INFO,
|
|
22
24
|
SUCCESS,
|
|
23
25
|
SUCCESS_STYLE,
|
|
@@ -32,7 +34,8 @@ from glaip_sdk.cli.agent_config import (
|
|
|
32
34
|
from glaip_sdk.cli.agent_config import (
|
|
33
35
|
sanitize_agent_config_for_cli as sanitize_agent_config,
|
|
34
36
|
)
|
|
35
|
-
from glaip_sdk.cli.
|
|
37
|
+
from glaip_sdk.cli.constants import DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
38
|
+
from glaip_sdk.cli.context import get_ctx_value, output_flags
|
|
36
39
|
from glaip_sdk.cli.display import (
|
|
37
40
|
build_resource_result_data,
|
|
38
41
|
display_agent_run_suggestions,
|
|
@@ -44,9 +47,7 @@ from glaip_sdk.cli.display import (
|
|
|
44
47
|
handle_rich_output,
|
|
45
48
|
print_api_error,
|
|
46
49
|
)
|
|
47
|
-
from glaip_sdk.cli.
|
|
48
|
-
export_resource_to_file_with_validation as export_resource_to_file,
|
|
49
|
-
)
|
|
50
|
+
from glaip_sdk.cli.hints import in_slash_mode
|
|
50
51
|
from glaip_sdk.cli.io import (
|
|
51
52
|
fetch_raw_resource_details,
|
|
52
53
|
)
|
|
@@ -64,9 +65,11 @@ from glaip_sdk.cli.utils import (
|
|
|
64
65
|
build_renderer,
|
|
65
66
|
coerce_to_row,
|
|
66
67
|
get_client,
|
|
68
|
+
handle_resource_export,
|
|
67
69
|
output_list,
|
|
68
70
|
output_result,
|
|
69
71
|
spinner_context,
|
|
72
|
+
with_client_and_spinner,
|
|
70
73
|
)
|
|
71
74
|
from glaip_sdk.cli.validators import (
|
|
72
75
|
validate_agent_instruction_cli as validate_agent_instruction,
|
|
@@ -77,7 +80,7 @@ from glaip_sdk.cli.validators import (
|
|
|
77
80
|
from glaip_sdk.cli.validators import (
|
|
78
81
|
validate_timeout_cli as validate_timeout,
|
|
79
82
|
)
|
|
80
|
-
from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT, DEFAULT_MODEL
|
|
83
|
+
from glaip_sdk.config.constants import AGENT_CONFIG_FIELDS, DEFAULT_AGENT_RUN_TIMEOUT, DEFAULT_MODEL
|
|
81
84
|
from glaip_sdk.exceptions import AgentTimeoutError
|
|
82
85
|
from glaip_sdk.icons import ICON_AGENT
|
|
83
86
|
from glaip_sdk.utils import format_datetime, is_uuid
|
|
@@ -91,6 +94,8 @@ console = Console()
|
|
|
91
94
|
# Error message constants
|
|
92
95
|
AGENT_NOT_FOUND_ERROR = "Agent not found"
|
|
93
96
|
|
|
97
|
+
# Instruction preview controls
|
|
98
|
+
|
|
94
99
|
|
|
95
100
|
def _safe_agent_attribute(agent: Any, name: str) -> Any:
|
|
96
101
|
"""Return attribute value for ``name`` while filtering Mock sentinels."""
|
|
@@ -143,10 +148,7 @@ def _build_fallback_agent_mapping(agent: Any) -> dict[str, Any]:
|
|
|
143
148
|
"description",
|
|
144
149
|
"model",
|
|
145
150
|
"agent_config",
|
|
146
|
-
"
|
|
147
|
-
"agents",
|
|
148
|
-
"mcps",
|
|
149
|
-
"timeout",
|
|
151
|
+
*[field for field in AGENT_CONFIG_FIELDS if field not in ("name", "instruction", "model")],
|
|
150
152
|
"tool_configs",
|
|
151
153
|
)
|
|
152
154
|
|
|
@@ -247,9 +249,7 @@ def _resolve_resources_by_name(
|
|
|
247
249
|
if not matches:
|
|
248
250
|
raise click.ClickException(f"{label} not found: {ref}")
|
|
249
251
|
if len(matches) > 1:
|
|
250
|
-
raise click.ClickException(
|
|
251
|
-
f"Multiple {resource_type}s named '{ref}'. Use ID instead."
|
|
252
|
-
)
|
|
252
|
+
raise click.ClickException(f"Multiple {resource_type}s named '{ref}'. Use ID instead.")
|
|
253
253
|
out.append(str(matches[0].id))
|
|
254
254
|
return out
|
|
255
255
|
|
|
@@ -312,12 +312,92 @@ def _format_fallback_agent_data(client: Any, agent: Any) -> dict:
|
|
|
312
312
|
return result_data
|
|
313
313
|
|
|
314
314
|
|
|
315
|
-
def
|
|
315
|
+
def _clamp_instruction_preview_limit(limit: int | None) -> int:
|
|
316
|
+
"""Normalise preview limit; 0 disables trimming."""
|
|
317
|
+
default = DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
318
|
+
if limit is None: # pragma: no cover
|
|
319
|
+
return default
|
|
320
|
+
try:
|
|
321
|
+
limit_value = int(limit)
|
|
322
|
+
except (TypeError, ValueError): # pragma: no cover - defensive parsing
|
|
323
|
+
return default
|
|
324
|
+
|
|
325
|
+
if limit_value <= 0:
|
|
326
|
+
return 0
|
|
327
|
+
|
|
328
|
+
return limit_value
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _build_instruction_preview(value: Any, limit: int) -> tuple[Any, bool]:
|
|
332
|
+
"""Return a trimmed preview for long instruction strings."""
|
|
333
|
+
if not isinstance(value, str) or limit <= 0: # pragma: no cover
|
|
334
|
+
return value, False
|
|
335
|
+
|
|
336
|
+
if len(value) <= limit:
|
|
337
|
+
return value, False
|
|
338
|
+
|
|
339
|
+
trimmed_value = value[:limit].rstrip()
|
|
340
|
+
preview = f"{trimmed_value}\n\n... (preview trimmed)"
|
|
341
|
+
return preview, True
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _prepare_agent_details_payload(
|
|
345
|
+
data: dict[str, Any],
|
|
346
|
+
*,
|
|
347
|
+
instruction_preview_limit: int,
|
|
348
|
+
) -> tuple[dict[str, Any], bool]:
|
|
349
|
+
"""Return payload ready for rendering plus trim indicator."""
|
|
350
|
+
payload = deepcopy(data)
|
|
351
|
+
trimmed = False
|
|
352
|
+
if instruction_preview_limit > 0:
|
|
353
|
+
preview, trimmed = _build_instruction_preview(payload.get("instruction"), instruction_preview_limit)
|
|
354
|
+
if trimmed:
|
|
355
|
+
payload["instruction"] = preview
|
|
356
|
+
return payload, trimmed
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _show_instruction_trim_hint(
|
|
360
|
+
ctx: Any,
|
|
361
|
+
*,
|
|
362
|
+
trimmed: bool,
|
|
363
|
+
preview_limit: int,
|
|
364
|
+
) -> None:
|
|
365
|
+
"""Render hint describing how to expand or collapse the instruction preview."""
|
|
366
|
+
if not trimmed or preview_limit <= 0:
|
|
367
|
+
return
|
|
368
|
+
|
|
369
|
+
view = get_ctx_value(ctx, "view", "rich") if ctx is not None else "rich"
|
|
370
|
+
if view != "rich": # pragma: no cover - non-rich view handling
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
suffix = f"[dim](preview: {preview_limit:,} chars)[/]"
|
|
374
|
+
if in_slash_mode(ctx):
|
|
375
|
+
console.print(
|
|
376
|
+
f"[{HINT_PREFIX_STYLE}]Tip:[/] Use '/details' again to toggle between trimmed and full prompts {suffix}"
|
|
377
|
+
)
|
|
378
|
+
return
|
|
379
|
+
|
|
380
|
+
console.print( # pragma: no cover - fallback hint rendering
|
|
381
|
+
f"[{HINT_PREFIX_STYLE}]Tip:[/] Run 'aip agents get <agent> --instruction-preview <n>' "
|
|
382
|
+
f"to control prompt preview length {suffix}"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _display_agent_details(
|
|
387
|
+
ctx: Any,
|
|
388
|
+
client: Any,
|
|
389
|
+
agent: Any,
|
|
390
|
+
*,
|
|
391
|
+
instruction_preview_limit: int | None = None,
|
|
392
|
+
) -> None:
|
|
316
393
|
"""Display full agent details using raw API data to preserve ALL fields."""
|
|
317
394
|
if agent is None:
|
|
318
395
|
handle_rich_output(ctx, markup_text(f"[{ERROR_STYLE}]❌ No agent provided[/]"))
|
|
319
396
|
return
|
|
320
397
|
|
|
398
|
+
preview_limit = _clamp_instruction_preview_limit(instruction_preview_limit)
|
|
399
|
+
trimmed_instruction = False
|
|
400
|
+
|
|
321
401
|
# Try to fetch and format raw agent data first
|
|
322
402
|
with spinner_context(
|
|
323
403
|
ctx,
|
|
@@ -329,9 +409,13 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
329
409
|
if formatted_data:
|
|
330
410
|
# Use raw API data - this preserves ALL fields including account_id
|
|
331
411
|
panel_title = f"{ICON_AGENT} {formatted_data.get('name', 'Unknown')}"
|
|
412
|
+
payload, trimmed_instruction = _prepare_agent_details_payload(
|
|
413
|
+
formatted_data,
|
|
414
|
+
instruction_preview_limit=preview_limit,
|
|
415
|
+
)
|
|
332
416
|
output_result(
|
|
333
417
|
ctx,
|
|
334
|
-
|
|
418
|
+
payload,
|
|
335
419
|
title=panel_title,
|
|
336
420
|
)
|
|
337
421
|
else:
|
|
@@ -349,12 +433,22 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
349
433
|
result_data = _format_fallback_agent_data(client, agent)
|
|
350
434
|
|
|
351
435
|
# Display using output_result
|
|
436
|
+
payload, trimmed_instruction = _prepare_agent_details_payload(
|
|
437
|
+
result_data,
|
|
438
|
+
instruction_preview_limit=preview_limit,
|
|
439
|
+
)
|
|
352
440
|
output_result(
|
|
353
441
|
ctx,
|
|
354
|
-
|
|
442
|
+
payload,
|
|
355
443
|
title="Agent Details",
|
|
356
444
|
)
|
|
357
445
|
|
|
446
|
+
_show_instruction_trim_hint(
|
|
447
|
+
ctx,
|
|
448
|
+
trimmed=trimmed_instruction,
|
|
449
|
+
preview_limit=preview_limit,
|
|
450
|
+
)
|
|
451
|
+
|
|
358
452
|
|
|
359
453
|
@click.group(name="agents", no_args_is_help=True)
|
|
360
454
|
def agents_group() -> None:
|
|
@@ -369,41 +463,47 @@ def _resolve_agent(
|
|
|
369
463
|
select: int | None = None,
|
|
370
464
|
interface_preference: str = "fuzzy",
|
|
371
465
|
) -> Any | None:
|
|
372
|
-
"""Resolve agent
|
|
466
|
+
"""Resolve an agent by ID or name, supporting fuzzy and questionary interfaces.
|
|
467
|
+
|
|
468
|
+
This function provides agent-specific resolution with flexible UI options.
|
|
469
|
+
It wraps resolve_resource_reference with agent-specific configuration, allowing
|
|
470
|
+
users to choose between fuzzy search and traditional questionary selection.
|
|
373
471
|
|
|
374
472
|
Args:
|
|
375
|
-
ctx: Click context
|
|
376
|
-
client: AIP client instance
|
|
377
|
-
ref: Agent
|
|
378
|
-
select: Pre-selected
|
|
379
|
-
interface_preference: "fuzzy" for
|
|
473
|
+
ctx: Click context for CLI command execution.
|
|
474
|
+
client: AIP SDK client instance.
|
|
475
|
+
ref: Agent identifier (UUID or name string).
|
|
476
|
+
select: Pre-selected index for non-interactive resolution (1-based).
|
|
477
|
+
interface_preference: UI preference - "fuzzy" for search or "questionary" for list.
|
|
380
478
|
|
|
381
479
|
Returns:
|
|
382
|
-
|
|
480
|
+
Agent object when found, None when resolution fails.
|
|
383
481
|
"""
|
|
482
|
+
# Configure agent-specific resolution parameters
|
|
483
|
+
resolution_config = {
|
|
484
|
+
"resource_type": "agent",
|
|
485
|
+
"get_by_id": client.agents.get_agent_by_id,
|
|
486
|
+
"find_by_name": client.agents.find_agents,
|
|
487
|
+
"label": "Agent",
|
|
488
|
+
}
|
|
489
|
+
# Use agent-specific resolution with flexible interface preference
|
|
384
490
|
return resolve_resource_reference(
|
|
385
491
|
ctx,
|
|
386
492
|
client,
|
|
387
493
|
ref,
|
|
388
|
-
"
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
"
|
|
494
|
+
resolution_config["resource_type"],
|
|
495
|
+
resolution_config["get_by_id"],
|
|
496
|
+
resolution_config["find_by_name"],
|
|
497
|
+
resolution_config["label"],
|
|
392
498
|
select=select,
|
|
393
499
|
interface_preference=interface_preference,
|
|
394
500
|
)
|
|
395
501
|
|
|
396
502
|
|
|
397
503
|
@agents_group.command(name="list")
|
|
398
|
-
@click.option(
|
|
399
|
-
|
|
400
|
-
)
|
|
401
|
-
@click.option(
|
|
402
|
-
"--type", "agent_type", help="Filter by agent type (config, code, a2a, langflow)"
|
|
403
|
-
)
|
|
404
|
-
@click.option(
|
|
405
|
-
"--framework", help="Filter by framework (langchain, langgraph, google_adk)"
|
|
406
|
-
)
|
|
504
|
+
@click.option("--simple", is_flag=True, help="Show simple table without interactive picker")
|
|
505
|
+
@click.option("--type", "agent_type", help="Filter by agent type (config, code, a2a, langflow)")
|
|
506
|
+
@click.option("--framework", help="Filter by framework (langchain, langgraph, google_adk)")
|
|
407
507
|
@click.option("--name", help="Filter by partial name match (case-insensitive)")
|
|
408
508
|
@click.option("--version", help="Filter by exact version match")
|
|
409
509
|
@click.option(
|
|
@@ -424,19 +524,20 @@ def list_agents(
|
|
|
424
524
|
) -> None:
|
|
425
525
|
"""List agents with optional filtering."""
|
|
426
526
|
try:
|
|
427
|
-
|
|
428
|
-
with spinner_context(
|
|
527
|
+
with with_client_and_spinner(
|
|
429
528
|
ctx,
|
|
430
529
|
"[bold blue]Fetching agents…[/bold blue]",
|
|
431
530
|
console_override=console,
|
|
432
|
-
):
|
|
433
|
-
agents
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
531
|
+
) as client:
|
|
532
|
+
# Query agents with specified filters
|
|
533
|
+
filter_params = {
|
|
534
|
+
"agent_type": agent_type,
|
|
535
|
+
"framework": framework,
|
|
536
|
+
"name": name,
|
|
537
|
+
"version": version,
|
|
538
|
+
"sync_langflow_agents": sync_langflow,
|
|
539
|
+
}
|
|
540
|
+
agents = client.agents.list_agents(**filter_params)
|
|
440
541
|
|
|
441
542
|
# Define table columns: (data_key, header, style, width)
|
|
442
543
|
columns = [
|
|
@@ -449,6 +550,14 @@ def list_agents(
|
|
|
449
550
|
|
|
450
551
|
# Transform function for safe attribute access
|
|
451
552
|
def transform_agent(agent: Any) -> dict[str, Any]:
|
|
553
|
+
"""Transform an agent object to a display row dictionary.
|
|
554
|
+
|
|
555
|
+
Args:
|
|
556
|
+
agent: Agent object to transform.
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
Dictionary with id, name, type, framework, and version fields.
|
|
560
|
+
"""
|
|
452
561
|
row = coerce_to_row(agent, ["id", "name", "type", "framework", "version"])
|
|
453
562
|
# Ensure id is always a string
|
|
454
563
|
row["id"] = str(row["id"])
|
|
@@ -467,7 +576,10 @@ def list_agents(
|
|
|
467
576
|
and len(agents) > 0
|
|
468
577
|
)
|
|
469
578
|
|
|
579
|
+
# Track picker attempt so the fallback table doesn't re-open the palette
|
|
580
|
+
picker_attempted = False
|
|
470
581
|
if interactive_enabled:
|
|
582
|
+
picker_attempted = True
|
|
471
583
|
picked_agent = _fuzzy_pick_for_resources(agents, "agent", "")
|
|
472
584
|
if picked_agent:
|
|
473
585
|
_display_agent_details(ctx, client, picked_agent)
|
|
@@ -482,15 +594,17 @@ def list_agents(
|
|
|
482
594
|
f"{ICON_AGENT} Available Agents",
|
|
483
595
|
columns,
|
|
484
596
|
transform_agent,
|
|
485
|
-
skip_picker=
|
|
486
|
-
|
|
487
|
-
|
|
597
|
+
skip_picker=(
|
|
598
|
+
not interactive_enabled
|
|
599
|
+
or picker_attempted
|
|
600
|
+
or simple
|
|
601
|
+
or any(param is not None for param in (agent_type, framework, name, version))
|
|
488
602
|
),
|
|
489
603
|
use_pager=False,
|
|
490
604
|
)
|
|
491
605
|
|
|
492
606
|
except Exception as e:
|
|
493
|
-
raise click.ClickException(str(e))
|
|
607
|
+
raise click.ClickException(str(e)) from e
|
|
494
608
|
|
|
495
609
|
|
|
496
610
|
@agents_group.command()
|
|
@@ -501,68 +615,66 @@ def list_agents(
|
|
|
501
615
|
type=click.Path(dir_okay=False, writable=True),
|
|
502
616
|
help="Export complete agent configuration to file (format auto-detected from .json/.yaml extension)",
|
|
503
617
|
)
|
|
618
|
+
@click.option(
|
|
619
|
+
"--instruction-preview",
|
|
620
|
+
type=int,
|
|
621
|
+
default=0,
|
|
622
|
+
show_default=True,
|
|
623
|
+
help="Instruction preview length when printing instructions (0 shows full prompt).",
|
|
624
|
+
)
|
|
504
625
|
@output_flags()
|
|
505
626
|
@click.pass_context
|
|
506
|
-
def get(
|
|
507
|
-
|
|
627
|
+
def get(
|
|
628
|
+
ctx: Any,
|
|
629
|
+
agent_ref: str,
|
|
630
|
+
select: int | None,
|
|
631
|
+
export: str | None,
|
|
632
|
+
instruction_preview: int,
|
|
633
|
+
) -> None:
|
|
634
|
+
r"""Get agent details.
|
|
508
635
|
|
|
636
|
+
\b
|
|
509
637
|
Examples:
|
|
510
638
|
aip agents get my-agent
|
|
511
639
|
aip agents get my-agent --export agent.json # Exports complete configuration as JSON
|
|
512
640
|
aip agents get my-agent --export agent.yaml # Exports complete configuration as YAML
|
|
513
641
|
"""
|
|
514
642
|
try:
|
|
515
|
-
client
|
|
643
|
+
# Initialize API client for agent retrieval
|
|
644
|
+
api_client = get_client(ctx)
|
|
516
645
|
|
|
517
|
-
# Resolve agent
|
|
518
|
-
agent = _resolve_agent(
|
|
519
|
-
ctx, client, agent_ref, select, interface_preference="questionary"
|
|
520
|
-
)
|
|
646
|
+
# Resolve agent reference using questionary interface for better UX
|
|
647
|
+
agent = _resolve_agent(ctx, api_client, agent_ref, select, interface_preference="questionary")
|
|
521
648
|
|
|
522
|
-
|
|
649
|
+
if not agent:
|
|
650
|
+
raise click.ClickException(f"Agent '{agent_ref}' not found")
|
|
651
|
+
|
|
652
|
+
# Handle export option if requested
|
|
523
653
|
if export:
|
|
524
|
-
|
|
525
|
-
# Auto-detect format from file extension
|
|
526
|
-
detected_format = detect_export_format(export_path)
|
|
527
|
-
|
|
528
|
-
# Always export comprehensive data - re-fetch agent with full details
|
|
529
|
-
try:
|
|
530
|
-
with spinner_context(
|
|
531
|
-
ctx,
|
|
532
|
-
"[bold blue]Fetching complete agent data…[/bold blue]",
|
|
533
|
-
console_override=console,
|
|
534
|
-
):
|
|
535
|
-
agent = client.agents.get_agent_by_id(agent.id)
|
|
536
|
-
except Exception as e:
|
|
537
|
-
handle_rich_output(
|
|
538
|
-
ctx,
|
|
539
|
-
markup_text(
|
|
540
|
-
f"[{WARNING_STYLE}]⚠️ Could not fetch full agent details: {e}[/]"
|
|
541
|
-
),
|
|
542
|
-
)
|
|
543
|
-
handle_rich_output(
|
|
544
|
-
ctx,
|
|
545
|
-
markup_text(
|
|
546
|
-
f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]"
|
|
547
|
-
),
|
|
548
|
-
)
|
|
549
|
-
|
|
550
|
-
export_resource_to_file(agent, export_path, detected_format)
|
|
551
|
-
handle_rich_output(
|
|
654
|
+
handle_resource_export(
|
|
552
655
|
ctx,
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
656
|
+
agent,
|
|
657
|
+
Path(export),
|
|
658
|
+
resource_type="agent",
|
|
659
|
+
get_by_id_func=api_client.agents.get_agent_by_id,
|
|
660
|
+
console_override=console,
|
|
556
661
|
)
|
|
557
662
|
|
|
558
663
|
# Display full agent details using the standardized helper
|
|
559
|
-
_display_agent_details(
|
|
664
|
+
_display_agent_details(
|
|
665
|
+
ctx,
|
|
666
|
+
api_client,
|
|
667
|
+
agent,
|
|
668
|
+
instruction_preview_limit=instruction_preview,
|
|
669
|
+
)
|
|
560
670
|
|
|
561
671
|
# Show run suggestions via centralized display helper
|
|
562
672
|
handle_rich_output(ctx, display_agent_run_suggestions(agent))
|
|
563
673
|
|
|
674
|
+
except click.ClickException:
|
|
675
|
+
raise
|
|
564
676
|
except Exception as e:
|
|
565
|
-
raise click.ClickException(str(e))
|
|
677
|
+
raise click.ClickException(str(e)) from e
|
|
566
678
|
|
|
567
679
|
|
|
568
680
|
def _validate_run_input(input_option: str | None, input_text: str | None) -> str:
|
|
@@ -570,9 +682,7 @@ def _validate_run_input(input_option: str | None, input_text: str | None) -> str
|
|
|
570
682
|
final_input_text = input_option if input_option else input_text
|
|
571
683
|
|
|
572
684
|
if not final_input_text:
|
|
573
|
-
raise click.ClickException(
|
|
574
|
-
"Input text is required. Use either positional argument or --input option."
|
|
575
|
-
)
|
|
685
|
+
raise click.ClickException("Input text is required. Use either positional argument or --input option.")
|
|
576
686
|
|
|
577
687
|
return final_input_text
|
|
578
688
|
|
|
@@ -584,8 +694,8 @@ def _parse_chat_history(chat_history: str | None) -> list[dict[str, Any]] | None
|
|
|
584
694
|
|
|
585
695
|
try:
|
|
586
696
|
return json.loads(chat_history)
|
|
587
|
-
except json.JSONDecodeError:
|
|
588
|
-
raise click.ClickException("Invalid JSON in chat history")
|
|
697
|
+
except json.JSONDecodeError as err:
|
|
698
|
+
raise click.ClickException("Invalid JSON in chat history") from err
|
|
589
699
|
|
|
590
700
|
|
|
591
701
|
def _setup_run_renderer(ctx: Any, save: str | None, verbose: bool) -> Any:
|
|
@@ -665,9 +775,7 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
|
|
|
665
775
|
if ext == "json":
|
|
666
776
|
save_data = {
|
|
667
777
|
"output": result or "",
|
|
668
|
-
"full_debug_output": getattr(
|
|
669
|
-
working_console, "get_captured_output", lambda: ""
|
|
670
|
-
)(),
|
|
778
|
+
"full_debug_output": getattr(working_console, "get_captured_output", lambda: "")(),
|
|
671
779
|
"timestamp": "captured during agent execution",
|
|
672
780
|
}
|
|
673
781
|
content = json.dumps(save_data, indent=2)
|
|
@@ -680,9 +788,7 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
|
|
|
680
788
|
|
|
681
789
|
with open(save, "w", encoding="utf-8") as f:
|
|
682
790
|
f.write(content)
|
|
683
|
-
print_markup(
|
|
684
|
-
f"[{SUCCESS_STYLE}]Full debug output saved to: {save}[/]", console=console
|
|
685
|
-
)
|
|
791
|
+
print_markup(f"[{SUCCESS_STYLE}]Full debug output saved to: {save}[/]", console=console)
|
|
686
792
|
|
|
687
793
|
|
|
688
794
|
@agents_group.command()
|
|
@@ -728,10 +834,11 @@ def run(
|
|
|
728
834
|
files: tuple[str, ...] | None,
|
|
729
835
|
verbose: bool,
|
|
730
836
|
) -> None:
|
|
731
|
-
"""Run an agent with input text.
|
|
837
|
+
r"""Run an agent with input text.
|
|
732
838
|
|
|
733
839
|
Usage: aip agents run <agent_ref> <input_text> [OPTIONS]
|
|
734
840
|
|
|
841
|
+
\b
|
|
735
842
|
Examples:
|
|
736
843
|
aip agents run my-agent "Hello world"
|
|
737
844
|
aip agents run agent-123 "Process this data" --timeout 600
|
|
@@ -745,9 +852,7 @@ def run(
|
|
|
745
852
|
|
|
746
853
|
try:
|
|
747
854
|
client = get_client(ctx)
|
|
748
|
-
agent = _resolve_agent(
|
|
749
|
-
ctx, client, agent_ref, select, interface_preference="fuzzy"
|
|
750
|
-
)
|
|
855
|
+
agent = _resolve_agent(ctx, client, agent_ref, select, interface_preference="fuzzy")
|
|
751
856
|
|
|
752
857
|
parsed_chat_history = _parse_chat_history(chat_history)
|
|
753
858
|
renderer, working_console = _setup_run_renderer(ctx, save, verbose)
|
|
@@ -796,17 +901,19 @@ def run(
|
|
|
796
901
|
except AgentTimeoutError as e:
|
|
797
902
|
error_msg = str(e)
|
|
798
903
|
handle_json_output(ctx, error=Exception(error_msg))
|
|
799
|
-
raise click.ClickException(error_msg)
|
|
904
|
+
raise click.ClickException(error_msg) from e
|
|
800
905
|
except Exception as e:
|
|
801
906
|
_handle_command_exception(ctx, e)
|
|
802
907
|
|
|
803
908
|
|
|
804
909
|
def _running_in_slash_mode(ctx: Any) -> bool:
|
|
910
|
+
"""Return True if the command is executing inside the slash session."""
|
|
805
911
|
ctx_obj = getattr(ctx, "obj", None)
|
|
806
912
|
return isinstance(ctx_obj, dict) and bool(ctx_obj.get("_slash_session"))
|
|
807
913
|
|
|
808
914
|
|
|
809
915
|
def _emit_verbose_guidance(ctx: Any) -> None:
|
|
916
|
+
"""Explain the modern alternative to the deprecated --verbose flag."""
|
|
810
917
|
if _running_in_slash_mode(ctx):
|
|
811
918
|
message = (
|
|
812
919
|
"[dim]Tip:[/] Verbose streaming has been retired in the command palette. Run the agent normally and open "
|
|
@@ -885,16 +992,12 @@ def _extract_and_validate_fields(
|
|
|
885
992
|
if not name:
|
|
886
993
|
raise click.ClickException("Agent name is required (--name or --import)")
|
|
887
994
|
if not instruction:
|
|
888
|
-
raise click.ClickException(
|
|
889
|
-
"Agent instruction is required (--instruction or --import)"
|
|
890
|
-
)
|
|
995
|
+
raise click.ClickException("Agent instruction is required (--instruction or --import)")
|
|
891
996
|
|
|
892
997
|
return name, instruction, model, tools, agents, mcps, timeout
|
|
893
998
|
|
|
894
999
|
|
|
895
|
-
def _validate_and_coerce_fields(
|
|
896
|
-
name: str, instruction: str, timeout: Any
|
|
897
|
-
) -> tuple[str, str, Any]:
|
|
1000
|
+
def _validate_and_coerce_fields(name: str, instruction: str, timeout: Any) -> tuple[str, str, Any]:
|
|
898
1001
|
"""Validate and coerce field values."""
|
|
899
1002
|
name = validate_agent_name(name)
|
|
900
1003
|
instruction = validate_agent_instruction(instruction)
|
|
@@ -905,19 +1008,11 @@ def _validate_and_coerce_fields(
|
|
|
905
1008
|
return name, instruction, timeout
|
|
906
1009
|
|
|
907
1010
|
|
|
908
|
-
def _resolve_resources(
|
|
909
|
-
client: Any, tools: tuple, agents: tuple, mcps: tuple
|
|
910
|
-
) -> tuple[list, list, list]:
|
|
1011
|
+
def _resolve_resources(client: Any, tools: tuple, agents: tuple, mcps: tuple) -> tuple[list, list, list]:
|
|
911
1012
|
"""Resolve tool, agent, and MCP references."""
|
|
912
|
-
resolved_tools = _resolve_resources_by_name(
|
|
913
|
-
|
|
914
|
-
)
|
|
915
|
-
resolved_agents = _resolve_resources_by_name(
|
|
916
|
-
client, agents, "agent", client.find_agents, "Agent"
|
|
917
|
-
)
|
|
918
|
-
resolved_mcps = _resolve_resources_by_name(
|
|
919
|
-
client, mcps, "mcp", client.find_mcps, "MCP"
|
|
920
|
-
)
|
|
1013
|
+
resolved_tools = _resolve_resources_by_name(client, tools, "tool", client.find_tools, "Tool")
|
|
1014
|
+
resolved_agents = _resolve_resources_by_name(client, agents, "agent", client.find_agents, "Agent")
|
|
1015
|
+
resolved_mcps = _resolve_resources_by_name(client, mcps, "mcp", client.find_mcps, "MCP")
|
|
921
1016
|
|
|
922
1017
|
return resolved_tools, resolved_agents, resolved_mcps
|
|
923
1018
|
|
|
@@ -944,16 +1039,12 @@ def _build_create_kwargs(
|
|
|
944
1039
|
}
|
|
945
1040
|
|
|
946
1041
|
# Handle language model selection
|
|
947
|
-
lm_selection_dict, should_strip_lm_identity = resolve_language_model_selection(
|
|
948
|
-
merged_data, model
|
|
949
|
-
)
|
|
1042
|
+
lm_selection_dict, should_strip_lm_identity = resolve_language_model_selection(merged_data, model)
|
|
950
1043
|
create_kwargs.update(lm_selection_dict)
|
|
951
1044
|
|
|
952
1045
|
# Handle import file specific logic
|
|
953
1046
|
if import_file:
|
|
954
|
-
_add_import_file_attributes(
|
|
955
|
-
create_kwargs, merged_data, should_strip_lm_identity
|
|
956
|
-
)
|
|
1047
|
+
_add_import_file_attributes(create_kwargs, merged_data, should_strip_lm_identity)
|
|
957
1048
|
|
|
958
1049
|
return create_kwargs
|
|
959
1050
|
|
|
@@ -999,12 +1090,7 @@ def _get_language_model_display_name(agent: Any, model: str | None) -> str:
|
|
|
999
1090
|
lm_display = getattr(agent, "model", None)
|
|
1000
1091
|
if not lm_display:
|
|
1001
1092
|
cfg = getattr(agent, "agent_config", {}) or {}
|
|
1002
|
-
lm_display = (
|
|
1003
|
-
cfg.get("lm_name")
|
|
1004
|
-
or cfg.get("model")
|
|
1005
|
-
or model
|
|
1006
|
-
or f"{DEFAULT_MODEL} (backend default)"
|
|
1007
|
-
)
|
|
1093
|
+
lm_display = cfg.get("lm_name") or cfg.get("model") or model or f"{DEFAULT_MODEL} (backend default)"
|
|
1008
1094
|
return lm_display
|
|
1009
1095
|
|
|
1010
1096
|
|
|
@@ -1039,7 +1125,7 @@ def _handle_command_exception(ctx: Any, e: Exception) -> None:
|
|
|
1039
1125
|
handle_json_output(ctx, error=e)
|
|
1040
1126
|
if get_ctx_value(ctx, "view") != "json":
|
|
1041
1127
|
print_api_error(e)
|
|
1042
|
-
raise click.
|
|
1128
|
+
raise click.exceptions.Exit(1) from e
|
|
1043
1129
|
|
|
1044
1130
|
|
|
1045
1131
|
def _handle_creation_exception(ctx: Any, e: Exception) -> None:
|
|
@@ -1082,8 +1168,9 @@ def create(
|
|
|
1082
1168
|
timeout: float | None,
|
|
1083
1169
|
import_file: str | None,
|
|
1084
1170
|
) -> None:
|
|
1085
|
-
"""Create a new agent.
|
|
1171
|
+
r"""Create a new agent.
|
|
1086
1172
|
|
|
1173
|
+
\b
|
|
1087
1174
|
Examples:
|
|
1088
1175
|
aip agents create --name "My Agent" --instruction "You are a helpful assistant"
|
|
1089
1176
|
aip agents create --import agent.json
|
|
@@ -1093,13 +1180,9 @@ def create(
|
|
|
1093
1180
|
|
|
1094
1181
|
# Handle import file or CLI args
|
|
1095
1182
|
if import_file:
|
|
1096
|
-
merged_data = _handle_import_file_logic(
|
|
1097
|
-
import_file, model, name, instruction, tools, agents, mcps, timeout
|
|
1098
|
-
)
|
|
1183
|
+
merged_data = _handle_import_file_logic(import_file, model, name, instruction, tools, agents, mcps, timeout)
|
|
1099
1184
|
else:
|
|
1100
|
-
merged_data = _build_cli_args_data(
|
|
1101
|
-
name, instruction, model, tools, agents, mcps, timeout
|
|
1102
|
-
)
|
|
1185
|
+
merged_data = _build_cli_args_data(name, instruction, model, tools, agents, mcps, timeout)
|
|
1103
1186
|
|
|
1104
1187
|
# Extract and validate fields
|
|
1105
1188
|
(
|
|
@@ -1111,14 +1194,10 @@ def create(
|
|
|
1111
1194
|
mcps,
|
|
1112
1195
|
timeout,
|
|
1113
1196
|
) = _extract_and_validate_fields(merged_data)
|
|
1114
|
-
name, instruction, timeout = _validate_and_coerce_fields(
|
|
1115
|
-
name, instruction, timeout
|
|
1116
|
-
)
|
|
1197
|
+
name, instruction, timeout = _validate_and_coerce_fields(name, instruction, timeout)
|
|
1117
1198
|
|
|
1118
1199
|
# Resolve resources
|
|
1119
|
-
resolved_tools, resolved_agents, resolved_mcps = _resolve_resources(
|
|
1120
|
-
client, tools, agents, mcps
|
|
1121
|
-
)
|
|
1200
|
+
resolved_tools, resolved_agents, resolved_mcps = _resolve_resources(client, tools, agents, mcps)
|
|
1122
1201
|
|
|
1123
1202
|
# Build create kwargs
|
|
1124
1203
|
create_kwargs = _build_create_kwargs(
|
|
@@ -1148,7 +1227,7 @@ def _get_agent_for_update(client: Any, agent_id: str) -> Any:
|
|
|
1148
1227
|
try:
|
|
1149
1228
|
return client.agents.get_agent_by_id(agent_id)
|
|
1150
1229
|
except Exception as e:
|
|
1151
|
-
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
|
|
1230
|
+
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}") from e
|
|
1152
1231
|
|
|
1153
1232
|
|
|
1154
1233
|
def _handle_update_import_file(
|
|
@@ -1230,16 +1309,12 @@ def _handle_update_import_config(
|
|
|
1230
1309
|
if not import_file:
|
|
1231
1310
|
return
|
|
1232
1311
|
|
|
1233
|
-
lm_selection, should_strip_lm_identity = resolve_language_model_selection(
|
|
1234
|
-
merged_data, None
|
|
1235
|
-
)
|
|
1312
|
+
lm_selection, should_strip_lm_identity = resolve_language_model_selection(merged_data, None)
|
|
1236
1313
|
update_data.update(lm_selection)
|
|
1237
1314
|
|
|
1238
1315
|
raw_cfg = merged_data.get("agent_config") if isinstance(merged_data, dict) else None
|
|
1239
1316
|
if isinstance(raw_cfg, dict):
|
|
1240
|
-
update_data["agent_config"] = sanitize_agent_config(
|
|
1241
|
-
raw_cfg, strip_lm_identity=should_strip_lm_identity
|
|
1242
|
-
)
|
|
1317
|
+
update_data["agent_config"] = sanitize_agent_config(raw_cfg, strip_lm_identity=should_strip_lm_identity)
|
|
1243
1318
|
|
|
1244
1319
|
excluded_fields = {
|
|
1245
1320
|
"name",
|
|
@@ -1289,8 +1364,9 @@ def update(
|
|
|
1289
1364
|
timeout: float | None,
|
|
1290
1365
|
import_file: str | None,
|
|
1291
1366
|
) -> None:
|
|
1292
|
-
"""Update an existing agent.
|
|
1367
|
+
r"""Update an existing agent.
|
|
1293
1368
|
|
|
1369
|
+
\b
|
|
1294
1370
|
Examples:
|
|
1295
1371
|
aip agents update my-agent --instruction "New instruction"
|
|
1296
1372
|
aip agents update my-agent --import agent.json
|
|
@@ -1308,16 +1384,18 @@ def update(
|
|
|
1308
1384
|
agents,
|
|
1309
1385
|
mcps,
|
|
1310
1386
|
timeout,
|
|
1311
|
-
) = _handle_update_import_file(
|
|
1312
|
-
import_file, name, instruction, tools, agents, mcps, timeout
|
|
1313
|
-
)
|
|
1387
|
+
) = _handle_update_import_file(import_file, name, instruction, tools, agents, mcps, timeout)
|
|
1314
1388
|
|
|
1315
|
-
update_data = _build_update_data(
|
|
1316
|
-
name, instruction, tools, agents, mcps, timeout
|
|
1317
|
-
)
|
|
1389
|
+
update_data = _build_update_data(name, instruction, tools, agents, mcps, timeout)
|
|
1318
1390
|
|
|
1319
1391
|
if merged_data:
|
|
1320
1392
|
_handle_update_import_config(import_file, merged_data, update_data)
|
|
1393
|
+
# Ensure instruction from import file is included if not already set via CLI
|
|
1394
|
+
# This handles the case where instruction is None in CLI args but exists in import file
|
|
1395
|
+
if import_file and (instruction is None or "instruction" not in update_data):
|
|
1396
|
+
import_instruction = merged_data.get("instruction")
|
|
1397
|
+
if import_instruction is not None:
|
|
1398
|
+
update_data["instruction"] = import_instruction
|
|
1321
1399
|
|
|
1322
1400
|
if not update_data:
|
|
1323
1401
|
raise click.ClickException("No update fields specified")
|
|
@@ -1352,7 +1430,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
|
|
|
1352
1430
|
try:
|
|
1353
1431
|
agent = client.agents.get_agent_by_id(agent_id)
|
|
1354
1432
|
except Exception as e:
|
|
1355
|
-
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
|
|
1433
|
+
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}") from e
|
|
1356
1434
|
|
|
1357
1435
|
# Confirm deletion when not forced
|
|
1358
1436
|
if not yes and not display_confirmation_prompt("Agent", agent.name):
|
|
@@ -1384,13 +1462,11 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
|
|
|
1384
1462
|
"--base-url",
|
|
1385
1463
|
help="Custom LangFlow server base URL (overrides LANGFLOW_BASE_URL env var)",
|
|
1386
1464
|
)
|
|
1387
|
-
@click.option(
|
|
1388
|
-
"--api-key", help="Custom LangFlow API key (overrides LANGFLOW_API_KEY env var)"
|
|
1389
|
-
)
|
|
1465
|
+
@click.option("--api-key", help="Custom LangFlow API key (overrides LANGFLOW_API_KEY env var)")
|
|
1390
1466
|
@output_flags()
|
|
1391
1467
|
@click.pass_context
|
|
1392
1468
|
def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
1393
|
-
"""Sync agents with LangFlow server flows.
|
|
1469
|
+
r"""Sync agents with LangFlow server flows.
|
|
1394
1470
|
|
|
1395
1471
|
This command fetches all flows from the configured LangFlow server and
|
|
1396
1472
|
creates/updates corresponding agents in the platform.
|
|
@@ -1399,6 +1475,7 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1399
1475
|
- Command options (--base-url, --api-key)
|
|
1400
1476
|
- Environment variables (LANGFLOW_BASE_URL, LANGFLOW_API_KEY)
|
|
1401
1477
|
|
|
1478
|
+
\b
|
|
1402
1479
|
Examples:
|
|
1403
1480
|
aip agents sync-langflow
|
|
1404
1481
|
aip agents sync-langflow --base-url https://my-langflow.com --api-key my-key
|
|
@@ -1415,15 +1492,16 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1415
1492
|
# Show success message for non-JSON output
|
|
1416
1493
|
if get_ctx_value(ctx, "view") != "json":
|
|
1417
1494
|
# Extract some useful info from the result
|
|
1418
|
-
success_count = result.get("data", {}).get("created_count", 0) + result.get(
|
|
1419
|
-
"
|
|
1420
|
-
)
|
|
1495
|
+
success_count = result.get("data", {}).get("created_count", 0) + result.get("data", {}).get(
|
|
1496
|
+
"updated_count", 0
|
|
1497
|
+
)
|
|
1421
1498
|
total_count = result.get("data", {}).get("total_processed", 0)
|
|
1422
1499
|
|
|
1423
1500
|
handle_rich_output(
|
|
1424
1501
|
ctx,
|
|
1425
1502
|
markup_text(
|
|
1426
|
-
f"[{SUCCESS_STYLE}]✅ Successfully synced {success_count} LangFlow agents
|
|
1503
|
+
f"[{SUCCESS_STYLE}]✅ Successfully synced {success_count} LangFlow agents "
|
|
1504
|
+
f"({total_count} total processed)[/]"
|
|
1427
1505
|
),
|
|
1428
1506
|
)
|
|
1429
1507
|
|