windlass 0.1.0__tar.gz

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 (154) hide show
  1. windlass-0.1.0/.gitignore +90 -0
  2. windlass-0.1.0/CHANGELOG.md +278 -0
  3. windlass-0.1.0/LICENSE +205 -0
  4. windlass-0.1.0/PKG-INFO +679 -0
  5. windlass-0.1.0/README.md +313 -0
  6. windlass-0.1.0/docs/concepts/agents.md +319 -0
  7. windlass-0.1.0/docs/concepts/architecture.md +249 -0
  8. windlass-0.1.0/docs/concepts/components.md +216 -0
  9. windlass-0.1.0/docs/concepts/rag.md +246 -0
  10. windlass-0.1.0/docs/concepts/safety-and-quality.md +269 -0
  11. windlass-0.1.0/docs/concepts/three-levels.md +150 -0
  12. windlass-0.1.0/docs/concepts/tools-and-mcp.md +235 -0
  13. windlass-0.1.0/docs/examples.md +108 -0
  14. windlass-0.1.0/docs/gen_reference.py +48 -0
  15. windlass-0.1.0/docs/getting-started/configuration.md +229 -0
  16. windlass-0.1.0/docs/getting-started/installation.md +160 -0
  17. windlass-0.1.0/docs/getting-started/quickstart.md +247 -0
  18. windlass-0.1.0/docs/guides/best-practices.md +329 -0
  19. windlass-0.1.0/docs/guides/faq.md +254 -0
  20. windlass-0.1.0/docs/guides/migration.md +228 -0
  21. windlass-0.1.0/docs/guides/performance.md +242 -0
  22. windlass-0.1.0/docs/guides/plugins.md +403 -0
  23. windlass-0.1.0/docs/guides/testing.md +337 -0
  24. windlass-0.1.0/docs/guides/troubleshooting.md +369 -0
  25. windlass-0.1.0/docs/hooks.py +68 -0
  26. windlass-0.1.0/docs/index.md +116 -0
  27. windlass-0.1.0/docs/tutorials/advanced.md +386 -0
  28. windlass-0.1.0/docs/tutorials/beginner.md +320 -0
  29. windlass-0.1.0/docs/tutorials/intermediate.md +364 -0
  30. windlass-0.1.0/examples/01_rag_basics/README.md +84 -0
  31. windlass-0.1.0/examples/01_rag_basics/main.py +120 -0
  32. windlass-0.1.0/examples/02_agent_tools/README.md +87 -0
  33. windlass-0.1.0/examples/02_agent_tools/main.py +184 -0
  34. windlass-0.1.0/examples/03_hybrid_retrieval/README.md +73 -0
  35. windlass-0.1.0/examples/03_hybrid_retrieval/main.py +105 -0
  36. windlass-0.1.0/examples/04_custom_components/README.md +103 -0
  37. windlass-0.1.0/examples/04_custom_components/main.py +233 -0
  38. windlass-0.1.0/examples/05_production_rag/README.md +112 -0
  39. windlass-0.1.0/examples/05_production_rag/main.py +244 -0
  40. windlass-0.1.0/examples/06_multi_agent/README.md +83 -0
  41. windlass-0.1.0/examples/06_multi_agent/main.py +234 -0
  42. windlass-0.1.0/examples/07_human_in_the_loop/README.md +99 -0
  43. windlass-0.1.0/examples/07_human_in_the_loop/main.py +175 -0
  44. windlass-0.1.0/examples/08_mcp/README.md +109 -0
  45. windlass-0.1.0/examples/08_mcp/main.py +193 -0
  46. windlass-0.1.0/examples/README.md +40 -0
  47. windlass-0.1.0/pyproject.toml +244 -0
  48. windlass-0.1.0/src/windlass/__init__.py +243 -0
  49. windlass-0.1.0/src/windlass/_version.py +7 -0
  50. windlass-0.1.0/src/windlass/agent/__init__.py +44 -0
  51. windlass-0.1.0/src/windlass/agent/builder.py +709 -0
  52. windlass-0.1.0/src/windlass/agent/checkpoint.py +330 -0
  53. windlass-0.1.0/src/windlass/agent/graph.py +410 -0
  54. windlass-0.1.0/src/windlass/agent/runtime.py +633 -0
  55. windlass-0.1.0/src/windlass/agent/supervisor.py +373 -0
  56. windlass-0.1.0/src/windlass/api.py +469 -0
  57. windlass-0.1.0/src/windlass/cli.py +389 -0
  58. windlass-0.1.0/src/windlass/core/__init__.py +145 -0
  59. windlass-0.1.0/src/windlass/core/cache.py +336 -0
  60. windlass-0.1.0/src/windlass/core/concurrency.py +341 -0
  61. windlass-0.1.0/src/windlass/core/config.py +461 -0
  62. windlass-0.1.0/src/windlass/core/container.py +383 -0
  63. windlass-0.1.0/src/windlass/core/exceptions.py +465 -0
  64. windlass-0.1.0/src/windlass/core/lazy.py +208 -0
  65. windlass-0.1.0/src/windlass/core/logging.py +204 -0
  66. windlass-0.1.0/src/windlass/core/registry.py +626 -0
  67. windlass-0.1.0/src/windlass/core/retry.py +288 -0
  68. windlass-0.1.0/src/windlass/core/text.py +505 -0
  69. windlass-0.1.0/src/windlass/core/types.py +671 -0
  70. windlass-0.1.0/src/windlass/core/vectors.py +306 -0
  71. windlass-0.1.0/src/windlass/interfaces/__init__.py +81 -0
  72. windlass-0.1.0/src/windlass/interfaces/base.py +191 -0
  73. windlass-0.1.0/src/windlass/interfaces/chunker.py +279 -0
  74. windlass-0.1.0/src/windlass/interfaces/embedding.py +259 -0
  75. windlass-0.1.0/src/windlass/interfaces/evaluator.py +264 -0
  76. windlass-0.1.0/src/windlass/interfaces/guardrail.py +289 -0
  77. windlass-0.1.0/src/windlass/interfaces/llm.py +410 -0
  78. windlass-0.1.0/src/windlass/interfaces/loader.py +349 -0
  79. windlass-0.1.0/src/windlass/interfaces/mcp.py +312 -0
  80. windlass-0.1.0/src/windlass/interfaces/memory.py +178 -0
  81. windlass-0.1.0/src/windlass/interfaces/preprocessor.py +195 -0
  82. windlass-0.1.0/src/windlass/interfaces/retriever.py +245 -0
  83. windlass-0.1.0/src/windlass/interfaces/tool.py +339 -0
  84. windlass-0.1.0/src/windlass/interfaces/tracer.py +366 -0
  85. windlass-0.1.0/src/windlass/interfaces/vectordb.py +340 -0
  86. windlass-0.1.0/src/windlass/providers/__init__.py +642 -0
  87. windlass-0.1.0/src/windlass/providers/chunkers/__init__.py +7 -0
  88. windlass-0.1.0/src/windlass/providers/chunkers/hierarchical.py +254 -0
  89. windlass-0.1.0/src/windlass/providers/chunkers/recursive.py +260 -0
  90. windlass-0.1.0/src/windlass/providers/chunkers/semantic.py +204 -0
  91. windlass-0.1.0/src/windlass/providers/chunkers/structural.py +323 -0
  92. windlass-0.1.0/src/windlass/providers/embeddings/__init__.py +7 -0
  93. windlass-0.1.0/src/windlass/providers/embeddings/hash.py +127 -0
  94. windlass-0.1.0/src/windlass/providers/embeddings/hf_inference.py +284 -0
  95. windlass-0.1.0/src/windlass/providers/embeddings/huggingface.py +187 -0
  96. windlass-0.1.0/src/windlass/providers/embeddings/openai.py +126 -0
  97. windlass-0.1.0/src/windlass/providers/evaluation/__init__.py +7 -0
  98. windlass-0.1.0/src/windlass/providers/evaluation/builtin.py +428 -0
  99. windlass-0.1.0/src/windlass/providers/evaluation/external.py +356 -0
  100. windlass-0.1.0/src/windlass/providers/guardrails/__init__.py +7 -0
  101. windlass-0.1.0/src/windlass/providers/guardrails/nemo.py +241 -0
  102. windlass-0.1.0/src/windlass/providers/guardrails/rules.py +241 -0
  103. windlass-0.1.0/src/windlass/providers/llm/__init__.py +9 -0
  104. windlass-0.1.0/src/windlass/providers/llm/anthropic.py +355 -0
  105. windlass-0.1.0/src/windlass/providers/llm/fake.py +271 -0
  106. windlass-0.1.0/src/windlass/providers/llm/gemini.py +291 -0
  107. windlass-0.1.0/src/windlass/providers/llm/groq.py +361 -0
  108. windlass-0.1.0/src/windlass/providers/llm/ollama.py +313 -0
  109. windlass-0.1.0/src/windlass/providers/llm/openai.py +424 -0
  110. windlass-0.1.0/src/windlass/providers/loaders/__init__.py +7 -0
  111. windlass-0.1.0/src/windlass/providers/loaders/media.py +296 -0
  112. windlass-0.1.0/src/windlass/providers/loaders/office.py +511 -0
  113. windlass-0.1.0/src/windlass/providers/loaders/text.py +507 -0
  114. windlass-0.1.0/src/windlass/providers/loaders/web.py +452 -0
  115. windlass-0.1.0/src/windlass/providers/mcp/__init__.py +7 -0
  116. windlass-0.1.0/src/windlass/providers/mcp/fastmcp.py +635 -0
  117. windlass-0.1.0/src/windlass/providers/memory/__init__.py +7 -0
  118. windlass-0.1.0/src/windlass/providers/memory/conversation.py +322 -0
  119. windlass-0.1.0/src/windlass/providers/memory/longterm.py +304 -0
  120. windlass-0.1.0/src/windlass/providers/observability/__init__.py +7 -0
  121. windlass-0.1.0/src/windlass/providers/observability/console.py +259 -0
  122. windlass-0.1.0/src/windlass/providers/observability/multi.py +160 -0
  123. windlass-0.1.0/src/windlass/providers/observability/platforms.py +424 -0
  124. windlass-0.1.0/src/windlass/providers/preprocessors/__init__.py +7 -0
  125. windlass-0.1.0/src/windlass/providers/preprocessors/clean.py +306 -0
  126. windlass-0.1.0/src/windlass/providers/preprocessors/dedup.py +321 -0
  127. windlass-0.1.0/src/windlass/providers/preprocessors/enrich.py +303 -0
  128. windlass-0.1.0/src/windlass/providers/preprocessors/privacy.py +307 -0
  129. windlass-0.1.0/src/windlass/providers/retrievers/__init__.py +7 -0
  130. windlass-0.1.0/src/windlass/providers/retrievers/bm25.py +365 -0
  131. windlass-0.1.0/src/windlass/providers/retrievers/contextual.py +326 -0
  132. windlass-0.1.0/src/windlass/providers/retrievers/hybrid.py +255 -0
  133. windlass-0.1.0/src/windlass/providers/retrievers/vector.py +247 -0
  134. windlass-0.1.0/src/windlass/providers/vectordb/__init__.py +7 -0
  135. windlass-0.1.0/src/windlass/providers/vectordb/chroma.py +382 -0
  136. windlass-0.1.0/src/windlass/providers/vectordb/faiss.py +445 -0
  137. windlass-0.1.0/src/windlass/providers/vectordb/memory.py +361 -0
  138. windlass-0.1.0/src/windlass/providers/vectordb/pinecone.py +442 -0
  139. windlass-0.1.0/src/windlass/py.typed +1 -0
  140. windlass-0.1.0/src/windlass/rag/__init__.py +34 -0
  141. windlass-0.1.0/src/windlass/rag/builder.py +739 -0
  142. windlass-0.1.0/src/windlass/rag/loading.py +250 -0
  143. windlass-0.1.0/src/windlass/rag/pipeline.py +854 -0
  144. windlass-0.1.0/src/windlass/testing.py +376 -0
  145. windlass-0.1.0/src/windlass/tools/__init__.py +458 -0
  146. windlass-0.1.0/src/windlass/tools/schema.py +417 -0
  147. windlass-0.1.0/tests/conftest.py +140 -0
  148. windlass-0.1.0/tests/test_components.py +1350 -0
  149. windlass-0.1.0/tests/test_core.py +705 -0
  150. windlass-0.1.0/tests/test_integration.py +932 -0
  151. windlass-0.1.0/tests/test_new_providers.py +215 -0
  152. windlass-0.1.0/tests/test_observability.py +320 -0
  153. windlass-0.1.0/tests/test_providers_http.py +227 -0
  154. windlass-0.1.0/tests/test_wiring_regressions.py +243 -0
