covalve 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 (49) hide show
  1. covalve-0.1.0/.gitignore +13 -0
  2. covalve-0.1.0/ADR/ADR-001.md +57 -0
  3. covalve-0.1.0/ADR/ADR-002.md +63 -0
  4. covalve-0.1.0/ADR/ADR-003.md +112 -0
  5. covalve-0.1.0/ADR/ADR-004.md +96 -0
  6. covalve-0.1.0/ADR/ADR-005.md +104 -0
  7. covalve-0.1.0/LICENSE +21 -0
  8. covalve-0.1.0/PKG-INFO +298 -0
  9. covalve-0.1.0/README.md +276 -0
  10. covalve-0.1.0/covalve/__init__.py +35 -0
  11. covalve-0.1.0/covalve/infrastructure/base/cache.py +12 -0
  12. covalve-0.1.0/covalve/infrastructure/base/guardrails.py +6 -0
  13. covalve-0.1.0/covalve/infrastructure/base/llm.py +11 -0
  14. covalve-0.1.0/covalve/infrastructure/base/log.py +7 -0
  15. covalve-0.1.0/covalve/infrastructure/base/memory.py +10 -0
  16. covalve-0.1.0/covalve/infrastructure/base/tools.py +7 -0
  17. covalve-0.1.0/covalve/infrastructure/contract.py +20 -0
  18. covalve-0.1.0/covalve/runtime/engine.py +98 -0
  19. covalve-0.1.0/covalve/runtime/executor/analyze_query.py +43 -0
  20. covalve-0.1.0/covalve/runtime/executor/error.py +14 -0
  21. covalve-0.1.0/covalve/runtime/executor/error_counter.py +18 -0
  22. covalve-0.1.0/covalve/runtime/executor/fallback.py +20 -0
  23. covalve-0.1.0/covalve/runtime/executor/guardrail.py +13 -0
  24. covalve-0.1.0/covalve/runtime/executor/main_llm.py +72 -0
  25. covalve-0.1.0/covalve/runtime/executor/retrieve_conv.py +15 -0
  26. covalve-0.1.0/covalve/runtime/executor/save_data.py +28 -0
  27. covalve-0.1.0/covalve/runtime/executor/tools_executor.py +65 -0
  28. covalve-0.1.0/covalve/runtime/executor/tools_mapper.py +18 -0
  29. covalve-0.1.0/covalve/runtime/hook/__init__.py +4 -0
  30. covalve-0.1.0/covalve/runtime/hook/context.py +11 -0
  31. covalve-0.1.0/covalve/runtime/hook/executor.py +32 -0
  32. covalve-0.1.0/covalve/runtime/hook/registry.py +43 -0
  33. covalve-0.1.0/covalve/runtime/init.py +76 -0
  34. covalve-0.1.0/covalve/runtime/models/context.py +60 -0
  35. covalve-0.1.0/covalve/runtime/models/infra.py +25 -0
  36. covalve-0.1.0/covalve/runtime/models/io.py +36 -0
  37. covalve-0.1.0/covalve/runtime/models/logs.py +14 -0
  38. covalve-0.1.0/covalve/runtime/models/metadata.py +33 -0
  39. covalve-0.1.0/covalve/runtime/pipeline.py +31 -0
  40. covalve-0.1.0/covalve/runtime/registry.py +23 -0
  41. covalve-0.1.0/covalve/runtime/validator/graph_traversal.py +44 -0
  42. covalve-0.1.0/covalve/schemas/__init__.py +0 -0
  43. covalve-0.1.0/covalve/schemas/schema.json +56 -0
  44. covalve-0.1.0/example/prompt-example/clarification_template.txt +13 -0
  45. covalve-0.1.0/example/prompt-example/main_llm_response.txt +14 -0
  46. covalve-0.1.0/example/prompt-example/query_analyze_prompt.txt +127 -0
  47. covalve-0.1.0/example/schemas-example/schema.json +56 -0
  48. covalve-0.1.0/example/schemas-example/tools_schema.json +7 -0
  49. covalve-0.1.0/pyproject.toml +35 -0
