@openlucaskaka/kagent 0.1.7

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.
Files changed (117) hide show
  1. package/README.md +353 -0
  2. package/npm/bin/kagent-serve.js +6 -0
  3. package/npm/bin/kagent.js +6 -0
  4. package/npm/lib/App.js +524 -0
  5. package/npm/lib/app-state.js +224 -0
  6. package/npm/lib/approval-choice.js +25 -0
  7. package/npm/lib/commands.js +59 -0
  8. package/npm/lib/editor.js +188 -0
  9. package/npm/lib/ink-runner.js +41 -0
  10. package/npm/lib/kagent-home.js +39 -0
  11. package/npm/lib/launcher.js +221 -0
  12. package/npm/lib/protocol.js +33 -0
  13. package/npm/lib/provider-setup.js +139 -0
  14. package/npm/lib/python-runner.js +892 -0
  15. package/npm/lib/runtime-client.js +390 -0
  16. package/npm/lib/terminal-input.js +127 -0
  17. package/npm/lib/terminal-text.js +19 -0
  18. package/npm/lib/terminal-width.js +14 -0
  19. package/npm/lib/transcript.js +227 -0
  20. package/npm/lib/ui-components.js +247 -0
  21. package/npm/lib/update-manager.js +334 -0
  22. package/package.json +39 -0
  23. package/pyproject.toml +55 -0
  24. package/src/kagent/__init__.py +90 -0
  25. package/src/kagent/cli/__init__.py +5 -0
  26. package/src/kagent/cli/__main__.py +6 -0
  27. package/src/kagent/cli/commands.py +112 -0
  28. package/src/kagent/cli/conversation.py +127 -0
  29. package/src/kagent/cli/interactive.py +841 -0
  30. package/src/kagent/cli/main.py +685 -0
  31. package/src/kagent/cli/memory.py +460 -0
  32. package/src/kagent/cli/pending_approval.py +169 -0
  33. package/src/kagent/cli/provider.py +27 -0
  34. package/src/kagent/cli/session_commands.py +401 -0
  35. package/src/kagent/cli/stdio_runtime.py +784 -0
  36. package/src/kagent/cli/trace.py +67 -0
  37. package/src/kagent/cli/ui.py +931 -0
  38. package/src/kagent/core/__init__.py +0 -0
  39. package/src/kagent/core/agent.py +296 -0
  40. package/src/kagent/core/faults.py +11 -0
  41. package/src/kagent/core/invariants.py +47 -0
  42. package/src/kagent/core/normalization.py +81 -0
  43. package/src/kagent/core/planning.py +48 -0
  44. package/src/kagent/core/state.py +73 -0
  45. package/src/kagent/core/summary.py +64 -0
  46. package/src/kagent/core/tools.py +196 -0
  47. package/src/kagent/core/trace.py +57 -0
  48. package/src/kagent/eval/__init__.py +11 -0
  49. package/src/kagent/eval/cases.py +229 -0
  50. package/src/kagent/eval/evaluator.py +216 -0
  51. package/src/kagent/integrations/__init__.py +3 -0
  52. package/src/kagent/integrations/audit.py +95 -0
  53. package/src/kagent/integrations/backends.py +131 -0
  54. package/src/kagent/integrations/memory.py +301 -0
  55. package/src/kagent/ops/__init__.py +0 -0
  56. package/src/kagent/ops/batch.py +156 -0
  57. package/src/kagent/ops/doctor.py +255 -0
  58. package/src/kagent/ops/metrics.py +214 -0
  59. package/src/kagent/ops/release_evidence.py +877 -0
  60. package/src/kagent/ops/release_manifest.py +142 -0
  61. package/src/kagent/ops/trace_replay.py +285 -0
  62. package/src/kagent/providers/__init__.py +7 -0
  63. package/src/kagent/providers/embeddings.py +187 -0
  64. package/src/kagent/providers/llm.py +770 -0
  65. package/src/kagent/py.typed +1 -0
  66. package/src/kagent/runtime/__init__.py +28 -0
  67. package/src/kagent/runtime/action_graph.py +543 -0
  68. package/src/kagent/runtime/agent.py +2089 -0
  69. package/src/kagent/runtime/approval.py +64 -0
  70. package/src/kagent/runtime/cancellation.py +64 -0
  71. package/src/kagent/runtime/checkpoint_state.py +146 -0
  72. package/src/kagent/runtime/checkpoint_storage.py +270 -0
  73. package/src/kagent/runtime/context.py +65 -0
  74. package/src/kagent/runtime/file_transaction.py +195 -0
  75. package/src/kagent/runtime/hooks.py +74 -0
  76. package/src/kagent/runtime/metadata.py +116 -0
  77. package/src/kagent/runtime/patch_checkpoints.py +385 -0
  78. package/src/kagent/runtime/policy.py +50 -0
  79. package/src/kagent/runtime/presentation.py +205 -0
  80. package/src/kagent/runtime/redaction.py +130 -0
  81. package/src/kagent/runtime/sandbox.py +331 -0
  82. package/src/kagent/runtime/skills.py +66 -0
  83. package/src/kagent/runtime/steering.py +56 -0
  84. package/src/kagent/runtime/steps.py +255 -0
  85. package/src/kagent/runtime/task_state.py +40 -0
  86. package/src/kagent/runtime/tools.py +3532 -0
  87. package/src/kagent/runtime/types.py +240 -0
  88. package/src/kagent/runtime/workspace.py +597 -0
  89. package/src/kagent/service/__init__.py +26 -0
  90. package/src/kagent/service/__main__.py +6 -0
  91. package/src/kagent/service/active_runs.py +178 -0
  92. package/src/kagent/service/cli.py +737 -0
  93. package/src/kagent/service/contract.py +2571 -0
  94. package/src/kagent/service/errors.py +71 -0
  95. package/src/kagent/service/idempotency.py +584 -0
  96. package/src/kagent/service/router.py +884 -0
  97. package/src/kagent/service/run.py +150 -0
  98. package/src/kagent/service/runtime.py +1915 -0
  99. package/src/kagent/service/runtime_approval.py +20 -0
  100. package/src/kagent/service/runtime_cancel.py +192 -0
  101. package/src/kagent/service/runtime_lifecycle.py +229 -0
  102. package/src/kagent/service/runtime_metadata.py +21 -0
  103. package/src/kagent/service/runtime_policy.py +115 -0
  104. package/src/kagent/service/runtime_recovery.py +573 -0
  105. package/src/kagent/service/runtime_resume.py +382 -0
  106. package/src/kagent/service/runtime_resume_claim.py +116 -0
  107. package/src/kagent/service/runtime_run.py +350 -0
  108. package/src/kagent/service/runtime_status.py +2007 -0
  109. package/src/kagent/service/safety.py +139 -0
  110. package/src/kagent/service/server.py +114 -0
  111. package/src/kagent/service/status.py +233 -0
  112. package/src/kagent/service/trace_store.py +322 -0
  113. package/src/kagent/service/transport.py +24 -0
  114. package/src/kagent/utils/__init__.py +0 -0
  115. package/src/kagent/utils/config_validation.py +21 -0
  116. package/src/kagent/utils/json_output.py +23 -0
  117. package/src/kagent/utils/paths.py +473 -0
