kora-agent 0.1.0__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.
Files changed (92) hide show
  1. kora/__init__.py +31 -0
  2. kora/_version.py +3 -0
  3. kora/cli.py +349 -0
  4. kora/host/__init__.py +166 -0
  5. kora/host/commands.py +711 -0
  6. kora/host/context.py +209 -0
  7. kora/host/identity.py +163 -0
  8. kora/host/instructions.py +247 -0
  9. kora/host/interactions.py +376 -0
  10. kora/host/loader.py +539 -0
  11. kora/host/permission.py +221 -0
  12. kora/host/repl.py +242 -0
  13. kora/host/runner.py +204 -0
  14. kora/host/storage.py +361 -0
  15. kora/host/workspace.py +349 -0
  16. kora/interface/__init__.py +34 -0
  17. kora/interface/console.py +203 -0
  18. kora/interface/interaction.py +72 -0
  19. kora/interface/markdown.py +163 -0
  20. kora/interface/repl.py +132 -0
  21. kora/kernel/__init__.py +23 -0
  22. kora/kernel/loop.py +215 -0
  23. kora/kernel/model.py +46 -0
  24. kora/kernel/tool.py +97 -0
  25. kora/kernel/types.py +62 -0
  26. kora/providers/__init__.py +205 -0
  27. kora/providers/api/__init__.py +22 -0
  28. kora/providers/api/anthropic_messages.py +344 -0
  29. kora/providers/api/base.py +94 -0
  30. kora/providers/api/converters.py +118 -0
  31. kora/providers/api/openai_completions.py +280 -0
  32. kora/providers/api/registry.py +78 -0
  33. kora/providers/auth.py +74 -0
  34. kora/providers/builtins/__init__.py +63 -0
  35. kora/providers/builtins/anthropic.py +136 -0
  36. kora/providers/builtins/cerebras.py +29 -0
  37. kora/providers/builtins/cohere.py +119 -0
  38. kora/providers/builtins/dashscope.py +213 -0
  39. kora/providers/builtins/deepseek.py +81 -0
  40. kora/providers/builtins/fireworks.py +101 -0
  41. kora/providers/builtins/google.py +98 -0
  42. kora/providers/builtins/groq.py +118 -0
  43. kora/providers/builtins/jdcloud.py +41 -0
  44. kora/providers/builtins/minimax.py +74 -0
  45. kora/providers/builtins/mistral.py +131 -0
  46. kora/providers/builtins/moonshot.py +74 -0
  47. kora/providers/builtins/nvidia.py +179 -0
  48. kora/providers/builtins/ollama.py +152 -0
  49. kora/providers/builtins/openai.py +193 -0
  50. kora/providers/builtins/openrouter.py +86 -0
  51. kora/providers/builtins/perplexity.py +55 -0
  52. kora/providers/builtins/siliconflow.py +124 -0
  53. kora/providers/builtins/stepfun.py +46 -0
  54. kora/providers/builtins/tencent.py +50 -0
  55. kora/providers/builtins/together.py +145 -0
  56. kora/providers/builtins/volcengine.py +82 -0
  57. kora/providers/builtins/xai.py +95 -0
  58. kora/providers/builtins/xiaomi.py +54 -0
  59. kora/providers/builtins/zhipu.py +138 -0
  60. kora/providers/errors.py +127 -0
  61. kora/providers/model.py +235 -0
  62. kora/providers/provider.py +164 -0
  63. kora/providers/registry.py +195 -0
  64. kora/providers/retry.py +154 -0
  65. kora/runtime/__init__.py +44 -0
  66. kora/runtime/agent.py +263 -0
  67. kora/runtime/events.py +96 -0
  68. kora/runtime/run.py +342 -0
  69. kora/runtime/session.py +247 -0
  70. kora/tools/__init__.py +128 -0
  71. kora/tools/base.py +94 -0
  72. kora/tools/config.py +50 -0
  73. kora/tools/decorator.py +193 -0
  74. kora/tools/execution/__init__.py +33 -0
  75. kora/tools/execution/code.py +361 -0
  76. kora/tools/execution/shell.py +220 -0
  77. kora/tools/filesystem/__init__.py +56 -0
  78. kora/tools/filesystem/editing.py +240 -0
  79. kora/tools/filesystem/listing.py +175 -0
  80. kora/tools/filesystem/reading.py +152 -0
  81. kora/tools/filesystem/searching.py +265 -0
  82. kora/tools/network/__init__.py +38 -0
  83. kora/tools/network/fetching.py +131 -0
  84. kora/tools/network/http.py +265 -0
  85. kora/tools/network/searching.py +119 -0
  86. kora/tools/security/__init__.py +45 -0
  87. kora/tools/security/patterns.py +248 -0
  88. kora/tools/security/validation.py +190 -0
  89. kora_agent-0.1.0.dist-info/METADATA +381 -0
  90. kora_agent-0.1.0.dist-info/RECORD +92 -0
  91. kora_agent-0.1.0.dist-info/WHEEL +4 -0
  92. kora_agent-0.1.0.dist-info/entry_points.txt +2 -0