@@ -0,0 +1,90 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib64/
14
+ parts/
15
+ sdist/
16
+ var/
17
+ wheels/
18
+ *.egg-info/
19
+ .installed.cfg
20
+ *.egg
21
+ MANIFEST
22
+
23
+ # Virtual environments
24
+ venv/
25
+ .venv/
26
+ env/
27
+ ENV/
28
+ .python-version
29
+
30
+ # Testing and coverage
31
+ .pytest_cache/
32
+ .coverage
33
+ .coverage.*
34
+ coverage.xml
35
+ htmlcov/
36
+ .tox/
37
+ .nox/
38
+ .hypothesis/
39
+
40
+ # Type checking and linting
41
+ .mypy_cache/
42
+ .dmypy.json
43
+ dmypy.json
44
+ .ruff_cache/
45
+ .pytype/
46
+
47
+ # Documentation
48
+ site/
49
+ docs/reference/
50
+
51
+ # Editors
52
+ .idea/
53
+ .vscode/
54
+ *.swp
55
+ *.swo
56
+ *~
57
+ .DS_Store
58
+ Thumbs.db
59
+
60
+ # Jupyter
61
+ .ipynb_checkpoints/
62
+ *.ipynb_checkpoints
63
+
64
+ # Windlass runtime artefacts
65
+ .windlass/
66
+ windlass.toml
67
+ windlass.json
68
+ windlass.yaml
69
+ *.faiss
70
+ *.meta.json
71
+ chroma/
72
+ .chroma/
73
+ index/
74
+ indexes/
75
+
76
+ # Secrets — never commit these
77
+ .env
78
+ .env.*
79
+ !.env.example
80
+ *.pem
81
+ *.key
82
+ credentials.json
83
+ service-account*.json
84
+
85
+ # Model and dataset caches
86
+ .cache/
87
+ models/
88
+ *.gguf
89
+ *.safetensors
90
+ *.bin
@@ -0,0 +1,278 @@
1
+ # Changelog
2
+
3
+ All notable changes to Windlass are recorded here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
6
+ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ Before 1.0, minor versions may change the public API. Every break gets an entry
9
+ here and a note in the [migration guide](docs/guides/migration.md).
10
+
11
+ ## [Unreleased]
12
+
13
+ ### Changed
14
+
15
+ - **The project is now called Windlass** (was "Harness", distributed as
16
+ `harness-ai`). The old name collided with an existing PyPI distribution and
17
+ with a well-known CI/CD vendor, neither of which was survivable for a package
18
+ people are meant to `import`. Everything renamed consistently: the
19
+ distribution is `windlass`, the import is `windlass`, the facade is
20
+ `Windlass`, the CLI is `windlass`, environment variables are `WINDLASS_*`,
21
+ the config file is `windlass.toml`, and plugin entry-point groups are
22
+ `windlass.plugins` / `windlass.<kind>`.
23
+
24
+ - **Every optional dependency now has an upper version bound.** Unbounded pins
25
+ are how two of the defects below shipped: `langgraph>=0.2.28` resolved to
26
+ `1.2.9` and `langfuse>=2.50` resolved to `4.14.1`, each across a major
27
+ version, into adapters written against the older API.
28
+
29
+ ### Added
30
+
31
+ - **`hf_inference` embeddings — the HuggingFace Inference API as a first-class
32
+ provider.** The existing `huggingface` provider runs sentence-transformers
33
+ locally, which means torch, a model download and the RAM to hold it. This one
34
+ calls the hosted endpoint and needs **no optional dependency at all**, since
35
+ `httpx` is already core. BGE and E5 instruction prefixes are declared through
36
+ the interface's hooks, so the query/document asymmetry those models need is
37
+ applied on the correct side rather than being a silent retrieval-quality bug.
38
+
39
+ - `huggingface_api_key` setting, reading `HUGGINGFACE_API_KEY` or `HF_TOKEN`,
40
+ and reported by `windlass doctor`.
41
+
42
+ - **`multi` tracer — fan one trace out to several backends.** Teams rarely have
43
+ exactly one place traces should land: a platform team standardises on
44
+ LangSmith while a product team already reads Langfuse, and during a migration
45
+ you want both. `observe("multi", backends=["langfuse", "langsmith"])` sends
46
+ every span to each. A backend that raises is logged once and skipped for the
47
+ rest of the run, never propagated — one misconfigured exporter must not take
48
+ down the others or the application.
49
+
50
+ - **`web` extras group** — `beautifulsoup4` and `lxml` only. Scraping a page
51
+ should not also install a PDF parser, an Excel reader and a YouTube client,
52
+ which is what the broader `loaders` group pulls in.
53
+
54
+ - **`ProviderError` now takes `status_code`.** Retry classification reads it, so
55
+ an adapter that omitted it silently turned a transient 429 or 503 into a hard
56
+ failure of the whole run. Previously the only way to set it was to assign the
57
+ attribute after construction — undiscoverable from the signature, and invisible
58
+ to a type checker.
59
+
60
+ ### Fixed
61
+
62
+ - **The LangGraph runtime never ran.** `.graph()` raised `NameError: name
63
+ 'Annotated' is not defined` before a single node executed. The module uses
64
+ `from __future__ import annotations`, so the state `TypedDict`'s annotations
65
+ are strings, and LangGraph resolves them with `get_type_hints` against the
66
+ *defining module's* globals — but `Annotated` was imported inside the builder
67
+ method. The state class now lives at module scope. A headline feature had
68
+ never once worked with `langgraph` installed, and the suite was green
69
+ throughout, because no test ever built a graph.
70
+
71
+ - **Every dependency-container binding was silently ignored.** The builders
72
+ passed the configured *default name* whenever the caller had not named a
73
+ component, and `Container.component()` only consults its bindings when the
74
+ spec is `None`, so that branch was unreachable from the builders. This broke
75
+ `Windlass.container().bind_instance(...)` — which the public API documents as
76
+ the place for application-wide wiring — and `capture_spans()`, the shipped
77
+ test helper, which collected nothing. Resolution order is now explicit:
78
+ builder call, then container binding, then configured default.
79
+
80
+ - **`resume()` dropped the approved tool call from `steps`.** `aresume`
81
+ delegates to `arun`, which starts a fresh step list, so the one action a human
82
+ explicitly authorised survived only in `messages`. Any audit trail reading
83
+ `steps` showed an effect with no step accounting for it.
84
+
85
+ - **A tracer could raise on the way out.** `_bounded_flush` starts a daemon
86
+ thread, and Python refuses new threads once interpreter shutdown has begun —
87
+ exactly when an `atexit` flush runs. Hosted tracers printed a traceback on
88
+ every clean exit, contradicting the adapter's own guarantee never to break the
89
+ application.
90
+
91
+ - **`LANGFUSE_BASE_URL` is now read.** The vendor SDK honours it, Windlass did
92
+ not, so a project on a non-default region silently disagreed with itself:
93
+ `windlass config` reported the default cloud host while the vendor client
94
+ quietly used the right one. They only agreed by luck.
95
+
96
+ ---
97
+
98
+ Six defects found by building a full third-party application against the
99
+ framework (multi-agent claims adjudication over Groq, HuggingFace Inference,
100
+ Pinecone, Langfuse and LangSmith). All six were invisible to the existing
101
+ suite, because each needs a real socket, a second installed distribution, or a
102
+ current vendor SDK to reproduce.
103
+
104
+ ### Added
105
+
106
+ - **Agents recover from an unparseable tool call instead of dying.** A model
107
+ that emits a tool call the provider cannot parse now raises the new
108
+ `MalformedToolCallError`, which `AgentRuntime` catches, feeds back to the
109
+ model as a correction, and retries — the same treatment a hallucinated tool
110
+ name already got. Groq's `tool_use_failed` is detected and mapped to it.
111
+
112
+ The common cause is a model trying to express a data dependency the protocol
113
+ cannot represent, nesting one call inside another's arguments
114
+ (`settle(amount=<function=compute>{...}</function>)`) because the value it
115
+ needs does not exist until the first call has run. Observed with Llama 3.3 on
116
+ Groq; it previously ended the run with a bare `ProviderError`.
117
+
118
+ Recoveries are bounded by `AgentBuilder.tool_call_retries()` (default 2) and
119
+ each one consumes an iteration, so a model that never recovers still
120
+ terminates. `tool_call_retries(0)` restores the previous behaviour.
121
+
122
+ - `tests/test_observability.py` — the hosted tracers had no tests at all.
123
+ Twenty-six cover version detection, span-kind translation, nesting, usage
124
+ reporting and flush deadlines against fakes shaped like each Langfuse SDK
125
+ generation.
126
+
127
+ ### Fixed
128
+
129
+ - **Langfuse tracing exported nothing on langfuse 3.x/4.x, then hung the
130
+ process.** The adapter targeted the v2 `trace()`/`span()`/`generation()`
131
+ surface, which no longer exists; every call raised `AttributeError` into the
132
+ adapter's own `except Exception`, so `doctor` reported healthy while zero
133
+ observations reached Langfuse. Separately, `flush()` blocked forever inside
134
+ Langfuse's `queue.join()` when a worker had stopped with items outstanding —
135
+ contradicting the documented guarantee that a tracer can never break the
136
+ application, and wedging any process that flushed. The adapter now detects
137
+ the installed generation and uses `start_observation(as_type=...)` on v3/v4
138
+ — whose observation types map almost one-to-one onto Windlass span kinds —
139
+ falling back to the v2 surface, and **raising at construction** when neither
140
+ is present rather than silently discarding every span. Every vendor `flush()`
141
+ now runs under a deadline, LangSmith included.
142
+
143
+ - **Blocking calls no longer close the event loop they run on.** `run_sync`
144
+ used `asyncio.run` when no loop was active, creating and destroying a loop
145
+ per call. Every provider that keeps a long-lived `httpx.AsyncClient` — Ollama
146
+ directly, and the OpenAI, Anthropic, Groq and Gemini SDKs underneath — pools
147
+ keep-alive sockets on the loop that opened them, so the *second* blocking
148
+ call raised `RuntimeError: Event loop is closed` from deep inside httpx. All
149
+ calls now share the background loop, which is the same reasoning `iter_sync`
150
+ already documented. Mock transports could never catch this: they open no
151
+ sockets, so loop identity is now asserted directly.
152
+ - **A cache passed to an `Embedder` constructor is no longer discarded.**
153
+ `cache or NullCache()` looked equivalent to a `None` check and was not: every
154
+ `Cache` implements `__len__`, so a freshly constructed (empty) cache is falsy.
155
+ `Windlass.embedding(..., cache=MemoryCache())` silently never cached. Only
156
+ `set_cache()` worked, which is the path the existing test happened to use.
157
+ - **A hand-constructed `Registry` is isolated again.** Discovery of
158
+ entry-point plugins ran on first lookup for *any* registry, so installing any
159
+ third-party Windlass plugin changed the contents of every registry in the
160
+ process — including the clean ones tests build, which made the suite's result
161
+ depend on what else was in the environment. Discovery is now opt-in
162
+ (`Registry(discover=True)`); the process-wide `REGISTRY` opts in, and
163
+ `load_plugins()` remains available on demand for any registry.
164
+ - **`RAGBuilder.min_score()` works with `.retriever(instance)`.** The threshold
165
+ was passed as construction config, which an already-built retriever cannot
166
+ accept, so the pairing failed at build time with an error that never
167
+ mentioned `min_score`. It is now applied to the live object, matching how
168
+ `AgentBuilder` already handles a pre-built MCP client.
169
+ - **`PineconeVectorStore.clear()` succeeds on a namespace that does not exist.**
170
+ Pinecone creates namespaces lazily and returns 404 for a delete-all against
171
+ one never written to, so teardown failed precisely when there was nothing to
172
+ tear down. Detection matches on status and message rather than exception
173
+ class, which moved between SDK generations.
174
+
175
+ ## [0.1.0] — 2026-07-26
176
+
177
+ First release.
178
+
179
+ ### Core
180
+
181
+ - Component registry with lazy, dotted-path registration, aliases and
182
+ case-insensitive lookup. Importing a provider is deferred until it is used.
183
+ - Plugin discovery via the `windlass.plugins` and `windlass.<kind>` entry-point
184
+ groups. A failing plugin logs a warning and is skipped unless
185
+ `strict_plugins` is set.
186
+ - Hierarchical dependency-injection container. `component()` accepts a registry
187
+ name, a live instance or a factory.
188
+ - Settings from defaults, a config file (TOML/JSON/YAML), the environment and
189
+ explicit arguments — in that precedence order. Conventional provider
190
+ variables such as `OPENAI_API_KEY` are read as-is.
191
+ - One exception hierarchy rooted at `WindlassError`, each error carrying an
192
+ actionable `hint` and structured `context`.
193
+ - Optional dependencies loaded through a single choke point, so a missing extra
194
+ produces a `MissingDependencyError` naming the exact `pip install` command.
195
+ - Async/sync bridge that detects a running event loop and dispatches to a
196
+ background loop thread, making the blocking API safe in Jupyter, FastAPI and
197
+ LangServe.
198
+ - Bounded-concurrency helpers, exponential backoff with jitter on transient
199
+ failures only, memory and disk caches, and a context-aware logger.
200
+
201
+ ### Interfaces
202
+
203
+ - Thirteen component contracts: `LLM`, `Embedder`, `Loader`, `Preprocessor`,
204
+ `Chunker`, `Retriever`, `VectorStore`, `Memory`, `Guardrail`, `Evaluator`,
205
+ `Tracer`, `Tool`, `MCPClient`.
206
+ - All async-first, with blocking variants derived from the same implementation.
207
+ - `native()` on every component, returning the wrapped SDK object.
208
+
209
+ ### Providers
210
+
211
+ - **LLMs** — OpenAI (and OpenAI-compatible gateways), Anthropic, Gemini, Groq,
212
+ Ollama, plus dependency-free `fake` and `echo` providers.
213
+ - **Embeddings** — HuggingFace `sentence-transformers` (with automatic E5/BGE/
214
+ Nomic instruction prefixes), OpenAI, and a dependency-free hashed n-gram model.
215
+ - **Vector stores** — in-memory (exact search, JSON persistence), FAISS
216
+ (flat/IVF/HNSW), ChromaDB, Pinecone.
217
+ - **Loaders** — PDF, DOCX, PPTX, XLSX, CSV, Markdown, HTML, JSON/JSONL, images
218
+ (OCR), audio (Whisper), web pages, YouTube transcripts, with automatic format
219
+ detection.
220
+ - **Preprocessors** — cleaning, PII detection and redaction, deduplication,
221
+ language detection, OCR fallback, table extraction, LLM metadata extraction.
222
+ - **Chunkers** — recursive, token, semantic, Markdown (heading-path aware), code
223
+ (13 languages), parent-child.
224
+ - **Retrievers** — BM25, dense vector with MMR, hybrid with Reciprocal Rank
225
+ Fusion, contextual enrichment with HyDE and multi-query expansion.
226
+ - **Memory** — buffer, sliding window, LLM summarising, vector long-term,
227
+ composite.
228
+ - **Guardrails** — rule-based (PII, prompt injection, leaked secrets, banned
229
+ terms) and NVIDIA NeMo Guardrails.
230
+ - **Evaluation** — built-in lexical and LLM-judged metrics, RAGAS, DeepEval.
231
+ - **Observability** — console, in-memory, LangSmith, Langfuse.
232
+ - **MCP** — FastMCP over stdio/SSE/HTTP, an in-process client for tests, and a
233
+ multi-server aggregator with automatic namespacing.
234
+
235
+ ### RAG
236
+
237
+ - `Windlass.rag()` fluent builder with automatic cross-component wiring: the
238
+ semantic chunker receives the embedder, the vector retriever receives the
239
+ embedder and store, hybrid retrieval builds its own BM25 leg, FAISS and
240
+ Pinecone receive the embedding dimensionality, parent-child chunking wires
241
+ parent expansion.
242
+ - Idempotent ingestion — chunk ids are content hashes, so re-ingesting
243
+ unchanged content upserts rather than duplicating.
244
+ - Metadata filtering with Mongo-style operators, pushed down to stores that
245
+ support it and applied client-side by those that do not.
246
+ - Context assembly against a token budget, dropping the lowest-ranked chunks
247
+ first so the best context always survives.
248
+ - `strict()` and `min_score()` for refusing to answer without relevant context.
249
+ - Streaming, persistence, and evaluation from the pipeline object.
250
+
251
+ ### Agents
252
+
253
+ - `Windlass.agent()` fluent builder.
254
+ - A built-in reason/act runtime with no dependencies, plus a LangGraph runtime
255
+ exposing a real `StateGraph` through `native_graph()`.
256
+ - Automatic JSON-schema generation from type hints and Google-style docstrings,
257
+ rendered per provider dialect.
258
+ - Parallel tool execution, per-tool timeouts, and tool failures reported to the
259
+ model rather than raised.
260
+ - Conversation and long-term memory keyed by `thread_id`.
261
+ - Checkpointing (in-memory and SQLite) enabling resume and time travel.
262
+ - Human-in-the-loop approval with reject-with-feedback and edited arguments.
263
+ - Multi-agent supervision with `run`, `broadcast` and `pipeline` coordination.
264
+
265
+ ### Tooling
266
+
267
+ - `windlass` CLI: `doctor`, `info`, `list`, `config`, `ask`, `chat`.
268
+ - `windlass.testing` — scripted models, offline pipeline and agent factories,
269
+ registry isolation, span capture, recording tools.
270
+ - Over 650 tests, running offline in under a minute with no API keys —
271
+ including every docstring example, executed as part of the suite so a
272
+ documented example that does not run fails the build.
273
+ - `mypy` clean, `ruff` clean, `black` formatted.
274
+ - MkDocs documentation site with a generated API reference.
275
+ - Eight runnable examples, all of which run on the core install alone.
276
+
277
+ [Unreleased]: https://github.com/Kukilbharadwaj/WINDLASS/compare/v0.1.0...HEAD
278
+ [0.1.0]: https://github.com/Kukilbharadwaj/WINDLASS/releases/tag/v0.1.0
windlass-0.1.0/LICENSE ADDED
@@ -0,0 +1,205 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
203
+
204
+ Copyright 2026 The Harness Authors
205
+