model-dispatcher 0.3.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.
- model_dispatcher-0.3.0/.dockerignore +13 -0
- model_dispatcher-0.3.0/.github/workflows/ci.yml +275 -0
- model_dispatcher-0.3.0/.github/workflows/release.yml +221 -0
- model_dispatcher-0.3.0/.gitignore +218 -0
- model_dispatcher-0.3.0/ARCHITECTURE.md +457 -0
- model_dispatcher-0.3.0/Dockerfile +36 -0
- model_dispatcher-0.3.0/LICENSE +21 -0
- model_dispatcher-0.3.0/PKG-INFO +169 -0
- model_dispatcher-0.3.0/README.md +120 -0
- model_dispatcher-0.3.0/clients/browser-agent/.gitignore +3 -0
- model_dispatcher-0.3.0/clients/browser-agent/README.md +98 -0
- model_dispatcher-0.3.0/clients/browser-agent/package-lock.json +1455 -0
- model_dispatcher-0.3.0/clients/browser-agent/package.json +43 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/agent.ts +88 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/config.ts +96 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/externalChat.ts +115 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/http.ts +100 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/index.ts +36 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/messages.ts +61 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/providers/anthropic.ts +86 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/providers/gemini.ts +95 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/providers/ollama.ts +81 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/providers/openaiCompatible.ts +89 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/registry.ts +60 -0
- model_dispatcher-0.3.0/clients/browser-agent/src/types.ts +79 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/agent.test.ts +92 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/config.test.ts +75 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/externalChat.test.ts +103 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/http.test.ts +140 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/messages.test.ts +64 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/providers/anthropic.test.ts +58 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/providers/gemini.test.ts +70 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/providers/ollama.test.ts +59 -0
- model_dispatcher-0.3.0/clients/browser-agent/tests/providers/openaiCompatible.test.ts +68 -0
- model_dispatcher-0.3.0/clients/browser-agent/tsconfig.build.json +9 -0
- model_dispatcher-0.3.0/clients/browser-agent/tsconfig.json +18 -0
- model_dispatcher-0.3.0/clients/typescript/.gitignore +3 -0
- model_dispatcher-0.3.0/clients/typescript/package-lock.json +1505 -0
- model_dispatcher-0.3.0/clients/typescript/package.json +55 -0
- model_dispatcher-0.3.0/clients/typescript/src/client.ts +148 -0
- model_dispatcher-0.3.0/clients/typescript/src/events.ts +77 -0
- model_dispatcher-0.3.0/clients/typescript/src/index.ts +56 -0
- model_dispatcher-0.3.0/clients/typescript/src/interceptors/appcheck.ts +33 -0
- model_dispatcher-0.3.0/clients/typescript/src/interceptors/auth.ts +34 -0
- model_dispatcher-0.3.0/clients/typescript/src/interceptors/handoff.ts +91 -0
- model_dispatcher-0.3.0/clients/typescript/src/interceptors/interceptor.ts +53 -0
- model_dispatcher-0.3.0/clients/typescript/src/interceptors/retry.ts +92 -0
- model_dispatcher-0.3.0/clients/typescript/src/interceptors/timeout.ts +48 -0
- model_dispatcher-0.3.0/clients/typescript/src/react/useGateway.ts +67 -0
- model_dispatcher-0.3.0/clients/typescript/src/types.ts +112 -0
- model_dispatcher-0.3.0/clients/typescript/tests/client.test.ts +204 -0
- model_dispatcher-0.3.0/clients/typescript/tests/units.test.ts +79 -0
- model_dispatcher-0.3.0/clients/typescript/tsconfig.build.json +9 -0
- model_dispatcher-0.3.0/clients/typescript/tsconfig.json +19 -0
- model_dispatcher-0.3.0/demo/README.md +55 -0
- model_dispatcher-0.3.0/demo/backend/app.py +190 -0
- model_dispatcher-0.3.0/demo/backend/requirements.txt +5 -0
- model_dispatcher-0.3.0/demo/frontend/.gitignore +5 -0
- model_dispatcher-0.3.0/demo/frontend/index.html +12 -0
- model_dispatcher-0.3.0/demo/frontend/package-lock.json +1732 -0
- model_dispatcher-0.3.0/demo/frontend/package.json +22 -0
- model_dispatcher-0.3.0/demo/frontend/src/App.tsx +203 -0
- model_dispatcher-0.3.0/demo/frontend/src/api.ts +75 -0
- model_dispatcher-0.3.0/demo/frontend/src/main.tsx +10 -0
- model_dispatcher-0.3.0/demo/frontend/src/styles.css +307 -0
- model_dispatcher-0.3.0/demo/frontend/tsconfig.json +20 -0
- model_dispatcher-0.3.0/demo/frontend/vite.config.ts +18 -0
- model_dispatcher-0.3.0/docs/USAGE.md +183 -0
- model_dispatcher-0.3.0/docs/hld/hld.md +424 -0
- model_dispatcher-0.3.0/docs/lld/lld.md +888 -0
- model_dispatcher-0.3.0/examples/basic_agent.py +120 -0
- model_dispatcher-0.3.0/pyproject.toml +85 -0
- model_dispatcher-0.3.0/src/model_dispatcher/__init__.py +107 -0
- model_dispatcher-0.3.0/src/model_dispatcher/_async_bridge.py +50 -0
- model_dispatcher-0.3.0/src/model_dispatcher/config.py +99 -0
- model_dispatcher-0.3.0/src/model_dispatcher/exceptions.py +134 -0
- model_dispatcher-0.3.0/src/model_dispatcher/fallback/__init__.py +35 -0
- model_dispatcher-0.3.0/src/model_dispatcher/fallback/chain.py +112 -0
- model_dispatcher-0.3.0/src/model_dispatcher/fallback/conditions.py +44 -0
- model_dispatcher-0.3.0/src/model_dispatcher/fallback/handlers.py +549 -0
- model_dispatcher-0.3.0/src/model_dispatcher/gateway.py +181 -0
- model_dispatcher-0.3.0/src/model_dispatcher/observability/__init__.py +8 -0
- model_dispatcher-0.3.0/src/model_dispatcher/observability/logging.py +28 -0
- model_dispatcher-0.3.0/src/model_dispatcher/observability/metrics.py +35 -0
- model_dispatcher-0.3.0/src/model_dispatcher/onboarding/__init__.py +14 -0
- model_dispatcher-0.3.0/src/model_dispatcher/onboarding/flow.py +69 -0
- model_dispatcher-0.3.0/src/model_dispatcher/onboarding/handoff.py +96 -0
- model_dispatcher-0.3.0/src/model_dispatcher/orchestration/__init__.py +19 -0
- model_dispatcher-0.3.0/src/model_dispatcher/orchestration/loop.py +203 -0
- model_dispatcher-0.3.0/src/model_dispatcher/orchestration/result.py +54 -0
- model_dispatcher-0.3.0/src/model_dispatcher/orchestration/state.py +60 -0
- model_dispatcher-0.3.0/src/model_dispatcher/orchestration/tools.py +110 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/__init__.py +33 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/anthropic_provider.py +216 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/base.py +102 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/gemini_provider.py +245 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/mock_provider.py +127 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/openai_compatible.py +117 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/openai_provider.py +218 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/registry.py +77 -0
- model_dispatcher-0.3.0/src/model_dispatcher/providers/retry_hints.py +79 -0
- model_dispatcher-0.3.0/src/model_dispatcher/py.typed +0 -0
- model_dispatcher-0.3.0/src/model_dispatcher/quota/__init__.py +19 -0
- model_dispatcher-0.3.0/src/model_dispatcher/quota/manager.py +139 -0
- model_dispatcher-0.3.0/src/model_dispatcher/quota/store.py +96 -0
- model_dispatcher-0.3.0/src/model_dispatcher/quota/tenant.py +63 -0
- model_dispatcher-0.3.0/src/model_dispatcher/quota/tokenizer.py +58 -0
- model_dispatcher-0.3.0/src/model_dispatcher/routing/__init__.py +8 -0
- model_dispatcher-0.3.0/src/model_dispatcher/routing/router.py +65 -0
- model_dispatcher-0.3.0/src/model_dispatcher/routing/triage.py +90 -0
- model_dispatcher-0.3.0/src/model_dispatcher/security/__init__.py +15 -0
- model_dispatcher-0.3.0/src/model_dispatcher/security/credentials.py +179 -0
- model_dispatcher-0.3.0/src/model_dispatcher/security/perimeter.py +80 -0
- model_dispatcher-0.3.0/src/model_dispatcher/security/redaction.py +62 -0
- model_dispatcher-0.3.0/src/model_dispatcher/types.py +229 -0
- model_dispatcher-0.3.0/templates/vercel-app/.env.example +37 -0
- model_dispatcher-0.3.0/templates/vercel-app/.gitignore +9 -0
- model_dispatcher-0.3.0/templates/vercel-app/FIREBASE_APPCHECK_SETUP.md +159 -0
- model_dispatcher-0.3.0/templates/vercel-app/README.md +141 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/__init__.py +6 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/appcheck.py +128 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/auth.py +148 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/firebase_app.py +66 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/http.py +85 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/pipeline.py +102 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/_lib/wiring.py +164 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/gateway.py +56 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/requirements.txt +13 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/tests/conftest.py +14 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/tests/test_auth.py +85 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/tests/test_firebase_app.py +42 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/tests/test_pipeline.py +193 -0
- model_dispatcher-0.3.0/templates/vercel-app/api/tests/test_wiring.py +52 -0
- model_dispatcher-0.3.0/templates/vercel-app/app/components/KeyWizard.tsx +58 -0
- model_dispatcher-0.3.0/templates/vercel-app/app/globals.css +107 -0
- model_dispatcher-0.3.0/templates/vercel-app/app/layout.tsx +22 -0
- model_dispatcher-0.3.0/templates/vercel-app/app/lib/gateway.ts +124 -0
- model_dispatcher-0.3.0/templates/vercel-app/app/page.tsx +82 -0
- model_dispatcher-0.3.0/templates/vercel-app/package.json +25 -0
- model_dispatcher-0.3.0/templates/vercel-app/tsconfig.json +20 -0
- model_dispatcher-0.3.0/templates/vercel-app/vercel.json +8 -0
- model_dispatcher-0.3.0/tests/conftest.py +78 -0
- model_dispatcher-0.3.0/tests/test_agent_loop.py +106 -0
- model_dispatcher-0.3.0/tests/test_fallback_chain.py +323 -0
- model_dispatcher-0.3.0/tests/test_gateway_facade.py +86 -0
- model_dispatcher-0.3.0/tests/test_onboarding_handoff.py +96 -0
- model_dispatcher-0.3.0/tests/test_providers_adapters.py +291 -0
- model_dispatcher-0.3.0/tests/test_quota_manager.py +69 -0
- model_dispatcher-0.3.0/tests/test_retry_hints.py +58 -0
- model_dispatcher-0.3.0/tests/test_router_triage.py +70 -0
- model_dispatcher-0.3.0/tests/test_security_redaction.py +102 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
python:
|
|
14
|
+
name: Lint, type-check & test (py${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Install package with dev extras
|
|
29
|
+
run: pip install -e ".[dev]"
|
|
30
|
+
|
|
31
|
+
- name: Ruff lint
|
|
32
|
+
run: ruff check src tests examples
|
|
33
|
+
|
|
34
|
+
- name: Ruff format check
|
|
35
|
+
run: ruff format --check src tests examples
|
|
36
|
+
|
|
37
|
+
- name: mypy (strict)
|
|
38
|
+
run: mypy --strict src examples
|
|
39
|
+
|
|
40
|
+
- name: pytest
|
|
41
|
+
run: pytest
|
|
42
|
+
|
|
43
|
+
- name: Run the basic_agent example (smoke test)
|
|
44
|
+
run: python examples/basic_agent.py
|
|
45
|
+
|
|
46
|
+
frontend:
|
|
47
|
+
name: Build React SPA
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
|
|
52
|
+
- name: Set up Node
|
|
53
|
+
uses: actions/setup-node@v4
|
|
54
|
+
with:
|
|
55
|
+
node-version: "22"
|
|
56
|
+
cache: npm
|
|
57
|
+
cache-dependency-path: demo/frontend/package-lock.json
|
|
58
|
+
|
|
59
|
+
- name: Install dependencies
|
|
60
|
+
working-directory: demo/frontend
|
|
61
|
+
run: npm ci
|
|
62
|
+
|
|
63
|
+
- name: Build
|
|
64
|
+
working-directory: demo/frontend
|
|
65
|
+
run: npm run build
|
|
66
|
+
|
|
67
|
+
ts_client:
|
|
68
|
+
name: TS client — type-check, test & build
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v4
|
|
72
|
+
|
|
73
|
+
- name: Set up Node
|
|
74
|
+
uses: actions/setup-node@v4
|
|
75
|
+
with:
|
|
76
|
+
node-version: "22"
|
|
77
|
+
cache: npm
|
|
78
|
+
cache-dependency-path: clients/typescript/package-lock.json
|
|
79
|
+
|
|
80
|
+
- name: Install dependencies
|
|
81
|
+
working-directory: clients/typescript
|
|
82
|
+
run: npm ci
|
|
83
|
+
|
|
84
|
+
- name: Type-check
|
|
85
|
+
working-directory: clients/typescript
|
|
86
|
+
run: npm run typecheck
|
|
87
|
+
|
|
88
|
+
- name: Test
|
|
89
|
+
working-directory: clients/typescript
|
|
90
|
+
run: npm test
|
|
91
|
+
|
|
92
|
+
- name: Build
|
|
93
|
+
working-directory: clients/typescript
|
|
94
|
+
run: npm run build
|
|
95
|
+
|
|
96
|
+
browser_agent:
|
|
97
|
+
name: Browser agent — type-check, test & build
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
|
|
102
|
+
- name: Set up Node
|
|
103
|
+
uses: actions/setup-node@v4
|
|
104
|
+
with:
|
|
105
|
+
node-version: "22"
|
|
106
|
+
cache: npm
|
|
107
|
+
cache-dependency-path: clients/browser-agent/package-lock.json
|
|
108
|
+
|
|
109
|
+
- name: Install dependencies
|
|
110
|
+
working-directory: clients/browser-agent
|
|
111
|
+
run: npm ci
|
|
112
|
+
|
|
113
|
+
- name: Type-check
|
|
114
|
+
working-directory: clients/browser-agent
|
|
115
|
+
run: npm run typecheck
|
|
116
|
+
|
|
117
|
+
- name: Test
|
|
118
|
+
working-directory: clients/browser-agent
|
|
119
|
+
run: npm test
|
|
120
|
+
|
|
121
|
+
- name: Build
|
|
122
|
+
working-directory: clients/browser-agent
|
|
123
|
+
run: npm run build
|
|
124
|
+
|
|
125
|
+
vercel_template_frontend:
|
|
126
|
+
name: Vercel template — build Next.js frontend
|
|
127
|
+
runs-on: ubuntu-latest
|
|
128
|
+
steps:
|
|
129
|
+
- uses: actions/checkout@v4
|
|
130
|
+
|
|
131
|
+
- name: Set up Node
|
|
132
|
+
uses: actions/setup-node@v4
|
|
133
|
+
with:
|
|
134
|
+
node-version: "22"
|
|
135
|
+
cache: npm
|
|
136
|
+
cache-dependency-path: clients/typescript/package-lock.json
|
|
137
|
+
|
|
138
|
+
- name: Build the TS client
|
|
139
|
+
working-directory: clients/typescript
|
|
140
|
+
run: |
|
|
141
|
+
npm ci
|
|
142
|
+
npm run build
|
|
143
|
+
|
|
144
|
+
- name: Point the template at the workspace TS client
|
|
145
|
+
# @joka-7/modeldispatcher-client is only published on a tagged release
|
|
146
|
+
# (see release.yml) and may not exist yet or may lag this commit.
|
|
147
|
+
# Building against the workspace copy means this check is self-contained
|
|
148
|
+
# and always exercises the client code actually changed in this PR —
|
|
149
|
+
# not a possibly-stale published version.
|
|
150
|
+
working-directory: templates/vercel-app
|
|
151
|
+
run: |
|
|
152
|
+
node -e "
|
|
153
|
+
const fs = require('fs');
|
|
154
|
+
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
155
|
+
p.dependencies['@joka-7/modeldispatcher-client'] = 'file:../../clients/typescript';
|
|
156
|
+
fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
|
|
157
|
+
"
|
|
158
|
+
|
|
159
|
+
- name: Install template dependencies
|
|
160
|
+
# npm install, not ci: the file: dependency swap above intentionally
|
|
161
|
+
# diverges from package-lock.json.
|
|
162
|
+
working-directory: templates/vercel-app
|
|
163
|
+
run: npm install
|
|
164
|
+
|
|
165
|
+
- name: Type-check
|
|
166
|
+
working-directory: templates/vercel-app
|
|
167
|
+
run: npm run typecheck
|
|
168
|
+
|
|
169
|
+
- name: Build (next build)
|
|
170
|
+
# A real build with zero Firebase env vars set — this is what catches
|
|
171
|
+
# both a missing/broken app/lib/gateway.ts and any Firebase call that
|
|
172
|
+
# isn't properly deferred to runtime (see that file's module doc).
|
|
173
|
+
working-directory: templates/vercel-app
|
|
174
|
+
run: npm run build
|
|
175
|
+
env:
|
|
176
|
+
NEXT_TELEMETRY_DISABLED: "1"
|
|
177
|
+
|
|
178
|
+
vercel_template:
|
|
179
|
+
name: Vercel template — lint & test wrapper (py${{ matrix.python-version }})
|
|
180
|
+
runs-on: ubuntu-latest
|
|
181
|
+
strategy:
|
|
182
|
+
fail-fast: false
|
|
183
|
+
matrix:
|
|
184
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
185
|
+
steps:
|
|
186
|
+
- uses: actions/checkout@v4
|
|
187
|
+
|
|
188
|
+
- name: Set up Python
|
|
189
|
+
uses: actions/setup-python@v5
|
|
190
|
+
with:
|
|
191
|
+
python-version: ${{ matrix.python-version }}
|
|
192
|
+
|
|
193
|
+
- name: Install gateway (dev extras) + wrapper dependencies
|
|
194
|
+
run: |
|
|
195
|
+
pip install -e ".[dev]"
|
|
196
|
+
pip install firebase-admin
|
|
197
|
+
|
|
198
|
+
- name: Ruff lint
|
|
199
|
+
run: ruff check templates
|
|
200
|
+
|
|
201
|
+
- name: Ruff format check
|
|
202
|
+
run: ruff format --check templates
|
|
203
|
+
|
|
204
|
+
- name: mypy (lenient — firebase-admin ships no type stubs)
|
|
205
|
+
env:
|
|
206
|
+
MYPYPATH: templates/vercel-app/api
|
|
207
|
+
run: >
|
|
208
|
+
mypy --config-file= --ignore-missing-imports
|
|
209
|
+
templates/vercel-app/api/gateway.py
|
|
210
|
+
templates/vercel-app/api/_lib
|
|
211
|
+
|
|
212
|
+
- name: pytest (dispatch pipeline)
|
|
213
|
+
run: pytest templates/vercel-app/api/tests
|
|
214
|
+
|
|
215
|
+
docker:
|
|
216
|
+
name: Build & publish demo image
|
|
217
|
+
runs-on: ubuntu-latest
|
|
218
|
+
needs: [python, frontend]
|
|
219
|
+
permissions:
|
|
220
|
+
contents: read
|
|
221
|
+
packages: write
|
|
222
|
+
steps:
|
|
223
|
+
- uses: actions/checkout@v4
|
|
224
|
+
|
|
225
|
+
- name: Set up Buildx
|
|
226
|
+
uses: docker/setup-buildx-action@v3
|
|
227
|
+
|
|
228
|
+
- name: Log in to GHCR
|
|
229
|
+
# Publish only from the default branch; feature branches and PRs build
|
|
230
|
+
# the image (validating the Dockerfile) without pushing.
|
|
231
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
232
|
+
uses: docker/login-action@v3
|
|
233
|
+
with:
|
|
234
|
+
registry: ghcr.io
|
|
235
|
+
username: ${{ github.actor }}
|
|
236
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
237
|
+
|
|
238
|
+
- name: Image metadata
|
|
239
|
+
id: meta
|
|
240
|
+
uses: docker/metadata-action@v5
|
|
241
|
+
with:
|
|
242
|
+
images: ghcr.io/${{ github.repository }}
|
|
243
|
+
tags: |
|
|
244
|
+
type=ref,event=branch
|
|
245
|
+
type=sha
|
|
246
|
+
type=raw,value=latest,enable={{is_default_branch}}
|
|
247
|
+
|
|
248
|
+
- name: Build (and push from the default branch)
|
|
249
|
+
uses: docker/build-push-action@v6
|
|
250
|
+
with:
|
|
251
|
+
context: .
|
|
252
|
+
push: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
|
|
253
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
254
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
255
|
+
cache-from: type=gha
|
|
256
|
+
cache-to: type=gha,mode=max
|
|
257
|
+
|
|
258
|
+
# ----------------------------------------------------------------------- #
|
|
259
|
+
# Deploy the published image to a hosting target. This is intentionally a
|
|
260
|
+
# manual, gated stub: wire it to your platform (Fly.io / Render / Cloud Run /
|
|
261
|
+
# a k8s cluster) by adding the deploy step and the platform token as a repo
|
|
262
|
+
# secret. It runs only on the default branch so feature branches don't deploy.
|
|
263
|
+
# ----------------------------------------------------------------------- #
|
|
264
|
+
deploy:
|
|
265
|
+
name: Deploy demo (configure target)
|
|
266
|
+
runs-on: ubuntu-latest
|
|
267
|
+
needs: docker
|
|
268
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
269
|
+
environment: demo
|
|
270
|
+
steps:
|
|
271
|
+
- name: Pending deploy target
|
|
272
|
+
run: |
|
|
273
|
+
echo "Image published to ghcr.io/${{ github.repository }}:latest"
|
|
274
|
+
echo "Add your host's deploy step here (e.g. flyctl deploy / render deploy"
|
|
275
|
+
echo "/ gcloud run deploy) plus its token as a repository secret."
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Triggered by pushing a version tag (e.g. `v0.2.0`). This publishes
|
|
4
|
+
# model-dispatcher to PyPI and the matching @joka-7/modeldispatcher-client
|
|
5
|
+
# build to GitHub Packages, and is what makes the git-pinned installs in
|
|
6
|
+
# templates/vercel-app/api/requirements.txt (and the README's
|
|
7
|
+
# `git+...@v0.2.0` examples) resolve to a real, published point in history.
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags:
|
|
11
|
+
- "v*.*.*"
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: release-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
verify:
|
|
19
|
+
name: Re-verify the tagged commit
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
|
|
29
|
+
- name: Install package with dev extras
|
|
30
|
+
run: |
|
|
31
|
+
pip install -e ".[dev]"
|
|
32
|
+
pip install firebase-admin
|
|
33
|
+
|
|
34
|
+
- name: Ruff lint
|
|
35
|
+
run: ruff check src tests templates
|
|
36
|
+
|
|
37
|
+
- name: Ruff format check
|
|
38
|
+
run: ruff format --check src tests templates
|
|
39
|
+
|
|
40
|
+
- name: mypy (strict, core library)
|
|
41
|
+
run: mypy --strict src
|
|
42
|
+
|
|
43
|
+
- name: pytest (core library + Vercel template)
|
|
44
|
+
run: pytest tests templates/vercel-app/api/tests
|
|
45
|
+
|
|
46
|
+
- name: Set up Node
|
|
47
|
+
uses: actions/setup-node@v4
|
|
48
|
+
with:
|
|
49
|
+
node-version: "22"
|
|
50
|
+
cache: npm
|
|
51
|
+
cache-dependency-path: clients/typescript/package-lock.json
|
|
52
|
+
|
|
53
|
+
- name: Install TS client dependencies
|
|
54
|
+
working-directory: clients/typescript
|
|
55
|
+
run: npm ci
|
|
56
|
+
|
|
57
|
+
- name: TS type-check
|
|
58
|
+
working-directory: clients/typescript
|
|
59
|
+
run: npm run typecheck
|
|
60
|
+
|
|
61
|
+
- name: TS test
|
|
62
|
+
working-directory: clients/typescript
|
|
63
|
+
run: npm test
|
|
64
|
+
|
|
65
|
+
- name: Set up Node (browser agent)
|
|
66
|
+
uses: actions/setup-node@v4
|
|
67
|
+
with:
|
|
68
|
+
node-version: "22"
|
|
69
|
+
cache: npm
|
|
70
|
+
cache-dependency-path: clients/browser-agent/package-lock.json
|
|
71
|
+
|
|
72
|
+
- name: Install browser-agent dependencies
|
|
73
|
+
working-directory: clients/browser-agent
|
|
74
|
+
run: npm ci
|
|
75
|
+
|
|
76
|
+
- name: Browser agent type-check
|
|
77
|
+
working-directory: clients/browser-agent
|
|
78
|
+
run: npm run typecheck
|
|
79
|
+
|
|
80
|
+
- name: Browser agent test
|
|
81
|
+
working-directory: clients/browser-agent
|
|
82
|
+
run: npm test
|
|
83
|
+
|
|
84
|
+
publish_pypi:
|
|
85
|
+
name: Publish model-dispatcher to PyPI
|
|
86
|
+
runs-on: ubuntu-latest
|
|
87
|
+
needs: verify
|
|
88
|
+
environment: pypi
|
|
89
|
+
permissions:
|
|
90
|
+
# Required for PyPI Trusted Publishing (OIDC) — no API token/secret needed.
|
|
91
|
+
# A "pending publisher" must be registered on PyPI first: Account Settings
|
|
92
|
+
# → Publishing, with owner=joka-7, repo=ModelDispatcher, workflow=release.yml.
|
|
93
|
+
# If that publisher was registered *without* an environment name, delete the
|
|
94
|
+
# `environment: pypi` line above to match.
|
|
95
|
+
id-token: write
|
|
96
|
+
contents: read
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v4
|
|
99
|
+
|
|
100
|
+
- name: Set up Python
|
|
101
|
+
uses: actions/setup-python@v5
|
|
102
|
+
with:
|
|
103
|
+
python-version: "3.12"
|
|
104
|
+
|
|
105
|
+
- name: Install build tooling
|
|
106
|
+
run: pip install build
|
|
107
|
+
|
|
108
|
+
- name: Verify pyproject.toml version matches the pushed tag
|
|
109
|
+
run: |
|
|
110
|
+
tag_version="${GITHUB_REF_NAME#v}"
|
|
111
|
+
pkg_version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
|
|
112
|
+
if [ "$tag_version" != "$pkg_version" ]; then
|
|
113
|
+
echo "::error::tag v$tag_version does not match pyproject.toml version $pkg_version"
|
|
114
|
+
exit 1
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
- name: Build sdist + wheel
|
|
118
|
+
run: python -m build
|
|
119
|
+
|
|
120
|
+
- name: Publish to PyPI
|
|
121
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
122
|
+
|
|
123
|
+
publish_ts_client:
|
|
124
|
+
name: Publish @joka-7/modeldispatcher-client
|
|
125
|
+
runs-on: ubuntu-latest
|
|
126
|
+
needs: verify
|
|
127
|
+
permissions:
|
|
128
|
+
contents: read
|
|
129
|
+
packages: write
|
|
130
|
+
steps:
|
|
131
|
+
- uses: actions/checkout@v4
|
|
132
|
+
|
|
133
|
+
- name: Set up Node
|
|
134
|
+
uses: actions/setup-node@v4
|
|
135
|
+
with:
|
|
136
|
+
node-version: "22"
|
|
137
|
+
registry-url: "https://npm.pkg.github.com"
|
|
138
|
+
scope: "@joka-7"
|
|
139
|
+
cache: npm
|
|
140
|
+
cache-dependency-path: clients/typescript/package-lock.json
|
|
141
|
+
|
|
142
|
+
- name: Install dependencies
|
|
143
|
+
working-directory: clients/typescript
|
|
144
|
+
run: npm ci
|
|
145
|
+
|
|
146
|
+
- name: Build
|
|
147
|
+
working-directory: clients/typescript
|
|
148
|
+
run: npm run build
|
|
149
|
+
|
|
150
|
+
- name: Verify package.json version matches the pushed tag
|
|
151
|
+
working-directory: clients/typescript
|
|
152
|
+
run: |
|
|
153
|
+
tag_version="${GITHUB_REF_NAME#v}"
|
|
154
|
+
pkg_version="$(node -p "require('./package.json').version")"
|
|
155
|
+
if [ "$tag_version" != "$pkg_version" ]; then
|
|
156
|
+
echo "::error::tag v$tag_version does not match package.json version $pkg_version"
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
- name: Publish to GitHub Packages
|
|
161
|
+
working-directory: clients/typescript
|
|
162
|
+
run: npm publish
|
|
163
|
+
env:
|
|
164
|
+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
165
|
+
|
|
166
|
+
publish_browser_agent:
|
|
167
|
+
name: Publish @joka-7/modeldispatcher-browser-agent
|
|
168
|
+
runs-on: ubuntu-latest
|
|
169
|
+
needs: verify
|
|
170
|
+
permissions:
|
|
171
|
+
contents: read
|
|
172
|
+
packages: write
|
|
173
|
+
steps:
|
|
174
|
+
- uses: actions/checkout@v4
|
|
175
|
+
|
|
176
|
+
- name: Set up Node
|
|
177
|
+
uses: actions/setup-node@v4
|
|
178
|
+
with:
|
|
179
|
+
node-version: "22"
|
|
180
|
+
registry-url: "https://npm.pkg.github.com"
|
|
181
|
+
scope: "@joka-7"
|
|
182
|
+
cache: npm
|
|
183
|
+
cache-dependency-path: clients/browser-agent/package-lock.json
|
|
184
|
+
|
|
185
|
+
- name: Install dependencies
|
|
186
|
+
working-directory: clients/browser-agent
|
|
187
|
+
run: npm ci
|
|
188
|
+
|
|
189
|
+
- name: Build
|
|
190
|
+
working-directory: clients/browser-agent
|
|
191
|
+
run: npm run build
|
|
192
|
+
|
|
193
|
+
- name: Verify package.json version matches the pushed tag
|
|
194
|
+
working-directory: clients/browser-agent
|
|
195
|
+
run: |
|
|
196
|
+
tag_version="${GITHUB_REF_NAME#v}"
|
|
197
|
+
pkg_version="$(node -p "require('./package.json').version")"
|
|
198
|
+
if [ "$tag_version" != "$pkg_version" ]; then
|
|
199
|
+
echo "::error::tag v$tag_version does not match package.json version $pkg_version"
|
|
200
|
+
exit 1
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
- name: Publish to GitHub Packages
|
|
204
|
+
working-directory: clients/browser-agent
|
|
205
|
+
run: npm publish
|
|
206
|
+
env:
|
|
207
|
+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
208
|
+
|
|
209
|
+
create_release:
|
|
210
|
+
name: Create GitHub Release
|
|
211
|
+
runs-on: ubuntu-latest
|
|
212
|
+
needs: [publish_pypi, publish_ts_client, publish_browser_agent]
|
|
213
|
+
permissions:
|
|
214
|
+
contents: write
|
|
215
|
+
steps:
|
|
216
|
+
- uses: actions/checkout@v4
|
|
217
|
+
|
|
218
|
+
- name: Create release with auto-generated notes
|
|
219
|
+
env:
|
|
220
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
221
|
+
run: gh release create "${{ github.ref_name }}" --generate-notes
|