Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
[
"@full-self-browsing/concierge",
"@full-self-browsing/concierge-react",
"@full-self-browsing/concierge-svelte"
"@full-self-browsing/concierge-svelte",
"@full-self-browsing/concierge-dom",
"@full-self-browsing/concierge-realtime"
]
],
"linked": [],
Expand Down
29 changes: 22 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:

- run: pnpm install --frozen-lockfile

- name: Validate v0.3 source and release policy
- name: Validate v0.4 source and release policy
run: |
node scripts/release/check.mjs source
node scripts/release/version.mjs self-test
Expand All @@ -50,7 +50,7 @@ jobs:

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: v0.3-archives-${{ github.sha }}
name: v0.4-archives-${{ github.sha }}
path: ${{ runner.temp }}/release-archives
if-no-files-found: error

Expand All @@ -65,15 +65,15 @@ jobs:
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: v0.3-archives-${{ github.sha }}
name: v0.4-archives-${{ github.sha }}
path: archives

- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: ${{ matrix.node }}
package-manager-cache: false

- name: Install and import the sealed trio
- name: Install and import the sealed five-package set
run: |
mkdir consumer
cd consumer
Expand All @@ -87,9 +87,24 @@ jobs:
await import("@full-self-browsing/concierge/ai-sdk/browser");
await import("@full-self-browsing/concierge-react");
await import("@full-self-browsing/concierge-svelte");
// dom and realtime ship in the fixed set, so they are imported here
// too. Both are expected to load with no DOM present: the dom
// contract guard runs on first registration rather than at module
// scope, and every realtime subpath reaches its transport lazily.
const dom = await import("@full-self-browsing/concierge-dom");
await import("@full-self-browsing/concierge-realtime");
await import("@full-self-browsing/concierge-realtime/openai");
await import("@full-self-browsing/concierge-realtime/webrtc");
await import("@full-self-browsing/concierge-realtime/websocket");
assertSingleInstance();
if (CONTRACT_VERSION !== 3 || adapter.EXPECTED_CORE_CONTRACT_VERSION !== 3) {
throw new Error("contract v3 did not survive the packed install");
for (const [label, observed] of [
["core", CONTRACT_VERSION],
["ai-sdk", adapter.EXPECTED_CORE_CONTRACT_VERSION],
["dom", dom.EXPECTED_CORE_CONTRACT_VERSION],
]) {
if (observed !== 4) {
throw new Error(`contract v4 did not survive the packed install: ${label} reported ${observed}`);
}
}
NODE

Expand All @@ -111,7 +126,7 @@ jobs:

- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: v0.3-archives-${{ github.sha }}
name: v0.4-archives-${{ github.sha }}
path: archives

- run: node scripts/release/compatibility.mjs "$(realpath archives)"
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
node scripts/release/seal.mjs self-test
node scripts/release/publisher.mjs self-test

- name: Open or update the fixed-trio Version Packages PR
- name: Open or update the fixed-set Version Packages PR
id: changesets
uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0
with:
Expand Down Expand Up @@ -203,7 +203,7 @@ jobs:
name: ${{ needs.seal.outputs.sealedArtifact }}
path: ${{ runner.temp }}/release-sealed

- name: Install the exact trio into an isolated example
- name: Install the exact package set into an isolated example
run: |
npm install --global npm@11.19.0
test "$(npm --version)" = "11.19.0"
Expand Down Expand Up @@ -284,13 +284,13 @@ jobs:
seal.runAttempt > Number(process.env.GITHUB_RUN_ATTEMPT) ||
seal.sourceRef !== process.env.GITHUB_REF ||
seal.outputArtifact !== process.env.RELEASE_OUTPUT_ARTIFACT ||
seal.distTag !== "latest" || seal.contractVersion !== 3
seal.distTag !== "latest" || seal.contractVersion !== 4
) throw new Error("release seal identity or digest drifted");

