@beeuni/sdk 0.1.0 → 0.3.0
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 +53 -92
- package/dist/beeuni.esm.min.js +36 -34
- package/dist/beeuni.global.js +36 -34
- package/dist/browser/cache/idb-sync-cache.js +15 -5
- package/dist/browser/session-sync/server-transcript-mirror.d.ts +7 -1
- package/dist/browser/session-sync/server-transcript-mirror.js +30 -24
- package/dist/browser/session-sync/session-sync-registry.d.ts +3 -1
- package/dist/browser/session-sync/session-sync-registry.js +48 -3
- package/dist/browser/stores/sync-store/keep-unchanged.d.ts +4 -0
- package/dist/browser/stores/sync-store/keep-unchanged.js +34 -0
- package/dist/browser/stores/sync-store.d.ts +7 -0
- package/dist/browser/stores/sync-store.js +122 -35
- package/dist/core/attachments/prompt-attachments.d.ts +4 -0
- package/dist/core/attachments/prompt-attachments.js +34 -0
- package/dist/core/capture/rules.d.ts +17 -0
- package/dist/core/capture/rules.js +27 -0
- package/dist/core/client/beeuni.d.ts +99 -34
- package/dist/core/client/beeuni.js +5 -11
- package/dist/core/client/capture.d.ts +105 -0
- package/dist/core/client/capture.js +48 -0
- package/dist/core/client/facade-catalog.d.ts +0 -4
- package/dist/core/client/facade-catalog.js +1 -5
- package/dist/core/client/facade-identity.d.ts +1 -0
- package/dist/core/client/facade-identity.js +1 -0
- package/dist/core/client/project-access-resources.d.ts +3 -1
- package/dist/core/client/project-access-resources.js +1 -1
- package/dist/core/client/project-connections.d.ts +2 -2
- package/dist/core/client/project-connections.js +2 -2
- package/dist/core/client/project-operations-admin.d.ts +4 -4
- package/dist/core/client/project-operations-review.d.ts +2 -3
- package/dist/core/client/project-operations-review.js +1 -0
- package/dist/core/client/project-operations-workspace.d.ts +4 -4
- package/dist/core/client/project-operations-workspace.js +1 -1
- package/dist/core/client/project-operations.d.ts +9 -19
- package/dist/core/client/project-operations.js +2 -6
- package/dist/core/client/project-platform-security.d.ts +1 -1
- package/dist/core/client/project-platform-settings.d.ts +1 -1
- package/dist/core/client/session-context.d.ts +2 -0
- package/dist/core/client/session-handle.d.ts +13 -0
- package/dist/core/client/session-lifecycle-resources.d.ts +11 -0
- package/dist/core/client/session-lifecycle-resources.js +4 -0
- package/dist/core/client/session-lifecycle-security.d.ts +2 -0
- package/dist/core/client/session-lifecycle-security.js +1 -0
- package/dist/core/client/session-readiness.d.ts +2 -0
- package/dist/core/client/session-readiness.js +20 -1
- package/dist/core/http/api-client.d.ts +1 -7
- package/dist/core/http/api-client.js +2 -37
- package/dist/core/http/auth.d.ts +2 -4
- package/dist/core/http/auth.js +2 -8
- package/dist/core/http/config.d.ts +2 -0
- package/dist/core/http/response-error.js +26 -11
- package/dist/core/http/transport.js +6 -1
- package/dist/core/models/composer-model.d.ts +14 -0
- package/dist/core/models/composer-model.js +21 -1
- package/dist/core/rest/platform-client/capture.d.ts +363 -0
- package/dist/core/rest/platform-client/capture.js +116 -0
- package/dist/core/rest/platform-client/client-policy.d.ts +8 -0
- package/dist/core/rest/platform-client/client-policy.js +30 -0
- package/dist/core/rest/platform-client/index.d.ts +4 -4
- package/dist/core/rest/platform-client/index.js +4 -4
- package/dist/core/rest/platform-client/lifecycle.js +18 -12
- package/dist/core/rest/platform-client/shared.d.ts +5 -0
- package/dist/core/rest/platform-client/shared.js +18 -0
- package/dist/core/rest/platform-client/types.d.ts +1 -1
- package/dist/core/rest/projects-client/account-secret-resources.d.ts +2 -1
- package/dist/core/rest/projects-client/accounts.d.ts +34 -0
- package/dist/core/rest/projects-client/accounts.js +10 -0
- package/dist/core/rest/projects-client/admin-providers.d.ts +0 -61
- package/dist/core/rest/projects-client/admin-providers.js +0 -6
- package/dist/core/rest/projects-client/agent-config.d.ts +3 -0
- package/dist/core/rest/projects-client/apps-fleet.d.ts +5 -1
- package/dist/core/rest/projects-client/apps-fleet.js +2 -2
- package/dist/core/rest/projects-client/apps.d.ts +11 -1
- package/dist/core/rest/projects-client/change-requests.d.ts +2 -0
- package/dist/core/rest/projects-client/change-requests.js +2 -0
- package/dist/core/rest/projects-client/connectors.d.ts +13 -55
- package/dist/core/rest/projects-client/connectors.js +5 -29
- package/dist/core/rest/projects-client/files.d.ts +3 -0
- package/dist/core/rest/projects-client/files.js +4 -0
- package/dist/core/rest/projects-client/gateway.d.ts +5 -0
- package/dist/core/rest/projects-client/git-backend.d.ts +1 -10
- package/dist/core/rest/projects-client/git-backend.js +0 -10
- package/dist/core/rest/projects-client/iam-actions.d.ts +76 -0
- package/dist/core/rest/projects-client/iam-actions.js +101 -0
- package/dist/core/rest/projects-client/iam-sso.d.ts +0 -10
- package/dist/core/rest/projects-client/iam-sso.js +0 -3
- package/dist/core/rest/projects-client/iam.d.ts +1 -0
- package/dist/core/rest/projects-client/iam.js +1 -0
- package/dist/core/rest/projects-client/index.d.ts +1 -4
- package/dist/core/rest/projects-client/index.js +1 -4
- package/dist/core/rest/projects-client/notifications.d.ts +1 -1
- package/dist/core/rest/projects-client/notifications.js +4 -0
- package/dist/core/rest/projects-client/projects.d.ts +4 -2
- package/dist/core/rest/projects-client/projects.js +4 -2
- package/dist/core/rest/projects-client/review-items.d.ts +2 -0
- package/dist/core/rest/projects-client/review-items.js +4 -0
- package/dist/core/rest/projects-client/review.d.ts +17 -3
- package/dist/core/rest/projects-client/review.js +11 -0
- package/dist/core/rest/projects-client/sandbox.d.ts +8 -9
- package/dist/core/rest/projects-client/secrets.d.ts +3 -0
- package/dist/core/rest/projects-client/session-attachments.js +14 -1
- package/dist/core/rest/projects-client/session-sandbox.d.ts +1 -1
- package/dist/core/rest/projects-client/sessions.d.ts +31 -4
- package/dist/core/rest/projects-client/sessions.js +34 -4
- package/dist/core/runtime/runtime-rest-client.js +1 -1
- package/dist/core/runtime/runtime-types.d.ts +1 -0
- package/dist/core/session/control-stream.d.ts +1 -0
- package/dist/core/session/control-stream.js +18 -1
- package/dist/core/session/open-bundle.d.ts +4 -4
- package/dist/core/session/open-bundle.js +29 -46
- package/dist/core/session/turn-end-watch.d.ts +47 -0
- package/dist/core/session/turn-end-watch.js +141 -0
- package/dist/core/session-log/guard.d.ts +6 -0
- package/dist/core/session-log/guard.js +109 -0
- package/dist/core/session-log/index.d.ts +7 -0
- package/dist/core/session-log/index.js +5 -0
- package/dist/core/session-log/saved-log.d.ts +10 -0
- package/dist/core/session-log/saved-log.js +25 -0
- package/dist/core/session-log/source.d.ts +25 -0
- package/dist/core/session-log/source.js +30 -0
- package/dist/core/session-log/store.d.ts +21 -0
- package/dist/core/session-log/store.js +126 -0
- package/dist/core/session-log/tool-call.d.ts +11 -0
- package/dist/core/session-log/tool-call.js +65 -0
- package/dist/core/session-log/turns/blocks.d.ts +60 -0
- package/dist/core/session-log/turns/blocks.js +124 -0
- package/dist/core/session-log/turns/history.d.ts +32 -0
- package/dist/core/session-log/turns/history.js +99 -0
- package/dist/core/session-log/turns/index.d.ts +4 -0
- package/dist/core/session-log/turns/index.js +4 -0
- package/dist/core/session-log/turns/metrics.d.ts +21 -0
- package/dist/core/session-log/turns/metrics.js +29 -0
- package/dist/core/session-log/turns/turn.d.ts +55 -0
- package/dist/core/session-log/turns/turn.js +279 -0
- package/dist/core/session-log/turns/v1-parts.d.ts +8 -0
- package/dist/core/session-log/turns/v1-parts.js +43 -0
- package/dist/core/session-log/types.d.ts +264 -0
- package/dist/core/session-log/types.js +6 -0
- package/dist/core/session-log/v1-view.d.ts +13 -0
- package/dist/core/session-log/v1-view.js +215 -0
- package/dist/core/session-log/v1.d.ts +31 -0
- package/dist/core/session-log/v1.js +473 -0
- package/dist/core/session-sync/copy-store-types.d.ts +19 -0
- package/dist/core/session-sync/copy-store-types.js +1 -0
- package/dist/core/session-sync/saved-copy-store.js +25 -4
- package/dist/core/session-sync/saved-transcript.d.ts +15 -1
- package/dist/core/session-sync/saved-transcript.js +55 -0
- package/dist/core/session-sync/session-sync-controller.js +3 -0
- package/dist/core/stream/event-stream.js +2 -2
- package/dist/core/turns/classify.d.ts +2 -1
- package/dist/core/turns/classify.js +7 -3
- package/dist/core/turns/edit-blocks.d.ts +1 -0
- package/dist/core/turns/edit-blocks.js +15 -0
- package/dist/core/turns/parts.d.ts +3 -2
- package/dist/core/turns/parts.js +4 -2
- package/dist/core/turns/segments/burst-summary.d.ts +1 -0
- package/dist/core/turns/segments/burst-summary.js +24 -0
- package/dist/core/turns/segments/group-steps.d.ts +4 -3
- package/dist/core/turns/segments/group-steps.js +9 -6
- package/dist/core/turns/segments/index.d.ts +1 -0
- package/dist/core/turns/segments/index.js +1 -0
- package/dist/core/turns/segments/narration.d.ts +5 -4
- package/dist/core/turns/segments/narration.js +12 -3
- package/dist/core/turns/segments/session-activity-groups.d.ts +2 -1
- package/dist/core/turns/segments/session-activity-groups.js +3 -1
- package/dist/core/turns/segments/step-label.d.ts +2 -1
- package/dist/core/turns/segments/step-label.js +3 -1
- package/dist/core/turns/segments/work-split.d.ts +10 -0
- package/dist/core/turns/segments/work-split.js +40 -0
- package/dist/core/turns/segments/working-turn.d.ts +4 -2
- package/dist/core/turns/segments/working-turn.js +9 -8
- package/dist/core/turns/state.d.ts +2 -7
- package/dist/core/turns/state.js +28 -134
- package/dist/core/turns/tool-kind.d.ts +1 -1
- package/dist/core/turns/tool-kind.js +3 -2
- package/dist/core/turns/tool-registry.js +1 -0
- package/dist/core/turns/tools/tool-meta.d.ts +3 -2
- package/dist/core/turns/tools/tool-meta.js +5 -2
- package/dist/core/turns/tools/tool-outcome.d.ts +2 -1
- package/dist/core/turns/tools/tool-outcome.js +3 -1
- package/dist/core/turns/types.d.ts +1 -1
- package/dist/core/turns/view-model.js +1 -13
- package/dist/core/warm-session-pool.d.ts +29 -0
- package/dist/core/warm-session-pool.js +127 -0
- package/dist/genui/catalog.d.ts +28 -0
- package/dist/genui/catalog.js +396 -0
- package/dist/genui/expansion.d.ts +3 -0
- package/dist/genui/expansion.js +295 -0
- package/dist/genui/fence-entry.d.ts +2 -0
- package/dist/genui/fence-entry.js +1 -0
- package/dist/genui/fence.d.ts +21 -0
- package/dist/genui/fence.js +138 -0
- package/dist/genui/index.d.ts +6 -0
- package/dist/genui/index.js +6 -0
- package/dist/genui/markdown.d.ts +12 -0
- package/dist/genui/markdown.js +104 -0
- package/dist/genui/parse.d.ts +6 -0
- package/dist/genui/parse.js +75 -0
- package/dist/genui/prompt.d.ts +2 -0
- package/dist/genui/prompt.js +206 -0
- package/dist/genui/react/default-components.d.ts +2 -0
- package/dist/genui/react/default-components.js +72 -0
- package/dist/genui/react/default-components.test.d.ts +1 -0
- package/dist/genui/react/default-components.test.js +94 -0
- package/dist/genui/react/genui-block-disabled.test.d.ts +1 -0
- package/dist/genui/react/genui-block-disabled.test.js +50 -0
- package/dist/genui/react/genui-block.d.ts +28 -0
- package/dist/genui/react/genui-block.js +91 -0
- package/dist/genui/react/genui-block.test.d.ts +1 -0
- package/dist/genui/react/genui-block.test.js +205 -0
- package/dist/genui/react/index.d.ts +2 -0
- package/dist/genui/react/index.js +2 -0
- package/dist/genui/share.d.ts +5 -0
- package/dist/genui/share.js +30 -0
- package/dist/genui/test-fixtures.d.ts +2 -0
- package/dist/genui/test-fixtures.js +16 -0
- package/dist/genui/types.d.ts +29 -0
- package/dist/genui/types.js +1 -0
- package/dist/genui/urls.d.ts +1 -0
- package/dist/genui/urls.js +18 -0
- package/dist/genui/validate.d.ts +9 -0
- package/dist/genui/validate.js +116 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/internal/connector-catalog.d.ts +48 -0
- package/dist/internal/connector-catalog.js +27 -0
- package/dist/internal/host-configuration.d.ts +22 -0
- package/dist/internal/host-configuration.js +28 -0
- package/dist/internal/platform-admin-react.d.ts +12 -0
- package/dist/internal/platform-admin-react.js +13 -0
- package/dist/internal/platform-admin.d.ts +9 -0
- package/dist/internal/platform-admin.js +9 -0
- package/dist/platform/ui.d.ts +8 -2
- package/dist/platform/ui.js +19 -4
- package/dist/react/chat/use-chat-turns.d.ts +1 -1
- package/dist/react/human-presence.d.ts +9 -0
- package/dist/react/human-presence.js +12 -0
- package/dist/react/index.d.ts +4 -13
- package/dist/react/index.js +4 -13
- package/dist/react/opencode.d.ts +1 -0
- package/dist/react/opencode.js +1 -0
- package/dist/react/query-contracts.d.ts +6 -0
- package/dist/react/query-contracts.js +6 -0
- package/dist/react/query-keys.d.ts +17 -2
- package/dist/react/query-keys.js +24 -2
- package/dist/react/reset-identity-state.js +2 -0
- package/dist/react/session-cache-write.d.ts +1 -0
- package/dist/react/session-cache-write.js +20 -0
- package/dist/react/session-transcript-subscription.js +3 -1
- package/dist/react/sign-in-with-beeuni.d.ts +6 -6
- package/dist/react/turn-end-handoff.d.ts +13 -0
- package/dist/react/turn-end-handoff.js +101 -0
- package/dist/react/use-admin-providers.d.ts +3 -6
- package/dist/react/use-admin-providers.js +1 -11
- package/dist/react/use-capture.d.ts +47 -0
- package/dist/react/use-capture.js +173 -0
- package/dist/react/use-feature-flag.js +1 -0
- package/dist/react/use-opencode-events/handle-event.d.ts +1 -0
- package/dist/react/use-opencode-events/handle-event.js +5 -0
- package/dist/react/use-opencode-events/handle-interaction-event.js +8 -3
- package/dist/react/use-opencode-events/handle-session-event.js +13 -8
- package/dist/react/use-opencode-events/handler-context.d.ts +1 -0
- package/dist/react/use-opencode-events/helpers.d.ts +1 -0
- package/dist/react/use-opencode-events/helpers.js +11 -1
- package/dist/react/use-opencode-events/index.js +1 -0
- package/dist/react/use-opencode-local.d.ts +5 -1
- package/dist/react/use-opencode-local.js +15 -2
- package/dist/react/use-opencode-sessions/commands.d.ts +11 -1
- package/dist/react/use-opencode-sessions/commands.js +21 -1
- package/dist/react/use-opencode-sessions/permissions.js +28 -1
- package/dist/react/use-project-sessions.d.ts +1 -1
- package/dist/react/use-project-sessions.js +6 -5
- package/dist/react/use-prompt-attachments.js +1 -0
- package/dist/react/use-review-summary.d.ts +13 -0
- package/dist/react/use-review-summary.js +32 -0
- package/dist/react/use-runtime-reconnect.js +1 -1
- package/dist/react/use-session-list-state.d.ts +6 -0
- package/dist/react/use-session-list-state.js +33 -0
- package/dist/react/use-session-log.d.ts +16 -0
- package/dist/react/use-session-log.js +143 -0
- package/dist/react/use-session-messages.d.ts +2 -1
- package/dist/react/use-session-messages.js +15 -14
- package/dist/react/use-session-stream.js +12 -1
- package/dist/react/use-session-sync.d.ts +2 -2
- package/dist/react/use-session-sync.js +10 -8
- package/dist/react/use-session-transcript-history.js +2 -12
- package/dist/react/use-session-working.d.ts +2 -0
- package/dist/react/use-session-working.js +10 -0
- package/dist/react/use-session.d.ts +6 -0
- package/dist/react/use-session.js +88 -6
- package/package.json +62 -8
|
@@ -2,6 +2,8 @@ import { ApiError, backendApi } from '../../http/api-client.js';
|
|
|
2
2
|
import { markSessionFresh } from '../../http/fresh-sessions.js';
|
|
3
3
|
import { currentSavedCopyStore } from '../../session-sync/saved-copy-store.js';
|
|
4
4
|
import { noteSessionStopped } from '../../http/session-stopped.js';
|
|
5
|
+
import { isSessionLogPage } from '../../session-log/guard.js';
|
|
6
|
+
import { loadSessionLogPage } from '../../session-log/source.js';
|
|
5
7
|
import { unwrap } from './shared.js';
|
|
6
8
|
export function sessionParentId(session) {
|
|
7
9
|
const parent = typeof session.parent_session_id === 'string'
|
|
@@ -34,6 +36,8 @@ function projectSessionListQuery(options) {
|
|
|
34
36
|
params.set('q', q);
|
|
35
37
|
for (const label of options?.labels ?? [])
|
|
36
38
|
params.append('label', label);
|
|
39
|
+
if (options?.view)
|
|
40
|
+
params.set(options.view, 'only');
|
|
37
41
|
return params.size > 0 ? `?${params}` : '';
|
|
38
42
|
}
|
|
39
43
|
export async function listProjectSessionsPage(projectId, options) {
|
|
@@ -63,6 +67,12 @@ export async function setSessionWatch(projectId, sessionId, watching) {
|
|
|
63
67
|
watching,
|
|
64
68
|
}));
|
|
65
69
|
}
|
|
70
|
+
export async function setSessionPinned(projectId, sessionId, pinned) {
|
|
71
|
+
return unwrap(await backendApi.put(`/projects/${projectId}/sessions/${sessionId}/pin`, { pinned }));
|
|
72
|
+
}
|
|
73
|
+
export async function setSessionArchived(projectId, sessionId, archived) {
|
|
74
|
+
return unwrap(await backendApi.put(`/projects/${projectId}/sessions/${sessionId}/archive`, { archived }));
|
|
75
|
+
}
|
|
66
76
|
export function resolvePublicShareUrl(share, origin) {
|
|
67
77
|
const raw = share.public_url ?? share.public_path ?? share.proxy_path ?? share.public_token ?? '';
|
|
68
78
|
if (!raw)
|
|
@@ -165,8 +175,22 @@ export async function getSessionTranscriptSync(projectId, sessionId, options) {
|
|
|
165
175
|
search.set('child', options.child);
|
|
166
176
|
return unwrap(await backendApi.get(`/projects/${projectId}/sessions/${sessionId}/transcript?${search.toString()}`, { showErrors: false, signal: options?.signal }));
|
|
167
177
|
}
|
|
168
|
-
export async function
|
|
169
|
-
|
|
178
|
+
export async function getSessionLogPage(projectId, sessionId, query = {}, options) {
|
|
179
|
+
let page;
|
|
180
|
+
try {
|
|
181
|
+
page = await loadSessionLogPage(projectId, sessionId, query, options?.signal);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error?.status === 404)
|
|
185
|
+
return null;
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
if (!isSessionLogPage(page))
|
|
189
|
+
throw new Error('The response is not a session log page');
|
|
190
|
+
return page;
|
|
191
|
+
}
|
|
192
|
+
export async function getSessionTurn(projectId, sessionId, options) {
|
|
193
|
+
return unwrap(await backendApi.get(`/projects/${projectId}/sessions/${sessionId}/turn`, options?.showErrors === false ? { showErrors: false } : undefined));
|
|
170
194
|
}
|
|
171
195
|
export async function getSessionOpenBundle(projectId, sessionId, options) {
|
|
172
196
|
const search = new URLSearchParams();
|
|
@@ -222,8 +246,14 @@ export async function deleteProjectSession(projectId, sessionId) {
|
|
|
222
246
|
void currentSavedCopyStore()?.remove(projectId, sessionId);
|
|
223
247
|
return result;
|
|
224
248
|
}
|
|
225
|
-
export async function
|
|
226
|
-
return unwrap(await backendApi.post(`/projects/${projectId}/sessions/${sessionId}/
|
|
249
|
+
export async function recoverProjectSession(projectId, sessionId) {
|
|
250
|
+
return unwrap(await backendApi.post(`/projects/${projectId}/sessions/${sessionId}/recover`, {}, { showErrors: false }));
|
|
251
|
+
}
|
|
252
|
+
export async function restoreProjectSession(projectId, sessionId) {
|
|
253
|
+
return unwrap(await backendApi.post(`/projects/${projectId}/sessions/${sessionId}/restore`, {}, { showErrors: false }));
|
|
254
|
+
}
|
|
255
|
+
export async function restartProjectSession(projectId, sessionId, _opts = {}) {
|
|
256
|
+
return unwrap(await backendApi.post(`/projects/${projectId}/sessions/${sessionId}/restart`, {}));
|
|
227
257
|
}
|
|
228
258
|
export async function stopProjectSession(projectId, sessionId) {
|
|
229
259
|
const stopped = unwrap(await backendApi.post(`/projects/${projectId}/sessions/${sessionId}/stop`, {}));
|
|
@@ -158,7 +158,7 @@ export function fetchEventTransport(fetchFn = globalThis.fetch) {
|
|
|
158
158
|
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
159
159
|
const cancel = () => {
|
|
160
160
|
try {
|
|
161
|
-
|
|
161
|
+
reader.cancel().catch(() => { });
|
|
162
162
|
}
|
|
163
163
|
catch {
|
|
164
164
|
}
|
|
@@ -16,6 +16,8 @@ export function openSessionStream(options) {
|
|
|
16
16
|
lastHealth: null,
|
|
17
17
|
runtimeRefs: 0,
|
|
18
18
|
connectedWithRuntime: false,
|
|
19
|
+
logRefs: 0,
|
|
20
|
+
connectedWithLog: false,
|
|
19
21
|
tabId: null,
|
|
20
22
|
authoritative: false,
|
|
21
23
|
reconnectNow: false,
|
|
@@ -33,6 +35,10 @@ export function openSessionStream(options) {
|
|
|
33
35
|
if (!target.connectedWithRuntime)
|
|
34
36
|
reconnect = true;
|
|
35
37
|
}
|
|
38
|
+
if (options.schema === 'v2')
|
|
39
|
+
target.logRefs += 1;
|
|
40
|
+
if (target.runtimeRefs > 0 && target.logRefs > 0 && !target.connectedWithLog)
|
|
41
|
+
reconnect = true;
|
|
36
42
|
if (options.tabId && target.tabId !== options.tabId) {
|
|
37
43
|
target.tabId = options.tabId;
|
|
38
44
|
reconnect = true;
|
|
@@ -66,8 +72,15 @@ export function openSessionStream(options) {
|
|
|
66
72
|
target.subscribers.delete(options);
|
|
67
73
|
if (options.runtime)
|
|
68
74
|
target.runtimeRefs -= 1;
|
|
69
|
-
if (
|
|
75
|
+
if (options.schema === 'v2')
|
|
76
|
+
target.logRefs -= 1;
|
|
77
|
+
if (target.subscribers.size > 0) {
|
|
78
|
+
if (target.connectedWithLog && (target.logRefs === 0 || target.runtimeRefs === 0) && target.attempt) {
|
|
79
|
+
target.reconnectNow = true;
|
|
80
|
+
target.attempt.abort();
|
|
81
|
+
}
|
|
70
82
|
return;
|
|
83
|
+
}
|
|
71
84
|
target.abort.abort();
|
|
72
85
|
if (streams.get(key) === target)
|
|
73
86
|
streams.delete(key);
|
|
@@ -132,10 +145,14 @@ async function run(options, shared) {
|
|
|
132
145
|
arm();
|
|
133
146
|
const withRuntime = shared.runtimeRefs > 0;
|
|
134
147
|
shared.connectedWithRuntime = withRuntime;
|
|
148
|
+
const withLog = withRuntime && shared.logRefs > 0;
|
|
149
|
+
shared.connectedWithLog = withLog;
|
|
135
150
|
try {
|
|
136
151
|
const url = new URL(`${platformConfig().backendUrl.replace(/\/$/, '')}/projects/${encodeURIComponent(options.projectId)}/sessions/${encodeURIComponent(options.sessionId)}/events`);
|
|
137
152
|
if (!withRuntime)
|
|
138
153
|
url.searchParams.set('channels', 'control');
|
|
154
|
+
if (withLog)
|
|
155
|
+
url.searchParams.set('schema', 'v2');
|
|
139
156
|
if (shared.tabId)
|
|
140
157
|
url.searchParams.set('tab_id', shared.tabId);
|
|
141
158
|
if (withRuntime && seq !== null && epoch) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type SessionAudit, type SessionOpenBundle, type SessionPrompt, type SessionTranscriptSyncEnvelope, type SessionTurn, type SessionTurnEnded, type SessionTurnFailure } from '../rest/projects-client/sessions.js';
|
|
2
2
|
export declare const OPEN_BUNDLE_SHARE_MS = 5000;
|
|
3
|
-
export declare const OPEN_BUNDLE_TRANSCRIPT_TTL_MS = 60000;
|
|
4
3
|
export declare const OPEN_BUNDLE_TRANSCRIPT_LIMIT = 40;
|
|
4
|
+
export declare const SAVED_WINDOW_HOLD_MS: number;
|
|
5
|
+
export declare function holdSavedWindow(projectId: string, sessionId: string, envelope: SessionTranscriptSyncEnvelope, nowMs?: number): void;
|
|
6
|
+
export declare function heldSavedWindow(projectId: string, sessionId: string, nowMs?: number): SessionTranscriptSyncEnvelope | null;
|
|
5
7
|
export declare function resetSessionOpenBundles(): void;
|
|
6
8
|
export interface OpenSessionBundleOptions {
|
|
7
9
|
transcript?: number;
|
|
@@ -9,16 +11,14 @@ export interface OpenSessionBundleOptions {
|
|
|
9
11
|
}
|
|
10
12
|
export declare function openSessionBundle(projectId: string, sessionId: string, options?: OpenSessionBundleOptions): void;
|
|
11
13
|
export declare function claimOpenBundle(projectId: string, sessionId: string, nowMs?: number): Promise<SessionOpenBundle | null> | null;
|
|
12
|
-
export declare function settledOpenBundle(projectId: string, sessionId: string, nowMs?: number): SessionOpenBundle | null;
|
|
13
14
|
export interface OpenBundleTurnObservation {
|
|
14
15
|
turns: SessionTurn[];
|
|
15
16
|
last_ended: SessionTurnEnded | undefined;
|
|
16
17
|
recent_failures?: SessionTurnFailure[];
|
|
18
|
+
can_stop?: boolean;
|
|
17
19
|
atMs: number;
|
|
18
20
|
}
|
|
19
21
|
export declare function openBundleTurn(bundle: SessionOpenBundle): OpenBundleTurnObservation | null;
|
|
20
22
|
export declare function openBundleQueue(bundle: SessionOpenBundle): SessionPrompt[] | null;
|
|
21
23
|
export declare function openBundleAudit(bundle: SessionOpenBundle): SessionAudit | null;
|
|
22
24
|
export declare function openBundleHistory(bundle: SessionOpenBundle): SessionTranscriptSyncEnvelope | null;
|
|
23
|
-
export declare function takeOpenBundleTranscriptAbsence(projectId: string, sessionId: string, nowMs?: number): boolean;
|
|
24
|
-
export declare function takeOpenBundleTranscript(projectId: string, sessionId: string, nowMs?: number): SessionTranscriptSyncEnvelope | null;
|
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
import { getSessionOpenBundle, } from '../rest/projects-client/sessions.js';
|
|
2
2
|
export const OPEN_BUNDLE_SHARE_MS = 5_000;
|
|
3
|
-
export const OPEN_BUNDLE_TRANSCRIPT_TTL_MS = 60_000;
|
|
4
3
|
export const OPEN_BUNDLE_TRANSCRIPT_LIMIT = 40;
|
|
4
|
+
export const SAVED_WINDOW_HOLD_MS = 5 * 60_000;
|
|
5
|
+
const HELD_WINDOW_CAP = 16;
|
|
6
|
+
const heldWindows = new Map();
|
|
7
|
+
export function holdSavedWindow(projectId, sessionId, envelope, nowMs = Date.now()) {
|
|
8
|
+
const key = scopeKey(projectId, sessionId);
|
|
9
|
+
heldWindows.delete(key);
|
|
10
|
+
heldWindows.set(key, { envelope, atMs: nowMs });
|
|
11
|
+
while (heldWindows.size > HELD_WINDOW_CAP) {
|
|
12
|
+
const oldest = heldWindows.keys().next().value;
|
|
13
|
+
if (oldest === undefined)
|
|
14
|
+
break;
|
|
15
|
+
heldWindows.delete(oldest);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function heldSavedWindow(projectId, sessionId, nowMs = Date.now()) {
|
|
19
|
+
const held = heldWindows.get(scopeKey(projectId, sessionId));
|
|
20
|
+
if (!held)
|
|
21
|
+
return null;
|
|
22
|
+
if (nowMs - held.atMs > SAVED_WINDOW_HOLD_MS) {
|
|
23
|
+
heldWindows.delete(scopeKey(projectId, sessionId));
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return held.envelope;
|
|
27
|
+
}
|
|
5
28
|
const entries = new Map();
|
|
6
|
-
const transcripts = new Map();
|
|
7
|
-
const absentTranscripts = new Map();
|
|
8
29
|
function scopeKey(projectId, sessionId) {
|
|
9
30
|
return `${projectId}/${sessionId}`;
|
|
10
31
|
}
|
|
11
32
|
export function resetSessionOpenBundles() {
|
|
12
33
|
entries.clear();
|
|
13
|
-
|
|
14
|
-
absentTranscripts.clear();
|
|
34
|
+
heldWindows.clear();
|
|
15
35
|
}
|
|
16
36
|
export function openSessionBundle(projectId, sessionId, options = {}) {
|
|
17
37
|
if (!projectId || !sessionId)
|
|
@@ -26,17 +46,12 @@ export function openSessionBundle(projectId, sessionId, options = {}) {
|
|
|
26
46
|
startedAtMs: nowMs,
|
|
27
47
|
settledAtMs: null,
|
|
28
48
|
promise: getSessionOpenBundle(projectId, sessionId, {
|
|
29
|
-
transcript: options.transcript ??
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
stashTranscript(key, bundle, now());
|
|
33
|
-
return bundle;
|
|
34
|
-
})
|
|
35
|
-
.catch(() => null),
|
|
49
|
+
transcript: options.transcript ??
|
|
50
|
+
(heldSavedWindow(projectId, sessionId, nowMs) ? 0 : OPEN_BUNDLE_TRANSCRIPT_LIMIT),
|
|
51
|
+
}).catch(() => null),
|
|
36
52
|
};
|
|
37
53
|
entry.promise = entry.promise.then((bundle) => {
|
|
38
54
|
entry.settledAtMs = now();
|
|
39
|
-
entry.bundle = bundle;
|
|
40
55
|
return bundle;
|
|
41
56
|
});
|
|
42
57
|
entries.set(key, entry);
|
|
@@ -59,10 +74,6 @@ export function claimOpenBundle(projectId, sessionId, nowMs = Date.now()) {
|
|
|
59
74
|
}
|
|
60
75
|
return entry.promise;
|
|
61
76
|
}
|
|
62
|
-
export function settledOpenBundle(projectId, sessionId, nowMs = Date.now()) {
|
|
63
|
-
const entry = entries.get(scopeKey(projectId, sessionId));
|
|
64
|
-
return entry && entry.settledAtMs !== null && claimable(entry, nowMs) ? (entry.bundle ?? null) : null;
|
|
65
|
-
}
|
|
66
77
|
export function openBundleTurn(bundle) {
|
|
67
78
|
const turn = bundle.turn;
|
|
68
79
|
if (!turn || turn.known !== true)
|
|
@@ -72,6 +83,7 @@ export function openBundleTurn(bundle) {
|
|
|
72
83
|
turns: turn.turns ?? [],
|
|
73
84
|
last_ended: turn.last_ended,
|
|
74
85
|
recent_failures: turn.recent_failures,
|
|
86
|
+
...(typeof turn.can_stop === 'boolean' ? { can_stop: turn.can_stop } : {}),
|
|
75
87
|
atMs: Number.isFinite(observedAtMs) ? observedAtMs : Date.now(),
|
|
76
88
|
};
|
|
77
89
|
}
|
|
@@ -104,32 +116,3 @@ export function openBundleHistory(bundle) {
|
|
|
104
116
|
const savedRoot = envelope.runtime_session_id ?? envelope.opencode_session_id;
|
|
105
117
|
return root && savedRoot === root ? envelope : null;
|
|
106
118
|
}
|
|
107
|
-
function stashTranscript(key, bundle, nowMs) {
|
|
108
|
-
const transcript = bundle.transcript;
|
|
109
|
-
if (!transcript || transcript.known !== true || transcript.requested !== true)
|
|
110
|
-
return;
|
|
111
|
-
if (!transcript.available || transcript.messages.length === 0) {
|
|
112
|
-
absentTranscripts.set(key, nowMs);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const { known: _known, requested: _requested, ...envelope } = transcript;
|
|
116
|
-
transcripts.set(key, { envelope, stashedAtMs: nowMs });
|
|
117
|
-
}
|
|
118
|
-
export function takeOpenBundleTranscriptAbsence(projectId, sessionId, nowMs = Date.now()) {
|
|
119
|
-
const key = scopeKey(projectId, sessionId);
|
|
120
|
-
const answeredAtMs = absentTranscripts.get(key);
|
|
121
|
-
if (answeredAtMs === undefined)
|
|
122
|
-
return false;
|
|
123
|
-
absentTranscripts.delete(key);
|
|
124
|
-
return nowMs - answeredAtMs <= OPEN_BUNDLE_TRANSCRIPT_TTL_MS;
|
|
125
|
-
}
|
|
126
|
-
export function takeOpenBundleTranscript(projectId, sessionId, nowMs = Date.now()) {
|
|
127
|
-
const key = scopeKey(projectId, sessionId);
|
|
128
|
-
const stash = transcripts.get(key);
|
|
129
|
-
if (!stash)
|
|
130
|
-
return null;
|
|
131
|
-
transcripts.delete(key);
|
|
132
|
-
if (nowMs - stash.stashedAtMs > OPEN_BUNDLE_TRANSCRIPT_TTL_MS)
|
|
133
|
-
return null;
|
|
134
|
-
return stash.envelope;
|
|
135
|
-
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { SessionTurnEndError, SessionTurnStatus } from '../rest/projects-client/sessions.js';
|
|
2
|
+
export declare const TURN_END_WATCH_FIRST_READ_MS = 1000;
|
|
3
|
+
export declare const TURN_END_WATCH_POLL_MS = 5000;
|
|
4
|
+
export declare const TURN_END_WATCH_LONG_TURN_MS: number;
|
|
5
|
+
export declare const TURN_END_WATCH_SLOW_POLL_MS = 15000;
|
|
6
|
+
export declare const TURN_END_WATCH_START_MS = 60000;
|
|
7
|
+
export declare const TURN_END_WATCH_MAX_MS: number;
|
|
8
|
+
export interface TurnEndHandoff {
|
|
9
|
+
projectId: string;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
openTurnToken: string | null;
|
|
12
|
+
lastEndedToken: string | null;
|
|
13
|
+
title?: () => string | undefined;
|
|
14
|
+
}
|
|
15
|
+
export type TurnEndOutcome = {
|
|
16
|
+
kind: 'completed';
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'failed';
|
|
19
|
+
error: SessionTurnEndError | null;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'stopped';
|
|
22
|
+
};
|
|
23
|
+
export type TurnEndVerdict = {
|
|
24
|
+
state: 'running';
|
|
25
|
+
} | {
|
|
26
|
+
state: 'waiting';
|
|
27
|
+
} | {
|
|
28
|
+
state: 'ended';
|
|
29
|
+
outcome: TurnEndOutcome;
|
|
30
|
+
};
|
|
31
|
+
export declare function readTurnEnd(handoff: TurnEndHandoff, read: SessionTurnStatus, sawOpen: boolean): TurnEndVerdict;
|
|
32
|
+
export interface TurnEndWatchDeps {
|
|
33
|
+
readTurn(projectId: string, sessionId: string): Promise<SessionTurnStatus>;
|
|
34
|
+
subscribe?(projectId: string, sessionId: string, onRead: (read: SessionTurnStatus) => void): () => void;
|
|
35
|
+
pushLive?(projectId: string, sessionId: string): boolean;
|
|
36
|
+
onEnded(handoff: TurnEndHandoff, outcome: TurnEndOutcome, watchedSinceMs: number): void;
|
|
37
|
+
now?: () => number;
|
|
38
|
+
setTimer?: (fn: () => void, ms: number) => unknown;
|
|
39
|
+
clearTimer?: (handle: unknown) => void;
|
|
40
|
+
}
|
|
41
|
+
export interface TurnEndWatch {
|
|
42
|
+
watch(handoff: TurnEndHandoff): void;
|
|
43
|
+
release(projectId: string, sessionId: string): void;
|
|
44
|
+
releaseAll(): void;
|
|
45
|
+
watching(): string[];
|
|
46
|
+
}
|
|
47
|
+
export declare function createTurnEndWatch(deps: TurnEndWatchDeps): TurnEndWatch;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { isAbortError } from '../http/abort-error.js';
|
|
2
|
+
export const TURN_END_WATCH_FIRST_READ_MS = 1_000;
|
|
3
|
+
export const TURN_END_WATCH_POLL_MS = 5_000;
|
|
4
|
+
export const TURN_END_WATCH_LONG_TURN_MS = 5 * 60_000;
|
|
5
|
+
export const TURN_END_WATCH_SLOW_POLL_MS = 15_000;
|
|
6
|
+
export const TURN_END_WATCH_START_MS = 60_000;
|
|
7
|
+
export const TURN_END_WATCH_MAX_MS = 12 * 60 * 60_000;
|
|
8
|
+
function outcomeOf(read) {
|
|
9
|
+
const ended = read.last_ended;
|
|
10
|
+
if (!ended)
|
|
11
|
+
return { kind: 'completed' };
|
|
12
|
+
const reason = ended.end_reason;
|
|
13
|
+
if (reason === 'completed' || reason === 'unknown' || reason === null)
|
|
14
|
+
return { kind: 'completed' };
|
|
15
|
+
const error = ended.error;
|
|
16
|
+
if (error) {
|
|
17
|
+
if (isAbortError({ name: error.name ?? undefined, message: error.message ?? undefined })) {
|
|
18
|
+
return { kind: 'stopped' };
|
|
19
|
+
}
|
|
20
|
+
return { kind: 'failed', error };
|
|
21
|
+
}
|
|
22
|
+
if (reason === 'failed') {
|
|
23
|
+
const listed = read.recent_failures?.some((failure) => !!ended.message_id && failure.message_id === ended.message_id);
|
|
24
|
+
if (!listed)
|
|
25
|
+
return { kind: 'stopped' };
|
|
26
|
+
}
|
|
27
|
+
return { kind: 'failed', error: null };
|
|
28
|
+
}
|
|
29
|
+
export function readTurnEnd(handoff, read, sawOpen) {
|
|
30
|
+
if (read.turns.length > 0)
|
|
31
|
+
return { state: 'running' };
|
|
32
|
+
const lastEndedToken = read.last_ended?.turn_token ?? null;
|
|
33
|
+
const endedSinceHandoff = handoff.openTurnToken !== null ||
|
|
34
|
+
sawOpen ||
|
|
35
|
+
(lastEndedToken !== null && lastEndedToken !== handoff.lastEndedToken);
|
|
36
|
+
if (!endedSinceHandoff)
|
|
37
|
+
return { state: 'waiting' };
|
|
38
|
+
return { state: 'ended', outcome: outcomeOf(read) };
|
|
39
|
+
}
|
|
40
|
+
function isFinalReadError(error) {
|
|
41
|
+
const status = error?.status;
|
|
42
|
+
return status === 401 || status === 403 || status === 404;
|
|
43
|
+
}
|
|
44
|
+
export function createTurnEndWatch(deps) {
|
|
45
|
+
const now = deps.now ?? Date.now;
|
|
46
|
+
const setTimer = deps.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
47
|
+
const clearTimer = deps.clearTimer ?? ((handle) => clearTimeout(handle));
|
|
48
|
+
const entries = new Map();
|
|
49
|
+
const keyOf = (projectId, sessionId) => `${projectId}/${sessionId}`;
|
|
50
|
+
function drop(key, entry) {
|
|
51
|
+
if (entries.get(key) !== entry)
|
|
52
|
+
return;
|
|
53
|
+
entry.dropped = true;
|
|
54
|
+
clearTimer(entry.timer);
|
|
55
|
+
entry.unsubscribe?.();
|
|
56
|
+
entries.delete(key);
|
|
57
|
+
}
|
|
58
|
+
function schedule(key, entry, ms) {
|
|
59
|
+
entry.timer = setTimer(() => void tick(key, entry), ms);
|
|
60
|
+
}
|
|
61
|
+
function evaluate(key, entry, read) {
|
|
62
|
+
if (entries.get(key) !== entry)
|
|
63
|
+
return;
|
|
64
|
+
const verdict = readTurnEnd(entry.handoff, read, entry.sawOpen);
|
|
65
|
+
if (verdict.state === 'ended') {
|
|
66
|
+
drop(key, entry);
|
|
67
|
+
deps.onEnded(entry.handoff, verdict.outcome, entry.sinceMs);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (verdict.state === 'running')
|
|
71
|
+
entry.sawOpen = true;
|
|
72
|
+
entry.lastState = verdict.state;
|
|
73
|
+
}
|
|
74
|
+
async function tick(key, entry) {
|
|
75
|
+
if (entries.get(key) !== entry)
|
|
76
|
+
return;
|
|
77
|
+
const { projectId, sessionId } = entry.handoff;
|
|
78
|
+
if (!deps.pushLive?.(projectId, sessionId)) {
|
|
79
|
+
try {
|
|
80
|
+
const read = await deps.readTurn(projectId, sessionId);
|
|
81
|
+
evaluate(key, entry, read);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (entries.get(key) !== entry)
|
|
85
|
+
return;
|
|
86
|
+
if (isFinalReadError(error)) {
|
|
87
|
+
drop(key, entry);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (entries.get(key) !== entry)
|
|
93
|
+
return;
|
|
94
|
+
const age = now() - entry.sinceMs;
|
|
95
|
+
const waitingTooLong = entry.lastState === 'waiting' && !entry.sawOpen && age >= TURN_END_WATCH_START_MS;
|
|
96
|
+
if (waitingTooLong || age >= TURN_END_WATCH_MAX_MS) {
|
|
97
|
+
drop(key, entry);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
schedule(key, entry, age >= TURN_END_WATCH_LONG_TURN_MS ? TURN_END_WATCH_SLOW_POLL_MS : TURN_END_WATCH_POLL_MS);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
watch(handoff) {
|
|
104
|
+
if (!handoff.projectId || !handoff.sessionId)
|
|
105
|
+
return;
|
|
106
|
+
const key = keyOf(handoff.projectId, handoff.sessionId);
|
|
107
|
+
const previous = entries.get(key);
|
|
108
|
+
if (previous)
|
|
109
|
+
drop(key, previous);
|
|
110
|
+
const entry = {
|
|
111
|
+
handoff,
|
|
112
|
+
sinceMs: now(),
|
|
113
|
+
sawOpen: false,
|
|
114
|
+
lastState: null,
|
|
115
|
+
timer: null,
|
|
116
|
+
unsubscribe: null,
|
|
117
|
+
dropped: false,
|
|
118
|
+
};
|
|
119
|
+
entries.set(key, entry);
|
|
120
|
+
schedule(key, entry, TURN_END_WATCH_FIRST_READ_MS);
|
|
121
|
+
const unsubscribe = deps.subscribe?.(handoff.projectId, handoff.sessionId, (read) => evaluate(key, entry, read));
|
|
122
|
+
if (entry.dropped)
|
|
123
|
+
unsubscribe?.();
|
|
124
|
+
else
|
|
125
|
+
entry.unsubscribe = unsubscribe ?? null;
|
|
126
|
+
},
|
|
127
|
+
release(projectId, sessionId) {
|
|
128
|
+
const key = keyOf(projectId, sessionId);
|
|
129
|
+
const entry = entries.get(key);
|
|
130
|
+
if (entry)
|
|
131
|
+
drop(key, entry);
|
|
132
|
+
},
|
|
133
|
+
releaseAll() {
|
|
134
|
+
for (const [key, entry] of [...entries])
|
|
135
|
+
drop(key, entry);
|
|
136
|
+
},
|
|
137
|
+
watching() {
|
|
138
|
+
return [...entries.keys()];
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SessionLogPage } from './source.js';
|
|
2
|
+
import type { SessionLogThreadHead } from './store.js';
|
|
3
|
+
import { type SessionLogMessage } from './types.js';
|
|
4
|
+
export declare function isSessionLogMessage(v: unknown): v is SessionLogMessage;
|
|
5
|
+
export declare function isSessionLogThreadHead(v: unknown): v is SessionLogThreadHead;
|
|
6
|
+
export declare function isSessionLogPage(v: unknown): v is SessionLogPage;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { SESSION_LOG_SCHEMA } from './types.js';
|
|
2
|
+
const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
3
|
+
const isStr = (v) => typeof v === 'string';
|
|
4
|
+
const isId = (v) => isStr(v) && v.length > 0;
|
|
5
|
+
const isStrOrNull = (v) => v === null || isStr(v);
|
|
6
|
+
const isOptional = (v, check) => v === undefined || check(v);
|
|
7
|
+
const oneOf = (...values) => (v) => values.includes(v);
|
|
8
|
+
const isCount = (v) => Number.isInteger(v) && v >= 0;
|
|
9
|
+
const isNum = (v) => typeof v === 'number';
|
|
10
|
+
const isSchemaRef = (v) => v.schema === SESSION_LOG_SCHEMA && isCount(v.v);
|
|
11
|
+
const isOptStr = (v) => isOptional(v, isStr);
|
|
12
|
+
const isExt = (v) => v === undefined || (isObj(v) && Object.values(v).every((e) => isObj(e) && isStr(e.version)));
|
|
13
|
+
const isModel = (v) => v === null || (isObj(v) && isStr(v.provider) && isStr(v.model) && isOptStr(v.variant));
|
|
14
|
+
const isUsage = (v) => v === null ||
|
|
15
|
+
(isObj(v) && isNum(v.input) && isNum(v.output) && isNum(v.cache_read) && isNum(v.cache_write) && isOptional(v.reasoning, isNum) && isOptional(v.cost, isNum));
|
|
16
|
+
const isResultContent = (c) => isObj(c) && ((c.type === 'text' && isStr(c.text)) || (c.type === 'attachment' && isStr(c.mime)));
|
|
17
|
+
const isToolResult = (r) => isObj(r) && Array.isArray(r.content) && r.content.every(isResultContent) && isOptional(r.model_content, (m) => Array.isArray(m) && m.every(isResultContent)) && typeof r.is_error === 'boolean';
|
|
18
|
+
const BLOCK = {
|
|
19
|
+
text: (b) => isStr(b.text) && isOptional(b.bytes, isCount) && isOptStr(b.ref) && (b.ref === undefined || b.bytes !== undefined),
|
|
20
|
+
reasoning: (b) => isStr(b.text),
|
|
21
|
+
attachment: (b) => isStr(b.mime) && isOptStr(b.ref) && isOptional(b.bytes, isCount) && (b.ref === undefined) === (b.bytes === undefined),
|
|
22
|
+
tool_call: (b) => isStr(b.call_id) &&
|
|
23
|
+
isStr(b.name) &&
|
|
24
|
+
isId(b.kind) &&
|
|
25
|
+
oneOf('pending', 'running', 'complete', 'error')(b.status) &&
|
|
26
|
+
isOptional(b.result, isToolResult),
|
|
27
|
+
compaction: (b) => isStrOrNull(b.summary) && isStrOrNull(b.first_kept_message_id),
|
|
28
|
+
subtask: (b) => isStr(b.thread_id) && isStr(b.agent) && isStr(b.description),
|
|
29
|
+
step: (b) => oneOf('start', 'finish')(b.phase),
|
|
30
|
+
harness: (b) => isId(b.harness) && isId(b.kind) && typeof b.model_visible === 'boolean',
|
|
31
|
+
};
|
|
32
|
+
function isBlocks(blocks, atRestInContext) {
|
|
33
|
+
if (!Array.isArray(blocks))
|
|
34
|
+
return false;
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
for (const b of blocks) {
|
|
37
|
+
if (!isObj(b) || !isId(b.id) || seen.has(b.id) || !Object.hasOwn(BLOCK, b.type))
|
|
38
|
+
return false;
|
|
39
|
+
if (!BLOCK[b.type](b) || !isExt(b.ext))
|
|
40
|
+
return false;
|
|
41
|
+
if (atRestInContext && b.type === 'tool_call' && (b.status === 'pending' || b.status === 'running' || !b.result))
|
|
42
|
+
return false;
|
|
43
|
+
seen.add(b.id);
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
export function isSessionLogMessage(v) {
|
|
48
|
+
return (isObj(v) &&
|
|
49
|
+
isSchemaRef(v) &&
|
|
50
|
+
isId(v.message_id) &&
|
|
51
|
+
isId(v.thread_id) &&
|
|
52
|
+
Number.isInteger(v.seq) &&
|
|
53
|
+
oneOf('user', 'assistant', 'system')(v.role) &&
|
|
54
|
+
oneOf('turn', 'compaction', 'context')(v.kind) &&
|
|
55
|
+
oneOf('streaming', 'complete', 'error', 'aborted', 'interrupted')(v.status) &&
|
|
56
|
+
typeof v.in_context === 'boolean' &&
|
|
57
|
+
isOptional(v.hidden_reason, oneOf('failed_attempt', 'aborted', 'retracted', 'reverted', 'superseded')) &&
|
|
58
|
+
isOptional(v.origin, oneOf('prompt', 'steer', 'command', 'automation', 'subagent', 'notification')) &&
|
|
59
|
+
isOptional(v.agent, isStrOrNull) &&
|
|
60
|
+
isOptional(v.reply_to, isStrOrNull) &&
|
|
61
|
+
isOptional(v.parent_message_id, isStrOrNull) &&
|
|
62
|
+
isOptStr(v.native_agent_id) &&
|
|
63
|
+
isOptStr(v.context_ref) &&
|
|
64
|
+
isModel(v.model) &&
|
|
65
|
+
isUsage(v.usage) &&
|
|
66
|
+
oneOf('stop', 'tool_calls', 'length', 'error', 'aborted', null)(v.finish) &&
|
|
67
|
+
(v.error === null || (isObj(v.error) && isId(v.error.code) && isStr(v.error.message))) &&
|
|
68
|
+
isStr(v.created_at) &&
|
|
69
|
+
isStrOrNull(v.completed_at) &&
|
|
70
|
+
isObj(v.producer) &&
|
|
71
|
+
isId(v.producer.harness) &&
|
|
72
|
+
isStr(v.producer.harness_version) &&
|
|
73
|
+
isStr(v.producer.adapter_version) &&
|
|
74
|
+
isExt(v.ext) &&
|
|
75
|
+
isBlocks(v.blocks, v.status !== 'streaming' && v.in_context === true));
|
|
76
|
+
}
|
|
77
|
+
export function isSessionLogThreadHead(v) {
|
|
78
|
+
return (isObj(v) &&
|
|
79
|
+
isSchemaRef(v) &&
|
|
80
|
+
isId(v.thread_id) &&
|
|
81
|
+
isStrOrNull(v.parent_thread_id) &&
|
|
82
|
+
(v.spawned_by === null || isObj(v.spawned_by)) &&
|
|
83
|
+
isStr(v.created_at));
|
|
84
|
+
}
|
|
85
|
+
function isSessionPatch(v) {
|
|
86
|
+
return (isObj(v) &&
|
|
87
|
+
isOptional(v.schema, (x) => x === SESSION_LOG_SCHEMA) &&
|
|
88
|
+
isOptional(v.v, isCount) &&
|
|
89
|
+
isOptStr(v.session_id) &&
|
|
90
|
+
isOptional(v.title, isStrOrNull) &&
|
|
91
|
+
isOptStr(v.created_at) &&
|
|
92
|
+
isOptional(v.restore_grade, oneOf('native', 'converted', 'partial')) &&
|
|
93
|
+
isOptional(v.todos, Array.isArray) &&
|
|
94
|
+
isOptional(v.pending, (p) => isObj(p) && Array.isArray(p.questions) && Array.isArray(p.permissions)) &&
|
|
95
|
+
isOptional(v.selection, (x) => isObj(x) && isOptional(x.agent, isStrOrNull) && isModel(x.model ?? null)) &&
|
|
96
|
+
isOptional(v.harness, (x) => isObj(x) && isStr(x.current) && Array.isArray(x.history)) &&
|
|
97
|
+
isExt(v.ext));
|
|
98
|
+
}
|
|
99
|
+
export function isSessionLogPage(v) {
|
|
100
|
+
return (isObj(v) &&
|
|
101
|
+
isCount(v.generation) &&
|
|
102
|
+
typeof v.has_more === 'boolean' &&
|
|
103
|
+
isSessionPatch(v.session) &&
|
|
104
|
+
Array.isArray(v.threads) &&
|
|
105
|
+
v.threads.every(isSessionLogThreadHead) &&
|
|
106
|
+
(v.thread_id === null || isId(v.thread_id)) &&
|
|
107
|
+
Array.isArray(v.messages) &&
|
|
108
|
+
v.messages.every((m) => isSessionLogMessage(m) && m.thread_id === v.thread_id));
|
|
109
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { KNOWN_TOOL_KINDS, SESSION_LOG_MINOR, SESSION_LOG_SCHEMA, type AttachmentBlock, type CompactionBlock, type CompactionLayoutEntry, type GradeCounts, type HarnessBlock, type KnownToolKind, type ModelRef, type ReasoningBlock, type RestoreGrade, type SessionLog, type SessionLogBlock, type SessionLogMessage, type SessionLogThread, type StepBlock, type SubtaskBlock, type TextBlock, type ThreadInteraction, type ToolCallBlock, type ToolResultContent, } from './types.js';
|
|
2
|
+
export type { Todo as SessionLogTodo, ToolKind as SessionLogToolKind } from './types.js';
|
|
3
|
+
export type { SessionLogPage, SessionLogPageQuery } from './source.js';
|
|
4
|
+
export { toolCallBlock, toolCallMetadata } from './tool-call.js';
|
|
5
|
+
export { toolCallError, toolCallRawOutput, toolCallStatus } from './tool-call.js';
|
|
6
|
+
export { sessionLogOfV1Rows } from './v1-view.js';
|
|
7
|
+
export * from './turns/index.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { KNOWN_TOOL_KINDS, SESSION_LOG_MINOR, SESSION_LOG_SCHEMA, } from './types.js';
|
|
2
|
+
export { toolCallBlock, toolCallMetadata } from './tool-call.js';
|
|
3
|
+
export { toolCallError, toolCallRawOutput, toolCallStatus } from './tool-call.js';
|
|
4
|
+
export { sessionLogOfV1Rows } from './v1-view.js';
|
|
5
|
+
export * from './turns/index.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CopyCodec, CopyStore } from '../session-sync/copy-store-types.js';
|
|
2
|
+
import type { SavedCopyStore } from '../session-sync/saved-copy-store.js';
|
|
3
|
+
import type { SessionLogPage } from './source.js';
|
|
4
|
+
export declare const SESSION_LOG_COPY: CopyCodec<SessionLogPage>;
|
|
5
|
+
export interface SessionLogCopies {
|
|
6
|
+
read(projectId: string, sessionId: string): SessionLogPage | null | Promise<SessionLogPage | null>;
|
|
7
|
+
write(projectId: string, sessionId: string, page: SessionLogPage): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerSessionLogCopies(store: SavedCopyStore, v2: CopyStore<SessionLogPage>, removeV1: (projectId: string, sessionId: string) => Promise<void>): void;
|
|
10
|
+
export declare function savedSessionLogCopies(store: SavedCopyStore | null | undefined): SessionLogCopies | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isSessionLogPage } from './guard.js';
|
|
2
|
+
const paintable = (page) => isSessionLogPage(page) && page.messages.length > 0;
|
|
3
|
+
function fit(stored, maxChars) {
|
|
4
|
+
const { messages } = stored.e;
|
|
5
|
+
for (let from = 0; from < messages.length; from++) {
|
|
6
|
+
const text = JSON.stringify(from === 0 ? stored : { ...stored, e: { ...stored.e, messages: messages.slice(from), has_more: true } });
|
|
7
|
+
if (text.length <= maxChars)
|
|
8
|
+
return text;
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
export const SESSION_LOG_COPY = { paintable, fit, capturedAt: () => 0 };
|
|
13
|
+
const copies = new WeakMap();
|
|
14
|
+
export function registerSessionLogCopies(store, v2, removeV1) {
|
|
15
|
+
copies.set(store, {
|
|
16
|
+
read: (projectId, sessionId) => v2.read(projectId, sessionId),
|
|
17
|
+
write: async (projectId, sessionId, page) => {
|
|
18
|
+
await v2.write(projectId, sessionId, page);
|
|
19
|
+
await removeV1(projectId, sessionId);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function savedSessionLogCopies(store) {
|
|
24
|
+
return (store && copies.get(store)) ?? null;
|
|
25
|
+
}
|