harness-core now has everything the headless agent loop needs:
- Tool trait/ToolCtx/ToolRegistry + 30k-char head+tail output truncation
- PermissionService: async ask over a oneshot + AppEvent::PermissionAsked,
Once/Always/Reject replies, an auto-approve stub for tests/headless runs
- Config: JSONC loading, bundled/global/project-chain/env precedence,
{env:VAR} and {file:path} interpolation
- llm.rs: LlmEvent/LlmRequest/Provider trait, wire message/content types
- engine/: outer loop (run_session), inner stream processor (persists
parts/messages as events arrive, executes tool calls inline), retry
policy (retries only the pre-first-event window), doom-loop guard,
system prompt assembly
Verified end-to-end against a scripted MockProvider: text -> tool call
(read) -> final text, with messages/parts persisted in the right shape,
plus a provider-error-before-any-event case surfacing as Errored (no
partial message left behind). 49 tests passing, clippy clean.
69 lines
1.8 KiB
TOML
69 lines
1.8 KiB
TOML
[workspace]
|
|
resolver = "2"
|
|
members = [
|
|
"crates/harness-core",
|
|
"crates/harness-providers",
|
|
"crates/harness-tools",
|
|
"crates/harness-mcp",
|
|
"crates/harness-lsp",
|
|
"crates/harness-app",
|
|
"crates/harness-tui",
|
|
]
|
|
|
|
[workspace.package]
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
license = "MIT"
|
|
repository = "https://github.com/esimon/ai-harness"
|
|
|
|
[workspace.dependencies]
|
|
harness-core = { path = "crates/harness-core" }
|
|
harness-providers = { path = "crates/harness-providers" }
|
|
harness-tools = { path = "crates/harness-tools" }
|
|
harness-mcp = { path = "crates/harness-mcp" }
|
|
harness-lsp = { path = "crates/harness-lsp" }
|
|
harness-app = { path = "crates/harness-app" }
|
|
|
|
tokio = { version = "1", features = ["full"] }
|
|
tokio-util = "0.7"
|
|
futures = "0.3"
|
|
async-stream = "0.3"
|
|
async-trait = "0.1"
|
|
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "stream", "json", "gzip"] }
|
|
eventsource-stream = "0.2"
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = { version = "1", features = ["raw_value"] }
|
|
schemars = "0.8"
|
|
serde_yaml_ng = "0.10"
|
|
jsonc-parser = { version = "0.26", features = ["serde"] }
|
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
|
ratatui = "0.29"
|
|
crossterm = { version = "0.28", features = ["event-stream"] }
|
|
tui-textarea = "0.7"
|
|
pulldown-cmark = "0.12"
|
|
rmcp = "0.1"
|
|
lsp-types = "0.97"
|
|
ignore = "0.4"
|
|
globset = "0.4"
|
|
grep-searcher = "0.1"
|
|
grep-regex = "0.1"
|
|
grep-matcher = "0.1"
|
|
similar = "2"
|
|
ulid = { version = "1", features = ["serde"] }
|
|
thiserror = "2"
|
|
anyhow = "1"
|
|
tracing = "0.1"
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
tracing-appender = "0.2"
|
|
dirs = "5"
|
|
shell-words = "1"
|
|
tempfile = "3"
|
|
insta = "1"
|
|
wiremock = "0.6"
|
|
|
|
[workspace.lints.rust]
|
|
unsafe_code = "deny"
|
|
|
|
[workspace.lints.clippy]
|
|
all = { level = "warn", priority = -1 }
|