const pinned = {
"config.mjs": "704e722e96934ac6f4534a28953e185aafd369713dd38f2964d3fa62523e10a4",
"release-publisher.mjs": "a6757a8a8c5f4ef67ab6318e8f492844c6b100bf0f12051a6fd1d5b9bd9f0636",
"release-line.json": "2fd76bdd314bfa509ede3a0e8b4a044c50fe556a1fcec015378986a2b6df899c",
"config.mjs": "17f2f25fd40aea7d99024c0da5c7fc8b137dc272646fa1b8d47947bfb3735866",
"release-publisher.mjs": "3ddab82fbf3ef5479f823618b8d1a79a73a1862b297459120d3596a2534a3f3b",
"release-line.json": "d650e2ac9707867db77b5f7b8fd2dd97f8fd0399f578a991091c73ee791dca73",
};
const expected = ["release-seal.json"];
for (const record of seal.tools) {
Expand Down Expand Up @@ -334,7 +334,7 @@ jobs:
appendFileSync(process.env.GITHUB_ENV, `RELEASE_NPM_CLI=${cli}\n`);
NODE

- name: Publish or safely resume the exact trio through OIDC
- name: Publish or safely resume the exact package set through OIDC
env:
RELEASE_OUTPUT_ARTIFACT: ${{ needs.seal.outputs.sealedArtifact }}
run: >-
Expand Down
61 changes: 61 additions & 0 deletions .release/lines/0.4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"schemaVersion": 1,
"releaseLine": "0.4",
"contractVersion": 4,
"initialVersion": "0.4.0",
"distTag": "latest",
"registry": "https://registry.npmjs.org/",
"repository": "fullselfbrowsing/Concierge",
"repositoryUrl": "git+https://github.com/fullselfbrowsing/Concierge.git",
"repositoryWebUrl": "https://github.com/fullselfbrowsing/Concierge",
"sourceRef": "refs/heads/main",
"workflowPath": ".github/workflows/release.yml",
"environment": "npm-production",
"node": {
"consumerEngine": ">=22.12.0",
"ci": "24",
"publisherMinimum": "22.14.0"
},
"npm": {
"version": "11.19.0",
"integrity": "sha512-SDd/hHg3KqHE5Ht2NHWxNYNtqCQ2pXAPLl6OtQhPyED5PHsRfrOtO199MZTIG2cQoQ1ZRI9t28shrD+2cr3AAw=="
},
"compatibility": {
"ai": "^6.0.0 || ^7.0.0",
"react": "^18.2.0 || ^19.0.0",
"reactDom": "^18.2.0 || ^19.0.0",
"svelte": "^5.0.0"
},
"packages": [
{
"name": "@full-self-browsing/concierge",
"path": "packages/concierge",
"role": "core",
"requiresCore": false
},
{
"name": "@full-self-browsing/concierge-react",
"path": "packages/concierge-react",
"role": "react",
"requiresCore": true
},
{
"name": "@full-self-browsing/concierge-svelte",
"path": "packages/concierge-svelte",
"role": "svelte",
"requiresCore": true
},
{
"name": "@full-self-browsing/concierge-dom",
"path": "packages/concierge-dom",
"role": "dom",
"requiresCore": true
},
{
"name": "@full-self-browsing/concierge-realtime",
"path": "packages/concierge-realtime",
"role": "realtime",
"requiresCore": true
}
]
}
45 changes: 29 additions & 16 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Compatibility

Concierge 0.3 is a supported public preview. The three public packages form one
fixed release set and share runtime contract v3.
Concierge 0.4 is a supported public preview. The five public packages form one
fixed release set and share runtime contract v4.

## Supported ranges

| Component | Supported range | Release certification |
| --- | --- | --- |
| Node.js | `>=22.12.0` | 22.12 floor consumer and Node 24 CI/publisher |
| `@full-self-browsing/concierge` | `^0.3.0` | Same patch as every adapter |
| `@full-self-browsing/concierge` | `^0.4.0` | Same patch as every adapter |
| `@full-self-browsing/concierge-dom` | `^0.4.0` | Installed consumer cell; imports with no DOM present |
| `@full-self-browsing/concierge-realtime` | `^0.4.0` | Installed consumer cell; root and `openai`/`webrtc`/`websocket` subpaths |
| React | `^18.2.0 || ^19.0.0` | 18.2 and 19.2 lines |
| React DOM | `^18.2.0 || ^19.0.0` | Matches React |
| Svelte | `^5.0.0` | 5.0 floor and current 5.56.9 |
Expand All @@ -21,7 +23,7 @@ the fixed package family has one runtime contract. Node 22.12 is the consumer
floor; contributing with the pinned pnpm requires Node 22.13 or newer. Trusted
npm publishing requires Node 22.14 or newer and uses Node 24.

## AI SDK stacks certified for 0.3.0
## AI SDK stacks certified for 0.4.0

| Cell | `ai` | `@ai-sdk/react` | OpenRouter provider | Purpose |
| --- | ---: | ---: | ---: | --- |
Expand All @@ -44,32 +46,43 @@ contract. Other AI SDK providers can consume the same `ToolSet`.
replay store additionally needs a browser IndexedDB implementation.
- `@full-self-browsing/concierge/openai-realtime` is runtime-neutral and owns no
WebRTC, audio, credential, transcript, or network capability.
- `@full-self-browsing/concierge-dom` is the framework-neutral visible-element
registry. It never searches the document; it only returns elements the
application registered.
- `@full-self-browsing/concierge-realtime` owns the voice session, delivery
ledger, and optional WebRTC/WebSocket channels. Core's
`/openai-realtime` entry remains a codec only.
- The full Next example declares the Node runtime. Edge deployment is not part
of the 0.3 support matrix.
of the 0.4 support matrix.
- CommonJS output and `require()` are not supported. Use ESM imports.

