Repository navigation
314 lines (313 loc) · 18 KB
/
Copy pathjavascript-sdk.yml
File metadata and controls
314 lines (313 loc) · 18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# Copyright 2026 Cellar Project Authors. Licensed under Apache-2.0.
name: JavaScript and Node SDK
on:
pull_request:
paths:
- 'crates/**'
- 'packages/cellar-sdk/**'
- 'packages/cellar-cloudflare/**'
- 'examples/javascript/**'
- 'examples/node/**'
- 'examples/streaming/**'
- 'examples/bindings/**'
- 'examples/pi-agent/**'
- 'examples/vercel-agent/**'
- 'examples/filesystem-agent/**'
- 'tools/javascript/**'
- 'tools/sandbox/**'
- 'tools/rpc/**'
- 'tools/qualification/**'
- 'tools/cellar-rpc-codegen/**'
- 'proto/**'
- 'docs/design/named-typed-rpc/*.proto'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/javascript-sdk.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
qualify:
name: JavaScript qualification (${{ matrix.profile }})
runs-on: ubuntu-22.04
# Independent runners keep builds and restart campaigns within the job
# ceiling. Each runner still executes its native fixtures serially.
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
profile: [adapters, examples, packages]
env:
CARGO_PROFILE_DEV_DEBUG: '0'
CARGO_PROFILE_TEST_DEBUG: '0'
RUST_TEST_THREADS: '1'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
- name: Rust toolchain
run: |
rustup toolchain install 1.98.1 --profile minimal --component clippy --component rustfmt
rustup default 1.98.1
- name: Locked npm build
run: |
npm ci --prefix tools/javascript --ignore-scripts
npm run --prefix tools/javascript format:check
npm ci --prefix examples/javascript --ignore-scripts
npm ci --prefix examples/node --ignore-scripts
npm ci --prefix examples/streaming --ignore-scripts
npm ci --prefix examples/bindings --ignore-scripts
npm ci --prefix examples/pi-agent --ignore-scripts
npm ci --prefix examples/vercel-agent --ignore-scripts
npm ci --prefix examples/filesystem-agent --ignore-scripts
npm ci --prefix tools/rpc --ignore-scripts
npm ci --prefix examples/vercel-agent/ui --ignore-scripts
npm run --prefix examples/node build
npm run --prefix examples/streaming build
npm run --prefix examples/bindings build
npm run --prefix examples/pi-agent build
npm test --prefix examples/pi-agent
npm run --prefix examples/vercel-agent build
npm run --prefix examples/vercel-agent/ui build
npm test --prefix examples/vercel-agent
npm run --prefix examples/vercel-agent format:check
node --test packages/cellar-sdk/test/streaming.test.mjs
node tools/javascript/node_modules/typescript/bin/tsc --noEmit --strict --target es2022 --module nodenext packages/cellar-sdk/test/types.ts packages/cellar-sdk/test/filesystem-types.ts
npm test --prefix tools/javascript
npm run --prefix examples/javascript build
npm test --prefix tools/rpc
npm run --prefix tools/rpc typecheck
npm run --prefix tools/rpc build
- name: Published sandbox compatibility input identities
if: matrix.profile == 'adapters'
run: |
node tools/sandbox/e2b/check.mjs
node --test tools/sandbox/e2b/check.test.mjs
node tools/sandbox/vercel/check.mjs
node --test tools/sandbox/vercel/check.test.mjs
python3 tools/sandbox/vercel/helper_test.py
npm ci --ignore-scripts --prefix tools/sandbox/compat
npm run inventory --prefix tools/sandbox/compat
npm test --prefix tools/sandbox/compat
node tools/sandbox/compat/build.mjs
npm ci --ignore-scripts --prefix tools/sandbox/cloudflare-v1
npm test --prefix tools/sandbox/cloudflare-v1
npm run build --prefix tools/sandbox/cloudflare-v1
- name: Chat UI desktop and mobile behavior
if: matrix.profile == 'adapters'
run: |
npm exec --prefix examples/vercel-agent/ui -- playwright install --with-deps chromium
npm run --prefix examples/vercel-agent/ui test:ui
- name: Adapter and real-node tests
if: matrix.profile == 'adapters'
env:
CELLAR_FS_JS_PROOF_REPORT_DIR: ${{ runner.temp }}/filesystem-proof-combined
CELLAR_FS_CONCURRENCY_REPORT_DIR: ${{ runner.temp }}/filesystem-concurrency-combined
# Independent native fixtures own short leases and concurrent runtimes.
run: cargo test --locked -p cellar-container -p cellar-guest -p cellar-javascript --features cellar-javascript/embed,cellar-javascript/node -- --test-threads=1
- name: Node-only feature
if: matrix.profile == 'adapters'
env:
CELLAR_FS_JS_PROOF_REPORT_DIR: ${{ runner.temp }}/filesystem-proof-node
CELLAR_FS_CONCURRENCY_REPORT_DIR: ${{ runner.temp }}/filesystem-concurrency-node
run: cargo test --locked -p cellar-javascript --no-default-features --features node -- --test-threads=1
- name: Preserve filesystem proof and shutdown ledgers
if: always() && matrix.profile == 'adapters'
uses: actions/upload-artifact@v4
with:
name: javascript-filesystem-proof-${{ github.run_id }}-${{ github.run_attempt }}
path: |
${{ runner.temp }}/filesystem-proof-combined/*.json
${{ runner.temp }}/filesystem-proof-node/*.json
${{ runner.temp }}/filesystem-concurrency-combined/*.json
${{ runner.temp }}/filesystem-concurrency-node/*.json
if-no-files-found: ignore
- name: Runtime archive and admission boundaries
if: matrix.profile == 'adapters'
run: |
cargo test --locked -p cellar --lib node_environment
cargo test --locked -p cellar --lib runtime_inventory
cargo test --locked -p cellar --lib python_environment::archive
cargo test --locked -p cellar --lib runtime_directories
cargo test --locked -p cellar --test native_artifacts
- name: Pi agent crash recovery
if: matrix.profile == 'examples'
run: |
cargo build --locked -p cellar-javascript --no-default-features --features node --bin cellar-pi-agent-example
CELLAR_PI_HOST="${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar-pi-agent-example" npm run --prefix examples/pi-agent test:e2e
- name: Vercel AI SDK agent crash recovery and concurrent tasks
if: matrix.profile == 'examples'
run: |
cargo build --locked -p cellar-javascript --no-default-features --features node --bin cellar-vercel-agent-example
CELLAR_AI_HOST="${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar-vercel-agent-example" npm run --prefix examples/vercel-agent test:e2e
CELLAR_AI_HOST="${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar-vercel-agent-example" npm run --prefix examples/vercel-agent test:tools
- name: Filesystem agent atomic tools and cold recovery
if: matrix.profile == 'examples'
run: |
cargo build --locked -p cellar-javascript --no-default-features --features node --bin cellar-filesystem-agent-example
CELLAR_FS_HOST="${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar-filesystem-agent-example" npm run --prefix examples/filesystem-agent test:e2e
- name: Vercel agent cold recovery from RustFS
if: matrix.profile == 'examples'
shell: bash
run: |
aws --version
store="cellar-ai-rustfs-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
private="$RUNNER_TEMP/cellar-ai-rustfs.env"
python3 - "$private" <<'PY'
import os, secrets, sys
with open(sys.argv[1], 'x', opener=lambda path, flags: os.open(path, flags, 0o600)) as output:
# This pinned RustFS image accepts the 20-character access-key
# profile; a 32-character key fails CreateBucket authentication.
output.write('AWS_ACCESS_KEY_ID=' + secrets.token_hex(10) + '\n')
output.write('AWS_SECRET_ACCESS_KEY=' + secrets.token_hex(32) + '\n')
PY
set -a
source "$private"
set +a
trap 'docker rm -f "$store" >/dev/null 2>&1 || true; rm -f "$private"' EXIT
docker run --detach --name "$store" --publish 127.0.0.1::9000 --cpus 2 --memory 2g \
--env "RUSTFS_ACCESS_KEY=$AWS_ACCESS_KEY_ID" \
--env "RUSTFS_SECRET_KEY=$AWS_SECRET_ACCESS_KEY" \
--env RUSTFS_CONSOLE_ENABLE=false \
ghcr.io/rustfs/rustfs@sha256:bffcab0c9d647aab0055d1c69d340b202d0909966b385932d4ead1aeb7602858 /data
export S3_ENDPOINT="http://$(docker port "$store" 9000/tcp)"
for attempt in $(seq 1 60); do
if curl --fail --silent "$S3_ENDPOINT/health" >/dev/null; then break; fi
sleep 1
done
curl --fail --silent "$S3_ENDPOINT/health" >/dev/null
export CELLAR_AI_STORE=s3 AWS_REGION=us-east-1
export CELLAR_FS_S3_BUCKET="cellar-filesystem-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
export CELLAR_FS_S3_ENDPOINT="$S3_ENDPOINT"
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api create-bucket \
--bucket "$CELLAR_FS_S3_BUCKET"
CELLAR_FS_FAULT_REPORT="$RUNNER_TEMP/filesystem-s3-proof-fault.json" \
cargo test --locked -p cellar --test native_node \
node_filesystem_faults::filesystem_s3_unproven_write_is_fenced_and_failed_recovery_refuses_admission \
-- --ignored --exact --nocapture
export CELLAR_FS_S3_BUCKET="cellar-filesystem-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-sockets"
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api create-bucket \
--bucket "$CELLAR_FS_S3_BUCKET"
CELLAR_FS_FAULT_REPORT="$RUNNER_TEMP/filesystem-s3-socket-fault.json" \
cargo test --locked -p cellar --test native_node \
node_filesystem_faults::filesystem_s3_socket_cuts_fence_unproven_writes_and_refuse_failed_recovery \
-- --ignored --exact --nocapture
export CELLAR_FS_S3_BUCKET="cellar-filesystem-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-stalls"
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api create-bucket \
--bucket "$CELLAR_FS_S3_BUCKET"
CELLAR_FS_FAULT_REPORT="$RUNNER_TEMP/filesystem-s3-stall-fault.json" \
cargo test --locked -p cellar --test native_node \
node_filesystem_faults::filesystem_s3_socket_stalls_fence_unproven_writes_and_refuse_failed_recovery \
-- --ignored --exact --nocapture
export CELLAR_AI_HOST="${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar-vercel-agent-example"
export CELLAR_AI_TEST_REPORT="$RUNNER_TEMP/vercel-rustfs-recovery.json"
npm run --prefix examples/vercel-agent test:e2e
export CELLAR_AI_TEST_REPORT="$RUNNER_TEMP/vercel-rustfs-tools.json"
npm run --prefix examples/vercel-agent test:tools
- name: RustFS recovery evidence
if: always() && matrix.profile == 'examples'
uses: actions/upload-artifact@v4
with:
name: vercel-rustfs-recovery
path: |
${{ runner.temp }}/vercel-rustfs-recovery.json
${{ runner.temp }}/vercel-rustfs-tools.json
${{ runner.temp }}/filesystem-s3-proof-fault.json
${{ runner.temp }}/filesystem-s3-socket-fault.json
${{ runner.temp }}/filesystem-s3-stall-fault.json
if-no-files-found: ignore
- name: Quality and engine boundaries
if: matrix.profile == 'adapters'
run: |
cargo clippy --locked -p cellar-container -p cellar-guest -p cellar-javascript --features cellar-javascript/embed,cellar-javascript/node --all-targets -- -D warnings
cargo format --check
cargo check-layout
python3 tools/check_native_dependencies.py
python3 tools/docs/check.py
- name: Native package
if: matrix.profile == 'examples'
run: cargo run --locked -p cellar -- build examples/javascript/project.json --output .cellar/javascript-package
- name: Runnable streaming examples and restart
if: matrix.profile == 'examples'
run: |
python3 examples/streaming/smoke.py --cellar "${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar" \
--backend rust --backend node-js --backend node-ts --backend v8
- name: Runnable binding examples, restart and rebinding
if: matrix.profile == 'examples'
run: |
python3 examples/bindings/smoke.py --cellar "${CARGO_TARGET_DIR:-$PWD/target}/debug/cellar" \
--backend rust --backend node-js --backend node-ts --backend v8
- name: Node runtime delivery
if: matrix.profile == 'packages'
env:
RUST_LOG: timing=debug,cellar::runtime=debug,store=debug
# Keep the existing handler deadlines and all debug/overflow checks.
# Optimize this repeated cold-restart artifact, as in native SDK CI.
CARGO_PROFILE_TEST_OPT_LEVEL: '1'
CARGO_PROFILE_TEST_DEBUG_ASSERTIONS: 'true'
CARGO_PROFILE_TEST_OVERFLOW_CHECKS: 'true'
run: |
cargo build --locked -p cellar-javascript --no-default-features --features node --bin cellar-node-example
mkdir -p .cellar
node --input-type=module <<'JS'
import {writeFileSync} from 'node:fs';
import {resolve} from 'node:path';
writeFileSync('.cellar/node-delivery.json',JSON.stringify({host:resolve(process.env.CARGO_TARGET_DIR ?? 'target','debug/cellar-node-example'),application:'../examples/node',entry:'dist/app.js',files:['dist','package.json','package-lock.json','node_modules']}));
JS
node tools/javascript/node-package.mjs .cellar/node-delivery.json .cellar/node-delivery
.cellar/node-delivery/launch.sh --help
export CELLAR_TEST_NODE_ENTRY="$PWD/.cellar/node-delivery/app/dist/app.js"
export CELLAR_TEST_NODE_EXECUTABLE="$PWD/.cellar/node-delivery/bin/node"
cargo test --locked -p cellar-javascript --no-default-features --features node --test node_runtime --no-run
# Finish build writeback before measuring fresh FULL-sync fixtures.
# Keep their real fsyncs and the existing handler deadline unchanged.
sync -f "${CARGO_TARGET_DIR:-$PWD/target}"
# Fresh stores and Node processes in every case. Stop at the first
# failure; these repetitions never retry a failed request or test.
for iteration in {1..100}; do
echo "Node delivery case $iteration/100"
cargo test --locked -p cellar-javascript --no-default-features --features node --test node_runtime
done
- name: Node fleet publish, restore and process recovery
if: matrix.profile == 'packages'
run: |
node tools/javascript/node-package.mjs --runtime examples/node/runtime.json .cellar/node-runtime
cargo run --locked -p cellar -- build examples/node/project.json --output .cellar/node-fleet-package
# Restore from the published archive, without the captured source tree.
mv .cellar/node-runtime .cellar/node-runtime-captured
CELLAR_NODE_PACKAGE="$PWD/.cellar/node-fleet-package" cargo test --locked -p cellar-javascript --no-default-features --features node --test fleet_package published_node_package -- --ignored
- name: Pi agent installed package end to end
if: matrix.profile == 'packages'
run: |
node tools/javascript/node-package.mjs --runtime examples/pi-agent/runtime.json .cellar/pi-agent-runtime
cargo run --locked -p cellar -- build examples/pi-agent/project.json --output .cellar/pi-agent-package
mv .cellar/pi-agent-runtime .cellar/pi-agent-runtime-captured
CELLAR_PI_PACKAGE="$PWD/.cellar/pi-agent-package" cargo test --locked -p cellar-javascript --no-default-features --features node --test fleet_package pi_agent_package -- --ignored --nocapture
- name: Filesystem agent installed package and session recovery
if: matrix.profile == 'packages'
run: |
node tools/javascript/node-package.mjs --runtime examples/filesystem-agent/runtime.json .cellar/filesystem-agent-runtime
cargo run --locked -p cellar -- build examples/filesystem-agent/project.json --output .cellar/filesystem-agent-package
mv .cellar/filesystem-agent-runtime .cellar/filesystem-agent-runtime-captured
CELLAR_FS_PACKAGE="$PWD/.cellar/filesystem-agent-package" cargo test --locked -p cellar-javascript --no-default-features --features node --test fleet_package filesystem_agent_package -- --ignored --nocapture
- name: Vercel installed package and filesystem recovery
if: matrix.profile == 'packages'
run: |
node tools/javascript/node-package.mjs --runtime examples/vercel-agent/runtime.json .cellar/vercel-agent-runtime
cargo run --locked -p cellar -- build examples/vercel-agent/project.json --output .cellar/vercel-agent-package
mv .cellar/vercel-agent-runtime .cellar/vercel-agent-runtime-captured
CELLAR_VERCEL_PACKAGE="$PWD/.cellar/vercel-agent-package" \
CELLAR_VERCEL_PACKAGE_REPORT="$RUNNER_TEMP/vercel-installed-filesystem.json" \
cargo test --locked -p cellar-javascript --no-default-features --features node --test fleet_package \
vercel::installed_vercel_filesystem_recovers_saved_reads_and_receipts -- --exact --ignored --nocapture
- name: Preserve installed filesystem recovery evidence
if: always() && matrix.profile == 'packages'
uses: actions/upload-artifact@v4
with:
name: vercel-installed-filesystem-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/vercel-installed-filesystem.json
if-no-files-found: ignore
- name: SDK archive
if: matrix.profile == 'packages'
run: npm pack ./packages/cellar-sdk --pack-destination .cellar --ignore-scripts