@@ -0,0 +1,150 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import io
5
+ import json
6
+ import warnings
7
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError
8
+ from typing import Any, Callable, Dict, Optional, Tuple
9
+
10
+ from kagent.service import errors as service_errors
11
+ from kagent.service.active_runs import ExecutionSlotLease
12
+ from kagent.service.errors import failure_payload
13
+ from kagent.service.runtime import ServiceConfig
14
+ from kagent.service.trace_store import persist_trace
15
+ from kagent.utils.config_validation import (
16
+ optional_json_bool,
17
+ optional_json_int,
18
+ )
19
+ from kagent.utils.json_output import json_ready
20
+
21
+
22
+ def execute_run_request(
23
+ body: bytes,
24
+ service_config: ServiceConfig,
25
+ agent_runner: Optional[Callable[[str, Any], Dict[str, Any]]] = None,
26
+ execution_slot_lease: Optional[ExecutionSlotLease] = None,
27
+ ) -> Tuple[int, Dict[str, Any]]:
28
+ try:
29
+ payload = json.loads(body.decode("utf-8"))
30
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
31
+ return 400, failure_payload(service_errors.INVALID_JSON, f"invalid JSON: {exc}")
32
+ if not isinstance(payload, dict):
33
+ return 400, failure_payload(
34
+ service_errors.INVALID_REQUEST_BODY,
35
+ "request body must be a JSON object",
36
+ )
37
+ goal = str(payload.get("goal", ""))
38
+ if not goal.strip():
39
+ return 400, failure_payload(service_errors.MISSING_GOAL, "goal is required")
40
+ if len(goal) > service_config.max_goal_chars:
41
+ return 413, failure_payload(
42
+ service_errors.GOAL_TOO_LARGE,
43
+ "goal exceeds max_goal_chars",
44
+ )
45
+ try:
46
+ wants_full_trace = optional_json_bool(payload, "full_trace", False)
47
+ except ValueError as exc:
48
+ return 400, failure_payload(service_errors.INVALID_REQUEST_BODY, str(exc))
49
+ if wants_full_trace and not service_config.allow_full_trace_response:
50
+ return 403, failure_payload(
51
+ service_errors.FULL_TRACE_DISABLED,
52
+ "full_trace responses are disabled",
53
+ )
54
+
55
+ warning_sink = io.StringIO()
56
+ with contextlib.redirect_stderr(warning_sink), warnings.catch_warnings():
57
+ warnings.simplefilter("ignore")
58
+ from kagent.core.agent import AgentConfig, run_agent
59
+ from kagent.core.summary import summarize_run
60
+
61
+ try:
62
+ defaults = AgentConfig()
63
+ config = AgentConfig(
64
+ max_steps=optional_int(payload, "max_steps", defaults.max_steps),
65
+ max_retries=optional_int(payload, "max_retries", defaults.max_retries),
66
+ )
67
+ except ValueError as exc:
68
+ return 400, failure_payload(service_errors.INVALID_AGENT_CONFIG, str(exc))
69
+
70
+ def run_with_config() -> Dict[str, Any]:
71
+ if agent_runner is not None:
72
+ return agent_runner(goal, config)
73
+ return run_agent(goal, config=config)
74
+
75
+ try:
76
+ release_worker_slot = (
77
+ execution_slot_lease.transfer()
78
+ if execution_slot_lease is not None
79
+ else None
80
+ )
81
+ timeout_options = {"timeout_seconds": service_config.run_timeout_seconds}
82
+ if release_worker_slot is not None:
83
+ timeout_options["on_complete"] = release_worker_slot
84
+ trace = run_with_timeout(run_with_config, **timeout_options)
85
+ except TimeoutError:
86
+ return 504, failure_payload(
87
+ service_errors.AGENT_RUN_TIMEOUT,
88
+ "agent run timed out",
89
+ )
90
+ except Exception:
91
+ return 500, failure_payload(service_errors.AGENT_RUN_FAILED, "agent run failed")
92
+ trace_path = ""
93
+ if service_config.trace_dir:
94
+ try:
95
+ trace_path = persist_trace(trace, service_config.trace_dir)
96
+ except OSError as exc:
97
+ return 500, failure_payload(
98
+ service_errors.TRACE_PERSISTENCE_FAILED,
99
+ f"could not persist trace: {exc}",
100
+ )
101
+ result = trace if wants_full_trace else summarize_run(trace)
102
+ if trace_path:
103
+ result["trace_path"] = trace_path
104
+ return 200, json_ready(result)
105
+
106
+
107
+ def run_with_timeout(
108
+ call,
109
+ *,
110
+ timeout_seconds: float,
111
+ on_timeout: Optional[Callable[[], None]] = None,
112
+ on_complete: Optional[Callable[[], None]] = None,
113
+ ) -> Dict[str, Any]:
114
+ executor = ThreadPoolExecutor(max_workers=1)
115
+
116
+ def run_and_complete() -> Dict[str, Any]:
117
+ try:
118
+ return call()
119
+ finally:
120
+ if on_complete is not None:
121
+ try:
122
+ on_complete()
123
+ except Exception:
124
+ # Lifecycle cleanup must not replace the worker result or error.
125
+ pass
126
+
127
+ future = executor.submit(run_and_complete)
128
+ try:
129
+ try:
130
+ return future.result(timeout=timeout_seconds)
131
+ except TimeoutError as timeout_error:
132
+ if future.done():
133
+ return future.result()
134
+ if on_timeout is not None:
135
+ on_timeout()
136
+ try:
137
+ future.result(timeout=timeout_seconds)
138
+ except TimeoutError:
139
+ pass
140
+ except Exception:
141
+ pass
142
+ raise timeout_error
143
+ finally:
144
+ if not future.done():
145
+ future.cancel()
146
+ executor.shutdown(wait=False, cancel_futures=True)
147
+
148
+
149
+ def optional_int(payload: Dict[str, Any], key: str, default: int) -> int:
150
+ return optional_json_int(payload, key, default)