The release gate installs only the packed trio into foreign temporary
consumers. Both framework cells verify that React and Svelte public entries can
be imported during ESM server rendering, typecheck with `skipLibCheck: false`,
and resolve the same physical core from the consumer and each adapter. The
The release gate installs the packed public set into foreign temporary
consumers. Both framework cells carry all five archives and verify that every
public entry can be imported during ESM server rendering, typechecks with
`skipLibCheck: false`, and resolves the same physical core from the consumer
and each adapter. `concierge-dom` and `concierge-realtime` are imported there
with no DOM present, which is what proves neither reaches `document` or a
transport at module scope. The
sealed AI 7 example then exercises the signed bridge in Chromium, Firefox, and
WebKit before the OIDC publish job can start.

## Version mixing

Do not mix contract-v2 and contract-v3 packages. All adapters keep core as a
peer dependency, and every runtime entry checks contract v3 before registration
Do not mix contract-v3 and contract-v4 packages. All adapters keep core as a
peer dependency, and every runtime entry checks contract v4 before registration
or dispatch.
Upgrade the trio and regenerate the lockfile together:
Upgrade the set and regenerate the lockfile together:

```sh
pnpm up @full-self-browsing/concierge@^0.3 \
@full-self-browsing/concierge-react@^0.3 \
@full-self-browsing/concierge-svelte@^0.3
pnpm up @full-self-browsing/concierge@^0.4 \
@full-self-browsing/concierge-react@^0.4 \
@full-self-browsing/concierge-svelte@^0.4 \
@full-self-browsing/concierge-dom@^0.4 \
@full-self-browsing/concierge-realtime@^0.4

pnpm why @full-self-browsing/concierge
```

The final command should converge on one physical core version. See the
[0.2-to-0.3 migration guide](./docs/migrations/0.2-to-0.3.md) for API changes
[0.3-to-0.4 migration guide](./docs/migrations/0.3-to-0.4.md) for API changes
and backward-compatible adoption guidance.
24 changes: 15 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ release archives.

- The catalog is least authority. Do not add generic click, selector,
coordinate, URL-navigation, DOM-query, or arbitrary-JavaScript actions.
- `@full-self-browsing/concierge-dom` never finds an element; it only
returns one the application registered. `scripts/pkg-dom-catalog-boundary.mjs`
enforces that on the built artifact. Adding an identifier to that script's
allow-set, or deleting a banned class, requires a threat model in the same
pull request.
- Core remains framework-, DOM-, model-provider-, and transport-neutral.
- One physical core owns catalog revisions, bridge identity, consent,
scheduling, deduplication, dispatch, workflow lineage, and terminal control.
Expand Down Expand Up @@ -69,24 +74,23 @@ Use a compound action and core's `workflow` controls for an application-owned
sequence. Child calls must use stable step IDs. Do not put loops, delays, child
dispatch, or cleanup orchestration in a framework or AI adapter.

## Contract v3 changes
## Contract v4 changes

Contract v3 includes atomic `ResolvedCatalog` revisions, structured validated
results, action-scoped bridge precedence, object-form dispatch, explicit
terminal batch outcomes, lifecycle events, compound-action lineage, and the
signed AI and OpenAI Realtime adapters' core dependencies.
Contract v4 includes handler-proposed consent payloads, `attestReadback`,
catalog acknowledgement with deferred `setContext` promotion, vacuous
snapshot fail-closed, and the widened catalog diagnostic vocabulary.

An additive implementation detail does not require a contract bump. A change
that lets two versions disagree about bridge shape, revision capability,
invocation identity, consent records, batch/terminal semantics, event lineage,
or signed dispatch interpretation does. Contract changes require:

1. a synchronized minor release of all three packages;
1. a synchronized minor release of all five packages;
2. every adapter's expected-contract guard to change together;
3. mismatch mutations proving failure occurs before registration or dispatch;
4. a migration guide and compatibility update.

Contract v3 is fixed throughout `0.3.x`.
Contract v4 is fixed throughout `0.4.x`. Contract v3 remains the 0.3 line.

## Tests and checks

Expand Down Expand Up @@ -132,9 +136,11 @@ The public release set is exactly:
1. `@full-self-browsing/concierge`
2. `@full-self-browsing/concierge-react`
3. `@full-self-browsing/concierge-svelte`
4. `@full-self-browsing/concierge-dom`
5. `@full-self-browsing/concierge-realtime`

They belong to one fixed Changesets group and must leave a Version Packages PR
at the same version. A user-visible change adds a changeset naming all three at
at the same version. A user-visible change adds a changeset naming all five at
the same bump level. Private examples and fixtures are never versioned.

Adapters keep core as `peerDependencies["@full-self-browsing/concierge"] =
Expand All @@ -157,7 +163,7 @@ created the code.

Historical `.planning` evidence and `scripts/phase-09-*` reproduce the v0.1
milestone and must not be rewritten as current release tooling. The live release
contract is `.release/lines/0.3.json`, `scripts/release/`, and
contract is `.release/lines/0.4.json`, `scripts/release/`, and
`.github/workflows/release.yml`.

## Pull requests
Expand Down
Loading
Loading