kora/__init__.py ADDED
@@ -0,0 +1,31 @@
1
+ """
2
+ Kora - A lightweight Agent framework.
3
+ """
4
+
5
+ from kora._version import __version__
6
+ from kora.runtime import Agent, Session
7
+ from kora.tools import tool
8
+
9
+ # Providers
10
+ from kora.providers import (
11
+ Model,
12
+ ModelSpec,
13
+ ModelCost,
14
+ Provider,
15
+ ProviderSpec,
16
+ get_provider_registry,
17
+ )
18
+
19
+ __all__ = [
20
+ "__version__",
21
+ "Agent",
22
+ "Session",
23
+ "tool",
24
+ # Providers
25
+ "Model",
26
+ "ModelSpec",
27
+ "ModelCost",
28
+ "Provider",
29
+ "ProviderSpec",
30
+ "get_provider_registry",
31
+ ]
kora/_version.py ADDED
@@ -0,0 +1,3 @@
1
+ """Version information for Kora."""
2
+
3
+ __version__ = "0.1.0"
kora/cli.py ADDED
@@ -0,0 +1,349 @@
1
+ """
2
+ CLI for Kora Agent Framework.
3
+
4
+ Provides commands to run agents:
5
+ - kora run --agent <path> "message" # One-shot execution
6
+ - kora code "message" # One-shot with kora-code agent
7
+ - kora code # Interactive REPL mode
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ from kora.host import (
17
+ setup_agent,
18
+ AgentSetup,
19
+ find_builtin_agent,
20
+ load_agent_commands,
21
+ ReplRuntime,
22
+ create_default_registry,
23
+ )
24
+ from kora.interface import (
25
+ ConsoleRenderer,
26
+ print_command_menu,
27
+ create_repl_input,
28
+ HAS_PROMPT_TOOLKIT,
29
+ render_markdown_lite,
30
+ )
31
+
32
+
33
+ def run_agent(
34
+ agent_path: Path,
35
+ workspace: Path,
36
+ user_message: str,
37
+ *,
38
+ provider: str | None = None,
39
+ model: str | None = None,
40
+ session_id: str | None = None,
41
+ ) -> int:
42
+ """
43
+ Run an agent with a single message (one-shot mode).
44
+
45
+ Args:
46
+ agent_path: Path to AGENT.md file.
47
+ workspace: Workspace directory for file operations.
48
+ user_message: The task or question for the agent.
49
+ provider: Model provider override.
50
+ model: Model name override.
51
+ session_id: Optional session ID to resume.
52
+
53
+ Returns:
54
+ Exit code (0 for success, 1 for error).
55
+ """
56
+ # Setup agent (Host layer)
57
+ setup = setup_agent(agent_path, workspace, provider=provider, model=model)
58
+ if setup is None:
59
+ print(f"Error: Failed to setup agent from {agent_path}", file=sys.stderr)
60
+ return 1
61
+
62
+ agent = setup.agent
63
+
64
+ # Open or resume session
65
+ if session_id:
66
+ session = agent.load_session(session_id)
67
+ if session is None:
68
+ print(f"Session {session_id} not found, creating new session")
69
+ session = agent.open_session(session_id=session_id)
70
+ else:
71
+ session = agent.open_session()
72
+
73
+ print(f"Workspace: {setup.workspace_id}")
74
+ print(f"Session: {session.id}")
75
+
76
+ # Use ConsoleRenderer for verbose one-shot mode
77
+ renderer = ConsoleRenderer(verbose=True)
78
+
79
+ # Run
80
+ session.send_sync(
81
+ user_message,
82
+ on_event=lambda e: _print_rendered(renderer.render(e))
83
+ )
84
+
85
+ # Save session after execution
86
+ session.save()
87
+
88
+ return 0
89
+
90
+
91
+ def _print_rendered(output: str | None) -> None:
92
+ """Print rendered output if not None."""
93
+ if output:
94
+ print(output)
95
+
96
+
97
+ def run_repl(
98
+ agent_path: Path,
99
+ workspace: Path,
100
+ *,
101
+ provider: str | None = None,
102
+ model: str | None = None,
103
+ session_id: str | None = None,
104
+ ) -> int:
105
+ """
106
+ Run an agent in interactive REPL mode.
107
+
108
+ Args:
109
+ agent_path: Path to AGENT.md file.
110
+ workspace: Workspace directory for file operations.
111
+ provider: Model provider override.
112
+ model: Model name override.
113
+ session_id: Optional session ID to resume.
114
+
115
+ Returns:
116
+ Exit code (0 for success, 1 for error).
117
+ """
118
+ # Setup agent (Host layer)
119
+ setup = setup_agent(agent_path, workspace, provider=provider, model=model)
120
+ if setup is None:
121
+ print(f"Error: Failed to setup agent from {agent_path}", file=sys.stderr)
122
+ return 1
123
+
124
+ agent = setup.agent
125
+ context_builder = setup.context_builder
126
+ provider_name = setup.provider_name
127
+ model_name = setup.model_name
128
+ workspace_id = setup.workspace_id
129
+
130
+ # Open or resume session
131
+ if session_id:
132
+ session = agent.load_session(session_id)
133
+ if session is None:
134
+ print(f"Session {session_id} not found, creating new session")
135
+ session = agent.open_session(session_id=session_id)
136
+ else:
137
+ session = agent.open_session()
138
+
139
+ # Create command registry and load agent extensions (ADR-010)
140
+ registry = create_default_registry()
141
+ loaded_count = load_agent_commands(setup.agent_package.path, registry)
142
+ if loaded_count > 0:
143
+ print(f" Loaded {loaded_count} custom command(s)")
144
+
145
+ # Create ReplRuntime - encapsulates all REPL logic (Host layer)
146
+ runtime = ReplRuntime(
147
+ session=session,
148
+ agent=agent,
149
+ context_builder=context_builder,
150
+ provider_name=provider_name,
151
+ model_name=model_name,
152
+ registry=registry,
153
+ )
154
+
155
+ # Use ConsoleRenderer for compact REPL mode
156
+ renderer = ConsoleRenderer(verbose=False)
157
+
158
+ # Print welcome message
159
+ print(f"\n🤖 Kora Code Agent")
160
+ print(f" Workspace: {workspace_id}")
161
+ print(f" Session: {session.id}")
162
+ print(f" Model: {provider_name}/{model_name}")
163
+ print(f" Workspace path: {workspace}")
164
+ print(f"\nType your message and press Enter. Type '/' to see commands.\n")
165
+
166
+ # Run REPL loop (Interface layer handles input)
167
+ return _run_repl(session, agent, runtime, renderer, registry)
168
+
169
+
170
+ def _run_repl(
171
+ session,
172
+ agent,
173
+ runtime: ReplRuntime,
174
+ renderer: ConsoleRenderer,
175
+ registry,
176
+ ) -> int:
177
+ """
178
+ Run REPL loop using interface layer for input.
179
+
180
+ Uses prompt_toolkit if available for auto-completion,
181
+ otherwise falls back to basic input.
182
+ """
183
+ # Create input handler from interface layer
184
+ repl_input = create_repl_input(registry)
185
+
186
+ try:
187
+ while True:
188
+ try:
189
+ # Add a blank line for visual breathing before input
190
+ user_input = repl_input.get_input("\n> ").strip()
191
+
192
+ if not user_input:
193
+ continue
194
+
195
+ # Basic REPL: show menu when user types just "/"
196
+ if not HAS_PROMPT_TOOLKIT and user_input == "/":
197
+ print_command_menu(registry)
198
+ continue
199
+
200
+ # Delegate command handling to ReplRuntime (Host layer)
201
+ result = runtime.execute_command(user_input)
202
+ if result is not None:
203
+ if runtime.is_exit_requested(result):
204
+ print(f"\n{render_markdown_lite(result.message)}")
205
+ break
206
+ prefix = "✅" if result.status == "ok" else "❌"
207
+ print(f"\n{render_markdown_lite(result.message)}")
208
+ continue
209
+
210
+ # Normal message to agent
211
+ session.send_sync(
212
+ user_input,
213
+ on_event=lambda e: _print_rendered(renderer.render(e))
214
+ )
215
+ session.save()
216
+
217
+ except KeyboardInterrupt:
218
+ print("\n\n👋 Session saved. Bye!")
219
+ break
220
+ except EOFError:
221
+ print("\n\n👋 Session saved. Bye!")
222
+ break
223
+
224
+ except Exception as e:
225
+ print(f"\n❌ Unexpected error: {e}", file=sys.stderr)
226
+ return 1
227
+
228
+ return 0
229
+
230
+
231
+ def main() -> int:
232
+ """Main CLI entry point."""
233
+ parser = argparse.ArgumentParser(
234
+ prog="kora",
235
+ description="Kora Agent Framework",
236
+ )
237
+ subparsers = parser.add_subparsers(dest="command", required=True)
238
+
239
+ # kora run --agent <path> [message]
240
+ run_parser = subparsers.add_parser("run", help="Run an agent from AGENT.md")
241
+ run_parser.add_argument(
242
+ "--agent",
243
+ type=Path,
244
+ required=True,
245
+ help="Path to AGENT.md file",
246
+ )
247
+ run_parser.add_argument(
248
+ "--workspace",
249
+ type=Path,
250
+ default=Path.cwd(),
251
+ help="Workspace directory (default: current directory)",
252
+ )
253
+ run_parser.add_argument(
254
+ "--provider",
255
+ help="Model provider (e.g., anthropic, openai, deepseek)",
256
+ )
257
+ run_parser.add_argument(
258
+ "--model",
259
+ help="Model name (e.g., claude-sonnet-4-20250514, gpt-4o)",
260
+ )
261
+ run_parser.add_argument(
262
+ "--session",
263
+ help="Resume a session by ID",
264
+ )
265
+ run_parser.add_argument(
266
+ "message",
267
+ nargs="?",
268
+ help="Task or question for the agent (omit for REPL mode)",
269
+ )
270
+
271
+ # kora code [message]
272
+ code_parser = subparsers.add_parser("code", help="Run Kora Code Agent")
273
+ code_parser.add_argument(
274
+ "--workspace",
275
+ type=Path,
276
+ default=Path.cwd(),
277
+ help="Workspace directory (default: current directory)",
278
+ )
279
+ code_parser.add_argument(
280
+ "--provider",
281
+ help="Model provider (e.g., anthropic, openai, deepseek)",
282
+ )
283
+ code_parser.add_argument(
284
+ "--model",
285
+ help="Model name (e.g., claude-sonnet-4-20250514, gpt-4o)",
286
+ )
287
+ code_parser.add_argument(
288
+ "--session",
289
+ help="Resume a session by ID",
290
+ )
291
+ code_parser.add_argument(
292
+ "message",
293
+ nargs="?",
294
+ help="Task or question for the agent (omit for REPL mode)",
295
+ )
296
+
297
+ args = parser.parse_args()
298
+
299
+ if args.command == "run":
300
+ agent_path = args.agent
301
+ if args.message:
302
+ return run_agent(
303
+ agent_path=agent_path,
304
+ workspace=args.workspace,
305
+ user_message=args.message,
306
+ provider=args.provider,
307
+ model=args.model,
308
+ session_id=args.session,
309
+ )
310
+ else:
311
+ return run_repl(
312
+ agent_path=agent_path,
313
+ workspace=args.workspace,
314
+ provider=args.provider,
315
+ model=args.model,
316
+ session_id=args.session,
317
+ )
318
+
319
+ elif args.command == "code":
320
+ agent_dir = find_builtin_agent("kora-code")
321
+ if agent_dir is None:
322
+ print("Error: Kora Code Agent not found", file=sys.stderr)
323
+ print("Install it: pip install kora-agent kora-code", file=sys.stderr)
324
+ print("Or: pip install kora-agent[code]", file=sys.stderr)
325
+ return 1
326
+
327
+ if args.message:
328
+ return run_agent(
329
+ agent_path=agent_dir,
330
+ workspace=args.workspace,
331
+ user_message=args.message,
332
+ provider=args.provider,
333
+ model=args.model,
334
+ session_id=args.session,
335
+ )
336
+ else:
337
+ return run_repl(
338
+ agent_path=agent_dir,
339
+ workspace=args.workspace,
340
+ provider=args.provider,
341
+ model=args.model,
342
+ session_id=args.session,
343
+ )
344
+
345
+ return 0
346
+
347
+
348
+ if __name__ == "__main__":
349
+ sys.exit(main())
kora/host/__init__.py ADDED
@@ -0,0 +1,166 @@
1
+ """
2
+ Host layer for Kora.
3
+
4
+ The host layer manages persistence, file system access, identity, and resources.
5
+ """
6
+
7
+ from kora.host.loader import (
8
+ AgentConfigYaml,
9
+ AgentPackage,
10
+ load_agent_from_markdown,
11
+ load_agent_package,
12
+ load_agent_commands,
13
+ load_agent_interactions,
14
+ find_builtin_agent,
15
+ )
16
+ from kora.host.storage import (
17
+ FileStorage,
18
+ FileStorageConfig,
19
+ RunState,
20
+ Storage,
21
+ )
22
+ from kora.host.identity import (
23
+ User,
24
+ IdentityResolver,
25
+ EnvIdentityResolver,
26
+ StaticIdentityResolver,
27
+ DefaultUserResolver,
28
+ )
29
+ from kora.host.workspace import (
30
+ WorkspaceBinding,
31
+ WorkspaceResolver,
32
+ )
33
+ from kora.host.permission import (
34
+ Permission,
35
+ PermissionDeniedError,
36
+ PermissionPolicy,
37
+ HostPermissionPolicy,
38
+ PermissivePolicy,
39
+ CompositePolicy,
40
+ create_default_policy,
41
+ )
42
+ from kora.host.instructions import (
43
+ InstructionScope,
44
+ InstructionSource,
45
+ TemplateContext,
46
+ InstructionComposer,
47
+ resolve_instruction_sources,
48
+ )
49
+ from kora.host.commands import (
50
+ CommandResult,
51
+ CommandContext,
52
+ CommandRegistry,
53
+ create_default_registry,
54
+ HelpCommand,
55
+ ClearCommand,
56
+ ExitCommand,
57
+ SessionCommand,
58
+ ModelCommand,
59
+ ModeCommand,
60
+ ContextCommand,
61
+ ResetCommand,
62
+ ReplAction,
63
+ VALID_MODES,
64
+ MODE_DESCRIPTIONS,
65
+ )
66
+ from kora.host.interactions import (
67
+ InteractionKind,
68
+ InteractionOption,
69
+ InteractionRequest,
70
+ InteractionResponse,
71
+ InteractionContext,
72
+ Interaction,
73
+ InteractionRegistry,
74
+ ChoiceInteraction,
75
+ ConfirmInteraction,
76
+ InputInteraction,
77
+ MenuInteraction,
78
+ create_default_registry as create_default_interaction_registry,
79
+ )
80
+ from kora.host.context import (
81
+ ContextRebuilder,
82
+ )
83
+ from kora.host.repl import (
84
+ ReplState,
85
+ ReplRuntime,
86
+ )
87
+ from kora.host.runner import (
88
+ AgentSetup,
89
+ setup_agent,
90
+ )
91
+
92
+ __all__ = [
93
+ # Agent loading
94
+ "load_agent_from_markdown",
95
+ "load_agent_package",
96
+ "load_agent_commands",
97
+ "load_agent_interactions",
98
+ "find_builtin_agent",
99
+ "AgentConfigYaml",
100
+ "AgentPackage",
101
+ # Storage
102
+ "Storage",
103
+ "FileStorage",
104
+ "FileStorageConfig",
105
+ "RunState",
106
+ # Identity
107
+ "User",
108
+ "IdentityResolver",
109
+ "EnvIdentityResolver",
110
+ "StaticIdentityResolver",
111
+ "DefaultUserResolver",
112
+ # Workspace
113
+ "WorkspaceBinding",
114
+ "WorkspaceResolver",
115
+ # Permission
116
+ "Permission",
117
+ "PermissionDeniedError",
118
+ "PermissionPolicy",
119
+ "HostPermissionPolicy",
120
+ "PermissivePolicy",
121
+ "CompositePolicy",
122
+ "create_default_policy",
123
+ # Instructions
124
+ "InstructionScope",
125
+ "InstructionSource",
126
+ "TemplateContext",
127
+ "InstructionComposer",
128
+ "resolve_instruction_sources",
129
+ # Commands
130
+ "CommandResult",
131
+ "CommandContext",
132
+ "CommandRegistry",
133
+ "create_default_registry",
134
+ "HelpCommand",
135
+ "ClearCommand",
136
+ "ExitCommand",
137
+ "SessionCommand",
138
+ "ModelCommand",
139
+ "ModeCommand",
140
+ "ContextCommand",
141
+ "ResetCommand",
142
+ "ReplAction",
143
+ "VALID_MODES",
144
+ "MODE_DESCRIPTIONS",
145
+ # Interactions
146
+ "InteractionKind",
147
+ "InteractionOption",
148
+ "InteractionRequest",
149
+ "InteractionResponse",
150
+ "InteractionContext",
151
+ "Interaction",
152
+ "InteractionRegistry",
153
+ "ChoiceInteraction",
154
+ "ConfirmInteraction",
155
+ "InputInteraction",
156
+ "MenuInteraction",
157
+ "create_default_interaction_registry",
158
+ # Context
159
+ "ContextRebuilder",
160
+ # REPL
161
+ "ReplState",
162
+ "ReplRuntime",
163
+ # Runner
164
+ "AgentSetup",
165
+ "setup_agent",
166
+ ]