Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4d401c3
Merge commit '26de9c5245ba20c7a872b4e68355f8fc26cab5ec' into feat/0.7…
andersalm Sep 30, 2026
00aacac
ci: prove pinned installed Home and model journeys
andersalm Sep 30, 2026
0954cf4
ci: bind journey fixtures to installed artifact schemas
andersalm Sep 30, 2026
46790c4
ci: bind installed gateway with a numeric loopback address
andersalm Sep 30, 2026
36d8edb
ci: keep installed journey scope separate from deferred resource life…
andersalm Sep 30, 2026
7720781
ci: support installed journey hashing on Python 3.9 and 3.10
andersalm Sep 30, 2026
72f6f96
ci: stage declared Kubo and keep failed journey receipts
andersalm Oct 1, 2026
53f1bd2
Merge commit '409dc1d6d07667b46ec4c89b391d498e95f8de3c' into feat/0.7…
andersalm Oct 1, 2026
e70faac
Merge final admitted context fixtures into installed core CI
andersalm Oct 1, 2026
2ac3a70
ci: use current Home setup and app controls
andersalm Oct 1, 2026
e7d7add
ci: use the seeded Kubo executable for model packages
andersalm Oct 1, 2026
8837e66
ci: bound pinned browser preparation on compatible installer Node
andersalm Oct 1, 2026
e3eb044
Merge remote-tracking branch 'origin/develop' into feat/0.7.2-ci-core…
andersalm Oct 1, 2026
0738258
ci: launch the Home gateway for installed journeys
andersalm Oct 1, 2026
7429962
test(ci): bind ARM runner policy to its preserved check name
andersalm Oct 1, 2026
8fb5fe1
test(browser): force private request pipe write failure
andersalm Oct 1, 2026
7022fe9
fix(ci): check installed Home gateway health route
andersalm Oct 1, 2026
84c59b8
ci: use Node 24 for installed journey preparation
andersalm Oct 1, 2026
6a29d17
Merge remote-tracking branch 'origin/develop' into feat/0.7.2-ci-core…
andersalm Oct 1, 2026
fc5cdd9
ci: reserve Mac runner space for installed journeys
andersalm Oct 1, 2026
cd00623
fix(ci): align installed journey data roots on macOS
andersalm Oct 1, 2026
0f2211d
ci: record bounded local model startup stages
andersalm Oct 1, 2026
e3db43f
merge: integrate develop CI cache and step limits
andersalm Oct 2, 2026
f6c66c5
ci: bound the installed greeting reply
andersalm Oct 2, 2026
a86586f
ci: measure generation and durable replies over three Mac journeys
andersalm Oct 2, 2026
24fc9f6
merge: integrate reviewed model fixes into installed journeys
andersalm Oct 2, 2026
4f4d5d4
merge: use the pinned ARM CI input for installed journeys
andersalm Oct 2, 2026
f84af0d
merge: inherit the reviewed current front door baseline
andersalm Oct 2, 2026
aa9a2bd
test(ci): refuse invalid reply acknowledgement timing evidence
andersalm Oct 2, 2026
524d1b2
Merge current develop and restore installed SmolLM2 UI proof (#150)
andersalm Oct 8, 2026
d468e1d
Check fixture Runtime ownership before process-group cleanup (#150)
andersalm Oct 8, 2026
ba93713
test(ci): follow Assistant terminal output contract
andersalm Oct 8, 2026
31bc7a5
Merge model contract parity prerequisite for installed Local AI proof
andersalm Oct 8, 2026
31330cc
test(ci): keep final engine absence proof with journey owner
andersalm Oct 8, 2026
62ea008
test(ci): keep browser failure authority in the isolated Home
andersalm Oct 8, 2026
ff13010
test(ci): check installed journey configuration directly
andersalm Oct 8, 2026
abc0543
test(models): share the pinned SmolLM2 fixture data
andersalm Oct 8, 2026
9f6781a
fix(setup): install fresh Kubo with macOS system Bash
andersalm Oct 8, 2026
02f45b2
fix(ci): record failures during installed browser setup
andersalm Oct 8, 2026
1ce4df3
fix(ci): wait for Assistant offer readiness before opening picker
andersalm Oct 8, 2026
064c572
fix(ci): capture phone reply after sidebar closes
andersalm Oct 8, 2026
91db4a4
fix(model): explain host and source engine refusals
andersalm Oct 8, 2026
1efc2ca
test(ci): prove recovery after an absent engine refusal
andersalm Oct 8, 2026
1fa40c3
test(ci): require fresh complete engine refusal evidence
andersalm Oct 8, 2026
b8d12e4
test(ci): wait for the visible Assistant reply
andersalm Oct 8, 2026
1df0256
fix(model): cap engine threads at available host CPUs
andersalm Oct 8, 2026
746d1e9
test(ci): await completed Assistant presentation
andersalm Oct 8, 2026
bcaaf93
test(model): keep thread budget checks focused
andersalm Oct 8, 2026
b939caf
Merge current develop for the local AI installed journey
andersalm Oct 8, 2026
202b460
ci: name the installed journey source tree (#150)
andersalm Oct 8, 2026
3495ddf
Merge remote-tracking branch 'origin/develop' into fix/0.7.2-ci-macos…
andersalm Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 78 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ jobs:
node scripts/people-discovery-smoke.mjs
- name: release artifact source proofs
run: |
node --test scripts/ci-model-package.test.mjs scripts/ci-installed-home-failure.test.mjs
python3 scripts/ci-release-policy-test.py
python3 scripts/ci-download-cache-test.py
python3 scripts/components-release-integrity-check.py --self-test
Expand Down Expand Up @@ -581,9 +582,21 @@ jobs:
with:
path: ${{ steps.kubo-pin.outputs.paths }}
key: ${{ steps.kubo-pin.outputs.key }}
- name: download pinned ARM64 engine input
if: matrix.os == 'ubuntu-22.04-arm'
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
with:
name: llama-arm64-bundle
path: ${{ runner.temp }}/llama-arm64-bundle
- name: verify pinned ARM64 engine input
if: matrix.os == 'ubuntu-22.04-arm'
run: bash scripts/build/build-llama-server-bundle.sh --verify-archive "$RUNNER_TEMP/llama-arm64-bundle"
- name: source-home into isolated HOME
env:
ELASTOS_COLLABORATION_STARTUP_MODE: isolated
SETUP_SOURCE_HOME_INSTALL_LLAMA_SERVER: '1'
SETUP_SOURCE_HOME_INSTALL_KUBO: '1'
ELASTOS_LLAMA_ARM64_BUNDLE: ${{ runner.temp }}/llama-arm64-bundle/llama-b10516-bin-ubuntu22.04-arm64-cpu.tar.gz
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/source-home-logs"
Expand All @@ -604,22 +617,51 @@ jobs:
scripts/setup-source-home.sh 2>&1 | tee "${RUNNER_TEMP}/source-home-logs/setup-source-home.log"
ELASTOS_DATA_DIR="${XDG_DATA_HOME}/elastos" \
scripts/installed-provider-verify.sh 2>&1 | tee "${RUNNER_TEMP}/source-home-logs/installed-provider-verify.log"
- name: download pinned ARM64 engine input
if: matrix.os == 'ubuntu-22.04-arm'
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
with:
name: llama-arm64-bundle
path: ${{ runner.temp }}/llama-arm64-bundle
- name: verify pinned ARM64 engine input
if: matrix.os == 'ubuntu-22.04-arm'
run: bash scripts/build/build-llama-server-bundle.sh --verify-archive "$RUNNER_TEMP/llama-arm64-bundle"
- name: local-carrier setup smoke
env:
ELASTOS_LLAMA_ARM64_BUNDLE: ${{ runner.temp }}/llama-arm64-bundle/llama-b10516-bin-ubuntu22.04-arm64-cpu.tar.gz
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/source-home-logs"
scripts/local-carrier-setup-smoke.sh 2>&1 | tee "${RUNNER_TEMP}/source-home-logs/local-carrier-setup-smoke.log"
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '24'
- name: prepare installed Home browser
timeout-minutes: 10
run: |
npm ci --ignore-scripts --prefix elastos/tools/browser-playwright-engine
export PLAYWRIGHT_BROWSERS_PATH="$RUNNER_TEMP/installed-home-browser"
npx --prefix elastos/tools/browser-playwright-engine playwright install chromium --with-deps --only-shell
echo "PLAYWRIGHT_BROWSERS_PATH=$PLAYWRIGHT_BROWSERS_PATH" >> "$GITHUB_ENV"
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '26'
- name: prepare signed SmolLM2 fixture
timeout-minutes: 20
env:
CI_SOURCE_HOME: ${{ runner.temp }}/elastos-source-home
run: scripts/ci-installed-journeys.sh prepare
- name: installed Marketplace Get and Assistant reply
timeout-minutes: 15
env:
CI_SOURCE_HOME: ${{ runner.temp }}/elastos-source-home
run: scripts/ci-installed-journeys.sh home
- name: summarize installed model journey
if: always()
env:
CI_SOURCE_HOME: ${{ runner.temp }}/elastos-source-home
run: scripts/ci-installed-journeys.sh summary
- name: upload installed model journey
if: always()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: source-home-journeys-${{ matrix.os }}
path: |
${{ runner.temp }}/source-home-journeys/**/*.json
${{ runner.temp }}/source-home-journeys/**/*.png
retention-days: 7
if-no-files-found: error
# ARM PRs also need the package for the Jetson compatibility gate.
# Uploads remain limited to tags, main and dispatch runs.
- name: build and package release binaries
Expand Down Expand Up @@ -741,6 +783,8 @@ jobs:
- name: source-home into isolated MAC_TEST_HOME
env:
ELASTOS_COLLABORATION_STARTUP_MODE: isolated
SETUP_SOURCE_HOME_INSTALL_LLAMA_SERVER: '1'
SETUP_SOURCE_HOME_INSTALL_KUBO: '1'
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/source-home-logs"
Expand Down Expand Up @@ -780,6 +824,31 @@ jobs:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '26'
- name: prepare signed SmolLM2 fixture
timeout-minutes: 20
env:
CI_SOURCE_HOME: ${{ runner.temp }}/elastos-mac-test-home
run: scripts/ci-installed-journeys.sh prepare
- name: installed Marketplace Get and Assistant reply
timeout-minutes: 15
env:
CI_SOURCE_HOME: ${{ runner.temp }}/elastos-mac-test-home
run: scripts/ci-installed-journeys.sh home-repeat
- name: summarize installed model journey
if: always()
env:
CI_SOURCE_HOME: ${{ runner.temp }}/elastos-mac-test-home
run: scripts/ci-installed-journeys.sh summary
- name: upload installed model journey
if: always()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: source-home-journeys-macos-14
path: |
${{ runner.temp }}/source-home-journeys/**/*.json
${{ runner.temp }}/source-home-journeys/**/*.png
retention-days: 7
if-no-files-found: error
# The hop starts from the published release the pin names. Its signed bytes are
# cached by the pin; only a miss reads them from the public seed.
- name: restore the pinned published release
Expand Down
12 changes: 10 additions & 2 deletions capsules/_shared/model-management.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
preparation_unavailable: "Preparation failed.",
});
const failureText = p => FAILURE_TEXT[p.failure_class] || "Preparation failed.";
const DISPATCH_UNAVAILABLE_TEXT = Object.freeze({
unsupported_host: "Keep this model on this device. To run it, use a supported device.",
source_engine_required: "This source Home needs its local model engine. Install the engine through source setup, then Retry.",
});
// One phase per Runtime projection. The full view (System) and the compact
// Marketplace detail read their copy from the same phase.
function phaseOf(r, p, message) {
Expand Down Expand Up @@ -43,6 +47,8 @@
function parseRuntime(r, cid) {
check(r && [r.admitted, r.kept, r.dispatch_ready].every(v => typeof v === "boolean"));
check(r.dispatch_ready ? r.admitted && /^model:[0-9a-f]{64}$/.test(r.offer_id) : r.offer_id === null);
check(r.dispatch_unavailable_reason == null || (r.admitted && !r.dispatch_ready &&
typeof r.dispatch_unavailable_reason === "string" && Object.hasOwn(DISPATCH_UNAVAILABLE_TEXT, r.dispatch_unavailable_reason)));
const p = r.preparation;
if (p !== null) {
check(p && p.cid === cid && text(p.operation_id, 160) && STATES.has(p.state));
Expand Down Expand Up @@ -97,7 +103,8 @@
"operation_id", "cid", "state", "total_bytes", "completed_bytes", "cancel_requested", "admitted", "activation_pending", "failure_class",
].map(key => [key, output[key]]));
return parseRuntime({ admitted: output.admitted, kept: output.kept,
dispatch_ready: output.dispatch_ready, offer_id: output.offer_id, preparation }, cid);
dispatch_ready: output.dispatch_ready, dispatch_unavailable_reason: output.dispatch_unavailable_reason,
offer_id: output.offer_id, preparation }, cid);
}
window.ElastosModelManagement = {
create({ root, capsule, token, buttonClass = "pc2-btn pc2-btn-secondary", cid: requiredCid = null, compact = false, onReadyOpen = null }) {
Expand Down Expand Up @@ -316,7 +323,8 @@
row.append(identity);
}
const phase = phaseOf(r, p, message);
const label = phase === "failed" ? failureText(p) : (compact ? COMPACT_PHASE_TEXT : PHASE_TEXT)[phase];
const label = phase === "failed" ? failureText(p) : phase === "service_unavailable" && r.dispatch_unavailable_reason
? DISPATCH_UNAVAILABLE_TEXT[r.dispatch_unavailable_reason] : (compact ? COMPACT_PHASE_TEXT : PHASE_TEXT)[phase];
row.append(element("p", label));
if (active(p)) {
const progress = element("progress"); progress.max = p.total_bytes || 1; progress.value = p.completed_bytes;
Expand Down
12 changes: 10 additions & 2 deletions capsules/marketplace/browser/model-management.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
preparation_unavailable: "Preparation failed.",
});
const failureText = p => FAILURE_TEXT[p.failure_class] || "Preparation failed.";
const DISPATCH_UNAVAILABLE_TEXT = Object.freeze({
unsupported_host: "Keep this model on this device. To run it, use a supported device.",
source_engine_required: "This source Home needs its local model engine. Install the engine through source setup, then Retry.",
});
// One phase per Runtime projection. The full view (System) and the compact
// Marketplace detail read their copy from the same phase.
function phaseOf(r, p, message) {
Expand Down Expand Up @@ -43,6 +47,8 @@
function parseRuntime(r, cid) {
check(r && [r.admitted, r.kept, r.dispatch_ready].every(v => typeof v === "boolean"));
check(r.dispatch_ready ? r.admitted && /^model:[0-9a-f]{64}$/.test(r.offer_id) : r.offer_id === null);
check(r.dispatch_unavailable_reason == null || (r.admitted && !r.dispatch_ready &&
typeof r.dispatch_unavailable_reason === "string" && Object.hasOwn(DISPATCH_UNAVAILABLE_TEXT, r.dispatch_unavailable_reason)));
const p = r.preparation;
if (p !== null) {
check(p && p.cid === cid && text(p.operation_id, 160) && STATES.has(p.state));
Expand Down Expand Up @@ -97,7 +103,8 @@
"operation_id", "cid", "state", "total_bytes", "completed_bytes", "cancel_requested", "admitted", "activation_pending", "failure_class",
].map(key => [key, output[key]]));
return parseRuntime({ admitted: output.admitted, kept: output.kept,
dispatch_ready: output.dispatch_ready, offer_id: output.offer_id, preparation }, cid);
dispatch_ready: output.dispatch_ready, dispatch_unavailable_reason: output.dispatch_unavailable_reason,
offer_id: output.offer_id, preparation }, cid);
}
window.ElastosModelManagement = {
create({ root, capsule, token, buttonClass = "pc2-btn pc2-btn-secondary", cid: requiredCid = null, compact = false, onReadyOpen = null }) {
Expand Down Expand Up @@ -316,7 +323,8 @@
row.append(identity);
}
const phase = phaseOf(r, p, message);
const label = phase === "failed" ? failureText(p) : (compact ? COMPACT_PHASE_TEXT : PHASE_TEXT)[phase];
const label = phase === "failed" ? failureText(p) : phase === "service_unavailable" && r.dispatch_unavailable_reason
? DISPATCH_UNAVAILABLE_TEXT[r.dispatch_unavailable_reason] : (compact ? COMPACT_PHASE_TEXT : PHASE_TEXT)[phase];
row.append(element("p", label));
if (active(p)) {
const progress = element("progress"); progress.max = p.total_bytes || 1; progress.value = p.completed_bytes;
Expand Down
Loading
Loading