@kortix/sdk 0.13.5 → 0.13.9
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.
- package/README.md +69 -6
- package/dist/browser/session-sync/server-transcript-mirror.d.ts +82 -0
- package/dist/browser/session-sync/server-transcript-mirror.d.ts.map +1 -0
- package/dist/browser/session-sync/server-transcript-mirror.js +143 -0
- package/dist/browser/session-sync/server-transcript-mirror.js.map +1 -0
- package/dist/browser/session-sync/session-sync-registry.d.ts +11 -21
- package/dist/browser/session-sync/session-sync-registry.d.ts.map +1 -1
- package/dist/browser/session-sync/session-sync-registry.js +48 -3
- package/dist/browser/session-sync/session-sync-registry.js.map +1 -1
- package/dist/browser/stores/sandbox-connection-store.d.ts +13 -1
- package/dist/browser/stores/sandbox-connection-store.d.ts.map +1 -1
- package/dist/browser/stores/sandbox-connection-store.js +5 -2
- package/dist/browser/stores/sandbox-connection-store.js.map +1 -1
- package/dist/browser/stores/session-working-store.d.ts +10 -5
- package/dist/browser/stores/session-working-store.d.ts.map +1 -1
- package/dist/browser/stores/session-working-store.js +32 -8
- package/dist/browser/stores/session-working-store.js.map +1 -1
- package/dist/browser/stores/sync-store.d.ts +29 -1
- package/dist/browser/stores/sync-store.d.ts.map +1 -1
- package/dist/browser/stores/sync-store.js +516 -393
- package/dist/browser/stores/sync-store.js.map +1 -1
- package/dist/core/auth/app-viewer.d.ts +57 -0
- package/dist/core/auth/app-viewer.d.ts.map +1 -0
- package/dist/core/auth/app-viewer.js +82 -0
- package/dist/core/auth/app-viewer.js.map +1 -0
- package/dist/core/auth/session.d.ts +45 -0
- package/dist/core/auth/session.d.ts.map +1 -0
- package/dist/core/auth/session.js +113 -0
- package/dist/core/auth/session.js.map +1 -0
- package/dist/core/client/kortix.d.ts +37 -18
- package/dist/core/client/kortix.d.ts.map +1 -1
- package/dist/core/client/kortix.js +47 -0
- package/dist/core/client/kortix.js.map +1 -1
- package/dist/core/http/config.d.ts +4 -2
- package/dist/core/http/config.d.ts.map +1 -1
- package/dist/core/http/config.js.map +1 -1
- package/dist/core/http/opencode-errors.d.ts +17 -0
- package/dist/core/http/opencode-errors.d.ts.map +1 -1
- package/dist/core/http/opencode-errors.js +25 -0
- package/dist/core/http/opencode-errors.js.map +1 -1
- package/dist/core/rest/platform-client/auth.d.ts +120 -0
- package/dist/core/rest/platform-client/auth.d.ts.map +1 -0
- package/dist/core/rest/platform-client/auth.js +98 -0
- package/dist/core/rest/platform-client/auth.js.map +1 -0
- package/dist/core/rest/platform-client/host-boundary.d.ts +5 -0
- package/dist/core/rest/platform-client/host-boundary.d.ts.map +1 -1
- package/dist/core/rest/platform-client/host-boundary.js.map +1 -1
- package/dist/core/rest/projects-client/accounts.d.ts +57 -0
- package/dist/core/rest/projects-client/accounts.d.ts.map +1 -1
- package/dist/core/rest/projects-client/accounts.js +31 -0
- package/dist/core/rest/projects-client/accounts.js.map +1 -1
- package/dist/core/rest/projects-client/apps.d.ts +9 -0
- package/dist/core/rest/projects-client/apps.d.ts.map +1 -1
- package/dist/core/rest/projects-client/apps.js.map +1 -1
- package/dist/core/rest/projects-client/billing.d.ts +2 -0
- package/dist/core/rest/projects-client/billing.d.ts.map +1 -1
- package/dist/core/rest/projects-client/billing.js.map +1 -1
- package/dist/core/rest/projects-client/connectors.d.ts +104 -19
- package/dist/core/rest/projects-client/connectors.d.ts.map +1 -1
- package/dist/core/rest/projects-client/connectors.js +56 -2
- package/dist/core/rest/projects-client/connectors.js.map +1 -1
- package/dist/core/rest/projects-client/index.d.ts +1 -0
- package/dist/core/rest/projects-client/index.d.ts.map +1 -1
- package/dist/core/rest/projects-client/index.js +1 -0
- package/dist/core/rest/projects-client/index.js.map +1 -1
- package/dist/core/rest/projects-client/oauth-clients.d.ts +47 -0
- package/dist/core/rest/projects-client/oauth-clients.d.ts.map +1 -0
- package/dist/core/rest/projects-client/oauth-clients.js +33 -0
- package/dist/core/rest/projects-client/oauth-clients.js.map +1 -0
- package/dist/core/rest/projects-client/projects.d.ts +23 -6
- package/dist/core/rest/projects-client/projects.d.ts.map +1 -1
- package/dist/core/rest/projects-client/projects.js +1 -0
- package/dist/core/rest/projects-client/projects.js.map +1 -1
- package/dist/core/rest/projects-client/session-sandbox.d.ts +52 -0
- package/dist/core/rest/projects-client/session-sandbox.d.ts.map +1 -1
- package/dist/core/rest/projects-client/session-sandbox.js.map +1 -1
- package/dist/core/rest/projects-client/sessions.d.ts +134 -1
- package/dist/core/rest/projects-client/sessions.d.ts.map +1 -1
- package/dist/core/rest/projects-client/sessions.js +47 -1
- package/dist/core/rest/projects-client/sessions.js.map +1 -1
- package/dist/core/session/index.d.ts +1 -0
- package/dist/core/session/index.d.ts.map +1 -1
- package/dist/core/session/index.js +1 -0
- package/dist/core/session/index.js.map +1 -1
- package/dist/core/session/open-bundle.d.ts +110 -0
- package/dist/core/session/open-bundle.d.ts.map +1 -0
- package/dist/core/session/open-bundle.js +183 -0
- package/dist/core/session/open-bundle.js.map +1 -0
- package/dist/core/session/poll-owner.d.ts +35 -0
- package/dist/core/session/poll-owner.d.ts.map +1 -0
- package/dist/core/session/poll-owner.js +90 -0
- package/dist/core/session/poll-owner.js.map +1 -0
- package/dist/core/session/static-file-preview.d.ts +50 -0
- package/dist/core/session/static-file-preview.d.ts.map +1 -0
- package/dist/core/session/static-file-preview.js +91 -0
- package/dist/core/session/static-file-preview.js.map +1 -0
- package/dist/core/session/wake-escalation.d.ts +188 -0
- package/dist/core/session/wake-escalation.d.ts.map +1 -0
- package/dist/core/session/wake-escalation.js +241 -0
- package/dist/core/session/wake-escalation.js.map +1 -0
- package/dist/core/session/working.d.ts +63 -2
- package/dist/core/session/working.d.ts.map +1 -1
- package/dist/core/session/working.js +66 -9
- package/dist/core/session/working.js.map +1 -1
- package/dist/core/session-sync/session-sync-controller.d.ts +34 -2
- package/dist/core/session-sync/session-sync-controller.d.ts.map +1 -1
- package/dist/core/session-sync/session-sync-controller.js +97 -11
- package/dist/core/session-sync/session-sync-controller.js.map +1 -1
- package/dist/core/stream/keepalive.d.ts +17 -0
- package/dist/core/stream/keepalive.d.ts.map +1 -0
- package/dist/core/stream/keepalive.js +19 -0
- package/dist/core/stream/keepalive.js.map +1 -0
- package/dist/core/turns/grouping.d.ts.map +1 -1
- package/dist/core/turns/grouping.js +13 -0
- package/dist/core/turns/grouping.js.map +1 -1
- package/dist/core/turns/types.d.ts +5 -0
- package/dist/core/turns/types.d.ts.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/kortix.esm.min.js +25 -25
- package/dist/kortix.global.js +25 -25
- package/dist/node/app-viewer.d.ts +41 -0
- package/dist/node/app-viewer.d.ts.map +1 -0
- package/dist/node/app-viewer.js +150 -0
- package/dist/node/app-viewer.js.map +1 -0
- package/dist/node/auth.d.ts +84 -0
- package/dist/node/auth.d.ts.map +1 -0
- package/dist/node/auth.js +414 -0
- package/dist/node/auth.js.map +1 -0
- package/dist/node/server.d.ts +19 -0
- package/dist/node/server.d.ts.map +1 -1
- package/dist/node/server.js +13 -1
- package/dist/node/server.js.map +1 -1
- package/dist/react/bedrock-invokable.d.ts +58 -0
- package/dist/react/bedrock-invokable.d.ts.map +1 -0
- package/dist/react/bedrock-invokable.js +83 -0
- package/dist/react/bedrock-invokable.js.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +7 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/model-flatten.d.ts +14 -1
- package/dist/react/model-flatten.d.ts.map +1 -1
- package/dist/react/model-flatten.js +3 -4
- package/dist/react/model-flatten.js.map +1 -1
- package/dist/react/opencode.d.ts +2 -1
- package/dist/react/opencode.d.ts.map +1 -1
- package/dist/react/opencode.js +2 -1
- package/dist/react/opencode.js.map +1 -1
- package/dist/react/provider-selection.d.ts +58 -0
- package/dist/react/provider-selection.d.ts.map +1 -1
- package/dist/react/provider-selection.js +253 -2
- package/dist/react/provider-selection.js.map +1 -1
- package/dist/react/session-start-giveup.d.ts +12 -0
- package/dist/react/session-start-giveup.d.ts.map +1 -0
- package/dist/react/session-start-giveup.js +13 -0
- package/dist/react/session-start-giveup.js.map +1 -0
- package/dist/react/session-title-sync.d.ts.map +1 -1
- package/dist/react/session-title-sync.js +15 -5
- package/dist/react/session-title-sync.js.map +1 -1
- package/dist/react/sign-in-with-kortix.d.ts +346 -0
- package/dist/react/sign-in-with-kortix.d.ts.map +1 -0
- package/dist/react/sign-in-with-kortix.js +65 -0
- package/dist/react/sign-in-with-kortix.js.map +1 -0
- package/dist/react/use-admin-accounts.d.ts +1 -1
- package/dist/react/use-admin-accounts.d.ts.map +1 -1
- package/dist/react/use-admin-accounts.js +1 -0
- package/dist/react/use-admin-accounts.js.map +1 -1
- package/dist/react/use-gateway-routing-policy.d.ts +1 -0
- package/dist/react/use-gateway-routing-policy.d.ts.map +1 -1
- package/dist/react/use-gateway-routing-policy.js +12 -1
- package/dist/react/use-gateway-routing-policy.js.map +1 -1
- package/dist/react/use-kortix-app-viewer.d.ts +13 -0
- package/dist/react/use-kortix-app-viewer.d.ts.map +1 -0
- package/dist/react/use-kortix-app-viewer.js +29 -0
- package/dist/react/use-kortix-app-viewer.js.map +1 -0
- package/dist/react/use-model-defaults.d.ts +7 -0
- package/dist/react/use-model-defaults.d.ts.map +1 -1
- package/dist/react/use-model-defaults.js +7 -1
- package/dist/react/use-model-defaults.js.map +1 -1
- package/dist/react/use-model-enablement.d.ts.map +1 -1
- package/dist/react/use-model-enablement.js +5 -1
- package/dist/react/use-model-enablement.js.map +1 -1
- package/dist/react/use-model-store.d.ts +31 -0
- package/dist/react/use-model-store.d.ts.map +1 -1
- package/dist/react/use-model-store.js +31 -2
- package/dist/react/use-model-store.js.map +1 -1
- package/dist/react/use-opencode-events/helpers.d.ts +49 -5
- package/dist/react/use-opencode-events/helpers.d.ts.map +1 -1
- package/dist/react/use-opencode-events/helpers.js +54 -6
- package/dist/react/use-opencode-events/helpers.js.map +1 -1
- package/dist/react/use-opencode-events/index.d.ts.map +1 -1
- package/dist/react/use-opencode-events/index.js +22 -3
- package/dist/react/use-opencode-events/index.js.map +1 -1
- package/dist/react/use-opencode-events/use-event-stream-refs.d.ts.map +1 -1
- package/dist/react/use-opencode-events/use-event-stream-refs.js +14 -2
- package/dist/react/use-opencode-events/use-event-stream-refs.js.map +1 -1
- package/dist/react/use-opencode-local.d.ts.map +1 -1
- package/dist/react/use-opencode-local.js +27 -8
- package/dist/react/use-opencode-local.js.map +1 -1
- package/dist/react/use-opencode-sessions/providers.d.ts.map +1 -1
- package/dist/react/use-opencode-sessions/providers.js +44 -3
- package/dist/react/use-opencode-sessions/providers.js.map +1 -1
- package/dist/react/use-poll-owner.d.ts +14 -0
- package/dist/react/use-poll-owner.d.ts.map +1 -0
- package/dist/react/use-poll-owner.js +32 -0
- package/dist/react/use-poll-owner.js.map +1 -0
- package/dist/react/use-project-llm-gateway.d.ts +27 -0
- package/dist/react/use-project-llm-gateway.d.ts.map +1 -0
- package/dist/react/use-project-llm-gateway.js +41 -0
- package/dist/react/use-project-llm-gateway.js.map +1 -0
- package/dist/react/use-project-models.d.ts +9 -0
- package/dist/react/use-project-models.d.ts.map +1 -1
- package/dist/react/use-project-models.js +24 -1
- package/dist/react/use-project-models.js.map +1 -1
- package/dist/react/use-runtime-reconnect.d.ts +11 -0
- package/dist/react/use-runtime-reconnect.d.ts.map +1 -1
- package/dist/react/use-runtime-reconnect.js +34 -3
- package/dist/react/use-runtime-reconnect.js.map +1 -1
- package/dist/react/use-session-prompts.d.ts +16 -1
- package/dist/react/use-session-prompts.d.ts.map +1 -1
- package/dist/react/use-session-prompts.js +76 -11
- package/dist/react/use-session-prompts.js.map +1 -1
- package/dist/react/use-session-send.d.ts.map +1 -1
- package/dist/react/use-session-send.js +14 -1
- package/dist/react/use-session-send.js.map +1 -1
- package/dist/react/use-session-start-give-up.d.ts +20 -0
- package/dist/react/use-session-start-give-up.d.ts.map +1 -0
- package/dist/react/use-session-start-give-up.js +60 -0
- package/dist/react/use-session-start-give-up.js.map +1 -0
- package/dist/react/use-session-sync.d.ts +22 -0
- package/dist/react/use-session-sync.d.ts.map +1 -1
- package/dist/react/use-session-sync.js +61 -5
- package/dist/react/use-session-sync.js.map +1 -1
- package/dist/react/use-session-working.d.ts +38 -0
- package/dist/react/use-session-working.d.ts.map +1 -1
- package/dist/react/use-session-working.js +81 -10
- package/dist/react/use-session-working.js.map +1 -1
- package/dist/react/use-session.d.ts +13 -13
- package/dist/react/use-session.d.ts.map +1 -1
- package/dist/react/use-session.js +74 -53
- package/dist/react/use-session.js.map +1 -1
- package/dist/react/use-static-file-preview.d.ts +12 -0
- package/dist/react/use-static-file-preview.d.ts.map +1 -0
- package/dist/react/use-static-file-preview.js +119 -0
- package/dist/react/use-static-file-preview.js.map +1 -0
- package/dist/react/use-wake-escalation.d.ts +51 -0
- package/dist/react/use-wake-escalation.d.ts.map +1 -0
- package/dist/react/use-wake-escalation.js +62 -0
- package/dist/react/use-wake-escalation.js.map +1 -0
- package/package.json +6 -4
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framing a file from the sandbox's static file server.
|
|
3
|
+
*
|
|
4
|
+
* A host that wants to SHOW an HTML file has exactly one correct move: load it
|
|
5
|
+
* from the server that ships inside the sandbox (port 3211, `/open?path=…`) and
|
|
6
|
+
* frame that URL. The tempting shortcut — hand the file's text to an iframe as
|
|
7
|
+
* `srcDoc` — cannot work, and not for a reason a flag can fix: `srcDoc` gives
|
|
8
|
+
* the document no URL at all, so `./style.css`, `img/logo.png` and `app.js`
|
|
9
|
+
* have no base to resolve against. A page written as a page arrives unstyled.
|
|
10
|
+
*
|
|
11
|
+
* Two rules live here rather than in the hook, because both are decisions and
|
|
12
|
+
* neither needs a network to be reasoned about.
|
|
13
|
+
*/
|
|
14
|
+
import { buildStaticFileHealthPreviewUrl, buildStaticFilePreviewUrl, hasPreviewTarget, } from './url.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve both URLs for one file, or `null` when there is nothing to address.
|
|
17
|
+
*
|
|
18
|
+
* The `null` is the whole point. `buildStaticFilePreviewUrl` answers with the
|
|
19
|
+
* INTERNAL form — `http://localhost:3211/open?path=…` — when no sandbox is
|
|
20
|
+
* bound, which is honest for a link that will be re-resolved on click and
|
|
21
|
+
* actively wrong for anything that loads or probes it now: that port is on the
|
|
22
|
+
* viewer's own machine. Framing it shows whatever the user happens to be
|
|
23
|
+
* running; probing it can answer `200` and mark a preview "ready" that can
|
|
24
|
+
* never load. A sandbox binds asynchronously, so every caller passes through
|
|
25
|
+
* this state on the way to a working preview — it is the common case, not an
|
|
26
|
+
* edge one.
|
|
27
|
+
*/
|
|
28
|
+
export function staticFilePreviewTargets(path, options) {
|
|
29
|
+
if (!path)
|
|
30
|
+
return null;
|
|
31
|
+
if (!hasPreviewTarget(options))
|
|
32
|
+
return null;
|
|
33
|
+
const previewUrl = buildStaticFilePreviewUrl(path, options);
|
|
34
|
+
if (!previewUrl)
|
|
35
|
+
return null;
|
|
36
|
+
return { previewUrl, healthUrl: buildStaticFileHealthPreviewUrl(options) };
|
|
37
|
+
}
|
|
38
|
+
/** Gap between liveness probes, ms. */
|
|
39
|
+
export const STATIC_FILE_HEALTH_RETRY_MS = 1_500;
|
|
40
|
+
/**
|
|
41
|
+
* How many probes before the wait becomes a reported failure.
|
|
42
|
+
*
|
|
43
|
+
* 20 × 1.5s ≈ 30s. The bound is not a guess about how long a sandbox takes to
|
|
44
|
+
* boot — it is the line past which silence stops being informative. Without it
|
|
45
|
+
* a surface spins "Starting preview server…" for the life of the tab; with it
|
|
46
|
+
* the user gets a sentence and a Retry.
|
|
47
|
+
*/
|
|
48
|
+
export const STATIC_FILE_HEALTH_MAX_ATTEMPTS = 20;
|
|
49
|
+
/** Whether a caller that has made `attempts` probes should make another. */
|
|
50
|
+
export function shouldRetryStaticFileHealth(attempts) {
|
|
51
|
+
return attempts < STATIC_FILE_HEALTH_MAX_ATTEMPTS;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Does an authenticated preview URL address the file we are asking for?
|
|
55
|
+
*
|
|
56
|
+
* `useAuthenticatedPreviewUrl` resolves in an effect, so on the render where a
|
|
57
|
+
* viewer switches to a different file it still holds the PREVIOUS file's URL.
|
|
58
|
+
* Framing that shows the page the user just navigated away from.
|
|
59
|
+
*
|
|
60
|
+
* Compare NORMALIZED, never by prefix. The subdomain form authenticates with a
|
|
61
|
+
* one-shot `token` that `appendPreviewToken` adds through `URLSearchParams`,
|
|
62
|
+
* which re-serializes the WHOLE query — and the static file URL is the one
|
|
63
|
+
* preview URL that has a query, so `?path=/workspace/a.html` comes back as
|
|
64
|
+
* `?path=%2Fworkspace%2Fa.html`. No prefix of the original survives that, and a
|
|
65
|
+
* prefix test shipped a preview stuck on "Starting preview server…" forever:
|
|
66
|
+
* the server was up, the URL was authenticated, and the check said it belonged
|
|
67
|
+
* to a different file. A prefix is wrong in the other direction too —
|
|
68
|
+
* `a.html.bak` starts with the URL for `a.html`.
|
|
69
|
+
*
|
|
70
|
+
* Both sides go through the same `URL` round-trip, so both carry the same
|
|
71
|
+
* encoding; `token` is dropped because it is the credential, not the address.
|
|
72
|
+
*/
|
|
73
|
+
function normalizeAddress(candidate) {
|
|
74
|
+
try {
|
|
75
|
+
const url = new URL(candidate);
|
|
76
|
+
url.searchParams.delete('token');
|
|
77
|
+
url.searchParams.sort();
|
|
78
|
+
return url.toString();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export function authenticatedUrlAddresses(authenticatedUrl, previewUrl) {
|
|
85
|
+
if (!authenticatedUrl || !previewUrl)
|
|
86
|
+
return false;
|
|
87
|
+
const authenticated = normalizeAddress(authenticatedUrl);
|
|
88
|
+
const wanted = normalizeAddress(previewUrl);
|
|
89
|
+
return authenticated !== null && authenticated === wanted;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=static-file-preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-file-preview.js","sourceRoot":"","sources":["../../../src/core/session/static-file-preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,EACzB,gBAAgB,GAEjB,MAAM,OAAO,CAAC;AAUf;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CACtC,IAAwB,EACxB,OAA4B;IAE5B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5C,MAAM,UAAU,GAAG,yBAAyB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,+BAA+B,CAAC,OAAO,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,uCAAuC;AACvC,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,EAAE,CAAC;AAElD,4EAA4E;AAC5E,MAAM,UAAU,2BAA2B,CAAC,QAAgB;IAC1D,OAAO,QAAQ,GAAG,+BAA+B,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAS,gBAAgB,CAAC,SAAiB;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACxB,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,gBAA2C,EAC3C,UAA8B;IAE9B,IAAI,CAAC,gBAAgB,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IACnD,MAAM,aAAa,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC5C,OAAO,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,MAAM,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wake escalation ladder — what a session view does when bringing a
|
|
3
|
+
* runtime up takes longer than it should.
|
|
4
|
+
*
|
|
5
|
+
* ## The failure this replaces
|
|
6
|
+
*
|
|
7
|
+
* Opening a stopped session starts a wake. The old model gave that wake a FIXED
|
|
8
|
+
* budget: the server's own `RUNTIME_WAKE_LEASE_MS` (240s,
|
|
9
|
+
* `apps/api/src/projects/session-lifecycle/runtime-wake-fence.ts:10`), after
|
|
10
|
+
* which maintenance stamps `stopReason: 'runtime_wake_failed'` and every
|
|
11
|
+
* subsequent `/start` short-circuits to a terminal payload
|
|
12
|
+
* (`apps/api/src/projects/routes/shared.ts:672-694`)
|
|
13
|
+
*
|
|
14
|
+
* "Couldn't start session <id> — The session runtime did not become
|
|
15
|
+
* reachable. Restart the session to try again."
|
|
16
|
+
*
|
|
17
|
+
* Measured on Essentia (2026-08-26, box `inqwpv4a1cc1kynlg46k8`): that card
|
|
18
|
+
* painted while the box was SECONDS from ready — its daemon logged
|
|
19
|
+
* `opencode ready` at 06:10:02, right after the budget expired. The card is a
|
|
20
|
+
* dead end with no auto-recovery, and the human's fix is always the same one
|
|
21
|
+
* click: "clicking restart made it work instantly". Two more recurrences
|
|
22
|
+
* followed, both during a post-deploy image rebuild — i.e. this class recurs on
|
|
23
|
+
* every ops event that slows a provider resume.
|
|
24
|
+
*
|
|
25
|
+
* ## The two rules that fix it
|
|
26
|
+
*
|
|
27
|
+
* 1. **A budget measures SILENCE, not elapsed time.** A wake that is visibly
|
|
28
|
+
* advancing — provider state moving, daemon boot phases changing, health
|
|
29
|
+
* improving — has not failed, however long it takes. Only a bounded window
|
|
30
|
+
* with ZERO observable change is evidence of a wedge. So the clock here is
|
|
31
|
+
* reset by any change to {@link WakeObservation.progress} and the elapsed
|
|
32
|
+
* total is never consulted.
|
|
33
|
+
*
|
|
34
|
+
* 2. **Escalate through the ladder the human uses, and only then give up.**
|
|
35
|
+
* A quiet `/start` retry first (free, and it heals a row that recovered on
|
|
36
|
+
* its own), then the RESTART the user would have clicked — bounded to
|
|
37
|
+
* {@link WAKE_MAX_RESTARTS}. The terminal card is what remains after the
|
|
38
|
+
* ladder is exhausted, and it then has to name what was tried
|
|
39
|
+
* ({@link wakeEscalationAttemptSummary}).
|
|
40
|
+
*
|
|
41
|
+
* A blanket "just restart it by default" was considered and REJECTED: it
|
|
42
|
+
* destroys fast warm resumes (a Platinum CoW resume reaches `running` in ~1.9s)
|
|
43
|
+
* by throwing away a box that was about to answer.
|
|
44
|
+
*
|
|
45
|
+
* ## Why `runtimeReachable` is a separate input from `waking`
|
|
46
|
+
*
|
|
47
|
+
* The session row is NOT proof the runtime is up. Observed on Essentia the same
|
|
48
|
+
* day: `POST …/start` answered 202 and the row stayed `running` for 5+ minutes
|
|
49
|
+
* while the E2B resume had silently failed — the provider reported the sandbox
|
|
50
|
+
* `stopped` and the daemon proxy answered `503 sandbox_not_ready`. A ladder that
|
|
51
|
+
* treated `stage: 'ready'` as the end of the wake would sit there forever. So
|
|
52
|
+
* the wake ends when the RUNTIME ANSWERS (`/kortix/health`), not when the
|
|
53
|
+
* control plane says it should have.
|
|
54
|
+
*
|
|
55
|
+
* That reachability is also a LATCH: once a runtime has answered, this machine
|
|
56
|
+
* is done for the life of the session view. A box that drops mid-session is
|
|
57
|
+
* `useRuntimeReconnect`'s problem, and auto-restarting it would destroy the
|
|
58
|
+
* turn the user is watching.
|
|
59
|
+
*
|
|
60
|
+
* Pure and clock-free: every decision is a function of the passed state plus one
|
|
61
|
+
* observation. The React glue lives in `react/use-wake-escalation.ts`.
|
|
62
|
+
*/
|
|
63
|
+
/**
|
|
64
|
+
* How long a wake may show ZERO observable change before the ladder escalates.
|
|
65
|
+
*
|
|
66
|
+
* Sized against the measured wake profile rather than a guess: a cold resume is
|
|
67
|
+
* 18.9s (Daytona) / 24.5s (Platinum) end to end, and each phase of it produces
|
|
68
|
+
* an observable change, so a healthy wake never accumulates more than a few
|
|
69
|
+
* seconds of silence. 75s is comfortably past the slowest legitimate single
|
|
70
|
+
* phase (the server's own provider-confirmation grace is 90s but it emits
|
|
71
|
+
* `runtime_waking` throughout) while still being three times faster to react
|
|
72
|
+
* than the 240s lease that produced the incident.
|
|
73
|
+
*/
|
|
74
|
+
export declare const WAKE_NO_PROGRESS_MS = 75000;
|
|
75
|
+
/**
|
|
76
|
+
* Automatic restarts the ladder may perform. Two, because the human fix that
|
|
77
|
+
* always works is one restart, and a second covers the case where the first
|
|
78
|
+
* landed during the same ops event (an image rebuild) that wedged the wake.
|
|
79
|
+
* Unbounded retries would be a restart loop against a genuinely dead provider.
|
|
80
|
+
*/
|
|
81
|
+
export declare const WAKE_MAX_RESTARTS = 2;
|
|
82
|
+
/**
|
|
83
|
+
* Minimum gap between two ladder actions.
|
|
84
|
+
*
|
|
85
|
+
* A server-declared wake failure short-circuits the no-progress window (there is
|
|
86
|
+
* nothing left to wait for), so without a floor the ladder would spend its whole
|
|
87
|
+
* budget inside one second. `POST /restart` plus its first `/start` take ~2.6s
|
|
88
|
+
* measured; 20s leaves the new attempt room to produce its first signal.
|
|
89
|
+
*/
|
|
90
|
+
export declare const WAKE_ESCALATION_COOLDOWN_MS = 20000;
|
|
91
|
+
/** One rung of the ladder. */
|
|
92
|
+
export type WakeEscalationStep = 'retry-start' | 'restart';
|
|
93
|
+
/** The action to dispatch on THIS tick — `none` on almost every tick. */
|
|
94
|
+
export type WakeEscalationDispatch = 'none' | WakeEscalationStep;
|
|
95
|
+
export type WakeEscalationStatus =
|
|
96
|
+
/** No wake in progress, or the runtime already answered. */
|
|
97
|
+
'idle'
|
|
98
|
+
/** A wake is running and has not needed help. */
|
|
99
|
+
| 'waking'
|
|
100
|
+
/** The ladder has intervened at least once and the wake continues. */
|
|
101
|
+
| 'escalating'
|
|
102
|
+
/** Every rung has been used; the host may now show a terminal card. */
|
|
103
|
+
| 'exhausted';
|
|
104
|
+
export interface WakeAttempt {
|
|
105
|
+
step: WakeEscalationStep;
|
|
106
|
+
atMs: number;
|
|
107
|
+
}
|
|
108
|
+
export interface WakeEscalationState {
|
|
109
|
+
status: WakeEscalationStatus;
|
|
110
|
+
/** What the host must do NOW. Read once per transition, never replayed. */
|
|
111
|
+
dispatch: WakeEscalationDispatch;
|
|
112
|
+
/** The last progress fingerprint seen, or null before the first observation. */
|
|
113
|
+
fingerprint: string | null;
|
|
114
|
+
/** When the fingerprint last changed. */
|
|
115
|
+
lastProgressAtMs: number | null;
|
|
116
|
+
/** When the ladder last dispatched an action. */
|
|
117
|
+
lastDispatchAtMs: number | null;
|
|
118
|
+
/** Everything the ladder has tried, oldest first. */
|
|
119
|
+
attempts: readonly WakeAttempt[];
|
|
120
|
+
/**
|
|
121
|
+
* How long the wake has shown no observable change. This is the
|
|
122
|
+
* PROGRESS-AWARE budget a host should render against — never wall-clock time
|
|
123
|
+
* since the wake began, which is what produced the premature terminal card.
|
|
124
|
+
*/
|
|
125
|
+
msSinceProgress: number;
|
|
126
|
+
/** The runtime has answered at least once in this session view. */
|
|
127
|
+
settled: boolean;
|
|
128
|
+
}
|
|
129
|
+
export interface WakeObservation {
|
|
130
|
+
nowMs: number;
|
|
131
|
+
/**
|
|
132
|
+
* The host is trying to bring this session's runtime up. False switches the
|
|
133
|
+
* ladder off entirely (no session, gated, unmounted) and resets it.
|
|
134
|
+
*/
|
|
135
|
+
waking: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* The RUNTIME answered — daemon health, not the session row. True ends the
|
|
138
|
+
* wake and latches: see the module comment.
|
|
139
|
+
*/
|
|
140
|
+
runtimeReachable: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Everything observable about this wake, joined into one value. Any change is
|
|
143
|
+
* progress. Build it with {@link wakeProgressFingerprint}.
|
|
144
|
+
*/
|
|
145
|
+
progress: string;
|
|
146
|
+
/**
|
|
147
|
+
* The server has declared this wake failed — the state that used to paint the
|
|
148
|
+
* terminal card. Escalates immediately: there is no further progress to wait
|
|
149
|
+
* for, only a rung of the ladder left to try.
|
|
150
|
+
*/
|
|
151
|
+
serverGaveUp: boolean;
|
|
152
|
+
}
|
|
153
|
+
export interface WakeEscalationLimits {
|
|
154
|
+
noProgressMs?: number;
|
|
155
|
+
maxRestarts?: number;
|
|
156
|
+
cooldownMs?: number;
|
|
157
|
+
}
|
|
158
|
+
export declare function initialWakeEscalationState(): WakeEscalationState;
|
|
159
|
+
/**
|
|
160
|
+
* Join the observable wake signals into one comparable value, dropping the ones
|
|
161
|
+
* that are not known yet.
|
|
162
|
+
*
|
|
163
|
+
* `null`/`undefined` are DROPPED rather than stringified so that a signal
|
|
164
|
+
* arriving for the first time (a sandbox row appearing, a health body parsing)
|
|
165
|
+
* reads as the progress it is, while a signal that is simply absent contributes
|
|
166
|
+
* nothing and cannot manufacture a change on its own.
|
|
167
|
+
*/
|
|
168
|
+
export declare function wakeProgressFingerprint(parts: readonly (string | number | boolean | null | undefined)[]): string;
|
|
169
|
+
/**
|
|
170
|
+
* Fold one observation into the ladder's state. Pure — same inputs, same output,
|
|
171
|
+
* no clock and no I/O.
|
|
172
|
+
*/
|
|
173
|
+
export declare function advanceWakeEscalation(state: WakeEscalationState, observation: WakeObservation, limits?: WakeEscalationLimits): WakeEscalationState;
|
|
174
|
+
/**
|
|
175
|
+
* The honest one-line status while the ladder is working, in the same voice as
|
|
176
|
+
* the boot-phase pill ("Waking the agent", "Connecting").
|
|
177
|
+
*
|
|
178
|
+
* Null while the first, ordinary wake is running — that wake already has honest
|
|
179
|
+
* copy and does not need a second component talking over it — and null once
|
|
180
|
+
* exhausted, where the terminal card takes over.
|
|
181
|
+
*/
|
|
182
|
+
export declare function wakeEscalationNote(state: WakeEscalationState): string | null;
|
|
183
|
+
/**
|
|
184
|
+
* What the ladder tried, for the terminal card. A dead end that cannot say what
|
|
185
|
+
* was already attempted invites the user to repeat it by hand.
|
|
186
|
+
*/
|
|
187
|
+
export declare function wakeEscalationAttemptSummary(state: WakeEscalationState): string | null;
|
|
188
|
+
//# sourceMappingURL=wake-escalation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wake-escalation.d.ts","sourceRoot":"","sources":["../../../src/core/session/wake-escalation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAAC;AAE3D,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,kBAAkB,CAAC;AAEjE,MAAM,MAAM,oBAAoB;AAC9B,4DAA4D;AAC1D,MAAM;AACR,iDAAiD;GAC/C,QAAQ;AACV,sEAAsE;GACpE,YAAY;AACd,uEAAuE;GACrE,WAAW,CAAC;AAEhB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,kBAAkB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,EAAE,sBAAsB,CAAC;IACjC,gFAAgF;IAChF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iDAAiD;IACjD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,qDAAqD;IACrD,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IACjC;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,0BAA0B,IAAI,mBAAmB,CAWhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAC/D,MAAM,CAER;AAYD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,mBAAmB,EAC1B,WAAW,EAAE,eAAe,EAC5B,MAAM,GAAE,oBAAyB,GAChC,mBAAmB,CA0ErB;AAOD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAM5E;AAQD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAStF"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wake escalation ladder — what a session view does when bringing a
|
|
3
|
+
* runtime up takes longer than it should.
|
|
4
|
+
*
|
|
5
|
+
* ## The failure this replaces
|
|
6
|
+
*
|
|
7
|
+
* Opening a stopped session starts a wake. The old model gave that wake a FIXED
|
|
8
|
+
* budget: the server's own `RUNTIME_WAKE_LEASE_MS` (240s,
|
|
9
|
+
* `apps/api/src/projects/session-lifecycle/runtime-wake-fence.ts:10`), after
|
|
10
|
+
* which maintenance stamps `stopReason: 'runtime_wake_failed'` and every
|
|
11
|
+
* subsequent `/start` short-circuits to a terminal payload
|
|
12
|
+
* (`apps/api/src/projects/routes/shared.ts:672-694`)
|
|
13
|
+
*
|
|
14
|
+
* "Couldn't start session <id> — The session runtime did not become
|
|
15
|
+
* reachable. Restart the session to try again."
|
|
16
|
+
*
|
|
17
|
+
* Measured on Essentia (2026-08-26, box `inqwpv4a1cc1kynlg46k8`): that card
|
|
18
|
+
* painted while the box was SECONDS from ready — its daemon logged
|
|
19
|
+
* `opencode ready` at 06:10:02, right after the budget expired. The card is a
|
|
20
|
+
* dead end with no auto-recovery, and the human's fix is always the same one
|
|
21
|
+
* click: "clicking restart made it work instantly". Two more recurrences
|
|
22
|
+
* followed, both during a post-deploy image rebuild — i.e. this class recurs on
|
|
23
|
+
* every ops event that slows a provider resume.
|
|
24
|
+
*
|
|
25
|
+
* ## The two rules that fix it
|
|
26
|
+
*
|
|
27
|
+
* 1. **A budget measures SILENCE, not elapsed time.** A wake that is visibly
|
|
28
|
+
* advancing — provider state moving, daemon boot phases changing, health
|
|
29
|
+
* improving — has not failed, however long it takes. Only a bounded window
|
|
30
|
+
* with ZERO observable change is evidence of a wedge. So the clock here is
|
|
31
|
+
* reset by any change to {@link WakeObservation.progress} and the elapsed
|
|
32
|
+
* total is never consulted.
|
|
33
|
+
*
|
|
34
|
+
* 2. **Escalate through the ladder the human uses, and only then give up.**
|
|
35
|
+
* A quiet `/start` retry first (free, and it heals a row that recovered on
|
|
36
|
+
* its own), then the RESTART the user would have clicked — bounded to
|
|
37
|
+
* {@link WAKE_MAX_RESTARTS}. The terminal card is what remains after the
|
|
38
|
+
* ladder is exhausted, and it then has to name what was tried
|
|
39
|
+
* ({@link wakeEscalationAttemptSummary}).
|
|
40
|
+
*
|
|
41
|
+
* A blanket "just restart it by default" was considered and REJECTED: it
|
|
42
|
+
* destroys fast warm resumes (a Platinum CoW resume reaches `running` in ~1.9s)
|
|
43
|
+
* by throwing away a box that was about to answer.
|
|
44
|
+
*
|
|
45
|
+
* ## Why `runtimeReachable` is a separate input from `waking`
|
|
46
|
+
*
|
|
47
|
+
* The session row is NOT proof the runtime is up. Observed on Essentia the same
|
|
48
|
+
* day: `POST …/start` answered 202 and the row stayed `running` for 5+ minutes
|
|
49
|
+
* while the E2B resume had silently failed — the provider reported the sandbox
|
|
50
|
+
* `stopped` and the daemon proxy answered `503 sandbox_not_ready`. A ladder that
|
|
51
|
+
* treated `stage: 'ready'` as the end of the wake would sit there forever. So
|
|
52
|
+
* the wake ends when the RUNTIME ANSWERS (`/kortix/health`), not when the
|
|
53
|
+
* control plane says it should have.
|
|
54
|
+
*
|
|
55
|
+
* That reachability is also a LATCH: once a runtime has answered, this machine
|
|
56
|
+
* is done for the life of the session view. A box that drops mid-session is
|
|
57
|
+
* `useRuntimeReconnect`'s problem, and auto-restarting it would destroy the
|
|
58
|
+
* turn the user is watching.
|
|
59
|
+
*
|
|
60
|
+
* Pure and clock-free: every decision is a function of the passed state plus one
|
|
61
|
+
* observation. The React glue lives in `react/use-wake-escalation.ts`.
|
|
62
|
+
*/
|
|
63
|
+
/**
|
|
64
|
+
* How long a wake may show ZERO observable change before the ladder escalates.
|
|
65
|
+
*
|
|
66
|
+
* Sized against the measured wake profile rather than a guess: a cold resume is
|
|
67
|
+
* 18.9s (Daytona) / 24.5s (Platinum) end to end, and each phase of it produces
|
|
68
|
+
* an observable change, so a healthy wake never accumulates more than a few
|
|
69
|
+
* seconds of silence. 75s is comfortably past the slowest legitimate single
|
|
70
|
+
* phase (the server's own provider-confirmation grace is 90s but it emits
|
|
71
|
+
* `runtime_waking` throughout) while still being three times faster to react
|
|
72
|
+
* than the 240s lease that produced the incident.
|
|
73
|
+
*/
|
|
74
|
+
export const WAKE_NO_PROGRESS_MS = 75_000;
|
|
75
|
+
/**
|
|
76
|
+
* Automatic restarts the ladder may perform. Two, because the human fix that
|
|
77
|
+
* always works is one restart, and a second covers the case where the first
|
|
78
|
+
* landed during the same ops event (an image rebuild) that wedged the wake.
|
|
79
|
+
* Unbounded retries would be a restart loop against a genuinely dead provider.
|
|
80
|
+
*/
|
|
81
|
+
export const WAKE_MAX_RESTARTS = 2;
|
|
82
|
+
/**
|
|
83
|
+
* Minimum gap between two ladder actions.
|
|
84
|
+
*
|
|
85
|
+
* A server-declared wake failure short-circuits the no-progress window (there is
|
|
86
|
+
* nothing left to wait for), so without a floor the ladder would spend its whole
|
|
87
|
+
* budget inside one second. `POST /restart` plus its first `/start` take ~2.6s
|
|
88
|
+
* measured; 20s leaves the new attempt room to produce its first signal.
|
|
89
|
+
*/
|
|
90
|
+
export const WAKE_ESCALATION_COOLDOWN_MS = 20_000;
|
|
91
|
+
export function initialWakeEscalationState() {
|
|
92
|
+
return {
|
|
93
|
+
status: 'idle',
|
|
94
|
+
dispatch: 'none',
|
|
95
|
+
fingerprint: null,
|
|
96
|
+
lastProgressAtMs: null,
|
|
97
|
+
lastDispatchAtMs: null,
|
|
98
|
+
attempts: [],
|
|
99
|
+
msSinceProgress: 0,
|
|
100
|
+
settled: false,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Join the observable wake signals into one comparable value, dropping the ones
|
|
105
|
+
* that are not known yet.
|
|
106
|
+
*
|
|
107
|
+
* `null`/`undefined` are DROPPED rather than stringified so that a signal
|
|
108
|
+
* arriving for the first time (a sandbox row appearing, a health body parsing)
|
|
109
|
+
* reads as the progress it is, while a signal that is simply absent contributes
|
|
110
|
+
* nothing and cannot manufacture a change on its own.
|
|
111
|
+
*/
|
|
112
|
+
export function wakeProgressFingerprint(parts) {
|
|
113
|
+
return parts.filter((part) => part !== null && part !== undefined).join('|');
|
|
114
|
+
}
|
|
115
|
+
/** The next rung, or null when the ladder is spent. */
|
|
116
|
+
function nextStep(attempts, maxRestarts) {
|
|
117
|
+
if (attempts.length === 0)
|
|
118
|
+
return 'retry-start';
|
|
119
|
+
const restarts = attempts.filter((attempt) => attempt.step === 'restart').length;
|
|
120
|
+
return restarts < maxRestarts ? 'restart' : null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Fold one observation into the ladder's state. Pure — same inputs, same output,
|
|
124
|
+
* no clock and no I/O.
|
|
125
|
+
*/
|
|
126
|
+
export function advanceWakeEscalation(state, observation, limits = {}) {
|
|
127
|
+
const noProgressMs = limits.noProgressMs ?? WAKE_NO_PROGRESS_MS;
|
|
128
|
+
const maxRestarts = limits.maxRestarts ?? WAKE_MAX_RESTARTS;
|
|
129
|
+
const cooldownMs = limits.cooldownMs ?? WAKE_ESCALATION_COOLDOWN_MS;
|
|
130
|
+
// The runtime answered. The wake is over, and nothing about it may leak into
|
|
131
|
+
// the next one. `settled` survives the reset: within one session view, a
|
|
132
|
+
// runtime that has answered is never woken again by this machine.
|
|
133
|
+
if (observation.runtimeReachable) {
|
|
134
|
+
return { ...initialWakeEscalationState(), settled: true };
|
|
135
|
+
}
|
|
136
|
+
// The host cannot classify the wake right now — PAUSE, do not forget.
|
|
137
|
+
//
|
|
138
|
+
// This is not hypothetical tidiness. `useRestartProjectSession` seeds the
|
|
139
|
+
// `/start` cache with `{stage: 'provisioning', sandbox: null}` the instant a
|
|
140
|
+
// restart is dispatched, and a null sandbox is exactly "cannot classify". If
|
|
141
|
+
// that cleared `attempts`, every rung the ladder fired would reset its own
|
|
142
|
+
// budget and `WAKE_MAX_RESTARTS` would bound nothing — a restart loop, which
|
|
143
|
+
// is strictly worse than the dead-end card this replaces.
|
|
144
|
+
//
|
|
145
|
+
// The silence clock IS cleared, so resuming re-baselines rather than
|
|
146
|
+
// escalating on the strength of a window the ladder never actually watched.
|
|
147
|
+
// The dispatch cooldown is deliberately kept: a pause must not become a way
|
|
148
|
+
// to fire two rungs back to back.
|
|
149
|
+
if (!observation.waking) {
|
|
150
|
+
return { ...state, dispatch: 'none', fingerprint: null, lastProgressAtMs: null, msSinceProgress: 0 };
|
|
151
|
+
}
|
|
152
|
+
// A runtime that already answered and later dropped is a mid-session
|
|
153
|
+
// reconnect, not a wake. Restarting it would destroy the live turn.
|
|
154
|
+
if (state.settled)
|
|
155
|
+
return { ...initialWakeEscalationState(), settled: true };
|
|
156
|
+
const previousProgressAtMs = state.lastProgressAtMs;
|
|
157
|
+
const first = previousProgressAtMs === null;
|
|
158
|
+
const changed = observation.progress !== state.fingerprint;
|
|
159
|
+
const lastProgressAtMs = previousProgressAtMs === null || changed ? observation.nowMs : previousProgressAtMs;
|
|
160
|
+
const msSinceProgress = Math.max(0, observation.nowMs - lastProgressAtMs);
|
|
161
|
+
const base = {
|
|
162
|
+
...state,
|
|
163
|
+
dispatch: 'none',
|
|
164
|
+
fingerprint: observation.progress,
|
|
165
|
+
lastProgressAtMs,
|
|
166
|
+
msSinceProgress,
|
|
167
|
+
status: state.attempts.length > 0 ? 'escalating' : 'waking',
|
|
168
|
+
};
|
|
169
|
+
if (state.status === 'exhausted')
|
|
170
|
+
return { ...base, status: 'exhausted' };
|
|
171
|
+
// A server-declared failure needs no window: the wake is over, only the
|
|
172
|
+
// ladder is left. Everything else waits out the silence.
|
|
173
|
+
const stalled = !first && !changed && msSinceProgress >= noProgressMs;
|
|
174
|
+
if (!observation.serverGaveUp && !stalled)
|
|
175
|
+
return base;
|
|
176
|
+
// One action per cooldown, whatever triggered it.
|
|
177
|
+
if (state.lastDispatchAtMs !== null &&
|
|
178
|
+
observation.nowMs - state.lastDispatchAtMs < cooldownMs) {
|
|
179
|
+
return base;
|
|
180
|
+
}
|
|
181
|
+
const step = nextStep(state.attempts, maxRestarts);
|
|
182
|
+
if (!step)
|
|
183
|
+
return { ...base, status: 'exhausted' };
|
|
184
|
+
return {
|
|
185
|
+
...base,
|
|
186
|
+
status: 'escalating',
|
|
187
|
+
dispatch: step,
|
|
188
|
+
attempts: [...state.attempts, { step, atMs: observation.nowMs }],
|
|
189
|
+
lastDispatchAtMs: observation.nowMs,
|
|
190
|
+
// The new attempt gets its own window: it has not been silent yet.
|
|
191
|
+
lastProgressAtMs: observation.nowMs,
|
|
192
|
+
msSinceProgress: 0,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const STEP_VERB = {
|
|
196
|
+
'retry-start': 'retrying',
|
|
197
|
+
restart: 'restarting',
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* The honest one-line status while the ladder is working, in the same voice as
|
|
201
|
+
* the boot-phase pill ("Waking the agent", "Connecting").
|
|
202
|
+
*
|
|
203
|
+
* Null while the first, ordinary wake is running — that wake already has honest
|
|
204
|
+
* copy and does not need a second component talking over it — and null once
|
|
205
|
+
* exhausted, where the terminal card takes over.
|
|
206
|
+
*/
|
|
207
|
+
export function wakeEscalationNote(state) {
|
|
208
|
+
if (state.status !== 'escalating')
|
|
209
|
+
return null;
|
|
210
|
+
const last = state.attempts[state.attempts.length - 1];
|
|
211
|
+
if (!last)
|
|
212
|
+
return null;
|
|
213
|
+
// The original wake is attempt 1, so the Nth ladder action is attempt N+1.
|
|
214
|
+
return `Still waking — ${STEP_VERB[last.step]} the runtime (attempt ${state.attempts.length + 1})`;
|
|
215
|
+
}
|
|
216
|
+
function countWord(count) {
|
|
217
|
+
if (count === 1)
|
|
218
|
+
return 'once';
|
|
219
|
+
if (count === 2)
|
|
220
|
+
return 'twice';
|
|
221
|
+
return `${count} times`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* What the ladder tried, for the terminal card. A dead end that cannot say what
|
|
225
|
+
* was already attempted invites the user to repeat it by hand.
|
|
226
|
+
*/
|
|
227
|
+
export function wakeEscalationAttemptSummary(state) {
|
|
228
|
+
if (state.status !== 'exhausted')
|
|
229
|
+
return null;
|
|
230
|
+
const restarts = state.attempts.filter((attempt) => attempt.step === 'restart').length;
|
|
231
|
+
const retried = state.attempts.some((attempt) => attempt.step === 'retry-start');
|
|
232
|
+
if (!retried && restarts === 0)
|
|
233
|
+
return null;
|
|
234
|
+
const parts = [];
|
|
235
|
+
if (retried)
|
|
236
|
+
parts.push('re-issuing the wake');
|
|
237
|
+
if (restarts > 0)
|
|
238
|
+
parts.push(`restarting the session ${countWord(restarts)}`);
|
|
239
|
+
return `Tried: ${parts.join(', then ')}.`;
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=wake-escalation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wake-escalation.js","sourceRoot":"","sources":["../../../src/core/session/wake-escalation.ts"],"names":[],"mappings":"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"}
|
|
@@ -129,9 +129,17 @@ export declare const TURN_END_LEDGER_LAG_MS = 3000;
|
|
|
129
129
|
export declare const OPTIMISTIC_ABORT_MAX_MS = 15000;
|
|
130
130
|
/** This tab's own record that a prompt went out. */
|
|
131
131
|
export interface SendReceipt {
|
|
132
|
-
/** The submission's tab-local name — never sent anywhere.
|
|
133
|
-
* `working` state can say WHICH send it is standing on. */
|
|
132
|
+
/** The submission's tab-local name — never sent anywhere. */
|
|
134
133
|
messageId: string;
|
|
134
|
+
/**
|
|
135
|
+
* The user-message turn that owns the working indicator while this receipt
|
|
136
|
+
* is live. A direct idle send names itself. A send made during an existing
|
|
137
|
+
* response names that existing turn, so its new bubble remains pending.
|
|
138
|
+
*
|
|
139
|
+
* `undefined` preserves the original contract and falls back to
|
|
140
|
+
* `messageId`. `null` explicitly means the caller cannot identify the turn.
|
|
141
|
+
*/
|
|
142
|
+
turnId?: string | null;
|
|
135
143
|
/** ms epoch at which the send left this tab. */
|
|
136
144
|
atMs: number;
|
|
137
145
|
/**
|
|
@@ -181,6 +189,25 @@ export interface WorkingServerInput {
|
|
|
181
189
|
/** One observed runtime status frame, stamped when this tab observed it. */
|
|
182
190
|
export interface WorkingStreamInput {
|
|
183
191
|
type: 'busy' | 'retry' | 'idle';
|
|
192
|
+
/**
|
|
193
|
+
* WHO minted the frame. `'wire'` (or absent — the field is additive) means
|
|
194
|
+
* the runtime's own SSE frame reached this tab. `'local'` means the tab
|
|
195
|
+
* synthesized it: `reconcileMissingBusySessions` reading absence out of a
|
|
196
|
+
* status snapshot, `markSessionAbortedLocally` on `server.instance.disposed`,
|
|
197
|
+
* `clearSession` on a cache-ownership handoff.
|
|
198
|
+
*
|
|
199
|
+
* The distinction exists for exactly one rule: only the runtime's own idle
|
|
200
|
+
* frame may CONTRADICT the lifecycle authority (`endedByRuntime`, and the
|
|
201
|
+
* "fresher frame knows more" ordering over an open row). A local frame is an
|
|
202
|
+
* inference, and the veto it inherited is unbounded on purpose — so one
|
|
203
|
+
* fabricated idle discarded every fresh `/turn` read for the rest of a quiet
|
|
204
|
+
* turn: the busy indicator left, the composer swapped Stop for Send, and
|
|
205
|
+
* both came back only when the reply finally streamed (dev, 2026-08-24). A
|
|
206
|
+
* local frame may still ANSWER when nothing fresher exists — the repair for
|
|
207
|
+
* a missed terminal frame stays a repair — it just cannot overrule a source
|
|
208
|
+
* that can actually know.
|
|
209
|
+
*/
|
|
210
|
+
origin?: 'wire' | 'local';
|
|
184
211
|
atMs: number;
|
|
185
212
|
}
|
|
186
213
|
/**
|
|
@@ -197,6 +224,13 @@ export interface WorkingStreamInput {
|
|
|
197
224
|
* live spinner and text growing on screen, and a composer showing its send
|
|
198
225
|
* arrow. Every observer had gone quiet; the only thing still speaking was the
|
|
199
226
|
* content, and nothing was listening to it.
|
|
227
|
+
*
|
|
228
|
+
* Content reaches the tab two ways, and both stamp this: pushed (a streamed
|
|
229
|
+
* part off the SSE wire) and PULLED (a liveness-poll tail read whose hydrate
|
|
230
|
+
* shows the transcript moved with its tail still open — `sync-store.hydrate`).
|
|
231
|
+
* The pull path is what answers when the wire itself is the thing that died
|
|
232
|
+
* (essentia, 2026-08-26: stream black-holed mid-turn, stale idle frame vetoing
|
|
233
|
+
* the open turn row, transcript minutes behind).
|
|
200
234
|
*/
|
|
201
235
|
export interface WorkingActivityInput {
|
|
202
236
|
atMs: number;
|
|
@@ -205,8 +239,35 @@ export interface WorkingActivityInput {
|
|
|
205
239
|
* still going to run, and when that list was read. */
|
|
206
240
|
export interface WorkingInboxInput {
|
|
207
241
|
pending: number;
|
|
242
|
+
/** This tab's clock at ISSUE or RECEIVE time. The AGE stamp: it only ever
|
|
243
|
+
* meets `nowMs` — the same clock — in `INBOX_OBSERVATION_MAX_MS`. */
|
|
208
244
|
atMs: number;
|
|
245
|
+
/**
|
|
246
|
+
* The SERVER's clock at the observation — `observed_at` captured before the
|
|
247
|
+
* read (GET, bundle, stream frame) or after the write (`POST .../prompts`).
|
|
248
|
+
* The ORDERING stamp: it only ever meets another `serverAtMs`. Absent when
|
|
249
|
+
* the server did not supply one.
|
|
250
|
+
*
|
|
251
|
+
* Two stamps because one field served both jobs and the jobs need different
|
|
252
|
+
* clocks. Ranked against a browser stamp, an API clock ±10 minutes off
|
|
253
|
+
* either rejected every later direct read (skew ahead) or aged the
|
|
254
|
+
* observation out on arrival (skew behind) — both reproduced in PR #6957's
|
|
255
|
+
* review as a stale empty snapshot hiding a backend-confirmed queue row.
|
|
256
|
+
*/
|
|
257
|
+
serverAtMs?: number;
|
|
209
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* May `candidate` replace `current` as the session's inbox observation?
|
|
261
|
+
*
|
|
262
|
+
* ONE clock per comparison. When both observations carry the server's stamp,
|
|
263
|
+
* the server clock decides — it is the only pair drawn from one clock, and it
|
|
264
|
+
* orders a read against a write exactly (a read issued before a POST carries an
|
|
265
|
+
* older `observed_at` than the POST's response, so it can never erase it).
|
|
266
|
+
* Otherwise the browser stamps decide, as before. Ties stand aside for the
|
|
267
|
+
* candidate: two reads of the same instant agree, and the newer arrival may
|
|
268
|
+
* carry a corrected list.
|
|
269
|
+
*/
|
|
270
|
+
export declare function inboxObservationSupersedes(candidate: WorkingInboxInput, current: WorkingInboxInput | null | undefined): boolean;
|
|
210
271
|
export interface WorkingInputs {
|
|
211
272
|
optimistic: SendReceipt | null;
|
|
212
273
|
/** This tab's pending stop. `null`/absent means it is not stopping. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"working.d.ts","sourceRoot":"","sources":["../../../src/core/session/working.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,gBAAgB,EACjB,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,wEAAwE;IACxE,MAAM,EAAE,aAAa,CAAC;IACtB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AAO5C;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAE9C,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B;
|
|
1
|
+
{"version":3,"file":"working.d.ts","sourceRoot":"","sources":["../../../src/core/session/working.ts"],"names":[],"mappings":"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"}
|