lpgcast 0.1.1__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.
- lpgcast-0.1.1/.github/workflows/build-docs.yml +65 -0
- lpgcast-0.1.1/.github/workflows/pre-commit.yml +39 -0
- lpgcast-0.1.1/.github/workflows/pypi-publish.yml +45 -0
- lpgcast-0.1.1/.github/workflows/tests.yml +76 -0
- lpgcast-0.1.1/.gitignore +225 -0
- lpgcast-0.1.1/.pre-commit-config.yaml +58 -0
- lpgcast-0.1.1/CHANGELOG.md +67 -0
- lpgcast-0.1.1/LICENSE +201 -0
- lpgcast-0.1.1/PKG-INFO +127 -0
- lpgcast-0.1.1/README.md +96 -0
- lpgcast-0.1.1/docs/_build/gen_cli.py +63 -0
- lpgcast-0.1.1/docs/_build/gen_pages.py +67 -0
- lpgcast-0.1.1/docs/_build/gen_settings.py +53 -0
- lpgcast-0.1.1/docs/assets/favicon.ico +0 -0
- lpgcast-0.1.1/docs/assets/favicon.svg +19 -0
- lpgcast-0.1.1/docs/assets/logo.png +0 -0
- lpgcast-0.1.1/docs/assets/logo.svg +18 -0
- lpgcast-0.1.1/docs/concepts/groundings.md +41 -0
- lpgcast-0.1.1/docs/concepts/identities.md +40 -0
- lpgcast-0.1.1/docs/concepts/index.md +49 -0
- lpgcast-0.1.1/docs/getting_started/installation.md +57 -0
- lpgcast-0.1.1/docs/getting_started/quickstart.md +97 -0
- lpgcast-0.1.1/docs/guides/benchmark.md +82 -0
- lpgcast-0.1.1/docs/guides/database.md +57 -0
- lpgcast-0.1.1/docs/guides/replay.md +43 -0
- lpgcast-0.1.1/docs/guides/schema.md +54 -0
- lpgcast-0.1.1/docs/index.md +134 -0
- lpgcast-0.1.1/docs/reference/index.md +8 -0
- lpgcast-0.1.1/docs/reference/output.md +41 -0
- lpgcast-0.1.1/docs/reference/python/index.md +20 -0
- lpgcast-0.1.1/docs/stylesheets/extra.css +497 -0
- lpgcast-0.1.1/examples/connections/file-backend.yaml +4 -0
- lpgcast-0.1.1/examples/connections/neo4j.yaml +7 -0
- lpgcast-0.1.1/examples/tickets/README.md +35 -0
- lpgcast-0.1.1/examples/tickets/episodes.jsonl +5 -0
- lpgcast-0.1.1/examples/tickets/schema.yaml +92 -0
- lpgcast-0.1.1/lpgcast/__init__.py +77 -0
- lpgcast-0.1.1/lpgcast/bench/README.md +12 -0
- lpgcast-0.1.1/lpgcast/bench/__init__.py +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/SPLITS.yaml +38 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/helpdesk/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/helpdesk/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/helpdesk/expected.yaml +38 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/lab/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/lab/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/lab/expected.yaml +48 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/logistics/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/logistics/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/logistics/expected.yaml +41 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/plant/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/plant/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/direction/plant/expected.yaml +38 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/helpdesk/case.yaml +6 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/helpdesk/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/helpdesk/expected.yaml +50 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/lab/case.yaml +6 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/lab/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/lab/expected.yaml +42 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/logistics/case.yaml +6 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/logistics/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/logistics/expected.yaml +48 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/plant/case.yaml +6 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/plant/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/distractors/plant/expected.yaml +41 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/helpdesk/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/helpdesk/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/helpdesk/expected.yaml +36 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/lab/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/lab/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/lab/expected.yaml +43 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/logistics/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/logistics/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/logistics/expected.yaml +39 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/plant/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/plant/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/identity/plant/expected.yaml +32 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/helpdesk/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/helpdesk/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/helpdesk/expected.yaml +51 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/lab/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/lab/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/lab/expected.yaml +57 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/logistics/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/logistics/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/logistics/expected.yaml +67 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/plant/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/plant/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/injection/plant/expected.yaml +49 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/helpdesk/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/helpdesk/episodes.jsonl +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/helpdesk/expected.yaml +55 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/lab/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/lab/episodes.jsonl +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/lab/expected.yaml +55 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/logistics/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/logistics/episodes.jsonl +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/logistics/expected.yaml +55 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/plant/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/plant/episodes.jsonl +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/mention/plant/expected.yaml +55 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/helpdesk/case.yaml +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/helpdesk/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/helpdesk/expected.yaml +56 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/lab/case.yaml +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/lab/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/lab/expected.yaml +55 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/logistics/case.yaml +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/logistics/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/logistics/expected.yaml +60 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/plant/case.yaml +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/plant/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/recast/plant/expected.yaml +46 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/helpdesk/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/helpdesk/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/helpdesk/expected.yaml +35 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/lab/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/lab/episodes.jsonl +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/lab/expected.yaml +58 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/logistics/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/logistics/episodes.jsonl +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/logistics/expected.yaml +40 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/plant/case.yaml +2 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/plant/episodes.jsonl +3 -0
- lpgcast-0.1.1/lpgcast/bench/cases/units/plant/expected.yaml +55 -0
- lpgcast-0.1.1/lpgcast/bench/cli.py +129 -0
- lpgcast-0.1.1/lpgcast/bench/corpus.py +274 -0
- lpgcast-0.1.1/lpgcast/bench/oracle.py +102 -0
- lpgcast-0.1.1/lpgcast/bench/report.py +314 -0
- lpgcast-0.1.1/lpgcast/bench/run.py +277 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/helpdesk-distractors.yaml +102 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/helpdesk.yaml +104 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/lab-distractors.yaml +104 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/lab.yaml +108 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/logistics-distractors.yaml +106 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/logistics.yaml +108 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/plant-distractors.yaml +102 -0
- lpgcast-0.1.1/lpgcast/bench/schemas/plant.yaml +96 -0
- lpgcast-0.1.1/lpgcast/bench/score.py +525 -0
- lpgcast-0.1.1/lpgcast/cast.py +420 -0
- lpgcast-0.1.1/lpgcast/cli.py +224 -0
- lpgcast-0.1.1/lpgcast/config.py +154 -0
- lpgcast-0.1.1/lpgcast/episode.py +80 -0
- lpgcast-0.1.1/lpgcast/extract.py +147 -0
- lpgcast-0.1.1/lpgcast/ground.py +102 -0
- lpgcast-0.1.1/lpgcast/llm/__init__.py +29 -0
- lpgcast-0.1.1/lpgcast/llm/cache.py +175 -0
- lpgcast-0.1.1/lpgcast/llm/client.py +464 -0
- lpgcast-0.1.1/lpgcast/llm/jsonparse.py +260 -0
- lpgcast-0.1.1/lpgcast/llm/usage.py +150 -0
- lpgcast-0.1.1/lpgcast/output.py +63 -0
- lpgcast-0.1.1/lpgcast/prompt.py +103 -0
- lpgcast-0.1.1/lpgcast/repair.py +79 -0
- lpgcast-0.1.1/lpgcast/resolve.py +257 -0
- lpgcast-0.1.1/lpgcast/schema_io.py +39 -0
- lpgcast-0.1.1/lpgcast/select.py +469 -0
- lpgcast-0.1.1/lpgcast/sink.py +81 -0
- lpgcast-0.1.1/lpgcast/validate.py +415 -0
- lpgcast-0.1.1/lpgcast/write.py +199 -0
- lpgcast-0.1.1/properdocs.yml +120 -0
- lpgcast-0.1.1/pyproject.toml +84 -0
- lpgcast-0.1.1/test/conftest.py +191 -0
- lpgcast-0.1.1/test/data/episodes.jsonl +3 -0
- lpgcast-0.1.1/test/data/manifest.yaml +14 -0
- lpgcast-0.1.1/test/data/plant.yaml +68 -0
- lpgcast-0.1.1/test/data/schema.yaml +41 -0
- lpgcast-0.1.1/test/test_bench.py +303 -0
- lpgcast-0.1.1/test/test_cache.py +66 -0
- lpgcast-0.1.1/test/test_cast.py +251 -0
- lpgcast-0.1.1/test/test_cli.py +150 -0
- lpgcast-0.1.1/test/test_client.py +251 -0
- lpgcast-0.1.1/test/test_config.py +40 -0
- lpgcast-0.1.1/test/test_dependency_weight.py +85 -0
- lpgcast-0.1.1/test/test_episode.py +37 -0
- lpgcast-0.1.1/test/test_examples.py +18 -0
- lpgcast-0.1.1/test/test_extract.py +140 -0
- lpgcast-0.1.1/test/test_ground.py +39 -0
- lpgcast-0.1.1/test/test_jsonparse.py +71 -0
- lpgcast-0.1.1/test/test_prompt.py +81 -0
- lpgcast-0.1.1/test/test_repair.py +57 -0
- lpgcast-0.1.1/test/test_resolve.py +160 -0
- lpgcast-0.1.1/test/test_select.py +198 -0
- lpgcast-0.1.1/test/test_validate.py +238 -0
- lpgcast-0.1.1/test/test_write.py +181 -0
- lpgcast-0.1.1/uv.lock +2959 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Build GitHub Pages
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
paths:
|
|
7
|
+
- 'docs/**'
|
|
8
|
+
- 'properdocs.yml'
|
|
9
|
+
- 'pyproject.toml'
|
|
10
|
+
- 'uv.lock'
|
|
11
|
+
- 'lpgcast/**'
|
|
12
|
+
# A pull request builds the site strictly but does not deploy it.
|
|
13
|
+
pull_request:
|
|
14
|
+
paths:
|
|
15
|
+
- 'docs/**'
|
|
16
|
+
- 'properdocs.yml'
|
|
17
|
+
- 'pyproject.toml'
|
|
18
|
+
- 'uv.lock'
|
|
19
|
+
- 'lpgcast/**'
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
# One deployment at a time; a newer push queues instead of cancelling one in flight.
|
|
26
|
+
# Each pull request builds in its own group.
|
|
27
|
+
concurrency:
|
|
28
|
+
group: pages-${{ github.event_name == 'pull_request' && github.ref || 'deploy' }}
|
|
29
|
+
cancel-in-progress: false
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
build:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- name: Checkout code
|
|
36
|
+
uses: actions/checkout@v7
|
|
37
|
+
- name: Install uv
|
|
38
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
39
|
+
with:
|
|
40
|
+
version: "0.12.21"
|
|
41
|
+
enable-cache: true
|
|
42
|
+
- name: Install dependencies
|
|
43
|
+
run: uv sync --no-sources --group docs
|
|
44
|
+
- name: Build site
|
|
45
|
+
run: uv run --no-sources properdocs build --strict --site-dir _site
|
|
46
|
+
- name: Upload Pages artifact
|
|
47
|
+
if: github.event_name != 'pull_request'
|
|
48
|
+
uses: actions/upload-pages-artifact@v5
|
|
49
|
+
with:
|
|
50
|
+
path: _site
|
|
51
|
+
|
|
52
|
+
deploy:
|
|
53
|
+
needs: build
|
|
54
|
+
if: github.event_name != 'pull_request'
|
|
55
|
+
permissions:
|
|
56
|
+
pages: write
|
|
57
|
+
id-token: write
|
|
58
|
+
environment:
|
|
59
|
+
name: github-pages
|
|
60
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- name: Deploy to GitHub Pages
|
|
64
|
+
id: deployment
|
|
65
|
+
uses: actions/deploy-pages@v5
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: pre-commit
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
pre-commit:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
22
|
+
with:
|
|
23
|
+
version: "0.12.21"
|
|
24
|
+
enable-cache: true
|
|
25
|
+
# Hook environments live in ~/.cache/pre-commit, outside uv's cache;
|
|
26
|
+
# keyed on the config so a pin change rebuilds and nothing else does.
|
|
27
|
+
- name: Cache hook environments
|
|
28
|
+
uses: actions/cache@v6
|
|
29
|
+
with:
|
|
30
|
+
path: ~/.cache/pre-commit
|
|
31
|
+
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}
|
|
32
|
+
# Lint and formatting only; type checking runs in tests.yml, where the
|
|
33
|
+
# whole program is installed.
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --no-sources --group dev --no-install-project
|
|
36
|
+
- name: Run pre-commit
|
|
37
|
+
run: uv run --no-sources pre-commit run --all-files
|
|
38
|
+
env:
|
|
39
|
+
SKIP: ty
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Upload Python Package to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
pypi-publish:
|
|
12
|
+
# Off until the `lpgcast` name is reserved on PyPI: set the repository
|
|
13
|
+
# variable PYPI_PUBLISH to `true` to turn publishing on.
|
|
14
|
+
if: vars.PYPI_PUBLISH == 'true'
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
environment:
|
|
17
|
+
name: pypi
|
|
18
|
+
url: https://pypi.org/p/lpgcast
|
|
19
|
+
permissions:
|
|
20
|
+
id-token: write
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
27
|
+
with:
|
|
28
|
+
version: "0.12.21"
|
|
29
|
+
# A release whose tag differs from the project version fails instead
|
|
30
|
+
# of publishing a version nobody tagged.
|
|
31
|
+
- name: Verify tag matches pyproject version
|
|
32
|
+
run: |
|
|
33
|
+
project_version="$(uv version --short)"
|
|
34
|
+
tag_version="${GITHUB_REF_NAME#v}"
|
|
35
|
+
echo "pyproject: ${project_version} / tag: ${tag_version}"
|
|
36
|
+
if [ "${project_version}" != "${tag_version}" ]; then
|
|
37
|
+
echo "::error::Release tag ${GITHUB_REF_NAME} does not match pyproject version ${project_version}"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
- name: Build and publish
|
|
41
|
+
run: |
|
|
42
|
+
uv build --no-sources
|
|
43
|
+
uv publish
|
|
44
|
+
env:
|
|
45
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
# Development uses graflo from a sibling checkout (`tool.uv.sources`); CI has
|
|
16
|
+
# none, so every sync passes `--no-sources` and resolves graflo from PyPI.
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
# Guards the packaged artifact: a plain install must import and stay light.
|
|
20
|
+
import-smoke:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
26
|
+
with:
|
|
27
|
+
version: "0.12.21"
|
|
28
|
+
- name: Build wheel
|
|
29
|
+
run: uv build --wheel --no-sources --out-dir dist
|
|
30
|
+
- name: Install the wheel
|
|
31
|
+
run: |
|
|
32
|
+
uv venv --python 3.12 /tmp/base-install
|
|
33
|
+
VIRTUAL_ENV=/tmp/base-install uv pip install dist/*.whl
|
|
34
|
+
- name: Import the documented entry points, loading nothing heavy
|
|
35
|
+
run: |
|
|
36
|
+
/tmp/base-install/bin/python -c "
|
|
37
|
+
import sys
|
|
38
|
+
from lpgcast import LPGCaster, load_schema, read_episodes, write_cast
|
|
39
|
+
forbidden = ['langchain', 'langgraph', 'torch', 'numpy', 'pandas', 'rdflib']
|
|
40
|
+
leaked = [name for name in forbidden if name in sys.modules]
|
|
41
|
+
assert not leaked, f'imported on a plain install: {leaked}'
|
|
42
|
+
print('import OK')
|
|
43
|
+
"
|
|
44
|
+
- name: Console scripts resolve
|
|
45
|
+
run: |
|
|
46
|
+
/tmp/base-install/bin/lpgcast --help
|
|
47
|
+
/tmp/base-install/bin/lpgcast-bench --help
|
|
48
|
+
/tmp/base-install/bin/lpgcast sheet --schema examples/tickets/schema.yaml > /dev/null
|
|
49
|
+
|
|
50
|
+
unit:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
strategy:
|
|
53
|
+
fail-fast: false
|
|
54
|
+
matrix:
|
|
55
|
+
# PRs and non-main pushes: 3.12 only. Pushes to main also run 3.11 and 3.13.
|
|
56
|
+
python-version: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && fromJSON('["3.11", "3.12", "3.13"]') || fromJSON('["3.12"]') }}
|
|
57
|
+
env:
|
|
58
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v7
|
|
61
|
+
- name: Install uv
|
|
62
|
+
uses: astral-sh/setup-uv@v10.2.0
|
|
63
|
+
with:
|
|
64
|
+
version: "0.12.21"
|
|
65
|
+
enable-cache: true
|
|
66
|
+
- name: Install dependencies
|
|
67
|
+
run: uv sync --no-sources --group dev
|
|
68
|
+
- name: Type check
|
|
69
|
+
if: matrix.python-version == '3.12'
|
|
70
|
+
run: uv run --no-sources ty check lpgcast test
|
|
71
|
+
# No model is called: tests use a scripted endpoint, and the `llm` and
|
|
72
|
+
# `neo4j` markers are skipped without --run-llm / --run-neo4j.
|
|
73
|
+
- name: Run tests
|
|
74
|
+
run: uv run --no-sources pytest
|
|
75
|
+
env:
|
|
76
|
+
PYTHONUNBUFFERED: '1'
|
lpgcast-0.1.1/.gitignore
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# PyBuilder
|
|
73
|
+
.pybuilder/
|
|
74
|
+
target/
|
|
75
|
+
|
|
76
|
+
# Jupyter Notebook
|
|
77
|
+
.ipynb_checkpoints
|
|
78
|
+
|
|
79
|
+
# IPython
|
|
80
|
+
profile_default/
|
|
81
|
+
ipython_config.py
|
|
82
|
+
|
|
83
|
+
# pyenv
|
|
84
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
85
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
86
|
+
# .python-version
|
|
87
|
+
|
|
88
|
+
# pipenv
|
|
89
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
90
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
91
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
92
|
+
# install all needed dependencies.
|
|
93
|
+
# Pipfile.lock
|
|
94
|
+
|
|
95
|
+
# uv
|
|
96
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
97
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
98
|
+
# commonly ignored for libraries.
|
|
99
|
+
# uv.lock
|
|
100
|
+
|
|
101
|
+
# poetry
|
|
102
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
103
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
104
|
+
# commonly ignored for libraries.
|
|
105
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
106
|
+
# poetry.lock
|
|
107
|
+
# poetry.toml
|
|
108
|
+
|
|
109
|
+
# pdm
|
|
110
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
111
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
112
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
113
|
+
# pdm.lock
|
|
114
|
+
# pdm.toml
|
|
115
|
+
.pdm-python
|
|
116
|
+
.pdm-build/
|
|
117
|
+
|
|
118
|
+
# pixi
|
|
119
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
120
|
+
# pixi.lock
|
|
121
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
122
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
123
|
+
.pixi/*
|
|
124
|
+
!.pixi/config.toml
|
|
125
|
+
|
|
126
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
127
|
+
__pypackages__/
|
|
128
|
+
|
|
129
|
+
# Celery stuff
|
|
130
|
+
celerybeat-schedule*
|
|
131
|
+
celerybeat.pid
|
|
132
|
+
|
|
133
|
+
# Redis
|
|
134
|
+
*.rdb
|
|
135
|
+
*.aof
|
|
136
|
+
*.pid
|
|
137
|
+
|
|
138
|
+
# RabbitMQ
|
|
139
|
+
mnesia/
|
|
140
|
+
rabbitmq/
|
|
141
|
+
rabbitmq-data/
|
|
142
|
+
|
|
143
|
+
# ActiveMQ
|
|
144
|
+
activemq-data/
|
|
145
|
+
|
|
146
|
+
# SageMath parsed files
|
|
147
|
+
*.sage.py
|
|
148
|
+
|
|
149
|
+
# Environments
|
|
150
|
+
.env
|
|
151
|
+
.envrc
|
|
152
|
+
.venv
|
|
153
|
+
env/
|
|
154
|
+
venv/
|
|
155
|
+
ENV/
|
|
156
|
+
env.bak/
|
|
157
|
+
venv.bak/
|
|
158
|
+
|
|
159
|
+
# Spyder project settings
|
|
160
|
+
.spyderproject
|
|
161
|
+
.spyproject
|
|
162
|
+
|
|
163
|
+
# Rope project settings
|
|
164
|
+
.ropeproject
|
|
165
|
+
|
|
166
|
+
# mkdocs/Zensical documentation
|
|
167
|
+
/site
|
|
168
|
+
|
|
169
|
+
# mypy
|
|
170
|
+
.mypy_cache/
|
|
171
|
+
.dmypy.json
|
|
172
|
+
dmypy.json
|
|
173
|
+
|
|
174
|
+
# Pyre type checker
|
|
175
|
+
.pyre/
|
|
176
|
+
|
|
177
|
+
# pytype static type analyzer
|
|
178
|
+
.pytype/
|
|
179
|
+
|
|
180
|
+
# Cython debug symbols
|
|
181
|
+
cython_debug/
|
|
182
|
+
|
|
183
|
+
# PyCharm
|
|
184
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
185
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
186
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
187
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
188
|
+
# .idea/
|
|
189
|
+
|
|
190
|
+
# Abstra
|
|
191
|
+
# Abstra is an AI-powered process automation framework.
|
|
192
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
193
|
+
# Learn more at https://abstra.io/docs
|
|
194
|
+
.abstra/
|
|
195
|
+
|
|
196
|
+
# Visual Studio Code
|
|
197
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
|
198
|
+
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
199
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
|
200
|
+
# could uncomment the following to ignore the entire vscode folder
|
|
201
|
+
# .vscode/
|
|
202
|
+
# Temporary file for partial code execution
|
|
203
|
+
tempCodeRunnerFile.py
|
|
204
|
+
|
|
205
|
+
# Ruff stuff:
|
|
206
|
+
.ruff_cache/
|
|
207
|
+
|
|
208
|
+
# PyPI configuration file
|
|
209
|
+
.pypirc
|
|
210
|
+
|
|
211
|
+
# Marimo
|
|
212
|
+
marimo/_static/
|
|
213
|
+
marimo/_lsp/
|
|
214
|
+
__marimo__/
|
|
215
|
+
|
|
216
|
+
# Streamlit
|
|
217
|
+
.streamlit/secrets.toml
|
|
218
|
+
|
|
219
|
+
# Response cache written by tests run without LPGCAST_CACHE_DIR
|
|
220
|
+
.test_cache/
|
|
221
|
+
|
|
222
|
+
# Benchmark reports; results are published elsewhere, never committed
|
|
223
|
+
bench-results/
|
|
224
|
+
|
|
225
|
+
.idea/
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
# Repository hygiene and JSON formatting. Env files, fixture data and vendored
|
|
3
|
+
# font files are excluded: their bytes are kept as committed.
|
|
4
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
+
rev: v6.0.0
|
|
6
|
+
hooks:
|
|
7
|
+
- id: check-merge-conflict
|
|
8
|
+
- id: check-added-large-files
|
|
9
|
+
args: [--maxkb=2000]
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
exclude: (^|/)(\.env|data/)|^lpgcast/plot/fonts/|\.svg$
|
|
12
|
+
- id: trailing-whitespace
|
|
13
|
+
args: [--markdown-linebreak-ext=md]
|
|
14
|
+
exclude: (^|/)(\.env|data/)|^lpgcast/plot/fonts/|\.svg$
|
|
15
|
+
- id: pretty-format-json
|
|
16
|
+
args: [--autofix, --indent, '4', --no-sort-keys]
|
|
17
|
+
|
|
18
|
+
# Python linting and formatting
|
|
19
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
20
|
+
rev: v0.16.10
|
|
21
|
+
hooks:
|
|
22
|
+
- id: ruff-check
|
|
23
|
+
args: [--fix]
|
|
24
|
+
- id: ruff-format
|
|
25
|
+
|
|
26
|
+
- repo: local
|
|
27
|
+
hooks:
|
|
28
|
+
# Type checking
|
|
29
|
+
- id: ty
|
|
30
|
+
name: ty check
|
|
31
|
+
entry: uv run --frozen ty check lpgcast test
|
|
32
|
+
language: system
|
|
33
|
+
types: [python]
|
|
34
|
+
pass_filenames: false
|
|
35
|
+
|
|
36
|
+
# Package docs must not point outside this repository
|
|
37
|
+
- id: no-external-doc-paths
|
|
38
|
+
name: no external doc paths
|
|
39
|
+
language: pygrep
|
|
40
|
+
entry: '(?i)docs/(design|reports|ISSUES|ROADMAP|PLANNING)|benchmarking/|papers/|platform-demos/|\bworkspace\b'
|
|
41
|
+
files: \.md$
|
|
42
|
+
|
|
43
|
+
# YAML formatting
|
|
44
|
+
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
|
|
45
|
+
rev: v2.16.0
|
|
46
|
+
hooks:
|
|
47
|
+
- id: pretty-format-yaml
|
|
48
|
+
args: [--autofix, --indent, '4', --preserve-quotes]
|
|
49
|
+
|
|
50
|
+
# TOML formatting and sorting. One tool only: pretty-format-toml is built on the
|
|
51
|
+
# toml-sort library, and its hook environment pins whatever toml-sort was current
|
|
52
|
+
# when it was installed. Once that differs from the rev below, the two rewrite
|
|
53
|
+
# inline tables back and forth ({a = 1} vs { a = 1 }) on every run.
|
|
54
|
+
- repo: https://github.com/pappasam/toml-sort
|
|
55
|
+
rev: v0.25.0
|
|
56
|
+
hooks:
|
|
57
|
+
- id: toml-sort
|
|
58
|
+
args: [-ia]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.1] - 2026-10-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Package skeleton**: `lpgcast` on Python ≥ 3.11 with six runtime dependencies (`graflo`, `openai`,
|
|
13
|
+
`pydantic`, `pydantic-settings`, `click`, `pyyaml`).
|
|
14
|
+
- **Settings** from `LPGCAST_LLM_*`, `LPGCAST_CACHE_*` and `LPGCAST_*` variables only; no `.env` file
|
|
15
|
+
is read. The default model is `gpt-5.6-luna`.
|
|
16
|
+
- **`LLMClient.acomplete_json`**: one JSON object per request from any OpenAI-compatible endpoint;
|
|
17
|
+
strict `json_schema` output with a `json_object` fallback, tolerant parsing, re-ask on malformed
|
|
18
|
+
JSON, one re-issue on timeout, typed configuration errors.
|
|
19
|
+
- **Response cache** keyed on the logical request, written atomically; read-only mode and
|
|
20
|
+
`LPGCAST_CACHE_REQUIRE_HIT` for replays that make no request. Without an API key only cached
|
|
21
|
+
responses are served.
|
|
22
|
+
- **Usage accounting**: calls, failures and tokens, with billed tokens kept apart from tokens
|
|
23
|
+
replayed from the cache; `track_usage()` scopes it per task.
|
|
24
|
+
- **CLI** `lpgcast` (alias `text2lpg`) with `sheet`: the type sheet, or with `--json-schema` the
|
|
25
|
+
reply schema, for a schema or manifest file.
|
|
26
|
+
- **Episodes** (`Episode`, `read_episodes`): text, source id, reference time, metadata (never shown
|
|
27
|
+
to the model) and thread context, from JSON Lines.
|
|
28
|
+
- **Schema selection** (`select`): exact-form, phrase and number-unit lanes fused by rank, a relative
|
|
29
|
+
relevance gate, and closure by graflo's `subschema()` under a budget; a schema under budget passes
|
|
30
|
+
whole, and a large schema nothing matches is a `SelectionError` with a reason.
|
|
31
|
+
- **Extraction prompt** (`build_messages`): byte-deterministic, type sheet and rules first, the text
|
|
32
|
+
inside a tagged block it cannot close.
|
|
33
|
+
- **`extract`**: one call per episode in the flat reply format, parsed into wire models; an episode
|
|
34
|
+
over `LPGCAST_MAX_EPISODE_TOKENS` is refused before any call.
|
|
35
|
+
- **CLI** `lpgcast select`: the slice each text would be cast against, as JSON lines or type sheets.
|
|
36
|
+
- **Validation** (`validate`): unknown types and relations, properties not declared on their type,
|
|
37
|
+
values that do not coerce to their field type, insufficient identities, dangling refs and quotes
|
|
38
|
+
not found in the text are findings; values are coerced (declared units stripped), reversed edges
|
|
39
|
+
flipped and quotes matched ignoring case, accents and whitespace, each recorded as a fix.
|
|
40
|
+
- **Typed repair**: at most two follow-up requests listing the findings by kind; the attempt that
|
|
41
|
+
keeps the most items wins.
|
|
42
|
+
- **Quarantine sink** (`JsonlQuarantineSink`): left-out items, failed episodes and `unmapped`
|
|
43
|
+
entries, with the raw reply.
|
|
44
|
+
- **Identity resolution and assembly** (`resolve`): natural keys, digests for hash and funnel types,
|
|
45
|
+
UUIDs derived from schema, episode, type and ref for assigned and blank types; mentions are never
|
|
46
|
+
written as vertices, and an edge to a mention known only by a secondary identity waits for a lookup.
|
|
47
|
+
- **Groundings**: one per vertex, edge and property, with character offsets found from the quote.
|
|
48
|
+
- **`LPGCaster`**: the whole pipeline over many episodes, concurrently; a misconfigured model or a
|
|
49
|
+
cache miss under replay stops the run.
|
|
50
|
+
- **`write_cast`**: defines the schema on the target (reusing an existing one), looks up
|
|
51
|
+
secondary-identity mentions and upserts through graflo's writer.
|
|
52
|
+
- **CLI** `lpgcast cast`: graph, groundings, quarantine, episode results and a run manifest under
|
|
53
|
+
`--out`; `--db` writes to a graflo connection; `--replay` makes no request.
|
|
54
|
+
- **`LPGCaster.cast_episode`** returns an `EpisodeOutcome` that also carries the slice, the
|
|
55
|
+
first reply as checked and the attempt kept.
|
|
56
|
+
- **Benchmark** `lpgcast-bench`: a versioned corpus of seven families in four domains with a
|
|
57
|
+
dev/test split and a pinned digest; exact scoring with no model as judge; an oracle row; a
|
|
58
|
+
fresh-call re-cast; JSON and Markdown reports with token counts and optional prices.
|
|
59
|
+
- **Top-level API**: `from lpgcast import LPGCaster, load_schema, read_episodes, write_cast, ...`;
|
|
60
|
+
names load on first use, so `import lpgcast` stays light.
|
|
61
|
+
- **Documentation site**: installation, quick start, how a cast works, identities and mentions,
|
|
62
|
+
groundings and quarantine, guides to schemas, replay, databases and the benchmark, and a
|
|
63
|
+
reference whose settings, command-line and Python pages are generated from the code.
|
|
64
|
+
- **Examples**: `examples/tickets/` (a support-desk schema and five texts) and
|
|
65
|
+
`examples/connections/` (file backend and Neo4j).
|
|
66
|
+
- **CI**: tests (with a check that a plain install imports and stays light), pre-commit, docs to
|
|
67
|
+
GitHub Pages, and PyPI publishing on release once enabled.
|