@@ -0,0 +1,13 @@
1
+ .*
2
+ cm-auto-global_truststore.jks
3
+ ImpalaJDBC41.jar
4
+ __pycache__/
5
+ UI/
6
+ mcpserver
7
+ log/
8
+ implement/
9
+ covalve/infrastructure/registry.py
10
+ jsonSchema/
11
+ prompt/
12
+ config/
13
+ dist/
@@ -0,0 +1,57 @@
1
+ # ADR-001: FSM-Based Pipeline Runtime
2
+
3
+ ## Status
4
+ #Accepted
5
+
6
+ ## Date
7
+ 2026-05-06
8
+
9
+ ## Context
10
+ When building an AI pipeline, several existing frameworks were evaluated,
11
+ including LangChain, LlamaIndex, and Haystack.
12
+ These frameworks are generally prompt-driven — routing, tool selection,
13
+ and decision-making are delegated to the LLM automatically. This approach
14
+ reduces the system's locus of control because control resides primarily in
15
+ the prompt rather than in the system itself.
16
+
17
+ The probabilistic and automated nature of routing makes pipeline behavior
18
+ difficult to predict and verify, even when additional stabilization
19
+ techniques are applied.
20
+
21
+ ## Decision
22
+ Build a fully controllable, code-based orchestrator using a Deterministic
23
+ Finite Automaton (DFA) as the foundation of the pipeline runtime.
24
+
25
+ ## Rationale
26
+ A DFA was chosen because it more accurately represents the execution
27
+ lifecycle of the pipeline compared to alternatives such as simple function
28
+ chains or DAG-based orchestration.
29
+
30
+ A DAG is inherently directional and does not naturally represent retry,
31
+ fallback, and error recovery behaviors, which are essential parts of this
32
+ pipeline's execution lifecycle. A DFA enables explicit states,
33
+ deterministic transitions, and a fully traceable lifecycle from start to
34
+ finish.
35
+
36
+ Compared to prompt-based frameworks, this approach provides full system
37
+ control — routing, error handling, and decision-making are implemented in
38
+ code rather than delegated to prompts. As a result, pipeline behavior
39
+ becomes predictable and verifiable because every state and transition is
40
+ defined explicitly.
41
+
42
+ ## Consequences
43
+
44
+ ### Positive
45
+ - Pipeline behavior is fully deterministic and auditable
46
+ - Error handling is explicit — every failure case has a defined execution path
47
+ - No dependency on external orchestration frameworks
48
+ - Easier tracing and debugging because every state transition is recorded
49
+
50
+ ### Negative
51
+ - More complex developer experience — contributors must understand
52
+ state machines and pipeline design before contributing
53
+ - Less accessible for non-developers — there is no visual interface like
54
+ n8n or LangFlow for inspecting or modifying flows
55
+ - No real-time activity graph visualization
56
+ - Flow changes require updates to schemas and executors rather than
57
+ simply modifying prompts
@@ -0,0 +1,63 @@
1
+ # ADR-002: Python as Implementation Language
2
+
3
+ ## Status
4
+ #Accepted
5
+
6
+ ## Date
7
+ 2026-05-06
8
+
9
+ ## Context
10
+ ml-runtime requires an implementation language that can integrate directly
11
+ with the AI ecosystem — including LLM SDKs, embedding models, and vector
12
+ stores.
13
+
14
+ The architectural foundation of ml-runtime traces back to StateFlowGuard,
15
+ a TypeScript library built previously. However, the decision to use
16
+ TypeScript/Node.js was never under consideration for ml-runtime — Python
17
+ was the baseline assumption from the start given its AI ecosystem maturity.
18
+
19
+ Rust was identified as the ideal systems language for a runtime of this
20
+ nature due to its memory safety guarantees, lack of GC, and true
21
+ parallelism. However, at this stage, the cost of integrating Rust with
22
+ the Python AI ecosystem outweighs the benefit. Rust AI clients are
23
+ largely community-maintained, and FFI boundary complexity via PyO3 adds
24
+ significant overhead for a project still in the pilot phase.
25
+
26
+ Python was chosen as the pragmatic baseline.
27
+
28
+ ## Decision
29
+ Implement ml-runtime in Python, using asyncio as the concurrency model
30
+ and Pydantic for schema validation and typed context objects.
31
+
32
+ ## Rationale
33
+ Python is the native language of the AI ecosystem. LLM SDKs, vector
34
+ stores, and embedding libraries all provide first-class Python support.
35
+ This eliminates integration friction at the AI layer.
36
+
37
+ asyncio provides sufficient concurrency for I/O-bound pipeline workloads
38
+ — LLM calls, vector store queries, and storage reads are all I/O-bound
39
+ operations where asyncio performs well.
40
+
41
+ Pydantic enforces schema contracts at runtime, partially mitigating
42
+ Python's lack of compile-time type enforcement.
43
+
44
+ ## Consequences
45
+
46
+ ### Positive
47
+ - Full compatibility with AI ecosystem libraries out of the box
48
+ - asyncio handles I/O-bound concurrency adequately for pipeline workloads
49
+ - Pydantic provides runtime type safety for PipelineContext and schemas
50
+
51
+ ### Negative
52
+ - GIL prevents true parallelism — CPU-bound executor work will block
53
+ other coroutines unless explicitly offloaded via run_in_executor()
54
+ - GC pressure increases under high request volume due to Pydantic object
55
+ churn per pipeline execution
56
+ - Python's dynamic typing requires disciplined use of type hints and
57
+ Pydantic — enforcement is opt-in, not compile-time
58
+
59
+ ## Future Consideration
60
+ Rust via PyO3 is the identified migration path if GIL or GC pressure
61
+ becomes a measurable bottleneck in production. The FSM core is a natural
62
+ candidate for extraction as a native extension while the Python AI layer
63
+ remains in place.
@@ -0,0 +1,112 @@
1
+ # ADR-003: Hook System Design
2
+
3
+ ## Status
4
+ #Accepted
5
+
6
+ ## Date
7
+ 2026-05-19
8
+
9
+ ## Context
10
+ As the runtime matured, there was a need to accommodate cross-cutting concerns
11
+ such as state transition logging, audit trails, and notifications without
12
+ coupling these concerns into executor logic. Executors should remain focused
13
+ on their single responsibility — processing a state and returning an event.
14
+
15
+ Hardcoding observability and extensibility logic directly into executors would
16
+ violate separation of concerns and make the runtime harder to maintain and extend.
17
+
18
+ The initial design used a `plugins.json` configuration file with two modes:
19
+ `hanging` (fire-and-forget) and `middleware` (blocking). After implementation,
20
+ this approach was replaced with a decorator-based `HookRegistry` for the
21
+ following reasons:
22
+
23
+ - `plugins.json` separates hook registration from hook implementation — a
24
+ contributor must read two files to understand one hook's behavior
25
+ - Decorator-based registration is more idiomatic in Python and easier to
26
+ trace via type checkers and IDE tooling
27
+ - The names `hanging` and `middleware` did not sufficiently express the
28
+ behavioral contract of each mode
29
+
30
+ ## Decision
31
+ Introduce a hook system implemented via a decorator-based `HookRegistry`
32
+ with two hook types: **observer** and **interceptor**.
33
+
34
+ ### Observer
35
+ Fire-and-forget. Can be attached to multiple nodes. Executed via
36
+ `asyncio.create_task()`. Used for observability concerns such as logging,
37
+ metrics, and audit trails that must not block pipeline execution.
38
+
39
+ ```python
40
+ @hooks.observer(nodes=["ANALYZE", "MAIN_LLM"], on=HookOn.EXIT)
41
+ async def fn(ctx: ReadOnlyContext) -> None:
42
+ ...
43
+ ```
44
+
45
+ ### Interceptor
46
+ Blocking. Single node only. Executed via `await`. Returns `bool` — if
47
+ `False`, the runtime emits the `on_false` event and redirects accordingly.
48
+ Used for concerns that must intercept execution before or after a node runs
49
+ and may need to halt or redirect the pipeline.
50
+
51
+ ```python
52
+ @hooks.interceptor(node="GUARDRAIL", on=HookOn.ENTER, on_false="OUT_OF_SCOPE")
53
+ async def fn(ctx: ReadOnlyContext) -> bool:
54
+ ...
55
+ ```
56
+
57
+ `on_false` is **required** on every interceptor. If no redirect is needed,
58
+ use an observer instead.
59
+
60
+ ### Single-node constraint on interceptor
61
+ Interceptor is constrained to a single node because each node may have a
62
+ different set of valid outgoing events. Allowing multi-node interceptors
63
+ would require one `on_false` event to be valid across all attached nodes
64
+ simultaneously — this cannot be guaranteed and would produce ambiguous
65
+ wiring between nodes and their `on_false` transitions. The single-node
66
+ constraint removes this ambiguity entirely.
67
+
68
+ ### ReadOnlyContext
69
+ All hooks receive a `ReadOnlyContext` — a subclass of `PipelineContext`
70
+ with `frozen=True`. Hooks observe pipeline state; they do not modify it.
71
+ This ensures hook side effects are bounded and cannot corrupt context.
72
+
73
+ ### Startup validation
74
+ `init_hooks()` validates all registered `on_false` events against the
75
+ schema transitions at startup. An interceptor whose `on_false` event is
76
+ not a valid transition in `schema.json` will raise an error before the
77
+ pipeline accepts any request.
78
+
79
+ ## Rationale
80
+ Hooks as a separate concern from executors keeps the core runtime clean.
81
+ Observability and extensibility are opt-in — implementors attach only what
82
+ they need without modifying executor code.
83
+
84
+ The event-based redirect mechanism for interceptors preserves graph
85
+ integrity. Interceptors cannot redirect to arbitrary nodes — they can only
86
+ emit events already defined in the schema, enforced at startup. This keeps
87
+ the FSM fully auditable.
88
+
89
+ `ReadOnlyContext` as the hook interface ensures that hook side effects are
90
+ predictable. Hooks observe state; they do not modify it.
91
+
92
+ Decorator-based registration keeps registration and implementation
93
+ co-located, reducing the cognitive overhead of understanding any given hook.
94
+
95
+ ## Consequences
96
+
97
+ ### Positive
98
+ - Observability concerns are decoupled from executor logic
99
+ - Implementors extend runtime behavior without touching core files
100
+ - Graph integrity is preserved — hooks cannot bypass schema-defined transitions
101
+ - Single-node constraint on interceptor eliminates `on_false` wiring ambiguity
102
+ - `on_false` startup validation catches misconfiguration before runtime
103
+ - Decorator-based registration is co-located with implementation — easier to read and trace
104
+
105
+ ### Negative
106
+ - Additional complexity for contributors — hook lifecycle, observer vs interceptor
107
+ distinction, and `on_false` requirements must be understood before use
108
+ - Interceptors add latency to the nodes they are attached to
109
+ - `on_false` events must be explicitly defined in `schema.json` — implementors
110
+ must keep hook registrations and schema in sync
111
+ - Single-node interceptor constraint means multi-node interception requires
112
+ registering separate interceptors per node
@@ -0,0 +1,96 @@
1
+ # ADR-004: Guardrail as an Optional Core Node
2
+
3
+ ## Status
4
+ #Accepted
5
+
6
+ ## Date
7
+ 2026-05-19
8
+
9
+ ## Context
10
+ The pipeline's ANALYZE state is responsible for classifying user queries into
11
+ structured intents. During development, domain boundary enforcement — rejecting
12
+ queries outside the operational scope of the runtime — was initially handled
13
+ inside ANALYZE by prompting the LLM to assign low confidence or an
14
+ `outofcontext` intent to out-of-scope queries.
15
+
16
+ This approach has several drawbacks:
17
+
18
+ - ANALYZE becomes responsible for two distinct concerns: intent classification
19
+ and domain boundary enforcement. This violates single responsibility.
20
+ - Domain context injected into the ANALYZE prompt increases token count on every
21
+ request, regardless of whether the query is out of scope.
22
+ - LLM-based boundary enforcement is probabilistic — as observed in testing,
23
+ out-of-scope queries occasionally pass through and receive full responses.
24
+ - Cost and latency scale with prompt size. Overloading ANALYZE with domain
25
+ guardrail logic compounds this as the domain context grows.
26
+
27
+ ## Decision
28
+ Introduce a dedicated GUARDRAIL node as an optional core node, positioned
29
+ between `RETRIEVE_PREVIOUS_CONVERSATION` and `ANALYZE` in the pipeline graph
30
+ when included.
31
+
32
+ GUARDRAIL is optional — its presence is declared in `schema.json`. If the
33
+ node is absent from the schema, the runtime proceeds directly from
34
+ `RETRIEVE_PREVIOUS_CONVERSATION` to `ANALYZE` without error.
35
+
36
+ When included, GUARDRAIL's implementation is injected via a `GuardrailBase`
37
+ abstract interface defined in `infrastructure/adapters/`, following the same
38
+ pattern as `LLMBase` and `StorageBase`. The core runtime does not know the
39
+ domain rules — only that a guardrail check must pass before ANALYZE is invoked.
40
+
41
+ Graph with GUARDRAIL included:
42
+ ```
43
+ RETRIEVE_PREVIOUS_CONVERSATION → GUARDRAIL → ANALYZE
44
+
45
+ FALLBACK (OUT_OF_SCOPE)
46
+ ```
47
+
48
+ Graph without GUARDRAIL:
49
+ ```
50
+ RETRIEVE_PREVIOUS_CONVERSATION → ANALYZE
51
+ ```
52
+ The short-term mitigation — handling `outofcontext` via domain prompt in
53
+ `main_llm_response.txt` — remains in place until GUARDRAIL is implemented.
54
+
55
+ ## Rationale
56
+ Schema-driven optionality is made reliable by ADR-005 — because every executor
57
+ is a pure function that returns a new context via `model_copy` rather than
58
+ mutating the received instance, nodes can be added or removed from the graph
59
+ without implicit side effects on downstream nodes.
60
+
61
+ GUARDRAIL is optional because not every deployment context requires the same
62
+ boundary enforcement strategy. A prototype or internal tool may have no
63
+ out-of-scope risk, and forcing a mandatory node would add unnecessary
64
+ implementation burden. The core remains agnostic.
65
+
66
+ Despite being optional, GUARDRAIL is strongly recommended for any production
67
+ deployment. LLM-based boundary enforcement in ANALYZE is probabilistic — as
68
+ observed in testing, out-of-scope queries occasionally bypass prompt-level
69
+ filtering. GUARDRAIL provides a deterministic enforcement layer before any
70
+ LLM call, at zero token cost.
71
+
72
+ The `GuardrailBase` interface keeps the core agnostic to implementation
73
+ strategy. Whether the implementor uses keyword matching, embedding similarity,
74
+ or a rule engine is an implementation detail the core does not need to know.
75
+
76
+ ## Consequences
77
+
78
+ ### Positive
79
+ - ANALYZE is responsible only for intent classification
80
+ - Out-of-scope queries are rejected before any LLM call — zero token cost
81
+ - Schema-driven optionality is preserved — GUARDRAIL can be included or
82
+ excluded via `schema.json` without affecting other nodes
83
+ - Core remains agnostic to business domain and enforcement strategy
84
+
85
+ ### Negative
86
+ - Optional status means production deployments may omit GUARDRAIL — the
87
+ runtime will not warn or block if the node is absent
88
+ - When included, adds one additional state to every pipeline execution,
89
+ including in-scope queries
90
+ - Implementors must understand that omitting GUARDRAIL delegates boundary
91
+ enforcement back to ANALYZE prompts, which is probabilistic
92
+
93
+ ## Recommendation
94
+ Production deployments should always include GUARDRAIL. Omitting it is
95
+ only appropriate for prototypes or internal tools where domain boundary
96
+ enforcement is not a requirement.
@@ -0,0 +1,104 @@
1
+ # ADR-005: No Direct Mutation of PipelineContext
2
+
3
+ ## Status
4
+ #Accepted
5
+
6
+ ## Date
7
+ 2026-05-21
8
+
9
+ ## Context
10
+ `PipelineContext` is the primary communication object passed between nodes
11
+ in the pipeline. It carries the accumulated results of each executor to
12
+ the next state in the graph.
13
+
14
+ During the pilot phase, executors were written to mutate `PipelineContext`
15
+ directly:
16
+
17
+ ```python
18
+ ctx.context.metadata = metadata
19
+ ctx.context.is_clarification = True
20
+ ctx.context.tools_data = {}
21
+ ```
22
+
23
+ This approach works functionally but violates the intent of how nodes should
24
+ interact with context. Direct mutation introduces several risks:
25
+
26
+ - Executors can overwrite fields set by previous nodes without explicit intent
27
+ - Side effects are implicit — it is not clear from the function signature
28
+ what a node will change
29
+ - Node behavior becomes order-dependent in ways that are not visible in the
30
+ schema, making the pipeline harder to reason about
31
+ - Schema-driven optionality — the ability to compose pipelines by including
32
+ or excluding nodes via `schema.json` — is fragile if nodes have implicit
33
+ side effects on shared state
34
+
35
+ This principle is foundational to ADR-004 (Guardrail as Optional Node).
36
+ Schema-driven optionality only works reliably if every node is a pure
37
+ function — same input context produces predictable output context, with no
38
+ hidden side effects on the received instance.
39
+
40
+ ## Decision
41
+ Executors must not mutate the `PipelineContext` instance they receive.
42
+ Instead, every executor must return a new context instance via Pydantic's
43
+ `model_copy(update={...})` pattern.
44
+
45
+ ```python
46
+ # before — direct mutation
47
+ ctx.context.metadata = metadata
48
+ return ReturnSchema(event="NEXT", context=ctx.context)
49
+
50
+ # after — return new instance
51
+ return ReturnSchema(
52
+ event="NEXT",
53
+ context=ctx.context.model_copy(update={"metadata": metadata})
54
+ )
55
+ ```
56
+
57
+ `PipelineContext` remains a mutable Pydantic model — this is not full
58
+ immutability. The constraint is behavioral: no executor may call attribute
59
+ assignment on the context instance it receives. All changes must go through
60
+ `model_copy`.
61
+
62
+ ## Rationale
63
+ `PipelineContext` is a message passed between nodes, not a shared global
64
+ state. Treating it as a message means each node is responsible for producing
65
+ the next version of that message explicitly — changes are visible in the
66
+ return value, not hidden as side effects.
67
+
68
+ This aligns with the functional pipeline principle: nodes are pure functions
69
+ that take context and return context. The FSM runtime loop is the only
70
+ entity that decides which context version becomes the active state.
71
+
72
+ This also enables schema-driven optionality — if a node can be added or
73
+ removed from the graph via `schema.json` without breaking other nodes,
74
+ each node must be self-contained and free of implicit dependencies on
75
+ mutation order.
76
+
77
+ ## Consequences
78
+
79
+ ### Positive
80
+ - Node behavior is explicit — all context changes are visible in the return value
81
+ - Nodes become self-contained — removing a node from the schema does not
82
+ silently break downstream nodes that depended on its mutations
83
+ - Easier to test — each executor can be tested in isolation with a fixed
84
+ input context
85
+ - Enables schema-driven optionality as described in ADR-004
86
+
87
+ ### Negative
88
+ - All existing executors need to be refactored — direct mutations are
89
+ pervasive in the current codebase
90
+ - `model_copy` creates a new Pydantic object per executor call — minor
91
+ memory overhead per pipeline execution, acceptable at current scale
92
+ - Slightly more verbose executor code compared to direct assignment
93
+
94
+ ## Refactor Scope
95
+ The following executors require refactoring as part of Phase 2:
96
+ - `handle_analyze` — mutates `metadata`, `error`, `last_error_emitted`
97
+ - `handle_fallback` — mutates `is_clarification`, `fallback_content`
98
+ - `handle_tools_mapper` — mutates `tool_list`
99
+ - `handle_execute_tools` — mutates `tools_data`, `tool_list`, `last_error_emitted`
100
+ - `handle_main_llm` — mutates `summarize`, `response`
101
+ - `handle_save_data_to_persistence` — no context mutation, compliant
102
+ - `handle_retrieve_previous_conversation` — mutates `background`
103
+ - `handle_error_counter` — mutates via redis, context passed through
104
+ - `handle_internal_server_error` — mutates `response`
covalve-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Candra Julius Indira Patty
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.