Metadata-Version: 2.4
Name: ExeCutie
Version: 0.1.0
Summary: Multi-provider agentic AI with live runtime access for PyQt6 applications.
Author: SeismicFlow
License: MIT
Project-URL: Homepage, https://github.com/<your-seismicflow-org>/executie
Project-URL: Repository, https://github.com/<your-seismicflow-org>/executie
Project-URL: Issues, https://github.com/<your-seismicflow-org>/executie/issues
Keywords: pyqt6,pyqt,qt,ai,agent,agentic,llm,groq,anthropic,openai,gemini,openrouter
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Environment :: X11 Applications :: Qt
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: openai>=1.0
Requires-Dist: anthropic>=0.25
Requires-Dist: requests>=2.28
Requires-Dist: beautifulsoup4>=4.11
Provides-Extra: gui
Requires-Dist: PyQt6>=6.4; extra == "gui"

# executie
*(as in "ExeCutie" — it executes, live, inside your running app)*

**One function. The model decides everything else.**

```python
from executie import ai

ai.setup("groq", "your-key-here")  # free, 14,400 req/day, no card
ai("what's the weather API look like for this project")
```

No `ai.ask()`, no `ai.search()`, no `ai.code()`, no extra flag for "agent
mode." One call. The model decides whether to answer directly, search the
web, run code, read a file, or reach into your application's own live
objects — and when it's done. Exactly like talking to Claude in a chat
window: one message box, one model, no separate modes.

## What makes this different

Agent frameworks exist. What we couldn't find anywhere else is an agent that
runs *inside* a live desktop application's own process, with direct access
to that application's live objects, while it's running.

Picture QGIS. It doesn't have the exact mapping algorithm you need today.
Ask anyway — the agent writes the backend function, builds a `QDialog` for
it that never existed before, and shows it to you live, inside your running
QGIS session. Close it and it's gone. Ask again tomorrow and it gets rebuilt
fresh, possibly a little different each time, because it's generated live,
not pulled from a template. (Nvidia's Jensen Huang has talked about software
increasingly being generated in real time, unique to the exact prompt and
moment — this is that idea, running inside a desktop app today.)

- **Claude Code** and **Cursor** work on files and processes. They can't call
  `app.render_current_view()` on your actual running app.
- **LangChain / AutoGen / smolagents**-style frameworks are script/server
  tools. No live GUI, no in-process kernel.
- **executie** runs inside your app's own IPython kernel. `run_python`
  executes in the *same namespace* your app is already running in — your
  instances, your data, your methods, all directly reachable — while the
  model can also create Qt widgets on the fly, install packages, hit the
  filesystem, and search the web, all in the same call.

Built for and stress-tested inside **SeismicFlow**
(`<link-to-your-seismicflow-repo>`) — a production PyQt6 geoscience
application — where it interprets seismic data, calls the app's own
processing functions, and creates PyQt6 dialogs live, on the fly, in the
running app.

## Install

```bash
pip install executie          # core: agent, tools, 5 providers
pip install executie[gui]     # + AIChatDock, a ready-made Qt chat panel
```

## Quick start

```python
from executie import ai

ai.setup("groq", "gsk_your_key_here")   # or ai.setup_from_env()

ai("search the web for the latest PyQt6 release notes")
ai("read ~/data.csv, clean the nulls, plot column 3, save to ~/out.png")
ai("list every variable in the current namespace and what it is")

# Multi-turn conversation
chat = ai.new_chat()
chat("create a Flask app with two endpoints")
chat("now add JWT auth")

# Control a running job
job = ai("do something long")
job.on_done(lambda result: print("done:", result[:100]))
job.stop()   # cancel mid-run, stops cleanly after the current step
```

## Drop-in GUI

```python
from executie import AIChatDock
from PyQt6.QtCore import Qt

dock = AIChatDock(parent=main_window)
main_window.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, dock)
dock.setup("groq", "gsk_your_key_here")   # optional — the dock also has its own connect form
```

Colors inherit from your application's palette automatically. No dark/light
mode flag needed — if your app re-themes, the dock follows.

## Safety: manual confirmation by default

Full computer access and live application access is a lot of power to hand
an agent. By default, **every single tool call** — `run_python`, `run_bash`,
file reads/writes, web search/fetch, `install_package`, and any custom tool
you register — shows a dialog with the exact call, syntax-highlighted,
before anything runs. Nothing is guessed at as "safe" and skipped; nothing
is hidden.

- **Allow / Cancel** on every call, no exceptions
- Fails closed — if the dialog times out or something goes wrong, the tool
  does *not* run
- Falls back to a plain `y/N` console prompt outside a Qt context

For fully autonomous operation (CI, batch jobs, once you trust the setup):

```python
ai.set_manual_mode(False)
```

or, without touching code:

```bash
export EXECUTIE_AUTO=1
```

The environment variable always wins, so it's a safe way to force autonomous
mode in a deployment without hunting through code paths.

## Give it your own tools

```python
from executie import register_tool

def query_my_database(sql: str) -> str:
    return str(my_db.execute(sql).fetchall())

register_tool(
    name="query_database",
    func=query_my_database,
    description="Run a SQL query against the application database.",
    parameters={
        "type": "object",
        "properties": {"sql": {"type": "string"}},
        "required": ["sql"],
    },
)

ai("query the database for all records from the last 7 days")
```

The model now has this tool alongside the built-ins — `run_python`,
`run_bash`, `web_search`, `web_fetch`, `read_file`, `write_file`,
`list_directory`, `install_package` — and decides on its own when to reach
for it. Custom tools go through the same confirmation dialog as everything
else.

## Providers

| Provider | Default model | Notes |
|---|---|---|
| `groq` | llama-3.3-70b-versatile | Free · 14,400 req/day · no card |
| `openrouter` | qwen/qwen3-coder-480b-a22b:free | Free · 200 req/day · 50+ models |
| `gemini` | gemini-2.5-flash | Free · 1,500 req/day · 1M context |
| `openai` | gpt-4o-mini | Paid · BYOK |
| `claude` | claude-sonnet-4-6 | Paid · BYOK · highest quality |

Switch providers with one call: `ai.setup("<provider>", "<api_key>")`.
Override the model for any provider with `ai.setup("<provider>", "<key>", model="...")`.

## Philosophy

No keyword matching. No regex on the user's message. No
`if "search" in message.lower()`. The model is told what it has access to —
full computer access, live application runtime, the web — and it decides,
every single time, whether a plain answer is enough or a dozen tool calls
are needed. There is exactly one entry point (`ai(...)`) for a one-word
greeting and a fifty-step task alike.

## Staying safe on the Qt main thread

`run_python` code — including matplotlib figures, new `QDialog`s, anything
Qt — is automatically dispatched to the main thread through a
`pyqtSignal`-based queue, so agent code never deadlocks your GUI even though
the agent itself runs in a background `QThread`.

## License

MIT — see [LICENSE](LICENSE).
