agentic-programming 0.4.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.
- agentic/__init__.py +48 -0
- agentic/apps/__init__.py +1 -0
- agentic/apps/mini_lesson.py +47 -0
- agentic/cli.py +319 -0
- agentic/context.py +574 -0
- agentic/function.py +232 -0
- agentic/functions/__init__.py +2 -0
- agentic/functions/extract_domain.py +19 -0
- agentic/functions/sentiment.py +17 -0
- agentic/functions/word_count.py +14 -0
- agentic/mcp/__init__.py +1 -0
- agentic/mcp/__main__.py +4 -0
- agentic/mcp/server.py +189 -0
- agentic/meta_functions/__init__.py +17 -0
- agentic/meta_functions/_helpers.py +265 -0
- agentic/meta_functions/create.py +108 -0
- agentic/meta_functions/create_app.py +136 -0
- agentic/meta_functions/create_skill.py +62 -0
- agentic/meta_functions/fix.py +109 -0
- agentic/providers/__init__.py +169 -0
- agentic/providers/anthropic.py +234 -0
- agentic/providers/claude_code.py +327 -0
- agentic/providers/codex.py +275 -0
- agentic/providers/gemini.py +211 -0
- agentic/providers/gemini_cli.py +165 -0
- agentic/providers/openai.py +249 -0
- agentic/runtime.py +232 -0
- agentic_programming-0.4.0.dist-info/LICENSE +21 -0
- agentic_programming-0.4.0.dist-info/METADATA +373 -0
- agentic_programming-0.4.0.dist-info/RECORD +33 -0
- agentic_programming-0.4.0.dist-info/WHEEL +5 -0
- agentic_programming-0.4.0.dist-info/entry_points.txt +2 -0
- agentic_programming-0.4.0.dist-info/top_level.txt +1 -0
agentic/__init__.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agentic Programming — Python functions that call LLMs with automatic context.
|
|
3
|
+
|
|
4
|
+
Three things:
|
|
5
|
+
|
|
6
|
+
@agentic_function Decorator. Records every call into a Context tree.
|
|
7
|
+
Runtime LLM runtime class. Handles context injection and recording.
|
|
8
|
+
Context The tree of execution records. Query it with summarize().
|
|
9
|
+
|
|
10
|
+
Quick start:
|
|
11
|
+
|
|
12
|
+
from agentic import agentic_function, Runtime
|
|
13
|
+
|
|
14
|
+
runtime = Runtime(call=my_llm_func, model="gpt-4o")
|
|
15
|
+
|
|
16
|
+
@agentic_function
|
|
17
|
+
def observe(task):
|
|
18
|
+
'''Look at the screen and describe what you see.'''
|
|
19
|
+
return runtime.exec(content=[
|
|
20
|
+
{"type": "text", "text": "Find the login button."},
|
|
21
|
+
{"type": "image", "path": "screenshot.png"},
|
|
22
|
+
])
|
|
23
|
+
|
|
24
|
+
@agentic_function(compress=True)
|
|
25
|
+
def navigate(target):
|
|
26
|
+
'''Navigate to a target element.'''
|
|
27
|
+
obs = observe(f"find {target}")
|
|
28
|
+
action = plan(obs)
|
|
29
|
+
act(action)
|
|
30
|
+
return verify(target)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from agentic.context import Context
|
|
34
|
+
from agentic.function import agentic_function
|
|
35
|
+
from agentic.runtime import Runtime
|
|
36
|
+
from agentic.meta_functions import create, create_app, fix, create_skill
|
|
37
|
+
from agentic.providers import detect_provider, create_runtime
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"agentic_function",
|
|
41
|
+
"Runtime",
|
|
42
|
+
"Context",
|
|
43
|
+
"create",
|
|
44
|
+
"create_app",
|
|
45
|
+
"fix",
|
|
46
|
+
"detect_provider",
|
|
47
|
+
"create_runtime",
|
|
48
|
+
]
|
agentic/apps/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Generated apps — created by agentic.meta_functions.create_app()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""A CLI tool that takes a topic and generates a mini-lesson: first identify 3 key concepts, then explain each one, then synthesize a takeaway. Generated by agentic create-app."""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
from agentic import agentic_function, create_runtime
|
|
6
|
+
|
|
7
|
+
runtime = create_runtime()
|
|
8
|
+
|
|
9
|
+
@agentic_function
|
|
10
|
+
def identify_key_concepts(topic: str) -> str:
|
|
11
|
+
"""Identify 3 key concepts related to the topic."""
|
|
12
|
+
return runtime.exec(content=[
|
|
13
|
+
{"type": "text", "text": f"Identify 3 key concepts about {topic}."},
|
|
14
|
+
])
|
|
15
|
+
|
|
16
|
+
@agentic_function
|
|
17
|
+
def explain_concepts(concepts: str) -> str:
|
|
18
|
+
"""Explain each of the identified key concepts."""
|
|
19
|
+
return runtime.exec(content=[
|
|
20
|
+
{"type": "text", "text": f"Explain these concepts: {concepts}."},
|
|
21
|
+
])
|
|
22
|
+
|
|
23
|
+
@agentic_function
|
|
24
|
+
def synthesize_takeaway(explanation: str) -> str:
|
|
25
|
+
"""Synthesize a takeaway from the explanations."""
|
|
26
|
+
return runtime.exec(content=[
|
|
27
|
+
{"type": "text", "text": f"Synthesize a takeaway from these explanations: {explanation}."},
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
def main():
|
|
31
|
+
parser = argparse.ArgumentParser(description="Generate a mini-lesson from a given topic.")
|
|
32
|
+
parser.add_argument("topic", help="The topic for the mini-lesson")
|
|
33
|
+
parser.add_argument("--provider", default=None, help="LLM provider override")
|
|
34
|
+
parser.add_argument("--model", default=None, help="Model override")
|
|
35
|
+
args = parser.parse_args()
|
|
36
|
+
|
|
37
|
+
global runtime
|
|
38
|
+
runtime = create_runtime(provider=args.provider, model=args.model)
|
|
39
|
+
|
|
40
|
+
concepts = identify_key_concepts(topic=args.topic)
|
|
41
|
+
explanation = explain_concepts(concepts=concepts)
|
|
42
|
+
takeaway = synthesize_takeaway(explanation=explanation)
|
|
43
|
+
|
|
44
|
+
print(takeaway)
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
main()
|
agentic/cli.py
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentic CLI — command-line interface for Agentic Programming.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
agentic create "description" --name my_func
|
|
6
|
+
agentic fix my_func --instruction "change X to Y"
|
|
7
|
+
agentic run my_func --arg key=value
|
|
8
|
+
agentic list
|
|
9
|
+
agentic create-skill my_func
|
|
10
|
+
agentic providers # show available providers
|
|
11
|
+
agentic create "desc" --provider anthropic --model claude-sonnet-4-20250514
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import sys
|
|
16
|
+
import json
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _add_provider_args(parser):
|
|
20
|
+
"""Add --provider and --model arguments to a subcommand parser."""
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"--provider", "-p",
|
|
23
|
+
default=None,
|
|
24
|
+
help="LLM provider: claude-code, codex, gemini-cli, anthropic, openai, gemini. "
|
|
25
|
+
"Auto-detected if not specified.",
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--model", "-m",
|
|
29
|
+
default=None,
|
|
30
|
+
help="Model name override (e.g. sonnet, gpt-4o, claude-sonnet-4-20250514).",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def main():
|
|
35
|
+
parser = argparse.ArgumentParser(
|
|
36
|
+
prog="agentic",
|
|
37
|
+
description="Agentic Programming CLI — create, fix, and run LLM-powered functions.",
|
|
38
|
+
)
|
|
39
|
+
sub = parser.add_subparsers(dest="command", help="Command to run")
|
|
40
|
+
|
|
41
|
+
# create
|
|
42
|
+
p_create = sub.add_parser("create", help="Create a new function from description")
|
|
43
|
+
p_create.add_argument("description", help="What the function should do")
|
|
44
|
+
p_create.add_argument("--name", "-n", required=True, help="Function name")
|
|
45
|
+
p_create.add_argument("--as-skill", action="store_true", help="Also create a SKILL.md")
|
|
46
|
+
_add_provider_args(p_create)
|
|
47
|
+
|
|
48
|
+
# fix
|
|
49
|
+
p_fix = sub.add_parser("fix", help="Fix an existing function")
|
|
50
|
+
p_fix.add_argument("name", help="Function name to fix")
|
|
51
|
+
p_fix.add_argument("--instruction", "-i", default=None, help="What to change")
|
|
52
|
+
_add_provider_args(p_fix)
|
|
53
|
+
|
|
54
|
+
# run
|
|
55
|
+
p_run = sub.add_parser("run", help="Run an existing function")
|
|
56
|
+
p_run.add_argument("name", help="Function name to run")
|
|
57
|
+
p_run.add_argument("--arg", "-a", action="append", default=[], help="Arguments as key=value")
|
|
58
|
+
_add_provider_args(p_run)
|
|
59
|
+
|
|
60
|
+
# list
|
|
61
|
+
sub.add_parser("list", help="List all saved functions")
|
|
62
|
+
|
|
63
|
+
# create-app
|
|
64
|
+
p_app = sub.add_parser("create-app", help="Create a complete runnable app (runtime + functions + main)")
|
|
65
|
+
p_app.add_argument("description", help="What the app should do")
|
|
66
|
+
p_app.add_argument("--name", "-n", default="app", help="App name (default: app)")
|
|
67
|
+
_add_provider_args(p_app)
|
|
68
|
+
|
|
69
|
+
# create-skill
|
|
70
|
+
p_skill = sub.add_parser("create-skill", help="Create a SKILL.md for a function")
|
|
71
|
+
p_skill.add_argument("name", help="Function name")
|
|
72
|
+
_add_provider_args(p_skill)
|
|
73
|
+
|
|
74
|
+
# providers
|
|
75
|
+
sub.add_parser("providers", help="Show available LLM providers and detection status")
|
|
76
|
+
|
|
77
|
+
args = parser.parse_args()
|
|
78
|
+
|
|
79
|
+
if args.command is None:
|
|
80
|
+
parser.print_help()
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
# Lazy imports — only load when needed
|
|
84
|
+
if args.command == "list":
|
|
85
|
+
_cmd_list()
|
|
86
|
+
elif args.command == "providers":
|
|
87
|
+
_cmd_providers()
|
|
88
|
+
elif args.command == "create":
|
|
89
|
+
_cmd_create(args.description, args.name, args.as_skill, args.provider, args.model)
|
|
90
|
+
elif args.command == "create-app":
|
|
91
|
+
_cmd_create_app(args.description, args.name, args.provider, args.model)
|
|
92
|
+
elif args.command == "fix":
|
|
93
|
+
_cmd_fix(args.name, args.instruction, args.provider, args.model)
|
|
94
|
+
elif args.command == "run":
|
|
95
|
+
_cmd_run(args.name, args.arg, args.provider, args.model)
|
|
96
|
+
elif args.command == "create-skill":
|
|
97
|
+
_cmd_create_skill(args.name, args.provider, args.model)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _get_runtime(provider=None, model=None):
|
|
101
|
+
"""Get a Runtime via auto-detection or explicit provider.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
provider: Provider name (e.g. "anthropic", "claude-code").
|
|
105
|
+
If None, auto-detects the best available.
|
|
106
|
+
model: Model name override.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
A ready-to-use Runtime instance.
|
|
110
|
+
"""
|
|
111
|
+
from agentic.providers import create_runtime
|
|
112
|
+
return create_runtime(provider=provider, model=model)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _get_functions_dir():
|
|
116
|
+
import os
|
|
117
|
+
return os.path.join(os.path.dirname(__file__), "functions")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _cmd_providers():
|
|
121
|
+
"""Show available providers and which one would be auto-detected."""
|
|
122
|
+
import os
|
|
123
|
+
import shutil
|
|
124
|
+
from agentic.providers import PROVIDERS
|
|
125
|
+
|
|
126
|
+
print("Available LLM providers:\n")
|
|
127
|
+
|
|
128
|
+
# Check what's available
|
|
129
|
+
detected = None
|
|
130
|
+
statuses = {}
|
|
131
|
+
|
|
132
|
+
cli_checks = {
|
|
133
|
+
"claude-code": ("claude", "Claude Code CLI"),
|
|
134
|
+
"codex": ("codex", "Codex CLI"),
|
|
135
|
+
"gemini-cli": ("gemini", "Gemini CLI"),
|
|
136
|
+
}
|
|
137
|
+
api_checks = {
|
|
138
|
+
"anthropic": ("ANTHROPIC_API_KEY", "Anthropic API"),
|
|
139
|
+
"openai": ("OPENAI_API_KEY", "OpenAI API"),
|
|
140
|
+
"gemini": ("GOOGLE_API_KEY", "Gemini API"),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Detection order matches detect_provider()
|
|
144
|
+
detection_order = ["claude-code", "codex", "gemini-cli", "anthropic", "openai", "gemini"]
|
|
145
|
+
|
|
146
|
+
for name in detection_order:
|
|
147
|
+
_, _, default_model = PROVIDERS[name]
|
|
148
|
+
|
|
149
|
+
if name in cli_checks:
|
|
150
|
+
cmd, label = cli_checks[name]
|
|
151
|
+
found = shutil.which(cmd) is not None
|
|
152
|
+
status = "ready" if found else "not found"
|
|
153
|
+
how = f"`{cmd}` in PATH" if found else f"install: npm install -g ..."
|
|
154
|
+
else:
|
|
155
|
+
env_var, label = api_checks[name]
|
|
156
|
+
found = bool(os.environ.get(env_var))
|
|
157
|
+
status = "ready" if found else "not set"
|
|
158
|
+
how = f"${env_var}" if found else f"export {env_var}=..."
|
|
159
|
+
|
|
160
|
+
if found and detected is None:
|
|
161
|
+
detected = name
|
|
162
|
+
marker = " <-- auto-detected"
|
|
163
|
+
else:
|
|
164
|
+
marker = ""
|
|
165
|
+
|
|
166
|
+
icon = "+" if found else "-"
|
|
167
|
+
print(f" [{icon}] {name:14s} ({label:16s}) model: {default_model:30s} [{status}]{marker}")
|
|
168
|
+
|
|
169
|
+
print()
|
|
170
|
+
if detected:
|
|
171
|
+
print(f"Auto-detected provider: {detected}")
|
|
172
|
+
print(f"Override with: agentic <command> --provider <name> --model <model>")
|
|
173
|
+
else:
|
|
174
|
+
print("No provider detected. Set up one of the above to get started.")
|
|
175
|
+
print("See: https://github.com/Fzkuji/Agentic-Programming#quick-start")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _cmd_list():
|
|
179
|
+
"""List all saved functions."""
|
|
180
|
+
import os
|
|
181
|
+
functions_dir = _get_functions_dir()
|
|
182
|
+
if not os.path.exists(functions_dir):
|
|
183
|
+
print("No functions created yet.")
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
files = [f[:-3] for f in os.listdir(functions_dir)
|
|
187
|
+
if f.endswith(".py") and f != "__init__.py"]
|
|
188
|
+
if not files:
|
|
189
|
+
print("No functions created yet.")
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
print(f"Functions ({len(files)}):\n")
|
|
193
|
+
for name in sorted(files):
|
|
194
|
+
filepath = os.path.join(functions_dir, f"{name}.py")
|
|
195
|
+
# Read first line of docstring
|
|
196
|
+
with open(filepath) as f:
|
|
197
|
+
content = f.read()
|
|
198
|
+
desc = ""
|
|
199
|
+
if '"""' in content:
|
|
200
|
+
start = content.index('"""') + 3
|
|
201
|
+
end = content.index('"""', start)
|
|
202
|
+
desc = content[start:end].strip().split("\n")[0]
|
|
203
|
+
print(f" {name:20s} {desc}")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _cmd_create(description, name, as_skill, provider=None, model=None):
|
|
207
|
+
"""Create a new function."""
|
|
208
|
+
from agentic.meta_functions import create
|
|
209
|
+
runtime = _get_runtime(provider, model)
|
|
210
|
+
|
|
211
|
+
print(f"Creating '{name}' (provider: {runtime.__class__.__name__})...")
|
|
212
|
+
fn = create(description=description, runtime=runtime, name=name, as_skill=as_skill)
|
|
213
|
+
print(f" Saved to agentic/functions/{name}.py")
|
|
214
|
+
if as_skill:
|
|
215
|
+
print(f" Skill created at skills/{name}/SKILL.md")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _cmd_create_app(description, name, provider=None, model=None):
|
|
219
|
+
"""Create a complete runnable app."""
|
|
220
|
+
from agentic.meta_functions import create_app
|
|
221
|
+
runtime = _get_runtime(provider, model)
|
|
222
|
+
|
|
223
|
+
print(f"Creating app '{name}' (provider: {runtime.__class__.__name__})...")
|
|
224
|
+
filepath = create_app(description=description, runtime=runtime, name=name)
|
|
225
|
+
print(f" Saved to {filepath}")
|
|
226
|
+
print(f" Run with: python {filepath}")
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _cmd_fix(name, instruction, provider=None, model=None):
|
|
230
|
+
"""Fix an existing function."""
|
|
231
|
+
import importlib
|
|
232
|
+
from agentic.meta_functions import fix
|
|
233
|
+
runtime = _get_runtime(provider, model)
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
mod = importlib.import_module(f"agentic.functions.{name}")
|
|
237
|
+
fn = getattr(mod, name)
|
|
238
|
+
except (ImportError, AttributeError):
|
|
239
|
+
print(f"Error: function '{name}' not found in agentic/functions/")
|
|
240
|
+
sys.exit(1)
|
|
241
|
+
|
|
242
|
+
print(f"Fixing '{name}' (provider: {runtime.__class__.__name__})...")
|
|
243
|
+
fixed = fix(fn=fn, runtime=runtime, instruction=instruction)
|
|
244
|
+
print(f" Fixed and saved to agentic/functions/{name}.py")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _cmd_run(name, arg_list, provider=None, model=None):
|
|
248
|
+
"""Run an existing function."""
|
|
249
|
+
import importlib
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
mod = importlib.import_module(f"agentic.functions.{name}")
|
|
253
|
+
fn = getattr(mod, name)
|
|
254
|
+
except (ImportError, AttributeError):
|
|
255
|
+
print(f"Error: function '{name}' not found in agentic/functions/")
|
|
256
|
+
sys.exit(1)
|
|
257
|
+
|
|
258
|
+
# Check if it needs runtime
|
|
259
|
+
import inspect
|
|
260
|
+
source = inspect.getsource(fn) if hasattr(fn, '_fn') else ""
|
|
261
|
+
if hasattr(fn, '_fn'):
|
|
262
|
+
try:
|
|
263
|
+
source = inspect.getsource(fn._fn)
|
|
264
|
+
except (OSError, TypeError):
|
|
265
|
+
source = ""
|
|
266
|
+
|
|
267
|
+
if "runtime.exec" in source or "runtime" in str(getattr(fn, '__globals__', {})):
|
|
268
|
+
runtime = _get_runtime(provider, model)
|
|
269
|
+
if hasattr(fn, '_fn') and fn._fn:
|
|
270
|
+
fn._fn.__globals__['runtime'] = runtime
|
|
271
|
+
elif hasattr(fn, '__globals__'):
|
|
272
|
+
fn.__globals__['runtime'] = runtime
|
|
273
|
+
|
|
274
|
+
# Parse arguments
|
|
275
|
+
kwargs = {}
|
|
276
|
+
for a in arg_list:
|
|
277
|
+
if "=" in a:
|
|
278
|
+
k, v = a.split("=", 1)
|
|
279
|
+
kwargs[k] = v
|
|
280
|
+
else:
|
|
281
|
+
print(f"Error: argument must be key=value, got '{a}'")
|
|
282
|
+
sys.exit(1)
|
|
283
|
+
|
|
284
|
+
result = fn(**kwargs)
|
|
285
|
+
print(result)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _cmd_create_skill(name, provider=None, model=None):
|
|
289
|
+
"""Create a SKILL.md for a function."""
|
|
290
|
+
import importlib
|
|
291
|
+
import inspect
|
|
292
|
+
from agentic.meta_functions import create_skill
|
|
293
|
+
runtime = _get_runtime(provider, model)
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
mod = importlib.import_module(f"agentic.functions.{name}")
|
|
297
|
+
fn = getattr(mod, name)
|
|
298
|
+
except (ImportError, AttributeError):
|
|
299
|
+
print(f"Error: function '{name}' not found in agentic/functions/")
|
|
300
|
+
sys.exit(1)
|
|
301
|
+
|
|
302
|
+
# Get source and description
|
|
303
|
+
try:
|
|
304
|
+
if hasattr(fn, '_fn'):
|
|
305
|
+
code = inspect.getsource(fn._fn)
|
|
306
|
+
else:
|
|
307
|
+
code = inspect.getsource(fn)
|
|
308
|
+
except (OSError, TypeError):
|
|
309
|
+
code = f"# Source not available for {name}"
|
|
310
|
+
|
|
311
|
+
description = getattr(fn, '__doc__', '') or name
|
|
312
|
+
|
|
313
|
+
print(f"Creating skill for '{name}'...")
|
|
314
|
+
path = create_skill(fn_name=name, description=description, code=code, runtime=runtime)
|
|
315
|
+
print(f" Skill created at {path}")
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if __name__ == "__main__":
|
|
319
|
+
main()
|