Metadata-Version: 2.4
Name: inquirycraft
Version: 0.6.0
Summary: A lightweight, extensible agent runtime with tools, memory, events, and replay
License-Expression: MIT
Project-URL: Repository, https://github.com/EE-PandaMinG/InquiryCraft
Project-URL: Issues, https://github.com/EE-PandaMinG/InquiryCraft/issues
Keywords: agent,llm,runtime,tools,mcp
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == "openai"
Requires-Dist: httpx>=0.27; extra == "openai"
Requires-Dist: lazy-loader>=0.4; extra == "openai"
Requires-Dist: requests>=2.31; extra == "openai"
Requires-Dist: tenacity>=9.0.0; extra == "openai"
Provides-Extra: tokens
Requires-Dist: tiktoken>=0.7; extra == "tokens"
Provides-Extra: mcp
Requires-Dist: mcp[cli]<1.27,>=1.3.0; extra == "mcp"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Requires-Dist: ruff>=0.15; extra == "dev"
Dynamic: license-file

# InquiryCraft

[![PyPI](https://img.shields.io/pypi/v/inquirycraft.svg)](https://pypi.org/project/inquirycraft/)
[![Python](https://img.shields.io/pypi/pyversions/inquirycraft.svg)](https://pypi.org/project/inquirycraft/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

InquiryCraft is a lightweight, extensible harness for building tool-using LLM agents.
It provides the execution loop and lifecycle primitives needed by standalone agents,
interactive CLIs, and larger host applications without imposing a domain workflow.

## Why InquiryCraft?

- **Small core** — the minimal installation depends only on Click.
- **Real agent loop** — provider request, tool call, tool result, and continuation are
  handled by a reusable `AgentRuntime`.
- **Provider-neutral contracts** — applications can implement `LLMClient` or use the
  optional OpenAI-compatible adapter.
- **Composable tools** — typed schemas, execution middleware, path policy, concurrent
  dispatch, output reduction, and raw artifact retention share one contract.
- **Durable runs** — append-only sessions, lifecycle events, cancellation, resume, and
  telemetry are built in.
- **Deterministic validation** — record/replay detects drift in messages, model options,
  tool schemas, call ordering, results, and stream mode.
- **Optional integrations** — provider SDKs, token counting, and MCP stay outside the
  minimal package.

## Install

Install the minimal runtime and CLI:

```bash
pip install inquirycraft
inquirycraft tools list
```

Install an OpenAI-compatible provider client:

```bash
pip install 'inquirycraft[openai]'
```

Other optional extras:

```bash
pip install 'inquirycraft[tokens]'
pip install 'inquirycraft[mcp]'
```

Importing `inquirycraft` resolves public symbols lazily. It does not initialize the CLI
or load provider SDKs.

## Quick start

Configure any OpenAI-compatible endpoint:

```bash
export INQUIRYCRAFT_API_KEY=...
export INQUIRYCRAFT_BASE_URL=http://127.0.0.1:8001/v1
export INQUIRYCRAFT_MODEL=your-model
```

Run a single task with the built-in file and shell tools:

```bash
mkdir -p workspace
inquirycraft run \
  --workspace ./workspace \
  "Inspect the workspace and write a concise summary to result.txt"
```

Start an interactive session:

```bash
inquirycraft repl --workspace ./workspace
```

## Python API

```python
import asyncio
import os
from pathlib import Path

from inquirycraft.llm.openai_adapter import OpenAICompatibleClient
from inquirycraft.runtime import AgentRuntime, RuntimeOptions
from inquirycraft.tools import default_tools


async def main() -> None:
    client = OpenAICompatibleClient(
        api_key=os.environ["INQUIRYCRAFT_API_KEY"],
        base_url=os.environ.get("INQUIRYCRAFT_BASE_URL"),
    )
    runtime = AgentRuntime(
        llm=client,
        options=RuntimeOptions(
            model=os.environ["INQUIRYCRAFT_MODEL"],
            workspace=Path("./workspace"),
            system_prompt="You are a careful coding agent.",
        ),
        tools=default_tools(),
    )
    try:
        print(await runtime.run("Inspect the workspace and summarize its contents."))
    finally:
        await client.aclose()


asyncio.run(main())
```

Implementing the `LLMClient` protocol is enough to connect another provider. Custom
tools subclass `BaseTool` and return a `ToolResult`; hooks and event sinks can be added
without modifying the loop.

## Sessions, events, and replay

Persist a conversation and its lifecycle events:

```bash
inquirycraft run "continue the task" \
  --session-log .inquirycraft/session.jsonl \
  --event-log .inquirycraft/events.jsonl
```

Session logs are append-only. If the file already exists, `run` and `repl` restore its
messages before the next turn.

`RecordingLLMClient` stores the exact provider-visible request and completion result or
stream chunks. `ReplayLLMClient` consumes that JSONL offline and raises
`ReplayMismatchError` when model parameters, messages, tool schemas, call ordering, or
stream mode drift. Generated timestamps and event IDs can be normalized without
loosening prompts, tool payloads, results, or ordering.

## Tools and path policy

InquiryCraft includes independent read, write, edit, grep, glob, list, and shell tools.
Filesystem scope is configured separately from tool behavior:

```python
from inquirycraft.tools import PathPolicy, ReadTool

policy = PathPolicy("./workspace", enabled=True)
read = ReadTool(path_policy=policy)
```

A strict `PathPolicy` contains model-generated paths under a configured root and any
explicitly allowed extra roots. Hosts that execute untrusted model output should also
apply process isolation and least-privilege credentials appropriate to their threat
model.

## CLI reference

```text
inquirycraft run             Run one tool-using agent task
inquirycraft repl            Start an interactive multi-turn session
inquirycraft tools list      List built-in tools
inquirycraft tools schema    Print tool schemas
inquirycraft events show     Inspect runtime event JSONL
```

Use `inquirycraft COMMAND --help` for command-specific options.

## Package layout

| Package | Responsibility |
| --- | --- |
| `inquirycraft.runtime` | Agent loop, hooks, cancellation, telemetry, and resume |
| `inquirycraft.llm` | Provider protocols, streaming models, retry, and adapters |
| `inquirycraft.tools` | Tool contracts, execution, file tools, and path policy |
| `inquirycraft.memory` | Messages, conversations, and persistent records |
| `inquirycraft.events` | Lifecycle JSONL and deterministic record/replay |
| `inquirycraft.executor` | Generic shell and Python execution helpers |
| `inquirycraft.mcp` | Optional MCP transport integration |
| `inquirycraft.cli` | Standalone commands and CLI composition contracts |

See [ARCHITECTURE.md](ARCHITECTURE.md) for design boundaries and validation layers.

## Development

```bash
uv sync --all-extras
uv run pytest -q
uv run ruff check .
uv run ruff format --check .
uv build
```

InquiryCraft supports Python 3.11 and newer and is distributed under the MIT License.
