KAITO Guardrail Core
kaito-guardrail-core provides KAITO-owned scanners and guardrail_core.streaming, a
standard-library-only submodule for SSE framing and OpenAI chat chunk
parsing/building. The streaming submodule does not scan, block, or implement
holdback policy.
Installation and development
python -m pip install -e ./guardrail_core
python -m pip install build==1.2.2.post1 twine==6.1.0 pytest==9.1.1
python -m build ./guardrail_core
python -m twine check --strict guardrail_core/dist/*
python -m pytest guardrail_core/tests guardrail_core/guardrail_core
The streaming tests import the installed package, not a sys.path-injected source
tree. CI builds the kaito-guardrail-core wheel, installs it without dependencies in a
fresh virtual environment, and runs the tests from outside the repository on
Python 3.12 through 3.14.
The distribution name is kaito-guardrail-core; Python imports remain guardrail_core,
including guardrail_core.streaming. The initial release keeps existing scanner
dependencies mandatory, although importing streaming itself uses only the standard
library. Packaging does not change parser, scanner, or holdback behavior.
Publishing
Only guardrail_core/ is built, not RAGEngine or the repository as a whole.
pyproject.toml is the single source of package metadata and version. Wheels
exclude tests; source distributions include tests and the build configuration.
The package license is a copy of the repository's Apache 2.0 license.
Before the first release, confirm the kaito-guardrail-core distribution name and
maintainer access with Brandon. An administrator must configure:
- A project or pending publisher on both TestPyPI and PyPI for
kaito-guardrail-core. - A GitHub Trusted Publisher on each index: owner
kaito-project, repositorykaito, workflow filenamerelease-guardrail-core.yaml, and the corresponding GitHub environment below. Publishing uses GitHub OIDC, not an API token. - GitHub environments
guardrail-core-testpypiandguardrail-core-pypi, restricted tomain. Require maintainer approval forguardrail-core-pypibefore enabling production publishing.
Reference: kaito-rag-api release workflow. This package is published from KAITO; no changes to that repository are needed.
After these changes and the intended package version merge into main, run the
Release KAITO Guardrail Core workflow:
- Select the workflow on
main. Supplyrelease_version, such as0.1.0, andrelease_commit, the full lowercase 40-character commit SHA onmain. The workflow checks ancestry, metadata/version agreement, and that the package tag does not already exist. It does not update the source version. - Build the source distribution and then its wheel. Validate metadata and distribution contents, then run all scanner and streaming tests against the installed wheel in a fresh environment outside the source checkout.
- Publish those artifacts to TestPyPI. Download its wheel using only TestPyPI and compare it byte-for-byte with the original. Install dependencies separately from PyPI, then install the downloaded wheel in a fresh environment and smoke test the version, imports, framing, and scanners. No mixed-index resolution is used.
- Approve the
guardrail-core-pypienvironment after verification succeeds. Publish the same stored wheel and source distribution to PyPI, without rebuilding. - Create
kaito-guardrail-core-v<version>and a GitHub Release pointing to the exact source commit, with those distributions attached. Package tags do not trigger KAITO's application release workflow, and the package release is not marked as the repository's latest release.
For transient publishing or index availability failures, inspect the error and rerun only failed jobs in the same workflow run to reuse the original artifacts. Existing versions are not silently skipped or overwritten. If a partial upload prevents retrying, coordinate recovery with the maintainers; do not rebuild different content under the same version. After a successful release, bump the version in a new PR before publishing again.
Only after the version exists on production PyPI should RAGEngine and
production-stack adopt an exact dependency such as kaito-guardrail-core==0.1.0.
Production images should install requirements rather than copy the library source.
Local development may continue using editable installation. Consumer changes and
holdback extraction are separate follow-ups.
Byte-oriented SSE framing
from guardrail_core.streaming.sse import SSEFramer
from guardrail_core.streaming.openai import parse_openai_chat_sse_event
framer = SSEFramer(max_event_bytes=1024 * 1024)
for chunk in [b'data: {"choices":[]}\r', b"\n\r", b"\n"]:
for event in framer.feed(chunk):
result = parse_openai_chat_sse_event(event)
print(result.status, result.payload)
for event in framer.finish():
print(event.data)
Call feed(bytes) in stream order and finish() exactly once at EOF. Both return
lists of complete SSEEvent objects. LF, CRLF, CR, mixed endings, and arbitrary
byte boundaries (including UTF-8 code points) are supported. A trailing CR is
held until the next byte or EOF determines whether it is part of CRLF.
Only complete events are decoded, using strict UTF-8. EOF never invents a blank
line: a single final line ending is not an event terminator.
Every terminating blank line produces an event, including blank-only and
comment-only events. data and data: both represent an empty data field;
one optional leading ASCII space is removed from field values. Multiple data
fields are joined with LF. Comments and other fields remain available but do not
contribute to data. Only CR/LF are line endings (not Unicode line separators).
event.raw_bytes: exact received bytes, including line endings and the terminating blank line, suitable for lossless forwarding.event.raw: decoded event body, excluding its final line ending and blank line.event.lines: body lines, including comments and non-data fields.event.data: joined data fields, orNonewhen no data fields exist.SSEEvent.from_raw(text): parse an already decoded event body, without framing; itsraw_bytesdefaults to the UTF-8 encoding of that body.
Errors and resource bounds
SSEFramingError is a ValueError with these subclasses:
| Exception | Meaning |
|---|---|
SSEDecodeError |
A complete event is not valid UTF-8; the original decode error is chained. |
SSEIncompleteEventError |
EOF left an unterminated event, including an incomplete UTF-8 sequence. |
SSEEventTooLargeError |
An event exceeded max_event_bytes (default 1 MiB). |
The positive integer limit counts wire bytes, including delimiters, independently
for each event. Buffering and processing are bounded by that limit and linear in
input size; a huge delimiter-free chunk is rejected without copying it in full.
Invalid limits and non-byte input raise ValueError/TypeError.
On a framing error, error.raw_bytes contains the failing event's buffered bytes
(at most the limit). error.completed_events contains earlier events completed
in the same call, so callers can explicitly choose whether to forward them.
The framer becomes unusable after either a framing error or finish(); subsequent
calls raise ValueError. There is no silent recovery, dropped malformed event,
or automatic failure policy.
OpenAI parsing contract
parse_openai_chat_sse_event(event) returns OpenAIChatChunkParseResult, retaining
RAGEngine's status names and convenience fields:
| Input | OpenAIChatChunkParseStatus |
|---|---|
| No data field, empty data, or whitespace-only data | NO_DATA |
Data equal to [DONE] after stripping whitespace |
DONE |
| Invalid JSON | MALFORMED_JSON, with error |
| Non-object payload, non-list choices, or non-object choice | INVALID_PAYLOAD, with error |
| Missing/non-integer choice index (including bool) | INVALID_PAYLOAD, with error |
| Missing/null delta | PARSED, treating delta as an empty object |
| Non-object, non-null delta | INVALID_PAYLOAD, with error |
| Missing/null content | PARSED, no text |
| Non-string, non-null content or finish_reason | INVALID_PAYLOAD, with error |
| Valid choices, including empty, role-only, and multi-choice chunks | PARSED |
Missing choices is treated as an empty list, matching RAGEngine (e.g. usage-only
chunks). Every choice is retained in order; integer indexes need not be zero or
contiguous. parsed_choices includes role-only and tool-call-only choices.
Each ParsedOpenAIChoice exposes choice_index, content, finish_reason, and
the complete original choice dictionary. payload retains all decoded fields
for object payloads, including invalid objects. contents and finish_reasons
contain only non-null extracted values; use parsed_choices for alignment.
The parser does not mutate input. Bare [DONE] without a data field is NO_DATA,
not a compatibility shortcut. Stream bytes remain available on the original event.
SSE builders
The functions in guardrail_core.streaming.openai return UTF-8-encodable strings
with LF delimiters, matching RAGEngine:
build_openai_chat_delta_sse_chunk(content, *, choice_index=0)build_openai_chat_finish_reason_sse_chunk(*, finish_reason="content_filter", choice_index=0)build_sse_done_chunk()build_sse_data_chunk(payload)for arbitrary JSON object fields and choices
Text builders create new minimal chunks; use the generic builder with a retained
payload to preserve metadata, or forward event.raw_bytes for byte-exact replay.
The framing regression cases are adapted from production-stack#228. Its single-choice/index-zero restrictions are intentionally not adopted.
Metadata
Release files for kaito-guardrail-core 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| kaito_guardrail_core-0.1.0.tar.gz | 33.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kaito_guardrail_core-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.7 kB
Release files / kaito_guardrail_core-0.1.0.tar.gz
| Download URL | kaito_guardrail_core-0.1.0.tar.gz |
|---|---|
| Size | 33.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1f8a50ffee0ada4e5433d90018d0ae68782f4a1a1efc3d348e7776ce5f4a6418
|
|
BLAKE2b-256 checksum How to use checksums |
473010c60dafd9c8f811790a40f0758b505ac4f449b46bd1b1ba1d728b816b24
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logRelease files / kaito_guardrail_core-0.1.0-py3-none-any.whl
| Download URL | kaito_guardrail_core-0.1.0-py3-none-any.whl |
|---|---|
| Size | 24.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e461d1b45cb5a22d5412e6fef3f5a4fe26ef8d3a28d09ae18e91a3165503d357
|
|
BLAKE2b-256 checksum How to use checksums |
617abcf753e2613a77a8151032dacf007cf2ca19c04486260b04b92a430adeaa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logSecurity for kaito-guardrail-core 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for kaito_guardrail_core-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.