nlweb-widget 0.9.12__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.
- nlweb_widget-0.9.12/.env.agentic.coding.example +18 -0
- nlweb_widget-0.9.12/.env.example +56 -0
- nlweb_widget-0.9.12/.github/CODEOWNERS +1 -0
- nlweb_widget-0.9.12/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- nlweb_widget-0.9.12/.github/dependabot.yml +7 -0
- nlweb_widget-0.9.12/.github/workflows/ci.yml +18 -0
- nlweb_widget-0.9.12/.github/workflows/release.yml +124 -0
- nlweb_widget-0.9.12/.gitignore +16 -0
- nlweb_widget-0.9.12/.nlweb-build-manifest.toml +144 -0
- nlweb_widget-0.9.12/.python-version +1 -0
- nlweb_widget-0.9.12/.vscode/launch.json +37 -0
- nlweb_widget-0.9.12/.vscode/tasks.json +93 -0
- nlweb_widget-0.9.12/AGENTS.md +34 -0
- nlweb_widget-0.9.12/ARCHITECTURE.md +43 -0
- nlweb_widget-0.9.12/AUTHORITATIVE-DOMAIN-DATA-CONTRACT.md +55 -0
- nlweb_widget-0.9.12/CHANGELOG.md +67 -0
- nlweb_widget-0.9.12/CONTRACT-TRACEABILITY.md +16 -0
- nlweb_widget-0.9.12/CONTRIBUTING.md +3 -0
- nlweb_widget-0.9.12/LICENSE +21 -0
- nlweb_widget-0.9.12/PKG-INFO +212 -0
- nlweb_widget-0.9.12/README.md +172 -0
- nlweb_widget-0.9.12/pyproject.toml +41 -0
- nlweb_widget-0.9.12/revision-iteration-manifest-0.9.12.toml +42 -0
- nlweb_widget-0.9.12/scripts/bootstrap-win10.ps1 +7 -0
- nlweb_widget-0.9.12/skills/nlweb-provider-qa/SKILL.md +16 -0
- nlweb_widget-0.9.12/skills/nlweb-release/SKILL.md +18 -0
- nlweb_widget-0.9.12/skills/nlweb-release/references/release-gates.md +11 -0
- nlweb_widget-0.9.12/skills.md +12 -0
- nlweb_widget-0.9.12/src/nlweb_widget/__init__.py +43 -0
- nlweb_widget-0.9.12/src/nlweb_widget/cli.py +18 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/__init__.py +52 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/adapters.py +335 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/fingerprint.py +20 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/haystack.py +105 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/models.py +72 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/neo4j.py +236 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/qdrant.py +154 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/qdrant_edge.py +202 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/retrieval.py +31 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/scheduler.py +29 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/service.py +239 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/sqlite.py +404 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/state.py +35 -0
- nlweb_widget-0.9.12/src/nlweb_widget/content/store.py +179 -0
- nlweb_widget-0.9.12/src/nlweb_widget/embedding_benchmark.py +86 -0
- nlweb_widget-0.9.12/src/nlweb_widget/embeddings.py +61 -0
- nlweb_widget-0.9.12/src/nlweb_widget/errors.py +25 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/__init__.py +13 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/_bridge.py +10 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/django_integration.py +46 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/fastapi_integration.py +143 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/flask_integration.py +64 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/starlette_integration.py +45 -0
- nlweb_widget-0.9.12/src/nlweb_widget/integrations/stdlib_http_integration.py +93 -0
- nlweb_widget-0.9.12/src/nlweb_widget/models.py +219 -0
- nlweb_widget-0.9.12/src/nlweb_widget/protocol.py +196 -0
- nlweb_widget-0.9.12/src/nlweb_widget/retrieval.py +50 -0
- nlweb_widget-0.9.12/src/nlweb_widget/settings.py +109 -0
- nlweb_widget-0.9.12/src/nlweb_widget/widget.py +460 -0
- nlweb_widget-0.9.12/tests/integration/test_fastapi_integration.py +129 -0
- nlweb_widget-0.9.12/tests/integration/test_http_error_contract.py +23 -0
- nlweb_widget-0.9.12/tests/integration/test_stdlib_contract.py +16 -0
- nlweb_widget-0.9.12/tests/packaging/test_manifest.py +72 -0
- nlweb_widget-0.9.12/tests/packaging/test_naming.py +19 -0
- nlweb_widget-0.9.12/tests/packaging/test_package_ownership.py +13 -0
- nlweb_widget-0.9.12/tests/unit/test_cli.py +5 -0
- nlweb_widget-0.9.12/tests/unit/test_content_recovery.py +69 -0
- nlweb_widget-0.9.12/tests/unit/test_content_sources_config.py +31 -0
- nlweb_widget-0.9.12/tests/unit/test_document_adapter.py +38 -0
- nlweb_widget-0.9.12/tests/unit/test_embedding_benchmark.py +26 -0
- nlweb_widget-0.9.12/tests/unit/test_embeddings.py +22 -0
- nlweb_widget-0.9.12/tests/unit/test_operational_state.py +81 -0
- nlweb_widget-0.9.12/tests/unit/test_optional_stores.py +203 -0
- nlweb_widget-0.9.12/tests/unit/test_protocol.py +47 -0
- nlweb_widget-0.9.12/tests/unit/test_protocol_compliance.py +295 -0
- nlweb_widget-0.9.12/tests/unit/test_protocol_matrix.py +147 -0
- nlweb_widget-0.9.12/tests/unit/test_qdrant_edge.py +34 -0
- nlweb_widget-0.9.12/tests/unit/test_settings.py +31 -0
- nlweb_widget-0.9.12/uv.lock +4983 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Agentic coding credential classification template.
|
|
2
|
+
# Copy to .env.agentic.coding locally; never commit the populated file.
|
|
3
|
+
|
|
4
|
+
# OpenAI / Codex-compatible API
|
|
5
|
+
OPENAI_API_KEY=
|
|
6
|
+
|
|
7
|
+
# Anthropic / Claude-compatible API
|
|
8
|
+
ANTHROPIC_API_KEY=
|
|
9
|
+
|
|
10
|
+
# Other coding-agent provider API keys, if used by local tooling
|
|
11
|
+
# CODE_AGENT_API_KEY=
|
|
12
|
+
|
|
13
|
+
# GitHub CLI / API authentication should normally remain in the user's
|
|
14
|
+
# OS credential store or `gh auth`; do not copy a personal token here.
|
|
15
|
+
# GITHUB_TOKEN=
|
|
16
|
+
|
|
17
|
+
# Optional package/release credentials should use CI trusted publishing instead.
|
|
18
|
+
# PYPI_TOKEN=
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Core
|
|
2
|
+
# Disabled by default: protects a fresh domain from accidental projection/retrieval.
|
|
3
|
+
NLWEB_ENABLED=false
|
|
4
|
+
NLWEB_PREFIX=/nlweb
|
|
5
|
+
NLWEB_SITE=default
|
|
6
|
+
NLWEB_RETRIEVAL_STORE=memory
|
|
7
|
+
# Optional Haystack InMemory semantic retrieval
|
|
8
|
+
# NLWEB_RETRIEVAL_STORE=haystack-memory
|
|
9
|
+
NLWEB_CONTENT_SYNC_ENABLED=true
|
|
10
|
+
NLWEB_CONTENT_SYNC_ON_STARTUP=false
|
|
11
|
+
NLWEB_CONTENT_SOURCES_FILE=./nlweb-sources.json
|
|
12
|
+
NLWEB_CONTENT_SYNC_STATE_FILE=.nlweb-sync-state.json
|
|
13
|
+
NLWEB_CONTENT_SYNC_INTERVAL_SECONDS=900
|
|
14
|
+
|
|
15
|
+
# Optional PostgreSQL + pgvector
|
|
16
|
+
# NLWEB_RETRIEVAL_STORE=pgvector
|
|
17
|
+
# NLWEB_POSTGRES_DATABASE_URL=postgresql+asyncpg://nlweb:nlweb@localhost:5432/nlweb
|
|
18
|
+
# NLWEB_PGVECTOR_DIMENSIONS=384
|
|
19
|
+
|
|
20
|
+
# Optional Neo4j
|
|
21
|
+
# NLWEB_RETRIEVAL_STORE=neo4j
|
|
22
|
+
# NLWEB_NEO4J_URI=neo4j://localhost:7687
|
|
23
|
+
# NLWEB_NEO4J_USERNAME=neo4j
|
|
24
|
+
# NLWEB_NEO4J_PASSWORD=
|
|
25
|
+
# NLWEB_NEO4J_DATABASE=neo4j
|
|
26
|
+
# NLWEB_NEO4J_VECTOR_DIMENSIONS=384
|
|
27
|
+
|
|
28
|
+
# Optional Qdrant Server / Cloud
|
|
29
|
+
# NLWEB_RETRIEVAL_STORE=qdrant
|
|
30
|
+
# NLWEB_QDRANT_URL=http://localhost:6333
|
|
31
|
+
# NLWEB_QDRANT_API_KEY=
|
|
32
|
+
# NLWEB_QDRANT_COLLECTION=nlweb_documents
|
|
33
|
+
# NLWEB_QDRANT_DIMENSIONS=384
|
|
34
|
+
|
|
35
|
+
# Optional Qdrant Edge (embedded/local, no server required)
|
|
36
|
+
# NLWEB_RETRIEVAL_STORE=qdrant_edge
|
|
37
|
+
# NLWEB_QDRANT_EDGE_PATH=./.nlweb-qdrant-edge
|
|
38
|
+
# NLWEB_QDRANT_EDGE_DIMENSIONS=384
|
|
39
|
+
|
|
40
|
+
# Optional SQLite + sqlite-vec hybrid retrieval (FTS5 + vector KNN)
|
|
41
|
+
# Install with: uv sync --extra sqlite
|
|
42
|
+
# NLWEB_RETRIEVAL_STORE=sqlite
|
|
43
|
+
# NLWEB_SQLITE_PATH=./.nlweb-sqlite/nlweb.db
|
|
44
|
+
# NLWEB_SQLITE_DIMENSIONS=384
|
|
45
|
+
|
|
46
|
+
# Optional local semantic embeddings (used by Haystack/Qdrant/PostgreSQL/Neo4j when
|
|
47
|
+
# an embedding provider is not injected). The default is multilingual and light enough
|
|
48
|
+
# for local development. For E5 models, query/passage prefixes are applied automatically.
|
|
49
|
+
# NLWEB_EMBEDDING_MODEL=sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
|
|
50
|
+
# NLWEB_EMBEDDING_QUERY_PREFIX=
|
|
51
|
+
# NLWEB_EMBEDDING_DOCUMENT_PREFIX=
|
|
52
|
+
# NLWEB_EMBEDDING_DEVICE=cpu
|
|
53
|
+
|
|
54
|
+
# Optional unstructured document ingestion via Docling for ContentSourceKind.CUSTOM.
|
|
55
|
+
# Install with: uv sync --extra documents
|
|
56
|
+
NLWEB_TEST_ENV=dev # Indicates whether tests for governance tests (manifests) needed to be performed
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @maintainers
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on: [push,pull_request]
|
|
3
|
+
permissions: {contents: read}
|
|
4
|
+
jobs:
|
|
5
|
+
core:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
strategy: {matrix: {python: ["3.10","3.11","3.12","3.13","3.14"]}}
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
10
|
+
with:
|
|
11
|
+
persist-credentials: false
|
|
12
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
13
|
+
- run: uv python install ${{ matrix.python }}
|
|
14
|
+
- run: uv sync --dev --all-extras --python ${{ matrix.python }}
|
|
15
|
+
- run: uv run --python ${{ matrix.python }} pytest
|
|
16
|
+
- run: uv run --python ${{ matrix.python }} ruff check .
|
|
17
|
+
- run: uv run --python ${{ matrix.python }} ruff format --check .
|
|
18
|
+
- run: uv build
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
|
|
7
|
+
# Default to read-only; grant write permissions only to jobs that need them.
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: pypi-release
|
|
13
|
+
queue: max
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
name: Validate, test, and build
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
|
|
27
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
28
|
+
|
|
29
|
+
- name: Install release Python
|
|
30
|
+
run: uv python install 3.12
|
|
31
|
+
|
|
32
|
+
- name: Install release dependencies
|
|
33
|
+
run: uv sync --dev --all-extras --python 3.12
|
|
34
|
+
|
|
35
|
+
- name: Verify tag matches project version
|
|
36
|
+
shell: bash
|
|
37
|
+
run: |
|
|
38
|
+
VERSION=$(uv run --python 3.12 python - <<'PY'
|
|
39
|
+
import tomllib
|
|
40
|
+
with open("pyproject.toml", "rb") as f:
|
|
41
|
+
print(tomllib.load(f)["project"]["version"])
|
|
42
|
+
PY
|
|
43
|
+
)
|
|
44
|
+
test "v${VERSION}" = "${GITHUB_REF_NAME}"
|
|
45
|
+
|
|
46
|
+
- name: Test
|
|
47
|
+
run: uv run --python 3.12 pytest
|
|
48
|
+
|
|
49
|
+
- name: Lint
|
|
50
|
+
run: uv run --python 3.12 ruff check .
|
|
51
|
+
|
|
52
|
+
- name: Format check
|
|
53
|
+
run: uv run --python 3.12 ruff format --check .
|
|
54
|
+
|
|
55
|
+
- name: Build distributions
|
|
56
|
+
run: uv build --python 3.12
|
|
57
|
+
|
|
58
|
+
- name: Upload distributions
|
|
59
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
60
|
+
with:
|
|
61
|
+
name: distributions
|
|
62
|
+
path: dist/
|
|
63
|
+
if-no-files-found: error
|
|
64
|
+
retention-days: 30
|
|
65
|
+
|
|
66
|
+
attest:
|
|
67
|
+
name: Attest build provenance
|
|
68
|
+
needs: build
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
permissions:
|
|
71
|
+
contents: read
|
|
72
|
+
id-token: write
|
|
73
|
+
attestations: write
|
|
74
|
+
|
|
75
|
+
steps:
|
|
76
|
+
- name: Download distributions
|
|
77
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
78
|
+
with:
|
|
79
|
+
name: distributions
|
|
80
|
+
path: dist/
|
|
81
|
+
|
|
82
|
+
- name: Attest build provenance
|
|
83
|
+
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
|
84
|
+
with:
|
|
85
|
+
subject-path: "dist/*"
|
|
86
|
+
|
|
87
|
+
github-release:
|
|
88
|
+
name: Create GitHub release
|
|
89
|
+
needs: [build, attest]
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
permissions:
|
|
92
|
+
contents: write
|
|
93
|
+
|
|
94
|
+
steps:
|
|
95
|
+
- name: Download distributions
|
|
96
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
97
|
+
with:
|
|
98
|
+
name: distributions
|
|
99
|
+
path: dist/
|
|
100
|
+
|
|
101
|
+
- name: Create GitHub release
|
|
102
|
+
uses: softprops/action-gh-release@8a0cd651e5b2365bd640854a3fa5dfc70e4875f3 # v3.0.4
|
|
103
|
+
with:
|
|
104
|
+
generate_release_notes: true
|
|
105
|
+
files: "dist/*"
|
|
106
|
+
|
|
107
|
+
publish-pypi:
|
|
108
|
+
name: Publish to PyPI
|
|
109
|
+
needs: [build, attest]
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
environment:
|
|
112
|
+
name: pypi
|
|
113
|
+
permissions:
|
|
114
|
+
id-token: write
|
|
115
|
+
|
|
116
|
+
steps:
|
|
117
|
+
- name: Download distributions
|
|
118
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
119
|
+
with:
|
|
120
|
+
name: distributions
|
|
121
|
+
path: dist/
|
|
122
|
+
|
|
123
|
+
- name: Publish to PyPI via trusted publishing
|
|
124
|
+
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1 v1.14.3
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
[manifest]
|
|
2
|
+
kind = "canonical-build-manifest"
|
|
3
|
+
schema_version = "2.0"
|
|
4
|
+
package_version = "0.9.12"
|
|
5
|
+
mutation_round = "release"
|
|
6
|
+
mutation_candidate = "nlweb-widget-0.9.12"
|
|
7
|
+
distribution_name = "nlweb-widget"
|
|
8
|
+
import_namespace = "nlweb_widget"
|
|
9
|
+
build_mode = "forward-only"
|
|
10
|
+
genesis_baseline_immutable = true
|
|
11
|
+
|
|
12
|
+
[governance]
|
|
13
|
+
active_revision_manifest_sha256 = "a6417d4294d7e5d86ae21c7fa890d56d64bc60687625c80892e28379d248e3fb"
|
|
14
|
+
active_revision_manifest = "revision-iteration-manifest-0.9.12.toml"
|
|
15
|
+
active_revision_manifest_required = true
|
|
16
|
+
active_revision_manifest_hash_required = true
|
|
17
|
+
only_declared_iteration_changes_permitted = true
|
|
18
|
+
unapproved_mutation_is_build_blocking = true
|
|
19
|
+
release_approved = true
|
|
20
|
+
|
|
21
|
+
[genesis]
|
|
22
|
+
package_sha256 = "cf22dcb24707a22a2f34a7565b30da73b221bc359e42ad9f6f85a17293f59c02"
|
|
23
|
+
docs_sha256 = "a2cfb30155bb3686ee0116266edeb4770e78fffd3c5718ae9389c9fa9ec53c0a"
|
|
24
|
+
immutable = true
|
|
25
|
+
|
|
26
|
+
[baseline_transition]
|
|
27
|
+
success_action = "promote-successful-result-to-next-baseline"
|
|
28
|
+
failure_action = "retain-current-baseline"
|
|
29
|
+
rollback = "explicit-only"
|
|
30
|
+
rollback_requires_hash_address = true
|
|
31
|
+
|
|
32
|
+
[recovery]
|
|
33
|
+
historical_capability_recovery = true
|
|
34
|
+
protected_capability_inventory_required = true
|
|
35
|
+
omission_point_recorded = true
|
|
36
|
+
reference_implementation_internals_forbidden = true
|
|
37
|
+
|
|
38
|
+
[providers]
|
|
39
|
+
postgres_pgvector_optional = true
|
|
40
|
+
neo4j_optional = true
|
|
41
|
+
haystack_optional = true
|
|
42
|
+
qdrant_optional = true
|
|
43
|
+
qdrant_edge_optional = true
|
|
44
|
+
sqlite_vec_optional = true
|
|
45
|
+
sqlite_vec_pin = "0.1.8"
|
|
46
|
+
docling_optional = true
|
|
47
|
+
sentence_transformers_optional = true
|
|
48
|
+
embedding_provider_injected = true
|
|
49
|
+
provider_tests_conditional = true
|
|
50
|
+
|
|
51
|
+
[protocol]
|
|
52
|
+
ask = "/ask"
|
|
53
|
+
mcp = "/mcp"
|
|
54
|
+
discovery = "/.well-known/nlweb"
|
|
55
|
+
health = "/health"
|
|
56
|
+
ask_is_normative = true
|
|
57
|
+
mcp_is_binding = true
|
|
58
|
+
discovery_is_non_normative_metadata = true
|
|
59
|
+
health_is_operational = true
|
|
60
|
+
root_domain_default = true
|
|
61
|
+
protocol_source_review_required = true
|
|
62
|
+
|
|
63
|
+
[lifecycle]
|
|
64
|
+
enabled_setting = "NLWEB_ENABLED"
|
|
65
|
+
enabled_default = false
|
|
66
|
+
projection_safeguard_only = true
|
|
67
|
+
widget_owned_state = "effective_state"
|
|
68
|
+
admin_lifecycle_extension_external = true
|
|
69
|
+
|
|
70
|
+
[content_projection]
|
|
71
|
+
source_registry_loading = true
|
|
72
|
+
startup_projection = true
|
|
73
|
+
relative_source_paths_resolved_against_registry = true
|
|
74
|
+
|
|
75
|
+
[ecosystem]
|
|
76
|
+
master_manifest = "nlweb-widget-ecosystem-manifest.toml"
|
|
77
|
+
examples_repository = "nlweb-widget-examples"
|
|
78
|
+
examples_are_published_to_pypi = false
|
|
79
|
+
examples_dependencies_must_not_enter_runtime = true
|
|
80
|
+
examples_are_independent_lifecycle = true
|
|
81
|
+
|
|
82
|
+
[structure]
|
|
83
|
+
framework_neutral_core = true
|
|
84
|
+
integrations_are_thin_adapters = true
|
|
85
|
+
adapter_pattern = "*_integration.py"
|
|
86
|
+
|
|
87
|
+
[examples]
|
|
88
|
+
repository = "nlweb-widget-examples"
|
|
89
|
+
kept_out_of_widget_repository = true
|
|
90
|
+
[tests]
|
|
91
|
+
all_test_imports_must_be_satisfied_by_dev_group = true
|
|
92
|
+
fresh_uv_sync_is_a_required_gate = true
|
|
93
|
+
required = ["unit", "integration", "packaging"]
|
|
94
|
+
python_minimum = "3.10"
|
|
95
|
+
live_llm_required = false
|
|
96
|
+
external_network_required = false
|
|
97
|
+
examples_test_suite_is_external = true
|
|
98
|
+
|
|
99
|
+
[docs]
|
|
100
|
+
independent_pyproject_required = true
|
|
101
|
+
static_docs_project_must_not_require_editable_build = true
|
|
102
|
+
zensical_required = true
|
|
103
|
+
role_based = true
|
|
104
|
+
protocol_contract_required = true
|
|
105
|
+
|
|
106
|
+
[vscode]
|
|
107
|
+
package_test_tasks_required = true
|
|
108
|
+
package_build_task_required = true
|
|
109
|
+
example_tasks_forbidden = true
|
|
110
|
+
aggregate_visibility_demo_task_forbidden = true
|
|
111
|
+
|
|
112
|
+
[packaging]
|
|
113
|
+
backend = "hatchling"
|
|
114
|
+
uv_backed = true
|
|
115
|
+
pyproject_required = true
|
|
116
|
+
revision_manifest_shipped = true
|
|
117
|
+
build_manifest_shipped = true
|
|
118
|
+
sync_state_shipped = false
|
|
119
|
+
|
|
120
|
+
[release]
|
|
121
|
+
tag_pattern = "v{version}"
|
|
122
|
+
tag_must_equal_project_version = true
|
|
123
|
+
trusted_publishing = true
|
|
124
|
+
provenance_attestation = true
|
|
125
|
+
|
|
126
|
+
[forward_only]
|
|
127
|
+
rules = [
|
|
128
|
+
"Never modify the genesis baseline.",
|
|
129
|
+
"Never introduce example-only dependencies into the published runtime graph.",
|
|
130
|
+
"Example applications and visibility infrastructure are governed by the examples repository.",
|
|
131
|
+
"Never apply undeclared revision changes.",
|
|
132
|
+
"A failed iteration cannot advance the baseline.",
|
|
133
|
+
"A successful iteration becomes the sole candidate next baseline.",
|
|
134
|
+
"Rollback is explicit, hash-addressed, and reviewable.",
|
|
135
|
+
"Build fails closed when governance metadata is inconsistent.",
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
[artifact_packaging]
|
|
139
|
+
fail_closed = true
|
|
140
|
+
forbidden_exact_names = [".env", ".nlweb-sync-state.json"]
|
|
141
|
+
manifest = "nlweb-widget-ecosystem-manifest.toml"
|
|
142
|
+
python_version_file = ".python-version"
|
|
143
|
+
python_version = "3.10"
|
|
144
|
+
forbidden_path_fragments = [".venv/", "__pycache__/", ".pytest_cache/", ".ruff_cache/", ".mypy_cache/", "*.pyc", "*.pyo", "dist/", "build/", ".env/", "node_modules/"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.10
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Python: Current test file",
|
|
6
|
+
"type": "debugpy",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"module": "pytest",
|
|
9
|
+
"args": [
|
|
10
|
+
"${file}",
|
|
11
|
+
"-q"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "Python: Package tests",
|
|
16
|
+
"type": "debugpy",
|
|
17
|
+
"request": "launch",
|
|
18
|
+
"module": "pytest",
|
|
19
|
+
"args": [
|
|
20
|
+
"tests",
|
|
21
|
+
"-q"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "Python: SQLite provider test",
|
|
26
|
+
"type": "debugpy",
|
|
27
|
+
"request": "launch",
|
|
28
|
+
"module": "pytest",
|
|
29
|
+
"args": [
|
|
30
|
+
"tests/unit/test_optional_stores.py",
|
|
31
|
+
"-k",
|
|
32
|
+
"sqlite",
|
|
33
|
+
"-q"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "2.0.0",
|
|
3
|
+
"tasks": [
|
|
4
|
+
{
|
|
5
|
+
"label": "test-all",
|
|
6
|
+
"type": "shell",
|
|
7
|
+
"command": "uv run pytest",
|
|
8
|
+
"problemMatcher": [
|
|
9
|
+
"$python"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"label": "test-unit",
|
|
14
|
+
"type": "shell",
|
|
15
|
+
"command": "uv run pytest tests/unit",
|
|
16
|
+
"problemMatcher": [
|
|
17
|
+
"$python"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"label": "test-integration",
|
|
22
|
+
"type": "shell",
|
|
23
|
+
"command": "uv run pytest tests/integration",
|
|
24
|
+
"problemMatcher": [
|
|
25
|
+
"$python"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"label": "test-packaging",
|
|
30
|
+
"type": "shell",
|
|
31
|
+
"command": "uv run pytest tests/packaging",
|
|
32
|
+
"problemMatcher": [
|
|
33
|
+
"$python"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"label": "test-optional-haystack-memory",
|
|
38
|
+
"type": "shell",
|
|
39
|
+
"command": "uv run pytest tests/unit/test_optional_stores.py -k haystack",
|
|
40
|
+
"problemMatcher": [
|
|
41
|
+
"$python"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"label": "test-optional-qdrant-edge",
|
|
46
|
+
"type": "shell",
|
|
47
|
+
"command": "uv run pytest tests/unit/test_optional_stores.py -k qdrant_edge",
|
|
48
|
+
"problemMatcher": [
|
|
49
|
+
"$python"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"label": "test-optional-qdrant-server",
|
|
54
|
+
"type": "shell",
|
|
55
|
+
"command": "uv run pytest tests/unit/test_optional_stores.py -k 'qdrant and not qdrant_edge'",
|
|
56
|
+
"problemMatcher": [
|
|
57
|
+
"$python"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"label": "test-optional-postgres-pgvector",
|
|
62
|
+
"type": "shell",
|
|
63
|
+
"command": "uv run pytest tests/unit/test_optional_stores.py -k postgres",
|
|
64
|
+
"problemMatcher": [
|
|
65
|
+
"$python"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"label": "test-optional-neo4j",
|
|
70
|
+
"type": "shell",
|
|
71
|
+
"command": "uv run pytest tests/unit/test_optional_stores.py -k neo4j",
|
|
72
|
+
"problemMatcher": [
|
|
73
|
+
"$python"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"label": "build-package",
|
|
78
|
+
"type": "shell",
|
|
79
|
+
"command": "uv build",
|
|
80
|
+
"problemMatcher": [
|
|
81
|
+
"$python"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"label": "Provider: sqlite \u2014 test",
|
|
86
|
+
"type": "shell",
|
|
87
|
+
"command": "uv run pytest tests/unit/test_optional_stores.py -k sqlite",
|
|
88
|
+
"problemMatcher": [
|
|
89
|
+
"$python"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Project
|
|
4
|
+
`nlweb-widget` is a framework-neutral Python library that exposes an authoritative domain-data projection through the NLWeb protocol. The published runtime is intentionally lean; optional providers, framework adapters, and reference examples remain separated.
|
|
5
|
+
|
|
6
|
+
## Authoritative references
|
|
7
|
+
- Read the active `revision-iteration-manifest-*.toml` and `.nlweb-build-manifest.toml` before mutation work.
|
|
8
|
+
- Treat `ARCHITECTURE.md`, `MUTATION.md`, `docs-provider-evaluations.md`, tests, and public docs as repository evidence; do not invent missing contracts.
|
|
9
|
+
- Preserve the forward-only baseline and hash-addressed rollback policy.
|
|
10
|
+
|
|
11
|
+
## Change boundaries
|
|
12
|
+
- Do not modify an immutable baseline or historical candidate.
|
|
13
|
+
- Do not introduce example-only dependencies into the runtime package.
|
|
14
|
+
- Do not break public APIs/import paths/endpoints/configuration/provider contracts.
|
|
15
|
+
- Protocol changes are limited to conformance corrections, normative failure semantics, or additive optional capabilities.
|
|
16
|
+
- Keep framework integrations thin and keep authoritative application data separate from AI-facing retrieval projections.
|
|
17
|
+
- Avoid opportunistic refactors, renames, dependency upgrades, or unrelated cleanup.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
- Install: `uv sync --dev`
|
|
21
|
+
- Tests: `uv run pytest`
|
|
22
|
+
- Lint: `uv run ruff check .`
|
|
23
|
+
- Format check: `uv run ruff format --check .`
|
|
24
|
+
- Build: `uv build`
|
|
25
|
+
- Optional full dependency QA: `uv sync --dev --all-extras`
|
|
26
|
+
|
|
27
|
+
## Verification
|
|
28
|
+
Run the smallest relevant checks first, then the full declared gates for release work. Configured optional-provider tests must exercise the real configured backend; unconfigured providers are skipped. A configured-but-unavailable provider is a failure.
|
|
29
|
+
|
|
30
|
+
## Security
|
|
31
|
+
Never commit credentials, tokens, private keys, `.env`, or `.env.agentic.coding`. Use `.env.agentic.coding.example` only as a classification/template file. Never place production secrets in examples, tests, CI logs, or generated bundles.
|
|
32
|
+
|
|
33
|
+
## Agent workflow
|
|
34
|
+
For non-trivial work: inspect → plan → smallest coherent edit → synchronize manifests/docs/tests → validate → report hashes and remaining risks. Human approval remains required for release promotion, rollback, credential use, and changes to protected agent/governance files.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
`nlweb-widget` is deliberately split into stable protocol/core abstractions and optional provider implementations.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
web framework adapter
|
|
7
|
+
|
|
|
8
|
+
v
|
|
9
|
+
NLWeb protocol core
|
|
10
|
+
|
|
|
11
|
+
+---- authoritative content ingestion
|
|
12
|
+
|
|
|
13
|
+
+---- RetrievalProvider boundary
|
|
14
|
+
|
|
|
15
|
+
+-- memory
|
|
16
|
+
+-- Haystack InMemory (optional)
|
|
17
|
+
+-- PostgreSQL + pgvector (optional)
|
|
18
|
+
+-- Neo4j (optional)
|
|
19
|
+
+-- Qdrant Server/Cloud (optional)
|
|
20
|
+
+-- Qdrant Edge (optional, separate in-process path)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Compatibility boundary
|
|
24
|
+
|
|
25
|
+
The public `NLWebWidget`, request/response models, retrieval protocols, and framework adapters remain the stable consumer-facing surface. Provider libraries are implementation details behind those interfaces.
|
|
26
|
+
|
|
27
|
+
## Retrieval
|
|
28
|
+
|
|
29
|
+
All semantic providers receive an injected `EmbeddingProvider` or use the optional local sentence-transformers helper. This keeps model choice outside store implementation and prevents incompatible vector dimensions from being silently mixed.
|
|
30
|
+
|
|
31
|
+
## Neo4j
|
|
32
|
+
|
|
33
|
+
Schema and vector-index DDL remain explicit Cypher. On Neo4j 2026.01+ the store uses the `SEARCH` clause for vector retrieval; older supported servers use the legacy vector procedure as a compatibility path.
|
|
34
|
+
|
|
35
|
+
## Content ingestion
|
|
36
|
+
|
|
37
|
+
Structured Schema.org/JSON-LD, web-page JSON-LD, RSS/Atom, sitemap, database, and custom callable sources remain supported. `CUSTOM` additionally has an optional Docling-backed document adapter for common unstructured files. Optional parsing libraries are not part of the base runtime dependency set.
|
|
38
|
+
|
|
39
|
+
## Protocol compliance
|
|
40
|
+
|
|
41
|
+
The `/ask` core owns the complete NLWeb v0.55 request envelope (`query`, `context`, `prefer`, `meta`), applies site/domain filters, emits the `_meta` response envelope, and supports the two normative response formats additively. Streaming remains an explicit transport capability not claimed by this core; a complete response is returned with `_meta.streaming=false` when requested.
|
|
42
|
+
|
|
43
|
+
`/mcp` has an independent MCP binding contract. `tools/list` exposes only capabilities actually implemented by the widget, `tools/call` maps application failures to `isError=true`, and unknown tools/invalid JSON-RPC requests use MCP protocol errors. NLWeb reference implementation internals are never imported.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Shared NLWeb Widget authoritative domain data contract
|
|
2
|
+
|
|
3
|
+
Status: approved planning baseline; implementation candidates are pending local-QA approval. This document is shared by the Widget and Examples mutation iterations. Official wire behavior is governed by the [NLWeb Specification](https://nlweb.ai/docs/specification), currently reviewed at v0.55 for the SSE event contract.
|
|
4
|
+
|
|
5
|
+
## Authority and precedence
|
|
6
|
+
|
|
7
|
+
1. Applicable official NLWeb and MCP protocol requirements govern wire behavior.
|
|
8
|
+
2. The Widget owns correct protocol serialization and transport behavior. An Examples convention cannot force or justify a conflicting Widget behavior.
|
|
9
|
+
3. The approved source-data contract governs how examples identify artifacts and retain source metadata.
|
|
10
|
+
4. Consumer-selected manifests and optional metadata may extend behavior only when they do not override standardized field semantics or required response structures.
|
|
11
|
+
|
|
12
|
+
Any suspected conflict must be recorded with the conflicting requirements, affected boundary, evidence, and proposed resolution. It is not silently considered approved.
|
|
13
|
+
|
|
14
|
+
## Result serialization
|
|
15
|
+
|
|
16
|
+
- For conversational-search responses, a requested `summarize` mode produces a result item with `@type: "SearchSummary"` (or a justified domain-specific type) and `text` containing the summary.
|
|
17
|
+
- A top-level `summary` property must not substitute for that result item.
|
|
18
|
+
- If the mode preference includes `summarize` among multiple comma-separated modes, the Widget must include a summary item.
|
|
19
|
+
- Result objects should expose the relevant authoritative schema properties at the result level rather than a private implementation wrapper such as `schema_object`.
|
|
20
|
+
- A suitable source `@type` is preserved. A manifest-declared type is a fallback only when the structured source has no suitable type.
|
|
21
|
+
- Optional grounding metadata must not be used to replace or redefine protocol fields. Its allowed shape and placement must conform to the applicable official specification, not merely to the examples manifest.
|
|
22
|
+
|
|
23
|
+
## Artifact identity and URL precedence
|
|
24
|
+
|
|
25
|
+
- Artifact identity is independent from chunk identity. All chunks for one artifact share the same canonical artifact URL.
|
|
26
|
+
- Chunk uniqueness remains in document IDs and internal chunk metadata. Synthetic `#chunk-N` fragments must not be added.
|
|
27
|
+
- A suitable `url` wins over `@id` for the artifact URL when both are present. Preserve a distinct `@id` where it remains useful as schema identity.
|
|
28
|
+
- Converter-provided URLs are retained. Configured registry URL fallbacks are only used when suitable document/converter URLs are absent.
|
|
29
|
+
- A configured fallback that represents a base path receives the artifact filename. A filename alone never proves a public evidence URI exists.
|
|
30
|
+
|
|
31
|
+
## Optional inbox evidence manifest
|
|
32
|
+
|
|
33
|
+
The Examples candidate defines an optional version-1 `nlweb-evidence-manifest.json` control file. Each `artifacts[]` entry has a safe relative `artifact` key and may contain `type` and `grounding`.
|
|
34
|
+
|
|
35
|
+
- The manifest is not ingested as ordinary prose.
|
|
36
|
+
- Manifest type is a fallback only; suitable source type wins.
|
|
37
|
+
- Grounding supplied by the consumer is persisted as a complete JSON object unchanged at the metadata boundary. If source-schema and metadata grounding are both present and differ, the Widget reports a source-metadata failure instead of silently overwriting either value.
|
|
38
|
+
- Conflicting source and manifest grounding is an explicit ingestion error, not a silent overwrite.
|
|
39
|
+
- No manifest entry means no manifest-declared evidence URI. Other valid source grounding remains possible.
|
|
40
|
+
- A declared URI is a consumer assertion, not proof of public reachability or authenticity. Never expose private paths or fabricate public URLs.
|
|
41
|
+
|
|
42
|
+
## HTTP streaming contract
|
|
43
|
+
|
|
44
|
+
When `prefer.streaming` is true on HTTP `/ask`, the Widget must return `text/event-stream` using Server-Sent Events. The v0.55 specification defines `start` (with `_meta.streaming: true`), indexed `result` events whose `item` matches the non-streaming result-item shape, optional `error` events using the failure response structure, and one `complete` event. The completion `_meta` must preserve `session_context` when present. Non-streaming requests retain the single JSON response. Framework adapters must not claim streaming support unless they implement the actual SSE transport; MCP remains its own binding.
|
|
45
|
+
|
|
46
|
+
## Independent mutation ownership
|
|
47
|
+
|
|
48
|
+
Widget iteration owns `/ask`, response formats, result projection, summary item structure, grounding serialization, streaming transport, and MCP protocol behavior. Examples iteration owns URL normalization in example ingestion, optional manifest parsing, source type precedence, metadata persistence, sample data, and documentation. Both use the same contract revision but have independent candidates, QA records, hashes, and promotion gates.
|
|
49
|
+
|
|
50
|
+
## Known limits requiring explicit QA status
|
|
51
|
+
|
|
52
|
+
- This local sandbox has Python 3.13 but no Python 3.12 installation for the Examples project's declared environment; offline sync cannot provision it.
|
|
53
|
+
- Haystack is declared in the Examples dependencies but is not installed in this sandbox. The actual MultiFileConverter path therefore remains unverified here; installation was attempted but blocked by DNS/network unavailability.
|
|
54
|
+
- Streaming is implemented in the candidate, but only the FastAPI route has a direct end-to-end SSE test in this sandbox; the Starlette, Django, Flask, and stdlib adapters still require framework-specific conformance tests.
|
|
55
|
+
- Before promotion, the maintainer must confirm exact applicable NLWeb/MCP specification revisions for the supported release matrix and rerun QA in the supported clean environment.
|